Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2e9e27f authored by Oliver Woodman's avatar Oliver Woodman
Browse files

Update ExoPlayer developer guide.

This is a minimal update, just to fix things that are broken
or no longer make sense as of the v1.2.0 release.

Change-Id: If519709c91c975d96b62e2dd28e18e2105735c2b
parent 03efba0e
Loading
Loading
Loading
Loading
+27 −29
Original line number Original line Diff line number Diff line
@@ -72,10 +72,8 @@ page.tags="audio","video","adaptive","streaming","DASH","smoothstreaming"
<ul>
<ul>
    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/library">
    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/library">
      ExoPlayer Library</a> &mdash; This part of the project contains the core library classes.</li>
      ExoPlayer Library</a> &mdash; This part of the project contains the core library classes.</li>
    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/simple">
    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo">
      Simple Demo</a> &mdash; This part of the app demonstrates a basic use of ExoPlayer.</li>
      Demo App</a> &mdash; This part of the project demonstrates usage of ExoPlayer,
    <li><a class="external-link" href="https://github.com/google/ExoPlayer/tree/master/demo/src/main/java/com/google/android/exoplayer/demo/full">
      Full Demo</a> &mdash; This part of the app demonstrates more advanced features,
      including the ability to select between multiple audio tracks, a background audio mode,
      including the ability to select between multiple audio tracks, a background audio mode,
      event logging and DRM protected playback. </li>
      event logging and DRM protected playback. </li>
</ul>
</ul>
@@ -137,9 +135,10 @@ player.setPlayWhenReady(true);
player.release(); // Don’t forget to release when done!
player.release(); // Don’t forget to release when done!
</pre>
</pre>


<p>For a complete example, see the {@code SimplePlayerActivity} in the ExoPlayer demo app, which
<p>For a complete example, see {@code PlayerActivity} and {@code DemoPlayer} in the ExoPlayer demo
  correctly manages an ExoPlayer instance with respect to both the {@link android.app.Activity} and
  app. Between them these classes correctly manage an ExoPlayer instance with respect to both the
  {@link android.view.Surface} lifecycles.</p>
  {@link android.app.Activity} and {@link android.view.Surface} lifecycles.
</p>




<h2 id="samplesource">SampleSource</h2>
<h2 id="samplesource">SampleSource</h2>
@@ -187,7 +186,7 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
</pre>
</pre>


<p>The ExoPlayer demo app provides a complete implementation of this code in
<p>The ExoPlayer demo app provides a complete implementation of this code in
  {@code DefaultRendererBuilder}. The {@code SimplePlaybackActivity} class uses it to play one
  {@code DefaultRendererBuilder}. The {@code PlayerActivity} class uses it to play one
  of the videos available in the demo app. Note that in the example, video and audio
  of the videos available in the demo app. Note that in the example, video and audio
  are muxed, meaning they are streamed together from a single URI. The {@code FrameworkSampleSource}
  are muxed, meaning they are streamed together from a single URI. The {@code FrameworkSampleSource}
  instance provides video samples to the {@code videoRenderer} object and audio samples to the
  instance provides video samples to the {@code videoRenderer} object and audio samples to the
@@ -211,9 +210,9 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
  which loads chunks of media data from which individual samples can be extracted. Each {@code
  which loads chunks of media data from which individual samples can be extracted. Each {@code
  ChunkSampleSource} requires a {@code ChunkSource} object to be injected through its constructor,
  ChunkSampleSource} requires a {@code ChunkSource} object to be injected through its constructor,
  which is responsible for providing media chunks from which to load and read samples. The {@code
  which is responsible for providing media chunks from which to load and read samples. The {@code
  DashMp4ChunkSource} and {@code SmoothStreamingChunkSource} classes provide DASH and SmoothStreaming
  DashChunkSource} class provides DASH playback using the FMP4 and WebM container formats. The
  playback using the FMP4 container format. The {@code DashWebMChunkSource} class uses the WebM
  {@code SmoothStreamingChunkSource} class provides SmoothStreaming playback using the FMP4
  container format to provide DASH playback.</p>
  container format.</p>


<p>All of the standard {@code ChunkSource} implementations require a {@code FormatEvaluator} and
<p>All of the standard {@code ChunkSource} implementations require a {@code FormatEvaluator} and
  a {@code DataSource} to be injected through their constructors. The {@code FormatEvaluator}
  a {@code DataSource} to be injected through their constructors. The {@code FormatEvaluator}
