android - 在 Android 上精确搜索 MP3 文件
问题描述
我正在构建一个应用程序,在该应用程序中准确查找 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 秒的偏移。
我在 ExoPlayer 的 github 上发现了这个问题。看起来这是具有 Mp3 格式的 ExoPlayer 的固有限制,它不会被修复。
我还发现这个问题似乎表明 Android 的本机 MadiaPlayer 和 MediaExtractor 中存在同样的问题。
有没有办法在 Android 上的本地(例如设备上)Mp3 文件中执行准确的搜索?我非常愿意采取任何黑客或解决方法。
解决方案
MP3 文件本质上不是可搜索的。它们不包含任何时间戳。它只是一系列 MPEG 帧,一个接一个。这使得这很棘手。寻找 MP3 的方法有两种,每种方法都有一些折衷。
最常见(也是最快)的方法是从第一个帧头读取比特率(或者,可能是前几个帧头的平均比特率),也许是 128k。然后,取整个文件的字节长度,除以这个比特率来估计文件的时间长度。然后,让用户搜索文件。如果他们寻找文件,则将文件的字节大小1:00
划分2:00
为 50% 标记,然后“针落”到流中。读取文件直到下一个帧头的同步字出现,然后开始解码。
可以想象,这种方法并不准确。充其量,您将平均处于目标的半帧以内。帧大小为 576 个样本,这是非常准确的。但是,首先计算落针点存在问题。最常见的问题是 ID3 标签等会增加文件的大小,从而影响大小计算。更严重的问题是可变比特率 (VBR) 文件。如果您有使用 VBR 编码的音乐,并且曲目的开头是静音或其他易于编码的,则开头可能是 32 kbps,而一秒可能是 320 kbps。计算文件时间长度时出现 10 倍错误!
第二种方法是将整个文件解码为原始 PCM 样本。这意味着您可以保证样本准确的搜索,但您必须至少解码到搜索点。如果您想要完整曲目的适当时间长度,则必须解码整个文件。大约 20 年前,这非常缓慢。寻找曲目所花费的时间几乎与听曲目到您要寻找的地方一样长!这些天来,对于短文件,您可能可以将它们解码得如此之快,以至于无关紧要。
TL;博士; 如果您必须进行样本精确搜索,请在将文件放入播放器之前先解码文件,但在决定此权衡之前先了解性能损失。
推荐阅读
- python-3.x - 如何修复 SMTPNotSupportedError 和 SMTPAuthenticationError?
- java - 如何找到在谷歌应用引擎服务器上找不到的请求 URL /MailDispatcherServlet?
- sql - 当类型为“smalldatetime”且值为 null 时,导出数据会出错
- scala - 否则数据框火花的情况
- .net - 将表单保存为位图而不调整大小
- c# - 有没有办法以另一种形式从组合框值过滤水晶报表中显示的数据
- python - Python QTcpSocket 和 QTcpServer 接收消息
- python - mypy 在 tox 中找不到模块
- python - 如何使用逗号分隔文件创建字典
- php - 如何从mysql表中检索数据