ExtAudioFileWrite 生成不可用的 m4a aac 文件

发布于 2024-09-30 05:16:42 字数 4180 浏览 0 评论 0原文

我正在尝试将单声道线性 pcm 文件转换为 aac 文件。经过一番努力,我终于使用以下设置输出了它,但现在该文件无法播放。我真的不知道该去哪里寻找 - 我找到的所有示例都与我已有的类似。

我见过的所有示例都有 destFormat.mBytesPerPacket = 0 但我无法让它写入(我在写入时得到 -66567,它解析为 kExtAudioFileError_MaxPacketSizeUnknown)。

ExtAudioFileRef sourceFile = 0;
ExtAudioFileRef destinationFile = 0;
OSStatus        error = noErr;

AudioStreamBasicDescription srcFormat, destFormat;
UInt32 size = sizeof(srcFormat);
error = ExtAudioFileOpenURL((CFURLRef)self.track.location, &sourceFile);
if(error != noErr)
    NSLog(@"conversion error: %i", error);
error = noErr;

ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &size, &srcFormat);

destFormat.mFormatID = kAudioFormatMPEG4AAC;
destFormat.mSampleRate = 22000;
destFormat.mFormatFlags = 0;
destFormat.mBytesPerPacket = 2; // must have a value or won't write apparently
destFormat.mFramesPerPacket = 0;
destFormat.mBytesPerFrame = 0;
destFormat.mChannelsPerFrame = 1;
destFormat.mBitsPerChannel = 0;
destFormat.mReserved = 0;

//create the output file

NSString *destURL = [self.track.location absoluteString];
NSLog(@"source url: %@", destURL);
destURL = [destURL substringToIndex:([destURL length] - 3)]; //remove caf extension
NSLog(@"source url with no extension: %@", destURL);
destURL = [NSString stringWithFormat:@"%@m4a",destURL]; //add acc extension
NSLog(@"dest url with correct extension: %@", destURL);
NSURL *destinationURL = [NSURL URLWithString:destURL];

size = sizeof(destFormat);
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, nil, &size, &destFormat);

error = ExtAudioFileCreateWithURL((CFURLRef)destinationURL, kAudioFileM4AType, &destFormat, NULL, kAudioFileFlags_EraseFile, &destinationFile);
if(error != noErr)
    NSLog(@"conversion error: %i", error);
error = noErr;

//canonical format
AudioStreamBasicDescription clientFormat;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mSampleRate = 22000;
int sampleSize = sizeof(AudioSampleType);
clientFormat.mFormatFlags = kAudioFormatFlagsCanonical;
clientFormat.mBitsPerChannel = 8 * sampleSize;
clientFormat.mChannelsPerFrame = 1;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = sampleSize;
clientFormat.mBytesPerFrame = sampleSize;
clientFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

//set the intermediate format to canonical on the source file for conversion (?)
ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);

//get the converter
AudioConverterRef audioConverter;
size = sizeof(audioConverter);
error = ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &audioConverter);
if(error != noErr)
    NSLog(@"error getting converter: %i", error);
error = noErr;

/*UInt32 bitRate = 64000;   
error = AudioConverterSetProperty(audioConverter, kAudioConverterEncodeBitRate, sizeof(bitRate), &bitRate);
if(error != noErr)
    NSLog(@"error setting bit rate: %i", error);
error = noErr;*/

// set up buffers
UInt32 bufferByteSize = 32768;
char srcBuffer[bufferByteSize];

NSLog(@"converting...");

int i=0;
while (true) {
    i++;
    AudioBufferList fillBufList;
    fillBufList.mNumberBuffers = 1;
    fillBufList.mBuffers[0].mNumberChannels = 1;
    fillBufList.mBuffers[0].mDataByteSize = bufferByteSize;
    fillBufList.mBuffers[0].mData = srcBuffer;

    // client format is always linear PCM - so here we determine how many frames of lpcm
    // we can read/write given our buffer size
    UInt32 numFrames = bufferByteSize / clientFormat.mBytesPerFrame;

    error = ExtAudioFileRead(sourceFile, &numFrames, &fillBufList); 
    if(error != noErr)
        NSLog(@"read error: %i run: %i", error, i);

    if (!numFrames) {
        // this is our termination condition
        error = noErr;
        break;
    }

    //this is the actual conversion
    error = ExtAudioFileWrite(destinationFile, numFrames, &fillBufList);

    if(error != noErr)
        NSLog(@"conversion error: %i run: %i", error, i);
}

if (destinationFile) ExtAudioFileDispose(destinationFile);
if (sourceFile) ExtAudioFileDispose(sourceFile);

I am trying to convert a mono linear pcm file to an aac file. After much struggle I finally got it out output using the below settings, but now the file won't play. I really don't know where to look - all of the examples I have found are similar to what I already have.

All of the samples I have seen have destFormat.mBytesPerPacket = 0 but I can't get it to write then (I get a -66567 on the write, which resolves to kExtAudioFileError_MaxPacketSizeUnknown).

ExtAudioFileRef sourceFile = 0;
ExtAudioFileRef destinationFile = 0;
OSStatus        error = noErr;

AudioStreamBasicDescription srcFormat, destFormat;
UInt32 size = sizeof(srcFormat);
error = ExtAudioFileOpenURL((CFURLRef)self.track.location, &sourceFile);
if(error != noErr)
    NSLog(@"conversion error: %i", error);
error = noErr;

ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &size, &srcFormat);

