2015-04-24 2 views
0

Целью здесь является создание файла mp4 с помощью видео через AVCaptureDataOutput и аудиозапись CoreAudio. Затем отправить CMSampleBuffers обоих к AVAssetWriter, который сопровождающей AVAssetWriterInput (AVMediaTypeVideo) и AVAssetWriterInput (AVMediaTypeAudio)Преобразование AudioBuffer в CMSampleBuffer с точным CMTime

Мой аудио кодировщика копирует AudioBuffer на новый CMSampleBuffer пассы его к AVAssetWriterInput (AVMediaTypeAudio). В этом примере показано, как выполняется преобразование AudioBuffer в CMSampleBuffer. Converstion to CMSampleBuffer

Короче говоря, он не работает. Видео появляется, но нет звука.

НО, если я прокомментирую кодировку видео, аудио записывается в файл и слышится.

Это говорит мне по опыту, что это вопрос времени. Converstion to CMSampleBuffer действительно показывает

CMSampleTimingInfo timing = { CMTimeMake(1, 44100.0), kCMTimeZero, kCMTimeInvalid }; 

Он производит время CMTimeCopyDescription из {0/1 = 0.000}, который, кажется, совершенно неправильно для меня. Я пытался отслеживать оказанные кадры и передачу FrameCount для значения времени и частота дискретизации для временной шкалы, как этого

CMSampleTimingInfo timing = { CMTimeMake(1, 44100.0), CMTimeMake(self.frameCount, 44100.0), kCMTimeInvalid }; 

Но нет костей. Более приятный CMSampleTimingInfo {107520/44100 = 2.438}, но по-прежнему нет звука в файле.

Видео CMSampleBuffer производит что-то вроде этого {65792640630624/1000000000 = 65792.641, rounded}. Это говорит о том, что AVCaptureVideoOutput имеет временную шкалу в 1 миллиард, вероятно, наносекунды. И я гость значение времени является чем-то вроде времени устройства. Я не могу найти информацию о том, что использует AVCaptureVideoOutput.

У кого-нибудь есть полезное руководство? Я даже на правильном пути?

Heres конверсий

CMSampleBufferRef buff = malloc(sizeof(CMSampleBufferRef)); 
    CMFormatDescriptionRef format = NULL; 

    self.frameCount += inNumberFrames; 

    CMTime presentationTime = CMTimeMake(self.frameCount, self.pcmASBD.mSampleRate); 

    AudioStreamBasicDescription audioFormat = self.pcmASBD; 
    CheckError(CMAudioFormatDescriptionCreate(kCFAllocatorDefault, 
               &audioFormat, 
               0, 
               NULL, 
               0, 
               NULL, 
               NULL, 
               &format), 
       "Could not create format from AudioStreamBasicDescription"); 

    CMSampleTimingInfo timing = { CMTimeMake(1, self.pcmASBD.mSampleRate), presentationTime, kCMTimeInvalid }; 

    CheckError(CMSampleBufferCreate(kCFAllocatorDefault, 
            NULL, 
            false, 
            NULL, 
            NULL, 
            format, 
            (CMItemCount)inNumberFrames, 
            1, 
            &timing, 
            0, 
            NULL, 
            &buff), 
       "Could not create CMSampleBufferRef"); 

    CheckError(CMSampleBufferSetDataBufferFromAudioBufferList(buff, 
                   kCFAllocatorDefault, 
                   kCFAllocatorDefault, 
                   0, 
                   audioBufferList), 
       "Could not set data in CMSampleBufferRef"); 

    [self.delegate didRenderAudioSampleBuffer:buff]; 

    CFRelease(buff); 

И assetWriters создать

