Расшифровка аудио формата ima4

Чтобы уменьшить размер загружаемого приложения для iPhone, я сжимаю некоторые аудиофайлы. В частности, я использую afconvert в командной строке, чтобы изменить формат.wav на формат.caf со сжатием ima4.

Я прочитал этот (wooji-juice.com) потрясающий пост на эту тему. У меня возникли проблемы с шагом "декодирование пакетов ima4". Я посмотрел их пример кода и застрял. Пожалуйста, помогите с каким-нибудь псевдокодом или примером кода, который поможет мне в правильном направлении.

Спасибо!

Дополнительная информация: Вот что я закончил и где у меня проблемы... Я могу воспроизводить файлы.wav как на симуляторе, так и на телефоне. Я могу сжать файлы.wav в.caf w / ima4, используя afconvert в командной строке. Я использую SoundEngine, который пришел с CrashLanding (я исправил одну утечку памяти). Я изменил код SoundEngine для поиска mFormatID 'ima4'.

Я не понимаю сообщение в блоге, связанное выше, начиная с "Расчет размера распакованных данных". Зачем мне это делать? Кроме того, что означает термин "пакет"? Я очень новичок в любом виде звукового программирования.

2 ответа

Решение

После сбора всех данных от Wooji-Juice, Multimedia Wiki и Apple, вот мое предложение (может потребоваться некоторый эксперимент):

Файловая структура

  • Файл Apple IMA4 сделан из пакета по 34 байта. Это пакетная единица, используемая для создания файла.
  • Каждый 34-байтовый пакет состоит из двух частей:
    • первые 2 байта содержат преамбулу: начальный предиктор и индекс шага
    • оставшиеся 32 байта содержат звуковые фрагменты (для получения 16-битной выборки используется фрагмент размером 4 бита)
  • Каждый пакет имеет 32 байта сжатых данных, которые представляют 64 выборки по 16 битов.
  • Если звуковой файл стереофонический, пакеты чередуются (один слева, один справа); должно быть четное количество пакетов.

расшифровка

Каждый пакет из 34 байтов приведет к распаковке 64 выборок по 16 бит. Таким образом, размер несжатых данных составляет 128 байт на пакет.

Псевдокод декодирования выглядит так:

int[] ima_index_table = ... // Index table from [Multimedia Wiki][2]
int[] step_table = ... // Step table from [Multimedia Wiki][2]
byte[] packet = ... // A packet of 34 bytes compressed
short[] output = ... // The output buffer of 128 bytes
int preamble = (packet[0] << 8) | packet[1];
int predictor = preamble && 0xFF80; // See [Multimedia Wiki][2]
int step_index = preamble && 0x007F; // See [Multimedia Wiki][2]
int i;
int j = 0;
for(i = 2; i < 34; i++) {
    byte data = packet[i];
    int lower_nibble = data && 0x0F;
    int upper_nibble = (data && 0xF0) >> 4;

    // Decode the lower nibble
    step_index += ima_index_table[lower_nibble];
    diff = ((signed)nibble + 0.5f) * step / 4;
    predictor += diff;
    step = ima_step_table[step index];

    // Clamp the predictor value to stay in range
    if (predictor > 65535)
        output[j++] = 65535;
    else if (predictor < -65536)
        output[j++] = -65536;
    else
        output[j++] = (short) predictor;

    // Decode the uppper nibble
    step_index += ima_index_table[upper_nibble];
    diff = ((signed)nibble + 0.5f) * step / 4;
    predictor += diff;
    step = ima_step_table[step index];

    // Clamp the predictor value to stay in range
    if (predictor > 65535)
        output[j++] = 65535;
    else if (predictor < -65536)
        output[j++] = -65536;
    else
        output[j++] = (short) predictor;
}

Термин "пакет" относится к группе сжатых аудиосэмплов с заголовком. Вам нужен заголовок для декодирования данных сразу после. Если вы считаете свой файл ima4 книгой, то каждый пакет - это страница. В верхней части находятся значения, необходимые для декодирования этой страницы, а затем сжатый звук.

Вот почему вам необходимо рассчитать размер распакованных данных (а затем освободить место для них) - поскольку они сжаты, вам необходимо преобразовать данные из сжатого звука в несжатый звук, прежде чем вы сможете его выводить. Чтобы выделить выходной буфер, вам нужно знать, насколько большим он должен быть (примечание: вам может потребоваться выводить порциями, которые больше, чем один пакет за раз).

Похоже, что типичная структура, согласно более раннему разделу "Обзор", состоит в том, что наборы из 64 выборок, каждые 16 бит (т.е. 128 байтов) транслируются в 2-байтовый заголовок и 32-байтовый набор сжатых выборок (34 байта). в целом). Таким образом, в типичном случае вы можете получить ожидаемый размер выходных данных, взяв размер входных данных, разделив на 34, чтобы получить количество пакетов, а затем умножив на 128 байтов для несжатого аудио на пакет.

Вы не должны этого делать, хотя. Похоже, вы должны вместо этого запросить kAudioFilePropertyDataFormat, чтобы получить mBytesPerPacket - это значение "34" выше, а mFramesPerPacket - это 64 выше, которое умножается на 2 (для 16-байтовых выборок), чтобы получить 128 байтов выход.

Затем для каждого пакета вам нужно будет выполнить декодирование, описанное в посте. В несколько более длинном псевдо-C-коде, предполагая, что вы получаете массивы байтов, для обработки заголовка:

packet = GetPacket();
Header = (packet[0] << 8) | packet[1]; //Big-endian 16-bit value
step_index = Header & 0x007f; //Lower seven bits
predictor = Header & 0xff80; //Upper nine bits
for (i = 2; i < mBytesPerPacket; i++)
{
    nibble = packet[i] & 0x0f; //Low Nibble
    process that nibble, per the blogpost -- be careful on sign-extension!
    nibble = (packet[i] & 0xf0) >> 4; //High Nibble
    process that nibble, per the blogpost -- be careful on sign-extension!
}

Расширение знака выше относится к тому факту, что сообщение включает обработку каждого клева как без знака, так и со знаком. Если старший бит полубайта (бит 3) равен 1, то он отрицательный; дополнительно сдвиг битов может делать расширение знака. Это не обрабатывается в указанном псевдокоде.

Другие вопросы по тегам