Android短影片系統硬編碼—實現音影片編碼(三)

雲豹科技曉彤發表於2021-07-01

MediaMuxer(音影片混合API)

MediaMuxer 的使用很簡單,在 Android Developer 官網 MediaMuxer API 說明中,也有其簡單的使用示例程式碼:

MediaMuxer muxer = new MediaMuxer("temp.mp4", OutputFormat.MUXER_OUTPUT_MPEG_4);

// More often, the MediaFormat will be retrieved from MediaCodec.getOutputFormat()

// or MediaExtractor.getTrackFormat().

MediaFormat audioFormat = new MediaFormat(...);

MediaFormat videoFormat = new MediaFormat(...);

int audioTrackIndex = muxer.addTrack(audioFormat);

int videoTrackIndex = muxer.addTrack(videoFormat);

ByteBuffer inputBuffer = ByteBuffer.allocate(bufferSize);

boolean finished = false;

BufferInfo bufferInfo = new BufferInfo();

 

muxer.start();

while(!finished) {

  // getInputBuffer() will fill the inputBuffer with one frame of encoded

  // sample from either MediaCodec or MediaExtractor, set isAudioSample to

  // true when the sample is audio data, set up all the fields of bufferInfo,

  // and return true if there are no more samples.

  finished = getInputBuffer(inputBuffer, isAudioSample, bufferInfo);

  if (!finished) {

    int currentTrackIndex = isAudioSample ? audioTrackIndex : videoTrackIndex;

    muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);

  }

};

muxer.stop();

muxer.release();

 

參照官方的說明和程式碼示例,我們可以知道,音影片混合(也可以音訊和音訊混合),只需要將編碼器的MediaFormat 加入到 MediaMuxer 中,得到一個音軌影片軌的索引,然後每次從編碼器中取出來的 ByteBuffer ,寫入( writeSampleData )到編碼器所在的軌道中就 ok 了。
這裡需要注意的是,一定要等編碼器設定編碼格式完成後,再將它加入到混合器中,編碼器編碼格式設定完成的標誌是dequeueOutputBuffer 得到返回值為 MediaCodec.INFO_OUTPUT_FORMAT_CHANGED

音影片錄製MP4檔案

前面兩篇文章已經給出了短影片系統音訊錄製的程式碼和影片錄製的程式碼,利用MediaMuxer 將其結合起來,就可以和簡單的完成錄製有聲音有影像的 MP4 檔案的功能了。短影片系統音訊錄製和影片錄製的基本流程保持不變,在錄製編碼後,不再將編碼的結果寫入到檔案流中,而是寫入為混合器的 sample data 。以影片為例,更改迴圈編碼的程式碼為:

// 流程一直,無需更改

int index=mVideoEnc.dequeueInputBuffer(-1);

if(index>=0){

    if(hasNewData){

        if(yuv==null){

            yuv=new byte[width*height*3/2];

        }

        rgbaToYuv(data,width,height,yuv);

    }

    ByteBuffer buffer=getInputBuffer(mVideoEnc,index);

    buffer.clear();

    buffer.put(yuv);

    // 結束時,傳送結束標誌,在編碼完成後結束

    mVideoEnc.queueInputBuffer(index,0,yuv.length,

        mStartFlag?0:MediaCodec.BUFFER_FLAG_END_OF_STREAM);

}

MediaCodec.BufferInfo mInfo=new MediaCodec.BufferInfo();

int outIndex=mVideoEnc.dequeueOutputBuffer(mInfo,0);

