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
This commit is contained in:
parent
8d6c4b8eb5
commit
7fbffc873c
@ -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);
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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<Map<String, Object>> id3Renderer = new MetadataTrackRenderer<>(
|
||||
sampleSource, new Id3Parser(), player, mainHandler.getLooper());
|
||||
Eia608TrackRenderer closedCaptionRenderer = new Eia608TrackRenderer(sampleSource, player,
|
||||
|
@ -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);
|
||||
|
@ -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<MediaPresentationDe
|
||||
if (audioRepresentationIsOpus) {
|
||||
audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource);
|
||||
} else {
|
||||
audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource);
|
||||
audioRenderer = new MediaCodecAudioTrackRenderer(audioSampleSource,
|
||||
MediaCodecSelector.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,14 +86,10 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
*/
|
||||
public static final int MSG_SET_PLAYBACK_PARAMS = 2;
|
||||
|
||||
/**
|
||||
* The name for the raw (passthrough) decoder OMX component.
|
||||
*/
|
||||
private static final String RAW_DECODER_NAME = "OMX.google.raw.decoder";
|
||||
|
||||
private final EventListener eventListener;
|
||||
private final AudioTrack audioTrack;
|
||||
|
||||
private boolean passthroughEnabled;
|
||||
private android.media.MediaFormat passthroughMediaFormat;
|
||||
private int audioSessionId;
|
||||
private long currentPositionUs;
|
||||
@ -104,13 +100,15 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param mediaCodecSelector A decoder selector.
|
||||
*/
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source) {
|
||||
this(source, null, true);
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector) {
|
||||
this(source, mediaCodecSelector, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param mediaCodecSelector A decoder selector.
|
||||
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||
* content is not required.
|
||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
||||
@ -119,24 +117,26 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
* permitted to play clear regions of encrypted media files before {@code drmSessionManager}
|
||||
* has obtained the keys necessary to decrypt encrypted regions of the media.
|
||||
*/
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys) {
|
||||
this(source, drmSessionManager, playClearSamplesWithoutKeys, null, null);
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys) {
|
||||
this(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param mediaCodecSelector A decoder selector.
|
||||
* @param eventHandler A handler to use when delivering events to {@code eventListener}. 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 MediaCodecAudioTrackRenderer(SampleSource source, Handler eventHandler,
|
||||
EventListener eventListener) {
|
||||
this(source, null, true, eventHandler, eventListener);
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||
Handler eventHandler, EventListener eventListener) {
|
||||
this(source, mediaCodecSelector, null, true, eventHandler, eventListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param mediaCodecSelector A decoder selector.
|
||||
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||
* content is not required.
|
||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
||||
@ -148,36 +148,16 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
* 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 MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
|
||||
this(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||
* content is not required.
|
||||
* @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
|
||||
* 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}
|
||||
* 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
|
||||
* 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 audioCapabilities The audio capabilities for playback on this device. May be null if the
|
||||
* default capabilities (no encoded audio passthrough support) should be assumed.
|
||||
*/
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener,
|
||||
AudioCapabilities audioCapabilities) {
|
||||
this(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener,
|
||||
audioCapabilities, AudioManager.STREAM_MUSIC);
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||
Handler eventHandler, EventListener eventListener) {
|
||||
this(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
|
||||
eventListener, null, AudioManager.STREAM_MUSIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source The upstream source from which the renderer obtains samples.
|
||||
* @param mediaCodecSelector A decoder selector.
|
||||
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||
* content is not required.
|
||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
||||
@ -192,20 +172,38 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
* default capabilities (no encoded audio passthrough support) should be assumed.
|
||||
* @param streamType The type of audio stream for the {@link AudioTrack}.
|
||||
*/
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener,
|
||||
AudioCapabilities audioCapabilities, int streamType) {
|
||||
super(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener);
|
||||
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||
Handler eventHandler, EventListener eventListener, AudioCapabilities audioCapabilities,
|
||||
int streamType) {
|
||||
super(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
|
||||
eventListener);
|
||||
this.eventListener = eventListener;
|
||||
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||
this.audioTrack = new AudioTrack(audioCapabilities, streamType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder)
|
||||
protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat)
|
||||
throws DecoderQueryException {
|
||||
return allowPassthrough(mimeType) ? new DecoderInfo(RAW_DECODER_NAME, true)
|
||||
: super.getDecoderInfo(mimeType, requiresSecureDecoder);
|
||||
String mimeType = mediaFormat.mimeType;
|
||||
return MimeTypes.isAudio(mimeType) && (MimeTypes.AUDIO_UNKNOWN.equals(mimeType)
|
||||
|| (allowPassthrough(mimeType) && mediaCodecSelector.getPassthroughDecoderName() != null)
|
||||
|| mediaCodecSelector.getDecoderInfo(mediaFormat, false) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DecoderInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, MediaFormat format,
|
||||
boolean requiresSecureDecoder) throws DecoderQueryException {
|
||||
if (allowPassthrough(format.mimeType)) {
|
||||
String passthroughDecoderName = mediaCodecSelector.getPassthroughDecoderName();
|
||||
if (passthroughDecoderName != null) {
|
||||
passthroughEnabled = true;
|
||||
return new DecoderInfo(passthroughDecoderName, false);
|
||||
}
|
||||
}
|
||||
passthroughEnabled = false;
|
||||
return super.getDecoderInfo(mediaCodecSelector, format, requiresSecureDecoder);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,10 +219,10 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureCodec(MediaCodec codec, String codecName, boolean codecIsAdaptive,
|
||||
protected void configureCodec(MediaCodec codec, boolean codecIsAdaptive,
|
||||
android.media.MediaFormat format, android.media.MediaCrypto crypto) {
|
||||
String mimeType = format.getString(android.media.MediaFormat.KEY_MIME);
|
||||
if (RAW_DECODER_NAME.equals(codecName) && !MimeTypes.AUDIO_RAW.equals(mimeType)) {
|
||||
if (passthroughEnabled) {
|
||||
// Override the MIME type used to configure the codec if we are using a passthrough decoder.
|
||||
format.setString(android.media.MediaFormat.KEY_MIME, MimeTypes.AUDIO_RAW);
|
||||
codec.configure(format, null, crypto, 0);
|
||||
@ -241,14 +239,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean handlesTrack(MediaFormat mediaFormat) throws DecoderQueryException {
|
||||
// TODO: Use MediaCodecList.findDecoderForFormat on API 23.
|
||||
String mimeType = mediaFormat.mimeType;
|
||||
return MimeTypes.isAudio(mimeType) && (MimeTypes.AUDIO_UNKNOWN.equals(mimeType)
|
||||
|| allowPassthrough(mimeType) || MediaCodecUtil.getDecoderInfo(mimeType, false) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||
throws ExoPlaybackException {
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
public final CodecCounters codecCounters;
|
||||
|
||||
private final MediaCodecSelector mediaCodecSelector;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final SampleHolder sampleHolder;
|
||||
@ -229,21 +230,24 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
|
||||
|
||||
/**
|
||||
* @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
|
||||
* media is not required.
|
||||
* @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
|
||||
* 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}
|
||||
* 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
|
||||
* 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,
|
||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
|
||||
public MediaCodecTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||
Handler eventHandler, EventListener eventListener) {
|
||||
super(source);
|
||||
Assertions.checkState(Util.SDK_INT >= 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();
|
||||
|
@ -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);
|
||||
|
@ -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<HostActivit
|
||||
VIDEO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, VIDEO_EVENT_ID,
|
||||
MIN_LOADABLE_RETRY_COUNT);
|
||||
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;
|
||||
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
|
||||
|
||||
@ -341,7 +343,7 @@ public final class DashTest extends ActivityInstrumentationTestCase2<HostActivit
|
||||
AUDIO_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, handler, logger, AUDIO_EVENT_ID,
|
||||
MIN_LOADABLE_RETRY_COUNT);
|
||||
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
|
||||
audioSampleSource, handler, logger);
|
||||
audioSampleSource, MediaCodecSelector.DEFAULT, handler, logger);
|
||||
audioCounters = audioRenderer.codecCounters;
|
||||
|
||||
TrackRenderer[] renderers = new TrackRenderer[RENDERER_COUNT];
|
||||
|
Loading…
x
Reference in New Issue
Block a user