如何使用 AVAssetWriter 在 ios 中写入 AAC 音频?

Posted

技术标签:

【中文标题】如何使用 AVAssetWriter 在 ios 中写入 AAC 音频?【英文标题】:How do I use AVAssetWriter to write AAC audio out in ios? 【发布时间】:2011-10-04 14:24:23 【问题描述】:

我正在使用 AVCaptureSession 从设备的麦克风和摄像头捕获音频和视频样本。

然后我尝试编写通过 AVCaptureSessions 委托方法返回的 CMSampleBuffers(使用 AVAssetWriter 和 AVAssetWriterInputs)

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

当我的音频 AVAssetWriterInput 配置为以 Apple 无损格式 (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];

有谁知道如何使用配置为编写 AAC 的 AVAssetWriterInput 正确编写从 AVCaptureSession 返回的音频样本?

【问题讨论】:

【参考方案1】:

我设法通过将作为所需输出设置传递的 AVEncoderBitRateKey 参数从 96 更改为 64000 来使其工作。

我用于初始化能够写入 AAC 音频的 AVAssetWriterInput 的音频设置现在看起来像

    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]

【讨论】:

对于新的 iPhone 4s,我还必须将 AVNumberOfChannelsKey 更改为 2 我就是想不通!我知道这与选项有关,但不知道具体是什么。谢谢!

以上是关于如何使用 AVAssetWriter 在 ios 中写入 AAC 音频?的主要内容,如果未能解决你的问题,请参考以下文章

AVAssetWriter 元数据日期问题

AVAssetWriter视频数据编码

无法在 iphone 3G 上使用 AVAssetWriter 从 UIImage 数组制作电影

如何使用 AVAssetReader 和 AVAssetWriter 创建 AAC 文件?

IOS 8时间推移功能

AVAssetWriter - 设置自定义帧率