一 背景:
用户需要通过flash或手机看监控视频,而目前绝大多数摄像机都是RTSP协议,所以需要做一个中转。
参考资料:
http://blog.csdn.net/firehood_/article/details/8813587
http://blog.csdn.net/firehood_/article/details/8783589
这两篇文章详细说明了mp4v2保存文件和把264文件通过RTMP直播,对这两方面感兴趣的可以直接看这两文章。本文只是把这两文章中读264转存转发改成读rtsp转存转发,多了一点live555的内容,其他基本一样,只稍调整了一点点接口部分。
二 流程:
1 live555从摄像机读音视频,为了便于讲解这里只讨论视频。
2 mp4v2保存成.mp4
3 librtmp上传视频流到nginx
4 web用户通过flash观看
三 技术讲解:
1 live555读RTSP视频,可以参考playCommon.cpp或testRTSPClient.cpp,前者功能全,后者简洁一些,不过支持多路流同时访问。如果自己写RTSP Client,环境不是很复杂,可以参考这份代码。
RTSP接收到H264视频后,不管是读写文件还是发送流,主要的问题就在SPS和PPS上面。这两个名字这里不做解释,自行google,这里只讲怎么取到这两个参数。
读live的源码,注意 playCommon.cpp中有一段:
else if (strcmp(subsession->mediumName(), "video") == 0 &&
(strcmp(subsession->codecName(), "H264") == 0)) {
// For H.264 video stream, we use a special sink that adds 'start codes', and (at the start) the SPS and PPS NAL units:
fileSink = H264VideoFileSink::createNew(*env, outFileName,
subsession->fmtp_spropparametersets(),
fileSinkBufferSize, oneFilePerFrame);
}
这里调用H264VideoFileSink保存264文件,播放正常,所以我们需要研究H264VideoFileSink的源码。
只需注意H264VideoFileSink.cpp里面的afterGettingFrame函数,如下:
if (!fHaveWrittenFirstFrame) {
// If we have PPS/SPS NAL units encoded in a "sprop parameter string", prepend these to the file:
unsigned numSPropRecords;
SPropRecord* sPropRecords = parseSPropParameterSets(fSPropParameterSetsStr, numSPropRecords);
for (unsigned i = 0; i < numSPropRecords; ++i) {
addData(start_code, 4, presentationTime);
addData(sPropRecords[i].sPropBytes, sPropRecords[i].sPropLength, presentationTime);
}
delete[] sPropRecords;
fHaveWrittenFirstFrame = True; // for next time
}
// Write the input data to the file, with the start code in front:
addData(start_code, 4, presentationTime);
注释的很明显了,这里再简单说一下:
for (unsigned i = 0; i < numSPropRecords; ++i) {
addData(start_code, 4, presentationTime);
addData(sPropRecords[i].sPropBytes, sPropRecords[i].sPropLength, presentationTime);
}
这里的sPropRecords是从外面传进来的参数:subsession->fmtp_spropparametersets(),从名字上看就是sps和pps合在一起的内容。
debug就可以发现,numSPropRecords==2,for循环两次,第一次是sps,第二次就是pps了。把这两个记住,保存264和发送RTMP时写在相应的位置,所有的工作基本就完成了。
2 mp4v2的api非常简单,没什么好说,唯一注意一点就是先从sps中读取视频的宽和高。可以参考后面代码。
3 librtmp,也很简单,只要注意先发关sps和pps
4 直播服务器用nginx+nginx_rtmp_module, google一下,文档很多。
四 运行环境: CentOS6.4及Ubuntu 12下运行正常。windows也可以,多平台时需要类型统一,比如UINT,BYTE,uint32_t, uint8_t ,稍稍改动一下就好。