gpt4 book ai didi

ios - 使用带回调的音频文件初始化将 MP3 转换为 AAC

转载 作者:行者123 更新时间:2023-11-29 13:10:33 25 4
gpt4 key购买 nike

对于我的 iOS 应用程序,我需要将存储在 NSData 对象中的 MP3 文件转换为 AAC 格式,该格式也将存储在 NSData 对象中以便稍后进行流式传输。我也在转换之间做一些 DSP,所以我利用 AudioFileOpenWithCallbacks 打开现有的内存中 MP3 文件,这工作正常。

但是,我无法使用 AudioFileInitializeWithCallbacks (AFIWCB) 创建可读 AAC 文件来填充 NSMutableData 对象。为了测试音频,我在转换完成后将 NSMutableData 对象写入磁盘,但是当我检查此文件的元数据时,没有比特率或 channel 信息,并且文件无法播放。不过文件大小大致正确。

如果我跳过 AFIWCB 并使用 ExtAudioFileCreateWithURL 直接写入磁盘,它会完美运行,尽管写入磁盘对我的应用程序来说是不可取的。

有没有人熟悉使用 AFIWCB 将音频写入内存缓冲区?文档不是很清楚,我觉得我漏掉了一些东西或者没有正确使用回调。

感谢您提供的任何帮助。

编辑:找出我的问题,它在 outputWriteProc 回调中。修复如下:

代码:

-(void) convertData: (NSData *) audioData {

AudioFileID refInputAudioFileID; //these will be wrapped in Ext Audio File
AudioFileID refOutputAudioFileID;
ExtAudioFileRef inputFileID; //these deal with the actual reading and writing
ExtAudioFileRef outputFileID;

// Client Audio Format Description
AudioStreamBasicDescription clientFormat;
memset(&clientFormat, 0, sizeof(clientFormat));
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mFramesPerPacket = 1;
clientFormat.mChannelsPerFrame = 2;
clientFormat.mBitsPerChannel = 32;
clientFormat.mBytesPerPacket = clientFormat.mBytesPerFrame = 4 * clientFormat.mChannelsPerFrame;
clientFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;// | kAudioFormatFlagIsNonInterleaved;
clientFormat.mSampleRate = 44100;

//Output Audio Format Description
AudioStreamBasicDescription outputFormat;
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mChannelsPerFrame = 2;
outputFormat.mSampleRate = 44100;
outputFormat.mFormatID = kAudioFormatMPEG4AAC;
outputFormat.mFormatFlags = kMPEG4Object_AAC_Main;
outputFormat.mBitsPerChannel = 0;
outputFormat.mBytesPerFrame = 0;
outputFormat.mBytesPerPacket = 0;
outputFormat.mFramesPerPacket = 1024;

//Open the Source Audio File (in Memory) and wrap it with an ExtAudioFile (this works fine)
OSStatus result = AudioFileOpenWithCallbacks(audioData, readProc, 0, getSizeProc, 0, kAudioFileMP3Type, &refInputAudioFileID);
if(result != noErr)
[self CheckResult:result withMessage:@"AudioFileOpenWithCallbacks failed "];

//2) wrap with ExtAudioFile (this works fine)
result = ExtAudioFileWrapAudioFileID(refInputAudioFileID, false, &inputFileID);
[self CheckResult:result withMessage:@"ExtAudioFileWrap failed for input audio "];

UInt64 fileSizeInFrames;
UInt32 sizeProp = sizeof(fileSizeInFrames);
result = 0;
result = ExtAudioFileGetProperty(inputFileID, kExtAudioFileProperty_FileLengthFrames, &sizeProp, &fileSizeInFrames);
if(result!=noErr)
[self CheckResult:result withMessage:@"ExtAudioFileGet Prop FileLengthFrames failed "];
else
sourceAudioFileSizeinFrames = fileSizeInFrames;

//Initialize the destination audio file using NSMutableData and wrap it with ExtAudioFile (this is where I'm having problems)
destAudioData = [[NSMutableData alloc] initWithCapacity:1000000];
result = 0;
result = AudioFileInitializeWithCallbacks(destAudioData, outputReadProc, outputWriteProc,
getOutputSizeProc, setOutputSizeProc, kAudioFileM4AType,
&outputFormat, 0, &refOutputAudioFileID);

[self CheckResult:result withMessage:@"AudioFIleIWithCallbacks failed "];

result = 0;
result = ExtAudioFileWrapAudioFileID(refOutputAudioFileID, true, &outputFileID);
[self CheckResult:result withMessage:@"ExtAudioFilWrap for dest audio failed "];

UInt32 outputFormatSize = sizeof(outputFormat);
result = 0;
result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &outputFormatSize, &outputFormat);
[self CheckResult:result withMessage:@"AudioFormatGetProp failed on output audio "];

