开发者

ExtAudioFileWrite producing unusable m4a aac files

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 ca开发者_StackOverflow社区nonical 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);


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).


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