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

ExoPlayer无法识别本地文件问题求助(Jetpack Compose场景)

问题描述

我在Jetpack Compose应用中尝试播放本地MP4文件,耗时一周查阅资料并测试多种代码片段,但多数已过时。尝试了两种实现方式:

尝试的代码

方式1(files目录文件)

var file = File(context.filesDir.getAbsolutePath(), "1.MP4")
val dataSourceFactory: DataSource.Factory = DefaultDataSource.Factory(
    context,
    DefaultDataSource.Factory(context)
)

val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
                .createMediaSource(MediaItem.fromUri(file.absolutePath))

val exoPlayer = ExoPlayer.Builder(context).build().apply {
    setMediaSource(mediaSource)
    prepare()
    play()
  }

方式2(raw资源文件)

val uri = RawResourceDataSource.buildRawResourceUri(R.raw.video3)
val mediaItem = MediaItem.fromUri(uri)
val exoPlayer = ExoPlayer.Builder(context).build().apply {
    setMediaItem(mediaItem)
    prepare()
    play()
}

已测试多个MP4和MP3文件,放置在assets、res/raw和data/data/[包名]/files目录下,且通过代码确认files目录下的文件存在:

var file = File(context.filesDir.getAbsolutePath(), "1.MP4")
if (file.exists())
// 返回true

但ExoPlayer无法识别文件,打印exoPlayer.videoSize.width.toString()结果为0,请求解决。


解决方案

以下是针对问题的具体排查和修复步骤:

1. 修正本地文件URI处理

直接使用文件路径字符串可能导致ExoPlayer无法正确解析,改用标准文件URI生成方式:

val file = File(context.filesDir, "1.MP4") // 简化路径写法
val mediaItem = MediaItem.fromUri(file.toUri())

// 简化DataSourceFactory创建(无需嵌套)
val dataSourceFactory = DefaultDataSource.Factory(context)
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
    .createMediaSource(mediaItem)

val exoPlayer = ExoPlayer.Builder(context).build().apply {
    setMediaSource(mediaSource)
    prepare()
}

2. 添加错误与状态监听排查问题

videoSize.width=0通常是文件解析失败,添加监听获取具体错误信息:

exoPlayer.addListener(object : Player.Listener {
    override fun onPlayerError(error: PlaybackException) {
        Log.e("ExoPlayer", "播放错误: ${error.errorCodeName} - ${error.message}")
    }

    override fun onPlaybackStateChanged(playbackState: Int) {
        when (playbackState) {
            Player.STATE_READY -> {
                val size = exoPlayer.videoSize
                Log.d("ExoPlayer", "视频尺寸: ${size.width}x${size.height}")
            }
            Player.STATE_BUFFERING -> Log.d("ExoPlayer", "缓冲中...")
            Player.STATE_IDLE -> Log.d("ExoPlayer", "播放器闲置")
            Player.STATE_ENDED -> Log.d("ExoPlayer", "播放结束")
        }
    }
})

3. 确保文件格式兼容ExoPlayer

ExoPlayer对MP4编码有明确要求,需满足:

  • 视频编码:H.264(AVC)或H.265(HEVC)
  • 音频编码:AAC、MP3等
    可通过FFmpeg工具查看文件编码信息:
ffmpeg -i 1.MP4

若编码不兼容,需转码为标准格式。

4. 正确绑定ExoPlayer到Compose UI

在Compose中必须通过AndroidView渲染PlayerView,否则播放器无法完成视频初始化:

@Composable
fun VideoPlayer(exoPlayer: ExoPlayer) {
    AndroidView(
        factory = { context ->
            PlayerView(context).apply {
                player = exoPlayer
                useController = true // 显示播放控制栏
            }
        },
        update = { view ->
            view.player = exoPlayer
        }
    )
}

5. 处理不同目录的文件加载

assets目录文件

需使用AssetDataSource.Factory加载:

val dataSourceFactory = AssetDataSource.Factory(context)
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
    .createMediaSource(MediaItem.fromUri("asset:///1.MP4"))

res/raw目录文件

确保R.raw.video3存在,文件名小写无特殊字符,原代码逻辑基本正确,可通过错误监听确认是否加载失败。

6. 验证文件可读性

除了file.exists(),还需确认文件可读:

if (file.exists() && file.canRead()) {
    // 文件存在且可读
} else {
    Log.e("FileError", "文件不可读")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:44:51