Android多媒體框架--08:MediaExtractor和MediaMuxer介紹

"本文轉(zhuǎn)載自:[yanbixing123]的Android MultiMedia框架完全解析 - MediaExtractor和MediaMuxer介紹"

1.概述

??Android中Native層抽象出來(lái)MediaMuxer類和MediaExtractor類析砸,MediaMuxer類主要用于將音頻和視頻數(shù)據(jù)進(jìn)行混合生成多媒體文件(如:mp4文件),而MediaExtractor則剛好相反,主要用于多媒體文件的音視頻數(shù)據(jù)的分離,即解封裝。

??而在文件播放中糠溜,首先需要做的就是解封裝躬贡, 所以在播放過(guò)程中劫谅,NuPlayer使用了這個(gè)MediaExtractor類氢妈,先來(lái)看看MediaExtractor在NuPlayer框架中所處的位置:

01.png

??下面給出一個(gè)Android App中使用MediaExtractor和MediaMuxer的例子粹污,先來(lái)看看application中是如何使用這些接口的。

2.MediaExtractor

??(1)該類主要用于音視頻混合數(shù)據(jù)的分離首量,接口比較簡(jiǎn)單壮吩,首先要通過(guò)setDataSource(String path)函數(shù)設(shè)置數(shù)據(jù)源,數(shù)據(jù)源可以是本地文件地址加缘,也可以使用HTTP協(xié)議的網(wǎng)絡(luò)碼流地址鸭叙。

extractor = new MediaExtractor();
extractor.setDataSource("/sdcard/test.mp4");

dumpFormat(extractor);

private void dumpFormat(MediaExtractor extractor) {                      
    int count = extractor.getTrackCount();                               
    Log.i(TAG, "playVideo: track count: " + count);                      
    for (int i = 0; i < count; i++) {                                    
        MediaFormat format = extractor.getTrackFormat(i);                
        Log.i(TAG, "playVideo: track " + i + ":" + getTrackInfo(format));

        String mime = format.getString(MediaFormat.KEY_MIME);
        if(mime.startsWith("Video/")){
            videoTrackIndex = i;
        } else if(mime.startsWith("audio/")){
           audioTrackIndex = 0;
        }
    }
}                                                                    

打開sdcard下的一個(gè)測(cè)試視頻,然后打印其軌道信息生百,軌道信息的遍歷可以通過(guò)MediaExtractor的 getTrackCount 和 getTrackFormat 配合完成递雀,如:MimeType,分辨率蚀浆、編碼格式缀程、碼率、幀率等等市俊。

??(2)獲取到媒體文件的詳細(xì)信息之后杨凑,就可以選擇指定的通道,并分離和讀取數(shù)據(jù)了:

mMediaExtractor.selectTrack(videoTrackIndex);

while(true) {
    int sampleSize = mMediaExtractor.readSampleData(buffer, 0);
    if(sampleSize < 0){
        break;
    }
    mMediaExtractor.advance(); //移動(dòng)到下一幀
}

mMediaExtractor.release(); //讀取結(jié)束后摆昧,要記得釋放資源

3.MediaMuxer

??(1)該類主要用于將音頻和視頻進(jìn)行混合生成多媒體文件撩满,創(chuàng)建該類對(duì)象,需要傳入輸出的文件位置以及格式绅你,構(gòu)造函數(shù)如下:

public MediaMuxer(String path, int format);

創(chuàng)建對(duì)象之后伺帘,一個(gè)比較重要的操作就是addTrack(),添加數(shù)據(jù)通道忌锯,該函數(shù)需要傳入MediaFormat對(duì)象伪嫁,MediaFormat即媒體格式類,用于描述媒體的格式參數(shù)偶垮,如視頻幀率张咳、音頻采樣率等。

??(2)在本示例中似舵,可以直接使用MediaExtractor.getTrackFormat()解析得到的MediaFormat對(duì)象脚猾,如果你希望自己來(lái)創(chuàng)建這個(gè)MediaFormat對(duì)象的話,可以使用該類的如下靜態(tài)方法創(chuàng)建:

MediaFormat format = MediaFormat.createVideoFormat("video/avc", 320, 240);

注意砚哗,如果手動(dòng)創(chuàng)建MediaFormat對(duì)象的話龙助,一定要記得設(shè)置"csd-0"和"csd-1"這兩個(gè)參數(shù):

byte[] csd0 = {x, x, x, x, x, ,x ...}
byte[] csd1 = {x, x, x, x, x, ,x ...}
format.setByteBuffer("csd-0", ByteBuffer.wrap(csd0));
format.setByteBuffer("csd-1", ByteBuffer.wrap(csd1));

