2014-01-13 13 views
11

私は、MediaCodecを使ってスクリーンキャプチャとオーディオを記録するアプリケーションを書いています。私は、mp4ファイルを作成するためにビデオとオーディオをmuxにMediaMuxerを使用しています。私は成功裏にビデオとオーディオを別々に書き込むことに成功しましたが、それらを一緒にマルチプレクサで試してみると、予期せぬ結果になります。オーディオはビデオなしで再生されるか、またはビデオはオーディオ直後に再生されます。私の推測では、私はタイムスタンプで何か間違っているのですが、私は正確に何が分かりません。私は既にその例を見てみました:https://github.com/OnlyInAmerica/HWEncoderExperiments/tree/audiotest/HWEncoderExperiments/src/main/java/net/openwatch/hwencoderexperimentsとbigflake.comのもので、答えを見つけることができませんでした。へオーディオとビデオの両方をマルチプレックスできません

mInputSurface.setPresentationTime(mSurfaceTexture.getTimestamp()); 
drainVideoEncoder(false); 

そして、この:私は、ビデオのタイムスタンプを設定するために、これを使用

 mVideoEncoder = MediaCodec.createEncoderByType(Preferences.MIME_TYPE); 
    mVideoEncoder.configure(mVideoFormat, null, null, 
      MediaCodec.CONFIGURE_FLAG_ENCODE); 
    mInputSurface = new InputSurface(mVideoEncoder.createInputSurface(), 
      mSavedEglContext); 
    mVideoEncoder.start(); 
    if (recordAudio){ 
     audioBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, 
     AudioFormat.ENCODING_PCM_16BIT); 
     mAudioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 44100, 
     AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, audioBufferSize); 
     mAudioRecorder.startRecording(); 

     mAudioEncoder = MediaCodec.createEncoderByType("audio/mp4a-latm"); 
     mAudioEncoder.configure(mAudioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 
     mAudioEncoder.start(); 
    } 
    try { 
     String fileId = String.valueOf(System.currentTimeMillis()); 
     mMuxer = new MediaMuxer(dir.getPath() + "/Video" 
       + fileId + ".mp4", 
       MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 
    } catch (IOException ioe) { 
     throw new RuntimeException("MediaMuxer creation failed", ioe); 
    } 
    mVideoTrackIndex = -1; 
    mAudioTrackIndex = -1; 
    mMuxerStarted = false; 

mVideoFormat = createMediaFormat(); 

    private static MediaFormat createVideoFormat() { 
    MediaFormat format = MediaFormat.createVideoFormat(
      Preferences.MIME_TYPE, mScreenWidth, mScreenHeight); 
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, 
      MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); 
    format.setInteger(MediaFormat.KEY_BIT_RATE, Preferences.BIT_RATE); 
    format.setInteger(MediaFormat.KEY_FRAME_RATE, Preferences.FRAME_RATE); 
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 
      Preferences.IFRAME_INTERVAL); 
    return format; 
} 
    mAudioFormat = createAudioFormat(); 

    private static MediaFormat createAudioFormat() { 
    MediaFormat format = new MediaFormat(); 
    format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); 
    format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); 
    format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 44100); 
    format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); 
    format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); 
    return format; 
} 

オーディオとビデオエンコーダー、ミュクサー:

は、ここに私のメディアフォーマットの設定ですオーディオタイムスタンプを設定する:

誰かが、私は問題を把握してください助けることができますか?
lastQueuedPresentationTimeStampUs = getNextQueuedPresentationTimeStampUs(); 

if(endOfStream) 
    mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, audioBuffer.length, lastQueuedPresentationTimeStampUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); 
else 
    mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, audioBuffer.length, lastQueuedPresentationTimeStampUs, 0); 


    mAudioBufferInfo.presentationTimeUs = getNextDeQueuedPresentationTimeStampUs(); 
    mMuxer.writeSampleData(mAudioTrackIndex, encodedData, 
          mAudioBufferInfo); 
    lastDequeuedPresentationTimeStampUs = mAudioBufferInfo.presentationTimeUs; 


    private static long getNextQueuedPresentationTimeStampUs(){ 
    long nextQueuedPresentationTimeStampUs = (lastQueuedPresentationTimeStampUs > lastDequeuedPresentationTimeStampUs) 
      ? (lastQueuedPresentationTimeStampUs + 1) : (lastDequeuedPresentationTimeStampUs + 1); 
    Log.i(TAG, "nextQueuedPresentationTimeStampUs: " + nextQueuedPresentationTimeStampUs); 
    return nextQueuedPresentationTimeStampUs; 
} 


private static long getNextDeQueuedPresentationTimeStampUs(){ 
    Log.i(TAG, "nextDequeuedPresentationTimeStampUs: " + (lastDequeuedPresentationTimeStampUs + 1)); 
    lastDequeuedPresentationTimeStampUs ++; 
    return lastDequeuedPresentationTimeStampUs; 
} 

私は「timestampUs XXX < lastTimestampUs XXX」エラー

を避けるために、この例https://github.com/OnlyInAmerica/HWEncoderExperiments/blob/audiotest/HWEncoderExperiments/src/main/java/net/openwatch/hwencoderexperiments/AudioEncodingTest.javaからそれを取りましたか

答えて

7

それはあなたがビデオのためのシステム提供のタイムスタンプを使用しているように見えますが、オーディオのためのシンプルなカウンター。何らかの形でビデオタイムスタンプがフレームごとにオーディオをシードするために使用されている場合を除き、それは上記には表示されていません。

は同期して再生するオーディオとビデオのために、あなたが同時に提示することが期待されているオーディオおよびビデオフレームの同じプレゼンテーションタイムスタンプを持っている必要があります。

もこのrelated questionを参照してください。

+0

おかげで、私は、オーディオとビデオを同期することができました!あなたは素晴らしいです:) – Alexey

+0

私はもう少し小さな問題があります。私の録音は、オーディオを再生してから、オーディオを再生しないで再生する方が速くなります。そして、オーディオトラックが歪んでいるようです。これはオーディオが各ビデオフレームでチャンクによってチャンクされているために起こると思います。書き込まれるオーディオチャンクのサイズは、fpsとサンプルレートに応じてカウントされます。私のfpsは大きく変わるので、オーディオは不等なチャンク、ひいては歪みによって書き込まれます。多分あなたはそれに対処する方法について何か提案がありますか? – Alexey

+0

残念ながら私はオーディオであまり仕事をしていません。オーディオタイムスタンプはどこから来ていますか?あなたは、ビデオタイムスタンプ(SurfaceTextureタイムスタンプ)の良いソースを持っています。あなたは、オーディオのために似たようなものを使用しているか、 'System.nanoTime()'でそれを偽っているはずです。 (メディアのものは、一般的に、System.nanoTime()と同じようにシステム単調時計を使用しますが、その一部ではナノ秒ではなくマイクロ秒が使用されます)。 – fadden

0

解決策は、単にオーディオサンプルを繰り返し再生することだと思います。 N個のオーディオサンプルごとに新しいビデオフレームが使用可能かどうかを確認し、新しいビデオフレームが到着するとすぐに同じタイムスタンプでMuxerに渡します。

int __buffer_offset = 0; 
final int CHUNK_SIZE = 100; /* record 100 samples each iteration */ 
while (!__new_video_frame_available) { 
    this._audio_recorder.read(__recorded_data, __buffer_offset, CHUNK_SIZE); 
    __buffer_offset += CHUNK_SIZE; 
} 

私はうまくいくと思います。

親切よろしく、 ヴォルフラム

たくさんfadden
関連する問題