2016-03-21 14 views
0

私は、マイクからのオーディオ(didGetAudioDataの上書き)とカメラからのビデオ(onpreviewframeを上書き)を多重化してmp4ファイルを作成したいと思います。同期の問題では、ビデオはオーディオよりも速く表示されます。私は互換性のない設定やpresentationTimeUsに関連する問題が誰かに私の問題の解決方法を教えてくれるのかどうか疑問に思いました。私のソフトウェアは以下の通りです。mp4ファイルにmediacodecとmediamuxerを使用すると、オーディオとビデオのトラック同期の問題が発生する

ビデオ設定

formatVideo = MediaFormat.createVideoFormat(MIME_TYPE_VIDEO, 640, 360); 
formatVideo.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar); 
formatVideo.setInteger(MediaFormat.KEY_BIT_RATE, 2000000); 
formatVideo.setInteger(MediaFormat.KEY_FRAME_RATE, 30); 
formatVideo.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 5); 

は、以下のようにビデオpresentationPTS、以下のようにオーディオpresentationPTSを得た

format = MediaFormat.createAudioFormat(MIME_TYPE, 48000/*sample rate*/, AudioFormat.CHANNEL_IN_MONO /*Channel config*/); 
format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); 
format.setInteger(MediaFormat.KEY_SAMPLE_RATE,48000); 
format.setInteger(MediaFormat.KEY_CHANNEL_COUNT,1); 
format.setInteger(MediaFormat.KEY_BIT_RATE,64000); 

if(generateIndex == 0) { 
    videoAbsolutePtsUs = 132; 
    StartVideoAbsolutePtsUs = System.nanoTime()/1000L; 
}else { 
    CurrentVideoAbsolutePtsUs = System.nanoTime()/1000L; 
    videoAbsolutePtsUs =132+ CurrentVideoAbsolutePtsUs-StartVideoAbsolutePtsUs; 
} 
generateIndex++; 

オーディオ構成を、持っ

if(generateIndex == 0) { 
    audioAbsolutePtsUs = 132; 
    StartAudioAbsolutePtsUs = System.nanoTime()/1000L; 
}else { 
    CurrentAudioAbsolutePtsUs = System.nanoTime()/1000L; 
    audioAbsolutePtsUs =CurrentAudioAbsolutePtsUs - StartAudioAbsolutePtsUs; 
} 

generateIndex++; 
audioAbsolutePtsUs = getJitterFreePTS(audioAbsolutePtsUs, audioInputLength/2); 

long startPTS = 0; 
long totalSamplesNum = 0; 
private long getJitterFreePTS(long bufferPts, long bufferSamplesNum) { 
    long correctedPts = 0; 
    long bufferDuration = (1000000 * bufferSamplesNum)/48000; 
    bufferPts -= bufferDuration; // accounts for the delay of acquiring the audio buffer 
    if (totalSamplesNum == 0) { 
     // reset 
     startPTS = bufferPts; 
     totalSamplesNum = 0; 
    } 
    correctedPts = startPTS + (1000000 * totalSamplesNum)/48000; 
    if(bufferPts - correctedPts >= 2*bufferDuration) { 
     // reset 
     startPTS = bufferPts; 
     totalSamplesNum = 0; 
     correctedPts = startPTS; 
    } 
    totalSamplesNum += bufferSamplesNum; 
    return correctedPts; 
} 

私の問題は、オーディオ専用のジッタ機能を適用したことが原因でしたか?はいの場合、ビデオにジッタ機能を適用するにはどうすればよいですか?私も正しいオーディオとビデオのプレゼンテーションを見つけようとしました.PTSはhttps://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.javaです。しかし、encodedecodeTestはビデオPTSのみを提供しました。それが、私の実装がオーディオとビデオの両方にシステムナノタイムを使用した理由です。もし、私がビデオのプレゼンテーションを使用したいのであれば、どのようにオーディオプレゼンテーションを作成するのですか?手伝ってくれてありがとう!

以下は、私が参照するためにビデオmediacodecにyuvフレームをキューする方法です。オーディオ部分については、それは異なるプレゼンテーションPTSを除いて同一である。私は自分のアプリケーションでこれを解決する方法

int videoInputBufferIndex; 
int videoInputLength; 
long videoAbsolutePtsUs; 
long StartVideoAbsolutePtsUs, CurrentVideoAbsolutePtsUs; 

int put_v =0; 
int get_v =0; 
int generateIndex = 0; 

