iPhone 扩展音频文件服务,mp3 -> PCM-> mp3

发布于 2024-09-29 05:56:59 字数 5888 浏览 1 评论 0原文

我想使用 Core Audio 扩展音频文件服务框架来读取 mp3 文件,将其作为 PCM 进行处理,然后将修改后的文件作为 mp3 文件写回。我能够将 mp3 文件转换为 PCM,但无法将 PCM 文件作为 mp3 写回。

我已经跟踪并分析了 Apple ExtAudioFileConvertTest 示例,但也无法使其正常工作。故障点是当我设置输出文件的客户端格式(设置为规范的 PCM 类型)时。此操作失败并出现错误“fmt?”如果输出目标类型设置为 mp3。

是否可以做mp3 -> PCM-> iPhone 上有 mp3 吗?如果我删除失败的行,为输出文件设置 kExtAudioFileProperty_ClientDataFormat,则代码会失败并显示“pkd?”当我稍后尝试写入输出文件时。所以基本上我有两个错误:

1)“fmt?”当尝试为输出文件设置 kExtAudioFileProperty_ClientDataFormat 时

2) “pkd?”当尝试写入输出文件时

这是设置文件的代码:

NSURL *fileUrl = [NSURL fileURLWithPath:sourceFilePath];
OSStatus error = noErr;

//
// Open the file
//
error = ExtAudioFileOpenURL((CFURLRef)fileUrl, &sourceFile);

if(error){
    NSLog(@"AudioClip: Error opening file at %@.  Error code %d", sourceFilePath, error);
    return NO;
}

//
// Store the number of frames in the file
//
SInt64 numberOfFrames = 0;
UInt32 propSize = sizeof(SInt64);
error = ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileLengthFrames, &propSize, &numberOfFrames);

if(error){
    NSLog(@"AudioClip: Error retreiving number of frames: %d", error);
    [self closeAudioFile];
    return NO;
}

frameCount = numberOfFrames;

//
// Get the source file format info
//
propSize = sizeof(sourceFileFormat);
memset(&sourceFileFormat, 0, sizeof(AudioStreamBasicDescription));

error = ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &propSize, &sourceFileFormat);

