一、MediaCodec 整體架構與設計思想
MediaCodec 是 Android 底層多媒體框架的核心組件,負責高效處理音視頻編解碼任務。其架構采用 生產者-消費者模型,通過雙緩沖區隊列(輸入/輸出)實現異步數據處理:
- 輸入緩沖區隊列:存放待編碼/解碼的原始數據(如 YUV 視頻幀或 PCM 音頻)。
- 輸出緩沖區隊列:存儲處理后的數據(如 H.264 流或解碼后的原始幀)。
- 硬件加速支持:優先調用設備專屬編解碼器(如高通 DSP),顯著降低 CPU 負載。
二、核心組件與關鍵 API 詳解
1. 編解碼器實例(MediaCodec)
- 創建方式:
支持通過 MIME 類型(如// 創建解碼器(H.264 示例) MediaCodec decoder = MediaCodec.createDecoderByType("video/avc"); // 創建編碼器(AAC 音頻示例) MediaCodec encoder = MediaCodec.createEncoderByType("audio/mp4a-latm");
video/avc
)或硬件編解碼器名稱創建。
2. 緩沖區管理
- 輸入緩沖區:
dequeueInputBuffer(timeoutUs)
:獲取空閑緩沖區索引。getInputBuffer(index)
:通過索引獲取ByteBuffer
對象填充數據。queueInputBuffer(...)
:提交數據給編解碼器處理。
- 輸出緩沖區:
dequeueOutputBuffer(BufferInfo, timeoutUs)
:獲取處理完成的緩沖區索引及元數據。getOutputBuffer(index)
:讀取編解碼后數據。releaseOutputBuffer(index, render)
:釋放緩沖區(若為視頻,render=true
可觸發渲染)。
3. 配置與狀態控制
- 配置參數(MediaFormat):
MediaFormat format = MediaFormat.createVideoFormat("video/avc", width, height); format.setInteger(MediaFormat.KEY_BIT_RATE, 5000000); // 碼率 format.setInteger(MediaFormat.KEY_FRAME_RATE, 30); // 幀率 format.setInteger(KEY_COLOR_FORMAT, COLOR_FormatYUV420Flexible); // 顏色空間 codec.configure(format, surface, null, 0); // surface 用于視頻渲染
- 生命周期控制:
start()
→ 進入運行狀態(Running
)。stop()
→ 回到未初始化狀態(Uninitialized
)。release()
→ 釋放資源。
三、核心類 MediaCodec.BufferInfo
深度解析
BufferInfo
是描述輸出緩沖區元數據的關鍵類,包含以下字段:
字段 | 類型 | 作用 |
---|---|---|
offset | int | 有效數據在緩沖區中的起始偏移(字節)。通常為 0,表示從緩沖區頭部開始讀取。 |
size | int | 有效數據長度(字節)。若為 0 且含 BUFFER_FLAG_END_OF_STREAM ,表示流結束。 |
presentationTimeUs | long | 呈現時間戳(微秒),用于音視頻同步(如視頻幀的渲染時機)。 |
flags | int | 緩沖區標志位(位掩碼),關鍵值包括: |
(0) : B or P 幀 | ||
- BUFFER_FLAG_KEY_FRAME (1):關鍵幀(I幀)。 | ||
- BUFFER_FLAG_END_OF_STREAM (4):流結束標記(EOS)。 | ||
- BUFFER_FLAG_CODEC_CONFIG (2):編解碼配置數據(如 SPS/PPS)。 |
典型使用場景:
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputIndex = codec.dequeueOutputBuffer(bufferInfo, timeoutUs);
if (outputIndex >= 0) {ByteBuffer outputBuffer = codec.getOutputBuffer(outputIndex);byte[] data = new byte[bufferInfo.size];outputBuffer.position(bufferInfo.offset);outputBuffer.get(data, 0, bufferInfo.size);// 關鍵幀處理if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {saveKeyFrame(data); // 存儲關鍵幀用于錯誤恢復}codec.releaseOutputBuffer(outputIndex, true);
}
四、工作流程與狀態機
- 關鍵狀態:
- Flushed:啟動后初始狀態,緩沖區為空。
- Running:持續處理數據(90% 時間處于此狀態)。
- End-of-Stream:輸入流結束,等待輸出剩余數據。
五、注意
-
同步 vs 異步模式:
- 同步模式:簡單但易阻塞主線程,適合低復雜度場景。
- 異步模式:通過
setCallback()
監聽事件,高效但需處理線程安全。
-
緩沖區復用:避免頻繁申請內存,提升性能(尤其高清視頻)。
-
設備兼容性:
- 使用
MediaCodecList
檢查編解碼器支持情況。 - 某些設備對
COLOR_FORMAT
支持有限,需動態適配。
- 使用
-
MediaCodec 通過雙緩沖區隊列和狀態機控制實現高效編解碼,核心在于:
緩沖區管理:dequeueInputBuffer
/queueInputBuffer
與dequeueOutputBuffer
/releaseOutputBuffer
的配對使用。 -
元數據解析:
BufferInfo
的flags
和presentationTimeUs
是同步與錯誤恢復的關鍵。 -
硬件加速:優先選擇設備專屬編解碼器(如
OMX.qcom.
前綴)以優化性能。