ffplay分析 (音视频同步:主时钟为音频)
《ffplay的數據結構分析》
《ffplay分析(從啟動到讀取線程的操作)》
《ffplay分析(視頻解碼線程的操作)》
《ffplay分析(音頻解碼線程的操作)》
《ffplay 分析(音頻從Frame(解碼后)隊列取數據到SDL輸出)》
《ffplay分析 (視頻從Frame(解碼后)隊列取數據到SDL輸出)》
《ffplay分析 (暫停 / 播放處理)》
《ffplay分析 (seek操作處理)》
《ffplay源碼(版本:ffmpeg-4.2.1)》
ffplay分析 (音視頻同步:主時鐘為音頻)
- 一、分析:
- 1、refresh_loop_wait_event():在refresh_loop_wait_event()函數內的remaining_time就是間隔判斷的休眠時間,這個值有默認值。但如果視頻快了這個值就是同步計算后返回的當前這一幀還要繼續顯示的時間,就會在這里休眠等待,但也不一定是多長時間都會休眠,返回的值要和默認的比較選擇一個更小的值進行休眠。這樣可以多次判斷更精準。
- 2、refresh_loop_wait_event():使用remaining_time調用video_fresh()進行視頻顯示,就會進行操作是接著往下顯示視頻幀還是保持顯示當前幀不變。
- 3、refresh_loop_wait_event():從Frame(解碼后)隊列中取出上一幀顯示的幀和將要顯示的一幀。并且進行判斷序列是否一樣,不同直接丟棄,獲取下一幀。
- 4、refresh_loop_wait_event():判斷是否是新的序列開始然后重置is->frame_timer,這個值表示在系統時間里上一幀的顯示時間,因為系統時間是變化的,只有使用系統時間才可以判斷每幀的顯示時長 是否到達了。
- 5、refresh_loop_wait_event():調用vp_duration()計算上一幀的持續時間(理論上的)
- 6、vp_duration():計算上一幀的持續時間(理論上的)
- 7、refresh_loop_wait_event():調用compute_target_delay()計算上一幀的持續時間(同步后實際上的)
- 8、compute_target_delay():判斷主時鐘不是視頻才行同步計算,獲取視頻時鐘與主時鐘的差值
- 9、compute_target_delay():根據delay(理論上的上一幀的顯示時長)設置同步閥值
- 10、compute_target_delay():使用diff差值和sync_threshold閥值判斷當前視頻與主時鐘相比是否快還是慢,計算上一幀(當前顯示的這)
- 11、refresh_loop_wait_event():獲取當前的系統時間和經過compute_target_delay()計算返回的當前顯示的幀的實際持續時長,判斷是否保持顯示當前的這一幀實行延時就是當前視頻快了,或往下走就是
- 12、refresh_loop_wait_event():此時可以顯示下一幀了,設置is->frame_timer新顯示的這一幀的系統時間
- 13、refresh_loop_wait_event():更新視頻時鐘
- 14、refresh_loop_wait_event():丟幀處理
- 15、refresh_loop_wait_event():到最后可以正常顯示新的一幀就是先調用frame_queue_next()移動讀索引,然后調用video_display()顯示新的一幀了
一、分析:
因為音頻和視頻解碼時間并不是都能在同一個時間點同時解碼完成進行播放,所以如果都在各自解碼完成后自主的直接播放就可能數據的時間點匹配不上。所以要有個基準的時間軸讓播放的數據匹配對應這個時間軸來進行播放。
ffplay 默認的音視頻同步方法就是音頻時鐘作為主時鐘,視頻同步音頻。音頻解碼完成直接播放,視頻就要實時的檢測音頻當前的時間點,進行匹配。
視頻播放時:
(1)通過一個循環播放和一個休眠時間間隔的判斷當前視頻時鐘和音頻時鐘的差值。
(2)這個差值有個閥值的范圍在范圍內都還是示為同步的,不作為處理,讓視頻幀按照duration顯示。如果差值是正數而且超出閥值范圍才表示視頻快了,此時當前顯示的視頻幀就要延長顯示時間。
(3)如果差值是負數而且超出閥值范圍才表示視頻慢了,此時當前顯示的視頻幀就要加快顯示時間。一般都是直接下一幀。而且如果還慢了一幀,就連當前將要顯示的幀都拋棄,再顯示下一幀。
1、refresh_loop_wait_event():在refresh_loop_wait_event()函數內的remaining_time就是間隔判斷的休眠時間,這個值有默認值。但如果視頻快了這個值就是同步計算后返回的當前這一幀還要繼續顯示的時間,就會在這里休眠等待,但也不一定是多長時間都會休眠,返回的值要和默認的比較選擇一個更小的值進行休眠。這樣可以多次判斷更精準。
2、refresh_loop_wait_event():使用remaining_time調用video_fresh()進行視頻顯示,就會進行操作是接著往下顯示視頻幀還是保持顯示當前幀不變。
3、refresh_loop_wait_event():從Frame(解碼后)隊列中取出上一幀顯示的幀和將要顯示的一幀。并且進行判斷序列是否一樣,不同直接丟棄,獲取下一幀。
4、refresh_loop_wait_event():判斷是否是新的序列開始然后重置is->frame_timer,這個值表示在系統時間里上一幀的顯示時間,因為系統時間是變化的,只有使用系統時間才可以判斷每幀的顯示時長 是否到達了。
5、refresh_loop_wait_event():調用vp_duration()計算上一幀的持續時間(理論上的)
6、vp_duration():計算上一幀的持續時間(理論上的)
7、refresh_loop_wait_event():調用compute_target_delay()計算上一幀的持續時間(同步后實際上的)
8、compute_target_delay():判斷主時鐘不是視頻才行同步計算,獲取視頻時鐘與主時鐘的差值
9、compute_target_delay():根據delay(理論上的上一幀的顯示時長)設置同步閥值
10、compute_target_delay():使用diff差值和sync_threshold閥值判斷當前視頻與主時鐘相比是否快還是慢,計算上一幀(當前顯示的這)
11、refresh_loop_wait_event():獲取當前的系統時間和經過compute_target_delay()計算返回的當前顯示的幀的實際持續時長,判斷是否保持顯示當前的這一幀實行延時就是當前視頻快了,或往下走就是
12、refresh_loop_wait_event():此時可以顯示下一幀了,設置is->frame_timer新顯示的這一幀的系統時間
13、refresh_loop_wait_event():更新視頻時鐘
14、refresh_loop_wait_event():丟幀處理
15、refresh_loop_wait_event():到最后可以正常顯示新的一幀就是先調用frame_queue_next()移動讀索引,然后調用video_display()顯示新的一幀了
總結
以上是生活随笔為你收集整理的ffplay分析 (音视频同步:主时钟为音频)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 颐和园可以拍照吗
- 下一篇: ffplay分析 (暂停 / 播放处理)