Commit 894ae1a3 by olly Committed by Oliver Woodman

Improve SimpleExoPlayer flexibility

- Allow extension and overriding of renderer creation.
  Several developers have asked for this, so that they
  can use their own renderers (typically extensions to
  the core ones) without losing the ability to use
  SimpleExoPlayer.
- Add option to not attempt extension renderer creation,
  for efficiency.
- Align build variants for internal and external demo
  apps. This is slightly unfortunate, but convergence
  seems necessary for useExtensionRenderers.
- Fix DASH playback tests to use the debug video
  renderer.

Issue #2102

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=140140915
parent cbf59888
...@@ -37,16 +37,23 @@ android { ...@@ -37,16 +37,23 @@ android {
abortOnError false abortOnError false
} }
flavorDimensions "extensions"
productFlavors { productFlavors {
noExtensions noExtns {
withExtensions dimension "extensions"
}
extns {
dimension "extensions"
} }
}
} }
dependencies { dependencies {
compile project(':library') compile project(':library')
withExtensionsCompile project(path: ':extension-ffmpeg') extnsCompile project(path: ':extension-ffmpeg')
withExtensionsCompile project(path: ':extension-flac') extnsCompile project(path: ':extension-flac')
withExtensionsCompile project(path: ':extension-opus') extnsCompile project(path: ':extension-opus')
withExtensionsCompile project(path: ':extension-vp9') extnsCompile project(path: ':extension-vp9')
} }
...@@ -36,13 +36,19 @@ public class DemoApplication extends Application { ...@@ -36,13 +36,19 @@ public class DemoApplication extends Application {
userAgent = Util.getUserAgent(this, "ExoPlayerDemo"); userAgent = Util.getUserAgent(this, "ExoPlayerDemo");
} }
DataSource.Factory buildDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) { public DataSource.Factory buildDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
return new DefaultDataSourceFactory(this, bandwidthMeter, return new DefaultDataSourceFactory(this, bandwidthMeter,
buildHttpDataSourceFactory(bandwidthMeter)); buildHttpDataSourceFactory(bandwidthMeter));
} }
HttpDataSource.Factory buildHttpDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) { public HttpDataSource.Factory buildHttpDataSourceFactory(DefaultBandwidthMeter bandwidthMeter) {
return new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter); return new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter);
} }
public boolean useExtensionRenderers() {
// We should return BuildConfig.FLAVOR_extensions.equals("extns") here, but this is currently
// incompatible with a Google internal build system.
return true;
}
} }
...@@ -251,12 +251,17 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay ...@@ -251,12 +251,17 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
} }
} }
@SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode =
((DemoApplication) getApplication()).useExtensionRenderers()
? (preferExtensionDecoders ? SimpleExoPlayer.EXTENSION_RENDERER_MODE_PREFER
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_ON)
: SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF;
TrackSelection.Factory videoTrackSelectionFactory = TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveVideoTrackSelection.Factory(BANDWIDTH_METER); new AdaptiveVideoTrackSelection.Factory(BANDWIDTH_METER);
trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory); trackSelectionHelper = new TrackSelectionHelper(trackSelector, videoTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, new DefaultLoadControl(), player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, new DefaultLoadControl(),
drmSessionManager, preferExtensionDecoders); drmSessionManager, extensionRendererMode);
player.addListener(this); player.addListener(this);
eventLogger = new EventLogger(trackSelector); eventLogger = new EventLogger(trackSelector);
......
...@@ -49,7 +49,7 @@ public final class ExoPlayerFactory { ...@@ -49,7 +49,7 @@ public final class ExoPlayerFactory {
/** /**
* Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated * Creates a {@link SimpleExoPlayer} instance. Must be called from a thread that has an associated
* {@link Looper}. * {@link Looper}. Available extension renderers are not used.
* *
* @param context A {@link Context}. * @param context A {@link Context}.
* @param trackSelector The {@link TrackSelector} that will be used by the instance. * @param trackSelector The {@link TrackSelector} that will be used by the instance.
...@@ -59,7 +59,8 @@ public final class ExoPlayerFactory { ...@@ -59,7 +59,8 @@ public final class ExoPlayerFactory {
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) { LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
return newSimpleInstance(context, trackSelector, loadControl, drmSessionManager, false); return newSimpleInstance(context, trackSelector, loadControl,
drmSessionManager, SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF);
} }
/** /**
...@@ -71,15 +72,15 @@ public final class ExoPlayerFactory { ...@@ -71,15 +72,15 @@ public final class ExoPlayerFactory {
* @param loadControl The {@link LoadControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * will not be used for DRM protected playbacks.
* @param preferExtensionDecoders True to prefer {@link Renderer} instances defined in * @param extensionRendererMode The extension renderer mode, which determines if and how available
* available extensions over those defined in the core library. Note that extensions must be * extension renderers are used. Note that extensions must be included in the application
* included in the application build for setting this flag to have any effect. * build for them to be considered available.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
boolean preferExtensionDecoders) { @SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode) {
return newSimpleInstance(context, trackSelector, loadControl, drmSessionManager, return newSimpleInstance(context, trackSelector, loadControl, drmSessionManager,
preferExtensionDecoders, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS); extensionRendererMode, DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS);
} }
/** /**
...@@ -91,17 +92,18 @@ public final class ExoPlayerFactory { ...@@ -91,17 +92,18 @@ public final class ExoPlayerFactory {
* @param loadControl The {@link LoadControl} that will be used by the instance. * @param loadControl The {@link LoadControl} that will be used by the instance.
* @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance * @param drmSessionManager An optional {@link DrmSessionManager}. May be null if the instance
* will not be used for DRM protected playbacks. * will not be used for DRM protected playbacks.
* @param preferExtensionDecoders True to prefer {@link Renderer} instances defined in * @param extensionRendererMode The extension renderer mode, which determines if and how available
* available extensions over those defined in the core library. Note that extensions must be * extension renderers are used. Note that extensions must be included in the application
* included in the application build for setting this flag to have any effect. * build for them to be considered available.
* @param allowedVideoJoiningTimeMs The maximum duration for which a video renderer can attempt to * @param allowedVideoJoiningTimeMs The maximum duration for which a video renderer can attempt to
* seamlessly join an ongoing playback. * seamlessly join an ongoing playback.
*/ */
public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector, public static SimpleExoPlayer newSimpleInstance(Context context, TrackSelector trackSelector,
LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager, LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
boolean preferExtensionDecoders, long allowedVideoJoiningTimeMs) { @SimpleExoPlayer.ExtensionRendererMode int extensionRendererMode,
long allowedVideoJoiningTimeMs) {
return new SimpleExoPlayer(context, trackSelector, loadControl, drmSessionManager, return new SimpleExoPlayer(context, trackSelector, loadControl, drmSessionManager,
preferExtensionDecoders, allowedVideoJoiningTimeMs); extensionRendererMode, allowedVideoJoiningTimeMs);
} }
/** /**
......
...@@ -21,11 +21,15 @@ import android.media.UnsupportedSchemeException; ...@@ -21,11 +21,15 @@ import android.media.UnsupportedSchemeException;
import android.net.Uri; import android.net.Uri;
import android.test.ActivityInstrumentationTestCase2; import android.test.ActivityInstrumentationTestCase2;
import android.util.Log; import android.util.Log;
import android.view.Surface;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto; import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.drm.HttpMediaDrmCallback;
import com.google.android.exoplayer2.drm.StreamingDrmSessionManager; import com.google.android.exoplayer2.drm.StreamingDrmSessionManager;
...@@ -34,6 +38,7 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecInfo; ...@@ -34,6 +38,7 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer2.playbacktests.util.ActionSchedule; import com.google.android.exoplayer2.playbacktests.util.ActionSchedule;
import com.google.android.exoplayer2.playbacktests.util.DebugSimpleExoPlayer;
import com.google.android.exoplayer2.playbacktests.util.DecoderCountersUtil; import com.google.android.exoplayer2.playbacktests.util.DecoderCountersUtil;
import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest; import com.google.android.exoplayer2.playbacktests.util.ExoHostedTest;
import com.google.android.exoplayer2.playbacktests.util.HostActivity; import com.google.android.exoplayer2.playbacktests.util.HostActivity;
...@@ -727,7 +732,17 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit ...@@ -727,7 +732,17 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
} }
@Override @Override
public MediaSource buildSource(HostActivity host, String userAgent, protected SimpleExoPlayer buildExoPlayer(HostActivity host, Surface surface,
MappingTrackSelector trackSelector,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
SimpleExoPlayer player = new DebugSimpleExoPlayer(host, trackSelector,
new DefaultLoadControl(), drmSessionManager);
player.setVideoSurface(surface);
return player;
}
@Override
protected MediaSource buildSource(HostActivity host, String userAgent,
TransferListener<? super DataSource> mediaTransferListener) { TransferListener<? super DataSource> mediaTransferListener) {
DataSource.Factory manifestDataSourceFactory = new DefaultDataSourceFactory(host, userAgent); DataSource.Factory manifestDataSourceFactory = new DefaultDataSourceFactory(host, userAgent);
DataSource.Factory mediaDataSourceFactory = new DefaultDataSourceFactory(host, userAgent, DataSource.Factory mediaDataSourceFactory = new DefaultDataSourceFactory(host, userAgent,
......
...@@ -19,17 +19,45 @@ import android.annotation.TargetApi; ...@@ -19,17 +19,45 @@ import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer; import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector; import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
import com.google.android.exoplayer2.trackselection.TrackSelector;
import com.google.android.exoplayer2.video.MediaCodecVideoRenderer; import com.google.android.exoplayer2.video.MediaCodecVideoRenderer;
import com.google.android.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
import java.util.ArrayList;
/** /**
* A debug extension of {@link SimpleExoPlayer}. Provides video buffer timestamp assertions.
*/
@TargetApi(16)
public class DebugSimpleExoPlayer extends SimpleExoPlayer {
public DebugSimpleExoPlayer(Context context, TrackSelector trackSelector,
LoadControl loadControl, DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
super(context, trackSelector, loadControl, drmSessionManager,
SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF, 0);
}
@Override
protected void buildVideoRenderers(Context context, Handler mainHandler,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager,
@ExtensionRendererMode int extensionRendererMode, VideoRendererEventListener eventListener,
long allowedVideoJoiningTimeMs, ArrayList<Renderer> out) {
out.add(new DebugMediaCodecVideoRenderer(context, MediaCodecSelector.DEFAULT,
allowedVideoJoiningTimeMs, mainHandler, eventListener,
MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY));
}
/**
* Decodes and renders video using {@link MediaCodecVideoRenderer}. Provides buffer timestamp * Decodes and renders video using {@link MediaCodecVideoRenderer}. Provides buffer timestamp
* assertions. * assertions.
*/ */
@TargetApi(16) private static class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer {
public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer {
private static final int ARRAY_SIZE = 1000; private static final int ARRAY_SIZE = 1000;
...@@ -108,4 +136,7 @@ public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer { ...@@ -108,4 +136,7 @@ public class DebugMediaCodecVideoRenderer extends MediaCodecVideoRenderer {
queueSize--; queueSize--;
return timestampsList[startIndex - 1]; return timestampsList[startIndex - 1];
} }
}
} }
...@@ -320,7 +320,8 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen ...@@ -320,7 +320,8 @@ public abstract class ExoHostedTest implements HostedTest, ExoPlayer.EventListen
MappingTrackSelector trackSelector, MappingTrackSelector trackSelector,
DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) { DrmSessionManager<FrameworkMediaCrypto> drmSessionManager) {
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(host, trackSelector, SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(host, trackSelector,
new DefaultLoadControl(), drmSessionManager, false, 0); new DefaultLoadControl(), drmSessionManager, SimpleExoPlayer.EXTENSION_RENDERER_MODE_OFF,
0);
player.setVideoSurface(surface); player.setVideoSurface(surface);
return player; return player;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment