亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2022年04月29日 10:48:02   作者:JulyYu  
在Android開發(fā)中提供了實(shí)現(xiàn)音視頻編解碼工具M(jìn)ediaCodec,針對(duì)對(duì)應(yīng)音視頻解碼類型通過(guò)該類創(chuàng)建對(duì)應(yīng)解碼器就能實(shí)現(xiàn)對(duì)數(shù)據(jù)進(jìn)行解碼操作。本文通過(guò)示例詳細(xì)講解了MediaCodec的使用,需要的可以參考一下

前言

獲取到音視頻軌道(編解碼格式),知道設(shè)備支持哪些編解碼器,下一步就是創(chuàng)建編解碼器去實(shí)現(xiàn)數(shù)據(jù)流的編解碼過(guò)程了。在Android開發(fā)中提供了實(shí)現(xiàn)音視頻編解碼工具MediaCodec,針對(duì)對(duì)應(yīng)音視頻解碼類型通過(guò)該類創(chuàng)建對(duì)應(yīng)解碼器就能實(shí)現(xiàn)對(duì)數(shù)據(jù)進(jìn)行解碼操作。

MediaCodec

MediaCodec所支持的數(shù)據(jù)類型:壓縮的音視頻數(shù)據(jù)、原始音頻數(shù)據(jù)和原始視頻數(shù)據(jù)。 首先show代碼,緊接著之前MediaExtactor提取資源,MediaCodecList遍歷支持格式,確認(rèn)設(shè)置支持該資源格式后通過(guò)MediaCodec創(chuàng)建解碼器(這里是做視頻解碼播放)。

// 加載資源
extractor.setDataSource(path);
// 獲取視頻軌道
int trackIndex = getTrackIndex(extractor,"video/");
// 獲取視頻軌道參數(shù)
MediaFormatInfo mediaFormatInfo = MediaFormatInfo.buildUpVideoMediaFormatInfo(extractor.getTrackFormat(trackIndex));
// 選取上述的視頻軌道
extractor.selectTrack(trackIndex);
MediaCodecInfo mediaCodecInfo = CodecInfoInstance.getInstance().selectDeCodec(mediaFormatInfo.getMime());
// 判斷設(shè)備是否支持該視頻解碼,創(chuàng)建視頻編碼器
if(mediaCodecInfo != null){
    mediaCodec = MediaCodec.createDecoderByType(mediaFormatInfo.getMime());
    mediaCodec.configure(mediaFormatInfo.getMediaFormat(),surface,null,0);
}

編解碼流程

  • MediaCodec的功能其實(shí)很簡(jiǎn)單通過(guò)一個(gè)數(shù)據(jù)緩沖去,將數(shù)據(jù)填充到輸入緩沖區(qū)給到Codec
  • Codec通過(guò)異步方式處理輸入緩沖區(qū)數(shù)據(jù)將處理好數(shù)據(jù)填充到輸出緩沖區(qū)
  • 客戶端從輸出緩沖區(qū)獲取到處理好的數(shù)據(jù)去消費(fèi),最后把緩沖區(qū)返還給Codec

部分代碼實(shí)現(xiàn)

  • dequeueInputBuffer:從輸入流隊(duì)列取數(shù)據(jù)進(jìn)行編碼操作
  • getInputBuffers: 獲取需要編碼數(shù)據(jù)的輸入隊(duì)列 返回ByteBuffer數(shù)組
  • queueInoutBuffer: 輸入流入隊(duì)列
  • dequeueOutputBuffer: 從輸入隊(duì)列中取出編碼操作結(jié)果數(shù)據(jù)
  • getOutPutBuffer: 獲取編解碼之后數(shù)據(jù)輸出隊(duì)列 返回一個(gè)ByterBuffer數(shù)組
  • releaseOutPutBuffer: 處理完成釋放ByterBuffer數(shù)組
while (!isEnd && !isInterrupted()){
    if (!mIsEOS) {
        mIsEOS = dequeueInputBuffers();
    }
    isEnd = dequeueOutputBuffers();
}

//輸入緩沖區(qū)
private boolean dequeueInputBuffers() {
    boolean isMediaEOS = false;
    //  等待編碼器輸入緩沖區(qū)數(shù)據(jù)出隊(duì)
    int inputBufferId = mediaCodec.dequeueInputBuffer(TIMEOUT_US);
    if (inputBufferId >= 0) {
        // 獲取緩存區(qū)數(shù)據(jù)
        ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferId);
        // 讀取數(shù)據(jù) 返回值sampleSize大于0表示還有數(shù)據(jù),否則表示結(jié)束
        int sampleSize = extractor.readSampleData(inputBuffer, 0);
        if (sampleSize < 0) {
            // 數(shù)據(jù)末尾 必須再次調(diào)用queueInputBuffer使用BUFFER_FLAG_END_OF_STREAM標(biāo)識(shí)符輸入到編碼器
            mediaCodec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            isMediaEOS = true;
            MediaLogUtils.printI(TAG + "end of stream");
        } else {
            // 輸入緩沖區(qū)數(shù)據(jù)入隊(duì)
            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ū)數(shù)據(jù) render為true渲染到surface上
            mediaCodec.releaseOutputBuffer(outputBufferId, true);
            break;
    }
    // 結(jié)尾
    if ((outBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
        MediaLogUtils.printI(TAG+"buffer stream end");
        return true;
    }
    return false;
}

生命周期

MediaCodec生命周期分為三種狀態(tài):Stopped、ExecutingReleased

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

Stopped

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

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

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

Executing

Flush:MediaCodec調(diào)用start方法后進(jìn)入FlushedMediaCodec就具備所有緩存能力。若可以在Executing,調(diào)用flush()回到Flushed狀態(tài)。

Running: 當(dāng)?shù)谝淮?code>InputBuffer輸入緩存被移除隊(duì)列,MediaCodec就會(huì)進(jìn)入到Running狀態(tài)。

End-of-Stream:將end-of-stream標(biāo)記輸入InputBuffer隊(duì)列,MediaCodec就會(huì)進(jìn)入到 End-of-Stream狀態(tài),MediaCodec就不再接收InputBuffer,但不影響輸出隊(duì)列OutBuffer產(chǎn)出直到end-of-stream標(biāo)記輸出為止(輸入和輸出中間是有一定處理時(shí)間)。

接口簡(jiǎn)介

createDecoderByType/createEncoderByType,創(chuàng)建解碼器/編碼器對(duì)象

createByCodecName,根據(jù)編解碼器名稱創(chuàng)建

configure,配置編解碼器配置

start,配置完成后需要執(zhí)行start完成配置

dequeueInputBuffer, 輸入隊(duì)列取數(shù)據(jù)編碼操作

queueInputBuffer,輸入入隊(duì)列

dequeueOutputBuffer,從輸出隊(duì)列取出編碼操作后的數(shù)據(jù)

releaseOutputBuffer,釋放輸出隊(duì)列釋放ByteBuffer數(shù)據(jù)

getInputBuffers,獲取需要編碼數(shù)據(jù)輸入流隊(duì)列,返回ByteBuffer數(shù)組

getOutputBuffers,獲取編解碼后數(shù)據(jù)輸出流隊(duì)列,返回ByteBuffer數(shù)組

flush,清空輸入和輸出端口

stop,終止decode/encode會(huì)話

release,釋放編解碼器資源

參考文章

到此這篇關(guān)于Android音視頻開發(fā)之MediaCodec的使用教程的文章就介紹到這了,更多相關(guān)Android MediaCodec內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論