Hi ,
I'm trying to create a video conferencing application using JMF. I need to access the frames before it is transmitted to the remote end, so I have a custom codec class. Below is the code:
public void startMedia(String peerIP, int peerPort, int recvPort, int fmt) { try { /* initialization start */ InetAddress inLocalAddr = InetAddress.getLocalHost(); InetAddress destAddr = InetAddress.getByName(peerIP); SessionAddress localAddr = new SessionAddress(inLocalAddr, recvPort, inLocalAddr, recvPort + 1); SessionAddress remoteAddr = new SessionAddress(destAddr, peerPort, destAddr, peerPort + 1); myVideoSessionManager.startSession(localAddr, localAddr, remoteAddr, null); /* initialization complete */ int m = 0; if (inputSource == null) { MediaLocator ml = new MediaLocator("vfw://0"); myDS = Manager.createDataSource(ml); } else { myDS = ((SourceCloneable) inputSource).createClone(); } myProcessor = Manager.createProcessor(myDS); myProcessor.addControllerListener(this); myProcessor.configure(); while (myProcessor.getState() != Processor.Configured) { } myProcessor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW_RTP)); TrackControl track[] = myProcessor.getTrackControls(); String videoFormat = track[0].getFormat().toString(); Dimension videoSize = parseVideoSize(videoFormat); // Instantiate and set the frame access codec to the data flow path. try { Codec codec[] = {new PostAccessCodec(videoSize)}; track[0].setCodecChain(codec); } catch (UnsupportedPlugInException e) { System.err.println("The process does not support effects."); } myProcessor.prefetch(); if (!waitForState(Processor.Prefetched)) { System.err.println("Failed to realise the processor."); // return false; } ds = myProcessor.getDataOutput(); try { ss = myVideoSessionManager.createSendStream(ds, 0); } catch (Exception e) { e.printStackTrace(); } //We start capture and transmission myProcessor.start(); ss.start(); } catch (Exception ex) { ex.printStackTrace(); } }
public class PreAccessCodec implements Codec { /** * Callback to access individual video frames. */ void accessFrame(Buffer frame) { // For demo, we'll just print out the frame #, time & // data length. long t = (long) (frame.getTimeStamp() / 10000000f); System.err.println( "Pre: frame #: " + frame.getSequenceNumber() + ", time: " + ((float) t) / 100f + ", len: " + frame.getLength()); } /** * The code for a pass through codec. */ protected Format supportedIns[] = new Format[]{new VideoFormat(null)}; protected Format supportedOuts[] = new Format[]{new VideoFormat(null)}; Format input = null, output = null; public String getName() { return "Pre-Access Codec"; } //these dont do anything public void open() { } public void close() { } public void reset() { } public Format[] getSupportedInputFormats() { return supportedIns; } public Format[] getSupportedOutputFormats(Format in) { if (in == null) { return supportedOuts; } else { Format outs[] = new Format[1]; outs[0] = in; return outs; } } public Format setInputFormat(Format format) { input = format; return input; } public Format setOutputFormat(Format format) { output = format; return output; } public int process(Buffer in, Buffer out) { // This is the "Callback" to access individual frames. accessFrame(in); // Swap the data between the input & output. Object data = in.getData(); in.setData(out.getData()); out.setData(data); // Copy the input attributes to the output out.setFlags(Buffer.FLAG_NO_SYNC); out.setFormat(in.getFormat()); out.setLength(in.getLength()); out.setOffset(in.getOffset()); return BUFFER_PROCESSED_OK; } public Object[] getControls() { return new Object[0]; } public Object getControl(String type) { return null; } } public class PostAccessCodec extends PreAccessCodec { long count = 0; // We'll advertize as supporting all video formats. public PostAccessCodec(Dimension size) { supportedIns = new Format[]{new RGBFormat()}; this.size = size; } /** * Callback to access individual video frames. */ void accessFrame(Buffer frame) { count = count + 1; long t = (long) (frame.getTimeStamp() / 10000000f); System.err.println( "Post: frame #: " + frame.getSequenceNumber() + ", time: " + ((float) t) / 100f + ", len: " + frame.getLength()); } public String getName() { return "Post-Access Codec"; } private Dimension size; } /** * Block until the processor has transitioned to the given state. * Return false if the transition failed. */ boolean waitForState(int state) { synchronized (waitSync) { try { while (myProcessor.getState() != state && stateTransitionOK) { waitSync.wait(); } } catch (Exception e) { } } return stateTransitionOK; } public Dimension parseVideoSize(String videoSize) { int x = 352, y = 288; StringTokenizer strtok = new StringTokenizer(videoSize, ", "); strtok.nextToken(); String size = strtok.nextToken(); StringTokenizer sizeStrtok = new StringTokenizer(size, "x"); try { x = Integer.parseInt(sizeStrtok.nextToken()); y = Integer.parseInt(sizeStrtok.nextToken()); } catch (NumberFormatException e) { System.out.println("unable to find video size, assuming default of 352*288"); } System.out.println("Image width = " + String.valueOf(x) + "\nImage height = " + String.valueOf(y)); return new Dimension(x, y); }
Below is the exception I got while executing the code:
I was able to access the frame when I set the content descriptor for processor to null as below:HTML Code:Class: com.ibm.media.codec.video.h263.NativeEncoder@1b7ae22 can only encode in sizes: 128x96, 176x144, 352x288. Failed to realize: com.sun.media.ProcessEngine@9903f4 Cannot build a flow graph with the customized options: Unable to add customed codecs: splibraries.VideoTool$PostAccessCodec@1926e90 Error: Unable to realize com.sun.media.ProcessEngine@9903f4 Failed to realise the processor. javax.media.NotRealizedError: getDataOutput cannot be called before realized at com.sun.media.ProcessEngine.getDataOutput(ProcessEngine.java:379)
myProcessor.setContentDescriptor(null);
But this will not allow me to get the data output from processor . Kindly help me to resolve the issue.


LinkBack URL
About LinkBacks
Reply With Quote