至于"csd-0"和"csd-1"是什么,對(duì)于H264視頻的話蛛芥,它對(duì)應(yīng)的是sps和pps泌参,對(duì)于AAC音頻的話幢痘,對(duì)應(yīng)的是ADTS宣赔,它一般存在于編碼器生成的IDR幀之中。

??(3)通過(guò) addTrack() 添加了數(shù)據(jù)通道之后答姥,記錄下函數(shù)返回的 trackIndex漓糙,然后就可以調(diào)用 MediaMuxer.writeSampleData() 愉快地向mp4文件中寫入數(shù)據(jù)了铣缠。

mMediaMuxer.writeSampleData(mVideoTrackIndex,buffer,info);

這里需要注意的就是writeSampleData函數(shù)的最后一個(gè)參數(shù)是一個(gè)BufferInfo對(duì)象,你必須認(rèn)真地填入“正確”的值:

BufferInfo info = new BufferInfo();
info.offset = 0;
info.size = sampleSize;
info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;
info.presentationTimeUs = timestamp;
  • info.size:必須填入數(shù)據(jù)的大欣デ荨蝗蛙;

  • info.flags:需要給出是否為同步幀/關(guān)鍵幀;

  • info.presentationTimeUs:必須給出正確的時(shí)間戳醉鳖,注意單位是 us捡硅,例如,對(duì)于幀率為 x f/s 的視頻而言盗棵,時(shí)間戳的間隔就是 1000/x ms壮韭。

??(4)完成后需要關(guān)閉以及釋放資源

mMediaMuxer.stop();
mMediaMuxer.releaser();

4.demo

??完整的demo代碼如下:

protected boolean process() throws IOException {
    mMediaExtractor = new MediaExtractor();
    mMediaExtractor.setDataSource(SDCARD_PATH+"/input.mp4");

    int mVideoTrackIndex = -1;
    int framerate = 0;
    for(int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
        MediaFormat format = mMediaExtractor.getTrackFormat(i);
        String mime = format.getString(MediaFormat.KEY_MIME);
        if(!mime.startsWith("video/")) {
            continue;
        }
        framerate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
        mMediaExtractor.selectTrack(i);
        mMediaMuxer = new MediaMuxer(SDCARD_PATH+"/ouput.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);
        mVideoTrackIndex = mMediaMuxer.addTrack(format);
        mMediaMuxer.start();
    }

    if(mMediaMuxer == null) {
        return false;
    }

    BufferInfo info = new BufferInfo();
    info.presentationTimeUs = 0;
    ByteBuffer buffer = ByteBuffer.allocate(500*1024);

    while(true) {
        int sampleSize = mMediaExtractor.readSampleData(buffer, 0);
        if(sampleSize < 0) {
            break;
        }

        mMediaExtractor.advance();
        info.offset = 0;
        info.size = sampleSize;
        info.flags = MediaCodec.BUFFER_FLAG_SYNC_FRAME;
        info.presentationTimeUs += 1000*1000/framerate;
        mMediaMuxer.writeSampleData(mVideoTrackIndex,buffer,info);
      }

    mMediaExtractor.release();
    mMediaMuxer.stop();
    mMediaMuxer.release();

    return true;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纹因,隨后出現(xiàn)的幾起案子喷屋,更是在濱河造成了極大的恐慌,老刑警劉巖瞭恰,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屯曹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡惊畏,警方通過(guò)查閱死者的電腦和手機(jī)恶耽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)颜启,“玉大人偷俭,你說(shuō)我怎么就攤上這事∨┣” “怎么了社搅?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乳规。 經(jīng)常有香客問(wèn)我形葬,道長(zhǎng),這世上最難降的妖魔是什么暮的? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任笙以,我火速辦了婚禮,結(jié)果婚禮上冻辩,老公的妹妹穿的比我還像新娘猖腕。我一直安慰自己拆祈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布倘感。 她就那樣靜靜地躺著放坏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪老玛。 梳的紋絲不亂的頭發(fā)上淤年,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蜡豹,去河邊找鬼麸粮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛镜廉,可吹牛的內(nèi)容都是我干的弄诲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼娇唯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼齐遵!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起视乐,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤洛搀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后佑淀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體留美,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年伸刃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谎砾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捧颅,死狀恐怖景图,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碉哑,我是刑警寧澤挚币,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站扣典,受9級(jí)特大地震影響妆毕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贮尖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一笛粘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦薪前、人聲如沸润努。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铺浇。三九已至,卻和暖如春垛膝,著一層夾襖步出監(jiān)牢的瞬間随抠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工繁涂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人二驰。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓扔罪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親桶雀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矿酵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容