探索 ExoPlayer 音视频播放技术(10):直播流

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

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

ExoPlayer 在无需特殊配置的情况下,能够开箱即用地播放大多数自适应直播流。如需了解更多详情,请参阅支持格式页面。

自适应直播流提供了一个定期更新的可用媒体窗口,以跟随当前实时时间移动。这意味着播放位置将始终位于此窗口内,通常靠近流被生成的实时时间。当前实时时间与播放位置之间的差异称为直播偏移。

1、检测和监控直播播放

每当直播窗口更新时,注册的 Player.Listener 实例将收到 onTimelineChanged 事件。您可以通过查询 Player 和 Timeline.Window 的各种方法来获取当前直播播放的详细信息,如下图所示。

探索 ExoPlayer 音视频播放技术(10):直播流
  • Player.isCurrentWindowLive 表示当前播放的媒体项是否为直播流。即使直播流已结束,此值仍为 true。
  • Player.isCurrentWindowDynamic 表示当前播放的媒体项是否仍在更新。对于尚未结束的直播流,此值通常为 true。请注意,对于某些非直播流,此标志也可能为 true。
  • Player.getCurrentLiveOffset 返回当前实时时间与播放位置之间的偏移量(如果可用)。
  • Player.getDuration 返回当前直播窗口的时长。
  • Player.getCurrentPosition 返回相对于直播窗口起始位置的播放位置。
  • Player.getCurrentMediaItem 返回当前媒体项,其中 MediaItem.liveConfiguration 包含应用提供的目标直播偏移和直播偏移调整参数。
  • Player.getCurrentTimeline 返回当前媒体结构的 Timeline。可以通过 Player.getCurrentMediaItemIndex 和 Timeline.getWindow 从 Timeline 中检索当前 Timeline.Window。在 Window 中:
    • Window.liveConfiguration 包含目标直播偏移和直播偏移调整参数。这些值基于媒体中的信息以及在 MediaItem.liveConfiguration 中设置的任何应用提供的覆盖值。
    • Window.windowStartTimeMs 是直播窗口开始时间自 Unix 纪元以来的时间。
    • Window.getCurrentUnixTimeMs 是当前实时时间自 Unix 纪元以来的时间。此值可能会根据服务器和客户端之间已知的时钟差异进行修正。
    • Window.getDefaultPositionMs 是播放器默认开始播放的直播窗口中的位置。

2、在直播流中寻址

可以使用 Player.seekTo 在直播窗口内任意位置进行寻址。传递的寻址位置相对于直播窗口的起始位置。例如,seekTo(0) 将寻址到直播窗口的起始位置。寻址后,播放器将尝试保持与寻址到的位置相同的直播偏移。

直播窗口还有一个默认位置,播放从此位置开始。此位置通常靠近直播边缘。可以通过调用 Player.seekToDefaultPosition 寻址到默认位置。

3、直播播放 UI

ExoPlayer 的默认 UI 组件显示直播窗口的时长以及当前播放位置在窗口内的位置。这意味着每次直播窗口更新时,位置将向后跳跃。如果需要不同的行为,例如显示 Unix 时间或当前直播偏移,可以 fork PlayerControlView 并根据需要进行修改。

4、配置直播播放参数

ExoPlayer 使用一些参数来控制播放位置与直播边缘的偏移,以及可用于调整此偏移的播放速度范围。

ExoPlayer 从以下三个地方获取这些参数的值,优先级从高到低(找到的第一个值将被使用):

  • 通过 MediaItem.Builder.setLiveConfiguration 传递的每个 MediaItem 的值。
  • 在 DefaultMediaSourceFactory 上设置的全局默认值。
  • 直接从媒体中读取的值。
