ExoPlayer 演示应用

ExoPlayer 的主要演示应用有两个主要用途

  1. 提供一个相对简单但功能齐全的 ExoPlayer 用法示例。该演示应用可以作为开发您自己应用的便捷起点。
  2. 方便试用 ExoPlayer。除了包含的示例外,该演示应用还可用于测试您自己的内容播放。

本页介绍如何获取、编译和运行演示应用。它还介绍了如何使用它来播放您自己的媒体。

获取代码

主演示应用的源代码位于我们的 GitHub 项目demos/main 文件夹中。如果您尚未操作,请将项目克隆到本地目录中

git clone https://github.com/androidx/media.git

接下来,在 Android Studio 中打开项目。您应该在 Android 项目视图中看到以下内容(演示应用的相关文件夹已展开)

The project in Android Studio

编译和运行

要编译和运行演示应用,请在 Android Studio 中选择并运行 demo 配置。演示应用将安装并在连接的 Android 设备上运行。如果可能,我们建议使用物理设备。如果您希望改用模拟器,请阅读支持的设备的模拟器部分,并确保您的虚拟设备使用的系统映像的 API 级别至少为 23。

SampleChooserActivity and PlayerActivity

演示应用会显示一个示例列表 (SampleChooserActivity)。选择一个示例将打开第二个 activity (PlayerActivity) 进行播放。该演示具有播放控制和轨道选择功能。它还使用 ExoPlayer 的 EventLogger 实用程序类将有用的调试信息输出到系统日志。此日志记录(以及其他标签的错误级别日志记录)可以通过以下命令查看

adb logcat EventLogger:V *:E

启用捆绑解码器

ExoPlayer 有许多扩展,允许使用捆绑的软件解码器,包括 AV1、VP9、Opus、FLAC 和 FFmpeg(仅限音频)。演示应用可以按照以下方式构建,以包含和使用这些扩展

  1. 构建您要包含的每个扩展。请注意,这是一个手动过程。有关说明,请参阅每个扩展中的 README.md 文件。
  2. 在 Android Studio 的“构建变体”视图中,将演示模块的构建变体设置为 withDecoderExtensionsDebugwithDecoderExtensionsRelease,如下图所示。

    Selecting the demo `withDecoderExtensionsDebug` build variant

  3. 正常编译、安装和运行 demo 配置。

默认情况下,仅当不存在合适的平台解码器时才使用扩展解码器。可以指定优先使用扩展解码器,如下一节所述。

播放您自己的内容

在演示应用中有多种方法可以播放您自己的内容。

1. 编辑 assets/media.exolist.json

演示应用中列出的示例是从 assets/media.exolist.json 加载的。通过编辑此 JSON 文件,可以从演示应用中添加和删除示例。其架构如下,其中 [O] 表示可选属性。

[
  {
    "name": "Name of heading",
    "samples": [
      {
        "name": "Name of sample",
        "uri": "The URI of the sample",
        "extension": "[O] Sample type hint. Cannot be combined with mime_type. Values: mpd, ism, m3u8",
        "clip_start_position_ms": "[O] A start point to which the sample should be clipped, in milliseconds"
        "clip_end_position_ms": "[O] An end point from which the sample should be clipped, in milliseconds"
        "drm_scheme": "[O] Drm scheme if protected. Values: widevine, playready, clearkey",
        "drm_license_uri": "[O] URI of the license server if protected",
        "drm_force_default_license_uri": "[O] Whether to force use of "drm_license_uri" for key requests that include their own license URI",
        "drm_key_request_properties": "[O] Key request headers if protected",
        "drm_session_for_clear_content": "[O] Whether to attach a DRM session to clear video and audio tracks"
        "drm_multi_session": "[O] Enables key rotation if protected",
        "mime_type": "[O] The MIME type of the sample. Cannot be combined with extension.",
        "subtitle_uri": "[O] The URI of a subtitle sidecar file",
        "subtitle_mime_type": "[O] The MIME type of subtitle_uri (required if subtitle_uri is set)",
        "subtitle_language": "[O] The BCP47 language code of the subtitle file (ignored if subtitle_uri is not set)",
        "ad_tag_uri": "[O] The URI of an ad tag to load via the IMA extension"
      },
      ...etc
    ]
  },
  ...etc
]

示例播放列表可以使用以下架构指定

[
  {
    "name": "Name of heading",
    "samples": [
      {
        "name": "Name of playlist sample",
        "playlist": [
          {
            "uri": "The URI of the first sample in the playlist",
            "extension": "[O] Sample type hint. Cannot be combined with mime_type. Values: mpd, ism, m3u8"
            "clip_start_position_ms": "[O] A start point to which the sample should be clipped, in milliseconds"
            "clip_end_position_ms": "[O] An end point from which the sample should be clipped, in milliseconds"
            "drm_scheme": "[O] Drm scheme if protected. Values: widevine, playready, clearkey",
            "drm_license_uri": "[O] URI of the license server if protected",
            "drm_force_default_license_uri": "[O] Whether to force use of "drm_license_uri" for key requests that include their own license URI",
            "drm_key_request_properties": "[O] Key request headers if protected",
            "drm_session_for_clear_content": "[O] Whether to attach a DRM session to clear video and audio tracks",
            "drm_multi_session": "[O] Enables key rotation if protected",
            "mime_type": "[O] The MIME type of the sample. Cannot be combined with extension.",
            "subtitle_uri": "[O] The URI of a subtitle sidecar file",
            "subtitle_mime_type": "[O] The MIME type of subtitle_uri (required if subtitle_uri is set)",
            "subtitle_language": "[O] The BCP47 language code of the subtitle file (ignored if subtitle_uri is not set)"
          },
          {
            "uri": "The URI of the second sample in the playlist",
            ...etc
          },
          ...etc
        ]
      },
      ...etc
    ]
  },
  ...etc
]

