FFMPEG多線程解碼
FFMPEG多線程編碼器一般以在Slice內分功能模塊進行多線程編碼,如h263,h263P,msmpeg(v1, v2, v3),wmv1。包含以下幾個線程:(1)Pre_estimation_motion_thread運動估計前的準備;(2)Estimation_motion_thread運動估計;(3)Mb_var_thread宏塊其他變量;(4)Encode_thread編碼主線程。當然也有例外,如FFV1編碼器按Slice為線程單位進行多線程編碼。
FFMPEG多線程解碼器分為Frame級和Slice級兩種,Slice級多線程同時解碼一幀中不同的部分。Frame級多線程同時接受多幀碼流,實現并行解碼,當前幀處于顯示狀態時,未來的幾幀已經在其他線程中被解碼。
1.???????? Slice Threading
???????? FFmpeg中,dvvideo_decoder, ffv1_decoder, h264_decoder, mpeg2_video_decoder和mpeg_video_decoder均支持了Slice Threading。
實現方法是:首先為codecContext注冊注冊多線程處理函數excute(),Codec解碼過程中處理Slice時調用avctx->excute()。excute()啟動Slice解碼工作線程開始多線程解碼,同時快速返回開始下一Slice的解析和解碼。
Frame Threading主線程和解碼線程的同步如圖1所示。
圖1 Frame Threading主線程和解碼線程的同步
2.???????? Frame Threading
???????? 目前為止支持Frame Threading的解碼器有h264_decoder, huffyuv_decoder, ffvhuff_decoder, mdec_decoder, mimic_decoder, mpeg4_decoder, theora_decoder, vp3_decoder和vp8_decoder。
???????? Frame Threading有如下限制:用戶函數draw_horiz_band()必須是線程安全的;為了提升性能,用戶應該為codec提供線程安全的get_buffer()回調函數;用戶必須能處理多線程帶來的延時。另外,支持Frame Threading的codec要求每個包包含一個完整幀。Buffer內容在ff_thread_await_progress()調用之前不能讀,同樣,包括加邊draw_edges()在內的處理,在ff_thread_report_progress()調用之后,Buffer內容不能寫。
???????? 每個線程都有以下四個狀態。如圖2所示,為了保證線程安全,若Codec未實現update_thread_context()和線程安全的get_buffer(),則必須在解碼完成后才能將狀態轉換為STATUS_SETUP_FINISHED,意味著下一個線程只能在當前線程解碼完成后才能開始解碼。
而如圖3所示,如果Codec實現update_thread_context()和線程安全的get_buffer(),線程狀態可以在解碼開始之前轉換為STATUS_SETUP_FINISHED,這樣,下一個線程就可能與當前線程并行。
圖2 Codec未實現update_thread_context()和線程安全的get_buffer(),線程狀態轉換
圖3 Codec實現update_thread_context()和線程安全的get_buffer(),線程狀態轉換
???????? 解碼主線程通過調用submit_packet()將碼流交給對應的解碼線程。主線程和解碼線程的同步如圖4所示。
圖4 Frame Threading主線程和解碼線程的同步