// Set Up Client Formats for Input
int size = sizeof(clientFormat);
result = 0;
result = ExtAudioFileSetProperty(inputFileID, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
[self CheckResult:result withMessage:@"Error on ExtAudioFileSetProperty ClientFormat on Input "];

// Specify the software codec
UInt32 codec = kAppleSoftwareAudioCodecManufacturer;
result = 0;
result = ExtAudioFileSetProperty(outputFileID, kExtAudioFileProperty_CodecManufacturer, sizeof(UInt32), &codec);
[self CheckResult:result withMessage:@"Error Setting Audio Codec for Output File "];

//specify client format on output
size = sizeof(clientFormat);
result = 0;
result = ExtAudioFileSetProperty(outputFileID, kExtAudioFileProperty_ClientDataFormat, sizeof(clientFormat), &clientFormat);
[self CheckResult:result withMessage:@"Error on ExtAudioFileSetProperty ClientDataFormat for Output File "];


UInt64 totalFrames = 0;
int ioBufferSizeSamples = 1024;

while (1) {

UInt32 bufferByteSize = ioBufferSizeSamples * 4 * 2;
char srcBuffer[bufferByteSize];
UInt32 numFrames = (bufferByteSize/clientFormat.mBytesPerFrame);

AudioBufferList fillBufList;
fillBufList.mNumberBuffers = 1;
fillBufList.mBuffers[0].mNumberChannels = clientFormat.mChannelsPerFrame;
fillBufList.mBuffers[0].mDataByteSize = bufferByteSize;
fillBufList.mBuffers[0].mData = srcBuffer;
result = 0;

//read samples
result = ExtAudioFileRead(inputFileID, &numFrames, &fillBufList);

if (result != noErr) {
[self CheckResult:result withMessage:@"Error on ExtAudioFileRead for input "];
totalFrames = 0;
break;
}
if (!numFrames)
break;

/**********Do DSP HERE*****************/

totalFrames = totalFrames + numFrames;

//write output audio here
result = 0;
result = ExtAudioFileWrite(outputFileID,
numFrames,
&fillBufList);

[self CheckResult:result withMessage:@"Error on ExtAudioFileWrite for output "];
}

// clean up
result = 0;
result = ExtAudioFileDispose(inputFileID);
[self CheckResult:result withMessage:@"Error on ExtAudioFileDispose InputFileId "];

result = 0;
AudioFileClose(refInputAudioFileID);
[self CheckResult:result withMessage:@"Error on AudioFile Clsoe InputFileId "];

result = 0;
ExtAudioFileDispose(outputFileID);
[self CheckResult:result withMessage:@"Error on ExtAudioFileDispose OutputFileID "];

result = 0;
AudioFileClose(refOutputAudioFileID);
[self CheckResult:result withMessage:@"Error on AudioFileClose OutputFileID "];

//save the destination audio file here...
NSString *destAudioPath = [[Utils audioFilePathPrefix] stringByAppendingPathComponent:
[NSString stringWithFormat:@"tone.m4a"]];

NSURL *destURL = [NSURL fileURLWithPath:destAudioPath];

BOOL writeOK = [destAudioData writeToURL:destURL atomically:YES];
if(!writeOK)
NSLog(@"problem writing the destination audio to its path \n");
}

/* *********These are the callbacks required for AudioFileOpen With Callbacks and they work fine **********/
static OSStatus readProc(void *inClientData,
SInt64 position,
UInt32 requestCount,
void *buffer,
UInt32 *actualCount)
{
NSData *inAudioData = (NSData *) inClientData;
size_t dataSize = inAudioData.length;
size_t bytesToRead = 0;

if(position < dataSize) {
size_t bytesAvailable = dataSize - position;
bytesToRead = requestCount <= bytesAvailable ? requestCount : bytesAvailable;
[inAudioData getBytes: buffer range:NSMakeRange(position, bytesToRead)];

*actualCount = bytesToRead;
} else {
NSLog(@"data was not read \n");
bytesToRead = 0;
*actualCount = 0;
}
return noErr;
}

static SInt64 getSizeProc(void* inClientData) {
NSData *inAudioData = (NSData *) inClientData;
size_t dataSize = inAudioData.length;
return dataSize;
}

/**************These are the callbacks for AudioFileInitializeWithCallbacks ********/

static OSStatus outputReadProc (void *outClientData,
SInt64 outputReadPosition,
UInt32 outputReadRequestCount,
void *outputReadBuffer,
UInt32 *outputReadActualCount)
{
NSData *inAudioData = (NSData *) outClientData;
size_t dataSize = inAudioData.length;
size_t bytesToRead = 0;

if(outputReadPosition < dataSize) {
size_t bytesAvailable = dataSize - outputReadPosition;
bytesToRead = outputReadRequestCount <= bytesAvailable ? outputReadRequestCount : bytesAvailable;
[inAudioData getBytes: outputReadBuffer range:NSMakeRange(outputReadPosition, bytesToRead)];

*outputReadActualCount = bytesToRead;
} else {
bytesToRead = 0;
*outputReadActualCount = 0;
}
return noErr;
}

static OSStatus outputWriteProc(void *outClientData,
SInt64 writePosition,
UInt32 writeRequestCount,
const void *writeBuffer,
UInt32 *writeActualCount){

NSMutableData *outAudioData = (NSMutableData *) outClientData;
UInt32 dataLen = [outAudioData length];
if(writePosition + writeRequestCount - 1 > dataLen){
[outAudioData increaseLengthBy:(writePosition + writeRequestCount - dataLen)];
}

[outAudioData replaceBytesInRange: NSMakeRange(writePosition, writeRequestCount) withBytes: writeBuffer];

*writeActualCount = writeRequestCount;

return noErr;
}

static SInt64 getOutputSizeProc(void *outClientData) {
NSMutableData *inAudioData = (NSMutableData *) outClientData;
size_t dataSize = inAudioData.length;
return dataSize;
}

static OSStatus setOutputSizeProc(void *outClientData, SInt64 inSize){
NSMutableData *inAudioData = (NSMutableData *)outClientData;
[inAudioData setLength: inSize];
return noErr;
}

最佳答案

解决了我的问题 - 我只是将数据附加到我的 outputWriteProc 回调。

ExtAudioFileClose 和 AudioFileClose 触发 outputWriteProc 回调来关闭文件,这些函数想要覆盖文件不同部分的数据。附加数据给我留下了垃圾头文件和其他损坏的部分。

关于ios - 使用带回调的音频文件初始化将 MP3 转换为 AAC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17504993/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com