Кодирование PCM (CMSampleBufferRef) в AAC на iOS – как установить частоту и битрейт?IOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 Кодирование PCM (CMSampleBufferRef) в AAC на iOS – как установить частоту и битрейт?

Сообщение Anonymous »

Я хочу закодировать PCM (

Код: Выделить всё

CMSampleBufferRef
(s) переходят из AVCaptureAudioDataOutputSampleBufferDelegate) в AAC.

Когда приходит первый CMSampleBufferRef, я устанавливаю оба (в/ out) AudioStreamBasicDescription(s), «выход» согласно документации

Код: Выделить всё

AudioStreamBasicDescription inAudioStreamBasicDescription = *CMAudioFormatDescriptionGetStreamBasicDescription((CMAudioFormatDescriptionRef)CMSampleBufferGetFormatDescription(sampleBuffer));

AudioStreamBasicDescription outAudioStreamBasicDescription = {0}; // Always initialize the fields of a new audio stream basic description structure to zero, as shown here: ...
outAudioStreamBasicDescription.mSampleRate = 44100; // The number of frames per second of the data in the stream, when the stream is played at normal speed. For compressed formats, this field indicates the number of frames per second of equivalent decompressed data. The mSampleRate field must be nonzero, except when this structure is used in a listing of supported formats (see “kAudioStreamAnyRate”).
outAudioStreamBasicDescription.mFormatID = kAudioFormatMPEG4AAC; // kAudioFormatMPEG4AAC_HE does not work. Can't find `AudioClassDescription`. `mFormatFlags` is set to 0.
outAudioStreamBasicDescription.mFormatFlags = kMPEG4Object_AAC_SSR; // Format-specific flags to specify details of the format. Set to 0 to indicate no format flags. See “Audio Data Format Identifiers” for the flags that apply to each format.
outAudioStreamBasicDescription.mBytesPerPacket = 0; // The number of bytes in a packet of audio data. To indicate variable packet size, set this field to 0. For a format that uses variable packet size, specify the size of each packet using an AudioStreamPacketDescription structure.
outAudioStreamBasicDescription.mFramesPerPacket = 1024; // The number of frames in a packet of audio data. For uncompressed audio, the value is 1. For variable bit-rate formats, the value is a larger fixed number, such as 1024 for AAC. For formats with a variable number of frames per packet, such as Ogg Vorbis, set this field to 0.
outAudioStreamBasicDescription.mBytesPerFrame = 0; // The number of bytes from the start of one frame to the start of the next frame in an audio buffer. Set this field to 0 for compressed formats. ...
outAudioStreamBasicDescription.mChannelsPerFrame = 1; // The number of channels in each frame of audio data. This value must be nonzero.
outAudioStreamBasicDescription.mBitsPerChannel = 0; // ... Set this field to 0 for compressed formats.
outAudioStreamBasicDescription.mReserved = 0; // Pads the structure out to force an even 8-byte alignment.  Must be set to 0.
и AudioConverterRef.

Код: Выделить всё

AudioClassDescription audioClassDescription;
memset(&audioClassDescription, 0, sizeof(audioClassDescription));
UInt32 size;
NSAssert(AudioFormatGetPropertyInfo(kAudioFormatProperty_Encoders, sizeof(outAudioStreamBasicDescription.mFormatID), &outAudioStreamBasicDescription.mFormatID, &size) == noErr, nil);
uint32_t count = size / sizeof(AudioClassDescription);
AudioClassDescription descriptions[count];
NSAssert(AudioFormatGetProperty(kAudioFormatProperty_Encoders, sizeof(outAudioStreamBasicDescription.mFormatID), &outAudioStreamBasicDescription.mFormatID, &size, descriptions) == noErr, nil);
for (uint32_t i = 0; i < count; i++) {

if ((outAudioStreamBasicDescription.mFormatID == descriptions[i].mSubType) && (kAppleSoftwareAudioCodecManufacturer == descriptions[i].mManufacturer)) {

memcpy(&audioClassDescription, &descriptions[i], sizeof(audioClassDescription));

}
}
NSAssert(audioClassDescription.mSubType == outAudioStreamBasicDescription.mFormatID && audioClassDescription.mManufacturer == kAppleSoftwareAudioCodecManufacturer, nil);
AudioConverterRef audioConverter;
memset(&audioConverter, 0, sizeof(audioConverter));
NSAssert(AudioConverterNewSpecific(&inAudioStreamBasicDescription, &outAudioStreamBasicDescription, 1, &audioClassDescription, &audioConverter) == 0, nil);
А затем я конвертирую каждый CMSampleBufferRef в необработанные данные AAC.

Код: Выделить всё

AudioBufferList inAaudioBufferList;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &inAaudioBufferList, sizeof(inAaudioBufferList), NULL, NULL, 0, &blockBuffer);
NSAssert(inAaudioBufferList.mNumberBuffers == 1, nil);

