将1ch 16000Hz PCM转换为2ch 44100Hz PCM



我需要转换格式为的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格式?

一些小费。

1.)音频文件ID参考音频文件ID;ExtAudioFileRef inputFileID;ExtAudioFileRef outputFileID;

^用NULL初始化指针。

2.)CFURLRef sourceURL=(__bridge CFURLRref)[[NSURL alloc]initFileURLWithPath:path];

^做:NSURL*源URL=[NSURL文件URLWithPath:path];

3.)NSData*content=[NSData dataWithBytes:NULL length:0];

^使用:NSData*内容=[NSData数据];

4.)result=ExtAudioFileCreateWithURL(源URL,kAudioFileM4AT类型,&outputFormat,NULL,kAudioPileFlags_EraseFile,&outputFileID);

^看起来你用错了kAudioFileType:试试kAudioFileAIFFType或kAudioFile WAVEType

这是我的两分钱。祝你好运!

最新更新