欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android音視頻開發(fā)之MediaCodec的使用教程

 更新時間:2022年04月29日 10:48:02   作者:JulyYu  
在Android開發(fā)中提供了實現(xiàn)音視頻編解碼工具MediaCodec,針對對應音視頻解碼類型通過該類創(chuàng)建對應解碼器就能實現(xiàn)對數據進行解碼操作。本文通過示例詳細講解了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):StoppedExecuting、Released

  • Stopped具有三種子狀態(tài):Uninitialized、Configured、Error
  • Executing具有三種子狀態(tài):Flushed、Running、End-of-Stream

Stopped

Uninitialized: UninitializedMediaCodec創(chuàng)建后初始狀態(tài)??赏ㄟ^reset()復位到Uninitialized

Configured: MediaCodec通過configure方法設置配置(編解碼器類型等)進入到Configured狀態(tài)。

Error: MediaCodec發(fā)生異常情況下會進入Error狀態(tài)。

Executing

Flush:MediaCodec調用start方法后進入FlushedMediaCodec就具備所有緩存能力。若可以在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ù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論