[Live-devel] Trouble streaming JPEG

Tom Aylesworth taylesworth at realitymobile.com
Tue Aug 30 08:05:22 PDT 2011


I'm using the DarwinInjector class to stream JPEG to our server.  (Yes, I know -- we ultimately don't plan to use JPEG but it lets us get the framework in place quickly.)  I have no trouble sending JPEG frames of ~10K (plus or minus 2K) but when sending higher resolution frames (480x360) of ~40K we see a lot of image corruption starting about halfway through the image that looks very much like what I'd expect from a buffer being overwritten before its prior contents had been sent.  Strangely, this doesn't appear related to frame rate.  If I limit my video source to only produce a frame per second, I get the same results.

I've attached my JpegCaptureDeviceSource class which provides the JPEGVideoSource implementation for my video source.  It's heavily based on the ElphelJPEGDeviceSource sample but since our video source doesn't provide a pull mechanism, I added two new public methods for it to provide data to JpegCaptureDeviceSource.  The gotAFrame() method provides the image data and JPEG quality.  The close() method tells it that the source won't provide more data.  It's using the Live 555 event mechanism to trigger our task scheduler to deliver the frame.  The only other change from Elphel is that we need to pull the quantization tables from the JPEG header.

Our video capture code (which we already had and works great in our existing product) runs on its own thread, captures an image in JPEG format and calls JpegCaptureDeviceSource::gotAFrame().  It also passes in a frameObj which contains state data about the frame.  It then waits and doesn't provide another frame until JpegCaptureDeviceSource::deliverFrameToClient() calls doneWithFrame() with that same frameObj.  This makes me somewhat confident that there are no buffer overwrites on our end.  By time we start capturing another frame, we've already copied the image data into the fTo buffer in FramedSource.

Here's the code that sets up the DarwinInjector, source, and sink.  (If the syntax looks strange it's because it's Objective-C++ which we are using as a thin interface layer between our Objective-C application and the Live555 C++ code.)  Obviously, this runs on its own thread.

// create Darwin injector
DarwinInjector * injector = DarwinInjector::createNew(*self.rtspEnvironment, progName, verbosityLevel);


// create video sink
struct in_addr dummyDestAddress;
dummyDestAddress.s_addr = 0;
Groupsock rtpGroupsockVideo(*self.rtspEnvironment, dummyDestAddress, 0, 0);
Groupsock rtcpGroupsockVideo(*self.rtspEnvironment, dummyDestAddress, 0, 0);
self.videoSink = JPEGVideoRTPSink::createNew(*self.rtspEnvironment, &rtpGroupsockVideo);


// create video source
self.videoSource = JpegCaptureDeviceSource::createNew(*self.rtspEnvironment);
if (self.videoSource == NULL)
{
*self.rtspEnvironment << "Unable to open video source: " << self.rtspEnvironment->getResultMsg() << "\n";
[self shutdownWithExitCode:1];
}


*self.rtspEnvironment << "Starting video capture device...\n";
self.videoSink->startPlaying(*self.videoSource, afterPlaying, self.videoSink);


// create rtcp channel
const unsigned estimatedSessionBandwidthVideo = 2000; // in kbps; for RTCP b/w share
const unsigned maxCNAMElen = 100;
unsigned char CNAME[maxCNAMElen+1];
gethostname((char*)CNAME, maxCNAMElen);
CNAME[maxCNAMElen] = '\0'; // just in case
RTCPInstance* videoRTCP = RTCPInstance::createNew(*self.rtspEnvironment, &rtcpGroupsockVideo,
estimatedSessionBandwidthVideo, CNAME,
videoSink, NULL /* we're a server */);


// connect rtp and rtcp channels to Darwin injector
injector->addStream(videoSink, videoRTCP);


// connect to server and start streaming data
if (!injector->setDestination([self.rtspServer UTF8String],
[self.rtspFile UTF8String],
"Cannonball",
"Cannonball live stream"))
{
*self.rtspEnvironment << "injector->setDestination() failed: " << self.rtspEnvironment->getResultMsg() << "\n";
[self shutdownWithExitCode:1];
return;
}


*self.rtspEnvironment << "Play this stream (from the Darwin Streaming Server) using the URL:\n"
<< "\trtsp://" << [self.rtspServer UTF8String] << "/" << [self.rtspFile UTF8String] << "\n";


// never returns
self.rtspEnvironment->taskScheduler().doEventLoop();

Any thoughts about what might be causing the issue we are seeing with streaming larger images?  Is there something I need to configure to handle larger images, maybe on the sink (RTP) side?

Thanks,

Thomas Aylesworth

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20110830/12f93520/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JpegCaptureDeviceSource.cpp
Type: application/octet-stream
Size: 6097 bytes
Desc: JpegCaptureDeviceSource.cpp
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20110830/12f93520/attachment-0002.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20110830/12f93520/attachment-0002.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JpegCaptureDeviceSource.hh
Type: application/octet-stream
Size: 1897 bytes
Desc: JpegCaptureDeviceSource.hh
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20110830/12f93520/attachment-0003.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.live555.com/pipermail/live-devel/attachments/20110830/12f93520/attachment-0003.htm>


More information about the live-devel mailing list