Искать назад, чтобы справиться с недопустимым заголовком MP3?

Я пишу приложение для декодирования MP3 кадров. У меня возникли трудности с поиском заголовков.

Заголовок MP3 состоит из 32 бит и начинается с подписи: 11111111 111.

Во внутреннем цикле ниже я ищу эту подпись. Когда эта подпись найдена, я извлекаю следующие два байта, а затем передаю последние три байта заголовка в пользовательский класс MpegFrame(). Класс проверяет целостность заголовка и анализирует информацию из него. MpegFrame.isValid() возвращает логическое значение, указывающее достоверность/целостность заголовка кадра. Если заголовок недействителен, внешний цикл выполняется снова, и подпись ищется снова.

При выполнении моей программы с CBR MP3 найдены только некоторые кадры. Приложение сообщает о множестве недопустимых кадров.

Я считаю, что недопустимые кадры могут быть результатом пропуска битов. Заголовок имеет длину 4 байта. Когда заголовок определяется как недействительный, я пропускаю все 4 байта и начинаю искать подпись со следующих четырех байтов. В следующем случае: 11111111 11101101 11111111 11101001 подпись заголовка находится в первых двух байтах, однако третий байт содержит ошибку, которая делает заголовок недействительным. Если я пропущу все байты, потому что я определил, что заголовок, начинающийся с первого байта, недействителен, я пропущу потенциальный заголовок, начинающийся с третьего байта (поскольку третий и четвертый байты содержат подпись).

Я не могу искать в InputStream назад, поэтому у меня следующий вопрос: Когда я определяю заголовок, начинающийся с байтов 1 и 2, как недопустимый, как мне запустить цикл поиска подписи, начинающийся с байта 2, а не с байта 5? ?

В приведенном ниже коде b — это первый байт рассматриваемого возможного заголовка, b1 — второй байт, b2 — третий байт и b3 — четвертый байт.

int bytesRead = 0;

//10 bytes of Tagv2
int j = 0;

byte[] tagv2h = new byte[10];
j = fis.read(tagv2h);
bytesRead += j;

ByteBuffer bb = ByteBuffer.wrap(new byte[]{tagv2h[6], tagv2h[7],tagv2h[8], tagv2h[9]});
bb.order(ByteOrder.BIG_ENDIAN);
int tagSize = bb.getInt();

byte[] tagv2 = new byte[tagSize];
j = fis.read(tagv2);
bytesRead += j;

while (bytesRead < MPEG_FILE.length()) {

        boolean foundHeader = false;

        // Seek frame
        int b = 0;
        int b1 = 0;
        while ((b = fis.read()) > -1) {
            bytesRead++;
            if (b == 255) {
                b1 = fis.read();
                if (b1 > -1) {
                    bytesRead++;
                    if (((b1 >> 5) & 0x7) == 0x7) {
                        System.out.println("Found header.");
                        foundHeader = true;
                        break;
                    }
                }
            }
        }

        if (!foundHeader) {
            continue;
        }

        int b2 = fis.read();
        int b3 = fis.read();

        MpegFrame frame = new MpegFrame(b1, b2, b3, false);
        if (!frame.isValid()) {
            System.out.println("Invalid header @ " + (bytesRead-4));
            continue;
        }

}

person noahnu    schedule 23.03.2014    source источник


Ответы (2)


Вы можете обернуть входной поток в PushbackInputStream. так что вы можете отодвинуть некоторые байты и повторно проанализировать их.

person Denis Tulskiy    schedule 24.03.2014

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

Seek() возвращает true, когда найден допустимый кадр (в другом месте хранится последний кадр, найденный при вызове Seek()). CheckHeader() проверяет целостность заголовка. SkipAudioData() считывает все аудиоданные кадра, помещая маркер потока в конец кадра.

private boolean Seek() throws IOException {
    while(!(CheckHeader() && SkipAudioData())){
        if(!ShiftHeader()){
            return false;
        }
    }
    return true;
}


private boolean ShiftHeader() {
    try {
        if (bytesRead >= MPEG_FILE.length()) {
            return false;
        }
    } catch (Exception ex) {
        ex.printStackTrace();
        return false;
    }

    header[0] = header[1];
    header[1] = header[2];
    header[2] = header[3];

    try {
        int b = fis.read();
        if (b > -1) {
            header[3] = b;
            return true;
        }
    } catch (IOException ex) {
        return false;
    } catch (Exception ex) {
        return false;
    }

    return false;
}
person noahnu    schedule 30.06.2014