Главная » Программирование звука » Слоты и фреймы

0

Фреймы  MPEG  измеряются  в  страницах,  или  слотах  (slot).  Для  Layer  I  страница равна 4 байтам, для Layer 2 и Layer 3 слот составляет 1 байт. Задача поиска очередного  заголовка  решается  элементарно:  мы  знаем  скорость  передачи  битов в  поступающих  данных  и  частоту  дискретизации  получаемого  на  выходе  звука. Кроме того, нам известно количество отсчетов, составляющих один пакет: 384 для Layer 1, 1152 для Layer 2 и Layer 3. Исходя из этого, можно приблизительно вычислить  длину  фрейма.  B  соответствии  с  форматом  MPEG  заголовки  располагаются на одинаковом расстоянии друг от друга.

Расположить  их  идеально  равномерно  удается  не  всегда,  так  что  в  заголовке есть  специальный  бит,  который  служит  признаком  того,  не  была  ли  добавлена кданному фрейму дополнительная страница.

Листинг 14.9. Поиск очередного заголовка

if (_bitRate == 0) {    // Нестандартная скорость  передачи битов.

} else if (_layer==1) {  // Для  Layer 1 страница состоит

// из  четырех байт.

_headerSpacing =      // Страниц в  пакете  =.

384         // Отсчетов в пакете.

/ 32           // Битов в  странице.

* _bitRate     // Битов за  секунду.

/ _samplingRate;        // Отсчетов за  секунду.

_header += _headerSpacing*4;   // 4 байта на   страницу.

if(_padding) _header += 4;     // Дополнительная  страница.

} else {   // Для  Layer 2 и  Layer 3 страница  равна  одному байту.

_headerSpacing =

1152

//

Отсчетов в пакете.

/ 8

//

Битов в  странице.

* _bitRate

//

Битов за  секунду.

/ _samplingRate;

//

Отсчетов за  секунду.

_header += _headerSpacing;

//

1 байт на   страницу.

if(_padding) _header += 1;

//

Дополнительная  страница.

}

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

Еще  один  способ,  позволяющий  использовать  нестандартную  скорость  передачи битов, заключается в применении особого кода, соответствующего произвольной  скорости  передачи  битов.  B  этом  случае  непосредственно  вычислить  длину фрейма  будет,  безусловно,  невозможно.  Поэтому  стандарт  предусматривает,  что при  применении  произвольной  скорости  передачи  битов  длина  фрейма  не  должна  изменяться  (за  исключением  указанных  страниц,  заполненных  незначащей  информацией). Благодаря этому, мы можем измерить длину первого фрейма, просто проведя  поиск ближайшего  предшествующего заголовка,  после  чего  использовать полученное  значение  для  остальных  фреймов.  Для  записи  количества  страниц  во фрейме я применял переменную _headerSpacing.

Листинг 14.10. Поиск следующего заголовка,

в котором указана произвольная скорость передачи битов

if (_headerSpacing) {    // Расстояние между   заголовками

// уже   известно.

if (_layer == 1) {    // Для  Layer 1 страница  содержит 4 байта.

_header += _headerSpacing * 4;

if(_padding) _header += 4;

} else {               // Для  Layer 2 и  Layer 3 страница

// содержит  1 байт.

_header += _headerSpacing;

if(_padding) _header += 1;

}

} else {                 // Нужно  искать следующий  заголовок.

int slotLength = (_layer == 1)?4:1;

_headerSpacing = 1;

_header+=slotLength;

while((_header[0] != 0xFF) || ((_header[1]&0xF0) != 0xF0) ) {

_header+ = slotLength;

_headerSpacing++;

}

if (_padding) _headerSpacing–;

}

При  внимательном  изучении  стандарта  становится  очевидно,  что  строчка  из идущих подряд единиц встретиться не может, так что ложная синхрогруппа может появиться только в случае ошибки.

Листинг 14.11. Чтение и декомпрессия очередного фрейма MPEG

// Чтение  и  декомпрессия  очередного  фрейма

void DecompressMpeg::NextFrame() {

if (ParseHeader()) { // Больше нет  заголовков.

_samplesRemaining = 0;

return;

}

// Инициализация для  декодирования.

_pcmSamples[0] = _sampleStorage[0];

_pcmSamples[1] = _sampleStorage[1];

switch(_layer) {

case 1: LayerlDecode(); break; case 2: Layer2Decode(); break; case 3: Layer3Decode(); break;

}

// Инициализация  для чтения выборок.

_pcmSamples[0] = _sampleStorage[0];

_pcmSamples[1] = _sampleStorage[1];

}

Источник: Кинтцель Т.  Руководство программиста по работе со звуком = A Programmer’s Guide to Sound: Пер. с англ. М.: ДМК Пресс, 2000. 432 с, ил. (Серия «Для программистов»).

По теме:

  • Комментарии