Add format and renderer support to renderer exceptions.

This makes the exception easier to interpret and helps with debugging of
externally reported issues.

PiperOrigin-RevId: 283965317
This commit is contained in:
tonihei 2019-12-05 14:59:42 +00:00 committed by Oliver Woodman
parent eb5016a6ff
commit 1e609e245b
12 changed files with 205 additions and 100 deletions

View File

@ -29,6 +29,7 @@
* Add `MediaPeriod.isLoading` to improve `Player.isLoading` state. * Add `MediaPeriod.isLoading` to improve `Player.isLoading` state.
* Fix issue where player errors are thrown too early at playlist transitions * Fix issue where player errors are thrown too early at playlist transitions
([#5407](https://github.com/google/ExoPlayer/issues/5407)). ([#5407](https://github.com/google/ExoPlayer/issues/5407)).
* Add `Format` and renderer support flags to renderer `ExoPlaybackException`s.
* DRM: * DRM:
* Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`. * Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`.
This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a

View File

@ -44,6 +44,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
private long streamOffsetUs; private long streamOffsetUs;
private long readingPositionUs; private long readingPositionUs;
private boolean streamIsFinal; private boolean streamIsFinal;
private boolean throwRendererExceptionIsExecuting;
/** /**
* @param trackType The track type that the renderer handles. One of the {@link C} * @param trackType The track type that the renderer handles. One of the {@link C}
@ -314,8 +315,8 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
@Nullable DrmSession<T> newSourceDrmSession = null; @Nullable DrmSession<T> newSourceDrmSession = null;
if (newFormat.drmInitData != null) { if (newFormat.drmInitData != null) {
if (drmSessionManager == null) { if (drmSessionManager == null) {
throw ExoPlaybackException.createForRenderer( throw createRendererException(
new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); new IllegalStateException("Media requires a DrmSessionManager"), newFormat);
} }
newSourceDrmSession = newSourceDrmSession =
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
@ -334,6 +335,30 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
return index; return index;
} }
/**
* Creates an {@link ExoPlaybackException} of type {@link ExoPlaybackException#TYPE_RENDERER} for
* this renderer.
*
* @param cause The cause of the exception.
* @param format The current format used by the renderer. May be null.
*/
protected final ExoPlaybackException createRendererException(
Exception cause, @Nullable Format format) {
@FormatSupport int formatSupport = RendererCapabilities.FORMAT_HANDLED;
if (format != null && !throwRendererExceptionIsExecuting) {
// Prevent recursive re-entry from subclass supportsFormat implementations.
throwRendererExceptionIsExecuting = true;
try {
formatSupport = RendererCapabilities.getFormatSupport(supportsFormat(format));
} catch (ExoPlaybackException e) {
// Ignore, we are already failing.
} finally {
throwRendererExceptionIsExecuting = false;
}
}
return ExoPlaybackException.createForRenderer(cause, getIndex(), format, formatSupport);
}
/** /**
* Reads from the enabled upstream source. If the upstream source has been read to the end then * Reads from the enabled upstream source. If the upstream source has been read to the end then
* {@link C#RESULT_BUFFER_READ} is only returned if {@link #setCurrentStreamFinal()} has been * {@link C#RESULT_BUFFER_READ} is only returned if {@link #setCurrentStreamFinal()} has been
@ -341,16 +366,16 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities {
* *
* @param formatHolder A {@link FormatHolder} to populate in the case of reading a format. * @param formatHolder A {@link FormatHolder} to populate in the case of reading a format.
* @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the * @param buffer A {@link DecoderInputBuffer} to populate in the case of reading a sample or the
* end of the stream. If the end of the stream has been reached, the * end of the stream. If the end of the stream has been reached, the {@link
* {@link C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer. * C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer.
* @param formatRequired Whether the caller requires that the format of the stream be read even if * @param formatRequired Whether the caller requires that the format of the stream be read even if
* it's not changing. A sample will never be read if set to true, however it is still possible * it's not changing. A sample will never be read if set to true, however it is still possible
* for the end of stream or nothing to be read. * for the end of stream or nothing to be read.
* @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or
* {@link C#RESULT_BUFFER_READ}. * {@link C#RESULT_BUFFER_READ}.
*/ */
protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer, protected final int readSource(
boolean formatRequired) { FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) {
int result = stream.readData(formatHolder, buffer, formatRequired); int result = stream.readData(formatHolder, buffer, formatRequired);
if (result == C.RESULT_BUFFER_READ) { if (result == C.RESULT_BUFFER_READ) {
if (buffer.isEndOfStream()) { if (buffer.isEndOfStream()) {

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.RendererCapabilities.FormatSupport;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException; import java.io.IOException;
@ -74,6 +75,19 @@ public final class ExoPlaybackException extends Exception {
*/ */
public final int rendererIndex; public final int rendererIndex;
/**
* If {@link #type} is {@link #TYPE_RENDERER}, this is the {@link Format} the renderer was using
* at the time of the exception, or null if the renderer wasn't using a {@link Format}.
*/
@Nullable public final Format rendererFormat;
/**
* If {@link #type} is {@link #TYPE_RENDERER}, this is the level of {@link FormatSupport} of the
* renderer for {@link #rendererFormat}. If {@link #rendererFormat} is null, this is {@link
* RendererCapabilities#FORMAT_HANDLED}.
*/
@FormatSupport public final int rendererFormatSupport;
/** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */ /** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */
public final long timestampMs; public final long timestampMs;
@ -86,7 +100,7 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance. * @return The created instance.
*/ */
public static ExoPlaybackException createForSource(IOException cause) { public static ExoPlaybackException createForSource(IOException cause) {
return new ExoPlaybackException(TYPE_SOURCE, cause, /* rendererIndex= */ C.INDEX_UNSET); return new ExoPlaybackException(TYPE_SOURCE, cause);
} }
/** /**
@ -94,10 +108,23 @@ public final class ExoPlaybackException extends Exception {
* *
* @param cause The cause of the failure. * @param cause The cause of the failure.
* @param rendererIndex The index of the renderer in which the failure occurred. * @param rendererIndex The index of the renderer in which the failure occurred.
* @param rendererFormat The {@link Format} the renderer was using at the time of the exception,
* or null if the renderer wasn't using a {@link Format}.
* @param rendererFormatSupport The {@link FormatSupport} of the renderer for {@code
* rendererFormat}. Ignored if {@code rendererFormat} is null.
* @return The created instance. * @return The created instance.
*/ */
public static ExoPlaybackException createForRenderer(Exception cause, int rendererIndex) { public static ExoPlaybackException createForRenderer(
return new ExoPlaybackException(TYPE_RENDERER, cause, rendererIndex); Exception cause,
int rendererIndex,
@Nullable Format rendererFormat,
@FormatSupport int rendererFormatSupport) {
return new ExoPlaybackException(
TYPE_RENDERER,
cause,
rendererIndex,
rendererFormat,
rendererFormat == null ? RendererCapabilities.FORMAT_HANDLED : rendererFormatSupport);
} }
/** /**
@ -107,7 +134,7 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance. * @return The created instance.
*/ */
public static ExoPlaybackException createForUnexpected(RuntimeException cause) { public static ExoPlaybackException createForUnexpected(RuntimeException cause) {
return new ExoPlaybackException(TYPE_UNEXPECTED, cause, /* rendererIndex= */ C.INDEX_UNSET); return new ExoPlaybackException(TYPE_UNEXPECTED, cause);
} }
/** /**
@ -127,14 +154,30 @@ public final class ExoPlaybackException extends Exception {
* @return The created instance. * @return The created instance.
*/ */
public static ExoPlaybackException createForOutOfMemoryError(OutOfMemoryError cause) { public static ExoPlaybackException createForOutOfMemoryError(OutOfMemoryError cause) {
return new ExoPlaybackException(TYPE_OUT_OF_MEMORY, cause, /* rendererIndex= */ C.INDEX_UNSET); return new ExoPlaybackException(TYPE_OUT_OF_MEMORY, cause);
} }
private ExoPlaybackException(@Type int type, Throwable cause, int rendererIndex) { private ExoPlaybackException(@Type int type, Throwable cause) {
this(
type,
cause,
/* rendererIndex= */ C.INDEX_UNSET,
/* rendererFormat= */ null,
/* rendererFormatSupport= */ RendererCapabilities.FORMAT_HANDLED);
}
private ExoPlaybackException(
@Type int type,
Throwable cause,
int rendererIndex,
@Nullable Format rendererFormat,
@FormatSupport int rendererFormatSupport) {
super(cause); super(cause);
this.type = type; this.type = type;
this.cause = cause; this.cause = cause;
this.rendererIndex = rendererIndex; this.rendererIndex = rendererIndex;
this.rendererFormat = rendererFormat;
this.rendererFormatSupport = rendererFormatSupport;
timestampMs = SystemClock.elapsedRealtime(); timestampMs = SystemClock.elapsedRealtime();
} }
@ -142,6 +185,8 @@ public final class ExoPlaybackException extends Exception {
super(message); super(message);
this.type = type; this.type = type;
rendererIndex = C.INDEX_UNSET; rendererIndex = C.INDEX_UNSET;
rendererFormat = null;
rendererFormatSupport = RendererCapabilities.FORMAT_UNSUPPORTED_TYPE;
cause = null; cause = null;
timestampMs = SystemClock.elapsedRealtime(); timestampMs = SystemClock.elapsedRealtime();
} }

View File

@ -378,7 +378,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
} }
maybeNotifyPlaybackInfoChanged(); maybeNotifyPlaybackInfoChanged();
} catch (ExoPlaybackException e) { } catch (ExoPlaybackException e) {
Log.e(TAG, "Playback error.", e); Log.e(TAG, getExoPlaybackExceptionMessage(e), e);
stopInternal( stopInternal(
/* forceResetRenderers= */ true, /* forceResetRenderers= */ true,
/* resetPositionAndState= */ false, /* resetPositionAndState= */ false,
@ -411,6 +411,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
// Private methods. // Private methods.
private String getExoPlaybackExceptionMessage(ExoPlaybackException e) {
if (e.type != ExoPlaybackException.TYPE_RENDERER) {
return "Playback error.";
}
return "Renderer error: index="
+ e.rendererIndex
+ ", type="
+ Util.getTrackTypeString(renderers[e.rendererIndex].getTrackType())
+ ", format="
+ e.rendererFormat
+ ", rendererSupport="
+ RendererCapabilities.getFormatSupportString(e.rendererFormatSupport);
}
private void setState(int state) { private void setState(int state) {
if (playbackInfo.playbackState != state) { if (playbackInfo.playbackState != state) {
playbackInfo = playbackInfo.copyWithPlaybackState(state); playbackInfo = playbackInfo.copyWithPlaybackState(state);

View File

@ -237,6 +237,29 @@ public interface RendererCapabilities {
return supportFlags & TUNNELING_SUPPORT_MASK; return supportFlags & TUNNELING_SUPPORT_MASK;
} }
/**
* Returns string representation of a {@link FormatSupport} flag.
*
* @param formatSupport A {@link FormatSupport} flag.
* @return A string representation of the flag.
*/
static String getFormatSupportString(@FormatSupport int formatSupport) {
switch (formatSupport) {
case RendererCapabilities.FORMAT_HANDLED:
return "YES";
case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES:
return "NO_EXCEEDS_CAPABILITIES";
case RendererCapabilities.FORMAT_UNSUPPORTED_DRM:
return "NO_UNSUPPORTED_DRM";
case RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE:
return "NO_UNSUPPORTED_TYPE";
case RendererCapabilities.FORMAT_UNSUPPORTED_TYPE:
return "NO";
default:
throw new IllegalStateException();
}
}
/** /**
* Returns the track type that the {@link Renderer} handles. For example, a video renderer will * Returns the track type that the {@link Renderer} handles. For example, a video renderer will
* return {@link C#TRACK_TYPE_VIDEO}, an audio renderer will return {@link C#TRACK_TYPE_AUDIO}, a * return {@link C#TRACK_TYPE_VIDEO}, an audio renderer will return {@link C#TRACK_TYPE_AUDIO}, a

View File

@ -90,10 +90,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
private boolean codecNeedsDiscardChannelsWorkaround; private boolean codecNeedsDiscardChannelsWorkaround;
private boolean codecNeedsEosBufferTimestampWorkaround; private boolean codecNeedsEosBufferTimestampWorkaround;
private android.media.MediaFormat passthroughMediaFormat; private android.media.MediaFormat passthroughMediaFormat;
private @C.Encoding int pcmEncoding; @Nullable private Format inputFormat;
private int channelCount;
private int encoderDelay;
private int encoderPadding;
private long currentPositionUs; private long currentPositionUs;
private boolean allowFirstBufferPositionDiscontinuity; private boolean allowFirstBufferPositionDiscontinuity;
private boolean allowPositionDiscontinuity; private boolean allowPositionDiscontinuity;
@ -551,15 +548,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override @Override
protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
super.onInputFormatChanged(formatHolder); super.onInputFormatChanged(formatHolder);
Format newFormat = formatHolder.format; inputFormat = formatHolder.format;
eventDispatcher.inputFormatChanged(newFormat); eventDispatcher.inputFormatChanged(inputFormat);
// If the input format is anything other than PCM then we assume that the audio decoder will
// output 16-bit PCM.
pcmEncoding = MimeTypes.AUDIO_RAW.equals(newFormat.sampleMimeType) ? newFormat.pcmEncoding
: C.ENCODING_PCM_16BIT;
channelCount = newFormat.channelCount;
encoderDelay = newFormat.encoderDelay;
encoderPadding = newFormat.encoderPadding;
} }
@Override @Override
@ -575,14 +565,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
mediaFormat.getString(MediaFormat.KEY_MIME)); mediaFormat.getString(MediaFormat.KEY_MIME));
} else { } else {
mediaFormat = outputMediaFormat; mediaFormat = outputMediaFormat;
encoding = pcmEncoding; encoding = getPcmEncoding(inputFormat);
} }
int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
int[] channelMap; int[] channelMap;
if (codecNeedsDiscardChannelsWorkaround && channelCount == 6 && this.channelCount < 6) { if (codecNeedsDiscardChannelsWorkaround && channelCount == 6 && inputFormat.channelCount < 6) {
channelMap = new int[this.channelCount]; channelMap = new int[inputFormat.channelCount];
for (int i = 0; i < this.channelCount; i++) { for (int i = 0; i < inputFormat.channelCount; i++) {
channelMap[i] = i; channelMap[i] = i;
} }
} else { } else {
@ -590,10 +580,17 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
} }
try { try {
audioSink.configure(encoding, channelCount, sampleRate, 0, channelMap, encoderDelay, audioSink.configure(
encoderPadding); encoding,
channelCount,
sampleRate,
0,
channelMap,
inputFormat.encoderDelay,
inputFormat.encoderPadding);
} catch (AudioSink.ConfigurationException e) { } catch (AudioSink.ConfigurationException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); // TODO(internal: b/145658993) Use outputFormat instead.
throw createRendererException(e, inputFormat);
} }
} }
@ -820,7 +817,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
return true; return true;
} }
} catch (AudioSink.InitializationException | AudioSink.WriteException e) { } catch (AudioSink.InitializationException | AudioSink.WriteException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); // TODO(internal: b/145658993) Use outputFormat instead.
throw createRendererException(e, inputFormat);
} }
return false; return false;
} }
@ -830,7 +828,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
try { try {
audioSink.playToEndOfStream(); audioSink.playToEndOfStream();
} catch (AudioSink.WriteException e) { } catch (AudioSink.WriteException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); // TODO(internal: b/145658993) Use outputFormat instead.
throw createRendererException(e, inputFormat);
} }
} }
@ -992,6 +991,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|| Util.DEVICE.startsWith("ms01")); || Util.DEVICE.startsWith("ms01"));
} }
@C.Encoding
private static int getPcmEncoding(Format format) {
// If the format is anything other than PCM then we assume that the audio decoder will output
// 16-bit PCM.
return MimeTypes.AUDIO_RAW.equals(format.sampleMimeType)
? format.pcmEncoding
: C.ENCODING_PCM_16BIT;
}
private final class AudioSinkListener implements AudioSink.Listener { private final class AudioSinkListener implements AudioSink.Listener {
@Override @Override

View File

@ -263,7 +263,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
try { try {
audioSink.playToEndOfStream(); audioSink.playToEndOfStream();
} catch (AudioSink.WriteException e) { } catch (AudioSink.WriteException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
return; return;
} }
@ -300,7 +300,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
TraceUtil.endSection(); TraceUtil.endSection();
} catch (AudioDecoderException | AudioSink.ConfigurationException } catch (AudioDecoderException | AudioSink.ConfigurationException
| AudioSink.InitializationException | AudioSink.WriteException e) { | AudioSink.InitializationException | AudioSink.WriteException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} }
@ -483,7 +483,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
} }
@DrmSession.State int drmSessionState = decoderDrmSession.getState(); @DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) { if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex()); throw createRendererException(decoderDrmSession.getError(), inputFormat);
} }
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
} }
@ -493,7 +493,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
try { try {
audioSink.playToEndOfStream(); audioSink.playToEndOfStream();
} catch (AudioSink.WriteException e) { } catch (AudioSink.WriteException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); // TODO(internal: b/145658993) Use outputFormat for the call from drainOutputBuffer.
throw createRendererException(e, inputFormat);
} }
} }
@ -644,7 +645,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
codecInitializedTimestamp - codecInitializingTimestamp); codecInitializedTimestamp - codecInitializingTimestamp);
decoderCounters.decoderInitCount++; decoderCounters.decoderInitCount++;
} catch (AudioDecoderException e) { } catch (AudioDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
} }

View File

@ -463,7 +463,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
try { try {
return supportsFormat(mediaCodecSelector, drmSessionManager, format); return supportsFormat(mediaCodecSelector, drmSessionManager, format);
} catch (DecoderQueryException e) { } catch (DecoderQueryException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, format);
} }
} }
@ -538,7 +538,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
try { try {
mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId); mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId);
} catch (MediaCryptoException e) { } catch (MediaCryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
mediaCryptoRequiresSecureDecoder = mediaCryptoRequiresSecureDecoder =
!sessionMediaCrypto.forceAllowInsecureDecoderComponents !sessionMediaCrypto.forceAllowInsecureDecoderComponents
@ -548,7 +548,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) { if (FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) {
@DrmSession.State int drmSessionState = codecDrmSession.getState(); @DrmSession.State int drmSessionState = codecDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) { if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex()); throw createRendererException(codecDrmSession.getError(), inputFormat);
} else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) { } else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) {
// Wait for keys. // Wait for keys.
return; return;
@ -559,7 +559,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
try { try {
maybeInitCodecWithFallback(mediaCrypto, mediaCryptoRequiresSecureDecoder); maybeInitCodecWithFallback(mediaCrypto, mediaCryptoRequiresSecureDecoder);
} catch (DecoderInitializationException e) { } catch (DecoderInitializationException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
} }
@ -722,8 +722,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
if (isMediaCodecException(e)) { if (isMediaCodecException(e)) {
throw ExoPlaybackException.createForRenderer( throw createRendererException(e, inputFormat);
createDecoderException(e, getCodecInfo()), getIndex());
} }
throw e; throw e;
} }
@ -1130,7 +1129,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
resetInputBuffer(); resetInputBuffer();
} }
} catch (CryptoException e) { } catch (CryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
return false; return false;
} }
@ -1186,7 +1185,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecReconfigurationState = RECONFIGURATION_STATE_NONE; codecReconfigurationState = RECONFIGURATION_STATE_NONE;
decoderCounters.inputBufferCount++; decoderCounters.inputBufferCount++;
} catch (CryptoException e) { } catch (CryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
return true; return true;
} }
@ -1199,7 +1198,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
} }
@DrmSession.State int drmSessionState = codecDrmSession.getState(); @DrmSession.State int drmSessionState = codecDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) { if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex()); throw createRendererException(codecDrmSession.getError(), inputFormat);
} }
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
} }
@ -1744,7 +1743,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
try { try {
mediaCrypto.setMediaDrmSession(sessionMediaCrypto.sessionId); mediaCrypto.setMediaDrmSession(sessionMediaCrypto.sessionId);
} catch (MediaCryptoException e) { } catch (MediaCryptoException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
setCodecDrmSession(sourceDrmSession); setCodecDrmSession(sourceDrmSession);
codecDrainState = DRAIN_STATE_NONE; codecDrainState = DRAIN_STATE_NONE;

View File

@ -165,7 +165,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
try { try {
nextSubtitle = decoder.dequeueOutputBuffer(); nextSubtitle = decoder.dequeueOutputBuffer();
} catch (SubtitleDecoderException e) { } catch (SubtitleDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, streamFormat);
} }
} }
@ -247,7 +247,7 @@ public final class TextRenderer extends BaseRenderer implements Callback {
} }
} }
} catch (SubtitleDecoderException e) { } catch (SubtitleDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, streamFormat);
} }
} }

View File

@ -26,7 +26,6 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport; import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport;
import com.google.android.exoplayer2.RendererCapabilities.FormatSupport;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
@ -218,7 +217,7 @@ public class EventLogger implements AnalyticsListener {
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(trackSelection, trackGroup, trackIndex); String status = getTrackStatusString(trackSelection, trackGroup, trackIndex);
String formatSupport = String formatSupport =
getFormatSupportString( RendererCapabilities.getFormatSupportString(
mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex)); mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex));
logd( logd(
" " " "
@ -257,7 +256,8 @@ public class EventLogger implements AnalyticsListener {
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(false); String status = getTrackStatusString(false);
String formatSupport = String formatSupport =
getFormatSupportString(RendererCapabilities.FORMAT_UNSUPPORTED_TYPE); RendererCapabilities.getFormatSupportString(
RendererCapabilities.FORMAT_UNSUPPORTED_TYPE);
logd( logd(
" " " "
+ status + status
@ -289,7 +289,7 @@ public class EventLogger implements AnalyticsListener {
@Override @Override
public void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters counters) { public void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters counters) {
logd(eventTime, "decoderEnabled", getTrackTypeString(trackType)); logd(eventTime, "decoderEnabled", Util.getTrackTypeString(trackType));
} }
@Override @Override
@ -319,7 +319,7 @@ public class EventLogger implements AnalyticsListener {
@Override @Override
public void onDecoderInitialized( public void onDecoderInitialized(
EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) { EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) {
logd(eventTime, "decoderInitialized", getTrackTypeString(trackType) + ", " + decoderName); logd(eventTime, "decoderInitialized", Util.getTrackTypeString(trackType) + ", " + decoderName);
} }
@Override @Override
@ -327,12 +327,12 @@ public class EventLogger implements AnalyticsListener {
logd( logd(
eventTime, eventTime,
"decoderInputFormat", "decoderInputFormat",
getTrackTypeString(trackType) + ", " + Format.toLogString(format)); Util.getTrackTypeString(trackType) + ", " + Format.toLogString(format));
} }
@Override @Override
public void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters counters) { public void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters counters) {
logd(eventTime, "decoderDisabled", getTrackTypeString(trackType)); logd(eventTime, "decoderDisabled", Util.getTrackTypeString(trackType));
} }
@Override @Override
@ -555,23 +555,6 @@ public class EventLogger implements AnalyticsListener {
} }
} }
private static String getFormatSupportString(@FormatSupport int formatSupport) {
switch (formatSupport) {
case RendererCapabilities.FORMAT_HANDLED:
return "YES";
case RendererCapabilities.FORMAT_EXCEEDS_CAPABILITIES:
return "NO_EXCEEDS_CAPABILITIES";
case RendererCapabilities.FORMAT_UNSUPPORTED_DRM:
return "NO_UNSUPPORTED_DRM";
case RendererCapabilities.FORMAT_UNSUPPORTED_SUBTYPE:
return "NO_UNSUPPORTED_TYPE";
case RendererCapabilities.FORMAT_UNSUPPORTED_TYPE:
return "NO";
default:
throw new IllegalStateException();
}
}
private static String getAdaptiveSupportString( private static String getAdaptiveSupportString(
int trackCount, @AdaptiveSupport int adaptiveSupport) { int trackCount, @AdaptiveSupport int adaptiveSupport) {
if (trackCount < 2) { if (trackCount < 2) {
@ -645,27 +628,6 @@ public class EventLogger implements AnalyticsListener {
} }
} }
private static String getTrackTypeString(int trackType) {
switch (trackType) {
case C.TRACK_TYPE_AUDIO:
return "audio";
case C.TRACK_TYPE_DEFAULT:
return "default";
case C.TRACK_TYPE_METADATA:
return "metadata";
case C.TRACK_TYPE_CAMERA_MOTION:
return "camera motion";
case C.TRACK_TYPE_NONE:
return "none";
case C.TRACK_TYPE_TEXT:
return "text";
case C.TRACK_TYPE_VIDEO:
return "video";
default:
return trackType >= C.TRACK_TYPE_CUSTOM_BASE ? "custom (" + trackType + ")" : "?";
}
}
private static String getPlaybackSuppressionReasonString( private static String getPlaybackSuppressionReasonString(
@PlaybackSuppressionReason int playbackSuppressionReason) { @PlaybackSuppressionReason int playbackSuppressionReason) {
switch (playbackSuppressionReason) { switch (playbackSuppressionReason) {

View File

@ -2001,6 +2001,33 @@ public final class Util {
return capabilities; return capabilities;
} }
/**
* Returns a string representation of a {@code TRACK_TYPE_*} constant defined in {@link C}.
*
* @param trackType A {@code TRACK_TYPE_*} constant,
* @return A string representation of this constant.
*/
public static String getTrackTypeString(int trackType) {
switch (trackType) {
case C.TRACK_TYPE_AUDIO:
return "audio";
case C.TRACK_TYPE_DEFAULT:
return "default";
case C.TRACK_TYPE_METADATA:
return "metadata";
case C.TRACK_TYPE_CAMERA_MOTION:
return "camera motion";
case C.TRACK_TYPE_NONE:
return "none";
case C.TRACK_TYPE_TEXT:
return "text";
case C.TRACK_TYPE_VIDEO:
return "video";
default:
return trackType >= C.TRACK_TYPE_CUSTOM_BASE ? "custom (" + trackType + ")" : "?";
}
}
@Nullable @Nullable
private static String getSystemProperty(String name) { private static String getSystemProperty(String name) {
try { try {

View File

@ -198,7 +198,7 @@ public abstract class SimpleDecoderVideoRenderer extends BaseRenderer {
while (feedInputBuffer()) {} while (feedInputBuffer()) {}
TraceUtil.endSection(); TraceUtil.endSection();
} catch (VideoDecoderException e) { } catch (VideoDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
decoderCounters.ensureUpdated(); decoderCounters.ensureUpdated();
} }
@ -681,7 +681,7 @@ public abstract class SimpleDecoderVideoRenderer extends BaseRenderer {
decoderInitializedTimestamp - decoderInitializingTimestamp); decoderInitializedTimestamp - decoderInitializingTimestamp);
decoderCounters.decoderInitCount++; decoderCounters.decoderInitCount++;
} catch (VideoDecoderException e) { } catch (VideoDecoderException e) {
throw ExoPlaybackException.createForRenderer(e, getIndex()); throw createRendererException(e, inputFormat);
} }
} }
@ -887,7 +887,7 @@ public abstract class SimpleDecoderVideoRenderer extends BaseRenderer {
} }
@DrmSession.State int drmSessionState = decoderDrmSession.getState(); @DrmSession.State int drmSessionState = decoderDrmSession.getState();
if (drmSessionState == DrmSession.STATE_ERROR) { if (drmSessionState == DrmSession.STATE_ERROR) {
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex()); throw createRendererException(decoderDrmSession.getError(), inputFormat);
} }
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
} }