Как использовать AVAssetWriter для записи звука AAC в ios?

Я использую AVCaptureSession для захвата аудио- и видеосэмплов с микрофона и камеры устройств.

Затем я пытаюсь записать CMSampleBuffers (используя AVAssetWriter и AVAssetWriterInputs), возвращаемые с помощью метода делегата AVCaptureSessions.

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:    (CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

Это отлично работает, когда мой аудио AVAssetWriterInput настроен на запись данных в формате Apple Lossless (kAudioFormatAppleLossless), но если я попытаюсь настроить аудио AVAssetWriterInput на использование AAC (kAudioFormatMPEG4AAC), он успешно записывает видео и аудио сэмплы в течение примерно 500 мс, а затем выходит из строя с следующая ошибка

writer has failed with Error Domain=AVFoundationErrorDomain Code=-11821 "Cannot Decode" UserInfo=0x4b2630 {NSLocalizedFailureReason=The media data could not be decoded. It may be damaged., NSUnderlyingError=0x4ad0f0 "The operation couldn’t be completed. (OSStatus error 560226676.)", NSLocalizedDescription=Cannot Decode}

Вот код, который я использую для создания своих AVAssetWriter и AVAssetWriterInputs.

NSError *error = nil;
m_VideoCaputurePath = [[NSString stringWithFormat:@"%@/%@.mp4",[UserData getSavePath],[UserData getUniqueFilename]] retain];

if( USE_AAC_AUDIO )
{
    m_audioAndVideoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:m_VideoCaputurePath] fileType:AVFileTypeMPEG4 error:&error];
}
else
{
    m_audioAndVideoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:m_VideoCaputurePath] fileType:AVFileTypeQuickTimeMovie error:&error];
}

//\Configure Video Writer Input
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                               AVVideoCodecH264, AVVideoCodecKey,
                               [NSNumber numberWithInt:640], AVVideoWidthKey,
                               [NSNumber numberWithInt:480], AVVideoHeightKey,
                               nil];

m_videoWriterInput = [[AVAssetWriterInput
                       assetWriterInputWithMediaType:AVMediaTypeVideo
                       outputSettings:videoSettings] retain];

m_videoWriterInput.expectsMediaDataInRealTime = YES;

//\Configure Audio Writer Input

AudioChannelLayout acl;
bzero(&acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;

NSDictionary*  audioOutputSettings;
if( USE_AAC_AUDIO )
{
    audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
                                          [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
                                          [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                                          [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey,
                                          [ NSNumber numberWithInt: 96 ], AVEncoderBitRateKey,
                                          nil];
}
else
{
    audioOutputSettings = [ NSDictionary dictionaryWithObjectsAndKeys:                       
                                          [ NSNumber numberWithInt: kAudioFormatAppleLossless ], AVFormatIDKey,
                                          [ NSNumber numberWithInt: 16 ], AVEncoderBitDepthHintKey,
                                          [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                                          [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,                                      
                                          [ NSData dataWithBytes: &acl length: sizeof( acl ) ], AVChannelLayoutKey, nil ];
}

m_audioWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:audioOutputSettings] retain];

m_audioWriterInput.expectsMediaDataInRealTime = YES;

//\Add inputs to Write
NSAssert([m_audioAndVideoWriter canAddInput:m_audioWriterInput], @"Cannot write to this type of audio input" );
NSAssert([m_audioAndVideoWriter canAddInput:m_videoWriterInput], @"Cannot write to this type of video input" );

[m_audioAndVideoWriter addInput:m_videoWriterInput];
[m_audioAndVideoWriter addInput:m_audioWriterInput];

Кто-нибудь знает, как правильно записывать аудиосэмплы, возвращаемые из AVCaptureSession, с помощью AVAssetWriterInput, настроенного для записи AAC?


person RyanSullivan    schedule 04.10.2011    source источник


Ответы (1)


Мне удалось заставить его работать, изменив параметр AVEncoderBitRateKey, переданный в качестве желаемых параметров вывода, с 96 до 64000.

Мои настройки звука для инициализации AVAssetWriterInput, способного записывать звук AAC, теперь выглядят так:

    NSDictionary*  audioOutputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [ NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
                                    [ NSNumber numberWithInt: 1 ], AVNumberOfChannelsKey,
                                    [ NSNumber numberWithFloat: 44100.0 ], AVSampleRateKey,
                                    [ NSData dataWithBytes: &acl length: sizeof( AudioChannelLayout ) ], AVChannelLayoutKey,
                                    [ NSNumber numberWithInt: 64000 ], AVEncoderBitRateKey,
                                    nil]
person RyanSullivan    schedule 05.10.2011
comment
С новым iPhone 4s мне также пришлось изменить AVNumberOfChannelsKey на 2. - person RyanSullivan; 17.10.2011
comment
Я просто не мог понять это! Я знал, что это как-то связано с опциями, но не знал, что именно. Спасибо за это! - person Pedro Mancheno; 04.05.2012