2016-03-21 13 views
0

Mikrofondan multipleksleme ses (didGetAudioData üzerine yaz) ve kameradan video (onpreviewframe üzerine yazarak) üretmek istiyorum mp4 dosyası üretmek istiyorum.Ancak, ses ve video ile karşılaştım Senkronizasyon problemi, video sesden daha hızlı görünecektir. Uyumsuz yapılandırmalar veya presentationTimeUs ile ilgili problemin, birisinin sorunu nasıl düzeltebilirim diye bana rehberlik edip edemeyeceğini merak ettim. Aşağıda benim yazılımı vardı.mediacodec ve mp4 dosyaları için mediamuxer kullanırken ses ve video parça senkronizasyonu sorunu

video yapılandırma

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); 

olarak aşağıdaki video presentationPTS, aşağıda ses presentationPTS var

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++; 

ses konfigürasyonu, var

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; 
} 

Sorunum yalnızca ses için jitter işlevinin uygulanmasından mı kaynaklandı? Varsa, video için jitter işlevini nasıl uygulayabilirim? Ayrıca https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java tarafından doğru ses ve video sunumlarını bulmaya çalıştım. Ancak encodedecodeTest sadece video PTS sağladı. Uygulamamın hem ses hem de video için sistem nanotim kullanmasının sebebi buydu. Eğer encodedecodetest içinde video sunumuPTS kullanmak istersem, uyumlu ses sunumunu nasıl yapabilirim? Yardım için teşekkürler! Aşağıda, referans için yuva çerçevesini video mediacodec'e nasıl sıraya koyacağım . Ses parçası için farklı sunumlar hariç aynıdır. Bunu çözüldü nasıl

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(); 
     } 
    } 
} 

cevap

0

benim uygulamada paylaşılan "senkronizasyon saat" karşı tüm video ve ses çerçevelerinin PTS ayarlayarak oldu başlar ( ayrıca iş parçacığı güvenli olduğu anlamına gelir senkronizasyonu dikkat edin) ne zaman ilk Video karesi (kendi kendine PTS 0'a sahip) mevcuttur. Dolayısıyla, ses kaydı videodan daha erken başlarsa, video başlayana kadar ses verileri işten çıkarılır (kodlayıcıya gitmez) ve daha sonra başlayacaksa, ilk ses PTS tüm videonun başlangıcına göre olacaktır.

Tabii ki, öncelikle sesin başlamasına izin vermekte özgürsünüz, ancak oyuncular genellikle ilk video çerçevesini atlayacak veya bekleyeceklerdir. Ayrıca, kodlanmış ses çerçevelerinin "sipariş dışı" durumuna geleceğine ve MediaMuxer'ın bir hatayla er ya da geç başarısız olmasına dikkat edin. Benim çözümüm onları şu şekilde sıraya koymaktı: yeni bir tane girdiğinde bunları pts ile sıralayın, sonra MediaMuxer'a 500 ms'den daha eski olanı (en yeni olana göre) yazınız, ancak sadece PTS'si en geç daha yüksek yazılı çerçeve. İdeal olarak bu, verilerin derhal 500 ms gecikme ile MediaMuxer'a yazılması anlamına gelir. En kötü durum, birkaç ses çerçevesini kaybedersiniz.

+0

Teşekkürler Adrian, bir sorum olabilir mi? Ben ses jitter serbest fonksiyonu (getJitterFreePTS), ses dequeueOutputBuffer açık bir hata olmadan mediacodec birkaç ses verileri gönderdikten sonra durdu buldum. Sorunun olası bir nedeni hakkında fikriniz var mı? –

+0

PTS'yi kontrol edin, monotonik olarak artmalı, ancak kodunuz 133'den başlıyor gibi görünüyor ve muhtemelen ikinci örneğinizden daha düşük bir şey elde edersiniz. Bir senkronizasyon saati kullanarak bunu çözer ve btw bir jitter işlevine ihtiyacınız olduğundan emin değilim, bloklar halinde ses alırsınız. Ayrıca, 48 kHz'nin tüm cihazlarda çalışacağı garanti edilmez, Android'de garanti edilen tek örnekleme oranı 44100'dür. –

+0

@ AdrianCrețu Hem görüntü hem ses kaydeden ve her iki iş parçacığının Sistem'den bir PTS zaman damgası almasını sağlayan bir kayıt motorum var.nano() maalesef bu, Audio'da jitter'e neden oluyor ve Audio'nun senkronizasyondan çıkmasını sağlıyor ve son videoda biraz geciktiriyorum, çözümünüzü okuyordum ama işe yaramayabilirdim, lütfen PTS sisteminizi nasıl uygulayacağınıza dair bir kod örneği verebilir misiniz? – Steve

İlgili konular