You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Android的ExoPlayer忽略HLS空播放列表?

解决ExoPlayer播放HLS时忽略空播放列表的问题

问题背景

Android应用用ExoPlayer播放HLS视频,服务器偶尔会返回只有头部、没有音视频轨道的空播放列表,且无法修改服务器行为。此时ExoPlayer会停在最后一帧停止播放,但iOS的AVPlayer却能正常继续播。排查后发现:

  • 收到空列表前,播放器会定期请求m3u8和ts文件;收到后只请求播放列表更新,DefaultHlsPlaylistTracker的onLoadCompleted不再触发。
  • 内部会触发onPlaylistError(错误类型为HlsPlaylistTracker.PlaylistStuckException),但这个错误没传递到播放器的外部回调。

解决方案

方案1:自定义播放列表解析器,过滤空列表

通过重写HlsPlaylistParser,在解析时如果遇到空播放列表,就返回上一次的有效列表,避免播放器进入异常状态。

  1. 实现自定义解析器:
public class NonEmptyHlsPlaylistParser extends DefaultHlsPlaylistParser {
    private HlsPlaylist lastValidPlaylist;

    @Override
    public HlsPlaylist parse(Uri uri, InputStream inputStream) throws IOException {
        HlsPlaylist playlist = super.parse(uri, inputStream);
        // 判断是否为空播放列表:媒体列表无分片或无音视频轨道
        if (playlist instanceof MediaPlaylist) {
            MediaPlaylist mediaPlaylist = (MediaPlaylist) playlist;
            if (mediaPlaylist.segments.isEmpty() || mediaPlaylist.tracks.isEmpty()) {
                // 有有效历史列表就返回历史,没有就返回当前(避免首次加载出问题)
                return lastValidPlaylist != null ? lastValidPlaylist : playlist;
            }
        }
        // 更新有效历史列表
        lastValidPlaylist = playlist;
        return playlist;
    }
}
  1. 替换ExoPlayer的默认解析器:
HlsMediaSource.Factory hlsFactory = new HlsMediaSource.Factory(dataSourceFactory)
        .setPlaylistParserFactory(() -> new NonEmptyHlsPlaylistParser());
// 用这个factory创建HlsMediaSource,再设置给ExoPlayer

方案2:自定义播放列表追踪器,忽略空列表错误

重写DefaultHlsPlaylistTracker的错误处理逻辑,遇到PlaylistStuckException时直接跳过,继续请求新的播放列表。

  1. 实现自定义追踪器:
public class TolerantHlsPlaylistTracker extends DefaultHlsPlaylistTracker {
    public TolerantHlsPlaylistTracker(Factory factory) {
        super(factory);
    }

    @Override
    protected void handlePlaylistError(PlaylistError playlistError) {
        // 识别空列表导致的异常
        if (playlistError.error instanceof PlaylistStuckException) {
            // 直接调度下一次播放列表更新,不触发错误停止
            schedulePlaylistUpdate(true);
            return;
        }
        // 其他错误按原逻辑处理
        super.handlePlaylistError(playlistError);
    }
}
  1. 配置到ExoPlayer中:
DefaultHlsPlaylistTracker.Factory trackerFactory = new DefaultHlsPlaylistTracker.Factory(dataSourceFactory);
TolerantHlsPlaylistTracker playlistTracker = new TolerantHlsPlaylistTracker(trackerFactory);

HlsMediaSource.Factory hlsFactory = new HlsMediaSource.Factory(dataSourceFactory)
        .setPlaylistTracker(playlistTracker);

方案3:监听播放器错误,主动恢复播放

如果前两个方案不好实现,可以尝试监听播放器的错误回调,捕获到PlaylistStuckException时主动恢复播放。

注意:需要确保错误能传递到外部回调,可通过Player.Listener实现:

player.addListener(new Player.Listener() {
    @Override
    public void onPlayerError(PlaybackException error) {
        if (error.getCause() instanceof HlsPlaylistTracker.PlaylistStuckException) {
            // 尝试恢复播放,比如重新准备或者继续播放
            player.play();
            // 或者重新加载媒体源
            if (player.getMediaItem() != null) {
                player.prepare();
            }
        }
    }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:25:57