destFormat.mFormatID = kAudioFormatMPEG4AAC;
destFormat.mSampleRate = 22000;
destFormat.mFormatFlags = 0;
destFormat.mBytesPerPacket = 2; // must have a value or won't write apparently
destFormat.mFramesPerPacket = 0;
destFormat.mBytesPerFrame = 0;
destFormat.mChannelsPerFrame = 1;
destFormat.mBitsPerChannel = 0;
destFormat.mReserved = 0;

//create the output file

NSString *destURL = [self.track.location absoluteString];
NSLog(@"source url: %@", destURL);
destURL = [destURL substringToIndex:([destURL length] - 3)]; //remove caf extension
NSLog(@"source url with no extension: %@", destURL);
destURL = [NSString stringWithFormat:@"%@m4a",destURL]; //add acc extension
NSLog(@"dest url with correct extension: %@", destURL);
NSURL *destinationURL = [NSURL URLWithString:destURL];

size = sizeof(destFormat);
AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, nil, &size, &destFormat);

error = ExtAudioFileCreateWithURL((CFURLRef)destinationURL, kAudioFileM4AType, &destFormat, NULL, kAudioFileFlags_EraseFile, &destinationFile);
if(error != noErr)
    NSLog(@"conversion error: %i", error);
error = noErr;

//canonical format
AudioStreamBasicDescription clientFormat;
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mSampleRate = 22000;
int sampleSize = sizeof(AudioSampleType);
clientFormat.mFormatFlags = kAudioFormatFlagsCanonical;
clientFormat.mBitsPerChannel = 8 * sampleSize;
clientFormat.mChannelsPerFrame = 1;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = sampleSize;
clientFormat.mBytesPerFrame = sampleSize;
clientFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

//set the intermediate format to canonical on the source file for conversion (?)
ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);

//get the converter
AudioConverterRef audioConverter;
size = sizeof(audioConverter);
error = ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &audioConverter);
if(error != noErr)
    NSLog(@"error getting converter: %i", error);
error = noErr;

/*UInt32 bitRate = 64000;   
error = AudioConverterSetProperty(audioConverter, kAudioConverterEncodeBitRate, sizeof(bitRate), &bitRate);
if(error != noErr)
    NSLog(@"error setting bit rate: %i", error);
error = noErr;*/

// set up buffers
UInt32 bufferByteSize = 32768;
char srcBuffer[bufferByteSize];

NSLog(@"converting...");

int i=0;
while (true) {
    i++;
    AudioBufferList fillBufList;
    fillBufList.mNumberBuffers = 1;
    fillBufList.mBuffers[0].mNumberChannels = 1;
    fillBufList.mBuffers[0].mDataByteSize = bufferByteSize;
    fillBufList.mBuffers[0].mData = srcBuffer;

    // client format is always linear PCM - so here we determine how many frames of lpcm
    // we can read/write given our buffer size
    UInt32 numFrames = bufferByteSize / clientFormat.mBytesPerFrame;

    error = ExtAudioFileRead(sourceFile, &numFrames, &fillBufList); 
    if(error != noErr)
        NSLog(@"read error: %i run: %i", error, i);

    if (!numFrames) {
        // this is our termination condition
        error = noErr;
        break;
    }

    //this is the actual conversion
    error = ExtAudioFileWrite(destinationFile, numFrames, &fillBufList);

    if(error != noErr)
        NSLog(@"conversion error: %i run: %i", error, i);
}

if (destinationFile) ExtAudioFileDispose(destinationFile);
if (sourceFile) ExtAudioFileDispose(sourceFile);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

若水微香 2024-10-07 05:16:42

您必须设置kExtAudioFileProperty_ClientDataFormat才能编码为非pcm格式(根据文档)。客户端格式是您要在应用程序中处理音频数据的格式(通常是 pcm)。

You have to set the kExtAudioFileProperty_ClientDataFormat in order to encode to non-pcm formats (according to documentation). The client-format is format in which you want to deal with the audio-data in your app (usually pcm).

强者自强 2024-10-07 05:16:42

此处发布的好示例: 使用 AVMutableAudioMix 调整资产内曲目的音量

这并不完全是你想要的,但它会在 m4a 中读取 ->转换为 pcm ->改变音量->然后保存回m4a。

Good example posted here: Using AVMutableAudioMix to adjust volumes for tracks within asset

It's not exactly what you want but it will read in an m4a -> convert to pcm -> change the volume -> then save back out to m4a.

沫尐诺 2024-10-07 05:16:42

您需要在目标文件上设置客户端数据格式以匹配源文件上的客户端格式。您现在设置的方式是,目标文件希望您将 AAC 传递给它,但事实并非如此。

You need to set the client data format on your destination file to match the client format on your source file. The way you have it set up now the destination file is expecting you to hand it AAC, which you're not.

情愿 2024-10-07 05:16:42

Core Audio 确实很神秘,错误结果通常与真正的错误没有什么关系。我看到的最明显的问题是 22000 的采样率对于 AAC 来说不是有效的。一些有效的采样率为 32000、44100 或 48000。我不确定是否支持其他采样率,但通常它们是这些数字的偶数倍或整除。

Core Audio is indeed mystifying and the error results usually have little to do with what's really wrong. The most obvious problem I see is that the sample rate of 22000 is not a valid one for AAC. Some of the valid sample rates are 32000, 44100, or 48000. I'm not sure if others are supported, but generally they're even multiples or evenly divisible by those numbers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文