JFjr - the JMF/FOBS/jME video renderer

Hi Lamma would you like to help me sort this code out … i am converting your code to support RTP also …but not successed as i dont know whats the problem as i am new to java too… using AVreceiver2.java am getting the video but using jme i cannot retreive data properly… i cannt understand how to convert it to …it would be very helpfull thanks





the code is below



package org.llama.jmf;

import java.awt.Graphics;

import java.awt.Image;

import java.io.File;

import java.net.InetAddress;

import java.net.URL;



import javax.media.;

import javax.media.control.FrameGrabbingControl;

import javax.media.format.VideoFormat;

import javax.media.util.BufferToImage;

import java.io.
;

import java.awt.;

import java.net.
;

import java.awt.event.;

import java.util.Vector;





import javax.media.rtp.
;

import javax.media.rtp.event.;

import javax.media.rtp.rtcp.
;

import javax.media.protocol.*;

import javax.media.format.AudioFormat;



import javax.media.Format;

import javax.media.format.FormatChangeEvent;

import javax.media.control.BufferControl;



import org.llama.jmf.AVReceive3.PlayerWindow;

import org.llama.jmf.SessionLabel;



public class JMFRTPGrabber implements ReceiveStreamListener, SessionListener,

ControllerListener  {

private static final int MAX_TRIES = 5;

private static final int TRY_PERIOD = 2000; // ms



private Player p;

private FrameGrabbingControl fg;

private BufferToImage bufferToImage = null;



private int width, height; // frame dimensions



// used for waiting until the player has started



private boolean stateTransitionOK = true;

String sessions[] = null;

RTPManager mgrs[] = null;

Vector playerWindows = null;

boolean dataReceived = false;

Object dataSync = new Object();

public JMFRTPGrabber(String sessions[])

{

this.sessions = sessions;

Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true));





}

