《ffplay的數據結構分析》
《ffplay分析(從啟動到讀取線程的操作)》
《ffplay分析(視頻解碼線程的操作)》
《ffplay分析(音頻解碼線程的操作)》
《ffplay 分析(音頻從Frame(解碼后)隊列取數據到SDL輸出)》
《ffplay分析 (音視頻同步:主時鐘為音頻)》
《ffplay分析 (暫停 / 播放處理)》
《ffplay分析 (seek操作處理)》
《ffplay源碼(版本:ffmpeg-4.2.1)》
ffplay分析 (視頻從解碼后隊列取數據到SDL輸出)
- 一、分析:
- 1、main():在main()函數開始時有創建SDL窗口的處理
- 2、read_thread():開啟讀取線程后,在read_thread()讀取數據線程中設置視頻流時調用set_default_window_size()設置顯示窗口的默認大小和渲染區域大小
- 3、set_default_window_size():判斷命令行是否有指定寬高沒有就使用幀寬高,作為窗口寬高調用calculate_display_rect()計算渲染區域
- 4、calculate_display_rect():使用像素比例計算實際寬高比
- 5、calculate_display_rect():首先使用高度為基準計算渲染區域,如果寬度大于實際窗口再以寬度為基準重新計算
- 6、calculate_display_rect():計算保存返回上層的渲染區域參數
- 7、event_loop():SDL的事件循環調用了refresh_loop_wait_event()進行更新顯示和獲取SDL事件(在主線程更新,event_loop()在主線程調用)
- 8、refresh_loop_wait_event():調用SDL_PumpEvents()、SDL_PeepEvents()、獲取SDL事件。如果沒有事件才進入while更新畫面,否則返回上一層處理相應事件。
- 9、refresh_loop_wait_event():調用usleep()等待同步和設置remaining_time默認等待時間
- 10、refresh_loop_wait_event():調用video_refresh()進行視頻更新
- 11、video_refresh():判斷是否是實時流操作
- 12、video_refresh():判斷是否是音頻流顯示操作
- 13、video_refresh():視頻流顯示操作,如果沒有數據就什么不做
- 14、video_refresh():獲取上一幀顯示的幀和將要顯示的一幀,用來計算同步時間操作
- 15、video_refresh():判斷將要顯示的一幀的序列與現在解碼的不同就直接拋棄,重新獲取
- 16、video_refresh():判斷是否是新的播放序列,重置is->frame_timer
- 17、video_refresh():判斷是否暫停,直接保持顯示
- 18、video_refresh():計算上一幀持續顯示的時長
- 19、video_refresh():根據計算得到的delay判斷是否繼續顯示上一幀還是往下走繼續更新
- 20、video_refresh():根據is->frame_timer用于下一輪的操作
- 21、video_refresh():更新當前的視頻時鐘
- 22、video_refresh():判斷是否進行丟幀處理
- 23、video_refresh():調用frame_queue_next()移動到下一幀
- 24、video_refresh():調用video_display()真正開始渲染畫面的操作
- 25、video_display():判斷是視頻流調用video_image_display()顯示
- 26、video_image_display():獲取將要顯示的這一幀
- 27、video_image_display():調用calculate_display_rect()根據窗口比例計算渲染區域(圖像)的寬高,調用upload_texture()將frame的yuv更新到is->vid_texture(SDL_Texture)
- 28、video_display():video_image_display()結束后,返回到video_display()最終調用SDL_RenderPresent()顯示畫面