【问题标题】:Unable to read MP3 frame header bytes?无法读取 MP3 帧头字节?
【发布时间】:2013-11-02 15:15:32
【问题描述】:

我正在使用 Java 开发一个音频项目,该项目要求我根据音频文件的数据(而不是文件扩展名)确定音频文件类型,但我遇到了 MP3 问题。据我了解,MP3 文件被分成帧,其中每个帧都有一个 4 字节的标头,其中包含 11 个用于帧同步和其他数据的分类。现在我的代码可以准确识别 WAVE 文件,但是当我开始读取测试 MP3 文件的字节时,我在任何地方都找不到 11111111 字节(11 个帧同步位中的前 8 个)。

try {
        FileInputStream fis = new FileInputStream(f);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[11];
        byte[] byteData;
        int bytes = 0;

        while ((bytes = fis.read(buff)) != -1) {
            baos.write(buff, 0, buff.length);
        }

        byteData = baos.toByteArray();

        fis.close();
        baos.close();

        if ((int)byteData[0] == 255) {
            type = "MP3";
        } else if (("" + (char)byteData[8] + (char)byteData[9] + 
                (char)byteData[10] + (char)byteData[11]) == "WAVE") {
            type = "WAVE";
        }

    }

【问题讨论】:

    标签: java mp3 wave


    【解决方案1】:

    您可能会发现 MP3 文件的前三个字节是:

    49 44 33
    

    这是带有 ID3v2 标签的 MP3 的“神奇数字”....at least according to wikipedia

    编辑

    好的,所以我查看了我的系统,我拥有的 MP3 包含幻数:

    73 68 51
    

    在 ascii 中是 'ID3'。

    请注意,您的字节操作存在一些问题....当您根据 int 值测试字节值时,您需要确保正确进行转换....测试:

    byte x = ....;
    if (x == 255) {...}
    

    对于任何 'x' 值都不会为真,因为 (byte)x 的范围为 -128 到 +127。

    要使这个测试工作你需要做:

    if ((x & 0xff) == 255) { .... }
    

    我已经修改了您在我的系统上进行测试的方法,并尝试了 WAV 文件和一些 MP3。这是我的代码:

    public static final String getValid(File f) throws IOException {
        FileInputStream fis = new FileInputStream(f);
        byte[] buff = new byte[12];
        int bytes = 0, pos = 0;
    
        while (pos < buff.length && (bytes = fis.read(buff, pos, buff.length - pos)) > 0) {
            pos += bytes;
        }
    
        fis.close();
    
       // this is your test.... which should bitmask the value too:
        if ((buff[0] & 0x000000ff) == 255) {
            return "MP3 " + f;
        }
        // My testing indicates this is the MP3 magic number
        if (   'I' == (char)buff[0]
            && 'D' == (char)buff[1]
            && '3' == (char)buff[2]) {
            return "MP3 ID3 Magic" + f;
        }
        // This is the magic number from wikipedia (spells '1,!')
        if (49 == buff[0] && 44 == buff[1] && 33 == buff[2]) {
            return "MP3 ID3v2" + f;
        }
        if (   'W' == (char)buff[8]
            && 'A' == (char)buff[9]
            && 'V' == (char)buff[10]
            && 'E' == (char)buff[11]) {
            return "WAVE " + f;
        }
    
        return "unknown " + f;
    
    }
    

    【讨论】:

    • 现在我正在阅读的第一个字节是-1 -5 -78,它不会以某种方式终止while循环。我存储信息的方式可能有错误吗?
    • 是的,你做错了,我要编辑我的答案......但首先,你打算只读取前 11 个字节吗?
    • 是的,文件的全部内容在别处读取。我意识到当前返回的字节是正确的,因为-1 -5 包含我正在寻找的初始 11 位。不过,我仍然不完全确定这是否是进行 MP3 验证的最佳方式。
    • 编辑了我的答案。注意两件事 - 不需要 ByteArrayOutputStream 和字节操作。
    • 49 44 33 来自the linked Wikipedia article 的“十六进制签名”列(相当于十进制73 68 51 和US-ASCII ID3)。
    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 2019-01-16
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 2015-10-25
    • 2020-06-21
    • 2017-12-16
    相关资源
    最近更新 更多