Commit 7fbffc87 by olly Committed by Oliver Woodman

Expose control over decoder selection.

This allows implementation and injection of custom MediaCodecSelector
instances. By injecting a custom selector, it's possible for applications
to exert more control over which decoder(s) they instantiate. For example,
applications can force use of a software decoder.

GitHub Issue #938
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=110369810
parent 8d6c4b8e
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player;
import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.audio.AudioCapabilities;
...@@ -47,6 +48,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; ...@@ -47,6 +48,7 @@ import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.content.Context; import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
...@@ -220,8 +222,8 @@ public class DashRendererBuilder implements RendererBuilder { ...@@ -220,8 +222,8 @@ public class DashRendererBuilder implements RendererBuilder {
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
DemoPlayer.TYPE_VIDEO); DemoPlayer.TYPE_VIDEO);
TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,
mainHandler, player, 50); drmSessionManager, true, mainHandler, player, 50);
// Build the audio renderer. // Build the audio renderer.
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
...@@ -232,7 +234,8 @@ public class DashRendererBuilder implements RendererBuilder { ...@@ -232,7 +234,8 @@ public class DashRendererBuilder implements RendererBuilder {
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
DemoPlayer.TYPE_AUDIO); DemoPlayer.TYPE_AUDIO);
TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, 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. // Build the text renderer.
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.google.android.exoplayer.demo.player; package com.google.android.exoplayer.demo.player;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.audio.AudioCapabilities;
...@@ -30,6 +31,7 @@ import com.google.android.exoplayer.upstream.DefaultBandwidthMeter; ...@@ -30,6 +31,7 @@ import com.google.android.exoplayer.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer.upstream.DefaultUriDataSource; import com.google.android.exoplayer.upstream.DefaultUriDataSource;
import android.content.Context; import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.net.Uri; import android.net.Uri;
...@@ -62,10 +64,11 @@ public class ExtractorRendererBuilder implements RendererBuilder { ...@@ -62,10 +64,11 @@ public class ExtractorRendererBuilder implements RendererBuilder {
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator,
BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE); BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context,
sampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, player.getMainHandler(), sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,
player, 50); player.getMainHandler(), player, 50);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource, 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, TrackRenderer textRenderer = new TextTrackRenderer(sampleSource, player,
player.getMainHandler().getLooper()); player.getMainHandler().getLooper());
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player;
import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException; import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
...@@ -40,6 +41,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; ...@@ -40,6 +41,7 @@ import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback; import com.google.android.exoplayer.util.ManifestFetcher.ManifestCallback;
import android.content.Context; import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.os.Handler; import android.os.Handler;
...@@ -149,9 +151,11 @@ public class HlsRendererBuilder implements RendererBuilder { ...@@ -149,9 +151,11 @@ public class HlsRendererBuilder implements RendererBuilder {
HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl, HlsSampleSource sampleSource = new HlsSampleSource(chunkSource, loadControl,
BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO); BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, DemoPlayer.TYPE_VIDEO);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, 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, 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<Map<String, Object>> id3Renderer = new MetadataTrackRenderer<>( MetadataTrackRenderer<Map<String, Object>> id3Renderer = new MetadataTrackRenderer<>(
sampleSource, new Id3Parser(), player, mainHandler.getLooper()); sampleSource, new Id3Parser(), player, mainHandler.getLooper());
Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player, Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player,
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.player;
import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities; import com.google.android.exoplayer.audio.AudioCapabilities;
...@@ -44,6 +45,7 @@ import com.google.android.exoplayer.util.ManifestFetcher; ...@@ -44,6 +45,7 @@ import com.google.android.exoplayer.util.ManifestFetcher;
import com.google.android.exoplayer.util.Util; import com.google.android.exoplayer.util.Util;
import android.content.Context; import android.content.Context;
import android.media.AudioManager;
import android.media.MediaCodec; import android.media.MediaCodec;
import android.os.Handler; import android.os.Handler;
...@@ -164,8 +166,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder { ...@@ -164,8 +166,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder {
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
DemoPlayer.TYPE_VIDEO); DemoPlayer.TYPE_VIDEO);
TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource, TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(context, videoSampleSource,
MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000, drmSessionManager, true, mainHandler, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 5000,
player, 50); drmSessionManager, true, mainHandler, player, 50);
// Build the audio renderer. // Build the audio renderer.
DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource audioDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
...@@ -176,7 +178,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder { ...@@ -176,7 +178,8 @@ public class SmoothStreamingRendererBuilder implements RendererBuilder {
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
DemoPlayer.TYPE_AUDIO); DemoPlayer.TYPE_AUDIO);
TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource, 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. // Build the text renderer.
DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent); DataSource textDataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.vp9opus; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer.demo.vp9opus;
import com.google.android.exoplayer.DefaultLoadControl; import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.SampleSource; import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.ChunkSampleSource;
...@@ -133,7 +134,8 @@ public class DashRendererBuilder implements ManifestCallback<MediaPresentationDe ...@@ -133,7 +134,8 @@ public class DashRendererBuilder implements ManifestCallback<MediaPresentationDe
if (audioRepresentationIsOpus) { if (audioRepresentationIsOpus) {
audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource); audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource);
} else { } else {
audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource); audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource,
MediaCodecSelector.DEFAULT);
} }
} }
......
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
import android.media.MediaCodec;
/**
* Selector of {@link MediaCodec} instances.
*/
public interface MediaCodecSelector {
/**
* Default implementation of {@link MediaCodecSelector}.
*/
public static final MediaCodecSelector DEFAULT = new MediaCodecSelector() {
/**
* The name for the raw (passthrough) decoder OMX component.
*/
private static final String RAW_DECODER_NAME = "OMX.google.raw.decoder";
@Override
public DecoderInfo getDecoderInfo(MediaFormat format, boolean requiresSecureDecoder)
throws DecoderQueryException {
return MediaCodecUtil.getDecoderInfo(format.mimeType, requiresSecureDecoder);
}
@Override
public String getPassthroughDecoderName() throws DecoderQueryException {
// TODO: Return null if the raw decoder doesn't exist.
return RAW_DECODER_NAME;
}
};
/**
* Selects a decoder to instantiate for a given format.
*
* @param format 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.
*/
DecoderInfo getDecoderInfo(MediaFormat format, boolean requiresSecureDecoder)
throws DecoderQueryException;
/**
* Gets the name of a decoder suitable for audio passthrough.
*
* @return The name of a decoder suitable for audio passthrough, or null if no suitable decoder
* exists.
* @throws DecoderQueryException Thrown if there was an error querying decoders.
*/
String getPassthroughDecoderName() throws DecoderQueryException;
}
...@@ -194,6 +194,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -194,6 +194,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
public final CodecCounters codecCounters; public final CodecCounters codecCounters;
private final MediaCodecSelector mediaCodecSelector;
private final DrmSessionManager drmSessionManager; private final DrmSessionManager drmSessionManager;
private final boolean playClearSamplesWithoutKeys; private final boolean playClearSamplesWithoutKeys;
private final SampleHolder sampleHolder; private final SampleHolder sampleHolder;
...@@ -229,21 +230,24 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -229,21 +230,24 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
/** /**
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
* @param mediaCodecSelector A decoder selector.
* @param drmSessionManager For use with encrypted media. May be null if support for encrypted * @param drmSessionManager For use with encrypted media. May be null if support for encrypted
* media is not required. * media is not required.
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions. * @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
* For example a media file may start with a short clear region so as to allow playback to * For example a media file may start with a short clear region so as to allow playback to
* begin in parallel with key acquisision. This parameter specifies whether the renderer is * begin in parallel with key acquisition. This parameter specifies whether the renderer is
* permitted to play clear regions of encrypted media files before {@code drmSessionManager} * permitted to play clear regions of encrypted media files before {@code drmSessionManager}
* has obtained the keys necessary to decrypt encrypted regions of the media. * has obtained the keys necessary to decrypt encrypted regions of the media.
* @param eventHandler A handler to use when delivering events to {@code eventListener}. May be * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be
* null if delivery of events is not required. * null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required. * @param eventListener A listener of events. May be null if delivery of events is not required.
*/ */
public MediaCodecTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager, public MediaCodecTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) { DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
Handler eventHandler, EventListener eventListener) {
super(source); super(source);
Assertions.checkState(Util.SDK_INT >= 16); Assertions.checkState(Util.SDK_INT >= 16);
this.mediaCodecSelector = Assertions.checkNotNull(mediaCodecSelector);
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys; this.playClearSamplesWithoutKeys = playClearSamplesWithoutKeys;
this.eventHandler = eventHandler; this.eventHandler = eventHandler;
...@@ -264,18 +268,35 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -264,18 +268,35 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
seekToInternal(); seekToInternal();
} }
@Override
protected final boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException {
return handlesTrack(mediaCodecSelector, mediaFormat);
}
/**
* Returns whether this renderer is capable of handling the provided track.
*
* @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 abstract boolean handlesTrack(MediaCodecSelector mediaCodecSelector,
MediaFormat mediaFormat) throws DecoderQueryException;
/** /**
* Returns a {@link DecoderInfo} for decoding media in the specified MIME type. * Returns a {@link DecoderInfo} for a given format.
* *
* @param mimeType The type of media to decode. * @param mediaCodecSelector The decoder selector.
* @param requiresSecureDecoder Whether a secure decoder is needed for decoding {@code mimeType}. * @param mediaFormat The format for which a decoder is required.
* @return {@link DecoderInfo} for decoding media in the specified MIME type, or {@code null} if * @param requiresSecureDecoder Whether a secure decoder is required.
* no suitable decoder is available. * @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. * @throws DecoderQueryException Thrown if there was an error querying decoders.
*/ */
protected DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder) protected DecoderInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector,
throws DecoderQueryException { MediaFormat mediaFormat, boolean requiresSecureDecoder) throws DecoderQueryException {
return MediaCodecUtil.getDecoderInfo(mimeType, requiresSecureDecoder); return mediaCodecSelector.getDecoderInfo(format, requiresSecureDecoder);
} }
/** /**
...@@ -283,12 +304,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -283,12 +304,11 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
* wish to configure the codec with a non-null surface. * wish to configure the codec with a non-null surface.
* *
* @param codec The {@link MediaCodec} to configure. * @param codec The {@link MediaCodec} to configure.
* @param codecName The name of the codec.
* @param codecIsAdaptive Whether the codec is adaptive. * @param codecIsAdaptive Whether the codec is adaptive.
* @param format The format for which the codec is being configured. * @param format The format for which the codec is being configured.
* @param crypto For drm protected playbacks, a {@link MediaCrypto} to use for decryption. * @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) { android.media.MediaFormat format, MediaCrypto crypto) {
codec.configure(format, null, crypto, 0); codec.configure(format, null, crypto, 0);
} }
...@@ -325,7 +345,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -325,7 +345,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
DecoderInfo decoderInfo = null; DecoderInfo decoderInfo = null;
try { try {
decoderInfo = getDecoderInfo(mimeType, requiresSecureDecoder); decoderInfo = getDecoderInfo(mediaCodecSelector, format, requiresSecureDecoder);
} catch (DecoderQueryException e) { } catch (DecoderQueryException e) {
notifyAndThrowDecoderInitError(new DecoderInitializationException(format, e, notifyAndThrowDecoderInitError(new DecoderInitializationException(format, e,
requiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR)); requiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR));
...@@ -346,8 +366,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -346,8 +366,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
codec = MediaCodec.createByCodecName(codecName); codec = MediaCodec.createByCodecName(codecName);
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("configureCodec"); TraceUtil.beginSection("configureCodec");
configureCodec(codec, codecName, codecIsAdaptive, format.getFrameworkMediaFormatV16(), configureCodec(codec, decoderInfo.adaptive, format.getFrameworkMediaFormatV16(), mediaCrypto);
mediaCrypto);
TraceUtil.endSection(); TraceUtil.endSection();
TraceUtil.beginSection("codec.start()"); TraceUtil.beginSection("codec.start()");
codec.start(); codec.start();
......
...@@ -128,29 +128,34 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -128,29 +128,34 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
/** /**
* @param context A context. * @param context A context.
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
* @param mediaCodecSelector A decoder selector.
* @param videoScalingMode The scaling mode to pass to * @param videoScalingMode The scaling mode to pass to
* {@link MediaCodec#setVideoScalingMode(int)}. * {@link MediaCodec#setVideoScalingMode(int)}.
*/ */
public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode) { public MediaCodecVideoTrackRenderer(Context context, SampleSource source,
this(context, source, videoScalingMode, 0); MediaCodecSelector mediaCodecSelector, int videoScalingMode) {
this(context, source, mediaCodecSelector, videoScalingMode, 0);
} }
/** /**
* @param context A context. * @param context A context.
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
* @param mediaCodecSelector A decoder selector.
* @param videoScalingMode The scaling mode to pass to * @param videoScalingMode The scaling mode to pass to
* {@link MediaCodec#setVideoScalingMode(int)}. * {@link MediaCodec#setVideoScalingMode(int)}.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
* can attempt to seamlessly join an ongoing playback. * can attempt to seamlessly join an ongoing playback.
*/ */
public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, public MediaCodecVideoTrackRenderer(Context context, SampleSource source,
long allowedJoiningTimeMs) { MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs) {
this(context, source, videoScalingMode, allowedJoiningTimeMs, null, null, -1); this(context, source, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, null,
-1);
} }
/** /**
* @param context A context. * @param context A context.
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
* @param mediaCodecSelector A decoder selector.
* @param videoScalingMode The scaling mode to pass to * @param videoScalingMode The scaling mode to pass to
* {@link MediaCodec#setVideoScalingMode(int)}. * {@link MediaCodec#setVideoScalingMode(int)}.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
...@@ -161,16 +166,17 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -161,16 +166,17 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
* @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between * @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between
* invocations of {@link EventListener#onDroppedFrames(int, long)}. * invocations of {@link EventListener#onDroppedFrames(int, long)}.
*/ */
public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, public MediaCodecVideoTrackRenderer(Context context, SampleSource source,
long allowedJoiningTimeMs, Handler eventHandler, EventListener eventListener, MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs,
int maxDroppedFrameCountToNotify) { Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) {
this(context, source, videoScalingMode, allowedJoiningTimeMs, null, false, eventHandler, this(context, source, mediaCodecSelector, videoScalingMode, allowedJoiningTimeMs, null, false,
eventListener, maxDroppedFrameCountToNotify); eventHandler, eventListener, maxDroppedFrameCountToNotify);
} }
/** /**
* @param context A context. * @param context A context.
* @param source The upstream source from which the renderer obtains samples. * @param source The upstream source from which the renderer obtains samples.
* @param mediaCodecSelector A decoder selector.
* @param videoScalingMode The scaling mode to pass to * @param videoScalingMode The scaling mode to pass to
* {@link MediaCodec#setVideoScalingMode(int)}. * {@link MediaCodec#setVideoScalingMode(int)}.
* @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer
...@@ -188,11 +194,12 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -188,11 +194,12 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
* @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between * @param maxDroppedFrameCountToNotify The maximum number of frames that can be dropped between
* invocations of {@link EventListener#onDroppedFrames(int, long)}. * invocations of {@link EventListener#onDroppedFrames(int, long)}.
*/ */
public MediaCodecVideoTrackRenderer(Context context, SampleSource source, int videoScalingMode, public MediaCodecVideoTrackRenderer(Context context, SampleSource source,
long allowedJoiningTimeMs, DrmSessionManager drmSessionManager, MediaCodecSelector mediaCodecSelector, int videoScalingMode, long allowedJoiningTimeMs,
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener, DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
int maxDroppedFrameCountToNotify) { Handler eventHandler, EventListener eventListener, int maxDroppedFrameCountToNotify) {
super(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener); super(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
eventListener);
this.frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context); this.frameReleaseTimeHelper = new VideoFrameReleaseTimeHelper(context);
this.videoScalingMode = videoScalingMode; this.videoScalingMode = videoScalingMode;
this.allowedJoiningTimeUs = allowedJoiningTimeMs * 1000; this.allowedJoiningTimeUs = allowedJoiningTimeMs * 1000;
...@@ -209,11 +216,11 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -209,11 +216,11 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
} }
@Override @Override
protected boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException { protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat)
// TODO: Use MediaCodecList.findDecoderForFormat on API 23. throws DecoderQueryException {
String mimeType = mediaFormat.mimeType; String mimeType = mediaFormat.mimeType;
return MimeTypes.isVideo(mimeType) && (MimeTypes.VIDEO_UNKNOWN.equals(mimeType) return MimeTypes.isVideo(mimeType) && (MimeTypes.VIDEO_UNKNOWN.equals(mimeType)
|| MediaCodecUtil.getDecoderInfo(mimeType, false) != null); || mediaCodecSelector.getDecoderInfo(mediaFormat, false) != null);
} }
@Override @Override
...@@ -316,7 +323,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -316,7 +323,7 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
// Override configureCodec to provide the surface. // Override configureCodec to provide the surface.
@Override @Override
protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive, protected void configureCodec(MediaCodec codec, boolean codecIsAdaptive,
android.media.MediaFormat format, MediaCrypto crypto) { android.media.MediaFormat format, MediaCrypto crypto) {
maybeSetMaxInputSize(format, codecIsAdaptive); maybeSetMaxInputSize(format, codecIsAdaptive);
codec.configure(format, surface, crypto, 0); codec.configure(format, surface, crypto, 0);
......
...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.DefaultLoadControl; ...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.DefaultLoadControl;
import com.google.android.exoplayer.ExoPlayer; import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.LoadControl; import com.google.android.exoplayer.LoadControl;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecSelector;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer; import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
import com.google.android.exoplayer.TrackRenderer; import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.chunk.ChunkSampleSource; import com.google.android.exoplayer.chunk.ChunkSampleSource;
...@@ -327,7 +328,8 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit ...@@ -327,7 +328,8 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, VIDEO_EVENT_ID, VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, VIDEO_EVENT_ID,
MIN_LOADABLE_RETRY_COUNT); MIN_LOADABLE_RETRY_COUNT);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(host, MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(host,
videoSampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, 0, handler, logger, 50); videoSampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
0, handler, logger, 50);
videoCounters = videoRenderer.codecCounters; videoCounters = videoRenderer.codecCounters;
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface); player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
...@@ -341,7 +343,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit ...@@ -341,7 +343,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, AUDIO_EVENT_ID, AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, AUDIO_EVENT_ID,
MIN_LOADABLE_RETRY_COUNT); MIN_LOADABLE_RETRY_COUNT);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer( MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
audioSampleSource, handler, logger); audioSampleSource, MediaCodecSelector.DEFAULT, handler, logger);
audioCounters = audioRenderer.codecCounters; audioCounters = audioRenderer.codecCounters;
TrackRenderer[] renderers = new TrackRenderer[RENDERER_COUNT]; TrackRenderer[] renderers = new TrackRenderer[RENDERER_COUNT];
......
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