Commit 335bb0af by olly Committed by Oliver Woodman

Implement decoder capability checks in MediaCodecTrackRenderers.

[Step 4 - Partial, of []

- The capabilities checks previously performed in VideoFormatSelectorUtil
  are now performed in MediaCodecVideoTrackRenderer. This means they'll be
  useful for non-chunk use cases (e.g. when using ExtractorSampleSource).
- Added capabilities checks for audio in MediaCodecAudioTrackRenderer. We
  didn't check audio capabilities previously.
- Added functionality to allow a TrackRenderer to indicate the extent of
  its adaptive support.

The idea here is that a TrackSelector (to be introduced) will have access to:

(a) TrackGroups from the SampleSource that indicate whether they support
adaptive playbacks and the formats of each individual track.
(b) TrackRenderers that indicate whether they support adaptive playbacks as
well as how capable they are of rendering formats of individual tracks.

This is everything that a TrackSelector needs from the player components in
order to decide how to wire things up. Note that a TrackSelector may opt to
treat FORMAT_EXCEEDS_CAPABILITIES as FORMAT_HANDLED at its own risk, if it
thinks that it (or the user) knows better. This is a request that we've seen
from third parties for better handling cases where capabilities aren't
accurately reported by the underlying platform.
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=114427428
parent 6bc52262
...@@ -15,9 +15,17 @@ ...@@ -15,9 +15,17 @@
*/ */
package com.google.android.exoplayer; package com.google.android.exoplayer;
import com.google.android.exoplayer.util.Util;
import android.annotation.TargetApi;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
/** /**
* Contains information about a media decoder. * Contains information about a media decoder.
*/ */
@TargetApi(16)
public final class DecoderInfo { public final class DecoderInfo {
/** /**
...@@ -36,13 +44,120 @@ public final class DecoderInfo { ...@@ -36,13 +44,120 @@ public final class DecoderInfo {
*/ */
public final boolean adaptive; public final boolean adaptive;
private final CodecCapabilities capabilities;
/**
* @param name The name of the decoder.
*/
/* package */ DecoderInfo(String name) {
this.name = name;
this.adaptive = false;
this.capabilities = null;
}
/** /**
* @param name The name of the decoder. * @param name The name of the decoder.
* @param adaptive Whether the decoder is adaptive. * @param capabilities The capabilities of the decoder.
*/ */
/* package */ DecoderInfo(String name, boolean adaptive) { /* package */ DecoderInfo(String name, CodecCapabilities capabilities) {
this.name = name; this.name = name;
this.adaptive = adaptive; this.capabilities = capabilities;
adaptive = isAdaptive(capabilities);
}
/**
* The profile levels supported by the decoder.
*
* @return The profile levels supported by the decoder.
*/
public CodecProfileLevel[] getProfileLevels() {
return capabilities == null || capabilities.profileLevels == null ? new CodecProfileLevel[0]
: capabilities.profileLevels;
}
/**
* Whether the decoder supports video with a specified width and height.
* <p>
* Must not be called if the device SDK version is less than 21.
*
* @param width Width in pixels.
* @param height Height in pixels.
* @return Whether the decoder supports video with the given width and height.
*/
@TargetApi(21)
public boolean isVideoSizeSupportedV21(int width, int height) {
if (capabilities == null) {
return false;
}
MediaCodecInfo.VideoCapabilities videoCapabilities = capabilities.getVideoCapabilities();
return videoCapabilities != null && videoCapabilities.isSizeSupported(width, height);
}
/**
* Whether the decoder supports video with a given width, height and frame rate.
* <p>
* Must not be called if the device SDK version is less than 21.
*
* @param width Width in pixels.
* @param height Height in pixels.
* @param frameRate Frame rate in frames per second.
* @return Whether the decoder supports video with the given width, height and frame rate.
*/
@TargetApi(21)
public boolean isVideoSizeAndRateSupportedV21(int width, int height, double frameRate) {
if (capabilities == null) {
return false;
}
MediaCodecInfo.VideoCapabilities videoCapabilities = capabilities.getVideoCapabilities();
return videoCapabilities != null && videoCapabilities.areSizeAndRateSupported(width, height,
frameRate);
}
/**
* Whether the decoder supports audio with a given sample rate.
* <p>
* Must not be called if the device SDK version is less than 21.
*
* @param sampleRate The sample rate in Hz.
* @return Whether the decoder supports audio with the given sample rate.
*/
@TargetApi(21)
public boolean isAudioSampleRateSupportedV21(int sampleRate) {
if (capabilities == null) {
return false;
}
MediaCodecInfo.AudioCapabilities audioCapabilities = capabilities.getAudioCapabilities();
return audioCapabilities != null && audioCapabilities.isSampleRateSupported(sampleRate);
}
/**
* Whether the decoder supports audio with a given channel count.
* <p>
* Must not be called if the device SDK version is less than 21.
*
* @param channelCount The channel count.
* @return Whether the decoder supports audio with the given channel count.
*/
@TargetApi(21)
public boolean isAudioChannelCountSupportedV21(int channelCount) {
if (capabilities == null) {
return false;
}
MediaCodecInfo.AudioCapabilities audioCapabilities = capabilities.getAudioCapabilities();
return audioCapabilities != null && audioCapabilities.getMaxInputChannelCount() >= channelCount;
}
private static boolean isAdaptive(CodecCapabilities capabilities) {
if (Util.SDK_INT >= 19) {
return isAdaptiveV19(capabilities);
} else {
return false;
}
}
@TargetApi(19)
private static boolean isAdaptiveV19(CodecCapabilities capabilities) {
return capabilities.isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback);
} }
} }
...@@ -21,8 +21,8 @@ package com.google.android.exoplayer; ...@@ -21,8 +21,8 @@ package com.google.android.exoplayer;
public final class DummyTrackRenderer extends TrackRenderer { public final class DummyTrackRenderer extends TrackRenderer {
@Override @Override
protected boolean handlesTrack(MediaFormat mediaFormat) throws ExoPlaybackException { protected int supportsFormat(MediaFormat mediaFormat) throws ExoPlaybackException {
return false; return TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
} }
@Override @Override
......
...@@ -328,7 +328,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -328,7 +328,7 @@ import java.util.concurrent.atomic.AtomicInteger;
MediaFormat adaptiveTrackFormat = null; MediaFormat adaptiveTrackFormat = null;
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
MediaFormat trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex); MediaFormat trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex);
if (renderer.handlesTrack(trackFormat)) { if (renderer.supportsFormat(trackFormat) == TrackRenderer.FORMAT_HANDLED) {
adaptiveTrackIndices[adaptiveTrackIndexCount++] = trackIndex; adaptiveTrackIndices[adaptiveTrackIndexCount++] = trackIndex;
if (adaptiveTrackFormat == null) { if (adaptiveTrackFormat == null) {
adaptiveTrackFormat = trackFormat.copyAsAdaptive("auto"); adaptiveTrackFormat = trackFormat.copyAsAdaptive("auto");
...@@ -345,7 +345,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -345,7 +345,7 @@ import java.util.concurrent.atomic.AtomicInteger;
} }
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
MediaFormat trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex); MediaFormat trackFormat = source.getTrackGroup(groupIndex).getFormat(trackIndex);
if (renderer.handlesTrack(trackFormat)) { if (renderer.supportsFormat(trackFormat) == TrackRenderer.FORMAT_HANDLED) {
rendererTrackGroups[rendererTrackCount] = groupIndex; rendererTrackGroups[rendererTrackCount] = groupIndex;
rendererTrackIndices[rendererTrackCount] = new int[] {trackIndex}; rendererTrackIndices[rendererTrackCount] = new int[] {trackIndex};
rendererTrackFormats[rendererTrackCount++] = trackFormat; rendererTrackFormats[rendererTrackCount++] = trackFormat;
......
...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.audio.AudioCapabilities; ...@@ -20,6 +20,7 @@ import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioTrack; import com.google.android.exoplayer.audio.AudioTrack;
import com.google.android.exoplayer.drm.DrmSessionManager; import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.util.MimeTypes; import com.google.android.exoplayer.util.MimeTypes;
import com.google.android.exoplayer.util.Util;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.media.AudioManager; import android.media.AudioManager;
...@@ -179,12 +180,34 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem ...@@ -179,12 +180,34 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
} }
@Override @Override
protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat) protected int supportsFormat(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat)
throws DecoderQueryException { throws DecoderQueryException {
String mimeType = mediaFormat.mimeType; String mimeType = mediaFormat.mimeType;
return MimeTypes.isAudio(mimeType) && (MimeTypes.AUDIO_UNKNOWN.equals(mimeType) if (!MimeTypes.isAudio(mimeType)) {
|| (allowPassthrough(mimeType) && mediaCodecSelector.getPassthroughDecoderName() != null) return TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
|| mediaCodecSelector.getDecoderInfo(mediaFormat, false) != null); }
if (allowPassthrough(mimeType) && mediaCodecSelector.getPassthroughDecoderName() != null) {
return TrackRenderer.FORMAT_HANDLED;
}
// TODO[REFACTOR]: Propagate requiresSecureDecoder to this point. Note that we need to check
// that the drm session can make use of a secure decoder, as well as that a secure decoder
// exists.
DecoderInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mediaFormat.mimeType, false);
if (decoderInfo == null) {
return TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
}
if (Util.SDK_INT >= 21) {
// Note: We assume support in the case that the sampleRate or channelCount is unknown.
if (mediaFormat.sampleRate != MediaFormat.NO_VALUE
&& !decoderInfo.isAudioSampleRateSupportedV21(mediaFormat.sampleRate)) {
return TrackRenderer.FORMAT_EXCEEDS_CAPABILITIES;
}
if (mediaFormat.channelCount != MediaFormat.NO_VALUE
&& !decoderInfo.isAudioChannelCountSupportedV21(mediaFormat.channelCount)) {
return TrackRenderer.FORMAT_EXCEEDS_CAPABILITIES;
}
}
return TrackRenderer.FORMAT_HANDLED;
} }
@Override @Override
...@@ -194,7 +217,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem ...@@ -194,7 +217,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
String passthroughDecoderName = mediaCodecSelector.getPassthroughDecoderName(); String passthroughDecoderName = mediaCodecSelector.getPassthroughDecoderName();
if (passthroughDecoderName != null) { if (passthroughDecoderName != null) {
passthroughEnabled = true; passthroughEnabled = true;
return new DecoderInfo(passthroughDecoderName, false); return new DecoderInfo(passthroughDecoderName);
} }
} }
passthroughEnabled = false; passthroughEnabled = false;
......
...@@ -27,7 +27,7 @@ public interface MediaCodecSelector { ...@@ -27,7 +27,7 @@ public interface MediaCodecSelector {
/** /**
* Default implementation of {@link MediaCodecSelector}. * Default implementation of {@link MediaCodecSelector}.
*/ */
public static final MediaCodecSelector DEFAULT = new MediaCodecSelector() { MediaCodecSelector DEFAULT = new MediaCodecSelector() {
/** /**
* The name for the raw (passthrough) decoder OMX component. * The name for the raw (passthrough) decoder OMX component.
...@@ -35,9 +35,9 @@ public interface MediaCodecSelector { ...@@ -35,9 +35,9 @@ public interface MediaCodecSelector {
private static final String RAW_DECODER_NAME = "OMX.google.raw.decoder"; private static final String RAW_DECODER_NAME = "OMX.google.raw.decoder";
@Override @Override
public DecoderInfo getDecoderInfo(MediaFormat format, boolean requiresSecureDecoder) public DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder)
throws DecoderQueryException { throws DecoderQueryException {
return MediaCodecUtil.getDecoderInfo(format.mimeType, requiresSecureDecoder); return MediaCodecUtil.getDecoderInfo(mimeType, requiresSecureDecoder);
} }
@Override @Override
...@@ -49,15 +49,15 @@ public interface MediaCodecSelector { ...@@ -49,15 +49,15 @@ public interface MediaCodecSelector {
}; };
/** /**
* Selects a decoder to instantiate for a given format. * Selects a decoder to instantiate for a given mime type.
* *
* @param format The format for which a decoder is required. * @param mimeType The mime type for which a decoder is required.
* @param requiresSecureDecoder Whether a secure 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 * @return A {@link DecoderInfo} describing the decoder to instantiate, or null if no suitable
* decoder exists. * decoder exists.
* @throws DecoderQueryException Thrown if there was an error querying decoders. * @throws DecoderQueryException Thrown if there was an error querying decoders.
*/ */
DecoderInfo getDecoderInfo(MediaFormat format, boolean requiresSecureDecoder) DecoderInfo getDecoderInfo(String mimeType, boolean requiresSecureDecoder)
throws DecoderQueryException; throws DecoderQueryException;
/** /**
......
...@@ -262,23 +262,40 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -262,23 +262,40 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
} }
@Override @Override
protected final boolean handlesTrack(MediaFormat mediaFormat) throws ExoPlaybackException { protected final int supportsAdaptive(String mimeType) throws ExoPlaybackException {
if (mimeType == null) {
return TrackRenderer.ADAPTIVE_NOT_SEAMLESS;
}
try { try {
return handlesTrack(mediaCodecSelector, mediaFormat); // TODO[REFACTOR]: Propagate requiresSecureDecoder to this point.
DecoderInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mimeType, false);
return decoderInfo != null && decoderInfo.adaptive ? TrackRenderer.ADAPTIVE_SEAMLESS
: TrackRenderer.ADAPTIVE_NOT_SEAMLESS;
} catch (DecoderQueryException e) {
throw new ExoPlaybackException(e);
}
}
@Override
protected final int supportsFormat(MediaFormat mediaFormat) throws ExoPlaybackException {
try {
return supportsFormat(mediaCodecSelector, mediaFormat);
} catch (DecoderQueryException e) { } catch (DecoderQueryException e) {
throw new ExoPlaybackException(e); throw new ExoPlaybackException(e);
} }
} }
/** /**
* Returns whether this renderer is capable of handling the provided track. * Returns the extent to which the renderer is capable of rendering a given format.
* *
* @param mediaCodecSelector The decoder selector. * @param mediaCodecSelector The decoder selector.
* @param mediaFormat The format of the track. * @param mediaFormat The format.
* @return True if the renderer can handle the track, false otherwise. * @return The extent to which the renderer is capable of rendering the given format. One of
* @throws DecoderQueryException Thrown if there was an error querying decoders. * {@link #FORMAT_HANDLED}, {@link #FORMAT_EXCEEDS_CAPABILITIES} and
* {@link #FORMAT_UNSUPPORTED_TYPE}.
* @throws DecoderQueryException If there was an error querying decoders.
*/ */
protected abstract boolean handlesTrack(MediaCodecSelector mediaCodecSelector, protected abstract int supportsFormat(MediaCodecSelector mediaCodecSelector,
MediaFormat mediaFormat) throws DecoderQueryException; MediaFormat mediaFormat) throws DecoderQueryException;
/** /**
...@@ -293,7 +310,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer ...@@ -293,7 +310,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
*/ */
protected DecoderInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector, protected DecoderInfo getDecoderInfo(MediaCodecSelector mediaCodecSelector,
MediaFormat mediaFormat, boolean requiresSecureDecoder) throws DecoderQueryException { MediaFormat mediaFormat, boolean requiresSecureDecoder) throws DecoderQueryException {
return mediaCodecSelector.getDecoderInfo(format, requiresSecureDecoder); return mediaCodecSelector.getDecoderInfo(format.mimeType, requiresSecureDecoder);
} }
/** /**
......
...@@ -213,11 +213,38 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer { ...@@ -213,11 +213,38 @@ public class MediaCodecVideoTrackRenderer extends MediaCodecTrackRenderer {
} }
@Override @Override
protected boolean handlesTrack(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat) protected int supportsFormat(MediaCodecSelector mediaCodecSelector, MediaFormat mediaFormat)
throws DecoderQueryException { throws DecoderQueryException {
String mimeType = mediaFormat.mimeType; String mimeType = mediaFormat.mimeType;
return MimeTypes.isVideo(mimeType) && (MimeTypes.VIDEO_UNKNOWN.equals(mimeType) if (!MimeTypes.isVideo(mimeType)) {
|| mediaCodecSelector.getDecoderInfo(mediaFormat, false) != null); return TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
}
// TODO[REFACTOR]: Propagate requiresSecureDecoder to this point. Note that we need to check
// that the drm session can make use of a secure decoder, as well as that a secure decoder
// exists.
DecoderInfo decoderInfo = mediaCodecSelector.getDecoderInfo(mediaFormat.mimeType, false);
if (decoderInfo == null) {
return TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
}
if (mediaFormat.width > 0 && mediaFormat.height > 0) {
if (Util.SDK_INT >= 21) {
// TODO[REFACTOR]: Propagate frame rate to this point.
// if (mediaFormat.frameRate > 0) {
// return decoderInfo.isSizeAndRateSupportedV21(mediaFormat.width, mediaFormat.height,
// mediaFormat.frameRate) ? TrackRenderer.TRACK_HANDLED
// : TrackRenderer.TRACK_NOT_HANDLED_EXCEEDS_CAPABILITIES;
// } else {
return decoderInfo.isVideoSizeSupportedV21(mediaFormat.width, mediaFormat.height)
? TrackRenderer.FORMAT_HANDLED : TrackRenderer.FORMAT_EXCEEDS_CAPABILITIES;
// }
}
// TODO[REFACTOR]: We should probably assume that we can decode at least the resolution of
// the display, or the camera, as a sanity check?
if (mediaFormat.width * mediaFormat.height > MediaCodecUtil.maxH264DecodableFrameSize()) {
return TrackRenderer.FORMAT_EXCEEDS_CAPABILITIES;
}
}
return TrackRenderer.FORMAT_HANDLED;
} }
@Override @Override
......
...@@ -46,11 +46,11 @@ public final class TrackGroup { ...@@ -46,11 +46,11 @@ public final class TrackGroup {
} }
/** /**
* @param supportsAdaptive Whether it's possible to adapt between multiple tracks in the group. * @param adaptive Whether it's possible to adapt between multiple tracks in the group.
* @param formats The track formats. * @param formats The track formats.
*/ */
public TrackGroup(boolean supportsAdaptive, MediaFormat... formats) { public TrackGroup(boolean adaptive, MediaFormat... formats) {
this.adaptive = supportsAdaptive; this.adaptive = adaptive;
this.formats = formats; this.formats = formats;
length = formats.length; length = formats.length;
} }
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer;
import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent; import com.google.android.exoplayer.ExoPlayer.ExoPlayerComponent;
import com.google.android.exoplayer.SampleSource.TrackStream; import com.google.android.exoplayer.SampleSource.TrackStream;
import com.google.android.exoplayer.util.Assertions; import com.google.android.exoplayer.util.Assertions;
import com.google.android.exoplayer.util.MimeTypes;
import java.io.IOException; import java.io.IOException;
...@@ -35,6 +36,42 @@ import java.io.IOException; ...@@ -35,6 +36,42 @@ import java.io.IOException;
public abstract class TrackRenderer implements ExoPlayerComponent { public abstract class TrackRenderer implements ExoPlayerComponent {
/** /**
* The {@link TrackRenderer} can seamlessly adapt between formats.
*/
public static final int ADAPTIVE_SEAMLESS = 0;
/**
* The {@link TrackRenderer} can adapt between formats, but may suffer a brief discontinuity
* (~50-100ms) when adaptation occurs.
*/
public static final int ADAPTIVE_NOT_SEAMLESS = 1;
/**
* The {@link TrackRenderer} does not support adaptation between formats.
*/
public static final int ADAPTIVE_NOT_SUPPORTED = 2;
/**
* The {@link TrackRenderer} is capable of rendering the format.
*/
public static final int FORMAT_HANDLED = 0;
/**
* The {@link TrackRenderer} is capable of rendering formats with the same mimeType, but the
* properties of the format exceed the renderer's capability.
* <p>
* Example: The {@link TrackRenderer} is capable of rendering H264 and the format's mimeType is
* {@link MimeTypes#VIDEO_H264}, but the format's resolution exceeds the maximum limit supported
* by the underlying H264 decoder.
*/
public static final int FORMAT_EXCEEDS_CAPABILITIES = 1;
/**
* The {@link TrackRenderer} is not capable of rendering the format, or any other format with the
* same mimeType.
* <p>
* Example: The {@link TrackRenderer} is only capable of rendering video and the track has an
* audio mimeType.
*/
public static final int FORMAT_UNSUPPORTED_TYPE = 2;
/**
* The renderer is idle. * The renderer is idle.
*/ */
protected static final int STATE_IDLE = 0; protected static final int STATE_IDLE = 0;
...@@ -75,13 +112,31 @@ public abstract class TrackRenderer implements ExoPlayerComponent { ...@@ -75,13 +112,31 @@ public abstract class TrackRenderer implements ExoPlayerComponent {
} }
/** /**
* Returns whether this renderer is capable of handling the provided track. * Returns the extent to which the renderer is capable of consuming from a {@link TrackStream}
* that adapts between multiple supported formats of a given mimeType, or of differing mimeTypes
* if {@code mimeType == null} is passed.
*
* @param mimeType The mimeType, or null to query the extent to which the renderer is capable of
* adapting between formats with different mimeTypes.
* @return The extent to which the renderer supports the adaptation. One of
* {@link #ADAPTIVE_SEAMLESS}, {@link #ADAPTIVE_NOT_SEAMLESS} and
* {@link #ADAPTIVE_NOT_SUPPORTED}.
* @throws ExoPlaybackException If an error occurs.
*/
protected int supportsAdaptive(String mimeType) throws ExoPlaybackException {
return ADAPTIVE_NOT_SUPPORTED;
}
/**
* Returns the extent to which the renderer is capable of rendering a given format.
* *
* @param mediaFormat The format of the track. * @param mediaFormat The format.
* @return True if the renderer can handle the track, false otherwise. * @return The extent to which the renderer is capable of rendering the given format. One of
* {@link #FORMAT_HANDLED}, {@link #FORMAT_EXCEEDS_CAPABILITIES} and
* {@link #FORMAT_UNSUPPORTED_TYPE}.
* @throws ExoPlaybackException If an error occurs. * @throws ExoPlaybackException If an error occurs.
*/ */
protected abstract boolean handlesTrack(MediaFormat mediaFormat) throws ExoPlaybackException; protected abstract int supportsFormat(MediaFormat mediaFormat) throws ExoPlaybackException;
/** /**
* Enable the renderer to consume from the specified {@link TrackStream}. * Enable the renderer to consume from the specified {@link TrackStream}.
......
...@@ -86,8 +86,9 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im ...@@ -86,8 +86,9 @@ public final class MetadataTrackRenderer<T> extends SampleSourceTrackRenderer im
} }
@Override @Override
protected boolean handlesTrack(MediaFormat mediaFormat) { protected int supportsFormat(MediaFormat mediaFormat) {
return metadataParser.canParse(mediaFormat.mimeType); return metadataParser.canParse(mediaFormat.mimeType) ? TrackRenderer.FORMAT_HANDLED
: TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
} }
@Override @Override
......
...@@ -155,8 +155,9 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement ...@@ -155,8 +155,9 @@ public final class TextTrackRenderer extends SampleSourceTrackRenderer implement
} }
@Override @Override
protected boolean handlesTrack(MediaFormat mediaFormat) { protected int supportsFormat(MediaFormat mediaFormat) {
return getParserIndex(mediaFormat) != -1; return getParserIndex(mediaFormat) != -1 ? TrackRenderer.FORMAT_HANDLED
: TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
} }
@Override @Override
......
...@@ -86,8 +86,9 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme ...@@ -86,8 +86,9 @@ public final class Eia608TrackRenderer extends SampleSourceTrackRenderer impleme
} }
@Override @Override
protected boolean handlesTrack(MediaFormat mediaFormat) { protected int supportsFormat(MediaFormat mediaFormat) {
return eia608Parser.canParse(mediaFormat.mimeType); return eia608Parser.canParse(mediaFormat.mimeType) ? TrackRenderer.FORMAT_HANDLED
: TrackRenderer.FORMAT_UNSUPPORTED_TYPE;
} }
@Override @Override
......
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