Расшифровка аудио формата 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, то он отрицательный; дополнительно сдвиг битов может делать расширение знака. Это не обрабатывается в указанном псевдокоде.