Android音視頻開發(fā)之MediaCodec的使用教程
前言
獲取到音視頻軌道(編解碼格式),知道設備支持哪些編解碼器,下一步就是創(chuàng)建編解碼器去實現(xiàn)數據流的編解碼過程了。在Android
開發(fā)中提供了實現(xiàn)音視頻編解碼工具MediaCodec
,針對對應音視頻解碼類型通過該類創(chuàng)建對應解碼器就能實現(xiàn)對數據進行解碼操作。
MediaCodec
MediaCodec
所支持的數據類型:壓縮的音視頻數據、原始音頻數據和原始視頻數據。 首先show代碼,緊接著之前MediaExtactor
提取資源,MediaCodecList
遍歷支持格式,確認設置支持該資源格式后通過MediaCodec
創(chuàng)建解碼器(這里是做視頻解碼播放)。
// 加載資源 extractor.setDataSource(path); // 獲取視頻軌道 int trackIndex = getTrackIndex(extractor,"video/"); // 獲取視頻軌道參數 MediaFormatInfo mediaFormatInfo = MediaFormatInfo.buildUpVideoMediaFormatInfo(extractor.getTrackFormat(trackIndex)); // 選取上述的視頻軌道 extractor.selectTrack(trackIndex); MediaCodecInfo mediaCodecInfo = CodecInfoInstance.getInstance().selectDeCodec(mediaFormatInfo.getMime()); // 判斷設備是否支持該視頻解碼,創(chuàng)建視頻編碼器 if(mediaCodecInfo != null){ mediaCodec = MediaCodec.createDecoderByType(mediaFormatInfo.getMime()); mediaCodec.configure(mediaFormatInfo.getMediaFormat(),surface,null,0); }
編解碼流程
MediaCodec
的功能其實很簡單通過一個數據緩沖去,將數據填充到輸入緩沖區(qū)給到Codec
Codec
通過異步方式處理輸入緩沖區(qū)數據將處理好數據填充到輸出緩沖區(qū)- 客戶端從輸出緩沖區(qū)獲取到處理好的數據去消費,最后把緩沖區(qū)返還給
Codec
部分代碼實現(xiàn)
- dequeueInputBuffer:從輸入流隊列取數據進行編碼操作
- getInputBuffers: 獲取需要編碼數據的輸入隊列 返回ByteBuffer數組
- queueInoutBuffer: 輸入流入隊列
- dequeueOutputBuffer: 從輸入隊列中取出編碼操作結果數據
- getOutPutBuffer: 獲取編解碼之后數據輸出隊列 返回一個ByterBuffer數組
- releaseOutPutBuffer: 處理完成釋放ByterBuffer數組
while (!isEnd && !isInterrupted()){ if (!mIsEOS) { mIsEOS = dequeueInputBuffers(); } isEnd = dequeueOutputBuffers(); } //輸入緩沖區(qū) private boolean dequeueInputBuffers() { boolean isMediaEOS = false; // 等待編碼器輸入緩沖區(qū)數據出隊 int inputBufferId = mediaCodec.dequeueInputBuffer(TIMEOUT_US); if (inputBufferId >= 0) { // 獲取緩存區(qū)數據 ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferId); // 讀取數據 返回值sampleSize大于0表示還有數據,否則表示結束 int sampleSize = extractor.readSampleData(inputBuffer, 0); if (sampleSize < 0) { // 數據末尾 必須再次調用queueInputBuffer使用BUFFER_FLAG_END_OF_STREAM標識符輸入到編碼器 mediaCodec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); isMediaEOS = true; MediaLogUtils.printI(TAG + "end of stream"); } else { // 輸入緩沖區(qū)數據入隊 mediaCodec.queueInputBuffer(inputBufferId, 0, sampleSize, extractor.getSampleTime(), 0); extractor.advance(); } } return isMediaEOS; } //輸出緩沖區(qū) private synchronized boolean dequeueOutputBuffers() { MediaCodec.BufferInfo outBufferInfo = new MediaCodec.BufferInfo(); //輸出緩沖區(qū) int outputBufferId = mediaCodec.dequeueOutputBuffer(outBufferInfo, TIMEOUT_US); switch (outputBufferId) { case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: MediaLogUtils.printI(TAG+"INFO_OUTPUT_FORMAT_CHANGED"); break; case MediaCodec.INFO_TRY_AGAIN_LATER: MediaLogUtils.printI(TAG+ "INFO_TRY_AGAIN_LATER"); break; case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: MediaLogUtils.printI(TAG+ "INFO_OUTPUT_BUFFERS_CHANGED"); break; default: // 延遲解碼 decodeDelay(outBufferInfo, mStartMs); // 釋放輸出緩沖區(qū)數據 render為true渲染到surface上 mediaCodec.releaseOutputBuffer(outputBufferId, true); break; } // 結尾 if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { MediaLogUtils.printI(TAG+"buffer stream end"); return true; } return false; }
生命周期
MediaCodec
生命周期分為三種狀態(tài):Stopped
、Executing
、Released
- Stopped具有三種子狀態(tài):Uninitialized、Configured、Error
- Executing具有三種子狀態(tài):Flushed、Running、End-of-Stream
Stopped
Uninitialized: Uninitialized
是MediaCodec
創(chuàng)建后初始狀態(tài)??赏ㄟ^reset()
復位到Uninitialized
Configured: MediaCodec
通過configure
方法設置配置(編解碼器類型等)進入到Configured
狀態(tài)。
Error: MediaCodec
發(fā)生異常情況下會進入Error
狀態(tài)。
Executing
Flush:MediaCodec
調用start
方法后進入Flushed
,MediaCodec
就具備所有緩存能力。若可以在Executing
,調用flush()
回到Flushed
狀態(tài)。
Running: 當第一次InputBuffer
輸入緩存被移除隊列,MediaCodec
就會進入到Running
狀態(tài)。
End-of-Stream:將end-of-stream
標記輸入InputBuffer
隊列,MediaCodec
就會進入到 End-of-Stream
狀態(tài),MediaCodec
就不再接收InputBuffer
,但不影響輸出隊列OutBuffer
產出直到end-of-stream
標記輸出為止(輸入和輸出中間是有一定處理時間)。
接口簡介
createDecoderByType/createEncoderByType,創(chuàng)建解碼器/編碼器對象
createByCodecName,根據編解碼器名稱創(chuàng)建
configure,配置編解碼器配置
start,配置完成后需要執(zhí)行start完成配置
dequeueInputBuffer, 輸入隊列取數據編碼操作
queueInputBuffer,輸入入隊列
dequeueOutputBuffer,從輸出隊列取出編碼操作后的數據
releaseOutputBuffer,釋放輸出隊列釋放ByteBuffer數據
getInputBuffers,獲取需要編碼數據輸入流隊列,返回ByteBuffer數組
getOutputBuffers,獲取編解碼后數據輸出流隊列,返回ByteBuffer數組
flush,清空輸入和輸出端口
stop,終止decode/encode會話
release,釋放編解碼器資源
到此這篇關于Android音視頻開發(fā)之MediaCodec的使用教程的文章就介紹到這了,更多相關Android MediaCodec內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android自定義View實現(xiàn)分段選擇按鈕的實現(xiàn)代碼
這篇文章主要介紹了Android自定義View實現(xiàn)分段選擇按鈕的實現(xiàn)代碼,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-12-12Android中使用Expandablelistview實現(xiàn)微信通訊錄界面
本文主要介紹了Android中使用Expandablelistview實現(xiàn)微信通訊錄界面(完善防微信APP)的方法,具有一定的參考價值,下面跟著小編一起來看下吧2016-12-12Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實現(xiàn))
這篇文章主要介紹了Android自定義Spinner下拉列表(使用ArrayAdapter和自定義Adapter實現(xiàn))的相關資料,需要的朋友可以參考下2015-10-10