探索 ExoPlayer 音视频播放技术(4):媒体项

这个系列文章我们来介绍一位海外工程师如何探索 ExoPlayer 音视频播放技术,对于想要开始学习音视频技术的朋友,这些文章是份不错的入门资料,这是第 4 篇:ExoPlayer 媒体项。

—— 来自公众号关键帧Keyframe的分享

1、媒体项 API

播放列表 API 基于 MediaItem 实例,这些实例可以方便地通过 MediaItem.Builder 构建。在播放器内部,MediaItem 通过 MediaSource.Factory 转换为可播放的 MediaSource。在没有自定义配置的情况下,此转换由 DefaultMediaSourceFactory 执行,它能够根据媒体项的属性构建复杂的媒体源。下面概述了可以在媒体项上设置的一些属性。

仅包含流 URI 的媒体项可以使用 fromUri 快捷方法构建:

val mediaItem = MediaItem.fromUri(videoUri)
MediaItem mediaItem = MediaItem.fromUri(videoUri);

对于所有其他情况,可以使用 MediaItem.Builder。在以下示例中,使用 ID 和一些附加元数据构建了一个媒体项:

val mediaItem = MediaItem.Builder().setMediaId(mediaId).setTag(myAppData).setUri(videoUri).build()
MediaItem mediaItem =
    new MediaItem.Builder().setMediaId(mediaId).setTag(myAppData).setUri(videoUri).build();

附加元数据对于在播放列表过渡时更新应用的 UI 非常有用。

2、图像

图像的播放需要在媒体项中指定持续时间,以确定图像在播放过程中应显示的时间。有关 Motion Photos 和图像加载库(例如 Glide)的更多信息,请参阅图像指南页面。

val mediaItem = MediaItem.Builder().setUri(imageUri).setImageDurationMs(3000).build()
MediaItem mediaItem =
    new MediaItem.Builder().setUri(imageUri).setImageDurationMs(3_000).build();

3、自适应媒体的非标准文件扩展名

ExoPlayer 为 DASH、HLS 和 SmoothStreaming 提供了自适应媒体源。如果此类自适应媒体项的 URI 以标准文件扩展名结尾,则会自动创建相应的媒体源。如果 URI 具有非标准扩展名或根本没有扩展名,则可以明确设置 MIME 类型以指示媒体项的类型:

val mediaItem = MediaItem.Builder().setUri(hlsUri).setMimeType(MimeTypes.APPLICATION_M3U8).build()
MediaItem mediaItem =
    new MediaItem.Builder().setUri(hlsUri).setMimeType(MimeTypes.APPLICATION_M3U8).build();

对于渐进式媒体流,不需要设置 MIME 类型。

4、受保护的内容

对于受保护的内容,应设置媒体项的 DRM 属性。UUID 是必需的,其他属性是可选的。

以下是一个配置示例,用于播放受 Widevine DRM 保护的项目,其中许可证 URI 不直接在媒体中可用(例如在 DASH 播放列表中),并且需要多个会话(例如由于密钥轮换):

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setDrmConfiguration(
      MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
        .setLicenseUri(licenseUri)
        .setMultiSession(true)
        .setLicenseRequestHeaders(httpRequestHeaders)
        .build()
    )
    .build()
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setDrmConfiguration(
            new MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
                .setLicenseUri(licenseUri)
                .setMultiSession(true)
                .setLicenseRequestHeaders(httpRequestHeaders)
                .build())
        .build();

在播放器内部,DefaultMediaSourceFactory 将这些属性传递给 DrmSessionManagerProvider 以获取 DrmSessionManager,然后将其注入到创建的 MediaSource 中。DRM 行为可以根据需要进一步自定义。

5、旁加载字幕轨道

要旁加载字幕轨道,可以在构建媒体项时添加 MediaItem.Subtitle 实例:

val subtitle =
  SubtitleConfiguration.Builder(subtitleUri)
    .setMimeType(mimeType) // 正确的 MIME 类型(必需)。
    .setLanguage(language) // 字幕语言(可选)。
    .setSelectionFlags(selectionFlags) // 轨道的选择标志(可选)。
    .build()
val mediaItem =
  MediaItem.Builder().setUri(videoUri).setSubtitleConfigurations(listOf(subtitle)).build()
MediaItem.SubtitleConfiguration subtitle =
    new MediaItem.SubtitleConfiguration.Builder(subtitleUri)
        .setMimeType(mimeType) // 正确的 MIME 类型(必需)。
        .setLanguage(language) // 字幕语言(可选)。
        .setSelectionFlags(selectionFlags) // 轨道的选择标志(可选)。
        .build();
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setSubtitleConfigurations(ImmutableList.of(subtitle))
        .build();

在内部,DefaultMediaSourceFactory 将使用 MergingMediaSource 将内容媒体源与每个字幕轨道的 SingleSampleMediaSource 合并。DefaultMediaSourceFactory 不支持为多周期 DASH 旁加载字幕。

要剪辑媒体项所引用的内容,可以设置自定义的开始和结束位置:

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setClippingConfiguration(
      MediaItem.ClippingConfiguration.Builder()
        .setStartPositionMs(startPositionMs)
        .setEndPositionMs(endPositionMs)
        .build()
    )
    .build()
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setClippingConfiguration(
            new ClippingConfiguration.Builder()
                .setStartPositionMs(startPositionMs)
                .setEndPositionMs(endPositionMs)
                .build())
        .build();

在内部,DefaultMediaSourceFactory 将使用 ClippingMediaSource 包装内容媒体源。还有其他剪辑属性。更多详细信息,请参阅 MediaItem.Builder 的 Javadoc。

6、广告插入

要插入广告,需要设置媒体项的广告标签 URI 属性:

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build())
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setAdsConfiguration(new MediaItem.AdsConfiguration.Builder(adTagUri).build())
        .build();

在内部,DefaultMediaSourceFactory 将把内容媒体源包装在 AdsMediaSource 中,以根据广告标签插入广告。要使此功能正常工作,播放器还需要相应地配置其 DefaultMediaSourceFactory

音视频方向学习、求职,欢迎加入我们的星球

丰富的音视频知识、面试题、技术方案干货分享,还可以进行面试辅导

探索 ExoPlayer 音视频播放技术(3):播放列表

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论