如何通过ExoPlayer获取歌曲艺术家、歌曲名等元数据?
解决ExoPlayer获取音频元数据(艺术家、歌曲名)的问题
嘿,我来帮你搞定这个ExoPlayer获取音频元数据的问题!你当前的代码已经实现了基础的音频播放,但确实缺少处理元数据的逻辑。下面我会一步步告诉你怎么修改代码,拿到你需要的艺术家、歌曲名等信息。
核心思路
ExoPlayer本身支持通过MetadataOutput接口监听元数据回调,不管是本地音频的ID3标签,还是网络电台的ICY元数据,都可以通过这个接口获取。我们需要做的就是:
- 确保使用的数据源/渲染器支持元数据传递
- 实现
MetadataOutput接口来接收并解析元数据 - 将这个监听注册到音频渲染器上
具体实现步骤
1. 实现元数据监听类
首先定义一个类来处理元数据的回调,这里我们同时兼容ID3标签(本地或带ID3的流媒体)和ICY元数据(网络电台常用):
private class MyMetadataListener implements MetadataOutput { @Override public void onMetadata(Metadata metadata) { // 遍历所有元数据条目 for (int i = 0; i < metadata.length(); i++) { Metadata.Entry entry = metadata.get(i); // 处理ID3标签(比如本地MP3或带ID3的流媒体) if (entry instanceof Id3Frame) { Id3Frame id3Frame = (Id3Frame) entry; if (id3Frame instanceof TextInformationFrame) { TextInformationFrame textFrame = (TextInformationFrame) id3Frame; String tagId = textFrame.id; String tagValue = textFrame.value; // 根据标签ID解析对应的内容 switch (tagId) { case "TIT2": // 歌曲名 Log.d("AudioMetadata", "歌曲名: " + tagValue); break; case "TPE1": // 艺术家 Log.d("AudioMetadata", "艺术家: " + tagValue); break; case "TALB": // 专辑名 Log.d("AudioMetadata", "专辑名: " + tagValue); break; // 其他需要的标签可以继续添加 } } } // 处理ICY元数据(网络电台常用) else if (entry instanceof IcyInfo) { IcyInfo icyInfo = (IcyInfo) entry; String icyTitle = icyInfo.title; // 很多电台的ICY标题格式是「艺术家 - 歌曲名」,可以自己拆分 if (!TextUtils.isEmpty(icyTitle)) { String[] parts = icyTitle.split(" - ", 2); if (parts.length == 2) { Log.d("AudioMetadata", "艺术家: " + parts[0]); Log.d("AudioMetadata", "歌曲名: " + parts[1]); } else { Log.d("AudioMetadata", "电台标题: " + icyTitle); } } } } } }
2. 修改后台播放代码
接下来把你的doInBackground代码修改一下,注册我们的元数据监听。这里我顺便把旧的ExtractorSampleSource替换成了ExoPlayer 2.x推荐的ProgressiveMediaSource(如果你用的是旧版本,也可以给ExtractorSampleSource设置setMetadataOutput,原理一样):
protected Boolean doInBackground(final String... args) { try { String radioUrl = station.getRadiourl(); Uri uri = Uri.parse(radioUrl); String userAgent = Util.getUserAgent(context, "ExoPlayerDemo"); // 配置OkHttp数据源(保持你原来的配置) OkHttpClient okHttpClient = new OkHttpClient(); DataSource.Factory dataSourceFactory = new OkHttpDataSource.Factory(okHttpClient) .setUserAgent(userAgent) .setCacheControl(CacheControl.FORCE_NETWORK); MediaSource mediaSource; if (radioUrl.endsWith(".m3u8")) { // HLS流用HlsMediaSource mediaSource = new HlsMediaSource.Factory(dataSourceFactory) .createMediaSource(uri); } else { // 普通流媒体/本地文件用ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory) .createMediaSource(uri); } // 创建音频渲染器 MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer( mediaSource, MediaCodecSelector.DEFAULT, null, true, null, null, AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); // 注册元数据监听 audioRenderer.setMetadataOutput(new MyMetadataListener()); exoPlayer.prepare(audioRenderer); return true; } catch (IllegalArgumentException | SecurityException | IllegalStateException e) { e.printStackTrace(); } return false; }
额外注意事项
- 如果你使用的是模块化的ExoPlayer依赖,确保已经引入了
exoplayer-metadata模块,这样才能处理各种元数据类型。 - 有些网络电台可能没有开启ICY元数据,这种情况下你就拿不到对应的信息,这是电台服务器的设置问题,客户端没法解决。
- 旧版本ExoPlayer的API可能略有不同,但核心都是通过
MetadataOutput来监听元数据。
内容的提问来源于stack exchange,提问作者turkce apps
相关产品推荐
相关产品推荐

