用MediaCodec實現多段視音訊的擷取與拼接

yangxi_001發表於2015-09-11

    轉自:http://blog.csdn.net/mouse_1894/article/details/34448563

    視音訊編輯中,對多段媒體素材進行擷取和拼接是非常常見的操作。擷取和拼接實際上是對媒體檔案資料重新進行組合的過程。

    要實現這些功能,就需要對媒體檔案進行編解碼操作,即先解碼要處理的媒體檔案資料,然後再按照某種規則對這些資料進行編碼,以生成我們所需的目標。


    Android提供的MediaCodec及其相關類為我們提供了所需的方法,這些類主要包括:MediaCodec、MediaExtractor、MediaMuxer、MediaFormat。

    MediaCodec用於建立視音訊編解碼器,通過它可以對視音訊資料進行編解碼操作,它是編解碼功能的核心類。

    MediaExtractor相當於一個reader,它用於讀取媒體檔案,並提取出其中的視音訊資料。

    MediaMuxer相當於一個writer,它用於將記憶體中的視音訊資料寫到檔案中。

    MediaFormat即媒體格式類,它用於描述媒體的格式引數,如視訊幀率、音訊取樣率等。

    對視音訊檔案進行擷取與拼接的主要過程是:先建立視音訊編解碼器,再分別啟動視訊執行緒和音訊執行緒,以分別對視音訊資料進行解碼、編碼,最後將編碼好的資料寫入檔案。

    主要邏輯如下,關鍵是三處執行緒同步的地方,具體原因稍後解釋。


    再來了解一下這幾個類的“脾氣”。

    一般用MediaCodec建立編解碼器時,使用的都是createDecoderByType方法,但在用三星PAD(API LEVEL 18, Android version 4.3)除錯時發現,呼叫該方法建立音訊編碼器時會出錯。故改為使用createByCodecName("OMX.SEC.aac.enc")建立音訊編碼器。估計這是一個API bug。

    configure decoder時,第一個格式引數要與源的格式相同,這裡可以先通過extractor將源的格式讀出來,再直接傳給configure方法。configure encoder時,需設定幾個必要的引數,具體請參考官方說明。

    當把全部要處理的資料灌給編解碼器後,使用queueInputBuffer(inputBufIndex,0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM)方法來通知編解碼器結束工作。之後,在OutputBuffer的bufferInfo中,將攜帶這個標誌,通過判斷是否有這個標誌,我們就可以斷定資料是否都已處理完成,以進行後續操作。再之後,dequeueOutputBuffer的返回都將是INFO_TRY_AGAIN_LATER。當然,如果你自己有辦法在OutputBuffer中判斷資料是否灌完,也可以不使用此標誌。

    當資料灌完後,要使用releaseOutputBuffer,把緩衝區釋放掉。否則,你會發現queueInputBuffer總是返回-1,因為沒有空閒的緩衝區了。

    MediaExtractor用來讀取原始檔,給定檔案路徑後,便可將其中的視音訊資料拿出來。關鍵是它的seekTo方法,它用於對讀取資料的遊標進行定位,可以定位到指定點前的最後一個sync點、指定點後的第一個sync點,或者與指定點最近的sync點。對於H.264資料,sync點可以認為是視訊關鍵幀的時碼位置。

    MediaMuxer的使用非常簡單,先建立,再新增視音訊軌,然後start,再writeSampleData,最後stop。需要注意的是,必需先新增完所有的視音訊軌後,再去start,而不能先start,再試圖去addTrack,否則會出錯。這也是為什麼在本文的邏輯中,視訊執行緒需要去wait音訊執行緒新增完音訊軌後再繼續的原因。

    需要注意的是,不能在啟動完編解碼器後,立即呼叫getOutputFormat企圖addTrack,而應該在dequeueOutputBuffer後的INFO_OUTPUT_FORMAT_CHANGED中呼叫,否則會出錯。

    當要向檔案中同時寫入視訊和音訊資料時,必需先writeSampleData所有視訊資料,再寫音訊資料,或者反之,即二者必需連續呼叫writeSampleData,不能交叉呼叫,否則寫出的檔案會有問題。這也是本文中為何muxer啟動後,音訊執行緒需等待視訊執行緒先寫完資料,自己才能繼續幹活的原因。

    當所有的writeSampleData完成後,不要忘記呼叫stop和release,否則寫出的檔案也會有問題。

    最後還要注意,這幾個類中,時間單位都是微秒,不要搞錯了。

相關文章