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

