基于 Android EXOPlayer 创建视频播放器

谷歌在开放 Android 套件的时候也非常方便的把自家的 Youtube 播放相关的前端开源总结了出来,也就是我们经常提到的 ExoPlayer 。这里也顺道说下其他端,如果你是 Web 端,你可以使用 谷歌家的 shaka-player , 如果你是 iOS 的话,你可以使用 AVPlayer 。他们都提供从基础 UI 空间到自适应分辨率的支持。当然你也可以选择其他框架。

创建一个简单的 MP4 播放器

首先我们引入依赖

implementation 'com.google.android.exoplayer:exoplayer:2.11.7'

这里我是直接用的最新的版本 2.11.7

接下来我们需要做一些初始化的工作

val player = SimpleExoPlayer.Builder(context!!).build()
            exoplayer_view.player = player
            val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(
                context,
                Util.getUserAgent(context!!, "yourApplicationName")
            )

            val mp4uri = "https://media.vued.vanthink.cn/CJ7%20-%20Trailer.mp4"
            val videoSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
                .createMediaSource(Uri.parse(mp4uri))
            player.prepare(videoSource)

在你的布局中引入 SimpleExoPlayerView

<LinearLayout
        android:id="@+id/player_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        android:orientation="horizontal">
        <com.google.android.exoplayer2.ui.SimpleExoPlayerView
            android:id="@+id/exoplayer_view"
            android:background="#000000"
            android:layout_width="match_parent"
            android:layout_height="260dp"/>
    </LinearLayout>

这样一个简单的播放器便实现了,效果如下:

播放控制栏

当然我们肯定希望播放器有自己的控制栏,SimpleExoPlayerView 默认自带了基础的控制功能,包括快进,进度条,播放暂停按钮等。如果你希望换成其他的,你也可使尝试 设置一些app:controller_layout_id来进行控件的自定义, 实现自己的 播放器 UI

我们可以创建类似 player_control_view.xml 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center">

    <ImageButton android:id="@id/exo_play"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="@drawable/icons8_play_button_96"/>

    <ImageButton android:id="@id/exo_pause"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:background="@drawable/icons8_pause_squared_96"/>

</LinearLayout>

然后通过设置 app:controller_layout_id 将其链接到当前播放试图。

大致效果如下

你可以参考着原有的布局文件进行改写,主要就是改变一些局部控件的样式和显示隐藏等。

播放 HLS

HLS 是目前比较常规的播放多分辨率视频的格式,广泛应用在各大视频 APP 中,通过宽带的对比,从而给用户提供最佳观看的视频质量。EXOPlayer 提供了对 DASH 和 HLS 的全面支持。而且用起来也非常方便,配置也更加强大。


val hlsuri = "https://media.wxzxzj.com/the_garden_of_words_trailer_english__1080p.m3u8"
 
 val hlsMediaSource =
                HlsMediaSource.Factory(dataSourceFactory).setAllowChunklessPreparation(true).createMediaSource(Uri.parse(hlsuri))              .createMediaSource(Uri.parse(hlsuri))

player.prepare(hlsMediaSource)

获取 manifest 文件信息

如果我们需要获取当前HLS manifest 从而进行处理的话,我们可以通过监听一些事件来实现,这和 hls.js 差不多太多

player.addListener(
                object : Player.EventListener {
                    override fun onTimelineChanged(
                        timeline: Timeline, @TimelineChangeReason reason: Int
                    ) {
                        val manifest: Any? = player.getCurrentManifest()
                        if (manifest != null) {
                            val hlsManifest = manifest as HlsManifest
                            for (item in hlsManifest.mediaPlaylist.segments) {
                                Log.d("hls", item.url)
                            }
                            
                        }
                    }
                })

比如代码中我们可以获取当前分片的 url 列表信息

EXOPlayer 中提供了很多事件方便我们使用:

https://exoplayer.dev/listening-to-player-events.html

文章代码可以参考 https://github.com/JackPu/android-webview-video/blob/master/app/app/src/main/java/com/example/videoapp/FirstFragment.kt