ExoPlayer2:ConcatenatingMediaSource播放列表新视频启动自动暂停及画面残留问题
我之前碰到过一模一样的问题!用onPositionDiscontinuity确实踩了触发时机太早的坑——暂停播放器后,SurfaceView还没来得及更新新视频的第一帧(甚至还没开始渲染),就停在上一帧的画面了。给你两个靠谱的解决方案:
1. 使用onMediaItemTransition回调(推荐)
这个回调是ExoPlayer专门为媒体项切换场景设计的,触发时机比onPositionDiscontinuity准确得多,只有当新的媒体项完全切换完成后才会调用。你可以在这个回调里完成暂停和Surface清空操作:
player.addListener(new Player.Listener() { @Override public void onMediaItemTransition(@Nullable MediaItem mediaItem, int transitionReason) { // 只处理自动切换的情况(比如播放完上一个视频自动切到下一个) if (transitionReason == Player.MEDIA_ITEM_TRANSITION_REASON_AUTO) { // 暂停播放器 player.setPlayWhenReady(false); // 清空SurfaceView的残留画面 clearSurfaceFrame(); } } private void clearSurfaceFrame() { SurfaceHolder holder = yourSurfaceView.getHolder(); Canvas canvas = holder.lockCanvas(); if (canvas != null) { // 用你需要的背景色填充画布,比如黑色或透明色 canvas.drawColor(Color.BLACK); holder.unlockCanvasAndPost(canvas); } } });
2. 针对旧版ExoPlayer的兼容方案
如果你的项目用的是比较旧的ExoPlayer版本,没有onMediaItemTransition这个API,可以通过监听onTimelineChanged来判断媒体项是否切换:
player.addListener(new Player.Listener() { private MediaItem previousMediaItem; @Override public void onTimelineChanged(Timeline timeline, int reason) { super.onTimelineChanged(timeline, reason); MediaItem currentMediaItem = player.getCurrentMediaItem(); // 对比前后媒体项,判断是否发生了切换 if (previousMediaItem != null && !previousMediaItem.equals(currentMediaItem)) { player.setPlayWhenReady(false); clearSurfaceFrame(); } previousMediaItem = currentMediaItem; } // 复用上面的clearSurfaceFrame方法 });
为什么onPositionDiscontinuity会失效?
这个回调的触发逻辑是“播放位置发生不连续变化”——比如切换媒体项、手动seek、播放出错跳转等场景都会触发。但它的触发时机太早了,往往新的媒体项还没开始渲染画面,SurfaceView还停留在上一个视频的最后一帧,这时候暂停播放器自然不会更新画面。而onMediaItemTransition是在媒体项切换流程完全完成后才触发,此时处理Surface清空就不会有残留问题了。
内容的提问来源于stack exchange,提问作者bagage
相关产品推荐
相关产品推荐

