diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b1b39b75b1..c9564e2d58 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -29,6 +29,7 @@ * Add `MediaPeriod.isLoading` to improve `Player.isLoading` state. * Fix issue where player errors are thrown too early at playlist transitions ([#5407](https://github.com/google/ExoPlayer/issues/5407)). + * Add `Format` and renderer support flags to renderer `ExoPlaybackException`s. * DRM: * Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`. This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java index bf43e74c2a..10573af419 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/BaseRenderer.java @@ -44,6 +44,7 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { private long streamOffsetUs; private long readingPositionUs; private boolean streamIsFinal; + private boolean throwRendererExceptionIsExecuting; /** * @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 newSourceDrmSession = null; if (newFormat.drmInitData != null) { if (drmSessionManager == null) { - throw ExoPlaybackException.createForRenderer( - new IllegalStateException("Media requires a DrmSessionManager"), getIndex()); + throw createRendererException( + new IllegalStateException("Media requires a DrmSessionManager"), newFormat); } newSourceDrmSession = drmSessionManager.acquireSession( @@ -334,6 +335,30 @@ public abstract class BaseRenderer implements Renderer, RendererCapabilities { 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 * {@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 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 - * {@link C#BUFFER_FLAG_END_OF_STREAM} flag will be set on the buffer. + * end of the stream. If the end of the stream has been reached, the {@link + * 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 * 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. * @return The result, which can be {@link C#RESULT_NOTHING_READ}, {@link C#RESULT_FORMAT_READ} or * {@link C#RESULT_BUFFER_READ}. */ - protected final int readSource(FormatHolder formatHolder, DecoderInputBuffer buffer, - boolean formatRequired) { + protected final int readSource( + FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired) { int result = stream.readData(formatHolder, buffer, formatRequired); if (result == C.RESULT_BUFFER_READ) { if (buffer.isEndOfStream()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java index 49aacd9638..653b6002d9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2; import android.os.SystemClock; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.RendererCapabilities.FormatSupport; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; @@ -74,6 +75,19 @@ public final class ExoPlaybackException extends Exception { */ 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. */ public final long timestampMs; @@ -86,7 +100,7 @@ public final class ExoPlaybackException extends Exception { * @return The created instance. */ 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 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. */ - public static ExoPlaybackException createForRenderer(Exception cause, int rendererIndex) { - return new ExoPlaybackException(TYPE_RENDERER, cause, rendererIndex); + public static ExoPlaybackException createForRenderer( + 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. */ 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. */ 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); this.type = type; this.cause = cause; this.rendererIndex = rendererIndex; + this.rendererFormat = rendererFormat; + this.rendererFormatSupport = rendererFormatSupport; timestampMs = SystemClock.elapsedRealtime(); } @@ -142,6 +185,8 @@ public final class ExoPlaybackException extends Exception { super(message); this.type = type; rendererIndex = C.INDEX_UNSET; + rendererFormat = null; + rendererFormatSupport = RendererCapabilities.FORMAT_UNSUPPORTED_TYPE; cause = null; timestampMs = SystemClock.elapsedRealtime(); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java index 4c25c180f4..240c6436c4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImplInternal.java @@ -378,7 +378,7 @@ import java.util.concurrent.atomic.AtomicBoolean; } maybeNotifyPlaybackInfoChanged(); } catch (ExoPlaybackException e) { - Log.e(TAG, "Playback error.", e); + Log.e(TAG, getExoPlaybackExceptionMessage(e), e); stopInternal( /* forceResetRenderers= */ true, /* resetPositionAndState= */ false, @@ -411,6 +411,20 @@ import java.util.concurrent.atomic.AtomicBoolean; // 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) { if (playbackInfo.playbackState != state) { playbackInfo = playbackInfo.copyWithPlaybackState(state); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java index 95f1749f10..a75765262b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/RendererCapabilities.java @@ -237,6 +237,29 @@ public interface RendererCapabilities { 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 * return {@link C#TRACK_TYPE_VIDEO}, an audio renderer will return {@link C#TRACK_TYPE_AUDIO}, a diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 3e48966c54..ae50d14728 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -90,10 +90,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media private boolean codecNeedsDiscardChannelsWorkaround; private boolean codecNeedsEosBufferTimestampWorkaround; private android.media.MediaFormat passthroughMediaFormat; - private @C.Encoding int pcmEncoding; - private int channelCount; - private int encoderDelay; - private int encoderPadding; + @Nullable private Format inputFormat; private long currentPositionUs; private boolean allowFirstBufferPositionDiscontinuity; private boolean allowPositionDiscontinuity; @@ -551,15 +548,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media @Override protected void onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException { super.onInputFormatChanged(formatHolder); - Format newFormat = formatHolder.format; - eventDispatcher.inputFormatChanged(newFormat); - // 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; + inputFormat = formatHolder.format; + eventDispatcher.inputFormatChanged(inputFormat); } @Override @@ -575,14 +565,14 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media mediaFormat.getString(MediaFormat.KEY_MIME)); } else { mediaFormat = outputMediaFormat; - encoding = pcmEncoding; + encoding = getPcmEncoding(inputFormat); } int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT); int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE); int[] channelMap; - if (codecNeedsDiscardChannelsWorkaround && channelCount == 6 && this.channelCount < 6) { - channelMap = new int[this.channelCount]; - for (int i = 0; i < this.channelCount; i++) { + if (codecNeedsDiscardChannelsWorkaround && channelCount == 6 && inputFormat.channelCount < 6) { + channelMap = new int[inputFormat.channelCount]; + for (int i = 0; i < inputFormat.channelCount; i++) { channelMap[i] = i; } } else { @@ -590,10 +580,17 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } try { - audioSink.configure(encoding, channelCount, sampleRate, 0, channelMap, encoderDelay, - encoderPadding); + audioSink.configure( + encoding, + channelCount, + sampleRate, + 0, + channelMap, + inputFormat.encoderDelay, + inputFormat.encoderPadding); } 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; } } catch (AudioSink.InitializationException | AudioSink.WriteException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + // TODO(internal: b/145658993) Use outputFormat instead. + throw createRendererException(e, inputFormat); } return false; } @@ -830,7 +828,8 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media try { audioSink.playToEndOfStream(); } 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")); } + @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 { @Override diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index d5a5ffe7bb..5ccbf04c5c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -263,7 +263,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements try { audioSink.playToEndOfStream(); } catch (AudioSink.WriteException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } return; } @@ -300,7 +300,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements TraceUtil.endSection(); } catch (AudioDecoderException | AudioSink.ConfigurationException | AudioSink.InitializationException | AudioSink.WriteException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } decoderCounters.ensureUpdated(); } @@ -483,7 +483,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements } @DrmSession.State int drmSessionState = decoderDrmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex()); + throw createRendererException(decoderDrmSession.getError(), inputFormat); } return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } @@ -493,7 +493,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements try { audioSink.playToEndOfStream(); } 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); decoderCounters.decoderInitCount++; } catch (AudioDecoderException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 50b3ab8a0e..90b1d4286e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -463,7 +463,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { return supportsFormat(mediaCodecSelector, drmSessionManager, format); } catch (DecoderQueryException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, format); } } @@ -538,7 +538,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { mediaCrypto = new MediaCrypto(sessionMediaCrypto.uuid, sessionMediaCrypto.sessionId); } catch (MediaCryptoException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } mediaCryptoRequiresSecureDecoder = !sessionMediaCrypto.forceAllowInsecureDecoderComponents @@ -548,7 +548,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (FrameworkMediaCrypto.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC) { @DrmSession.State int drmSessionState = codecDrmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex()); + throw createRendererException(codecDrmSession.getError(), inputFormat); } else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) { // Wait for keys. return; @@ -559,7 +559,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { maybeInitCodecWithFallback(mediaCrypto, mediaCryptoRequiresSecureDecoder); } catch (DecoderInitializationException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } } @@ -722,8 +722,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { decoderCounters.ensureUpdated(); } catch (IllegalStateException e) { if (isMediaCodecException(e)) { - throw ExoPlaybackException.createForRenderer( - createDecoderException(e, getCodecInfo()), getIndex()); + throw createRendererException(e, inputFormat); } throw e; } @@ -1130,7 +1129,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { resetInputBuffer(); } } catch (CryptoException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } return false; } @@ -1186,7 +1185,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecReconfigurationState = RECONFIGURATION_STATE_NONE; decoderCounters.inputBufferCount++; } catch (CryptoException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } return true; } @@ -1199,7 +1198,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } @DrmSession.State int drmSessionState = codecDrmSession.getState(); if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex()); + throw createRendererException(codecDrmSession.getError(), inputFormat); } return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; } @@ -1744,7 +1743,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { try { mediaCrypto.setMediaDrmSession(sessionMediaCrypto.sessionId); } catch (MediaCryptoException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } setCodecDrmSession(sourceDrmSession); codecDrainState = DRAIN_STATE_NONE; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java index d359eebfdb..058b1c4526 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/TextRenderer.java @@ -165,7 +165,7 @@ public final class TextRenderer extends BaseRenderer implements Callback { try { nextSubtitle = decoder.dequeueOutputBuffer(); } 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) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, streamFormat); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index 6caf549afe..0a303c1df7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -26,7 +26,6 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.RendererCapabilities; 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.analytics.AnalyticsListener; import com.google.android.exoplayer2.audio.AudioAttributes; @@ -218,7 +217,7 @@ public class EventLogger implements AnalyticsListener { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { String status = getTrackStatusString(trackSelection, trackGroup, trackIndex); String formatSupport = - getFormatSupportString( + RendererCapabilities.getFormatSupportString( mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex)); logd( " " @@ -257,7 +256,8 @@ public class EventLogger implements AnalyticsListener { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { String status = getTrackStatusString(false); String formatSupport = - getFormatSupportString(RendererCapabilities.FORMAT_UNSUPPORTED_TYPE); + RendererCapabilities.getFormatSupportString( + RendererCapabilities.FORMAT_UNSUPPORTED_TYPE); logd( " " + status @@ -289,7 +289,7 @@ public class EventLogger implements AnalyticsListener { @Override public void onDecoderEnabled(EventTime eventTime, int trackType, DecoderCounters counters) { - logd(eventTime, "decoderEnabled", getTrackTypeString(trackType)); + logd(eventTime, "decoderEnabled", Util.getTrackTypeString(trackType)); } @Override @@ -319,7 +319,7 @@ public class EventLogger implements AnalyticsListener { @Override public void onDecoderInitialized( EventTime eventTime, int trackType, String decoderName, long initializationDurationMs) { - logd(eventTime, "decoderInitialized", getTrackTypeString(trackType) + ", " + decoderName); + logd(eventTime, "decoderInitialized", Util.getTrackTypeString(trackType) + ", " + decoderName); } @Override @@ -327,12 +327,12 @@ public class EventLogger implements AnalyticsListener { logd( eventTime, "decoderInputFormat", - getTrackTypeString(trackType) + ", " + Format.toLogString(format)); + Util.getTrackTypeString(trackType) + ", " + Format.toLogString(format)); } @Override public void onDecoderDisabled(EventTime eventTime, int trackType, DecoderCounters counters) { - logd(eventTime, "decoderDisabled", getTrackTypeString(trackType)); + logd(eventTime, "decoderDisabled", Util.getTrackTypeString(trackType)); } @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( int trackCount, @AdaptiveSupport int adaptiveSupport) { 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( @PlaybackSuppressionReason int playbackSuppressionReason) { switch (playbackSuppressionReason) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java index 23447acddf..c8a947e7d6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/Util.java @@ -2001,6 +2001,33 @@ public final class Util { 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 private static String getSystemProperty(String name) { try { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/video/SimpleDecoderVideoRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/video/SimpleDecoderVideoRenderer.java index 9aa50e4388..bf0a28ffa0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/video/SimpleDecoderVideoRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/video/SimpleDecoderVideoRenderer.java @@ -198,7 +198,7 @@ public abstract class SimpleDecoderVideoRenderer extends BaseRenderer { while (feedInputBuffer()) {} TraceUtil.endSection(); } catch (VideoDecoderException e) { - throw ExoPlaybackException.createForRenderer(e, getIndex()); + throw createRendererException(e, inputFormat); } decoderCounters.ensureUpdated(); } @@ -681,7 +681,7 @@ public abstract class SimpleDecoderVideoRenderer extends BaseRenderer { decoderInitializedTimestamp - decoderInitializingTimestamp); decoderCounters.decoderInitCount++; } 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(); if (drmSessionState == DrmSession.STATE_ERROR) { - throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex()); + throw createRendererException(decoderDrmSession.getError(), inputFormat); } return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; }