#27 RTP bug using FMJ in JMF framework

open
nobody
None
5
2007-12-02
2007-12-02
Anonymous
No

Hi all !

First of all, thanks for your great job !

I'm using FMJ's RTP Session Manager inside Sun's JMF framework.

I place FMJ.jar in my classpath, and I do something like this:
PackageManager.getProtocolPrefixList().add(0, "net.sf.fmj");

Then I have some troubles sending/receiving a Video stream: the buffer in RTPSendStream.transferData() is sometimes erased by other data, and wrong RTP packets are sent.

I looked up what was happening: Sun's JMF uses several buffers in their RawBufferMux (sort of double buffering). When read method is called, RawBufferMux swaps its internal buffer with the one we pass in parameters.

FMJ also does something like this:

if (recvBuffer.getData() != buffer)
System.arraycopy(recvBuffer.getData(), recvBuffer.getOffset(), buffer, RTPHeader.SIZE, recvBuffer.getLength());

As a result, we share the same buffer between Sun's JMF and FMJ ! And, then, buffer is sometimes erased by JMF !

I found a second bug about timestamp, still in RTPSendStream. In transferData, timestamp is directly taken from Buffer. But buffer's timestamp is in nanoseconds, and clockRate is not taken into account. Timestamp field in RTP is only 4 bytes... and time in nanoseconds may be greater than 4 bytes !

As a result, player receives packets with a random timestamp...

Here is a patch that resolves these bugs. It works for my application.

Thank you again for your work !

Discussion

  • Nobody/Anonymous

    A patch that resolves the two bugs.

     
  • Nobody/Anonymous

    Logged In: NO

    I've also detected that packets created by my packetizer are
    overridden when sending it through the JMF RTP.

    After some analyzation I've found the bug in the AbstractPacketizer.java
    code.

    In the process method the packetBuffer has to be recreated, because
    it may be still in the output queue of the JMF (outputbuffer is not
    already processed through the CircularBuffer), but there are more
    incoming packets to the packetizer with further data. So code in
    AbstractPacketizer may be

    process(...)
    ...
    if (packetComplete)
    {
    outputBuffer.setData(packetBuffer);
    outputBuffer.setOffset(0);
    outputBuffer.setLength(bytesInPacketBuffer);
    bytesInPacketBuffer = 0;
    packetBuffer = new byte[packetSize];

    if (inputBuffer.getLength() == 0) result = BUFFER_PROCESSED_OK;
    else
    result = INPUT_BUFFER_NOT_CONSUMED;
    }
    ....

    As a workaround if you create your own packetizer create a copy of AbstractPacketizer and fix this if you subclass your packetizer from the FMJ's AbstractPacketizer.