是否可以在不下载的情况下获取远程音频文件的持续时间?

Car*_*los 3 android android-mediaplayer

我有远程音频文件的 URL。我需要为带有跟踪详细信息的适配器列表构建数据。这是代码的这一部分

    Log.d("audioURL", audio.getUrl());
    MediaPlayer tmpMedia;
    tmpMedia = MediaPlayer.create(getContext(), Uri.parse(audio.getUrl()));
    holder.txtDuration.setDuration(tmpMedia.getDuration()/1000);
    tmpMedia.release();
Run Code Online (Sandbox Code Playgroud)

但它的工作速度太慢了。LogCat 写的是这样的:

15:05:51.783: D/audioURL(776): http://cs4859.vk.me/u14195999/audios/0cbd695ddf50.mp3
15:05:51.783: D/MediaPlayer(776): Couldn't open file on client side, trying server side
15:05:53.813: D/audioURL(776): http://cs4859.vk.me/u14195999/audios/0cbd695ddf50.mp3
15:05:53.823: D/MediaPlayer(776): Couldn't open file on client side, trying server side
15:05:55.373: D/audioURL(776): http://cs4859.vk.me/u14195999/audios/0cbd695ddf50.mp3
15:05:55.383: D/MediaPlayer(776): Couldn't open file on client side, trying server side
15:05:58.143: D/audioURL(776): http://cs1626.vk.me/u149968/audios/04298447cd3c.mp3
15:05:58.153: D/MediaPlayer(776): Couldn't open file on client side, trying server side
Run Code Online (Sandbox Code Playgroud)

...等等。因此,我的大约 30 首曲目的播放列表在大约 7 分钟内初始化。

我猜,MediaPlayer类方法会getDuration()依次下载这些曲目(或其中的某些部分)以获取它们的持续时间。

有没有办法在不下载曲目的情况下快速获得这些持续时间?

Halim Qarroum,这似乎是一个正确的方法,但我在MediaMetadataRetriever上课时遇到了一些麻烦。

这是我上面的代码:

    if (android.os.Build.VERSION.SDK_INT < 10){
        holder.txtDuration.setDuration(audio.getTrackDuration());
    } else {
        MediaMetadataRetriever mRetriever = new MediaMetadataRetriever();
        Log.d("URI", Uri.parse(audio.getUrl()).toString());
        mRetriever.setDataSource(getContext(), Uri.parse(audio.getUrl()));
        String s = mRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
        holder.txtDuration.setDuration(Long.parseLong(s));
        mRetriever.release();
    }
Run Code Online (Sandbox Code Playgroud)

应用程序mRetriever.setDataSource(getContext(), Uri.parse(audio.getUrl()));因终止IllegalArgumentException。该audio.getURl()字符串http://cs4859.vk.me/u14195999/audios/134dfe90d1ec.mp3

为什么会出现异常?

Dhe*_*kar 6

我假设是 mp3,因为“音频文件”是一个笼统的短语。

\n\n

方法一:获取ID3标签

\n\n

变体 1:第 3 方库

\n\n

您将需要查看 mp3 文件中的 ID3 标签。\n除非您在其他地方跟踪所需的元数据。

\n\n

要具体获取文件的轨道长度,您需要查看 ID3 元数据标记,特别是标记的“TRCK”帧。

\n\n

要仅下载 ID3 标签部分,您必须首先下载文件的 ID3 标头部分。

\n\n

网站包含有关 ID3 标签格式的非常具体的信息。您需要查看 ID3 标签的版本号,然后在此基础上查找有关 ID3 标签长度的信息。然后,您必须下载整个标签,因为框架没有任何特定的顺序。

\n\n

然后您应该能够使用第三方库来查找 TRCK 帧及其数据。

\n\n

变体 2:HTTP 黑客

\n\n

对于 ID3v2 标签,抓住文件的开头。(ID3v2 帧可能位于其他地方,但实际上它们总是在那里。)您无法提前知道标签将持续多长时间。对于纯文本标签,您可能会在前 512-1024 字节中找到所需的信息。不幸的是,越来越多的 MP3 嵌入了 \xe2\x80\x98album art\xe2\x80\x99 图片,这些图片可能会更长;尝试选择一个能够优雅地忽略截断的 ID3 信息的 ID3 库。

\n\n

ID3v1 标签位于文件末尾。同样,你无法判断它们会持续多久。当然,您事先并不知道该文件是否具有 ID3v1 标签、ID3v2 标签、两者都有或都没有。一般来说,现在 ID3v2 是更好的选择。

\n\n

要通过 HTTP 读取文件的一部分,您需要Range标头。这也不是所有地方都支持。

\n\n

方法二:估算

\n\n

您可以通过 HTTP HEAD 请求获取文件大小。持续时间意味着以秒为单位的播放时间,如果不获取整个文件就无法获取。您可以通过获取前几个 MP3 帧,查看其比特率并假设文件的其余部分具有相同的比特率来猜测,但考虑到可变比特率编码的流行,这将接近准确的可能性是相当大低的。

\n\n
\n

理论上,ID3 标签可以包含可以让您更好地猜测 ASPI 和 ETCO 标签中的长度的信息。但在实践中,这些很少出现。

\n
\n\n

制作人员

\n\n
\n

感谢 SO 和互联网上的各个作者,当然是我脑海中一楼的那个人。

\n
\n


Hal*_*oum 5

Dheeb 发布了一个非常详细的答案。但是,ID3 tags并不总是出现在 mp3 文件中。您可以使用MediaMetadataRetrieverAndroid 框架附带的类,而不是寻找这些标签,这会迫使您将此方法限制为 mp3 文件。

此类可以为您提供来自某些类型的音频/视频文件的多个元数据,其中一个信息是持续时间。此方法具有标准的优点,因为它随 Android SDK 一起提供,并且不限于一种音频格式。

来自 Android 开发者相关页面:

MediaMetadataRetriever 类提供了一个统一的接口,用于从输入媒体文件中检索帧和元数据。

使用此类的一个简单代码示例:

MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(your_data_source);
String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long timeInmillisec = Long.parseLong( time );
long duration = timeInmillisec / 1000;
long hours = duration / 3600;
long minutes = (duration - hours * 3600) / 60;
long seconds = duration - (hours * 3600 + minutes * 60);
Run Code Online (Sandbox Code Playgroud)


小智 5

存在与 MediaMetadataRetriever 相关的错误。你可以试试,

 metaRetreiver.setDataSource("<remoteUrl>", new HashMap<String, String>());
Run Code Online (Sandbox Code Playgroud)