diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java index 3d2f24dd02..918eb62400 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/DashRendererBuilder.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; @@ -47,6 +48,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.Util; import android.content.Context; +import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; import android.util.Log; @@ -220,8 +222,8 @@ public class DashRendererBuilder implements RendererBuilder { VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, - MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, - mainHandler, player, 50); + MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, + drmSessionManager, true, mainHandler, player, 50); // Build the audio renderer. DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); @@ -232,7 +234,8 @@ public class DashRendererBuilder implements RendererBuilder { AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, - drmSessionManager, true, mainHandler, player, AudioCapabilities.getCapabilities(context)); + MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player, + AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); // Build the text renderer. DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java index faf39ab907..70cdf54717 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/ExtractorRendererBuilder.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer.demo.player; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; @@ -30,6 +31,7 @@ import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer.upstream.DefaultUriDataSource; import android.content.Context; +import android.media.AudioManager; import android.media.MediaCodec; import android.net.Uri; @@ -62,10 +64,11 @@ public class ExtractorRendererBuilder implements RendererBuilder { ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, - sampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, player.getMainHandler(), - player, 50); + sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, + player.getMainHandler(), player, 50); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, - null, true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context)); + MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player, + AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player, player.getMainHandler().getLooper()); diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java index 51475c9341..ccdd3c4034 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/HlsRendererBuilder.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; @@ -40,6 +41,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; import android.content.Context; +import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; @@ -149,9 +151,11 @@ public class HlsRendererBuilder implements RendererBuilder { HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, - sampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, mainHandler, player, 50); + sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, + 5000, mainHandler, player, 50); MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, - null, true, player.getMainHandler(), player, AudioCapabilities.getCapabilities(context)); + MediaCodecSelector.DEFAULT, null, true, player.getMainHandler(), player, + AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); MetadataTrackRenderer> id3Renderer = new MetadataTrackRenderer<>( sampleSource, new Id3Parser(), player, mainHandler.getLooper()); Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player, diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java b/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java index 7e4211807d..4cfba22134 100644 --- a/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java +++ b/demo/src/main/java/com/google/android/exoplayer/demo/player/SmoothStreamingRendererBuilder.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.audio.AudioCapabilities; @@ -44,6 +45,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; import com.google.android.exoplayer.util.Util; import android.content.Context; +import android.media.AudioManager; import android.media.MediaCodec; import android.os.Handler; @@ -164,8 +166,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder { VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, - MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, mainHandler, - player, 50); + MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, + drmSessionManager, true, mainHandler, player, 50); // Build the audio renderer. DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); @@ -176,7 +178,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder { AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_AUDIO); TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, - drmSessionManager, true, mainHandler, player, AudioCapabilities.getCapabilities(context)); + MediaCodecSelector.DEFAULT, drmSessionManager, true, mainHandler, player, + AudioCapabilities.getCapabilities(context), AudioManager.STREAM_MUSIC); // Build the text renderer. DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); diff --git a/demo_misc/vp9_opus_sw/src/main/java/com/google/android/exoplayer/demo/vp9opus/DashRendererBuilder.java b/demo_misc/vp9_opus_sw/src/main/java/com/google/android/exoplayer/demo/vp9opus/DashRendererBuilder.java index fc32d837a6..98a4b03da2 100644 --- a/demo_misc/vp9_opus_sw/src/main/java/com/google/android/exoplayer/demo/vp9opus/DashRendererBuilder.java +++ b/demo_misc/vp9_opus_sw/src/main/java/com/google/android/exoplayer/demo/vp9opus/DashRendererBuilder.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.vp9opus; import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.chunk.ChunkSampleSource; @@ -133,7 +134,8 @@ public class DashRendererBuilder implements ManifestCallback= 16); + this.mediaCodecSelector = Assertions.checkNotNull(mediaCodecSelector); this.drmSessionManager = drmSessionManager; this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; this.eventHandler = eventHandler; @@ -264,18 +268,35 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer seekToInternal(); } + @Override + protected final boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException { + return handlesTrack(mediaCodecSelector, mediaFormat); + } + /** - * Returns a {@link DecoderInfo} for decoding media in the specified MIME type. + * Returns whether this renderer is capable of handling the provided track. * - * @param mimeType The type of media to decode. - * @param requiresSecureDecoder Whether a secure decoder is needed for decoding {@code mimeType}. - * @return {@link DecoderInfo} for decoding media in the specified MIME type, or {@code null} if - * no suitable decoder is available. + * @param mediaCodecSelector The decoder selector. + * @param mediaFormat The format of the track. + * @return True if the renderer can handle the track, false otherwise. * @throws DecoderQueryException Thrown if there was an error querying decoders. */ - protected DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder) - throws DecoderQueryException { - return MediaCodecUtil.getDecoderInfo(mimeType, requiresSecureDecoder); + protected abstract boolean handlesTrack(MediaCodecSelector mediaCodecSelector, + MediaFormat mediaFormat) throws DecoderQueryException; + + /** + * Returns a {@link DecoderInfo} for a given format. + * + * @param mediaCodecSelector The decoder selector. + * @param mediaFormat The format for which a decoder is required. + * @param requiresSecureDecoder Whether a secure decoder is required. + * @return A {@link DecoderInfo} describing the decoder to instantiate, or null if no suitable + * decoder exists. + * @throws DecoderQueryException Thrown if there was an error querying decoders. + */ + protected DecoderInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, + MediaFormat mediaFormat, boolean requiresSecureDecoder) throws DecoderQueryException { + return mediaCodecSelector.getDecoderInfo(format, requiresSecureDecoder); } /** @@ -283,12 +304,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer * wish to configure the codec with a non-null surface. * * @param codec The {@link MediaCodec} to configure. - * @param codecName The name of the codec. * @param codecIsAdaptive Whether the codec is adaptive. * @param format The format for which the codec is being configured. * @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption. */ - protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive, + protected void configureCodec(MediaCodec codec, boolean codecIsAdaptive, android.media.MediaFormat format, MediaCrypto crypto) { codec.configure(format, null, crypto, 0); } @@ -325,7 +345,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer DecoderInfo decoderInfo = null; try { - decoderInfo = getDecoderInfo(mimeType, requiresSecureDecoder); + decoderInfo = getDecoderInfo(mediaCodecSelector, format, requiresSecureDecoder); } catch (DecoderQueryException e) { notifyAndThrowDecoderInitError(new DecoderInitializationException(format, e, requiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); @@ -346,8 +366,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer codec = MediaCodec.createByCodecName(codecName); TraceUtil.endSection(); TraceUtil.beginSection("configureCodec"); - configureCodec(codec, codecName, codecIsAdaptive, format.getFrameworkMediaFormatV16(), - mediaCrypto); + configureCodec(codec, decoderInfo.adaptive, format.getFrameworkMediaFormatV16(), mediaCrypto); TraceUtil.endSection(); TraceUtil.beginSection("codec.start()"); codec.start(); diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java index ba10897b56..e37b2f99b8 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecVideoTrackRenderer.java @@ -128,29 +128,34 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { /** * @param context A context. * @param source The upstream source from which the renderer obtains samples. + * @param mediaCodecSelector A decoder selector. * @param videoScalingMode The scaling mode to pass to * {@link MediaCodec#setVideoScalingMode(int)}. */ - public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode) { - this(context, source, videoScalingMode, 0); + public MediaCodecVideoTrackRenderer(Context context, SampleSource source, + MediaCodecSelector mediaCodecSelector, int videoScalingMode) { + this(context, source, mediaCodecSelector, videoScalingMode, 0); } /** * @param context A context. * @param source The upstream source from which the renderer obtains samples. + * @param mediaCodecSelector A decoder selector. * @param videoScalingMode The scaling mode to pass to * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * can attempt to seamlessly join an ongoing playback. */ - public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, - long allowedJoiningTimeMs) { - this(context, source, videoScalingMode, allowedJoiningTimeMs, null, null, -1); + public MediaCodecVideoTrackRenderer(Context context, SampleSource source, + MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs) { + this(context, source, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, null, + -1); } /** * @param context A context. * @param source The upstream source from which the renderer obtains samples. + * @param mediaCodecSelector A decoder selector. * @param videoScalingMode The scaling mode to pass to * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer @@ -161,16 +166,17 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { * @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between * invocations of {@link EventListener#onDroppedFrames(int, long)}. */ - public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, - long allowedJoiningTimeMs, Handler eventHandler, EventListener eventListener, - int maxDroppedFrameCountToNotify) { - this(context, source, videoScalingMode, allowedJoiningTimeMs, null, false, eventHandler, - eventListener, maxDroppedFrameCountToNotify); + public MediaCodecVideoTrackRenderer(Context context, SampleSource source, + MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs, + Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) { + this(context, source, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false, + eventHandler, eventListener, maxDroppedFrameCountToNotify); } /** * @param context A context. * @param source The upstream source from which the renderer obtains samples. + * @param mediaCodecSelector A decoder selector. * @param videoScalingMode The scaling mode to pass to * {@link MediaCodec#setVideoScalingMode(int)}. * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer @@ -188,11 +194,12 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { * @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between * invocations of {@link EventListener#onDroppedFrames(int, long)}. */ - public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, - long allowedJoiningTimeMs, DrmSessionManager drmSessionManager, - boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener, - int maxDroppedFrameCountToNotify) { - super(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener); + public MediaCodecVideoTrackRenderer(Context context, SampleSource source, + MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs, + DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys, + Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) { + super(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, + eventListener); this.frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); this.videoScalingMode = videoScalingMode; this.allowedJoiningTimeUs = allowedJoiningTimeMs * 1000; @@ -209,11 +216,11 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { } @Override - protected boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException { - // TODO: Use MediaCodecList.findDecoderForFormat on API 23. + protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat) + throws DecoderQueryException { String mimeType = mediaFormat.mimeType; return MimeTypes.isVideo(mimeType) && (MimeTypes.VIDEO_UNKNOWN.equals(mimeType) - || MediaCodecUtil.getDecoderInfo(mimeType, false) != null); + || mediaCodecSelector.getDecoderInfo(mediaFormat, false) != null); } @Override @@ -316,7 +323,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { // Override configureCodec to provide the surface. @Override - protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive, + protected void configureCodec(MediaCodec codec, boolean codecIsAdaptive, android.media.MediaFormat format, MediaCrypto crypto) { maybeSetMaxInputSize(format, codecIsAdaptive); codec.configure(format, surface, crypto, 0); diff --git a/playbacktests/src/main/java/com/google/android/exoplayer/playbacktests/gts/DashTest.java b/playbacktests/src/main/java/com/google/android/exoplayer/playbacktests/gts/DashTest.java index 731e08a596..4323e86a9e 100644 --- a/playbacktests/src/main/java/com/google/android/exoplayer/playbacktests/gts/DashTest.java +++ b/playbacktests/src/main/java/com/google/android/exoplayer/playbacktests/gts/DashTest.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; +import com.google.android.exoplayer.MediaCodecSelector; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.chunk.ChunkSampleSource; @@ -327,7 +328,8 @@ public final class DashTest extends ActivityInstrumentationTestCase2