<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          FFmpeg 中的多線程解碼

          共 2979字,需瀏覽 6分鐘

           ·

          2022-03-05 12:08

          ffmpeg 中使用到的多線程的概念:

          共享變量的互斥

          互斥鎖(mutex-lock)是一種信號量,用來防止兩個線程在同一時刻訪問相同的共享資源,它有鎖定狀態(tài)和非鎖定狀態(tài)。

          在任意時刻,一個線程要想存取共享數(shù)據(jù),線程必須首先獲得mutex-lock,當此線程釋放此共享數(shù)據(jù)的時候必須對mutex-lock解鎖,在一個任意的時間內(nèi),只有一個線程能鎖定互斥鎖,通過函數(shù)pthread_mutex_lock上鎖,通過函數(shù)pthread_mutex_unlock解鎖。

          同步條件變量

          條件變量用來提供另一種線程同步的方法,其基于實際的變量值來實現(xiàn)線程的同步操作,設(shè)置了條件變量的情況下,線程就不需要通過不停的輪詢來查詢條件是否滿足,也不需要不停的忙等,從而能夠節(jié)省很多系統(tǒng)資源。

          一個條件變量總是和一個mutex-lock對應(yīng),系統(tǒng)通過pthread_cond_await函數(shù)來阻塞調(diào)用的線程,一直到條件變量得到滿足。

          當這個線程阻塞的時候?qū)?yīng)的mutex-lock會自動解鎖,但當該線程運行的時候,其對應(yīng)的mutex-lock會被加鎖。

          使用函數(shù)pthread_cond_signal來喚醒等待在條件變量的另一個線程,當用來喚醒多個處于阻塞狀態(tài)線程時通過pthread_cond_broadcast函數(shù)來完成。

          ffmpeg實現(xiàn)多線程方案:

          Thread List,線程列表,線程列表中的每一項都映射一個解碼線程。

          主線程會從線程列表中按照序號由小到大(循環(huán))提取解碼線程,并把解碼任務(wù)提交到該解碼線程。

          同時主線程在提交完解碼任務(wù)后也會從線程列表中按照序號由小到大(循環(huán))提取解碼線程,并嘗試從該解碼線程獲取解碼完成的幀。

          M,主線程,主要目的有兩個:

          • 向解碼線程提交解碼任務(wù)。FFmpeg中是以packet為單位進行解碼任務(wù)的提交的,按照前一小節(jié)的描述,F(xiàn)Fmpeg就是以frame為單位進行解碼任務(wù)的提交的。

          • 從解碼線程獲取解碼所得的幀并進行返回。

            不過在第一輪進行任務(wù)提交的時候是不會去獲取幀,在第一輪任務(wù)提交完成后,此時所有解碼線程都已經(jīng)開始進行了解碼作業(yè),那么主線程就可以開始等待第一個線程解碼完成,然后嘗試去獲得解碼完成的幀。

            這里的“嘗試”,是因為就像單線程解碼時那樣,并不一定是每次調(diào)用解碼API都會返回一幀的。由于h264編碼的視頻中常常包含B幀,這會使得碼流的解碼順序并非幀的播放順序,但是解碼API必須按照幀的播放順序進行返回,因此在進行幀的返回時會進行相應(yīng)的調(diào)整。

            接下來每次向一個線程提交一個解碼任務(wù)后,都需要等待下一個線程空閑并嘗試返回幀。

          • T,解碼線程,接收解碼任務(wù)并進行解碼。解碼線程是以frame為單位進行處理的。解碼線程解碼主線程所提交的packet,執(zhí)行與單線程時一樣的解碼作業(yè)。

          ffmpeg中的多線程解碼主要分為片 Slice級別的多線程解碼 和 幀F(xiàn)rame級別的多線程解碼:

          Slice級的解碼效率比Frame級的解碼效率要低,故,本文先考慮Frame級的多線程解碼。

          Frame級的多線程解碼

          通過查看ffmpeg源碼,了解到Frame級的多線程解碼流程大致如下:

          其中右側(cè)的frame_worker_thread為解碼線程,在open解碼器時就已經(jīng)創(chuàng)建,隨后阻塞在pthread_cond_wait(&p->input_cond, &p->mutex)函數(shù)。等待被主線程喚醒。

          當主線程運行到ff_thread_decode_frame函數(shù)時,會調(diào)用submit_packet函數(shù),這個函數(shù)的目的就是將packet包交給解碼線程。

          submit_packet函數(shù)會調(diào)用pthread_cond_signal(&p->input_cond)函數(shù),這個函數(shù)就是為喚醒剛才阻塞的解碼線程。

          當主線程喚醒解碼線程后,其pthread_cond_wait(&p->output_cond, &p->progress_mutex)函數(shù)會進入阻塞狀態(tài),等待解碼線程喚醒。

          1. 如果Codec未實現(xiàn)update_thread_context()和線程安全的get_buffer(),則必須在解碼完成后才能將狀態(tài)轉(zhuǎn)換為STATUS_SETUP_FINISHED,意味著下一個線程只能在當前線程解碼完成后才能開始解碼。當解碼線程解碼完成后,會用pthread_cond_signal(&p->output_cond)將主線程喚醒,其中會通過回調(diào)函數(shù)將解碼線程解碼出來的frame獲取,從而輸出。


          2. 如果Codec實現(xiàn)update_thread_context()和線程安全的get_buffer(),線程狀態(tài)可以在解碼開始之前轉(zhuǎn)換為STATUS_SETUP_FINISHED,這樣,主線程就能夠被喚醒,就能夠去讀包進行下一個包的解碼,因此下一個線程就可能與當前線程并行。

          Slice級的多線程解碼:

          ffmpeg的slice級并行只能在幀內(nèi)并行。

          因此,如果在某個視頻在編碼時,一幀圖像分為多個slice進行編碼的話,那么在使用ffmpeg解碼時調(diào)用slice級并行解碼就會得到不錯的效果。

          而在實際應(yīng)用中,大多數(shù)h264編碼的視頻都是一幀只有一個slice,對于這種視頻,就算采用了slice級并行,也只有一個線程在進行解碼作業(yè)。

          如果一幀,即一個packet分為幾個slice時,會先把這一幀前面的slice加入隊列,到最后一個slice時統(tǒng)一對這一幀的所有slice進行并行解碼。其中涉及到的關(guān)鍵要素如下:

          Slice Context List,slice的上下文是slice context(FFmpeg中的變量為slice_ctx),如果一幀中有多個slice,那么會把slice上下文組成一個列表。前面所說的入隊列操作會對該列表進行填充以供后續(xù)解碼使用。

          M,主線程,如單線程一樣的流程,從用戶調(diào)用解碼API一直執(zhí)行到我們前面所說的入隊列,到最后一個slice時會調(diào)用一個入口函數(shù)啟動多線程解碼操作。在調(diào)用入口函數(shù)后,主線程參與的多線程解碼過程一共包含三個步驟:

          1. 通過發(fā)送啟動消息激活其它正在等待的解碼線程。
          2. 在啟動多線程解碼后,主線程也會一同作為其中一個線程進行slice的解碼。
          3. 最后等待所有線程完成任務(wù)后返回。

          T,解碼線程,接收到主線程所發(fā)起的啟動消息后,解碼線程會到Slice Context List去提取其中一個slice context(原子操作),然后進行slice解碼。

          作者:frgfnjrgn
          來源:https://blog.csdn.net/yihuanyihuan/article/details/104019536

          一個音視頻領(lǐng)域?qū)I(yè)問答的小圈子!

          推薦閱讀:

          音視頻開發(fā)工作經(jīng)驗分享 || 視頻版

          OpenGL ES 學(xué)習資源分享

          開通專輯 | 細數(shù)那些年寫過的技術(shù)文章專輯

          Android NDK 免費視頻在線學(xué)習?。?!

          你想要的音視頻開發(fā)資料庫來了

          推薦幾個堪稱教科書級別的 Android 音視頻入門項目

          覺得不錯,點個在看唄~

          瀏覽 67
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕在线观看第一页 | 操大黑逼视频 | 色一情一区二 | 色噜噜一区二区三区 | 琪琪在线视频 |