P2PSDK 对接外部音视频采集播放的常见问题(以直播模块C++版为例)
1、什么是外部视频采集?
在是P2PSDK播放视频是,有时候视频源不是本机的默认摄像头,需要从外部获取视频流,这个时候就需要将视频流输入到P2PSDK,这个过程就叫做对接外部视频采集。
2、对接了外部视频采集,播放端连接视频打不开。
- 1)用播放端观看:下方的视频帧统计为0.
这个时候基本可以判断外部采集对接失败,外部采集视频流数据没有传入SDK。检查一下步骤:
1.是否在初始化设置启用外部采集采集。
1 |
String sInitParam = "(VideoInExternal){1}" + ...; |
2.是否注册视频采集回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
pgDevVideoIn.SetCallback(m_oVideoInCB); ... public pgDevVideoIn.OnCallback m_oVideoInCB = new pgDevVideoIn.OnCallback() { @Override public int Open(int iDevNO, int iPixBytes, int iWidth, int iHeight, int iBitRate, int iFrmRate, int iKeyFrmRate) { // TODO Auto-generated method stub Log.d("pgLiveCapExter", "pgDevVideoIn.OnCallback.Open"); // The iDevID is '1234'. int iDevID = 1234; ... return iDevID; } @Override public void Close(int iDevID) { // TODO Auto-generated method stub ... Log.d("pgLiveCapExter", "pgDevVideoIn.OnCallback.Close"); } @Override public void Ctrl(int iDevID, int iCtrl, int iParam) { // TODO Auto-generated method stub Log.d("pgLiveCapExter", "pgDevVideoIn.OnCallback.Ctrl"); ... } }; ... pgDevVideoIn.CaptureProcExt(iDevID, data, 0, data.length, iFormat, isKeyFrame); |
需要注意的是iDevNo和iDevID的区别:
iDevNo是由SDK传入,调用VideoStart是定义的 CameraNo值会作为iDevNo传到这里。可以抽象理解为摄像头设备ID。
iDevID是回调函数的返回值,中间件内部可以用来识别输入的不同的视频流,同时在调用 pgDevVideoIn.CaptureProcExt 时作为第一个参数输入。
一般SDK回调Open时通知设备开始采集视频,设备采集到视频后在另外的线程调用 pgDevVideoIn.CaptureProcExt 将视频数据输入SDK,SDK回调Close时通知设备停止采集,SDK回调Close之后调用 pgDevVideoIn.CaptureProc* 数据将不被SDK接受。同时会在日志中看到 “CPGSysCommonDevice::DevVideoInCaptureProc: not found validable callback, iDevID=” 的打印。(以上例子源码是安卓Java版本,C语言版本的原理一致,API命名略有不同)
- 2)用播放端观看看到到了视频帧统计数据不为0.但是依旧黑屏。
这个时候可以判定视频无法解码,视频无法解码有几种情况:
- 视频采集是设置的Mode和实际的视频分辨率数据不一致。如果视频源不是P2PSDK定义的标准分辨率,那么就需要参考文档,设置一个特别的分辨率。查看《P2P 直播模块C++开发手册 v1.19.doc》 中的pgLiveVideoModeSize函数
关键帧格式不对,我们要求的关键帧格式是00 00 00 01+ SPS +00 00 00 01+ PPS+00 00 00 01+ IFrame。 其中00 00 00 01是H264协议文档中定义的Start Code(更严谨的说法是H264标准中支持的Start Code有可以是00 00 01或者00 00 00 01,大部分设备都是使用00 00 00 01作为Start code 也不排除有些视频帧Start code是00 00 01)。 SPS 和PPS是一些视频的参数数据。具体的细节可以下载H264的文档查看。 建议查看《H.264-AVC-ISO_IEC_14496-10.pdf》第211页(直播SDK 1.43.1 版本之后SDK支持设置SDK内部自组帧)

关于H264协议的简要定义说明:
H264中视频帧和一些视频帧的信息都被定义为 NAL ,每个NAL都由StartCode分开,StartCode之后的第一位数据带有NAL的类型数据,参考ffmpeg的NAL类型定义
https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/h264.h
参考博客怎样获取nal类型:
http://www.cnblogs.com/545235abc/p/4091182.html
P2PSDK要求传入SDK的视频数据,关键帧前面需要带有SPS和PPS才能解码。
在实践中发现,使用RTSP等协议库获取到的视频帧,关键帧前面可能没有带StartCode,也没有带SPS和PPS。而是在RTSP之前的握手中将SPS和PPS加密传输到了RTSP客户端,这个时候就需要在将关键帧传入P2PSDK中时将SPS、PPS、StartCode、关键帧拼接到一起后再传入到P2P SDK 。
附:
音频对接时常见问题
1、 传输音频格式
格式 | PCM16(一个采样16位2字节) |
采样 | 11025 |
帧率 | 25 |
单帧采样数 | 441 |
单帧数据大小 | 882 Byte |
单帧播放时间 | 40ms |
声道 | 单声道 |
SDK外部采集和输出的音频格式如上所有,如果设备采集到的音频不支持以上格式,就需要通过各种方法转换成以上格式传入我们的SDK,我们SDK也支持配置转换。或者播放器 不支持上述格式,也需要进行格式转换。
2、回调函数的关键返回值
回调函数 pfnAudioOutOpen 、 pfnAudioInOpen 、 pfnVideoInOpen 、 pfnVideoOutOpen 需要返回一个大于0 的数,否则失败。
回调 pfnAudioOutPlay 需要返回 uDataSize ,如果返回值小于uDataSize或者等于0,那么SDK会认为音频数据没有接收完成,将会重发音频数据。如果返回0,将会无法输出正确的音频。