// 全局设置。
val player =
  ExoPlayer.Builder(context)
    .setMediaSourceFactory(DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
    .build()

// 每个 MediaItem 的设置。
val mediaItem =
  MediaItem.Builder()
    .setUri(mediaUri)
    .setLiveConfiguration(
      MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build()
    )
    .build()
player.setMediaItem(mediaItem)
// 全局设置。
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setMediaSourceFactory(
            new DefaultMediaSourceFactory(context).setLiveTargetOffsetMs(5000))
        .build();

// 每个 MediaItem 的设置。
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(mediaUri)
        .setLiveConfiguration(
            new MediaItem.LiveConfiguration.Builder().setMaxPlaybackSpeed(1.02f).build())
        .build();
player.setMediaItem(mediaItem);

可用的配置值包括:

  • targetOffsetMs:目标直播偏移。如果可能,播放器将尝试在播放过程中接近此直播偏移。
  • minOffsetMs:允许的最小直播偏移。即使在根据当前网络条件调整偏移时,播放器也不会尝试在播放过程中低于此偏移。
  • maxOffsetMs:允许的最大直播偏移。即使在根据当前网络条件调整偏移时,播放器也不会尝试在播放过程中超过此偏移。
  • minPlaybackSpeed:播放器可用于回退以达到目标直播偏移的最小播放速度。
  • maxPlaybackSpeed:播放器可用于赶上目标直播偏移的最大播放速度。

5、播放速度调整

在播放低延迟直播流时,ExoPlayer 通过轻微改变播放速度来调整直播偏移。播放器将尝试匹配媒体或应用提供的目标直播偏移,但也会对不断变化的网络条件做出反应。例如,如果在播放过程中出现重新缓冲,播放器将稍微降低播放速度,以远离直播边缘。如果网络随后变得足够稳定,可以再次支持靠近直播边缘播放,播放器将加快播放速度,以回到目标直播偏移。

如果不需要自动播放速度调整,可以通过将 minPlaybackSpeed 和 maxPlaybackSpeed 属性设置为 1.0f 来禁用。同样,对于非低延迟直播流,可以通过将这些属性显式设置为非 1.0f 的值来启用。有关如何设置这些属性的更多详细信息,请参阅上面的配置部分。

自定义播放速度调整算法

如果启用了速度调整,LivePlaybackSpeedControl 将定义进行哪些调整。可以实现自定义 LivePlaybackSpeedControl,或者自定义默认实现 DefaultLivePlaybackSpeedControl。在这两种情况下,可以在构建播放器时设置实例。

val player =
  ExoPlayer.Builder(context)
    .setLivePlaybackSpeedControl(
      DefaultLivePlaybackSpeedControl.Builder().setFallbackMaxPlaybackSpeed(1.04f).build()
    )
    .build()
ExoPlayer player =
    new ExoPlayer.Builder(context)
        .setLivePlaybackSpeedControl(
            new DefaultLivePlaybackSpeedControl.Builder()
                .setFallbackMaxPlaybackSpeed(1.04f)
                .build())
        .build();

DefaultLivePlaybackSpeedControl 的相关自定义参数包括:

  • fallbackMinPlaybackSpeed 和 fallbackMaxPlaybackSpeed:如果媒体和应用提供的 MediaItem 均未定义限制,则可用于调整的最小和最大播放速度。
  • proportionalControlFactor:控制速度调整的平滑程度。较高值使调整更突然、更反应迅速,但也更可能被察觉。较低值则使速度之间的过渡更平滑,但调整速度较慢。
  • targetLiveOffsetIncrementOnRebufferMs:每次发生重新缓冲时,此值将被加到目标直播偏移上,以便更谨慎地进行调整。通过将此值设置为 0 可以禁用此功能。
  • minPossibleLiveOffsetSmoothingFactor:用于根据当前缓冲的媒体跟踪最小可能直播偏移的指数平滑因子。非常接近 1 的值意味着估计更谨慎,可能需要更长时间才能适应改善的网络条件,而较低值则意味着估计将更快调整,但存在更高遇到重新缓冲的风险。

6、BehindLiveWindowException 和 ERROR_CODE_BEHIND_LIVE_WINDOW

如果播放位置落后于直播窗口,例如播放器暂停或缓冲的时间足够长,就会发生这种情况。如果发生,播放将失败,并通过 Player.Listener.onPlayerError 报告一个错误代码为 ERROR_CODE_BEHIND_LIVE_WINDOW 的异常。应用程序代码可能希望处理此类错误,通过在默认位置恢复播放。示例应用的 PlayerActivity 就采用了这种方法。

override fun onPlayerError(error: PlaybackException) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // 在直播边缘重新初始化播放器。
    player.seekToDefaultPosition()
    player.prepare()
  } else {
    // 处理其他错误
  }
}
@Override
public void onPlayerError(PlaybackException error) {
  if (error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW) {
    // 在直播边缘重新初始化播放器。
    player.seekToDefaultPosition();
    player.prepare();
  } else {
    // 处理其他错误
  }
}

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

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

探索 ExoPlayer 音视频播放技术(10):直播流

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

(0)

相关推荐

发表回复

登录后才能评论