【问题标题】:ExtAudioFileWrite to m4a/aac failing on dual-core devices (ipad 2, iphone 4s)ExtAudioFileWrite 到 m4a/aac 在双核设备(ipad 2、iphone 4s)上失败
【发布时间】:2012-01-03 23:00:36
【问题描述】:

我编写了一个循环来使用扩展音频文件服务将我的应用生成的 pcm 音频数据编码为 aac。编码在后台线程中同步进行,而不是实时进行。

对于 ios 4 和 5,编码在 ipad 1 和 iphone 3gs/4 上完美运行。但是,对于双核设备(iphone 4s、ipad 2),对 ExtAudioFileWrite 的第三次调用会使编码线程崩溃,并且没有堆栈跟踪和没有错误代码。

这里是有问题的代码:

数据格式

AudioStreamBasicDescription AUCanonicalASBD(Float64 sampleRate, 
                                        UInt32 channel){
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate         = sampleRate;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagsAudioUnitCanonical;
audioFormat.mChannelsPerFrame   = channel;
audioFormat.mBytesPerPacket     = sizeof(AudioUnitSampleType);
audioFormat.mBytesPerFrame      = sizeof(AudioUnitSampleType);
audioFormat.mFramesPerPacket    = 1;
audioFormat.mBitsPerChannel     = 8 * sizeof(AudioUnitSampleType);
audioFormat.mReserved           = 0;
return audioFormat;
}

AudioStreamBasicDescription MixdownAAC(void){
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate         = 44100.0;
audioFormat.mFormatID           = kAudioFormatMPEG4AAC;
audioFormat.mFormatFlags        = kMPEG4Object_AAC_Main;
audioFormat.mChannelsPerFrame   = 2;
audioFormat.mBytesPerPacket     = 0;
audioFormat.mBytesPerFrame      = 0;
audioFormat.mFramesPerPacket    = 1024;
audioFormat.mBitsPerChannel     = 0;
audioFormat.mReserved           = 0;
return audioFormat;
}

渲染循环

OSStatus err;
ExtAudioFileRef outFile;
NSURL *mixdownURL = [NSURL fileURLWithPath:filePath isDirectory:NO];

// internal data format
AudioStreamBasicDescription localFormat = AUCanonicalASBD(44100.0, 2);

// output file format
AudioStreamBasicDescription mixdownFormat = MixdownAAC();
err = ExtAudioFileCreateWithURL((CFURLRef)mixdownURL,
                             kAudioFileM4AType,
                             &mixdownFormat, 
                             NULL,
                             kAudioFileFlags_EraseFile,
                             &outFile);


err = ExtAudioFileSetProperty(outFile, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &localFormat);

// prep
AllRenderData *allData = &allRenderData;
writeBuffer = malloc(sizeof(AudioBufferList) + (2*sizeof(AudioBuffer)));
writeBuffer->mNumberBuffers = 2;
writeBuffer->mBuffers[0].mNumberChannels = 1;
writeBuffer->mBuffers[0].mDataByteSize = bufferBytes;
writeBuffer->mBuffers[0].mData = malloc(bufferBytes);
writeBuffer->mBuffers[1].mNumberChannels = 1;
writeBuffer->mBuffers[1].mDataByteSize = bufferBytes;
writeBuffer->mBuffers[1].mData = malloc(bufferBytes);

memset(writeBuffer->mBuffers[0].mData, 0, bufferBytes);
memset(writeBuffer->mBuffers[1].mData, 0, bufferBytes);

UInt32 framesToGet;
UInt32 frameCount = allData->gLoopStartFrame;
UInt32 startFrame = allData->gLoopStartFrame;
UInt32 lastFrame = allData->gLoopEndFrame;

// write one silent buffer
ExtAudioFileWrite(outFile, bufferFrames, writeBuffer);

while (frameCount < lastFrame){

    // how many frames do we need to get
    if (lastFrame - frameCount > bufferFrames)
        framesToGet = bufferFrames;
    else
        framesToGet = lastFrame - frameCount;

    // get dem frames
    err = theBigOlCallback((void*)&allRenderData,
                            NULL, NULL, 1,
                           framesToGet, writeBuffer);

    // write to output file
    ExtAudioFileWrite(outFile, framesToGet, writeBuffer);

    frameCount += framesToGet;
}

