代码之家  ›  专栏  ›  技术社区  ›  Vasiliy

Android上MP3文件的精确搜索

  •  2
  • Vasiliy  · 技术社区  · 7 年前

    我正在构建一个应用程序,在其中准确查找MP3文件非常重要。

    目前,我使用exoplayer的方式如下:

    public void playPeriod(long startPositionMs, long endPositionMs) {
    
        MediaSource mediaSource = new ClippingMediaSource(
                new ExtractorMediaSource.Factory(mDataSourceFactory).createMediaSource(mFileUri),
                startPositionMs * 1000,
                endPositionMs * 1000
        );
    
        mExoPlayer.prepare(mediaSource);
        mExoPlayer.setPlayWhenReady(true);
    
    }
    

    在某些情况下,这种方法会导致相对于预期播放时间的偏移量为1-3秒。

    I found this issue on ExoPlayer's github . 看起来这是MP3格式的exoplayer的一个内在限制,它不会被修复。

    I also found this question 这似乎表明安卓的原生madiaplayer和mediaextractor也存在同样的问题。

    有没有一种方法可以在Android上的本地(如在设备上)MP3文件中执行精确搜索?我非常愿意接受任何黑客攻击或变通方法。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Brad    7 年前

    MP3文件本身不可查找。它们不包含任何时间戳。它只是一系列MPEG帧,一个接一个。这让事情变得很棘手。寻找MP3有两种方法,每种方法都有一些折衷。

    最常见(也是最快)的方法是从第一个帧头读取比特率(或者,从前几个帧头读取平均比特率),也许是128K。然后,取整个文件的字节长度,除以这个比特率来估计文件的时间长度。然后,让用户搜索该文件。如果他们寻求 1:00 变成一个 2:00 文件,将文件的字节大小划分为50%标记,并将“针落”放入流中。读取文件,直到出现下一帧头的同步字,然后开始解码。

    你可以想象,这个方法不准确。充其量,你将平均在目标的半帧内。帧大小为576个样本,这是相当准确的。但是,在计算落针点时,首先存在一些问题。最常见的问题是ID3标记和类似的标记会向文件中添加大小,从而引发大小计算。更严重的问题是可变比特率(VBR)文件。如果您有用vbr编码的音乐,并且曲目的开头是无声的或易于编码,则开头可能是32 kbps,而一秒钟内可能是320 kbps。计算文件的时间长度时出错10倍!

    第二种方法是将整个文件解码为原始的PCM样本。这意味着你可以保证样品的准确寻找,但是你 必须 至少解码到搜索点。如果你想要一个适合全程的时间长度,你 必须 解码整个文件。大约20年前,这是令人痛苦的缓慢。寻找一个轨道几乎需要听的时间轨道,你正在寻找的点!现在,对于短文件,您可能可以快速解码它们,这并不重要。

    tl;dr;如果您必须进行样本精确搜索,请在将文件放入播放机之前先对其进行解码,但在决定这种权衡之前,请先了解性能损失。

    推荐文章