@@ -242,7 +241,7 @@ BandwidthMeter bandwidthMeter = new BandwidthMeter();
// Build the video renderer.
// Build the video renderer.
DataSource videoDataSource = new HttpDataSource(userAgent,
DataSource videoDataSource = new HttpDataSource(userAgent,
        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
ChunkSource videoChunkSource = new DashMp4ChunkSource(videoDataSource,
ChunkSource videoChunkSource = new DashChunkSource(videoDataSource,
        new AdaptiveEvaluator(bandwidthMeter), videoRepresentations);
        new AdaptiveEvaluator(bandwidthMeter), videoRepresentations);
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource,
ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource,
        loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
        loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
@@ -253,7 +252,7 @@ MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
// Build the audio renderer.
// Build the audio renderer.
DataSource audioDataSource = new HttpDataSource(userAgent,
DataSource audioDataSource = new HttpDataSource(userAgent,
        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
        HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter);
ChunkSource audioChunkSource = new DashMp4ChunkSource(audioDataSource,
ChunkSource audioChunkSource = new DashChunkSource(audioDataSource,
        new FormatEvaluator.FixedEvaluator(), audioRepresentation);
        new FormatEvaluator.FixedEvaluator(), audioRepresentation);
SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource,
SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource,
        loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
        loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true);
@@ -273,9 +272,8 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
</p>
</p>


<p>The ExoPlayer demo app provides complete implementation of this code in
<p>The ExoPlayer demo app provides complete implementation of this code in
  {@code DashVodRendererBuilder}. The {@code SimplePlaybackActivity} class uses this builder to
  {@code DashRendererBuilder}. The {@code PlayerActivity} class uses this builder to
  construct renderers for playing DASH sample videos in the demo app. It asynchronously fetches a
  construct renderers for playing DASH sample videos in the demo app. For an
  specified MPD file in order to construct the required {@code Representation} objects. For an
  equivalent SmoothStreaming example, see the {@code SmoothStreamingRendererBuilder} class in the
  equivalent SmoothStreaming example, see the {@code SmoothStreamingRendererBuilder} class in the
  demo app.</p>
  demo app.</p>


@@ -313,7 +311,7 @@ if (format.width * format.height &lt;= maxDecodableFrameSize) {
}
}
</pre>
</pre>


<p>This approach is used to filter {@code Representations} in the {@code DashVodRendererBuilder}
<p>This approach is used to filter {@code Representations} in the {@code DashRendererBuilder}
  class of the ExoPlayer demo app, and similarly to filter track indices in {@code
  class of the ExoPlayer demo app, and similarly to filter track indices in {@code
  SmoothStreamingRendererBuilder}.</p>
  SmoothStreamingRendererBuilder}.</p>


@@ -372,24 +370,26 @@ boolean isAdaptive = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264).adaptiv
<p>In addition to high level listeners, many of the individual components provided by the
<p>In addition to high level listeners, many of the individual components provided by the
  ExoPlayer library allow their own event listeners. For example, {@code
  ExoPlayer library allow their own event listeners. For example, {@code
  MediaCodecVideoTrackRenderer} has constructors that take a {@code
  MediaCodecVideoTrackRenderer} has constructors that take a {@code
  MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code SimplePlayerActivity}
  MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code DemoPlayer}
  acts as a listener so that it can adjust the dimensions of the target surface to have the correct
  acts as the listener to multiple individual components, forwarding events to {@code PlayerActivity}.
  height and width ratio for the video being played:</p>
  This approach allows {@code PlayerActivity} to adjust the dimensions of the target surface
  to have the correct height and width ratio for the video being played:</p>


<pre>
<pre>
&#64;Override
&#64;Override
public void onVideoSizeChanged(int width, int height) {
public void onVideoSizeChanged(int width, int height, float pixelWidthAspectRatio) {
  surfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (float) width / height);
  surfaceView.setVideoWidthHeightRatio(
          height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
}
}
</pre>
</pre>


<p>The {@code RendererBuilder} classes in the ExoPlayer demo app inject the activity as the
<p>The {@code RendererBuilder} classes in the ExoPlayer demo app inject the {@code DemoPlayer} as
  listener, for example in the {@code DashVodRendererBuilder} class:</p>
  the listener to each component, for example in the {@code DashRendererBuilder} class:</p>


<pre>
<pre>
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
        videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
        sampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,
        0, <strong>mainHandler, playerActivity</strong>, 50);
        null, <strong>player.getMainHandler(), player</strong>, 50);
</pre>
</pre>


<p>Note that you must pass a {@link android.os.Handler} object to the renderer, which determines
<p>Note that you must pass a {@link android.os.Handler} object to the renderer, which determines
@@ -441,9 +441,7 @@ player.blockingSendMessage(videoRenderer,


<p>You must use a blocking message because the contract of {@link
<p>You must use a blocking message because the contract of {@link
  android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed()} requires that the
  android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed()} requires that the
  app does not attempt to access the surface after the method returns. The {@code
  app does not attempt to access the surface after the method returns.</p>
  SimplePlayerActivity} class in the demo app demonstrates how the surface should be set and
  cleared.</p>




<h2 id="customizing">Customizing ExoPlayer</h2>
<h2 id="customizing">Customizing ExoPlayer</h2>
−302 B (39.5 KiB)
Loading image diff...