public boolean initialize() {



        try {

    mgrs = new RTPManager[sessions.length];

    //playerWindows = new Vector();



    SessionLabel session;



    // Open the RTP sessions.

    for (int i = 0; i < sessions.length; i++) {



// Parse the session addresses.

try {

    session = new SessionLabel(sessions);

} catch (IllegalArgumentException e) {

    System.err.println("Failed to parse the session address given: " + sessions);

    return false;

}



System.err.println("  - Open RTP session for: addr: " + session.addr + " port: " + session.port + " ttl: " + session.ttl);



mgrs = (RTPManager) RTPManager.newInstance();

mgrs.addSessionListener(this);

mgrs.addReceiveStreamListener(this);



// Initialize the RTPManager with the RTPSocketAdapter

mgrs.initialize(new RTPSocketAdapter(

InetAddress.getByName(session.addr),

session.port, session.ttl));



// You can try out some other buffer size to see

// if you can get better smoothness.

BufferControl bc = (BufferControl)mgrs.getControl("javax.media.control.BufferControl");

if (bc != null)

    bc.setBufferLength(350);

    }



        } catch (Exception e){

            System.err.println("Cannot create the RTP Session: " + e.getMessage());

            return false;

        }



// Wait for data to arrive before moving on.



long then = System.currentTimeMillis();

long waitingPeriod = 60000;  // wait for a maximum of 30 secs.



try{

    synchronized (dataSync) {

while (!dataReceived &&

System.currentTimeMillis() - then < waitingPeriod) {

    if (!dataReceived)

System.err.println("  - Waiting for RTP data to arrive…");

    dataSync.wait(1000);

}

    }

} catch (Exception e) {}



if (!dataReceived) {

    System.err.println("No RTP data was received.");

    close();

    return false;

}



        return true;

    }





    public boolean isDone() {

return playerWindows.size() == 0;

    }





    /**

    * Close the players and the session managers.

    /

    protected void close() {



for (int i = 0; i < playerWindows.size(); i++) {

    try {

((PlayerWindow)playerWindows.elementAt(i)).close();

    } catch (Exception e) {}

}



playerWindows.removeAllElements();



// close the RTP session.

for (int i = 0; i < mgrs.length; i++) {

    if (mgrs != null) {

                mgrs.removeTargets( "Closing session from AVReceive3");

                mgrs.dispose();

mgrs = null;

    }

}

    }





    PlayerWindow find(Player p) {

for (int i = 0; i < playerWindows.size(); i++) {

    PlayerWindow pw = (PlayerWindow)playerWindows.elementAt(i);

    if (pw.player == p)

return pw;

}

return null;

    }



public void controllerUpdate(ControllerEvent evt)

// respond to events

{

if (evt instanceof StartEvent) { // the player has started

synchronized (dataSync) {

stateTransitionOK = true;

dataSync.notifyAll();

}

} else if (evt instanceof ResourceUnavailableEvent) {

synchronized (dataSync) { // there was a problem getting a player

// resource

stateTransitionOK = false;

dataSync.notifyAll();

}

} else if (evt instanceof EndOfMediaEvent) { // make the movie loop

System.out.println("loop the movie");

p.setMediaTime(new Time(0));

p.start();

}

}

public synchronized void update(SessionEvent evt) {

if (evt instanceof NewParticipantEvent) {

    Participant p = ((NewParticipantEvent)evt).getParticipant();

    System.err.println("  - A new participant had just joined: " + p.getCNAME());

}

    }

public synchronized void update( ReceiveStreamEvent evt) {



RTPManager mgr = (RTPManager)evt.getSource();

Participant participant = evt.getParticipant(); // could be null.

ReceiveStream stream = evt.getReceiveStream();  // could be null.



if (evt instanceof RemotePayloadChangeEvent) {

   

    System.err.println("  - Received an RTP PayloadChangeEvent.");

    System.err.println("Sorry, cannot handle payload change.");

    System.exit(0);



}

   

else if (evt instanceof NewReceiveStreamEvent) {



    try {

stream = ((NewReceiveStreamEvent)evt).getReceiveStream();

DataSource ds = stream.getDataSource();



// Find out the formats.

RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl");



Player p = javax.media.Manager.createRealizedPlayer(ds);

if (p == null)

    return;



p.addControllerListener(this);

fg = (FrameGrabbingControl) p.getControl("javax.media.control.FrameGrabbingControl");

if (fg == null) {

System.out.println("Frame grabber could not be created");

System.exit(0);

}

// check if the player has a visual component

if (p.getVisualComponent() == null) {

System.out.println("No visual component found");

System.exit(0);

}



// wait until the player has started

System.out.println("Starting the player…");

p.start();

if (!waitForStart()) {

System.err.println("Failed to start the player.");

System.exit(0);

}

waitForBufferToImage();

}



    catch (Exception e) {

System.err.println("NewReceiveStreamEvent exception " + e.getMessage());

return;

    }

       



}



    }

private boolean waitForStart()

// wait for the player to enter its Started state

{

synchronized (dataSync) {

try {

while (p.getState() != Controller.Started && stateTransitionOK)

dataSync.wait();

} catch (Exception e) {

}

}

return stateTransitionOK;

} // end of waitForStart()



private void waitForBufferToImage()

/

  • Wait for the BufferToImage object to be initialized. Movies with an audio
  • track may take several seconds to initialize this object, so this method
  • makes up to MAX_TRIES attempts.

    /

    {

    int tryCount = MAX_TRIES;

    System.out.println("Initializing BufferToImage…");

    while (tryCount > 0) {

    if (hasBufferToImage()) // initialization succeeded

    break;

    try { // initialization failed so wait a while and try again

    System.out.println("Waiting…");

    Thread.sleep(TRY_PERIOD);

    } catch (InterruptedException e) {

    System.out.println(e);

    }

    tryCount–;

    }



    if (tryCount == 0) {

    System.out.println("Giving Up");

    System.exit(0);

    }

    }



    private boolean hasBufferToImage()

    /

  • The BufferToImage object is initialized here, so that when getFrame() is
  • called later, the snap can be quickly changed to an image.

    *
  • The object is initialized by taking a snap, which may be an actual
  • picture or be 'empty'.

    *
  • An 'empty' snap is a Buffer object with no video information, as detected
  • by examining its component VideoFormat data.

    *
  • An 'empty' snap is caused by the delay in the player, which although in
  • its started state still takes several seconds to start playing the movie.
  • This delay occurs when the movie has a video and audio track.

    *
  • There's no delay if the movie only has a video track.

    /

    {

    Buffer buf = fg.grabFrame(); // take a snap

    if (buf == null) {

    System.out.println("No grabbed frame");

    return false;

    }



    // there is a buffer, but check if it's empty or not

    VideoFormat vf = (VideoFormat) buf.getFormat();

    if (vf == null) {

    System.out.println("No video format");

    return false;

    }



    System.out.println("Video format: " + vf);

    width = vf.getSize().width; // extract the image's dimensions

    height = vf.getSize().height;



    // initialize bufferToImage with the video format info.

    bufferToImage = new BufferToImage(vf);

    return true;

    }



    synchronized public void stopMovie()

    /

  • stopMovie() and getFrame() are synchronized so that it's not possible to
  • close down the player while a frame is being copied from its movie.

    */

    {

    p.close();

    }



    synchronized public void grabFrame(Graphics g, int width, int heigth) {

    // grab the current frame as a buffer object

    Buffer buf = fg.grabFrame();

    if (buf == null) {

    System.out.println("No grabbed buffer");

    return;

    }



    // convert buffer to image

    Image im = bufferToImage.createImage(buf);

    if (im == null) {

    System.out.println("No grabbed image");

    return;

    }

    g.drawImage(im, 0, 0, width, heigth, null);

    }





    public int getImageWidth() {

    return width;

    }



    public int getImageHeight() {

    return height;

    }

    }

    class SessionLabel {



    public String addr = null;

    public int port;

    public int ttl = 1;



    SessionLabel(String session) throws IllegalArgumentException {



        int off;

        String portStr = null, ttlStr = null;



        if (session != null && session.length() > 0) {

    while (session.length() > 1 && session.charAt(0) == '/')

        session = session.substring(1);



    // Now see if there's a addr specified.

    off = session.indexOf('/');

    if (off == -1) {

        if (!session.equals(""))

    addr = session;

    } else {

        addr = session.substring(0, off);

        session = session.substring(off + 1);

        // Now see if there's a port specified

        off = session.indexOf('/');

        if (off == -1) {

    if (!session.equals(""))

        portStr = session;

        } else {

    portStr = session.substring(0, off);

    session = session.substring(off + 1);

    // Now see if there's a ttl specified

    off = session.indexOf('/');

    if (off == -1) {

        if (!session.equals(""))

    ttlStr = session;

    } else {

        ttlStr = session.substring(0, off);

    }

        }

    }

        }



        if (addr == null)

    throw new IllegalArgumentException();



        if (portStr != null) {

    try {

        Integer integer = Integer.valueOf(portStr);

        if (integer != null)

    port = integer.intValue();

    } catch (Throwable t) {

        throw new IllegalArgumentException();

    }

        } else

    throw new IllegalArgumentException();



        if (ttlStr != null) {

    try {

        Integer integer = Integer.valueOf(ttlStr);

        if (integer != null)

    ttl = integer.intValue();

    } catch (Throwable t) {

        throw new IllegalArgumentException();

    }

        }

    }

        }