uint32_t bufferSize = inAaudioBufferList.mBuffers[0].mDataByteSize;
uint8_t *buffer = (uint8_t *)malloc(bufferSize);
memset(buffer, 0, bufferSize);
AudioBufferList outAudioBufferList;
outAudioBufferList.mNumberBuffers = 1;
outAudioBufferList.mBuffers[0].mNumberChannels = inAaudioBufferList.mBuffers[0].mNumberChannels;
outAudioBufferList.mBuffers[0].mDataByteSize = bufferSize;
outAudioBufferList.mBuffers[0].mData = buffer;

UInt32 ioOutputDataPacketSize = 1;

NSAssert(AudioConverterFillComplexBuffer(audioConverter, inInputDataProc, &inAaudioBufferList, &ioOutputDataPacketSize, &outAudioBufferList, NULL) == 0, nil);

NSData *data = [NSData dataWithBytes:outAudioBufferList.mBuffers[0].mData length:outAudioBufferList.mBuffers[0].mDataByteSize];

free(buffer);
CFRelease(blockBuffer);

Код: Выделить всё

inInputDataProc()
реализация:

Код: Выделить всё

OSStatus inInputDataProc(AudioConverterRef inAudioConverter, UInt32 *ioNumberDataPackets, AudioBufferList *ioData, AudioStreamPacketDescription **outDataPacketDescription, void *inUserData)
{
AudioBufferList audioBufferList = *(AudioBufferList *)inUserData;

ioData->mBuffers[0].mData = audioBufferList.mBuffers[0].mData;
ioData->mBuffers[0].mDataByteSize = audioBufferList.mBuffers[0].mDataByteSize;

return  noErr;
}
Теперь данные содержат мой необработанный AAC, который я помещаю в кадр ADTS с соответствующим заголовком ADTS, и последовательность этих кадров ADTS представляет собой воспроизводимый документ AAC.< /p>

Но я не понимаю этот код настолько, насколько хотелось бы. В общем, я не понимаю звук... Я просто как-то написал его, следуя блогам, форумам и документации, прошло довольно много времени, и теперь он работает, но я не знаю, почему и как изменить некоторые параметры. Итак, вот мои вопросы:
  • Мне нужно использовать этот конвертер, когда аппаратный кодер занят (AVAssetWriter) . Вот почему я делаю конвертер SW через AudioConverterNewSpecific(), а не AudioConverterNew(). Но теперь установка OutAudioStreamBasicDescription.mFormatID = kAudioFormatMPEG4AAC_HE; не работает. Не могу найти AudioClassDescription. Даже если для mFormatFlags установлено значение 0. Что я теряю, используя kAudioFormatMPEG4AAC (

    Код: Выделить всё

    kMPEG4Object_AAC_SSR
    ) поверх kAudioFormatMPEG4AAC_HE? Что мне следует использовать для прямой трансляции? kMPEG4Object_AAC_SSR или kMPEG4Object_AAC_Main?
  • Как правильно изменить частоту дискретизации? Если я установлю outAudioStreamBasicDescription.mSampleRate, например, на 22050 или 8000, воспроизведение звука будет замедляться. Я установил индекс частоты дискретизации в заголовке ADTS на ту же частоту, что и outAudioStreamBasicDescription.mSampleRate.
  • Как изменить битрейт? ffmpeg -i показывает эту информацию для созданного aac:

    Код: Выделить всё

    Stream #0:0: Audio: aac, 44100 Hz, mono, fltp, 64 kb/s
    .
    Как изменить ее, например, на 16 кбит/с? Битрейт падает по мере уменьшения частоты, но я полагаю, это не единственный способ? И воспроизведение ухудшается из-за уменьшения частоты, как я уже упоминал в пункте 2.
  • Как рассчитать размер буфера? Теперь я установил его в uint32_t bufferSize = inAaudioBufferList.mBuffers[0].mDataByteSize;, так как считаю, что сжатый формат не будет больше несжатого... Но не слишком ли это излишне?< /li>
    Как правильно установить ioOutputDataPacketSize? Если я правильно понимаю документацию, мне следует установить ее как UInt32 ioOutputDataPacketSize =ufferSize/outAudioStreamBasicDescription.mBytesPerPacket;, но mBytesPerPacket равен 0. Если я установлю ее в 0, AudioConverterFillComplexBuffer() вернет ошибка. Если я установлю значение 1, оно будет работать, но я не знаю, почему...
  • В inInputDataProc() есть 3 "out "параметры. Я установил только ioData. Должен ли я также установить ioNumberDataPackets и outDataPacketDescription? Почему и как?


Подробнее здесь: https://stackoverflow.com/questions/198 ... and-bitrat
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»