Главная » Программирование звука » Обработка потока байтов

0

Чтобы упростить выделение битов из потока данных, я использую один байтовый буфер, который смещается вперед. B результате постоянно работаю со сплошным  блоком  памяти.  Переменная  _bufferStorage  это  блок  памяти,  в  котором хранятся  данные.  Вспомогательные  методы  будут  изменять  значение  переменной

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

Для простоты работы с данными как Layer 1, так и Layer 2, требуется, чтобы сжатые единицы информации шли следом за заголовком фрейма. По существу, мы можем работать с пакетами сжатых данных. Однако в формате Layer 3 сделано еще одно улучшение. Поскольку часть аудиоданных может сжиматься легче, чем остальные, в уровне 3 разрешается размещать сжатые данные за границами фрейма.

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

Листинг 14.4. Переменные для хранения поступающих байтов MPEG

void FillBuffer(); // Поддержка буферов  данных

// в  заполненном состоянии.

void ResetBits();  // Перезапуск процесса  извлечения  битов.

long GetBits(int numBits);     // Извлечение битов.

AudioByte _bufferStorage[2048];

AudioByte *_buffer;             // Начало области  активных

// данных в  буфере.

int    _bitsRemaining;   // Осталось битов  в  старшем байте.

AudioByte *_bufferEnd;   // Конец   области  активных  данных

// в буфере.

AudioByte *_header;      // Положение  заголовка  в буфере.

Листинг 14.5. Инициализация переменных буфера MPEG

_buffer = _bufferStorage + sizeof(_bufferStorage);

_header = _bufferEnd = _buffer;

_headerSpacing = 0;    // He задан.

Листинг 14.6. Управление буфером MPEG

// Перемещаем данные  к  началу  буфера и  заполняем

// остальное пространство.

void DecompressMpeg::FillBuffer() {

// Выход  за  конец буфера?!

if (_header > _bufferStorage+sizeof(_bufferStorage)) {

// Внутренняя  ошибка: буфер  исчерпан.

cerr << "Internal error; buffer exhausted!\n";

_buffer = _header;

}

if (_buffer > _header) { // Пропустили очередной  заголовок?!

// Ошибка  синхронизации: фрейм   слишком  велик!

cerr << "Synchronization error; frame too big!\n";

_buffer = _header;

}

// Блокируем частые  вызовы ReadBytes() для  получения

// маленьких  порций данных.

if (_buffer < (_bufferStorage+512)) return; int totalBufferSize = sizeof(_bufferStorage); int bufferSize = _bufferEnd _buffer; memmove(_bufferStorage,_buffer, bufferSize);

_header = _buffer _bufferStorage;

_bufferEnd = _buffer _bufferStorage;

_buffer = _bufferStorage;

_bufferEnd += ReadBytes(_bufferEnd, totalBufferSize bufferSize);

}

Рассмотренный выше метод FillBuffer гарантирует, что у нас всегда будет обрабатываться  непрерывный  блок  данных.  Ha  следующем  этапе  нужно  собрать механизм, с помощью которого можно будет извлекать из потока переменное число  битов.  Ключевым  моментом  такой  ситуации  является  переменная  _bitsRemaining, контролирующая количество неиспользованных битов в первом байте буфера.

Листинг 14.6. Управление буфером MPEG (продолжение)

void DecompressMpeg::ResetBits() {

_bitsRemaining = 8;

}

int masks[] = {0,1,3,7,0xF,0x1F,0x3F,0x7F,0xFF};

long DecompressMpeg::GetBits(int numBits) {

if(_bitsRemaining == 0) {      // Если   в  этом байте  все  биты

// обработаны…

_buffer++;                   //…переходим  к  следующему.

_bitsRemaining = 8;

}

if(_bitsRemaining >= numBits) { // Можно использовать  данные

// из этого  байта

// для заполнения?

_bitsRemaining = numBits;

return (*_buffer>>_bitsRemaining)&masks[numBits];

}

// Израсходуем оставшуюся часть  этого  байта, а затем

// возвращаемся, чтобы считывать  данные дальше.

long result = (*_buffer & masks[_bitsRemaining])

<< (numBits _bitsRemaining);

numBits = _bitsRemaining;     // B данный  момент  нам   столько

// битов не   нужно.

_bitsRemaining = 8;             // Переходим  на   следующий  бит.

_buffer++;

return result | GetBits(numBits);

}

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

По теме:

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