【问题标题】:How can I extract the audio data from an mp3 file?如何从 mp3 文件中提取音频数据?
【发布时间】:2016-06-10 11:36:40
【问题描述】:

我需要创建一个独立于元数据的 mp3 文件散列(即,可以在重新标记后计算相同的散列)。如何将音频数据仅提取到内存中,而不通过解压缩器实际运行?

MAD 似乎是一个很好的起点 - http://www.underbit.com/products/mad/,但似乎并没有明显公开执行此操作的函数。

任何指针表示赞赏!

【问题讨论】:

    标签: c++ c mp3


    【解决方案1】:

    如何才能将音频数据仅提取到内存中,而不通过解压缩器实际运行?

    您无法在不解压缩的情况下提取音频数据 - 它已被压缩!但是,如果您只想要原始压缩流,请继续阅读!

    典型的 mp3 音频文件将分为几个部分:
    [可能的元标记]
    [可能是垃圾]
    [可能的 XING/LAME 标签 [可能更多垃圾]]
    [mp3 音频帧]
    [可能的元标记]

    可能的元标记: 大多数 mp3 音频文件的头部都会有一个 id3 标记。请注意,某些用户可能会使用不同的标记格式标记他们的 mp3 文件,例如 APE,因此您也需要考虑到这一点。

    可能是垃圾: 一些 mp3 音频文件已被多次标记、重新标记和转换,元标记标头可能无法为您提供第一个音频帧的准确偏移量,作为先前标记的残余可以留下。 foobar2000 可以选择解决此问题。

    可能的 XING/LAME 标签:这些包含在 mp3 音频帧中,但它们不包含实际音频。 madplay 有代码向您展示如何读取和解析这些帧。 XING/LAME 标头可能有帧数,因此值得解析这些标头。同样,如果该文件已通过许多不同的标记器和编辑器,则可能会在此处找到几个格式错误、无效的音频帧。

    MP3 音频帧:实际压缩流,分为“帧”。每帧都以同步位模式 0xFFE 开始。

    可能的元标记:在文件末尾找到更多元标记的情况并不少见。 id3v1、APE、歌词都可以在这里找到。

    要查找音频帧偏移量,您需要解析任何元标记标头,然后开始查找同步位模式。您不能只从文件开头开始寻找同步模式,因为并非所有标记器都正确支持unsynchronization,因此元标记本身可能包含 0xFFE 模式。

    获得第一个音频帧的偏移量后,您应该查看文件末尾并计算其中有多少非音频数据,以便知道何时停止解析音频。一旦有了音频数据开头的偏移量和音频数据结尾的偏移量,就可以通过哈希/校验和函数传递音频数据!

    【讨论】:

      【解决方案2】:

      您可以使用ffmpeg 直接通过复制模式访问音频内容。什么格式都没有关系,因为 API 将为您提供一个包含原始数据的容器(仅在复制模式下)。如果您有视频或想要处理解码后的音频数据,您还可以解复用和解码。

      查看 ffmpeg 的示例以快速了解如何执行此操作。通过使用 ffmpeg,我的意思是不使用该工具,而是使用 c++/c 中的 libffmpeg(libavformat,libavcodec),尽管我认为您也可以使用 ffmpeg 工具从 cmdline 执行此操作,方法是将输出发送到 stdout 并将其通过管道传输到 md5sum 或等价的东西(如果你是 unix 用户,那就是)。

      特殊情况“-acodec copy”告诉 ffmpeg 使用与解码相同的编解码器进行编码。换言之,不会发生音频转码。

      【讨论】:

        【解决方案3】:

        什么样的音频数据?原始解码的 PCM 流?单独的 MP3 帧?如果它是封装在 .wav 中的 MP3 怎么办?它仍然可以有 .mp3 扩展名,但有完整的 .wav 包装。

        剥离 ID3v1 标记很简单 - 文件末尾只有 128 个字节。 ID3v2 有点难 - 它是可变长度的,并且添加到 MP3 的开头,您必须解析长度字段(这是 4 个字节,其中仅使用最低 7 位,为标签提供 28 位最大长度)。 .wav 包装器会更难——我不知道 .wav 强加为元数据的任何细节。

        【讨论】:

        • 嗯,我什至没有考虑过 MP3 可能在 .wav 包装器中...我想提取单个 MP3 帧。这将省略 id3 v1 和 v2 标签,所以我应该能够从中获得一个独立于标签的哈希......对吗?
        • 很久以前我一直在做一个 mp3 解码器,甚至还为该文件获取了 ISO 规范的副本……要考虑的小事情太多了……最重要的是也就是说,mp3 可以与 mpeg 视频交错 - mp3 格式被设计为可以轻松嵌入到几乎任何东西中,因此很难准确地确定 mp3 音频帧的实际位置。
        • 我购买了一台索尼​​数字录音机。我可以在 Linux 下挂载文件系统,但我无法找到它存储曲目标记的位置。 id3v2 显示我的一个 mp3 录音包含一个 2756 字节的 GEOB 帧。我想在添加曲目标记之前和之后提取它以查看我的曲目标记是否隐藏在此处。因此,这是另一个答案,它解释了如何提取特定帧,而不仅仅是音频帧。
        【解决方案4】:

        我最近也需要解决这个问题(检测具有不同 ID3 标签的重复 mp3 文件)。最简单的做法是使用 ffmpeg 制作一份去掉所有 ID3 标签的 mp3 文件的副本,然后取一个 md5 总和。

        https://github.com/pepaslabs/mp3md5sum

        【讨论】:

          【解决方案5】:

          ffmpeg 可以单独计算音频文件的音频片段的 MD5 哈希,即无元数据。

          用途:

          ffmpeg -v -i $file -acodec copy -f md5 -
          

          请注意,FLAC 已经将 MD5 哈希存储为元数据。

          【讨论】:

            【解决方案6】:

            我为一个带有无法处理标签的旧 mp3 播放器的 Linux 机器编写了这个简单的小 sn-p。剩下的只是 mp3 标头和数据(在标准输出上编码)。您可以将它用于您的 md5。

            #include <fcntl.h>
            #define DUMPTAGS
            int main(int argc, char **argv){
               unsigned char buf[4096];
               int len,fd = open(argv[1],O_RDONLY);
               while (len=read(fd,buf,10)){ // handle ID3v2 tags (maybe multiple)
                  if (buf[0]=='I' && buf[1]=='D' && buf[2]=='3'){
                     len=read(fd,buf,buf[9]|(buf[8] << 7)|(buf[7] << 14)|(buf[6] << 21));
            #ifdef DUMPTAGS
                     write(2,buf,len);
            #endif
                  } else break;
               }
               while (write(1,buf,len)){
                  unsigned char tag[3] = {'T','A','G'}, *end;
                  len=read(fd,buf,4096);
                  end=(unsigned char *)memmem(buf,len,&tag,3);
                  if (end){ //handle ID3v1 tag (should only be 1)
                     write(1,buf,end-buf);
            #ifdef DUMPTAGS
                     write(2,end,len-(end-buf));
            #endif
                     break;
                  }
               }
            }
            

            【讨论】:

              猜你喜欢
              • 2022-08-13
              • 1970-01-01
              • 2010-10-30
              • 1970-01-01
              • 2015-09-05
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-04-16
              相关资源
              最近更新 更多