YUV视频花屏分析
本文的转载得到了零声教育的QQ同意。
1. 前言
视频花屏是多媒体工程师最常见的问题之一,也是最棘手的问题之一,笔者此前也数次遇到这样的问题,今天在此总结分享下经验。
本文分析的重点是视频录制过程中引起的花屏问题,粗浅涉及视频播放。但是其中都不会涉及到编码器或者解码器本身所引起的花屏问题。
本文所用到的测试资源如下图:
2. 视频花屏问题定位
当遇到视频花屏时,首先要定位是最先出现的花屏的是哪个阶段产生的花屏。以视频录制为例,其具体流程如下:
采集阶段不属于本文分析范畴
通过使用其它播放器播放视频和检验采集到的原始数据这两种手段可以定位到具体的问题。具体步骤如下:
3. 视频花屏三种类型
常见视频花屏有以下三种原因造成:
- 渲染脏数据
- 丢帧
- 图像格式转换
3.1 渲染脏数据
渲染脏数据是未完成渲染的数据。具体来讲就是在视频帧渲染到一半的时候,即被送到编码器编码。
此问题发生在视频渲染阶段。
3.1.1 特征
(1)图像具有明显的撕裂或者错位特征
渲染脏数据造成的结果就是该图像一半是当前帧的数据,另一半是上一帧的数据
(2)渲染脏数据通常不会造成持续型的花屏现象
如下图所示,图片中上下存在明显错位的现象。
PS:一般脏数据的渲染结果不一定像下图中那么规则。
3.1.2 产生原因与解决方法
以笔者的经验产生的原因有两类:
通过glReadPixels等类似方法从OpenGL获取数据,在draw和glReadPixels中间没有等待绘制完
解决方法是:在draw和glReadPixels中间调用glFinish方法
PS:
(1)不要滥用glFinish方法,该函数会严重影响渲染效率,如果不是立即从GPU中读取数据的话可采用glFlush代替
(2)glReadPixels非常非常耗时,建议新建一个新的渲染线程,把数据在新线程中重新渲染一遍,然后调用glReadPixels
如果多个渲染线程通过共享纹理的方式进行工作,确认该纹理在多个线程中工作是否互斥行为。
如前文提到的开辟一个渲染线程专门进行glReadPixels操作,如果有这样类似的行为尽量采用多缓冲机制。
PS:笔者的经验是当存在多个渲染线程
3.1.3 总结
解决此问题的方法就是等该帧渲染完成后再捕获渲染后的数据,同时需要注意的性能问题。具体方法有多缓冲:
(1)加锁
最简单的方法,但是慎用会影响渲染效率
(2)多缓冲
这是必须的
(3)glFlush/glFinish
笔者的经验是普通绘制完毕后调用glFlush,在glReadPixels方法前调用glFinish。
3.2 丢帧
此处所说丢帧丢弃的是视频编码后的视频帧,通常发生在复用(Mux)阶段。
由于视频编码后帧之间存在依赖关系,丢帧会带来极其严重花屏效果,并且具有持续性影响。
此问题发生在视频编码阶段。
3.2.1 特征
(1)纯粹的花屏,且花屏效果没有明显的规则性(比如撕裂、错位)
(2)连续多帧存在花屏现象
如下图所示:
3.2.2 产生原因与解决方法
产生原因
视频帧时间戳(PTS)不对
由于大部分复用器(Muxer)都严格要求视频帧PTS是严格递增的,比如ffmpeg中mp4 Muxer如果当前帧的PTS小于或等于前一帧的PTS,那么该帧就不会被写入文件,ffmpeg会报”Invalid pts”错误。
视频向音频同步引发丢帧
缓冲队列溢出
解决方法
引发此问题的原因众多,具体案例具体分析。关键是确认花屏是由于丢帧引起的,以及什么原因引发的丢帧。
后面介绍几种视频分析方法,帮助确认丢帧的问题。
3.3 图像格式转换
在视频编解码中必然会涉及到YUV和RGB图像格式的转换,并且YUV还有多种格式。如果转换格式或者算法不正确也会引发视频花屏问题。
此问题发生在视频渲染或者播放阶段。
3.3.1 特征
由YUV与RGB图像格式转换引发的花屏现象有很多无法判断,但是有一种情况基本可以判定是由于此原因引发的:
(1)图像的黑白数据是正常的,但是色彩不正常,比如色彩偏色、甚至错乱。
(2)图像整体依然处于可识别的状态,但是存在明显的彩色斑块
如下图所示:
3.3.2 产生原因与解决方法
产生原因
YUV格式错误
YUV有很多种格式,任意两种之间都都会造成转换出来的图像存在巨大差异。
图片大小
给格式转换算法设置的宽高和图像本身存在微小差异。
比如笔者在Android MTK机型上遇到过,MTK为了做GPU数据对其优化,是得GPU产出的图像分辨率和常规分辨率存在微小差距,最后造成图像色彩混乱,修复后还存在绿边问题,需要特色处理。
图像转换算法
(1)不同的图像制式对应RGB与YUV转换矩阵不同,其转换的色彩也存在偏差。
(2)目前大部分采用硬件加速的技术(GPU)实现图像格式转换,不同平台可能存在差异。
解决方法
首先把YUV数据保存下来,然后用专门的工具对其进行转换,查看转换效果,然后做进一步的分析。
YUV240P数据如下图所示:
总结:
(1)图像的黑白数据是基本正常的,色彩混乱:
可能是由于错误的图像大小引发的,亦可能是由于算法不支持该图像的分辨率引起的
(2)图像整体依然处于可识别的状态,但是存在明显的彩色斑块
基本确认是由于错误地识别YUV格式引起的(我很确定地告诉你,你把YUV420P和NV12搞混了)
4. 视频分析工具与使用
4.1 视频丢帧分析
4.1.1 ffprobe
ffprobe是FFmpeg里面比较重要的一个工具,在此不在多说了。
(1) 获取帧信息
ffprobe -show_frames We_Are_Young.mp4 > frames.info
(2)统计I帧数量
keyframe=1 : key frame
pict_type=I : I-frame
cat frames.info | grep “pict_type=I” |wc -l
(3)统计视频帧数量
cat frames.info | grep “media_type=video” |wc -l
ffprobe -show_format -show_streams filename
4.1.2 VideoEye
VideoEye[2]是雷霄骅开发的一款视频分析工具,功能很多,比较强大。
项目主页
SourceForge:https://sourceforge.net/projects/videoeye/
Github:https://github.com/leixiaohua1020/VideoEye
开源中国:
http://git.oschina.net/leixiaohua1020/VideoEye
具体操作和介绍参见开源实时视频码流分析软件:VideoEye
下面这张图是视频PTS分析的截图
4.2 YUV分析
4.2.1 YUV与RGB格式转换
(1)视频
ffmpeg -i VID20160412102008.mp4 -c:v rawvideo -pix_fmt yuv420p out.yuv
(2)图像
RGB ==> YUV
ffmpeg -i a.bmp -pix_fmt yuv420p -y a.yuv
YUV ==> RGB
ffmpeg -pix_fmt yuv420p -video_size 352x288 -i a.yuv -y b.bmp
4.2.2 YUV预览
不管用什么工具都必须知道YUV数据的宽高信息,否则无法对YUV数据进行分析。
ffplay
ffplay -f rawvideo -video_size 640x480 test.yuv
mplayer
mplayer name.yuv -demuxer rawvideo -rawvideo w=352:h=288
mpv
mpv VID.yuv --demuxer=rawvideo --demuxer-rawvideo-w=720 --demuxer-rawvideo-h=1280
GLYUVPlay
GLYUVPlay是MAC上一款查看YUV数据的工具,官方网站为
http://bax.comlab.uni-rostock.de/en/projects/glyuvplay/
下面是其截图