func createVideoInputWriter()->AVAssetWriterInput? { 
     let numPixels        = Int(self.size.width * self.size.height) 
     let bitsPerPixel:Int      = 11 
     let bitRate         = Int64(numPixels * bitsPerPixel) 
     let fps:Int         = 30 
     let settings:[NSObject : AnyObject]   = [ 
      AVVideoCodecKey       : AVVideoCodecH264, 
      AVVideoWidthKey       : self.size.width, 
      AVVideoHeightKey      : self.size.height, 
      AVVideoCompressionPropertiesKey   : [ 
       AVVideoAverageBitRateKey   : NSNumber(longLong: bitRate), 
       AVVideoMaxKeyFrameIntervalKey  : NSNumber(integer: fps) 
      ] 
     ] 

     var assetWriter:AVAssetWriterInput! 
     if self.mainAssetWriter.canApplyOutputSettings(settings, forMediaType:AVMediaTypeVideo) { 
      assetWriter        = AVAssetWriterInput(mediaType:AVMediaTypeVideo, outputSettings:settings) 
      assetWriter.expectsMediaDataInRealTime = true 
      if self.mainAssetWriter.canAddInput(assetWriter) { 
       self.mainAssetWriter.addInput(assetWriter) 
      } 
     } 
     return assetWriter; 
    } 

    func createAudioInputWriter()->AVAssetWriterInput? { 
     let settings:[NSObject : AnyObject]   = [ 
      AVFormatIDKey       : kAudioFormatMPEG4AAC, 
      AVNumberOfChannelsKey     : 2, 
      AVSampleRateKey       : 44100, 
      AVEncoderBitRateKey      : 64000 
     ] 

     var assetWriter:AVAssetWriterInput! 
     if self.mainAssetWriter.canApplyOutputSettings(settings, forMediaType:AVMediaTypeAudio) { 
      assetWriter        = AVAssetWriterInput(mediaType:AVMediaTypeAudio, outputSettings:settings) 
      assetWriter.expectsMediaDataInRealTime = true 
      if self.mainAssetWriter.canAddInput(assetWriter) { 
       self.mainAssetWriter.addInput(assetWriter) 
      } else { 
       let error = NSError(domain:CMHDFileEncoder.Domain, code:CMHDFileEncoderErrorCode.CantAddInput.rawValue, userInfo:nil) 
       self.errorDelegate.hdFileEncoderError(error) 
      } 
     } else { 
      let error = NSError(domain:CMHDFileEncoder.Domain, code:CMHDFileEncoderErrorCode.CantApplyOutputSettings.rawValue, userInfo:nil) 
      self.errorDelegate.hdFileEncoderError(error) 
     } 
     return assetWriter 
    } 

ответ

1

Конечно, была проблема в течение 2-х недель, отправил вопрос на пятницу ночью, и нашли решение утро понедельника.

Исследование я наткнулся с поставить меня на правильном пути ...

1000000000 временные рамки для наносекунд. Но значение времени должно быть наносекундами устройств абсолютного времени.

Это сообщение объясняет лучше, чем я могу - mach time

Я закончил с использованием этого кода, чтобы исправить

CMSampleBufferRef buff = malloc(sizeof(CMSampleBufferRef)); 
    CMFormatDescriptionRef format = NULL; 

    AudioStreamBasicDescription audioFormat = self.pcmASBD; 
    CheckError(CMAudioFormatDescriptionCreate(kCFAllocatorDefault, 
               &audioFormat, 
               0, 
               NULL, 
               0, 
               NULL, 
               NULL, 
               &format), 
       "Could not create format from AudioStreamBasicDescription"); 

    uint64_t time = inTimeStamp->mHostTime; 
    /* Convert to nanoseconds */ 
    time *= info.numer; 
    time /= info.denom; 
    CMTime presentationTime     = CMTimeMake(time, kDeviceTimeScale); 
    CMSampleTimingInfo timing    = { CMTimeMake(1, self.pcmASBD.mSampleRate), presentationTime, kCMTimeInvalid }; 

    CheckError(CMSampleBufferCreate(kCFAllocatorDefault, 
            NULL, 
            false, 
            NULL, 
            NULL, 
            format, 
            (CMItemCount)inNumberFrames, 
            1, 
            &timing, 
            0, 
            NULL, 
            &buff), 
       "Could not create CMSampleBufferRef"); 

    CheckError(CMSampleBufferSetDataBufferFromAudioBufferList(buff, 
                   kCFAllocatorDefault, 
                   kCFAllocatorDefault, 
                   0, 
                   audioBufferList), 
       "Could not set data in CMSampleBufferRef"); 
+0

Здравствуйте, спасибо за этим решение, вы можете объяснить мне, что inTimeStamp ? и информация? –

+0

Эй, Pablo, 'inTimeStamp' - это метка времени, связанная с буфером-образцом от функции обратного вызова, установленной на аудиоустройстве. Он присваивается через «AURenderCallbackStruct».Я очень рекомендую [Learning Core Audio] (http://www.amazon.com/Learning-Core-Audio-Hands-On-Programming/dp/0321636848), если вы хотите узнать больше. – hatebyte

+0

Спасибо! Проблема в том, что я получаю AudioBufferList из потоковой службы. Вы знаете, как я могу это сделать? –

Смежные вопросы