[Live-devel] Proper use of StreamReplicator

Jan Ekholm jan.ekholm at d-pointer.com
Fri Oct 17 02:16:54 PDT 2014


On 17 okt 2014, at 04:34, Ross Finlayson <finlayson at live555.com> wrote:

>> 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.
> 
> Yes, it's hard to use, but that's mainly because it's used to build complex systems.  It's also intended for experienced systems programmers; not for the 'faint of heart' :-)  Finally, everyone should remember that Live Networks, Inc. is not a charity, and I make no money by helping people with the software 'for free' on this mailing list; it's just something that I do as a public service.

Indeed. You should make it easier to support you, perhaps with a sponsorship program where you
can pay some predefined amounts as appreciation for support and the software. Make it easy to just click
a few buttons. Invoices etc are much more work for a customer and is what scared me off last spring when
I queried how I could pay for the help you'd given me. I still don't mind paying, but we in the rest of the world 
are not really accustomed to US software consulting prices, so at least I can not pay for weeks of work 
(that's what I get in a whole year).

> 
>> 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 {
> 
> First, because you're streaming from live sources (rather than prerecorded files), make sure that your "LocalMJpegUnicastServerMediaSubsession" constructor sets the "reuseFirstSource" parameter - in the "OnDemandServerMediaSubsession" constructor - to True.

It does set it to true.

>> 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 );
> 
> I would replace this line with:
> 	if (m_replicator == NULL) {
> 		m_replicator = StreamReplicator::createNew( envir(), source, False );
> 		startSavingStream(yourFileName);
> 	}
> and, of course, initialize "m_replicator" to NULL in your constructor.

Ok. I've never been really sure if the source should be created in createNewStreamSource() along with
the replicator or if it is better to create both in the constructor and in createNewStreamSource() just return 
replicator->createStreamReplica()? If I create the source in the constructor and reuse it there really is no
difference, it still does not work. I do think the replicator does not work in a more complex situation like
this.

> 
>> When I use this ServerMediaSubsession and connect a client the call sequence I see is:
>> 
>> LocalMJpegUnicastServerMediaSubsession::createNewStreamSource() 
>> LocalMJpegUnicastServerMediaSubsession::createNewRTPSink()
> 
> FYI, at this point, you should also be seeing:
> 	~JPEGVideoRTPSink()
> 	~StreamReplica()

Yes, I see JPEGVideoRTPSink being destroyed three times as createNewStreamSource() is called three times. 
First with a clientSessionID=0 and the other times with valid large ids. No idea why three times, perhaps VLC which
acts as the client does something interesting. Trying with testRTSPClient I only see two calls. Perhaps VLC retries
something as there is no data. The output from testRTSPClient is:

./testProgs/testRTSPClient rtsp://192.168.1.12:8554/camera0
Opening connection to 192.168.1.12, port 8554...
...remote connection opened
Sending request: DESCRIBE rtsp://192.168.1.12:8554/camera0 RTSP/1.0
CSeq: 2
User-Agent: ./testProgs/testRTSPClient (LIVE555 Streaming Media v2014.10.07)
Accept: application/sdp


Received 562 new bytes of response data.
Received a complete DESCRIBE response:
RTSP/1.0 200 OK
CSeq: 2
Date: Fri, Oct 17 2014 07:48:44 GMT
Content-Base: rtsp://192.168.1.12:8554/camera0/
Content-Type: application/sdp
Content-Length: 396

v=0
o=- 1413532111476134 1 IN IP4 192.168.1.12
s=Local unicast MJPEG camera
i=Camera
t=0 0
a=tool:LIVE555 Streaming Media v2014.10.07
a=type:broadcast
a=control:*
a=source-filter: incl IN IP4 * 192.168.1.12
a=rtcp-unicast: reflection
a=range:npt=0-
a=x-qt-text-nam:Local unicast MJPEG camera
a=x-qt-text-inf:Camera
m=video 0 RTP/AVP 26
c=IN IP4 0.0.0.0
b=AS:200
a=control:track1

[URL:"rtsp://192.168.1.12:8554/camera0/"]: Got a SDP description:
v=0
o=- 1413532111476134 1 IN IP4 192.168.1.12
s=Local unicast MJPEG camera
i=Camera
t=0 0
a=tool:LIVE555 Streaming Media v2014.10.07
a=type:broadcast
a=control:*
a=source-filter: incl IN IP4 * 192.168.1.12
a=rtcp-unicast: reflection
a=range:npt=0-
a=x-qt-text-nam:Local unicast MJPEG camera
a=x-qt-text-inf:Camera
m=video 0 RTP/AVP 26
c=IN IP4 0.0.0.0
b=AS:200
a=control:track1

[URL:"rtsp://192.168.1.12:8554/camera0/"]: Initiated the "video/JPEG" subsession (client ports 56224-56225)
Sending request: SETUP rtsp://192.168.1.12:8554/camera0/track1 RTSP/1.0
CSeq: 3
User-Agent: ./testProgs/testRTSPClient (LIVE555 Streaming Media v2014.10.07)
Transport: RTP/AVP;unicast;client_port=56224-56225


Received 214 new bytes of response data.
Received a complete SETUP response:
RTSP/1.0 200 OK
CSeq: 3
Date: Fri, Oct 17 2014 07:48:44 GMT
Transport: RTP/AVP;unicast;destination=192.168.1.12;source=192.168.1.12;client_port=56224-56225;server_port=6970-6971
Session: 476829A6;timeout=65


[URL:"rtsp://192.168.1.12:8554/camera0/"]: Set up the "video/JPEG" subsession (client ports 56224-56225)
[URL:"rtsp://192.168.1.12:8554/camera0/"]: Created a data sink for the "video/JPEG" subsession
Sending request: PLAY rtsp://192.168.1.12:8554/camera0/ RTSP/1.0
CSeq: 4
User-Agent: ./testProgs/testRTSPClient (LIVE555 Streaming Media v2014.10.07)
Session: 476829A6
Range: npt=0.000-


Received 187 new bytes of response data.
Received a complete PLAY response:
RTSP/1.0 200 OK
CSeq: 4
Date: Fri, Oct 17 2014 07:48:44 GMT
Range: npt=0.000-
Session: 476829A6
RTP-Info: url=rtsp://192.168.1.12:8554/camera0/track1;seq=52977;rtptime=2830850619


[URL:"rtsp://192.168.1.12:8554/camera0/"]: Started playing session...
^C

>> LocalMJpegUnicastServerMediaSubsession::createNewStreamSource() 
>> LocalMJpegUnicastServerMediaSubsession::createNewRTPSink()
> 
> The reason for this is that the first "createNewStreamSource()"/"createNewRTPSink()" calls are to create 'dummy' objects that the RTSP server uses to get the stream's SDP description (for the RTSP 'DESCRIBE" command).  These two objects are then deleted (thus the "FYI" above).  Then, 'real' source and sink objects are created.

Yes, that seems to be normal behavior.

So far there doesn't seem to be any error in what I'm trying to do, but the stream simply is not playing. Is there
really a startPlaying() being called for the replicated stream too?

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






More information about the live-devel mailing list