if(error){
    NSLog(@"AudioClip: Error getting source audio file properties: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Set the format for our read.  We read in PCM, clip, then write out mp3
//
memset(&readFileFormat, 0, sizeof(AudioStreamBasicDescription));

readFileFormat.mFormatID            = kAudioFormatLinearPCM;
readFileFormat.mSampleRate          = 44100;
readFileFormat.mFormatFlags         = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved;
readFileFormat.mChannelsPerFrame    = 1;
readFileFormat.mBitsPerChannel      = 8 * sizeof(AudioSampleType);
readFileFormat.mFramesPerPacket     = 1;
readFileFormat.mBytesPerFrame       = sizeof(AudioSampleType);
readFileFormat.mBytesPerPacket      = sizeof(AudioSampleType);
readFileFormat.mReserved            = 0;

propSize = sizeof(readFileFormat);
error = ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, propSize, &readFileFormat);

if(error){
    NSLog(@"AudioClip: Error setting read format: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Set the format for the output file that we will write
//
propSize = sizeof(targetFileFormat);
memset(&targetFileFormat, 0, sizeof(AudioStreamBasicDescription));

targetFileFormat.mFormatID          = kAudioFormatMPEGLayer3;
targetFileFormat.mChannelsPerFrame  = 1;

//
// Let the API fill in the rest
//
error = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &propSize, &targetFileFormat);

if(error){
    NSLog(@"AudioClip: Error getting target file format info: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Create our target file
//
NSURL *writeURL = [NSURL fileURLWithPath:targetFilePath];

error = ExtAudioFileCreateWithURL( (CFURLRef)writeURL, kAudioFileMP3Type, 
                                  &targetFileFormat, NULL,
                                  kAudioFileFlags_EraseFile, 
                                  &targetFile);

if(error){
    NSLog(@"AudioClip: Error opening target file for writing: %d", error);
    [self closeAudioFile];
    return NO;
}


//
// Set the client format for the output file the same as our client format for the input file
//
propSize = sizeof(readFileFormat);
error = ExtAudioFileSetProperty(targetFile, kExtAudioFileProperty_ClientDataFormat, propSize, &readFileFormat);

if(error){
    NSLog(@"AudioClip: Error, cannot set client format for output file: %d", error);
    [self closeAudioFile];
    return NO;
}

以及读/写的代码:

NSInteger framesToRead = finalFrameNumber - startFrameNumber;

while(framesToRead > 0){
    //
    // Read frames into our data
    //
    short *data = (short *)malloc(framesToRead * sizeof(short));
    if(!data){
        NSLog(@"AudioPlayer: Cannot init memory for read buffer");
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    AudioBufferList bufferList;
    OSStatus error = noErr;
    UInt32 loadedPackets = framesToRead;

    bufferList.mNumberBuffers = 1;
    bufferList.mBuffers[0].mNumberChannels = 1;
    bufferList.mBuffers[0].mData = data;
    bufferList.mBuffers[0].mDataByteSize = (framesToRead * sizeof(short));

    NSLog(@"AudioClip: Before read nNumberBuffers = %d, mNumberChannels = %d, mData = %p, mDataByteSize = %d",
          bufferList.mNumberBuffers, bufferList.mBuffers[0].mNumberChannels, bufferList.mBuffers[0].mData,
          bufferList.mBuffers[0].mDataByteSize);

    error = ExtAudioFileRead(sourceFile, &loadedPackets, &bufferList);

    if(error){
        NSLog(@"AudioClip: Error %d from ExtAudioFileRead", error);
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    //
    // Now write the data to our file which will convert it into a mp3 file
    //

    NSLog(@"AudioClip: After read nNumberBuffers = %d, mNumberChannels = %d, mData = %p, mDataByteSize = %d",
          bufferList.mNumberBuffers, bufferList.mBuffers[0].mNumberChannels, bufferList.mBuffers[0].mData,
          bufferList.mBuffers[0].mDataByteSize);

    error = ExtAudioFileWrite(targetFile, loadedPackets, &bufferList);

    if(error){
        NSLog(@"AudioClip: Error %d from ExtAudioFileWrite", error);
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    framesToRead -= loadedPackets;
}

I would like to use the Core Audio extended audio file services framework to read a mp3 file, process it as a PCM, then write the modified file back as a mp3 file. I am able to convert the mp3 file to PCM, but am NOT able to write the PCM file back as a mp3.

I have followed and analyzed the Apple ExtAudioFileConvertTest sample and also cannot get that to work. The failure point is when I set the client format for the output file(set to a canonical PCM type). This fails with error "fmt?" if the output target type is set to mp3.

Is it possible to do mp3 -> PCM -> mp3 on the iPhone? If I remove the failing line, setting the kExtAudioFileProperty_ClientDataFormat for the output file, the code fails with "pkd?" when I try to write to the output file later. So basically I have 2 errors:

1) "fmt?" when trying to set kExtAudioFileProperty_ClientDataFormat for the output file

2) "pkd?" when trying to write to the output file

Here is the code to set up the files:

NSURL *fileUrl = [NSURL fileURLWithPath:sourceFilePath];
OSStatus error = noErr;

//
// Open the file
//
error = ExtAudioFileOpenURL((CFURLRef)fileUrl, &sourceFile);

if(error){
    NSLog(@"AudioClip: Error opening file at %@.  Error code %d", sourceFilePath, error);
    return NO;
}

//
// Store the number of frames in the file
//
SInt64 numberOfFrames = 0;
UInt32 propSize = sizeof(SInt64);
error = ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileLengthFrames, &propSize, &numberOfFrames);

if(error){
    NSLog(@"AudioClip: Error retreiving number of frames: %d", error);
    [self closeAudioFile];
    return NO;
}

frameCount = numberOfFrames;

//
// Get the source file format info
//
propSize = sizeof(sourceFileFormat);
memset(&sourceFileFormat, 0, sizeof(AudioStreamBasicDescription));

error = ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &propSize, &sourceFileFormat);

if(error){
    NSLog(@"AudioClip: Error getting source audio file properties: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Set the format for our read.  We read in PCM, clip, then write out mp3
//
memset(&readFileFormat, 0, sizeof(AudioStreamBasicDescription));

readFileFormat.mFormatID            = kAudioFormatLinearPCM;
readFileFormat.mSampleRate          = 44100;
readFileFormat.mFormatFlags         = kAudioFormatFlagsCanonical | kAudioFormatFlagIsNonInterleaved;
readFileFormat.mChannelsPerFrame    = 1;
readFileFormat.mBitsPerChannel      = 8 * sizeof(AudioSampleType);
readFileFormat.mFramesPerPacket     = 1;
readFileFormat.mBytesPerFrame       = sizeof(AudioSampleType);
readFileFormat.mBytesPerPacket      = sizeof(AudioSampleType);
readFileFormat.mReserved            = 0;

propSize = sizeof(readFileFormat);
error = ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, propSize, &readFileFormat);

if(error){
    NSLog(@"AudioClip: Error setting read format: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Set the format for the output file that we will write
//
propSize = sizeof(targetFileFormat);
memset(&targetFileFormat, 0, sizeof(AudioStreamBasicDescription));

targetFileFormat.mFormatID          = kAudioFormatMPEGLayer3;
targetFileFormat.mChannelsPerFrame  = 1;

//
// Let the API fill in the rest
//
error = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &propSize, &targetFileFormat);

if(error){
    NSLog(@"AudioClip: Error getting target file format info: %d", error);
    [self closeAudioFile];
    return NO;
}

//
// Create our target file
//
NSURL *writeURL = [NSURL fileURLWithPath:targetFilePath];

error = ExtAudioFileCreateWithURL( (CFURLRef)writeURL, kAudioFileMP3Type, 
                                  &targetFileFormat, NULL,
                                  kAudioFileFlags_EraseFile, 
                                  &targetFile);

if(error){
    NSLog(@"AudioClip: Error opening target file for writing: %d", error);
    [self closeAudioFile];
    return NO;
}


//
// Set the client format for the output file the same as our client format for the input file
//
propSize = sizeof(readFileFormat);
error = ExtAudioFileSetProperty(targetFile, kExtAudioFileProperty_ClientDataFormat, propSize, &readFileFormat);

if(error){
    NSLog(@"AudioClip: Error, cannot set client format for output file: %d", error);
    [self closeAudioFile];
    return NO;
}

And the code to read/write:

NSInteger framesToRead = finalFrameNumber - startFrameNumber;

while(framesToRead > 0){
    //
    // Read frames into our data
    //
    short *data = (short *)malloc(framesToRead * sizeof(short));
    if(!data){
        NSLog(@"AudioPlayer: Cannot init memory for read buffer");
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    AudioBufferList bufferList;
    OSStatus error = noErr;
    UInt32 loadedPackets = framesToRead;

    bufferList.mNumberBuffers = 1;
    bufferList.mBuffers[0].mNumberChannels = 1;
    bufferList.mBuffers[0].mData = data;
    bufferList.mBuffers[0].mDataByteSize = (framesToRead * sizeof(short));

    NSLog(@"AudioClip: Before read nNumberBuffers = %d, mNumberChannels = %d, mData = %p, mDataByteSize = %d",
          bufferList.mNumberBuffers, bufferList.mBuffers[0].mNumberChannels, bufferList.mBuffers[0].mData,
          bufferList.mBuffers[0].mDataByteSize);

    error = ExtAudioFileRead(sourceFile, &loadedPackets, &bufferList);

    if(error){
        NSLog(@"AudioClip: Error %d from ExtAudioFileRead", error);
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    //
    // Now write the data to our file which will convert it into a mp3 file
    //

    NSLog(@"AudioClip: After read nNumberBuffers = %d, mNumberChannels = %d, mData = %p, mDataByteSize = %d",
          bufferList.mNumberBuffers, bufferList.mBuffers[0].mNumberChannels, bufferList.mBuffers[0].mData,
          bufferList.mBuffers[0].mDataByteSize);

    error = ExtAudioFileWrite(targetFile, loadedPackets, &bufferList);

    if(error){
        NSLog(@"AudioClip: Error %d from ExtAudioFileWrite", error);
        [self notifyDelegateFailure];
        [self closeAudioFile];
        return;
    }

    framesToRead -= loadedPackets;
}

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

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

发布评论

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

评论(1

偏爱你一生 2024-10-06 05:56:59

Apple 不提供 MP3 编码器,仅提供解码器。源文档有点过时,但据我所知它仍然是最新的: http://developer.apple.com/library/ios/#documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html%23 //apple_ref/doc/uid/TP40003577-CH7-SW1

我认为你最好的选择可能是使用 AAC。

Apple doesn't supply an MP3 encoder- only a decoder. The source document is a bit outdated, but AFAIK it is still current: http://developer.apple.com/library/ios/#documentation/MusicAudio/Conceptual/CoreAudioOverview/SupportedAudioFormatsMacOSX/SupportedAudioFormatsMacOSX.html%23//apple_ref/doc/uid/TP40003577-CH7-SW1

I think your best bet might be to use AAC.

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