HK + FFMPEG + X264 + QSV + libRTMP + FMS踩了坑

来源:互联网 发布:字幕时间轴调整软件 编辑:程序博客网 时间:2024/05/16 18:19

最近自己写一个软件,利用海康摄像机的RTSP流通过ffmpeg拉取之后解码成YUV进行相关细节处理,在用X264或者QSV编码,通过rtmp发送到fms的程序。


为了保证程序的稳定性,界面配置控制层和底层转码,图像处理,图像合成等采用了多进程的方式,就是为了方便底层可能不稳定从而易维护(其实就是为了偷懒,真内存泄漏啦啥的,直接结束进程在拉起来,图像中断不超过500ms,感觉挺划算)。


谁知道,踩了坑了。


1.librtmp推流到fms,过一段时间后(这个时间一般是若干小时),从fms拉出来的图像,播放器播放仅能播放第一个I帧,后续的帧解码不出来。不显示。查看流的信息后发现,帧确实收到了,但是没有时间戳,时间戳都是0.所以应该是哪里的时间戳出了问题。使用rtmp我没有采用他的扩展时间戳,是将毫秒级的时间%0xFFFFFF来做的,即到了24位的时间就归零。确实没看出什么问题。但是librtmp的内部其实已经针对时间戳和扩展时间戳做了处理。在 RTMP_SendPacket 中


中已经有了相关的超出0xFFFFFF时间的处理方式,所以其实直接赋值毫秒级时间戳即可。改正之后,貌似问题消失了。当然针对时间戳必须严格递增,音视频必须同一时间轴时间递增,这些是必须的了,算是一个坑吧。


2.关于X264编码,如果我们为了低延时,一般都会采用 zerolatency 的方式进行编码,在x264中,此种方式默认开启了多线程编码,即一帧视频,为了尽可能少的延时,会采用多slice的方式进行编码,实际我们从x264输出的数据可以看出,一帧分为了几个slice,分别按照首尾顺序给出。并且帧间的分隔符即H.264的头为 00 00 00 01 而,slice间的分隔头为00 00 01 这就是我们看到的H.264数据有两种分隔符的原因(是否采用了多slice编码)。按照rtmp发送数据单一的slice不能单独的做为I帧或者P帧组包,目前我采用的方式是将slice合并成一个完整的帧在通过协议发送出去。

再此,附上h.264封装librtmp所需要封装的flv tag头 
I帧的body头封装:

P帧的头封装

3.YUV数据的透明叠加,

 我们知道YUV数据中Y为灰度值,UV为颜色,在YUV图像合成的过程中,直接complex是整个空间的替换。也有朋友会说,我的这一套为啥这么麻烦,直接调用ffmpeg的命令行,拉取ffmpeg -re -i rtsp://xxxxxx  -vcodec copy -an -f flv rtmp://xxxx  就搞定了,就算是有视频合成,叠加,添加一个参数进去就好了。其实我是为了视频流不中断,又可以随时叠加图片LOGO,GIF,视频等,并且可以随时调整位置才搞的。再编码可以保持数据流一直通畅,动态的进行YUV数据的叠加处理就可以搞定。

扯远了,YUV数据的透明叠加,其实分析数据发现,带有透明图层的YUV(png图片解码后的YUV40P),需要透明的部分,Y一般值为 0x10, U 一般值为 0x80, V一般值为0x80,OK 知道了这些近似的数值,直接叠加处理就好了... 看起来效果还是不错的!

不写了,先到这,最终还美化了下界面,纯属吃饱了没事干。

原创粉丝点击