視訊花屏分析

微巖發表於2017-05-12

1. 前言

視訊花屏是多媒體工程師最常見的問題之一,也是最棘手的問題之一,筆者此前也數次遇到這樣的問題,今天在此總結分享下經驗。

本文分析的重點是視訊錄製過程中引起的花屏問題,粗淺涉及視訊播放。但是其中都不會涉及到編碼器或者解碼器本身所引起的花屏問題。

本文所用到的測試資源如下圖:
這裡寫圖片描述


2. 視訊花屏問題定位

當遇到視訊花屏時,首先要定位是最先出現的花屏的是哪個階段產生的花屏。以視訊錄製為例,其具體流程如下:

這裡寫圖片描述

採集階段不屬於本文分析範疇
通過使用其它播放器播放視訊和檢驗採集到的原始資料這兩種手段可以定位到具體的問題。具體步驟如下:

Created with Raphaël 2.1.0開始更換播放器是否花屏?渲染資料是否花屏?原始資料是否花屏?採集問題結束渲染問題編碼問題播放解碼問題yesnoyesnoyesno

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/
下面是其截圖
這裡寫圖片描述


5. 參考文獻

[1] wikipedia YUV
[2] 開源實時視訊碼流分析軟體:VideoEye

相關文章