如果需要,密钥请求头被指定为一个对象,其中包含每个头的字符串属性

"drm_key_request_properties": {
  "name1": "value1",
  "name2": "value2",
  ...etc
}

在示例选择器 activity 中,溢出菜单包含用于指定是否优先使用扩展解码器的选项。

本地文件 URI 和分区存储限制

当指定本地文件 URI 时,演示应用会请求必要的存储访问权限以读取这些文件。然而,从 Android 13 开始,无法加载不以典型媒体文件扩展名(如 .mp4)结尾的任意文件。如果您需要加载此类文件,可以将其放置在演示应用的特定存储目录中,该目录没有访问限制。此目录通常位于 /sdcard/Android/data/androidx.media3.demo.main/files

2. 加载外部 exolist.json 文件

演示应用可以使用上述架构加载外部 JSON 文件,并按照 *.exolist.json 约定命名。例如,如果您在 https://yourdomain.com/samples.exolist.json 托管此类文件,则可以使用以下方式在演示应用中打开它

adb shell am start -a android.intent.action.VIEW \
    -d https://yourdomain.com/samples.exolist.json

在安装了演示应用的设备上点击 *.exolist.json 链接(例如,在浏览器或电子邮件客户端中)也会在演示应用中打开它。因此,托管 *.exolist.json JSON 文件提供了一种简单的方式来分发内容,供他人在演示应用中试用。

3. 触发 Intent

Intent 可用于绕过示例列表并直接启动播放。要播放单个示例,请将 intent 的操作设置为 androidx.media3.demo.main.action.VIEW,并将其数据 URI 设置为要播放的示例的 URI。此类 intent 可以使用以下命令从终端触发

adb shell am start -a androidx.media3.demo.main.action.VIEW \
    -d https://yourdomain.com/sample.mp4

单个示例 intent 支持的可选额外数据有

  • 示例配置额外数据
    • mime_type [String] 示例 MIME 类型提示。例如,DASH 内容的 application/dash+xml
    • clip_start_position_ms [Long] 示例应被裁剪的起始点,以毫秒为单位。
    • clip_end_position_ms [Long] 示例应被裁剪的结束点,以毫秒为单位。
    • drm_scheme [String] 如果受保护,则为 DRM 方案。有效值为 widevineplayreadyclearkey。也接受 DRM 方案 UUID。
    • drm_license_uri [String] 如果受保护,则为许可证服务器的 URI。
    • drm_force_default_license_uri [Boolean] 对于包含其自身许可证 URI 的密钥请求,是否强制使用 drm_license_uri
    • drm_key_request_properties [String array] 如果受保护,则为以 name1, value1, name2, value2 等形式打包的密钥请求头。
    • drm_session_for_clear_content [Boolean] 是否将 DRM 会话附加到明文视频和音频轨道。
    • drm_multi_session [Boolean] 如果受保护,则启用密钥轮换。
    • subtitle_uri [String] 字幕附带文件的 URI。
    • subtitle_mime_type [String] subtitle_uri 的 MIME 类型(如果设置了 subtitle_uri,则为必填项)。
    • subtitle_language [String] 字幕文件的 BCP47 语言代码(如果未设置 subtitle_uri,则忽略)。
    • ad_tag_uri [String] 使用 [IMA 扩展][ ] 加载的广告标签的 URI。
    • prefer_extension_decoders [Boolean] 扩展解码器是否优先于平台解码器。

当使用 adb shell am start 触发 intent 时,可以使用 --es 设置一个可选的字符串额外数据(例如,--es extension mpd)。可以使用 --ez 设置一个可选的布尔额外数据(例如,--ez prefer_extension_decoders TRUE)。可以使用 --el 设置一个可选的长整型额外数据(例如,--el clip_start_position_ms 5000)。可以使用 --esa 设置一个可选的字符串数组额外数据(例如,--esa drm_key_request_properties name1,value1)。

要播放示例播放列表,请将 intent 的操作设置为 androidx.media3.demo.main.action.VIEW_LIST。示例配置额外数据与 androidx.media3.demo.main.action.VIEW 相同,但有两个不同之处

  • 额外数据的键应包含下划线和示例的 0-based 索引作为后缀。例如,extension_0 将提示第一个示例的样本类型。drm_scheme_1 将设置第二个示例的 DRM 方案。
  • 示例的 URI 作为额外数据传递,键为 uri_<sample-index>

其他与示例无关的额外数据不会改变。例如,您可以在终端中运行以下命令来播放包含两个项目的播放列表,并覆盖第二个项目的扩展名

adb shell am start -a androidx.media3.demo.main.action.VIEW_LIST \
    --es uri_0 https://a.com/sample1.mp4 \
    --es uri_1 https://b.com/sample2.fake_mpd \
    --es extension_1 mpd