Подтвердить что ты не робот

Как определить, имеет ли WAV файл заголовок 44 или 46 байтов?

Я обнаружил, что опасно предполагать, что все аудиофайлы PCM wav содержат 44 байта данных заголовка до начала выборки. Хотя это распространено, многие приложения (например, ffmpeg) будут генерировать wav с 46-байтным заголовком и игнорировать этот факт, в то время как обработка приведет к поврежденному и нечитаемому файлу. Но как вы можете определить, как долго заголовок на самом деле?

Очевидно, что есть способ сделать это, но я искал и мало разбирался в этом. Многие аудиопроекты там предполагают 44 (или, наоборот, 46) в зависимости от собственного контекста авторов.

4b9b3361

Ответ 1

Трюк заключается в том, чтобы посмотреть на "Subchunk1Size", который представляет собой 4-байтовое целое число, начинающееся с байта 16 заголовка. В нормальном 44-байтовом wav это целое число будет 16 [10, 0, 0, 0]. Если это 46-байтовый заголовок, это целое число будет 18 [12, 0, 0, 0] или, может быть, даже выше, если есть дополнительные расширяемые метаданные (редко?).

Дополнительные данные сами (если есть), начинаются в байте 36.

Итак, простая программа С# для определения длины заголовка будет выглядеть так:

static void Main(string[] args)
{
    byte[] bytes = new byte[4];
    FileStream fileStream = new FileStream(args[0], FileMode.Open, FileAccess.Read);
    fileStream.Seek(16, 0);
    fileStream.Read(bytes, 0, 4);
    fileStream.Close();
    int Subchunk1Size = BitConverter.ToInt32(bytes, 0);

    if (Subchunk1Size < 16)
        Console.WriteLine("This is not a valid wav file");
    else
        switch (Subchunk1Size)
        {
            case 16:
                Console.WriteLine("44-byte header");
                break;
            case 18:
                Console.WriteLine("46-byte header");
                break;
            default:
                Console.WriteLine("Header contains extra data and is larger than 46 bytes");
                break;
        }
}

Ответ 2

Вы должны проверить все данные заголовка, чтобы узнать, что представляют собой фактические размеры. Файлы широковещательного Wave Format будут содержать еще более крупную подстроку расширения. Файлы WAV и AIFF из Pro Tools имеют еще больше фрагментов расширения, которые недокументированы, а также данные после аудио. Если вы хотите быть уверенным, где начинается отсчет пробных данных, вам нужно действительно искать фрагмент данных ( "данные" для файлов WAV и "SSND" для AIFF).

В обзоре все подканалы WAV соответствуют следующему формату:

Subchunk Descriptor (4 bytes)
    Subchunk Size (4 byte integer, little endian)
    Subchunk Data (size is Subchunk Size)

Это очень легко обрабатывать. Все, что вам нужно сделать, это прочитать дескриптор, если он не тот, который вы ищете, прочитайте размер данных и перейдите к следующему. Простая Java-процедура для этого будет выглядеть так:

//
// Quick note for people who don't know Java well:
// 'in.read(...)' returns -1 when the stream reaches
// the end of the file, so 'if (in.read(...) < 0)'
// is checking for the end of file.
//
public static void printWaveDescriptors(File file)
        throws IOException {
    try (FileInputStream in = new FileInputStream(file)) {
        byte[] bytes = new byte[4];

        // read first 4 bytes
        // should be RIFF descriptor
        if (in.read(bytes) < 0) {
            return;
        }

        printDescriptor(bytes);

        // first subchunk will always be at byte 12
        // there is no other dependable constant
        in.skip(8);

        for (;;) {
            // read each chunk descriptor
            if (in.read(bytes) < 0) {
                break;
            }

            printDescriptor(bytes);

            // read chunk length
            if (in.read(bytes) < 0) {
                break;
            }

            // skip the length of this chunk
            // next bytes should be another descriptor or EOF
            in.skip(
                  (bytes[0] & 0xFF)
                | (bytes[1] & 0xFF) << 8
                | (bytes[2] & 0xFF) << 16
                | (bytes[3] & 0xFF) << 24
            );
        }

        System.out.println("end of file");
    }
}

private static void printDescriptor(byte[] bytes)
        throws IOException {
    String desc = new String(bytes, "US-ASCII");
    System.out.println("found '" + desc + "' descriptor");
}

Например, это случайный файл WAV, который у меня был:

found 'RIFF' descriptor
found 'bext' descriptor
found 'fmt ' descriptor
found 'minf' descriptor
found 'elm1' descriptor
found 'data' descriptor
found 'regn' descriptor
found 'ovwf' descriptor
found 'umid' descriptor
end of file

Примечательно, что здесь как "fmt", так и "data" законно появляются между другими кусками, потому что спецификация Microsoft RIFF говорит, что подчленки могут появляться в Любой заказ. Даже некоторые крупные аудиосистемы, которые я знаю, ошибаются и не учитывают этого.

Итак, если вы хотите найти определенный фрагмент, прокрутите файл, проверяя каждый дескриптор, пока не найдете тот, который вы ищете.

Ответ 3

В дополнение к превосходному ответу Radiodef я хотел бы добавить 3 вещи, которые не очевидны.

  • Единственное правило для файлов WAV - это фрагмент FMT, который перед блоком DATA. Кроме того, вы найдете фрагменты, о которых вы не знаете в начале, перед блоком DATA и после него. Вы должны прочитать заголовок для каждого фрагмента, чтобы перейти вперед, чтобы найти следующий фрагмент.

  • Блок FMT обычно встречается в 16-байтовом и 18-байтовом вариантах, но спецификация фактически позволяет больше 18 байт. Если поле размера заголовка FMT chunk больше 16, байты 17 и 18 также определяют, сколько лишних байтов есть, поэтому, если они равны нулю, вы получите 18-байтовый FMT-фрагмент, идентичный 16-байтовому. Безопасно читать только первые 16 байтов фрагмента FMT и анализировать их, игнорируя их больше. Почему это имеет значение? - не намного больше, но Windows XP Media Player смог воспроизводить 16-битные WAV файлы, но 24-битные WAV файлы, только если FMT-фрагмент был расширенной (18+ байт) версией. Там было много жалоб, что "Windows не воспроизводит мои 24-битные WAV файлы", но если бы у него был 18-байтовый FMT-фрагмент, это было бы... Microsoft исправила это когда-то в первые дни Windows 7, поэтому 24-бит с 16-байтовыми FMT файлами теперь работает нормально.

  • (Недавно добавлено) Размеры блоков с нечетными размерами происходят довольно часто. В основном видно, когда создается 24-битный моно файл. Это неявно из спецификации, но размер куска определяет фактическую длину данных (нечетное значение) и байта pad (ноль) добавляется после куска и до начала следующего фрагмента. Таким образом, куски всегда начинаются с четных границ, но сам размер блока сохраняется как фактическое нечетное значение.