mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
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
10 changed files with 210 additions and 105 deletions
|
|
@ -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;
|
||||||
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 {
|
||||||
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 {
|
||||||
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 @@
|
||||||
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;
|
||||||
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 {
|
||||||
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;
|
||||||
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;
|
||||||
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 {
|
||||||
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;
|
||||||
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;
|
||||||
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 {
|
||||||
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 {
|
||||||
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;
|
||||||
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
|
||||||
if (audioRepresentationIsOpus) {
|
if (audioRepresentationIsOpus) {
|
||||||
audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource);
|
audioRenderer = new LibopusAudioTrackRenderer(audioSampleSource);
|
||||||
} else {
|
} 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;
|
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 EventListener eventListener;
|
||||||
private final AudioTrack audioTrack;
|
private final AudioTrack audioTrack;
|
||||||
|
|
||||||
|
private boolean passthroughEnabled;
|
||||||
private android.media.MediaFormat passthroughMediaFormat;
|
private android.media.MediaFormat passthroughMediaFormat;
|
||||||
private int audioSessionId;
|
private int audioSessionId;
|
||||||
private long currentPositionUs;
|
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 source The upstream source from which the renderer obtains samples.
|
||||||
|
* @param mediaCodecSelector A decoder selector.
|
||||||
*/
|
*/
|
||||||
public MediaCodecAudioTrackRenderer(SampleSource source) {
|
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector) {
|
||||||
this(source, null, true);
|
this(source, mediaCodecSelector, null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 content. May be null if support for encrypted
|
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||||
* content is not required.
|
* content is not required.
|
||||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
* @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}
|
* 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.
|
||||||
*/
|
*/
|
||||||
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||||
boolean playClearSamplesWithoutKeys) {
|
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys) {
|
||||||
this(source, drmSessionManager, playClearSamplesWithoutKeys, null, null);
|
this(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 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 MediaCodecAudioTrackRenderer(SampleSource source, Handler eventHandler,
|
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||||
EventListener eventListener) {
|
Handler eventHandler, EventListener eventListener) {
|
||||||
this(source, null, true, eventHandler, eventListener);
|
this(source, mediaCodecSelector, null, true, eventHandler, eventListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 content. May be null if support for encrypted
|
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||||
* content is not required.
|
* content is not required.
|
||||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
* @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.
|
* 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 MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener) {
|
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||||
this(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener,
|
Handler eventHandler, EventListener eventListener) {
|
||||||
null);
|
this(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
|
||||||
}
|
eventListener, null, AudioManager.STREAM_MUSIC);
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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 content. May be null if support for encrypted
|
* @param drmSessionManager For use with encrypted content. May be null if support for encrypted
|
||||||
* content is not required.
|
* content is not required.
|
||||||
* @param playClearSamplesWithoutKeys Encrypted media may contain clear (un-encrypted) regions.
|
* @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.
|
* default capabilities (no encoded audio passthrough support) should be assumed.
|
||||||
* @param streamType The type of audio stream for the {@link AudioTrack}.
|
* @param streamType The type of audio stream for the {@link AudioTrack}.
|
||||||
*/
|
*/
|
||||||
public MediaCodecAudioTrackRenderer(SampleSource source, DrmSessionManager drmSessionManager,
|
public MediaCodecAudioTrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
|
||||||
boolean playClearSamplesWithoutKeys, Handler eventHandler, EventListener eventListener,
|
DrmSessionManager drmSessionManager, boolean playClearSamplesWithoutKeys,
|
||||||
AudioCapabilities audioCapabilities, int streamType) {
|
Handler eventHandler, EventListener eventListener, AudioCapabilities audioCapabilities,
|
||||||
super(source, drmSessionManager, playClearSamplesWithoutKeys, eventHandler, eventListener);
|
int streamType) {
|
||||||
|
super(source, mediaCodecSelector, drmSessionManager, playClearSamplesWithoutKeys, eventHandler,
|
||||||
|
eventListener);
|
||||||
this.eventListener = eventListener;
|
this.eventListener = eventListener;
|
||||||
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
this.audioSessionId = AudioTrack.SESSION_ID_NOT_SET;
|
||||||
this.audioTrack = new AudioTrack(audioCapabilities, streamType);
|
this.audioTrack = new AudioTrack(audioCapabilities, streamType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder)
|
protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat)
|
||||||
throws DecoderQueryException {
|
throws DecoderQueryException {
|
||||||
return allowPassthrough(mimeType) ? new DecoderInfo(RAW_DECODER_NAME, true)
|
String mimeType = mediaFormat.mimeType;
|
||||||
: super.getDecoderInfo(mimeType, requiresSecureDecoder);
|
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
|
@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) {
|
android.media.MediaFormat format, android.media.MediaCrypto crypto) {
|
||||||
String mimeType = format.getString(android.media.MediaFormat.KEY_MIME);
|
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.
|
// 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);
|
format.setString(android.media.MediaFormat.KEY_MIME, MimeTypes.AUDIO_RAW);
|
||||||
codec.configure(format, null, crypto, 0);
|
codec.configure(format, null, crypto, 0);
|
||||||
|
|
@ -241,14 +239,6 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
|
||||||
return this;
|
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
|
@Override
|
||||||
protected void onEnabled(int track, long positionUs, boolean joining)
|
protected void onEnabled(int track, long positionUs, boolean joining)
|
||||||
throws ExoPlaybackException {
|
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;
|
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
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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
|
||||||
seekToInternal();
|
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 mediaCodecSelector The decoder selector.
|
||||||
* @param requiresSecureDecoder Whether a secure decoder is needed for decoding {@code mimeType}.
|
* @param mediaFormat The format of the track.
|
||||||
* @return {@link DecoderInfo} for decoding media in the specified MIME type, or {@code null} if
|
* @return True if the renderer can handle the track, false otherwise.
|
||||||
* no suitable decoder is available.
|
|
||||||
* @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 abstract boolean handlesTrack(MediaCodecSelector mediaCodecSelector,
|
||||||
throws DecoderQueryException {
|
MediaFormat mediaFormat) throws DecoderQueryException;
|
||||||
return MediaCodecUtil.getDecoderInfo(mimeType, requiresSecureDecoder);
|
|
||||||
|
/**
|
||||||
|
* 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.
|
* 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
|
||||||
|
|
||||||
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
|
||||||
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 {
|
||||||
/**
|
/**
|
||||||
* @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 {
|
||||||
* @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 {
|
||||||
* @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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 {
|
||||||
|
|
||||||
// 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;
|
||||||
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
|
||||||
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
|
||||||
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];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue