ExoPlayer架构详解与源码分析(17)——TrackSelector

系列文章目录

ExoPlayer架构详解与源码分析(1)——前言
ExoPlayer架构详解与源码分析(2)——Player
ExoPlayer架构详解与源码分析(3)——Timeline
ExoPlayer架构详解与源码分析(4)——整体架构
ExoPlayer架构详解与源码分析(5)——MediaSource
ExoPlayer架构详解与源码分析(6)——MediaPeriod
ExoPlayer架构详解与源码分析(7)——SampleQueue
ExoPlayer架构详解与源码分析(8)——Loader
ExoPlayer架构详解与源码分析(9)——TsExtractor
ExoPlayer架构详解与源码分析(10)——H264Reader
ExoPlayer架构详解与源码分析(11)——DataSource
ExoPlayer架构详解与源码分析(12)——Cache
ExoPlayer架构详解与源码分析(13)——TeeDataSource和CacheDataSource
ExoPlayer架构详解与源码分析(14)——ProgressiveMediaPeriod
ExoPlayer架构详解与源码分析(15)——Renderer
ExoPlayer架构详解与源码分析(16)——LoadControl
ExoPlayer架构详解与源码分析(17)——TrackSelector



前言

好了四大组件就剩TrackSelector没讲了。这里回顾下系列开头的构架图。

在这里插入图片描述

TrackSelector负责选择每个播放器渲染器要使用的轨道。

与播放器交互

在播放期间,播放器与TrackSelector之间会发生以下交互:

  • 创建播放器时,它将通过调用 init 来初始化 TrackSelector。
  • 当播放器需要进行轨道选择时,它将调用 selectTracks。通常发生在播放开始的时候。
  • 播放器需要在 Renderer 渲染数据前选择好轨道。例如播放器在缓存数据时,当MediaPeriod preare完成时就会选择轨道。播放器通过调用 onSelectionActivated 告诉TrackSelector当前变为Activated状态。
  • 如果TrackSelector希望向播放器指出以前做出的选择是无效的,TrackSelector 可以通过调用onTrackSelectionsInvalidated。这个监听是在播放器调用 TrackSelector.init 时注册给 TrackSelector 的。如果轨道选择器的配置已更改,则调用intrackSelectionsInvaliDated通知,例如,如果现在希望使用特定语言的音轨。这将触发播放器进行新的轨道选择。请注意,如果当前播放期的新选择的规定与之前轨道选择不同,则播放前将重新缓冲。
  • 当播放器被释放时,它会通过调用release来释放曲目选择器。

渲染器配置

selectTracks 返回的 TrackSelectorResult 不仅包含每个渲染器的 TrackSelections,还包含定义Renderer在使用相应媒体时应应用的配置参数的 RendererConfigurations。TrackSelector指定 Renderer 配置信息似乎不符合常识,但实际上两者紧密结合在一起。如果以特定方式配置Renderer,则可能只能播放某些组合轨道。同样,如果选择了某些轨道,则可能只能以特定方式配置渲染器。因此,需要同步确定轨道选择和相应的 Renderer 配置。

线程模型

播放器对TrackSelector进行的所有调用都在播放器的内部播放线程上进行。TrackSelector可能从任何线程回调 onTrackSelectionsInvalidated,线程模型参考ExoPlayer架构详解与源码分析(4)——整体架构

MappingTrackSelector

MappingTrackSelector首先在TrackGroup和Renderer之间建立映射,然后根据该映射为每个渲染器创建ExoTrackSelection 。

  @Override
  //播放器调用执行轨道选择
  public final TrackSelectorResult selectTracks(
      RendererCapabilities[] rendererCapabilities,//包含了所有Renderer的信息,播放器初始化时会获取,RendererCapabilities定义了Renderer 的功能相关信息
      TrackGroupArray trackGroups,//MediaPeriod prepared 后,播放器通过getTrackGroups从中获取的所有轨道信息
      MediaPeriodId periodId,//关联当前的MediaPeriod
      Timeline timeline)//当前的Timeline
      throws ExoPlaybackException {
   
    //选择期间被写入的数据结构,最后一位用来记录可以与任何renderer关联的轨道相关数据
    int[] rendererTrackGroupCounts = new int[rendererCapabilities.length + 1];
    TrackGroup[][] rendererTrackGroups = new TrackGroup[rendererCapabilities.length + 1][];
    @Capabilities int[][][] rendererFormatSupports = new int[rendererCapabilities.length + 1][][];
    for (int i = 0; i < rendererTrackGroups.length; i++) {
   
      rendererTrackGroups[i] = new TrackGroup[trackGroups.length];
      rendererFormatSupports[i] = new int[trackGroups.length][];
    }

    //确定每个renderer 能适应混合 mimeType,默认的MediaCodec能适应但是可能会出现短暂的不连续性返回8,字幕和其他渲染器一般不支持返回0
    @AdaptiveSupport
    int[] rendererMixedMimeTypeAdaptationSupports =
        getMixedMimeTypeAdaptationSupports(rendererCapabilities);

    for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
   
      TrackGroup group = trackGroups.get(groupIndex);
      // 为每个轨道 查找一个合适的renderer
      boolean preferUnassociatedRenderer = group.type == C.TRACK_TYPE_METADATA;
      int rendererIndex =
          findRenderer(
              rendererCapabilities, group, rendererTrackGroupCounts, preferUnassociatedRenderer);
      // 确定查找出的Renderer是否支持当前轨道 格式
      @Capabilities
      int[] rendererFormatSupport =
          rendererIndex == rendererCapabilities.length
              ? new int[group.length]
              : getFormatSupport(rendererCapabilities[rendererIndex], group);
      // 保存结果
      int rendererTrackGroupCount = rendererTrackGroupCounts[rendererIndex];
      rendererTrackGroups[rendererIndex][rendererTrackGroupCount] = group;
      rendererFormatSupports[rendererIndex][rendererTrackGroupCount] = rendererFormatSupport;
      rendererTrackGroupCounts[rendererIndex]++;
    }

    // 为每个renderer创建一个TrackGroupArray
    TrackGroupArray[] rendererTrackGroupArrays = new TrackGroupArray[rendererCapabilities.length];
    String[] rendererNames = new String[rendererCapabilities.length];
    int[] rendererTrackTypes = new int[rendererCapabilities.length];
    for (int i = 0; i < rendererCapabilities.length; i++) {
   
      int rendererTrackGroupCount = rendererTrackGroupCounts[i];
      rendererTrackGroupArrays[i] =
          new TrackGroupArray(
              Util.nullSafeArrayCopy(rendererTrackGroups[i], rendererTrackGroupCount));
      rendererFormatSupports[i] =
          Util.nullSafeArrayCopy(rendererFormatSupports[i], rendererTrackGroupCount);
      rendererNames[i] = rendererCapabilities[i].getName();
      rendererTrackTypes[i] = rendererCapabilities[i].getTrackType();
    }

    // Create a track group array for track groups not mapped to a renderer.
    int unmappedTrackGroupCount = rendererTrackGroupCounts[rendererCapabilities.length];
    TrackGroupArray unmappedTrackGroupArray =
        new TrackGroupArray(
            Util.nullSafeArrayCopy(
                rendererTrackGroups[rendererCapabilities.length], unmappedTrackGroupCount));

    // 构建出mappedTrackInfo 
    MappedTrackInfo mappedTrackInfo =
        new MappedTrackInfo(
            rendererNames,
            rendererTrackTypes,
            rendererTrackGroupArrays,
            rendererMixedMimeTypeAdaptationSupports,
            rendererFormatSupports,
            unmappedTrackGroupArray);

    Pair<@NullableType RendererConfiguration[], @NullableType ExoTrackSelection[]> result =
        selectTracks(//调用子类选择轨道
            mappedTrackInfo,
            rendererFormatSupports,
            rendererMixedMimeTypeAdaptationSupports,
            periodId,
            timeline);
    //最终获取Tracks 
    
  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值