ExoPlayer详解系列文章

一、DASH

ExoPlayer支持多种容器格式的DASH。必须对媒体流进行解复用,这意味着必须在DASH清单中的不同AdaptationSet元素中定义视频,音频和文本(CEA-608是一个例外,如下表所述)。还必须支持包含的音频和视频样本格式(有关详细信息,请参阅 示例格式部分)。

特征支持评论
集装箱
FMP4仅拆分流
WebM仅拆分流
Matroska仅拆分流
MPEG-TS没有支持计划
隐藏式字幕/字幕
TTML根据ISO / IEC 14496-30原始或嵌入FMP4中
WebVTT根据ISO / IEC 14496-30原始或嵌入FMP4中
CEA-608携带在FMP4视频流中嵌入的SEI消息
元数据
EMSG元数据嵌入在FMP4中
内容保护
WidevineAPI 19+(“cenc”方案)和25+(“cbcs”,“cbc1”和“cens”方案)
PlayReady SL2000仅限Android TV
ClearKeyAPI 21+

1、创建MediaSource

要播放DASH流,请DashMediaSource像往常一样创建并准备播放器。

	// Create a data source factory.
	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a DASH media source pointing to a DASH manifest uri.
	MediaSource mediaSource = new DashMediaSource.Factory(dataSourceFactory)
	    .createMediaSource(dashUri);
	// Create a player instance.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the DASH media source.
	player.prepare(mediaSource);

ExoPlayer将自动调整清单中定义的表示,同时考虑可用带宽和设备功能。

2、访问清单

您可以通过调用Player.getCurrentManifest来检索当前清单。对于DASH,您应该将返回的对象强制转换为DashManifest。该onTimelineChanged回调Player.EventListener也被称为清单加载。对于点播内容,这将发生一次,对于直播内容可能会发生多次。下面的代码片段显示了应用程序在加载清单时如何执行操作。

	player.addListener(
	    new Player.EventListener() {
	      @Override
	      public void onTimelineChanged(
	          Timeline timeline,
	          @Nullable Object manifest,
	          @Player.TimelineChangeReason int reason) {
	        if (manifest != null) {
	          DashManifest dashManifest = (DashManifest) manifest;
	          // Do something with the manifest.
	        }
	      }
	    });

3、侧载清单

对于特定用例,有一种替代方法可以通过将DashManifest对象传递给构造函数来提供清单。

	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a dash media source with a dash manifest.
	MediaSource mediaSource = new DashMediaSource.Factory(dataSourceFactory)
	    .createMediaSource(dashManifest);
	// Create a player instance which gets an adaptive track selector by default.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the dash media source.
	player.prepare(mediaSource);

4、自定义DASH播放

ExoPlayer提供多种方式让您根据应用的需求定制播放体验。以下部分简要介绍了构建DashMediaSource时可用的一些自定义选项。有关更多常规自定义选项,请参阅“ 自定义”页面

(1)、自定义服务器交互

某些应用可能希望拦截HTTP请求和响应。您可能希望注入自定义请求标头,读取服务器的响应标头,修改请求的URI等。例如,您的应用程序可以通过在请求媒体段时将标记作为标头注入来验证自身。您可以通过将自定义HttpDataSources注入到你创建的DashMediaSource中来实现这些行为。以下代码段显示了标头注入的示例:

	DashMediaSource dashMediaSource =
	    new DashMediaSource.Factory(
	            () -> {
	              HttpDataSource dataSource = new DefaultHttpDataSource(userAgent);
	              // Set a custom authentication request header.
	              dataSource.setRequestProperty("Header", "Value");
	              return dataSource;
	            })
	        .createMediaSource(dashUri);

(2)、自定义错误处理

实现自定义LoadErrorHandlingPolicy允许应用程序自定义ExoPlayer对加载错误的反应方式。例如,应用程序可能希望快速失败而不是多次重试,或者可能想要自定义控制player在每次重试之间等待多长时间的退避逻辑。以下代码段显示了在创建DashMediaSource以下内容时如何实现自定义退避逻辑:

	DashMediaSource dashMediaSource =
	    new DashMediaSource.Factory(dataSourceFactory)
	        .setLoadErrorHandlingPolicy(
	            new DefaultLoadErrorHandlingPolicy() {
	              @Override
	              public long getRetryDelayMsFor(...) {
	                // Implement custom back-off logic here.
	              }
	            })
	        .createMediaSource(dashUri);

您可以在我们的媒体帖子中找到有关错误处理的更多信息。

5、BehindLiveWindowException

在播放具有有限可用性的直播流的情况下,如果播放器暂停或缓冲足够长的时间段,则播放器可能落后于该实况窗口。在这种情况下,抛出一个BehindLiveWindowException,可以捕获它并在现场边缘恢复player。演示应用程序的PlayerActivity举例说明了这种方法。

	@Override
	public void onPlayerError(ExoPlaybackException e) {
	  if (isBehindLiveWindow(e)) {
	    // Re-initialize player at the live edge.
	  } else {
	    // Handle other errors
	  }
	}
	
	private static boolean isBehindLiveWindow(ExoPlaybackException e) {
	  if (e.type != ExoPlaybackException.TYPE_SOURCE) {
	    return false;
	  }
	  Throwable cause = e.getSourceException();
	  while (cause != null) {
	    if (cause instanceof BehindLiveWindowException) {
	      return true;
	    }
	    cause = cause.getCause();
	  }
	  return false;
	}


二、HLS

ExoPlayer支持多种容器格式的HLS。还必须支持包含的音频和视频样本格式(有关详细信息,请参阅 示例格式部分)。我们强烈鼓励HLS内容制作产生高品质的HLS流,描述 在这里。

特征支持评论
集装箱
MPEG-TS
FMP4 / CMAF
ADTS(AAC)
MP3
隐藏式字幕/字幕
CEA-608
WebVTT
元数据
ID3元数据
内容保护
AES-128
样品AES-128没有
WidevineAPI 19+(“cenc”方案)和25+(“cbcs”方案)
PlayReady SL2000仅限Android TV

1、创建MediaSource

要播放HLS流,请像往常一样创建HlsMediaSource并准备播放器。

	// Create a data source factory.
	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a HLS media source pointing to a playlist uri.
	HlsMediaSource hlsMediaSource =
	    new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
	// Create a player instance.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the HLS media source.
	player.prepare(hlsMediaSource);

URI传递给HlsMediaSource.Factory.createMediaSource()可以指向媒体播放列表或主播放列表。如果URI指向声明多个#EXT-X-STREAM-INF标签的主播放列表,则ExoPlayer将自动调整变体,同时考虑可用带宽和设备功能。

2、自定义HLS播放

ExoPlayer提供多种方式让您根据应用的需求定制播放体验。以下部分简要介绍了构建HlsMediaSource时可用的一些自定义选项。有关更多常规自定义选项,请参阅“自定义”页面

(1)、启用更快的启动时间

通过启用无块准备,您可以显着提高HLS启动时间。当您启用无块准备并且#EXT-X-STREAM-INF标签包含该 CODECS属性时,ExoPlayer将避免在准备过程中下载媒体段。以下代码段显示了如何启用无块准备:

	HlsMediaSource hlsMediaSource =
	    new HlsMediaSource.Factory(dataSourceFactory)
	        .setAllowChunklessPreparation(true)
	        .createMediaSource(hlsUri);

您可以在我们的关于无框准备的媒体帖子中找到更多详细信息。

(2)、自定义服务器交互

某些应用可能希望拦截HTTP请求和响应。您可能希望注入自定义请求标头,读取服务器的响应标头,修改请求的URI等。例如,您的应用程序可以通过在访问媒体段的URI中注入自定义标记来验证自身。您可以通过将自定义HttpDataSources注入到创建的HlsMediaSource中来实现这些行为。以下代码段显示了请求标头注入的示例:

	HlsMediaSource hlsMediaSource =
	    new HlsMediaSource.Factory(
	            dataType -> {
	              HttpDataSource dataSource =
	                  new DefaultHttpDataSource(userAgent);
	              if (dataType == C.DATA_TYPE_MEDIA) {
	                // The data source will be used for fetching media segments. We
	                // set a custom authentication request header.
	                dataSource.setRequestProperty("Header", "Value");
	              }
	              return dataSource;
	            })
	        .createMediaSource(hlsUri);

(3)、自定义错误处理

实现自定义LoadErrorHandlingPolicy允许应用程序自定义ExoPlayer对加载错误的反应方式。例如,应用程序可能希望快速失败而不是多次重试,或者可能想要自定义控制player在每次重试之间等待多长时间的退避逻辑。以下代码段显示了在创建以下HlsMediaSource内容时如何实现自定义退避逻辑:

	HlsMediaSource hlsMediaSource =
	    new HlsMediaSource.Factory(dataSourceFactory)
	        .setLoadErrorHandlingPolicy(
	            new DefaultLoadErrorHandlingPolicy() {
	              @Override
	              public long getRetryDelayMsFor(...) {
	                // Implement custom back-off logic here.
	              }
	            })
	        .createMediaSource(hlsUri);

您可以在我们的媒体帖子中找到有关错误处理的更多信息

3、创建高质量的HLS内容

为了充分利用ExoPlayer,您可以遵循某些指导原则来改进您的HLS内容。阅读我们在ExoPlayer中关于HLS播放的媒体帖子,以获得完整的解释。要点是:

  • 使用精确的段持续时间。
  • 使用连续媒体流; 避免跨段的媒体结构的变化。
  • 使用#EXT-X-INDEPENDENT-SEGMENTS标签。
  • 更喜欢分离的流,而不是包含视频和音频的文件。
  • 包括主播放列表中的所有信息。

以下指南专门适用于直播流:

  • 使用#EXT-X-PROGRAM-DATE-TIME标签。
  • 使用#EXT-X-DISCONTINUITY-SEQUENCE标签。
  • 提供一个长时间存在的窗口。一分钟或时间越长越好。

4、BehindLiveWindowException

在播放具有有限可用性的直播流的情况下,如果播放器暂停或缓冲足够长的时间段,则播放器可能落后于该实况窗口。在这种情况下,抛出一个BehindLiveWindowException,可以捕获它并在现场边缘恢复player。演示应用程序的PlayerActivity举例说明了这种方法。

	@Override
	public void onPlayerError(ExoPlaybackException e) {
	  if (isBehindLiveWindow(e)) {
	    // Re-initialize player at the live edge.
	  } else {
	    // Handle other errors
	  }
	}
	
	private static boolean isBehindLiveWindow(ExoPlaybackException e) {
	  if (e.type != ExoPlaybackException.TYPE_SOURCE) {
	    return false;
	  }
	  Throwable cause = e.getSourceException();
	  while (cause != null) {
	    if (cause instanceof BehindLiveWindowException) {
	      return true;
	    }
	    cause = cause.getCause();
	  }
	  return false;
	}


三、Smoothtreaming

ExoPlayer支持使用FMP4容器格式的SmoothStreaming。必须对媒体流进行解复用,这意味着必须在SmoothStreaming清单中的不同StreamIndex元素中定义视频,音频和文本。还必须支持包含的音频和视频样本格式(有关详细信息,请参阅 示例格式部分)。

特征支持评论
集装箱
FMP4仅拆分流
隐藏式字幕/字幕
TTML嵌入在FMP4中
内容保护
PlayReady SL2000仅限Android TV

1、创建媒体源

要播放SmoothStreaming流,请像往常一样使用它创建SsMediaSource并准备播放器。

	// Create a data source factory.
	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a SmoothStreaming media source pointing to a manifest uri.
	MediaSource mediaSource =
	    new SsMediaSource.Factory(dataSourceFactory).createMediaSource(ssUri);
	// Create a player instance.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the SmoothStreaming media source.
	player.prepare(mediaSource);

ExoPlayer将自动调整清单中定义的流,同时考虑可用带宽和设备功能。

2、访问清单

您可以通过调用来检索当前清单Player.getCurrentManifest。对于SmoothStreaming,您应该将返回的对象强制转换为SsManifest。该 onTimelineChanged回调Player.EventListener每当清单加载也被称为。对于点播内容,这将发生一次,对于直播内容可能会发生多次。下面的代码片段显示了应用程序在加载清单时如何执行操作。

	player.addListener(
	    new Player.EventListener() {
	      @Override
	      public void onTimelineChanged(
	          Timeline timeline,
	          @Nullable Object manifest,
	          @Player.TimelineChangeReason int reason) {
	        if (manifest != null) {
	          SsManifest ssManifest = (SsManifest) manifest;
	          // Do something with the manifest.
	        }
	      }
	    });

3、侧载清单

对于特定用例,有一种替代方法可以通过将SsManifest对象传递给构造函数来提供清单。

	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a smooth streaming media source with a smooth streaming  manifest.
	MediaSource mediaSource =
	    new SsMediaSource.Factory(dataSourceFactory).createMediaSource(ssManifest);
	// Create a player instance which gets an adaptive track selector by default.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the media source.
	player.prepare(mediaSource);

4、自定义SmoothStreaming回放

ExoPlayer提供多种方式让您根据应用的需求定制播放体验。以下部分简要介绍了构建SsMediaSource时可用的一些自定义选项。有关更多常规自定义选项,请参阅“ 自定义”页面

(1)、自定义服务器交互

某些应用可能希望拦截HTTP请求和响应。您可能希望注入自定义请求标头,读取服务器的响应标头,修改请求的URI等。例如,您的应用程序可以通过在访问媒体段的URI中注入自定义标记来验证自身。您可以通过将自定义HttpDataSources注入到创建的SsMediaSource中来实现这些行为。以下代码段显示了请求标头注入的示例:

SsMediaSource ssMediaSource =
    new SsMediaSource.Factory(
            () -> {
              HttpDataSource dataSource = new DefaultHttpDataSource(userAgent);
              // Set a custom authentication request header.
              dataSource.setRequestProperty("Header", "Value");
              return dataSource;
            })
        .createMediaSource(ssUri);

(1)、自定义错误处理

实现自定义LoadErrorHandlingPolicy允许应用程序自定义ExoPlayer对加载错误的反应方式。例如,应用程序可能希望快速失败而不是多次重试,或者可能想要自定义控制player在每次重试之间等待多长时间的退避逻辑。以下代码段显示了在创建以下SsMediaSource内容时如何实现自定义退避逻辑:

	SsMediaSource ssMediaSource =
	    new SsMediaSource.Factory(dataSourceFactory)
	        .setLoadErrorHandlingPolicy(
	            new DefaultLoadErrorHandlingPolicy() {
	              @Override
	              public long getRetryDelayMsFor(...) {
	                // Implement custom back-off logic here.
	              }
	            })
	        .createMediaSource(ssUri);

您可以在我们的媒体帖子中找到有关错误处理的更多信息。

5、BehindLiveWindowException

在播放具有有限可用性的直播流的情况下,如果播放器暂停或缓冲足够长的时间段,则播放器可能落后于该实况窗口。在这种情况下,抛出一个BehindLiveWindowException,可以捕获它并在现场边缘恢复player。演示应用程序的PlayerActivity举例说明了这种方法。

@Override
public void onPlayerError(ExoPlaybackException e) {
  if (isBehindLiveWindow(e)) {
    // Re-initialize player at the live edge.
  } else {
    // Handle other errors
  }
}

private static boolean isBehindLiveWindow(ExoPlaybackException e) {
  if (e.type != ExoPlaybackException.TYPE_SOURCE) {
    return false;
  }
  Throwable cause = e.getSourceException();
  while (cause != null) {
    if (cause instanceof BehindLiveWindowException) {
      return true;
    }
    cause = cause.getCause();
  }
  return false;


四、Progressive

以下容器格式的流可以由ExoPlayer直接播放。还必须支持包含的音频和视频样本格式(有关详细信息,请参阅 示例格式部分)。

容器格式支持评论
MP4
M4A
FMP4
WebM
Matroska
MP3有些流只能使用恒定比特率寻求**
Ogg包含Vorbis,Opus和Flac
WAV
MPEG-TS
MPEG-PS
FLV不可寻求*
ADTS(AAC)只能使用恒定比特率寻求**
Flac仅使用Flac扩展名
AMR只能使用恒定比特率寻求**

*寻求不受支持,因为容器不提供元数据(例如,样本索引)以允许媒体播放器以有效的方式执行搜索。如果需要寻求,我们建议使用更合适的容器格式。

**这些提取器具有FLAG_ENABLE_CONSTANT_BITRATE_SEEKING用于使用恒定比特率假设来实现近似搜索的标志。默认情况下不启用此功能。最简单的方法来启用此功能支持它的是使用所有提取 DefaultExtractorsFactory.setConstantBitrateSeekingEnabled,描述 在这里

1、创建MediaSource

要播放渐进流,请像往常一样创建ProgressiveMediaSource并准备播放器。

	// Create a data source factory.
	DataSource.Factory dataSourceFactory =
	    new DefaultHttpDataSourceFactory(Util.getUserAgent(context, "app-name"));
	// Create a progressive media source pointing to a stream uri.
	MediaSource mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
	    .createMediaSource(progressiveUri);
	// Create a player instance.
	SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context);
	// Prepare the player with the progressive media source.
	player.prepare(mediaSource);

2、自定义渐进式播放

ExoPlayer提供多种方式让您根据应用的需求定制播放体验。以下部分简要介绍了构建ProgressiveMediaSource时可用的一些自定义选项。有关更多常规自定义选项,请参阅“ 自定义”页面

(1)、设置提取器标志

提取器标志可用于控制如何提取单个格式。它们可以设置为 DefaultExtractorsFactory,然后可以在实例化时使用ProgressiveMediaSource.Factory。以下示例传递一个标志,该标志禁用MP4流的编辑列表解析。

	DefaultExtractorsFactory extractorsFactory =
	    new DefaultExtractorsFactory()
	        .setMp4ExtractorFlags(Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS);
	ProgressiveMediaSource progressiveMediaSource =
	    new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
	        .createMediaSource(progressiveUri);

(2)、启用恒定比特率搜索

对于MP3,ADTS和AMR流,您可以使用带FLAG_ENABLE_CONSTANT_BITRATE_SEEKING标志的恒定比特率假设启用近似搜索。可以使用上述方法为各个提取器设置这些标志。要为所有支持它的提取器启用恒定比特率搜索,请使用DefaultExtractorsFactory.setConstantBitrateSeekingEnabled

DefaultExtractorsFactory extractorsFactory =
    new DefaultExtractorsFactory().setConstantBitrateSeekingEnabled(true);
ProgressiveMediaSource progressiveMediaSource =
    new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
        .createMediaSource(progressiveUri);

(3)、自定义服务器交互

某些应用可能希望拦截HTTP请求和响应。您可能希望注入自定义请求标头,读取服务器的响应标头,修改请求的URI等。例如,您的应用程序可以通过在请求媒体段时将标记作为标头注入来验证自身。您可以通过将自定义HttpDataSources注入到ProgressiveMediaSourcecreate中来实现这些行为。以下代码段显示了标头注入的示例:

ProgressiveMediaSource progressiveMediaSource =
    new ProgressiveMediaSource.Factory(
            () -> {
              HttpDataSource dataSource =
                  new DefaultHttpDataSource(userAgent);
              // Set a custom authentication request header.
              dataSource.setRequestProperty("Header", "Value");
              return dataSource;
            })
        .createMediaSource(progressiveUri);

(1)、自定义错误处理

实现自定义LoadErrorHandlingPolicy允许应用程序自定义ExoPlayer对加载错误的反应方式。例如,应用程序可能希望快速失败而不是多次重试,或者可能想要自定义控制玩家在每次重试之间等待多长时间的退避逻辑。以下代码段显示了在创建以下ProgressiveMediaSource内容时如何实现自定义退避逻辑 :

ProgressiveMediaSource progressiveMediaSource =
    new ProgressiveMediaSource.Factory(dataSourceFactory)
        .setLoadErrorHandlingPolicy(
            new DefaultLoadErrorHandlingPolicy() {
              @Override
              public long getRetryDelayMsFor(...) {
                // Implement custom back-off logic here.
              }
            })
        .createMediaSource(progressiveUri);

您可以在我们的媒体帖子中找到有关错误处理的更多信息。



您的关注和点赞是我分享的动力,如有帮助请勿吝啬!ヽ( ̄▽ ̄)ノ



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