## 一般流程 1. 使用者從MediaCodec請求一個空的輸入buffer(ByteBuffer),填充滿數據後將它傳遞給MediaCodec處理。 2. MediaCodec處理完這些數據並將處理結果輸出至一個空的輸出buffer(ByteBuffer)中。 3. 使用者從MediaCodec獲取輸出buffer的數據,消耗掉裡面的數據,使用完輸出buffer的數據之後,將其釋放回編解碼器。 流程如下圖所示: ![[android_mediacodec_flow.png]] ## 生命週期 MediaCodec的生命週期有三種狀態:Stopped、Executing、Released。 - Stopped,包含三種子狀態:Uninitialized、Configured、Error。 - Executing,包含三種子狀態:Flushed、Running、End-of-Stream。 ![[android_mediacodec_life_cycle.png]] **Stopped** 的三種子狀態: 1. Uninitialized:當創建了一個MediaCodec對象,此時處於Uninitialized狀態。可以在任何狀態調用reset()方法使MediaCodec返回到Uninitialized狀態。 2. Configured:使用configure(…)方法對MediaCodec進行配置轉為Configured狀態。 3. Error:MediaCodec遇到錯誤時進入Error狀態。錯誤可能是在隊列操作時返回的錯誤或者異常導致的。 **Executing** 的三種子狀態: 1. Flushed:在調用start()方法後MediaCodec立即進入Flushed子狀態,此時MediaCodec會擁有所有的緩存。可以在Executing狀態的任何時候通過調用flush()方法返回到Flushed子狀態。 2. Running:一旦第一個輸入緩存(input buffer)被移出隊列,MediaCodec就轉入Running子狀態,這種狀態佔據了MediaCodec的大部分生命週期。通過調用stop()方法轉移到Uninitialized狀態。 3. End-of-Stream:將一個帶有end-of-stream標記的輸入buffer入隊列時,MediaCodec將轉入End-of-Stream子狀態。在這種狀態下,MediaCodec不再接收之後的輸入buffer,但它仍然產生輸出buffer直到end-of-stream標記輸出。 **Released** 1. 當使用完MediaCodec後,必須調用release()方法釋放其資源。調用release()方法進入最終的Released狀態。 ## API ### createEncoderByType - [createEncoderByType](https://developer.android.com/reference/android/media/MediaCodec#createEncoderByType(java.lang.String)) ### createDecoderByType - [createDecoderByType](https://developer.android.com/reference/android/media/MediaCodec#createDecoderByType(java.lang.String)) ### configure - [configure]([MediaCodec  |  Android Developers](https://developer.android.com/reference/android/media/MediaCodec#configure(android.media.MediaFormat,%20android.view.Surface,%20android.media.MediaCrypto,%20int))) ### start - [start](https://developer.android.com/reference/android/media/MediaCodec#start()) ### dequeueInputBuffer - [dequeueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueInputBuffer(long)) ### queueInputBuffer - [queueInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#queueInputBuffer(int,%20int,%20int,%20long,%20int)) ### getInputBuffer - [getInputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getInputBuffer(int)) ### dequeueOutputBuffer - [dequeueOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#dequeueOutputBuffer(android.media.MediaCodec.BufferInfo,%20long)) ### getOutputBuffer - [getOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#getOutputBuffer(int)) ### releaseOutputBuffer - [releaseOutputBuffer](https://developer.android.com/reference/android/media/MediaCodec#releaseOutputBuffer(int,%20boolean)) ### stop - [stop](https://developer.android.com/reference/android/media/MediaCodec#stop()) ### release - [release](https://developer.android.com/reference/android/media/MediaCodec#release()) ## 使用 1. 根據需求使用createEncoderByType或是createDecoderByType建立codec。以下以encode為例。 2. 呼叫configure,傳入相應的MediaFormat。 3. 呼叫start,開始encode。 4. 建立一個迴圈,不斷的傳入要encode的buffer,也不斷的拿出已經encode的buffer。 5. 在迴圈內,要傳入的buffer處理方法: 1. 呼叫dequeueInputBuffer,試探是否有能用的buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做index。 2. 如果index合法,用`inputBuffer = queueInputBuffer(index)`來取得可用的buffer。這裡假設buffer的變數叫做inputBuffer。 3. 將要encode的資料copy到inputBuffer。 6. 在迴圈內,要取得已經encode buffer的方法: 1. 呼叫dequeueOutputBuffer,試探是否有encoded buffer,如果有,回傳值將大於等於0(>= 0)。這裡假設回傳值的變數叫做index。 2. 如果index合法,用`outputBuffer = getOutputBuffer(index)`來取得可用的buffer。這裡假設buffer的變數叫做outputBuffer。 3. outputBuffer 就是已經 encode 好的,就看你怎麼處理。 4. 重要!呼叫 releaseOutputBuffer 來回收剛剛那一塊 buffer。 Psuedo code 如下: ```kotlin while (true) // send buffer to encode index = dequeueInputBuffer() if (index >= 0) inputBuffer = queueInputBuffer(index) copy(inputBuffer, srcBuffer) // Get encoded buffer index = dequeueOutputBuffer() if (index >= 0) outputBuffer = getOutputBuffer(index) releaseOutputBuffer(index) ``` ## 參考資料 - [Android音视频之使用MediaCodec编解码AAC - 简书](https://www.jianshu.com/p/14daab91b951) - [MultiMediaLearning/app/src/main/java/com/richie/multimedialearning/mediacodec at master · isuperqiang/MultiMediaLearning](https://github.com/isuperqiang/MultiMediaLearning/tree/master/app/src/main/java/com/richie/multimedialearning/mediacodec) - [初识MediaCodec - 知乎](https://zhuanlan.zhihu.com/p/45224834) - [MediaCodec的使用介绍 - 简书](https://www.jianshu.com/p/f5a1c9318524) - [Android原生编解码接口MediaCodec详解 - 掘金](https://juejin.cn/post/7086297619764346887) - [AndroidMediaCodecDemo/AudioDecoder.kt at main · king-ma1993/AndroidMediaCodecDemo](https://github.com/king-ma1993/AndroidMediaCodecDemo/blob/main/app/src/main/java/com/myl/mediacodedemo/decode/audio/AudioDecoder.kt) - [Android使用系统API进行音视频编码_key_max_input_size_blueberry_mu的博客-CSDN博客](https://blog.csdn.net/a992036795/article/details/54286654) - [MediaCodec 完成PCM编码成AAC - 知乎](https://zhuanlan.zhihu.com/p/564759685) - [MediaCodec 同步方式完成AAC硬解成PCM - 知乎](https://zhuanlan.zhihu.com/p/564734700)