[Live-devel] Proper use of StreamReplicator

Jan Ekholm jan.ekholm at d-pointer.com
Thu Oct 16 12:19:45 PDT 2014


Hi,

I've use Live555 for some prototypes for a while now and it's working quite well so far. My use cases
are to act as a cental video hub for a number of remote surveillance cameras as well as locally connected
USB cameras and serve H264/MJPEG streams using unicast and multicast. Those scenarios more or
less work ok. The code isn't too pretty but Live555 is quite hard to use.

Now I need to save the streams to disk too. There is the handy StreamReplicator class that should allow
me to save the streams to disk as well as stream them to clients, but I've not really understood how to use
it correctly. From what I've understood I need to create one StreamReplicator for the source stream and
then replicator->createNewStreamReplica() for the streaming as well as the saving. Well, this does not work
at all so I'm doing something wrong.

The class that handles a local USB camera and unicasts MJPEG is basically:

class LocalMJpegUnicastServerMediaSubsession : public OnDemandServerMediaSubsession {
...
protected:

    virtual FramedSource* createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate);

    virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource);

private:
    CameraParameters m_cameraParameters;
    StreamReplicator * m_replicator;
    FileSink * m_saveSink;
};


FramedSource* LocalMJpegUnicastServerMediaSubsession::createNewStreamSource (unsigned clientSessionID, unsigned& estBitRate) {
    // create and initialize a source for the camera. This is a JPEGVideoSource subclass that captures, encodes and delivers JPEG frames
    // it works fine as long as do not try to use StreamReplicator
    MJpegFramedSource *source = MJpegFramedSource::createNew( envir() );
    source->initialize( m_cameraParameters );

    m_replicator = StreamReplicator::createNew( envir(), source, False );

    return m_replicator->createStreamReplica();
}

RTPSink* LocalMJpegUnicastServerMediaSubsession::createNewRTPSink (Groupsock* rtpGroupsock, unsigned char rtpPayloadTypeIfDynamic, FramedSource* inputSource) {
    return JPEGVideoRTPSink::createNew( envir(), rtpGroupsock );
}  

When I use this ServerMediaSubsession and connect a client the call sequence I see is:

LocalMJpegUnicastServerMediaSubsession::createNewStreamSource() 
LocalMJpegUnicastServerMediaSubsession::createNewRTPSink()
LocalMJpegUnicastServerMediaSubsession::createNewStreamSource() 
LocalMJpegUnicastServerMediaSubsession::createNewRTPSink()

Nothing is however delivered to the network. As if the stream doesn't start. I never see a call to
MJpegFramedSource::doGetNextFrame() which is the overridden method for, well, getting the next
frame. No errors, no crashes and no data. If I now try to save the stream I do get something
saved, but I have not analyzed the file yet. The amount of data looks correct though (a lot of
data very fast). To start saving I use code like (simplified):

void LocalMJpegUnicastServerMediaSubsession::startSavingStream (const std::string & filename) {
    FramedSource * source = m_replicator->createStreamReplica();
    m_saveSink = FileSink::createNew( envir(), filename.c_str(), bufferSize );
    m_saveSink->startPlaying( *source, 0, 0 );
}

So I get no stream but a saved file.

If I change my createNewStreamSource () back to the below it works fine for streaming:

FramedSource* LocalMJpegUnicastServerMediaSubsession::createNewStreamSource (unsigned clientSessionID, unsigned& estBitRate) {
    MJpegFramedSource *source = MJpegFramedSource::createNew( envir() );
    source->initialize( m_cameraParameters );
    return source;
}

In this case there is no replicator at all and I can not save the stream. Trying to later add a replicator to the
source and then use that with the FileSink leads to infinite recursion in doGetNextFrame(). But as I've understood
I can not use a replicator like this the behavior is perhaps to be expected. In this case I get a stream but no save
file.

So, how would one properly use StreamReplicator here so that I get both a stream and a save file? Later I also need
to be able to save streams that are local cameras multicasted as well as remote proxied cameras.

-- 
Jan Ekholm
jan.ekholm at d-pointer.com






More information about the live-devel mailing list