Files
Obsidian-Main/20.01. Android/MediaCodec.md

6.8 KiB
Raw Blame History

一般流程

  1. 使用者從MediaCodec請求一個空的輸入bufferByteBuffer填充滿數據後將它傳遞給MediaCodec處理。
  2. MediaCodec處理完這些數據並將處理結果輸出至一個空的輸出bufferByteBuffer中。
  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. ErrorMediaCodec遇到錯誤時進入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

createDecoderByType

configure

start

dequeueInputBuffer

queueInputBuffer

getInputBuffer

dequeueOutputBuffer

getOutputBuffer

releaseOutputBuffer

stop

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 合法,用 #queueInputBuffer,像是 inputBuffer = queueInputBuffer(index) 來取得可用的 buffer。這裡假設 buffer 的變數叫做 inputBuffer。
    3. 將要 encode 的資料 copy 到 inputBuffer。
    4. 若要停止 encode送出 codec.queueInputBuffer(inputBufIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
  6. 在迴圈內要取得已經encode buffer的方法
    1. 呼叫 #dequeueOutputBuffer,試探是否有 encoded buffer如果有回傳值將大於等於0>= 0。這裡假設回傳值的變數叫做 index。
    2. 如果 index合法#getOutputBuffer,像是outputBuffer = getOutputBuffer(index) 來取得可用的 buffer。這裡假設 buffer 的變數叫做 outputBuffer。
    3. outputBuffer 就是已經 encode 好的,就看你怎麼處理。
    4. 重要!呼叫 #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)

參考資料