From a2e9e27f4c87112dfd27ced16254a4736180cd4f Mon Sep 17 00:00:00 2001
From: Oliver Woodman For a complete example, see the {@code SimplePlayerActivity} in the ExoPlayer demo app, which
- correctly manages an ExoPlayer instance with respect to both the {@link android.app.Activity} and
- {@link android.view.Surface} lifecycles. For a complete example, see {@code PlayerActivity} and {@code DemoPlayer} in the ExoPlayer demo
+ app. Between them these classes correctly manage an ExoPlayer instance with respect to both the
+ {@link android.app.Activity} and {@link android.view.Surface} lifecycles.
+ 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
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
@@ -211,9 +210,9 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
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,
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
- playback using the FMP4 container format. The {@code DashWebMChunkSource} class uses the WebM
- container format to provide DASH playback.
@@ -137,9 +135,10 @@ player.setPlayWhenReady(true);
player.release(); // Don’t forget to release when done!
-SampleSource
@@ -187,7 +186,7 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
All of the standard {@code ChunkSource} implementations require a {@code FormatEvaluator} and a {@code DataSource} to be injected through their constructors. The {@code FormatEvaluator} @@ -242,7 +241,7 @@ BandwidthMeter bandwidthMeter = new BandwidthMeter(); // Build the video renderer. DataSource videoDataSource = new HttpDataSource(userAgent, HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter); -ChunkSource videoChunkSource = new DashMp4ChunkSource(videoDataSource, +ChunkSource videoChunkSource = new DashChunkSource(videoDataSource, new AdaptiveEvaluator(bandwidthMeter), videoRepresentations); ChunkSampleSource videoSampleSource = new ChunkSampleSource(videoChunkSource, loadControl, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); @@ -253,7 +252,7 @@ MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer( // Build the audio renderer. DataSource audioDataSource = new HttpDataSource(userAgent, HttpDataSource.REJECT_PAYWALL_TYPES, bandwidthMeter); -ChunkSource audioChunkSource = new DashMp4ChunkSource(audioDataSource, +ChunkSource audioChunkSource = new DashChunkSource(audioDataSource, new FormatEvaluator.FixedEvaluator(), audioRepresentation); SampleSource audioSampleSource = new ChunkSampleSource(audioChunkSource, loadControl, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, true); @@ -273,9 +272,8 @@ MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
The ExoPlayer demo app provides complete implementation of this code in - {@code DashVodRendererBuilder}. The {@code SimplePlaybackActivity} class uses this builder to - construct renderers for playing DASH sample videos in the demo app. It asynchronously fetches a - specified MPD file in order to construct the required {@code Representation} objects. For an + {@code DashRendererBuilder}. The {@code PlayerActivity} class uses this builder to + construct renderers for playing DASH sample videos in the demo app. For an equivalent SmoothStreaming example, see the {@code SmoothStreamingRendererBuilder} class in the demo app.
@@ -313,7 +311,7 @@ if (format.width * format.height <= maxDecodableFrameSize) { } -This approach is used to filter {@code Representations} in the {@code DashVodRendererBuilder} +
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 SmoothStreamingRendererBuilder}.
@@ -372,24 +370,26 @@ boolean isAdaptive = MediaCodecUtil.getDecoderInfo(MimeTypes.VIDEO_H264).adaptivIn addition to high level listeners, many of the individual components provided by the ExoPlayer library allow their own event listeners. For example, {@code MediaCodecVideoTrackRenderer} has constructors that take a {@code - MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code SimplePlayerActivity} - acts as a listener so that it can adjust the dimensions of the target surface to have the correct - height and width ratio for the video being played:
+ MediaCodecVideoTrackRenderer.EventListener}. In the ExoPlayer demo app, {@code DemoPlayer} + acts as the listener to multiple individual components, forwarding events to {@code PlayerActivity}. + 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:
@Override
-public void onVideoSizeChanged(int width, int height) {
- surfaceView.setVideoWidthHeightRatio(height == 0 ? 1 : (float) width / height);
+public void onVideoSizeChanged(int width, int height, float pixelWidthAspectRatio) {
+ surfaceView.setVideoWidthHeightRatio(
+ height == 0 ? 1 : (width * pixelWidthAspectRatio) / height);
}
-The {@code RendererBuilder} classes in the ExoPlayer demo app inject the activity as the - listener, for example in the {@code DashVodRendererBuilder} class:
+The {@code RendererBuilder} classes in the ExoPlayer demo app inject the {@code DemoPlayer} as + the listener to each component, for example in the {@code DashRendererBuilder} class:
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer( - videoSampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, - 0, mainHandler, playerActivity, 50); + sampleSource, null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, + null, player.getMainHandler(), player, 50);
Note that you must pass a {@link android.os.Handler} object to the renderer, which determines @@ -441,9 +441,7 @@ player.blockingSendMessage(videoRenderer,
You must use a blocking message because the contract of {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed()} requires that the - app does not attempt to access the surface after the method returns. The {@code - SimplePlayerActivity} class in the demo app demonstrates how the surface should be set and - cleared.
+ app does not attempt to access the surface after the method returns.FUiValdX#`bYuLgCG;
zxYMap#X~%Of5Jt}@^uD@DmkV&88(Z=cRwh--y~P7eVXH^j@jg@HBy$rp)I2VY$-oG
zlL4w8`qn<@FCklZ>qOoqDmk!HQN$m$^UWtR!2e|m!MT<{eUP~r)hC2sTG8KXutwn{
z6s+&T%-q^!<_1wF2F8{zk_h86jFvc-rs+Uk<31cLdydXM%aHA@7U(wYQ{C0ot`-ZZ
zmS_KT85N*0NhCuc=pB~XOk|KYb9{|Z2V5)2W8E}b=4#`>J5AgH_zy@`&N1_d@@{s@
zg+OBCY?~hW;vVD$A}DeXR1Ke<5Ot;_v$j=NYprb1Jn~rk9M_7Cn|z*N&@v4*QnxP?
z#rPr3n|~%iKXr^jKFq-By(K~!m;u_warGI#D$A}tkCup|5CCq*3f`b-!SBIhYj~Q3of^qG4kPou1lr+OFco(a6JL
zMGrkxvofo|+PuXepZAs1a>j9Fmkpj3Fb&aZQcXQP%Ehu9I~P_4X}W;1;Nr;J-55HM
z6YY!OYTs?`bKb8dKlKoYZ#JVqbNOl$Q}|4gdWv31`3#zd-BA$XnKGdP=Spz$^2O6`
z;nIa{&v~zDSVfT?l{EF(dXuW09zV`q&K#qlt18&w%DhSp0Mu>?{3Y1oW7(XDF@7ca
z1gfgC3Oa7`KK{Wn%+~I?w^|15Cngm|(kLceJ1<7{ae<$!I1IyIF}DJGjPNFXPt=t6
zBMZN_IvXK{Tn4rA`%_ub+z;Py{2B-t#l9WMOfHd5*=q9mDN^qg7EPPndQJH=j&($}
zD`c764~a34P|(z8`Pl*~fC^`+-d~PS#1;fodteIE 6=c|bB
za=FWLr%s_OrfPSkW>{r&gYI$BF78-_NEa4+_9L=xyW;f4!R7BCxdqnhU@T~W;_xzc
zdjN;Wg!>ZW@oBi4z-xxtTRP!1gLA*)!(o-{-9G5Q?{Zg;zHv7UN
zz7~Pg-|=^BQZ%9T3!wnxH7>o(G&CWvrCQ21e&RxHoy{$162uUhw^e&nj?X9LHA)sE
za$oO77|8on8leyv*NR`5;$K~In}a|G_iN;s^S?w=564U*%PkCbpGM=4Y+{{ttEkNC
z2kxF$!^UJI&zKIizE&|ZyRgiUnpK30I;+H)o?FQ@gIbF`aU1|I*<-(9?vLaS49sVL
zSy8{ZYT7=;gl@CZNrr1a9Hk189cEH{xX!u{Wmv&WvgYyr7A3RtYKQZgLt3HUS~%*H
zbnsj;RpbE6d|$#KQv%I#c*FQ*SKfH&_>nC9>RGHvJd-ZYf`MmQ6`T3*x{I$u-p%M3
zU6aAV@b9yMAhhQDSf7;OUnHoa!K}-RBSAzfF{;({#^Got1$g4Ui?s6HCZ@*de0D!w
zr34aO1jI(qoV(KFW$APk&YUOm*elfn=V|2ShK4)tnY_c-
~sKlEWy=#^g+}e
z-o=;uidw<4>c?-hHO5z#1&_Twf{}r#u)&_BA2K)B*m({eE2h2of!kP&1PO^ZBv!>n
z#Xn?Inne06rcJN