最近遇到有人问live555视频直播的问题,刚好前段时间接触过,这个功能可以通过读内存数据实现;
具体实现方式是参考的这篇文章思路,可以先了解一下看看:
http://blog.chinaunix.net/uid-15063109-id-132142.html
live555源码里面有一个读文件的测试demo,live555mediaserver,本文修改这份源码实现读内存直播功能;
首先先了解一下live555数据流和live555mediaserver demo中的函数调用层次,以H264为例:
由以上两个图可知,要想实现直播功能,有两个方案:
1)修改BypteStreamFileSource类中的 读取文件代码,改成从内存中读取,这个方案修改最简单,但是会破坏Live555框架的源码
2)参考BypteStreamFileSource写一个ByteStreamLiveSource,修改读文件部分;
由于source是由H264VideoFileServerMediaSubsession创建并调用的,所以要同步新建一个H264VideoLiveServerMediaSubsession类
这里只讨论第二种方案,下面看代码:
1)DynamicRTSPServer.cpp 中 createNewSMS函数:
} else if (strcmp(extension, ".264") == 0) {
// Assumed to be a H.264 Video Elementary Stream file:
NEW_SMS("H.264 Video");
OutPacketBuffer::maxSize = 100000; // allow for some possibly large H.264 frames
sms->addSubsession(H264VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource));
} else if (strcmp(extension, ".265") == 0) {
上面的代码就是根据RTSP请求中文件名的后缀调用不同的码流解析类,由于我们新建了一个 H264VideoLiveServerMediaSubsession 类,这里要改成
sms->addSubsession(H264VideoLiveServerMediaSubsession::createNew(env, fileName, reuseSource));
2)修改H264VideoLiveServerMediaSubsession类修改createNewStreamSource函数
FramedSource* H264VideoLiveServerMediaSubsession::createNewStreamSource(unsigned clientSessionId, unsigned& estBitrate)
{
/* Remain to do : assign estBitrate */
estBitrate = 1000; // kbps, estimate
// Create the video source:
ByteStreamLiveSource* liveSource = ByteStreamLiveSource::createNew(envir(), fFileName);
//ByteStreamFileSource* liveSource = ByteStreamFileSource::createNew(envir(), fFileName);
if (liveSource == NULL)
{
return NULL;
}
// Create a framer for the Video Elementary Stream:
return H264VideoStreamFramer::createNew(envir(), liveSource);
}
3)ByteStreamLiveSource修改
void ByteStreamFileSource::doGetNextFrame() {
if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
handleClosure();
return;
}
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
doReadFromFile();
#else
if (!fHaveStartedReading) {
// Await readable data from the file:
envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
(TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
fHaveStartedReading = True;
}
#endif
}
上面ByteStreamFileSource是读取文件代码,只要在新建的ByteStreamLiveSource为中添加一个doReadFromBuffer函数,实现从内存中读取功能,然后替换掉doReadFromFile函数就OK了,像这样:
void ByteStreamLiveSource::doGetNextFrame() {
// if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
// handleClosure();
// return;
// }
#ifdef READ_FROM_FILES_SYNCHRONOUSLY
doReadFromBuffer();
#else
if (!fHaveStartedReading) {
// Await readable data from the file:
envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
(TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
fHaveStartedReading = True;
}
#endif
}
doReadFromBuffer需要拷贝码流数据到 fTo 缓冲区,实现也比较简单,这里就不写了。
H264VideoLiveServerMediaSubsession类和ByteStreamLiveSource类源文件地址:
http://download.csdn.net/detail/lifexx/9654860
ps: 源文件无法执行,仅供参考