Извлечь звуковые кадры из файла AMR-NB

Я написал алгоритм для извлечения каждого кадра из файла AMR. Я считал первые 6 байт файла заголовком, а следующую информацию — аудиокадрами. Каждый аудиокадр состоит из заголовка кадра и аудиоданных. Заголовок кадра сообщает размер кадра в байтах (используя таблицу режимов CMR — 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 байтов и достигаю байта №. 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. Также двоичный вывод неверен, поскольку он использует то же преобразование. Я не проверял метод преобразования (который я здесь не публиковал). Простите за беспокойство.


person Alexandru Circus    schedule 05.07.2013    source источник
comment
Вы можете открыть свой файл в vim или любом шестнадцатеричном редакторе и посмотреть, что он показывает как заголовок файла?   -  person Rajeev    schedule 11.07.2013


Ответы (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 АМР 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. Я считаю, что ваш пример не рассказывает здесь всю историю.

person Rajeev    schedule 11.07.2013
comment
Спасибо за Ваш ответ. Проблема здесь заключалась в том, как вы упомянули, что я вслепую пропустил первые 6 байтов БЕЗ проверки того, что они действительно принадлежат заголовку AMR. Вместо этого файл amr был файлом 3gp. Теперь мне удалось извлечь необработанный amr из .3gp, и все работает нормально. Итак, вы предлагаете расширить таблицу CMR на 8 -> 6 байт и 15 -> 1 байт? - person Alexandru Circus; 11.07.2013
comment
а 9-11 надо отбросить? Если у меня есть значение 9, я не должен пропускать ни одного байта? - person Alexandru Circus; 11.07.2013
comment
Да, сэр... ваша логика должна включать режим 8 размером 6 байт и режим 15 размером 1 байт. Вообще я бы пропустил все режимы с 9 по 14, т.к. до сих пор за 4 года работы с AMR в сценариях реального времени я не встречал ни одного кадра с этими режимами. - person Rajeev; 11.07.2013
comment
Если ваш файл действительно соответствует стандарту AMR, вы не должны сталкиваться с режимами 9-14. Ниже строки из AMR RFC Типы кадров дополнительного комфортного шума, указанные в таблице 1a в [2] (т. е. GSM-EFR CN, IS-641 CN и PDC-EFR CN), НЕ ДОЛЖНЫ использоваться в этом формате полезной нагрузки. потому что стандартизированный кодек AMR требуется только для реализации общего типа кадра AMR SID, а не тех, которые являются родными для встроенных кодировок. - person Rajeev; 11.07.2013
comment
Нам нужно то же самое сейчас, есть ли у кого-нибудь полный пример кода для разбора файлов AMR? - person eaorak; 17.08.2016