android - ExoPlayer如何在加载视频期间显示加载第一帧
问题描述
我有一个提供视频 URI 和(预加载!)第一帧 URI 的 API。如何使用已经可用的第一帧初始化 ExoPlayer?
@Singleton
class MediaPlayer @Inject constructor(private val context: Context) {
companion object {
var exoPlayer: SimpleExoPlayer? = null
var pauseItem = false
}
fun initializeExoplayer(uri: Uri): SimpleExoPlayer {
if (exoPlayer != null) {
resetPlayer()
}
val trackSelector = DefaultTrackSelector()
trackSelector.setParameters(
DefaultTrackSelector.ParametersBuilder()
.setForceLowestBitrate(true)
.setMaxAudioBitrate(128_000)
)
exoPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector)
val mediaSource = createMediaSource(uri)
val loopingSource = LoopingMediaSource(mediaSource)
exoPlayer?.prepare(loopingSource)
exoPlayer?.volume = 1f
return exoPlayer!!
}
fun resetPlayer() {
exoPlayer?.playWhenReady = false
exoPlayer?.stop()
exoPlayer?.release()
exoPlayer = null
}
private fun createMediaSource(uri: Uri): MediaSource {
val userAgent = Util.getUserAgent(context, "ExoPlayerIntro")
val dataSourceFactory = DefaultDataSourceFactory(context, userAgent)
val mediaSource =
ProgressiveMediaSource.Factory(dataSourceFactory, DefaultExtractorsFactory())
.createMediaSource(uri)
return Objects.requireNonNull(mediaSource, "MediaSource cannot be null")
}
}
我还询问了 Google 团队: https ://github.com/google/ExoPlayer/issues/8139
解决方案
我也找不到任何解决这个问题的方法。但是,可以通过使用额外的 ImageView 来解决。我通过在视频的 SurfaceView 上重叠 ImageView 解决了 MediaPlayer 中的相同问题。
- 在 ImageView 中加载视频的第一帧。确保 ImageView 的大小和位置隐藏了 Video/SurfaceView。
- 渲染视频的第一帧后,立即隐藏 ImageView。
第 2 步可以通过以下方式实现:
媒体播放器:
val onInfoListener = object : MediaPlayer.OnInfoListener {
override fun onInfo(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
imageView.visibility = View.GONE
}
return false
}
}
mediaPlayer.setOnInfoListener(onInfoListener)
ExoPlayer:您可以在 VideoListener 中使用 onRenderedFirstFrame 回调,并以类似的方式隐藏 ImageView。
文档:
default void onRenderedFirstFrame()
在设置表面后第一次渲染帧时调用,或者因为渲染器被重置,或者因为正在渲染的流被更改。
推荐阅读
- vue.js - 带有 axios 助手的 axios 拦截器
- docker - 为什么当 vanila docker 成功时 docker-compose 失败(许可)
- ios - 应用程序的 Info.plist 文件应包含一个 NSBluetoothAlwaysUsageDescription 键,而该键位于 plist 文件中
- python - Airflow - 从自定义对象生成 DAG
- javascript - 如何使用纯 javascript 获取第一个可见的 body 元素(在屏幕上)
- pdf - 有没有办法在 pdf acro 字段中强制换行?
- django - 部署到服务器后可通过端口 3000 访问应用程序
- android - Flutter web 在现有的 Flutter 应用程序中创建问题
- python - 我想在 Python Pandas Dataframe 的数字列之一中添加双引号
- dart - add 和 sink.add 有什么区别?