Почему у секции "fmt " размер не равен 16 байтам? |
Добавил(а) microsin |
Обычно у WAV-файла со стандартным заголовком размер секции "fmt " составляет 16 байт, тогда у этой секции структура традиционная: typedef __packed struct _TWavFmtGeneric { uint16_t compression; // 2 байта, формат звуковых данных. Определяет // наличие кодека или его отсутствие. uint16_t channels; // 2 байта, количество каналов uint32_t samplerate; // 4 байта, количество выборок в секунду uint32_t bytespersecond; // 4 байта, количество байт в секунду. uint16_t blockalign; // 2 байта, выравнивание блоков данных в файле uint16_t bitspersample; // 2 байта, разрядность одной выборки. }TWavFmtGeneric; Однако из этого правила есть исключения, о чем подробнее рассказывается в этой статье. Основное правило - при обработке WAV-файла нужно проверять размер всех секций. Находящиеся в общем пользовании файлы формата WAV могут неожиданно содержать расширенные секции с традиционными идентификаторами. Например, файлы WAV и AIFF пакета Pro Tools имеют больше секций расширения, которые нигде не задокументированы, а также содержат дополнительную информацию после фактических данных звука. Если Вы хотите успешно добраться до данных звука и определить их начало и конец, то на самом деле нужно искать секцию с идентификатором "data" и прочитать её размер (для файлов AIFF соответствующим идентификатором для информации о данных звука будет "SSND"). Правило 1: у дескриптора секции WAV-файла формат всегда одинаковый. Хорошая новость: несмотря на некоторую путаницу с идентификаторами и их следованием в теле WAV-файла, блок идентификации секций (дескриптор секции) имеет всегда один и тот же формат: typedef struct _TRIFFsection { char id[4]; // 4 байта, текстовый идентификатор секции uint32_t len; // 4 байта, длина секции }TRIFFsection; По этой причине процесс обработки файла значительно упрощается. Все, что требуется, это просто прочитать блоки идентификации секции (назовем его дескриптор секции), и если он нас не интересует, просто переносим позицию чтения в файле на следующий дескриптор. Следующий простой код на Java демонстрирует этот процесс (код просто выведет название всех секций WAV-файла). // Здесь функция 'in.read(...)' вернет -1, когда был достигнут
// конец файла, так что проверка 'if (in.read(...) < 0)'
// покажет окончание файла. public static void printWaveDescriptors(File file) throws IOException { try (FileInputStream in = new FileInputStream(file)) { byte[] bytes = new byte[4]; // Прочитаем первые 4 байта, там должен быть // дескриптор RIFF: if (in.read(bytes) < 0) { return; } printDescriptor(bytes); // У первой секции всегда размер 12, из которых 4 // уже были прочитаны, так что пропустим еще 8 байт: in.skip(8); for (;;) { // Цикл с чтением и проверкой каждого дескриптора секции. if (in.read(bytes) < 0) { break; } printDescriptor(bytes); // Прочитаем длину секции. if (in.read(bytes) < 0) { break; } // Пропуск в файле длины этой секции. Последующие байты // должны быть либо другим дескриптором, либо завершением // файла (EOF). int length = (Byte.toUnsignedInt(bytes[0]) | Byte.toUnsignedInt(bytes[1]) << 8 | Byte.toUnsignedInt(bytes[2]) << 16 | Byte.toUnsignedInt(bytes[3]) << 24); in.skip(Integer.toUnsignedLong(length)); } System.out.println("Конец файла."); } } Например, могут встретиться следующие секции в произвольном WAV-файле (идентификаторы имеют размер 4 байта): RIFF Следует отметить, что секция и "fmt ", и секция "data" могут совершенно законно находиться в любом месте WAV-файла. Месторасположение этих секций в файле, как и других секций, спецификацией Microsoft RIFF жестко не определено - теоретически они могут следовать друг за другом в любом порядке. [Размер секции "fmt "] Итак, с секциями wav-файла разобрались, и стоит иметь в виду еще 3 важных правила, касающихся появления в файле информации о формате (секция "fmt ") и самих звуковых данных (секция "data"). Правило 2: секция "fmt " всегда идет перед секцией "data", это выполняется всегда. Однако перед секцией "data" и после неё могут быть и любые другие секции - в том числе секции не определенные ни в каком стандарте (это даже дает Вам возможность добавлять в WAV-файл свои собственные секции). Совместите правило 1 и правило 2, и с их помощью легко обработаете любой WAV-файл. Правило 3: у секции "fmt " размер не всегда 16 байт. Существуют вариации 16 байт и 18 байт, однако стандарт не ограничивает размер этой секции, он может быть и больше 18 байт. Если в поле размера дескриптора "fmt " указано больше 16 байт, то байты 17 и 18 также указывают, сколько здесь имеется дополнительных байт. Если оба байта 17 и 18 равны 0, то это просто секция "fmt " с размером 18, идентичная секции "fmt " с размером 16, не более того, и на эти два байта не стоит обращать внимания (их надо просто пропустить). Т. е. совершенно безопасно прочитать предыдущие данные формата точно так же, как если бы это была секция "fmt " стандартного размера 16. Почему произошло изменение формата секции "fmt "? Проигрыватель медиа-файлов Windows XP Media Player мог воспроизводить 16-битные WAV-файлы, но с 24-битными WAV-файлами потребовалось расширение секции "fmt " до версии 18+. Раньше было много жалоб на то, что Windows не может проигрывать 24-битные WAV-файлы, однако если была секция "fmt " с 18 байтами, то она смогла бы это делать сразу. Компания Microsoft исправила это позже в Windows 7, так что 24 бита сейчас хорошо работают вместе с 16-байтными секциями "fmt ". Правило 4. Довольно часто встречаются секции с нечетными размерами. Иногда это происходит с 24-битным монофоническим файлом. В спецификации четко не указано, что в дескрипторе задается реальный размер последующей секции, даже если он нечетный. В случае нечетного размера секции после неё (перед следующим дескриптором) добавляются нулевой байт. Таким образом, порции данных всегда начинаются с четных границ, но сам размер порции сохраняется как фактическое (даже нечетное) значение. [Ссылки] 1. How can I detect whether a WAV file has a 44 or 46-byte header? site:stackoverflow.com. |