// write one trailing silent buffer
memset(writeBuffer->mBuffers[0].mData, 0, bufferBytes);
memset(writeBuffer->mBuffers[1].mData, 0, bufferBytes);
processLimiterInPlace8p24(limiter, writeBuffer->mBuffers[0].mData, writeBuffer->mBuffers[1].mData, bufferFrames);
ExtAudioFileWrite(outFile, bufferFrames, writeBuffer);

err = ExtAudioFileDispose(outFile);

pcm 帧已正确创建,但 ExtAudioFileWrite 在第 2 次/第 3 次调用时失败。

有什么想法吗?谢谢!

【问题讨论】:

  • 你能发布你如何填充缓冲区以及如何调用 ExtAudioFileWrite 吗?
  • 在经历了很多挫折并且没有得到 Apple 的帮助后,我的同事发现了问题所在。显然,在较新的 iOS 设备(iPad 2 和 iPhone 4S)上,44.1 kHz 不是 AAC 编码的有效采样率,至少在使用外部音频文件服务时是这样。 48 kHz 工作得很好。我已将此作为错误提交给 Apple,希望他们会处理它。

标签: iphone ios ipad core-audio aac


【解决方案1】:

我遇到了一个非常相似的问题,我尝试使用扩展音频文件服务将 PCM 声音流式传输到 iPad 2 上的 m4a 文件中。除了每次调用 ExtAudioFileWrite 都返回错误代码 -66567 之外,一切似乎都正常工作(kExtAudioFileError_MaxPacketSizeUnknown)。我最终找到的解决方法是将“编解码器制造商”设置为软件而不是硬件。所以放置

UInt32 codecManf = kAppleSoftwareAudioCodecManufacturer;
ExtAudioFileSetProperty(FileToWrite, kExtAudioFileProperty_CodecManufacturer, sizeof(UInt32), &codecManf);

就在您设置客户端数据格式之前。

这会让我相信 Apple 的硬件编解码器只能支持非常特定的编码,但软件编解码器可以更可靠地执行您想要的操作。就我而言,将软件编解码器转换为 m4a 的时间比将完全相同的文件写入 LPCM 格式的时间要长 50%。

有谁知道 Apple 是否在某处指定了他们的音频编解码器硬件的功能?似乎软件工程师一直在玩长达数小时的猜谜游戏,即为客户端和文件设置 AudioStreamBasicDescription 和 AudioChannelLayout 中的约 20 个参数,直到出现任何可能的排列......

【讨论】:

  • 我花了两天时间调试为什么 AAC 编码突然停止在我的 iPhone 4S 上的多个应用程序上工作,但在我的其他 iOS 设备上却没有。这成功了。我不知道你是怎么想出来的,但非常感谢你,希望你在 SO 上发布更多内容。
  • 我刚刚翻阅了扩展音频文件服务参考并尝试设置变量的每个组合,直到某些东西起作用:P 很高兴我能提供帮助!现在,如果有人能解释为什么设备的硬件功能如此不一致......
  • 伙计...向你致敬。我想知道我的代码中发生了什么严重错误,导致 ExtAudioFileWrite 崩溃而没有回溯。谢谢你的帮助。我已经填补了一个错误,感谢你。希望它将与rorprklacks 的其他错误报告合并。再次感谢。
  • 有趣的更新,虽然这似乎解决了问题并且我们的应用程序现在可以在 iPhone 和 iPad 上构建和运行,但新 iPad 仍然存在同样的问题。即使打开了 softwareaudiocodecmanufacturer 标志,也会发生同样无法追踪的崩溃。奇怪...
  • @Dan1one:我在 iPhone 5 上遇到了同样的问题。当从我的音频单元混音器输出捕获音频并通过 CAAudioUnitOutputCapturer 将其写入 AAC 文件时,ExtAudioFileWriteAsync() API 失败。我之前将编解码器制造商设置为使用软件编解码器,这解决了 4s 上的问题,但它再次出现在 iPhone 5 上,即使使用了软件编解码器设置。您找到解决方法了吗?谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多