You need to enable JavaScript to run this app. 如何在ExoPlayer中正确播放每3秒动态更新的m3u8直播流地址?
优惠活动
大模型
产品
解决方案
定价
更多

如何在ExoPlayer中正确播放每3秒动态更新的m3u8直播流地址?

核心问题原因

你当前使用ConcatenatingMediaSource的逻辑是按队列顺序播放媒体源,只有前一个媒体源播放完成后才会加载下一个,并不会自动切换到新添加的有效地址,所以旧地址过期后播放器仍在请求失效的旧m3u8地址,直接触发源错误。

正确实现方案

方案1:自定义DataSource动态替换请求地址(最优,无卡顿切换)

这是最适配你的场景的方案,不需要频繁更换MediaSource,只需要在Http请求发起前动态替换最新的有效流地址即可。

  1. 先自定义HttpDataSource,重写open方法,每次打开请求的时候替换成最新的流地址:
public class DynamicUrlHttpDataSource extends DefaultHttpDataSource {
    private Supplier<String> latestUrlSupplier;

    public DynamicUrlHttpDataSource(int connectTimeoutMs, int readTimeoutMs, boolean allowCrossProtocolRedirects, Supplier<String> latestUrlSupplier) {
        super("ExoPlayer", connectTimeoutMs, readTimeoutMs, allowCrossProtocolRedirects, null);
        this.latestUrlSupplier = latestUrlSupplier;
    }

    @Override
    public long open(DataSpec dataSpec) throws HttpDataSourceException {
        // 每次发起请求前替换成最新的有效地址
        String latestUrl = latestUrlSupplier.get();
        DataSpec newDataSpec = new DataSpec.Builder()
                .setUri(latestUrl)
                .setPosition(dataSpec.position)
                .setLength(dataSpec.length)
                .setKey(dataSpec.key)
                .setFlags(dataSpec.flags)
                .build();
        return super.open(newDataSpec);
    }
}
  1. 自定义DataSource.Factory返回上面的自定义DataSource:
public class DynamicUrlHttpDataSourceFactory implements DataSource.Factory {
    private Supplier<String> latestUrlSupplier;

    public DynamicUrlHttpDataSourceFactory(Supplier<String> latestUrlSupplier) {
        this.latestUrlSupplier = latestUrlSupplier;
    }

    @Override
    public DataSource createDataSource() {
        return new DynamicUrlHttpDataSource(15000, 15000, true, latestUrlSupplier);
    }
}
  1. 初始化播放器,用全局变量保存最新的流地址:
// 全局变量保存最新流地址
private String latestStreamUrl;

// 初始化播放器逻辑
latestStreamUrl = dataItem.getVideo();
DynamicUrlHttpDataSourceFactory dataSourceFactory = new DynamicUrlHttpDataSourceFactory(() -> latestStreamUrl);
HlsMediaSource hlsMediaSource = new HlsMediaSource.Factory(dataSourceFactory)
        .createMediaSource(MediaItem.fromUri(latestStreamUrl));
player.setMediaSource(hlsMediaSource);
player.prepare();
player.setPlayWhenReady(true);
  1. 定时拉取新地址的时候只需要更新latestStreamUrl变量即可,不需要操作MediaSource:
private void setLiveStreamData(String id) {
    Call<LiveStreamData> liveStreamDataCall = RetrofitBuilder.newCreate().getStreamLive(id);
    liveStreamDataCall.enqueue(new Callback<LiveStreamData>() {
        @Override
        public void onResponse(@NotNull Call<LiveStreamData> call, @NotNull Response<LiveStreamData> response) {
            if (response.isSuccessful() && response.body() != null) {
                // 只需要更新最新地址变量即可
                latestStreamUrl = response.body().getUrl();
            }
        }

        @Override
        public void onFailure(@NotNull Call<LiveStreamData> call, @NotNull Throwable t) {
            Log.e(TAG, "onFailure: ", t);
        }
    });
}

方案2:替换MediaSource处理(适合地址变化不频繁的场景)

如果不想自定义DataSource,也可以在获取新地址后直接替换当前播放的MediaSource,开启无缝切换配置避免卡顿:

  1. 初始化ExoPlayer的时候开启无缝切换:
ExoPlayer player = new ExoPlayer.Builder(context)
        .setSeekBackIncrementMs(0)
        .setSeekForwardIncrementMs(0)
        .build();
  1. 获取新地址后直接替换MediaSource:
@Override
public void onResponse(@NotNull Call<LiveStreamData> call, @NotNull Response<LiveStreamData> response) {
    if (response.isSuccessful() && response.body() != null) {
        HlsMediaSource newHlsMediaSource = new HlsMediaSource.Factory(new DefaultHttpDataSourceFactory())
                .createMediaSource(MediaItem.fromUri(response.body().getUrl()));
        // 直接替换当前播放的媒体源,第二个参数传true表示保留当前播放位置无缝切换
        player.setMediaSource(newHlsMediaSource, true);
    }
}
额外注意事项
  • 不需要使用ConcatenatingMediaSource,这个组件是用来播放多个连续的媒体片段的,完全不适合你的动态流地址更新场景
  • 建议给ExoPlayer添加错误监听,遇到源错误的时候可以自动重试,避免偶发的地址更新不及时导致播放终止

内容的提问来源于stack exchange,提问作者BroscR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 10:54:04