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

如何在Media3中添加本地SRT字幕?及PlayerView超时设置问题

Media3 实现SRT字幕与PlayerView超时逻辑修改方案

一、加载同名SRT字幕

Media3中加载外部字幕的核心是通过SubtitleMediaItem将字幕文件关联到主媒体项,具体步骤如下:

  1. 生成字幕文件路径:从视频文件路径替换后缀得到SRT路径,比如视频路径为file:///storage/emulated/0/video.mp4,则字幕路径为file:///storage/emulated/0/video.srt。
  2. 配置字幕数据源:使用LocalUriDataSource.Factory适配本地SRT文件的数据源需求。
  3. 构建字幕媒体项:指定字幕格式(SRT对应MimeTypes.APPLICATION_SUBRIP)和数据源,构建SubtitleMediaItem。
  4. 关联到主媒体项:将字幕媒体项添加到MediaItem的字幕列表,再加载到播放器。

示例代码:

// 视频文件Uri
val videoUri = Uri.parse("file:///storage/emulated/0/video.mp4")
// 生成同名SRT字幕Uri
val subtitleUri = Uri.parse(videoUri.toString().replace(".mp4", ".srt"))

// 字幕数据源工厂
val subtitleDataSourceFactory = LocalUriDataSource.Factory(requireContext())

// 构建字幕媒体项
val subtitleMediaItem = SubtitleMediaItem.Builder()
    .setUri(subtitleUri)
    .setMimeType(MimeTypes.APPLICATION_SUBRIP)
    .setDataSourceFactory(subtitleDataSourceFactory)
    .build()

// 构建主媒体项并关联字幕
val mediaItem = MediaItem.Builder()
    .setUri(videoUri)
    .addSubtitle(subtitleMediaItem)
    .build()

// 加载到播放器
player.setMediaItem(mediaItem)
player.prepare()

如果需要自动检测目录下的同名字幕,可以封装工具方法遍历视频所在目录,匹配后缀为.srt的同名文件。

二、修改PlayerView控件超时逻辑

app:show_timeout="3000"是默认控制器的初始显示时长,默认逻辑会让进度条先隐藏、整体控件延迟两倍时间隐藏。要自定义超时逻辑,可通过以下两种方案实现:

方案1:自定义ControllerBehavior

继承DefaultPlayerControlView.ControllerBehavior,重写updateVisibility方法,完全自定义显示隐藏的延迟规则:

class CustomControllerBehavior(context: Context, attrs: AttributeSet?) :
    DefaultPlayerControlView.ControllerBehavior(context, attrs) {

    private val hideHandler = Handler(Looper.getMainLooper())
    private val hideRunnable = Runnable {
        controlView?.hide()
    }

    override fun updateVisibility(isPlaying: Boolean, userInitiated: Boolean) {
        // 移除之前的延迟任务
        hideHandler.removeCallbacks(hideRunnable)
        controlView?.show()

        // 自定义延迟规则:播放时5秒后隐藏,暂停时10秒后隐藏
        val delayMs = if (isPlaying) 5000L else 10000L
        hideHandler.postDelayed(hideRunnable, delayMs)
    }
}

然后在布局中指定自定义Behavior,同时禁用默认超时:

<androidx.media3.ui.PlayerView
    android:id="@+id/playerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:controller_behavior="com.yourpackage.CustomControllerBehavior"
    app:show_timeout="0"/>

方案2:监听控制器可见性

通过setControllerVisibilityListener手动控制显示隐藏时机:

playerView.setControllerVisibilityListener { visibility ->
    if (visibility == View.VISIBLE && player.isPlaying) {
        // 播放时4秒后隐藏控制器
        Handler(Looper.getMainLooper()).postDelayed({
            playerView.hideController()
        }, 4000)
    }
}

// 点击屏幕时重新显示控制器
playerView.setOnClickListener {
    playerView.showController()
}

三、代码优化建议

  1. 绑定生命周期:将播放器与Fragment生命周期绑定,避免内存泄漏:
    lifecycle.addObserver(object : DefaultLifecycleObserver {
        override fun onStart(owner: LifecycleOwner) {
            player.playWhenReady = true
        }
    
        override fun onStop(owner: LifecycleOwner) {
            player.playWhenReady = false
        }
    
        override fun onDestroy(owner: LifecycleOwner) {
            player.release()
        }
    })
    
  2. 逻辑分离:将媒体项构建、字幕加载等逻辑抽成单独工具类或方法,避免Fragment代码臃肿。
  3. 错误处理:添加字幕加载失败的监听,通过Player.Listener捕获异常:
    player.addListener(object : Player.Listener {
        override fun onError(error: PlaybackException) {
            if (error.errorCode == PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND) {
                // 提示用户字幕文件不存在
            }
        }
    })
    
  4. 播放器复用:后续迁移到Activity时,建议用ViewModel管理播放器实例,避免重复创建销毁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 12:52:46