public void setByteBufferVideo(byte[] buffer, boolean isUsingFrontCamera, boolean Input_endOfStream){ 
    if(Build.VERSION.SDK_INT >=18){ 
     try{ 

      endOfStream = Input_endOfStream; 
      if(!Input_endOfStream){ 
      ByteBuffer[] inputBuffers = mVideoCodec.getInputBuffers(); 
      videoInputBufferIndex = mVideoCodec.dequeueInputBuffer(-1); 

       if (VERBOSE) { 
        Log.w(TAG,"[put_v]:"+(put_v)+"; videoInputBufferIndex = "+videoInputBufferIndex+"; endOfStream = "+endOfStream); 
       } 

       if(videoInputBufferIndex>=0) { 
        ByteBuffer inputBuffer = inputBuffers[videoInputBufferIndex]; 
        inputBuffer.clear(); 

        inputBuffer.put(mNV21Convertor.convert(buffer)); 
        videoInputLength = buffer.length; 

        if(generateIndex == 0) { 
         videoAbsolutePtsUs = 132; 
         StartVideoAbsolutePtsUs = System.nanoTime()/1000L; 
        }else { 
         CurrentVideoAbsolutePtsUs = System.nanoTime()/1000L; 
         videoAbsolutePtsUs =132+ CurrentVideoAbsolutePtsUs - StartVideoAbsolutePtsUs; 
        } 

        generateIndex++; 

        if (VERBOSE) { 
         Log.w(TAG, "[put_v]:"+(put_v)+"; videoAbsolutePtsUs = " + videoAbsolutePtsUs + "; CurrentVideoAbsolutePtsUs = "+CurrentVideoAbsolutePtsUs); 
        } 

        if (videoInputLength == AudioRecord.ERROR_INVALID_OPERATION) { 
         Log.w(TAG, "[put_v]ERROR_INVALID_OPERATION"); 
        } else if (videoInputLength == AudioRecord.ERROR_BAD_VALUE) { 
         Log.w(TAG, "[put_v]ERROR_ERROR_BAD_VALUE"); 
        } 
        if (endOfStream) { 
         Log.w(TAG, "[put_v]:"+(put_v++)+"; [get] receive endOfStream"); 
         mVideoCodec.queueInputBuffer(videoInputBufferIndex, 0, videoInputLength, videoAbsolutePtsUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
        } else { 
         Log.w(TAG, "[put_v]:"+(put_v++)+"; receive videoInputLength :" + videoInputLength); 
         mVideoCodec.queueInputBuffer(videoInputBufferIndex, 0, videoInputLength, videoAbsolutePtsUs, 0); 
        } 
       } 
      } 
     }catch (Exception x) { 
      x.printStackTrace(); 
     } 
    } 
} 

答えて

0

共有「同期クロック」に対するすべてのビデオとオーディオフレームのPTSを設定することによりだった(同期も、それはスレッドセーフだ意味に注意してください)ときに最初に起動しますビデオフレーム(それ自体でPTS 0を有する)が利用可能である。したがって、オーディオ録画がビデオより早く開始されると、オーディオデータはビデオが開始されるまで解読され(エンコーダには入りません)、後で開始されると、最初のオーディオPTSはビデオ全体の開始からの相対的なものになります。

勿論、オーディオは最初に開始することができますが、プレーヤーは通常、最初のビデオフレームをスキップしたり、待ったりします。また、エンコードされたオーディオフレームが「順不同」に到着し、MediaMuxerは遅かれ早かれエラーで失敗することに注意してください。私の解決策は、これらのすべてをキューに入れることでした。新しいものが来たらptsでソートし、最新のものよりも高いPTSを持つものだけMediaMuxerに(最新のものと比較して)500ミリ秒より古いものをすべて書き出します書かれたフレーム。これは理想的には、データが500msの遅延でMediaMuxerにスムーズに書き込まれることを意味します。最悪の場合、いくつかのオーディオフレームが失われます。

+0

ありがとう、アドリアン、私に質問がありますか?オーディオジッタフリー関数(getJitterFreePTS)を削除した場合、オーディオdequeueOutputBufferがいくつかのオーディオデータをmediacodecに明白なエラーなしで送信した後に停止しました。考えられる原因について考えていますか? –

+0

PTSを確認すると、単調に増加するはずですが、コードから133で始まっているように見えます。おそらく、2番目のサンプルではそれよりも低いものが得られます。同期クロックを使用するとこれを解決し、ジッタ機能が必要かどうかわからないので、ブロック単位でオーディオを受信します。また、48 kHzはすべてのデバイスで動作することは保証されていませんが、Androidで保証されているサンプルレートは44100です。 –

+0

@AdrianCreţu私はビデオとオーディオの両方を記録し、両方のスレッドがシステムからPTSタイムスタンプを取得する記録エンジンを持っています。nano()は残念ながらオーディオでジッタを発生させ、オーディオを同期させず、最終ビデオで少し遅れてしまいます。私はあなたのソリューションを読んでいますが、PTSシステムの実装方法のコード例を提供できませんでしたか? – Steve

関連する問題