do {

    if(outIndex>=0){

        ByteBuffer outBuf=getOutputBuffer(mVideoEnc,outIndex);

        // 裡面不在是寫入到檔案,而是寫入為混合器的 sample data

        if(mTrackCount==3&&mInfo.size>0){

            mMuxer.writeSampleData(mVideoTrack,outBuf,mInfo);

        }

        mVideoEnc.releaseOutputBuffer(outIndex,false);

        outIndex=mVideoEnc.dequeueOutputBuffer(mInfo,0);

        Log.e("wuwang","outIndex-->"+outIndex);

        // 編碼結束的標誌

        if((mInfo.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0){

            return true;

        }

    }else if(outIndex==MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){

       // 按照 MediaMuxer 中所說,加入軌道的時機在這裡

        mVideoTrack=mMuxer.addTrack(mVideoEnc.getOutputFormat());

        Log.e("wuwang","video track-->"+mVideoTrack);

        mTrackCount++;

        // 一定要音軌影片軌都加入後,再開始混合

        if(mTrackCount==2){

            mMuxer.start();

            mTrackCount=3;

        }

    }

}while (outIndex>=0);

 

當然是用MediaMuxer 前,肯定是需要建立一個 MediaMuxer 的例項的:

mMuxer=new MediaMuxer(path+"."+postfix, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);

 

短影片系統音訊的操作和影片一樣更改,將音訊編碼也加入MeidaMuxer 的軌道中,得到一個軌道索引,將編碼後的資料加入為 MediaMuxer 當前音軌的 sample data 。音軌和上面的視軌各自做各自的,結束錄製時,都傳送結束標誌,然後在短影片系統編碼結束後,停止混合器就可以得到一個固定位元速率的 MP4 檔案了。

總結

至此,有關Android 短影片系統硬編碼部落格就結束了。但是在實際使用 MediaCodec MediaMuxer 的過程中,總會遇到這樣或者那樣的問題,硬編硬解,和硬體相關比較緊密, Android 雖然提供了一個很好的 API ,但是各個廠商在實現的過程中,總是會做些讓自己變得獨特的事情。當然他們的目的並不是為了獨特,有的是為了讓產品變得更優秀(雖然最後可能會做砸了),有的是為了省錢,用軟體去彌補硬體的缺陷,最後的結果就是苦了做上層開發的碼農們。
從博主在使用MediaCodec MediaMuxer 的過程中遇到的問題,總結下需要注意主要有以下幾點:

MediaCodec Android4.1 新增 API MediaMuxer Android4.3 新增 API
顏色空間。按照Android 本身的意思, COLOR_FormatYUV420Planar 應該是所有硬體平臺都支援的。但是實際上並不是這樣。所以在設定顏色空間時,應該獲取硬體平臺所支援的顏色空間,確保它是支援你打算使用的顏色空間,不支援的話應該啟用備用方案(使用其他當前硬體支援的顏色空間)。
影片尺寸,在一些手機上,短影片系統影片錄製的尺寸可以是任意的。但是有些手機,不支援的尺寸設定會導致錄製的影片現錯亂。博主在使用Oppo R7 測試, 360*640 的影片,單獨錄製影片沒問題,音影片混合後,出現了顏色錯亂的情況,而在 360F4 手機上,卻都是沒問題的。將影片寬高都設定為 16 的倍數,可以解決這個問題。
短影片系統編碼器格式設定,諸如音訊編碼的取樣率、位元率等,取值也需要結合硬體平臺來設定,否則也會導致崩潰或其他問題。這個其實和顏色空間的選擇一樣。
網上看到許多queueInputBuffer 中設定 presentationTimeUs System.nanoTime()/1000 ,這樣做會導致編碼出來的音影片,在播放時,總時長顯示的是錯誤的。應該記錄開始時候的 nanoTime ,然後設定 presentationTimeUs (System.nanoTime()-nanoTime)/1000
短影片系統錄製結束時,應該傳送結束標誌MediaCodec.BUFFER_FLAG_END_OF_STREAM ,在編碼後區獲得這個標誌時再終止迴圈,而不是直接終止迴圈。
應該還有其他需要注意的問題。我暫時還沒遇到。
————————————————

宣告:宣告:本文由雲豹科技轉發自CSDN 湖廣午王 】部落格,如有侵權請聯絡作者刪除
原文連結:https://blog.csdn.net/junzia/article/details/54018671

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70002045/viewspace-2779322/,如需轉載,請註明出處,否則將追究法律責任。

相關文章