最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

MediaCodec

MediaCodec所支持的數(shù)據(jù)類型:壓縮的音視頻數(shù)據(jù)、原始音頻數(shù)據(jù)和原始視頻數(shù)據(jù)。 首先show代碼,緊接著之前MediaExtactor提取資源,MediaCodecList遍歷支持格式,確認設(shè)置支持該資源格式后通過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ù)據(jù)緩沖去,將數(shù)據(jù)填充到輸入緩沖區(qū)給到Codec
  • Codec通過異步方式處理輸入緩沖區(qū)數(shù)據(jù)將處理好數(shù)據(jù)填充到輸出緩沖區(qū)
  • 客戶端從輸出緩沖區(qū)獲取到處理好的數(shù)據(jù)去消費,最后把緩沖區(qū)返還給Codec

部分代碼實現(xiàn)

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

//輸入緩沖區(qū)
private boolean dequeueInputBuffers() {
    boolean isMediaEOS = false;
    //  等待編碼器輸入緩沖區(qū)數(shù)據(jù)出隊
    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標識符輸入到編碼器
            mediaCodec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
            isMediaEOS = true;
            MediaLogUtils.printI(TAG + "end of stream");
        } else {
            // 輸入緩沖區(qū)數(shù)據(jù)入隊
            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、Executing、Released

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

Stopped

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

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

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

Executing

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

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

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

接口簡介

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

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

configure,配置編解碼器配置

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

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

queueInputBuffer,輸入入隊列

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

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

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

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

flush,清空輸入和輸出端口

stop,終止decode/encode會話

release,釋放編解碼器資源

參考文章

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

相關(guān)文章

  • Flutter?中檢測常用的命令詳解

    Flutter?中檢測常用的命令詳解

    這篇文章主要介紹了Flutter?中檢測常用的命令詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Android ScrollView實現(xiàn)橫向和豎向拖動回彈效果

    Android ScrollView實現(xiàn)橫向和豎向拖動回彈效果

    這篇文章主要為大家詳細介紹了Android ScrollView實現(xiàn)橫向和豎向拖動回彈效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Android 自定義TextView實現(xiàn)滑動解鎖高亮文字

    Android 自定義TextView實現(xiàn)滑動解鎖高亮文字

    這篇文章主要介紹了Android 自定義TextView實現(xiàn)滑動解鎖高亮文字的相關(guān)資料,需要的朋友可以參考下
    2018-03-03
  • Android關(guān)于獲取時間的記錄(小結(jié))

    Android關(guān)于獲取時間的記錄(小結(jié))

    這篇文章主要介紹了Android關(guān)于獲取時間的記錄(小結(jié)),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Android開關(guān)控件Switch的使用案例

    Android開關(guān)控件Switch的使用案例

    今天小編就為大家分享一篇關(guān)于Android開關(guān)控件Switch的使用案例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • kotlin的函數(shù)forEach示例詳解

    kotlin的函數(shù)forEach示例詳解

    在 Kotlin 中,forEach 是一個高階函數(shù),用于遍歷集合中的每個元素并對其執(zhí)行指定的操作,它的核心特點是 簡潔、函數(shù)式,適用于需要遍歷集合且無需返回值的場景,這篇文章主要介紹了kotlin的函數(shù)forEach示例詳解,需要的朋友可以參考下
    2025-03-03
  • Android項目開發(fā) 教你實現(xiàn)Periscope點贊效果

    Android項目開發(fā) 教你實現(xiàn)Periscope點贊效果

    這篇文章主要為大家分享了Android項目開發(fā),一步一步教你實現(xiàn)Periscope點贊效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Android ViewDragHelper使用介紹

    Android ViewDragHelper使用介紹

    ViewDragHelper是support.v4下提供的用于處理拖拽滑動的輔助類。接下來通過本文給大家介紹Android ViewDragHelper使用,感興趣的朋友一起看看吧
    2017-08-08
  • 淺析Android TextView常用屬性

    淺析Android TextView常用屬性

    TextView是用來顯示文本的組件。這篇文章給大家詳細介紹了Android TextView常用屬性 ,需要的朋友參考下
    2018-04-04
  • Android實戰(zhàn)APP啟動速度優(yōu)化

    Android實戰(zhàn)APP啟動速度優(yōu)化

    本篇文章給大家通過實戰(zhàn)總結(jié)了Android開發(fā)APP啟動速度優(yōu)化的方法以及需要注意的地方,有需要的朋友可以參考下。
    2018-05-05

最新評論

讷河市| 洛南县| 沂源县| 潼南县| 武定县| 鹤山市| 若尔盖县| 辽中县| 都安| 青冈县| 孟连| 阿瓦提县| 张家港市| 沧源| 邯郸县| 遵义市| 浦城县| 巴林右旗| 莫力| 灵武市| 类乌齐县| 南康市| 霍城县| 六安市| 永平县| 延长县| 怀安县| 监利县| 拉孜县| 潮安县| 丰台区| 龙泉市| 祁东县| 江源县| 平潭县| 宝兴县| 太白县| 鄯善县| 大厂| 闸北区| 长丰县|