我需要使用以下格式转换PCM音频数据:
Data format: 1 ch, 16000 Hz, 'lpcm' (0x0000000C) 16-bit little-endian signed integer
no channel layout.
estimated duration: 1.101063 sec
audio bytes: 35234
audio packets: 17617
bit rate: 256000 bits per second
packet size upper bound: 2
maximum packet size: 2
audio data file offset: 44
optimized
source bit depth: I16
至16位2ch(立体声)44100Hz PCM。
我的输入文件是NSData,理想情况下,如果我最终可以使用NSData而不是将输出保存到文件。我已经看过许多转换不同音频格式的教程和示例,但它们看起来非常复杂,我想知道是否有任何简单的解决方案可以做到这一点。这是我到目前为止尝试过的代码:
-(void)convertAudioToRequiredFormat:(NSData *)data {
AudioFileID refAudioFileID;
ExtAudioFileRef inputFileID;
ExtAudioFileRef outputFileID;
OSStatus result = AudioFileOpenWithCallbacks((__bridge void *)(data), readProc, 0, getSizeProc, 0, kAudioFormatLinearPCM, &refAudioFileID);
if (result != noErr) {
DLog(@"error reading input audio file");
}
result = ExtAudioFileWrapAudioFileID(refAudioFileID, false, &inputFileID);
if (result != noErr){
DLog(@"problem in theAudioFileReaderWithData function Wraping the audio FileID: result code %i \n", (int)result);
}
AudioStreamBasicDescription clientFormat;
memset(&clientFormat, 0, sizeof(clientFormat));
clientFormat.mFormatID = kAudioFormatLinearPCM;
clientFormat.mSampleRate = 16000;
clientFormat.mFramesPerPacket = 1;
clientFormat.mBytesPerPacket = 2; //16 bits * 1 channel
clientFormat.mBytesPerFrame = 2;
clientFormat.mChannelsPerFrame = 1; //1 channel
clientFormat.mBitsPerChannel = 16;
clientFormat.mFormatFlags = kCAFLinearPCMFormatFlagIsLittleEndian;
clientFormat.mReserved = 0;
AudioStreamBasicDescription outputFormat;
memset(&outputFormat, 0, sizeof(outputFormat));
outputFormat.mFormatID = kAudioFormatLinearPCM;
outputFormat.mSampleRate = 44100;
outputFormat.mFramesPerPacket = 1; //it is always 1 for PCM
outputFormat.mBytesPerPacket = 4; //4 Bytes = 2 * 16 bits
outputFormat.mBytesPerFrame = 4;
outputFormat.mChannelsPerFrame = 2; //2 channels = stereo
outputFormat.mBitsPerChannel = 16; //16 bits per channel
outputFormat.mFormatFlags = kCAFLinearPCMFormatFlagIsLittleEndian;
clientFormat.mReserved = 0;
UInt32 outputFormatSize = sizeof(outputFormat);
result = 0;
result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &outputFormatSize, &outputFormat);
if(result != noErr)
NSLog(@"could not set the output format with status code %i \n",(int)result);
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath = [docPaths objectAtIndex:0];
NSString *path = [docPath stringByAppendingPathComponent:@"newFormat.wav"];
CFURLRef sourceURL = (__bridge CFURLRef)[[NSURL alloc] initFileURLWithPath:path];
NSFileManager *fm = [NSFileManager defaultManager];
if (![fm fileExistsAtPath:path]) {
NSData *content = [NSData dataWithBytes:NULL length:0];
[fm createFileAtPath:path contents:content attributes:nil];
}
result = 0;
result = ExtAudioFileCreateWithURL(sourceURL, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outputFileID);
if(result != noErr){
NSLog(@"ExtAudioFileCreateWithURL failed for outputFileID with status %i \n", (int)result);
}
int size = sizeof(clientFormat);
result = 0;
result = ExtAudioFileSetProperty(inputFileID, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
if(result != noErr)
NSLog(@"error on ExtAudioFileSetProperty for input File with result code %i \n", (int)result);
size = sizeof(clientFormat);
result = 0;
result = ExtAudioFileSetProperty(outputFileID, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat);
if(result != noErr)
NSLog(@"error on ExtAudioFileSetProperty for output File with result code %i \n", (int)result);
int totalFrames = 0;
UInt32 outputFilePacketPosition = 0; //in bytes
UInt32 encodedBytes = 0;
while (1) {
UInt32 bufferByteSize = 22050 * 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;
result = ExtAudioFileRead(inputFileID, &numFrames, &fillBufList);
if (result != noErr) {
NSLog(@"Error on ExtAudioFileRead with result code %i \n", (int)result);
totalFrames = 0;
break;
}
if (!numFrames)
break;
totalFrames = totalFrames + numFrames;
result = 0;
result = ExtAudioFileWrite(outputFileID,
numFrames,
&fillBufList);
if(result!= noErr){
NSLog(@"ExtAudioFileWrite failed with code %i \n", (int)result);
}
encodedBytes += numFrames * clientFormat.mBytesPerFrame;
}
//Clean up
ExtAudioFileDispose(inputFileID);
ExtAudioFileDispose(outputFileID);
AudioFileClose(refAudioFileID);
}
static OSStatus readProc(void* clientData, SInt64 position, UInt32 requestCount, void* buffer, UInt32* actualCount)
{
NSData *inAudioData = (__bridge NSData *) clientData;
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)];
} else {
NSLog(@"data was not read \n");
bytesToRead = 0;
}
if(actualCount)
*actualCount = bytesToRead;
return noErr;
}
static SInt64 getSizeProc(void* clientData) {
NSData *inAudioData = (__bridge NSData *) clientData;
size_t dataSize = inAudioData.length;
return dataSize;
}
不幸的是它不起作用,我最终会在那行中使用EXC_BAD_ACCESS:
result = ExtAudioFileCreateWithURL(sourceURL, kAudioFileM4AType, &outputFormat, NULL, kAudioFileFlags_EraseFile, &outputFileID);
我不知道是什么导致了这个错误(错误的AudioStreamBasicDescription?)。有人可以帮我解决吗?或者可能有更简单的方法将音频数据转换为所需的PCM格式?
答案 0 :(得分:0)
一些tipps。
1)。 AudioFileID refAudioFileID; ExtAudioFileRef inputFileID; ExtAudioFileRef outputFileID;
^使用NULL初始化指针。
2)。 CFURLRef sourceURL =(__ bridge CFURLRef)[[NSURL alloc] initFileURLWithPath:path];
^做: NSURL * sourceURL = [NSURL fileURLWithPath:path];
3)。 NSData * content = [NSData dataWithBytes:NULL length:0];
^使用: NSData * content = [NSData data];
4)。 result = ExtAudioFileCreateWithURL(sourceURL,kAudioFileM4AType,&amp; outputFormat,NULL,kAudioFileFlags_EraseFile,&amp; outputFileID);
^看起来好像使用了错误的kAudioFileType:尝试kAudioFileAIFFType或kAudioFileWAVEType
我的两分钱。祝你好运!