Целью здесь является создание файла 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
}
Здравствуйте, спасибо за этим решение, вы можете объяснить мне, что inTimeStamp ? и информация? –
Эй, Pablo, 'inTimeStamp' - это метка времени, связанная с буфером-образцом от функции обратного вызова, установленной на аудиоустройстве. Он присваивается через «AURenderCallbackStruct».Я очень рекомендую [Learning Core Audio] (http://www.amazon.com/Learning-Core-Audio-Hands-On-Programming/dp/0321636848), если вы хотите узнать больше. – hatebyte
Спасибо! Проблема в том, что я получаю AudioBufferList из потоковой службы. Вы знаете, как я могу это сделать? –