6

我目前正在编写一个 UPnP 远程控制应用程序,用于将远程 MediaServer 连接到远程 MediaRenderer。由于实际的 MP3 文件不会发送到 Android 设备,我希望能够获得当前播放文件的专辑封面,而无需将整个 MP3 文件下载到我的手机上。

我读过这MediaMetadataRetriever对这种事情很有用,但我无法让它发挥作用。我尝试的每一种方式,我都会IllegalArgumentException通过调用 来得到一个MediaMetadataRetriever#setDataSource,这表明我的文件句柄或 URI 是无效的。

MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();

以下内容有效,因为它是设备本身的直接文件路径:

metaRetriever.setDataSource("/sdcard/Music/Daft_Punk/Homework/01 - Daftendirekt.mp3");

但是,以下任何操作都会失败并出现相同的错误:

metaRetriever.setDataSource(appCtx, Uri.parse("http://192.168.1.144:49153/content/media/object_id/94785/res_id/1/rct/aa"));
metaRetriever.setDataSource(appCtx, Uri.parse("http://192.168.1.144:49153/content/media/object_id/94785/res_id/0/ext/file.mp3"));
metaRetriever.setDataSource("http://192.168.1.144:49153/content/media/object_id/94785/res_id/0/ext/file.mp3");

第一个是从 UPnP 元数据中提取的专辑ArtURI(没有 *.mp3 扩展名,但如果粘贴到 Web 浏览器中,文件将下载)。

第二次和第三次尝试使用 UPnP 元数据中的“res”值,它指向服务器上的实际文件。

我希望我只是错误地解析了 URI,但我没有想法。

有什么建议么?另外,从 UPnP 服务器拉取数据时,有没有更好的方法来完全做到这一点?FWIW,我正在使用 Cling UPnP 库。

== 解决方案 ==

我开始研究 william-seemann 的答案,这让我想到了这个:MediaMetadataRetriever.setDataSource(String path) 不再接受 URL

这篇文章的评论 #2 提到使用setDataSource()仍然接受远程 URL 的不同版本。

这是我最终做的事情,效果很好:

private Bitmap downloadBitmap(final String url) {
     final MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
     metaRetriever.setDataSource(url, new HashMap<String, String>());
     try {
        final byte[] art = metaRetriever.getEmbeddedPicture();
        return BitmapFactory.decodeByteArray(art, 0, art.length);
     } catch (Exception e) {
        Logger.e(LOGTAG, "Couldn't create album art: " + e.getMessage());
        return BitmapFactory.decodeResource(getResources(), R.drawable.album_art_missing);
     }
  }
4

2 回答 2

1

FFmpegMediaMetadataRetriever将从远程文件中提取元数据(披露:我创建了它)。我有与MediaMetadataRetriever相同的接口,但它使用FFmpeg作为它的后端。这是一个例子:

FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mUri);
String album = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ALBUM);
String artist = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ARTIST);
byte [] artwork = mmr.getEmbeddedPicture();
mmr.release();
于 2013-08-01T03:06:08.940 回答
0

查看源代码MediaMetadataRetriever不是来自官方 Android 存储库,但它应该仍然相似,如果不等效的话)向我展示了这一点:

if (uri == null) {
    throw new IllegalArgumentException();
}

和这个:

ContentResolver resolver = context.getContentResolver();

try {
    fd = resolver.openAssetFileDescriptor(uri, "r");
} catch(FileNotFoundException e) {
    throw new IllegalArgumentException();
}

if (fd == null) {
    throw new IllegalArgumentException();
}

FileDescriptor descriptor = fd.getFileDescriptor();

if (!descriptor.valid()) {
    throw new IllegalArgumentException();
}

您的异常来自这些块之一。

通过查看MediaMetadataRetriever文档和源代码,在我看来该文件必须在设备上。您可以使用 a Uri,但我认为它必须类似于"file:///android_asset/mysound.mp3". 不过我可能是错的;你确定MediaMetadataRetriever可以用来通过网络解析文件吗?

于 2013-07-31T16:54:34.333 回答