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:

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)
I was able to access the frame when I set the content descriptor for processor to null as below:
myProcessor.setContentDescriptor(null);

But this will not allow me to get the data output from processor . Kindly help me to resolve the issue.