Извлечение аудио кадров из файла AMR-NB
Я написал алгоритм для извлечения каждого кадра из файла AMR. Я считал, что первые 6 байтов файла являются заголовком, а следующая информация - аудио кадры. Каждый аудио кадр состоит из заголовка кадра и аудиоданных. Заголовок кадра сообщает размер кадра в байтах (с использованием таблицы CMR Mode - http://www.developer.nokia.com/Community/Wiki/AMR_format). Размер кадра сохраняется в первом байте кадра -> от второго бита до 5-го бита, считая MSB как первый бит.
Алгоритм не работает, и я решил отобразить на экране каждый байт в двоичном виде (0 и 1), и кажется, что иногда размер размера кадра больше 7, а таблица CMR имеет только 0...7 значений.
Ниже приведена таблица CMR:
CMR MODE FRAME SIZE( in bytes )
0 AMR 4.75 13
1 AMR 5.15 14
2 AMR 5.9 16
3 AMR 6.7 18
4 AMR 7.4 20
5 AMR 7.95 21
6 AMR 10.2 27
7 AMR 12.2 32
и мой вывод (каждый байт из файла AMR):
0 -> 0 0 0 0 0 0 0 0
1 -> 0 0 0 0 0 0 0 0
2 -> 0 0 0 0 0 0 0 0
3 -> 0 0 0 1 1 0 0 0
4 -> 0 1 1 0 0 1 1 0
5 -> 0 0 1 0 1 1 1 0
6 -> 1 0 0 1 1 1 1 0
7 -> 0 0 0 0 1 1 1 0
8 -> 1 1 0 0 1 1 0 0
9 -> 1 1 1 0 0 1 1 0
10 -> 0 0 0 0 1 1 1 0
11 -> 0 0 1 0 1 1 0 0
12 -> 0 0 0 0 0 0 0 0
13 -> 0 0 0 0 0 0 0 0
14 -> 0 0 0 0 0 0 0 0
15 -> 0 0 0 0 0 0 0 0
16 -> 1 0 0 1 0 1 1 0
17 -> 1 1 0 0 1 1 1 0
18 -> 1 1 1 1 0 1 1 0
19 -> 1 0 1 1 0 1 1 0
20 -> 1 1 0 0 1 1 0 0
21 -> 1 1 1 0 0 1 1 0
22 -> 0 0 0 0 1 1 1 0
23 -> 0 0 1 0 1 1 0 0
24 -> 0 0 0 0 0 0 0 0
25 -> 0 0 0 0 0 0 0 0
26 -> 0 1 0 0 0 0 0 0
27 -> 1 0 0 1 1 0 0 0
28 -> 1 0 1 1 0 1 1 0
29 -> 1 1 1 1 0 1 1 0
30 -> 1 1 1 1 0 1 1 0
31 -> 0 1 1 0 1 1 1 0
32 -> 0 0 0 0 0 0 0 0
33 -> 0 0 0 0 0 0 0 0
34 -> 0 0 0 0 0 0 0 0
35 -> 0 0 1 1 0 1 1 0
36 -> 1 0 1 1 0 1 1 0
37 -> 0 1 1 0 1 1 1 0
38 -> 0 0 0 1 0 1 1 0
39 -> 0 0 1 0 0 1 1 0
40 -> 0 0 0 0 0 0 0 0
Я взял байт номер 6: 10011110 -> 0011 - это номер 3, а базовое значение CMR для 3 - 18. Я пропускаю 18 байтов и достигаю байта nr. 6+18 = 24: 00000000 - значение CMR для 0 равно 13, и я пропускаю еще 13 байтов -> 24+13=37: 01101110 -> 1101 is 13 WHICH ISN'T IN CMR table
Что я делаю не так? Я полагаю, что печать в двоичном виде является правильным. Ниже приведен алгоритм чтения каждого кадра (не для отображения двоичного пути):
private void displayNrOfFrames() throws Exception{
FileInputStream fis = null;
try {
fis = new FileInputStream(mFile);
long result = fis.skip(6);
if(result != 6){
throw new Exception("Could not skip first 6 bytes(header) of AMR.");
}
int number = 0;
int bit = 0;
byte b;
BitSet bs;
while((b = Integer.valueOf(fis.read()).byteValue()) != -1){
bs = Util.fromByte(b);
number = 0;
//convert bits [1..4] to number
for (int i = 1; i <= 4; i++) {
bit = bs.get(i)? 1:0;
number += bit*Math.pow(2, 4 - i);
}
System.out.println(number);
if(!CMR_MAP.containsKey(number)){
throw new Exception("Could not parse AMR file.");
}
//skip the number of bytes of this frame.
fis.skip(CMR_MAP.get(number));
}
} catch (IOException e) {
e.printStackTrace();
}
}
[EDIT]
Похоже, что я делаю неправильно преобразование из байта в BitSet, а затем вызывает сбой алгоритма. В байте номер 6 он должен быть представлен числом 121, но ошибочно представлен номером 158. Также двоичный вывод неверен, поскольку он использует то же преобразование. Я не проверял метод конвертации (который я не разместил здесь). Извините за беспокойство.
1 ответ
Я надеюсь, что я не слишком поздно с этим ответом.
Перво-наперво: из той же ссылки вы можете видеть, что первые 6 байтов (заголовок файла) должны быть 0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A. Это постоянное значение и всегда должно быть там. Если его нет, то файл, вероятно, поврежден и не должен использоваться. Поэтому не следует слепо пропускать первые 6 байтов.
Теперь кодек AMR поддерживает DTX (прерывистая передача). DTX - это не что иное, как способ экономии полосы пропускания за счет уменьшения объема данных, когда вокодер обнаруживает тишину. Ваш анализатор amr должен быть готов к ожиданию DTX. Для AMR-NB (узкополосный amr или просто amr) DTX сигнализируется с использованием режима 8. Таким образом, ваша карта CMR должна содержать следующую запись
8 AMR SID 6 (SID - индикатор молчания... указывает, что период молчания начинается)
После SID будут действительные кадры тишины длиной 1 байт (только заголовок... БЕЗ ДАННЫХ), поэтому у вас должна быть запись для
15 AMR NO_DATA 1
Режимы 9-11 следует отказаться. И режимы 12-14 зарезервированы для будущего использования (как правило, они также отбрасываются). Вся вышеупомянутая информация была учтена с учетом того, что используется одноканальный AMR.
В отпечатки, которые вы вставили
6 -> 1 0 0 1 1 1 1 0
Это должен быть заголовок AMR Toc
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|F| FT |Q|P|P|
+-+-+-+-+-+-+-+-+
Для хранения бит F должен быть 0, но в вашем примере это 1. И последние два бита (которые являются битами заполнения) должны быть нулевыми, но в вашем примере это не 0. Я считаю, что ваш пример не рассказывает полную историю здесь.