【问题标题】:Precise seek in MP3 files on Android在 Android 上精确搜索 MP3 文件
【发布时间】:2019-05-13 12:09:07
【问题描述】:

我正在构建一个应用程序,在该应用程序中,准确查找 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。看起来这是 ExoPlayer 与 Mp3 格式的内在限制,它不会被修复。

I also found this question 这似乎表明 Android 的原生 MadiaPlayer 和 MediaExtractor 中存在同样的问题。

有没有办法在 Android 上的本地(例如设备上)Mp3 文件中执行准确的搜索?我非常愿意采取任何黑客或解决方法。

【问题讨论】:

    标签: android android-mediaplayer mp3 exoplayer


    【解决方案1】:

    MP3 文件本质上是不可搜索的。它们不包含任何时间戳。它只是一系列 MPEG 帧,一个接一个。这使得这很棘手。寻找 MP3 的方法有两种,每种方法都有一些折衷。

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

    您可以想象,这种方法并不准确。充其量,您将平均处于目标的半帧以内。帧大小为 576 个样本,这是非常准确的。但是,首先计算落针点存在问题。最常见的问题是 ID3 标签等会增加文件的大小,从而影响大小计算。更严重的问题是可变比特率 (VBR) 文件。如果您有使用 VBR 编码的音乐,并且曲目的开头是静音或其他易于编码的,则开头可能是 32 kbps,而一秒可能是 320 kbps。计算文件时长时出现 10 倍的错误!

    第二种方法是将整个文件解码为原始 PCM 样本。这意味着您可以保证样本准确的搜索,但您必须至少解码到搜索点。如果您想要完整曲目的适当时间长度,您必须解码整个文件。大约 20 年前,这非常缓慢。寻找曲目所花费的时间几乎与听曲目到您要寻找的地方一样长!如今,对于短文件,您可能可以将它们解码得如此之快,以至于它并不重要。

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

    【讨论】:

    • 感谢您提供非常丰富的回复。我不介意先探讨您关于解码文件的建议,但我不知道您的意思。您是否碰巧知道我可以阅读有关此主题的资源?否则,您能否向我推荐几个搜索词,让我在 Google 上大致了解您的建议?
    • @Vasiliy 我不是 Android 开发人员,但我认为您会使用 MediaExtractor (developer.android.com/reference/android/media/MediaExtractor) 对文件进行解复用(对于 MP3 来说可能甚至不需要!)和 MediaCodec (developer.android.com/reference/android/media/MediaCodec)实际解码它。一些谷歌搜索导致了此 AAC 代码:github.com/taehwandev/MediaCodecExample/blob/master/src/net/… 它应该类似于对 MP3 执行相同操作。
    • 好的,非常感谢您的帮助。这应该让我开始。如果没有更具体的内容,我稍后会接受答案。
    • 感谢您非常有帮助的回答。我遇到了问题,您的回答帮助我理解问题并找到解决方案stackoverflow.com/a/57916886/348589
    • @shadysherif 没问题!很高兴您发现这很有帮助。
    【解决方案2】:

    恒定比特率的 mp3 更好。我使用的系统是将mp3中每个帧头的样本偏移位置记录到一个列表中。然后寻找,我会通过使用列表中的值寻找所需样本之前最接近的帧头,然后从该位置读取到我想要的样本。这工作得相当好,但并不完美,因为渲染的波形是从参考帧解码的,而不是从文件开头解码的值。如果需要准确,请使用 libmpg123,它似乎几乎是样本准确的。如果是商业应用,请注意检查许可。

    【讨论】:

    • 所以样本和寻道时间毕竟是有关系的。你能详细说明一下吗?
    【解决方案3】:

    对于将来可能遇到此问题的人,我最终只是将 mp3 转换为 m4a。在我的具体情况下,这是最简单的解决方案。

    【讨论】:

    • 回到原始来源比从 MP3 转换要好得多。 MP3 和 AAC 都是有损的。在它们之间进行转换会导致额外的质量损失。
    • @Brad 好吧,有时您所拥有的只是 mp3 文件,您需要确保准确的搜索功能。即使这意味着质量损失......
    • 您可以像使用 AAC 一样将 MP3 音频放入 MP4 容器中,并通过这种方式获得容器中时间戳的好处。 ffmpeg -i yourfile.mp3 -acodec copy output.mp4
    • @Brad 很有趣。如果该项目需要更多维护,我会尝试您的建议。非常感谢。
    • 我用模拟慢速网络测试了 MP3 -> MP4。确实它也适用于浏览器,有时浏览器会尝试通过范围请求来查找 MP3 文件,但它们失败了。然而,对于 MP4,它似乎在处理范围请求方面效果更好。
    猜你喜欢
    • 2018-12-07
    • 1970-01-01
    • 2019-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    • 2016-12-24
    • 1970-01-01
    相关资源
    最近更新 更多