re: newJMonkey

Unfortunatly I know very little about JMF & RTP. I also see you're using BufferToImage, which I only played around with a bit. What I've written is a jME renderer so that with jME you don't have to use that very slow method. This looks like you're not even using jME?



re: oliver1974

I haven't heard any reports that it works on linux/mac, but with FOBS it shouldn't be a problem. I'd love for someone to comfirm that though.

I also have little knowledge about it and i am really struggling with java…but if i dont use buffertoimage how then i would be able to see the real image instead of buffer …Thanks

Well, my renderer (which this thread is about) renders the buffer straight into a jME texture.

i wrote a small app that i use with java webstart, and it works like a charm on the 3 platforms, without having to install anything but a java VM

Finally a confirmed report :slight_smile:



Do you use the "patched" version of FOBS? How do you get around the fact that FOBS wants urls that point to real files instead of files in jars, in combination with Webstart? (or doesn't your app include video files with the webstart).

yes, i 'm using the patched version of fobs.

regarding to videos, as i never been able to use http protocol directly, i implemented my own buffering technique, in fact i disable video caching in jmf and have a thread that download the file locally to a temp directory, while this thread is downloading, i'm playing the file locally. the downloading thread is computing the bandwith and determine when the reading can start. it's like quicktime fast start mode. that's how i get the rid of the network.

i plan to use pipes to read the videos, but this way is working fine, i'm able to play any dvd vob files directly via a lan and any divx file over internet.

The only restriction: if you look a 3go video, u must have 3go of free disk space.

all files and textures are externals and the jar of the scene is just 120ko.

Nice solution. Who doesn't have 3GB of free space these days anyway :slight_smile:

if you're ok with it llama, i'm ready to help you to improve this jme part (i mean video texturing). I'm working on it for my company but i'll publish my work to you.

my knowledge isn't perfect but i'm sure we can make something cool…

that sounds like a great idea…get it complete and jme:ified :slight_smile: whiihaa

Ok unixseb I sent you a PM with my contact info.



As for jmefying it, I guess jME should support updateable textures anyway, rather than hackin' it in with LWJGL everytime. So I guess I got myself a task there.

can you convert that task to get cubemap textures in? :slight_smile: didn't you have that aaalmost up and running?  :smiley:

Well, I was working on every type except cubemaps for now… (and uh, actually did have it running). But yeah, I figured as long as I'm messing up the texture system I might as well add this to the list.



Of course the official excuse is jME is in a feature freeze right now…

HI lama i have cracked the rtp stuff and it work fine i can transmit from one computer and receive the video on another computer uisng my grabber. the only problem i am having is when i play a file which has both video and audio it doesnot show the video just audio … i can see some images but i cann see full video … you mention that i am using buffertoimage() function that take lot of time to update …how can i update buffer directly to the texture instead first to image…



the code is below

you have to call this class from any where



like

String arg[]={"192.168.0.2/42050","192.168.0.2/42052"};

//jmf = new JMFGrabber("c:\Movies\partido.avi");

jmf = new JMFRTPGrabber(arg);



package org.llama.jmf;

import java.awt.Graphics;

import java.awt.Image;

import java.io.File;

import java.net.InetAddress;

import java.net.URL;



import javax.media.;

import javax.media.control.FrameGrabbingControl;

import javax.media.format.VideoFormat;

import javax.media.util.BufferToImage;

import java.io.
;

import java.awt.;

import java.net.
;

import java.awt.event.;

import java.util.Vector;





import javax.media.rtp.
;

import javax.media.rtp.event.;

import javax.media.rtp.rtcp.
;

import javax.media.protocol.;

import javax.media.format.AudioFormat;



import javax.media.Format;

import javax.media.format.FormatChangeEvent;

import javax.media.control.BufferControl;



import org.llama.jmf.AVReceive3.PlayerWindow;

import org.llama.jmf.SessionLabel;



public class JMFRTPGrabber implements ReceiveStreamListener, SessionListener,

ControllerListener  {



private static final int MAX_TRIES = 5;

private static final int TRY_PERIOD = 2000; // ms

private Player p;

private FrameGrabbingControl fg;

private BufferToImage bufferToImage = null;

private int width, height; // frame dimensions

// used for waiting until the player has started

private boolean stateTransitionOK = true;

String sessions[] = null;

RTPManager mgrs[] = null;

// used for waiting until the player has started

Object dataSync = new Object();

public JMFRTPGrabber(String sessions[])

{

this.sessions = sessions;

Manager.setHint(Manager.PLUGIN_PLAYER, new Boolean(true));



}

public boolean initialize() {



        //try {

    mgrs = new RTPManager[sessions.length];

    SessionLabel session;

    // Open the RTP sessions.

    for (int i = 0; i < sessions.length; i++) {



// Parse the session addresses.

try {

    session = new SessionLabel(sessions);



System.err.println("  - Open RTP session for: addr: " + session.addr + " port: " + session.port + " ttl: " + session.ttl);



mgrs = (RTPManager) RTPManager.newInstance();

mgrs.addSessionListener(this);

mgrs.addReceiveStreamListener(this);



// Initialize the RTPManager with the RTPSocketAdapter

mgrs.initialize(new RTPSocketAdapter(

InetAddress.getByName(session.addr),

session.port, session.ttl));



        } catch (Exception e){



      }

  }

        return true;

       





public void controllerUpdate(ControllerEvent evt)

// respond to events

{

if (evt instanceof StartEvent) { // the player has started

synchronized (dataSync) {

stateTransitionOK = true;

dataSync.notifyAll();

}

} else if (evt instanceof ResourceUnavailableEvent) {

synchronized (dataSync) { // there was a problem getting a player

// resource

stateTransitionOK = false;

dataSync.notifyAll();

}

}

//if you want to loop the movie uncomment it

//

// } else if (evt instanceof EndOfMediaEvent) { // make the movie loop

// System.out.println("loop the movie");

// p.setMediaTime(new Time(0));

// p.start();

// }

}

//check session events like a new participant information

public synchronized void update(SessionEvent evt) {

if (evt instanceof NewParticipantEvent) {

    Participant p = ((NewParticipantEvent)evt).getParticipant();

    System.err.println("  - A new participant had just joined: " + p.getCNAME());

}

    }

//if the data receive this event will call



public synchronized void update( ReceiveStreamEvent evt) {



RTPManager mgr = (RTPManager)evt.getSource();

Participant participant = evt.getParticipant(); // could be null.

ReceiveStream stream = evt.getReceiveStream();  // could be null.



if (evt instanceof RemotePayloadChangeEvent) {

   

    System.err.println("  - Received an RTP PayloadChangeEvent.");

    System.err.println("Sorry, cannot handle payload change.");

    System.exit(0);



}    

else if (evt instanceof NewReceiveStreamEvent) {



    try {

stream = ((NewReceiveStreamEvent)evt).getReceiveStream();

DataSource ds = stream.getDataSource();



// Find out the formats.

RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl");



Player p = javax.media.Manager.createRealizedPlayer(ds);

if (p == null)

    return;



p.addControllerListener(this);

fg = (FrameGrabbingControl) p.getControl("javax.media.control.FrameGrabbingControl");

//in case of just audio data the i commented System.exit(0) becuase it should play

//the audio if no video is availabe

if (fg == null) {

System.out.println("Frame grabber could not be created");

//System.exit(0);

}

// check if the player has a visual component

if (p.getVisualComponent() == null) {

System.out.println("No visual component found");

//System.exit(0);

}



// wait until the player has started

System.out.println("Starting the player…");

p.start();

if (!waitForStart()) {

System.err.println("Failed to start the player.");

System.exit(0);

}

waitForBufferToImage();

}



    catch (Exception e) {

    System.err.println("NewReceiveStreamEvent exception " + e.getMessage());

return;

    }

       



}



    }

private boolean waitForStart()

// wait for the player to enter its Started state

{

synchronized (dataSync) {

try {

while (p.getState() != Controller.Started && stateTransitionOK)

dataSync.wait();

} catch (Exception e) {

}

}

return stateTransitionOK;

} // end of waitForStart()



private void waitForBufferToImage()

/

  • Wait for the BufferToImage object to be initialized. Movies with an audio
  • track may take several seconds to initialize this object, so this method
  • makes up to MAX_TRIES attempts.

    /

    {

    try {

    int tryCount = MAX_TRIES;

    System.out.println("Initializing BufferToImage…");

    while (tryCount > 0) {

    if (hasBufferToImage()) // initialization succeeded

    break;

    try { // initialization failed so wait a while and try again

    System.out.println("Waiting…");

    Thread.sleep(TRY_PERIOD);

    } catch (InterruptedException e) {

    System.out.println(e);

    }

    tryCount–;

    }

    if (tryCount == 0) {

    System.out.println("Giving Up");

    //System.exit(0); // try to play the audio but dont exit the application

    }

    } catch (Exception e) {

    // TODO: handle exception



    return ;

    }

    }



    private boolean hasBufferToImage()

    /

  • The BufferToImage object is initialized here, so that when getFrame() is
  • called later, the snap can be quickly changed to an image.

    *
  • The object is initialized by taking a snap, which may be an actual
  • picture or be 'empty'.

    *
  • An 'empty' snap is a Buffer object with no video information, as detected
  • by examining its component VideoFormat data.

    *
  • An 'empty' snap is caused by the delay in the player, which although in
  • its started state still takes several seconds to start playing the movie.
  • This delay occurs when the movie has a video and audio track.

    *
  • There's no delay if the movie only has a video track.

    /

    {

    try {

    Buffer buf = fg.grabFrame(); // take a snap

    if (buf == null) {

    System.out.println("No grabbed frame");

    return false;

    }

    // there is a buffer, but check if it's empty or not

    VideoFormat vf = (VideoFormat) buf.getFormat();

    if (vf == null) {

    System.out.println("No video format");

    return false;

    }

    System.out.println("Video format: " + vf);

    width = vf.getSize().width; // extract the image's dimensions

    height = vf.getSize().height;

    // initialize bufferToImage with the video format info.

    bufferToImage = new BufferToImage(vf);

    return true;

    } catch (Exception e) {

    // TODO: handle exception

    //System.err.println(e.getMessage());

    // try to play the audio or nothing in case we dont have video

    return false;

    }

    }



    synchronized public void stopMovie()

    /

  • stopMovie() and getFrame() are synchronized so that it's not possible to
  • close down the player while a frame is being copied from its movie.

    */

    {

    p.close();

    }



    synchronized public void grabFrame(Graphics g, int width, int heigth) {

    try {

    // grab the current frame as a buffer object

    Buffer buf = fg.grabFrame();

    if (buf == null) {

    System.out.println("No grabbed buffer");

    return;

    }

    // convert buffer to image

    Image im = bufferToImage.createImage(buf);

    if (im == null) {

    System.out.println("No grabbed image");

    return;

    }

    g.drawImage(im, 0, 0, width, heigth, null);

    } catch (Exception e) {

    // TODO: handle exception

    //System.err.println(e.getMessage());

    }

    }





    public int getImageWidth() {

    return width;

    }



    public int getImageHeight() {

    return height;

    }

    }

    class SessionLabel {



    public String addr = null;

    public int port;

    public int ttl = 1;



    SessionLabel(String session) throws IllegalArgumentException {



        int off;

        String portStr = null, ttlStr = null;



        if (session != null && session.length() > 0) {

    while (session.length() > 1 && session.charAt(0) == '/')

        session = session.substring(1);



    // Now see if there's a addr specified.

    off = session.indexOf('/');

    if (off == -1) {

        if (!session.equals(""))

    addr = session;

    } else {

        addr = session.substring(0, off);

        session = session.substring(off + 1);

        // Now see if there's a port specified

        off = session.indexOf('/');

        if (off == -1) {

    if (!session.equals(""))

        portStr = session;

        } else {

    portStr = session.substring(0, off);

    session = session.substring(off + 1);

    // Now see if there's a ttl specified

    off = session.indexOf('/');

    if (off == -1) {

        if (!session.equals(""))

    ttlStr = session;

    } else {

        ttlStr = session.substring(0, off);

    }

        }

    }

        }



        if (addr == null)

    throw new IllegalArgumentException();



        if (portStr != null) {

    try {

        Integer integer = Integer.valueOf(portStr);

        if (integer != null)

    port = integer.intValue();

    } catch (Throwable t) {

        throw new IllegalArgumentException();

    }

        } else

    throw new IllegalArgumentException();



        if (ttlStr != null) {

    try {

        Integer integer = Integer.valueOf(ttlStr);

        if (integer != null)

    ttl = integer.intValue();

    } catch (Throwable t) {

        throw new IllegalArgumentException();

    }

        }

    }

        }



    Thanks

For that you'd have to look at my code.

Ok, I actually looked a bit at this code, and updates to the last version of FOBS. For the perfomance patch to actually work you'll have to change an extra line in the FOBS code, I added that to the start post. For the rest it looks to be fine.



I also noticed that on my new dual core CPU I don't have any stuttering anymore ever when audio is enabled. Also with Java 1.6 the JavaSound renderer seems to work fine again here.

i confirm , the javasound renderer is fixed in java v6 :slight_smile:

what is the last version you're talking about (FOBS) ?? is it 0.4.1 ?

Yes, 0.4.1

Hello Everyone



I am quite new to jMF and jME and would like to ask some of the experts here if it would be possible to have live video from a webcam displayed within a jME game?



In my case there would be two firewire webcams (based on libdc1394). According to this sourceforge project (http://sourceforge.net/projects/jlibdc1394) it should theoretically be possible to access the images of the webcams through jMF.



I would be happy about any comments. However, it seems obvious that nobody has tested it by now. :wink:



Thanks and hello to the forum.

Nemo








JFjr can render some non-FOBS output formats, I've tried it with a webcam input source for example (but not using this code). Be sure to follow the installation instruction without FOBS, and then adapt the code to open a 1394 stream instead of a file, and hope the output format is supported. (if it's YUV you're out of luck though, you'd have to adapt the part where data is uploaded to texture, or port the JOGL based YUV shader from the FOBS project).