ExtAudioFileСписать в m4a / aac не удалось на двухъядерных устройствах (ipad 2, iphone 4s) - PullRequest
6 голосов
/ 04 января 2012

Я написал цикл для кодирования аудиоданных PCM, сгенерированных моим приложением, в aac с использованием Extended Audio File Services.Кодирование происходит в фоновом потоке синхронно, а не в реальном времени.

Кодирование работает безупречно на ipad 1 и iphone 3gs / 4 для ios 4 и 5. Однако для двухъядерных устройств (iphone 4s, ipad 2) третий вызов ExtAudioFileWrite приводит к сбою потока кодирования без трассировки стека и без кода ошибки.

Вот код, о котором идет речь:

Форматы данных

AudioStreamBasicDescription AUCanonicalASBD(Float64 sampleRate, 
                                        UInt32 channel){
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate         = sampleRate;
audioFormat.mFormatID           = kAudioFormatLinearPCM;
audioFormat.mFormatFlags        = kAudioFormatFlagsAudioUnitCanonical;
audioFormat.mChannelsPerFrame   = channel;
audioFormat.mBytesPerPacket     = sizeof(AudioUnitSampleType);
audioFormat.mBytesPerFrame      = sizeof(AudioUnitSampleType);
audioFormat.mFramesPerPacket    = 1;
audioFormat.mBitsPerChannel     = 8 * sizeof(AudioUnitSampleType);
audioFormat.mReserved           = 0;
return audioFormat;
}

AudioStreamBasicDescription MixdownAAC(void){
AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate         = 44100.0;
audioFormat.mFormatID           = kAudioFormatMPEG4AAC;
audioFormat.mFormatFlags        = kMPEG4Object_AAC_Main;
audioFormat.mChannelsPerFrame   = 2;
audioFormat.mBytesPerPacket     = 0;
audioFormat.mBytesPerFrame      = 0;
audioFormat.mFramesPerPacket    = 1024;
audioFormat.mBitsPerChannel     = 0;
audioFormat.mReserved           = 0;
return audioFormat;
}

Цикл рендеринга

OSStatus err;
ExtAudioFileRef outFile;
NSURL *mixdownURL = [NSURL fileURLWithPath:filePath isDirectory:NO];

// internal data format
AudioStreamBasicDescription localFormat = AUCanonicalASBD(44100.0, 2);

// output file format
AudioStreamBasicDescription mixdownFormat = MixdownAAC();
err = ExtAudioFileCreateWithURL((CFURLRef)mixdownURL,
                             kAudioFileM4AType,
                             &mixdownFormat, 
                             NULL,
                             kAudioFileFlags_EraseFile,
                             &outFile);


err = ExtAudioFileSetProperty(outFile, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &localFormat);

// prep
AllRenderData *allData = &allRenderData;
writeBuffer = malloc(sizeof(AudioBufferList) + (2*sizeof(AudioBuffer)));
writeBuffer->mNumberBuffers = 2;
writeBuffer->mBuffers[0].mNumberChannels = 1;
writeBuffer->mBuffers[0].mDataByteSize = bufferBytes;
writeBuffer->mBuffers[0].mData = malloc(bufferBytes);
writeBuffer->mBuffers[1].mNumberChannels = 1;
writeBuffer->mBuffers[1].mDataByteSize = bufferBytes;
writeBuffer->mBuffers[1].mData = malloc(bufferBytes);

memset(writeBuffer->mBuffers[0].mData, 0, bufferBytes);
memset(writeBuffer->mBuffers[1].mData, 0, bufferBytes);

UInt32 framesToGet;
UInt32 frameCount = allData->gLoopStartFrame;
UInt32 startFrame = allData->gLoopStartFrame;
UInt32 lastFrame = allData->gLoopEndFrame;

// write one silent buffer
ExtAudioFileWrite(outFile, bufferFrames, writeBuffer);

while (frameCount < lastFrame){

    // how many frames do we need to get
    if (lastFrame - frameCount > bufferFrames)
        framesToGet = bufferFrames;
    else
        framesToGet = lastFrame - frameCount;

    // get dem frames
    err = theBigOlCallback((void*)&allRenderData,
                            NULL, NULL, 1,
                           framesToGet, writeBuffer);

    // write to output file
    ExtAudioFileWrite(outFile, framesToGet, writeBuffer);

    frameCount += framesToGet;
}

// write one trailing silent buffer
memset(writeBuffer->mBuffers[0].mData, 0, bufferBytes);
memset(writeBuffer->mBuffers[1].mData, 0, bufferBytes);
processLimiterInPlace8p24(limiter, writeBuffer->mBuffers[0].mData, writeBuffer->mBuffers[1].mData, bufferFrames);
ExtAudioFileWrite(outFile, bufferFrames, writeBuffer);

err = ExtAudioFileDispose(outFile);

Кадры PCM созданы правильно, но ExtAudioFileWrite завершается с ошибкой 2-й / 3-й раз, когда он вызывается.

Есть идеи?Спасибо!

1 Ответ

18 голосов
/ 22 марта 2012

У меня была очень похожая проблема, когда я пытался использовать Extended Audio File Services для потоковой передачи звука PCM в файл m4a на iPad 2. Казалось, что все работает, за исключением того, что каждый вызов ExtAudioFileWrite возвращает код ошибки -66567.(kExtAudioFileError_MaxPacketSizeUnknown).Исправление, которое я в конечном итоге нашел, состояло в том, чтобы установить «Производитель кодеков» на программное обеспечение вместо аппаратного.Поэтому поместите

UInt32 codecManf = kAppleSoftwareAudioCodecManufacturer;
ExtAudioFileSetProperty(FileToWrite, kExtAudioFileProperty_CodecManufacturer, sizeof(UInt32), &codecManf);

непосредственно перед установкой формата данных клиента.

Это заставит меня поверить, что аппаратные кодеки Apple могут поддерживать только очень специфическую кодировку, но программные кодеки могут более надежноделай что хочешь.В моем случае перевод программного кодека в m4a занимает на 50% больше времени, чем запись точно такого же файла в формат LPCM.

Кто-нибудь знает, указывает ли Apple где-нибудь, на что способно их аппаратное обеспечение аудиокодека?Похоже, что разработчики программного обеспечения застряли в многочасовой игре в угадывание установки ~ 20 параметров в AudioStreamBasicDescription и AudioChannelLayout для клиента и файла для каждой возможной перестановки, пока что-то не заработает ...

...