diff --git a/api.txt b/api.txt index 911f5b4e5b..946ed8a3d1 100644 --- a/api.txt +++ b/api.txt @@ -1192,7 +1192,7 @@ package androidx.media3.common { field public static final androidx.media3.common.VideoSize UNKNOWN; field @IntRange(from=0) public final int height; field @FloatRange(from=0, fromInclusive=false) public final float pixelWidthHeightRatio; - field @IntRange(from=0, to=359) public final int unappliedRotationDegrees; + field @Deprecated @IntRange(from=0, to=359) public final int unappliedRotationDegrees; field @IntRange(from=0) public final int width; } diff --git a/libraries/common/src/main/java/androidx/media3/common/VideoSize.java b/libraries/common/src/main/java/androidx/media3/common/VideoSize.java index 91a25d0a73..502e77e231 100644 --- a/libraries/common/src/main/java/androidx/media3/common/VideoSize.java +++ b/libraries/common/src/main/java/androidx/media3/common/VideoSize.java @@ -41,19 +41,10 @@ public final class VideoSize { public final int height; /** - * Clockwise rotation in degrees that the application should apply for the video for it to be - * rendered in the correct orientation. - * - *
Is 0 if unknown or if no rotation is needed. - * - *
Player should apply video rotation internally, in which case unappliedRotationDegrees is 0. - * But when a player can't apply the rotation, for example before API level 21, the unapplied - * rotation is reported by this field for application to handle. - * - *
Applications that use {@link android.view.TextureView} can apply the rotation by calling - * {@link android.view.TextureView#setTransform}. + * @deprecated Rotation is handled internally by the player, so this is always zero. */ @IntRange(from = 0, to = 359) + @Deprecated public final int unappliedRotationDegrees; /** @@ -73,7 +64,7 @@ public final class VideoSize { */ @UnstableApi public VideoSize(@IntRange(from = 0) int width, @IntRange(from = 0) int height) { - this(width, height, DEFAULT_UNAPPLIED_ROTATION_DEGREES, DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO); + this(width, height, DEFAULT_PIXEL_WIDTH_HEIGHT_RATIO); } /** @@ -81,13 +72,25 @@ public final class VideoSize { * * @param width The video width in pixels. * @param height The video height in pixels. - * @param unappliedRotationDegrees Clockwise rotation in degrees that the application should apply - * for the video for it to be rendered in the correct orientation. See {@link - * #unappliedRotationDegrees}. * @param pixelWidthHeightRatio The width to height ratio of each pixel. For the normal case of * square pixels this will be equal to 1.0. Different values are indicative of anamorphic * content. */ + @SuppressWarnings("deprecation") // Calling through to deprecated constructor + @UnstableApi + public VideoSize( + @IntRange(from = 0) int width, + @IntRange(from = 0) int height, + @FloatRange(from = 0, fromInclusive = false) float pixelWidthHeightRatio) { + this(width, height, DEFAULT_UNAPPLIED_ROTATION_DEGREES, pixelWidthHeightRatio); + } + + /** + * @deprecated Use {@link VideoSize#VideoSize(int, int, float)} instead. {@code + * unappliedRotationDegrees} is not needed on API 21+. + */ + @SuppressWarnings("deprecation") // Setting deprecate field + @Deprecated @UnstableApi public VideoSize( @IntRange(from = 0) int width, @@ -100,6 +103,7 @@ public final class VideoSize { this.pixelWidthHeightRatio = pixelWidthHeightRatio; } + @SuppressWarnings("deprecation") // Including deprecated field in equality @Override public boolean equals(@Nullable Object obj) { if (this == obj) { @@ -115,6 +119,7 @@ public final class VideoSize { return false; } + @SuppressWarnings("deprecation") // Including deprecated field in hashCode @Override public int hashCode() { int result = 7; @@ -130,6 +135,7 @@ public final class VideoSize { private static final String FIELD_UNAPPLIED_ROTATION_DEGREES = Util.intToStringMaxRadix(2); private static final String FIELD_PIXEL_WIDTH_HEIGHT_RATIO = Util.intToStringMaxRadix(3); + @SuppressWarnings("deprecation") // Including deprecated field in bundle @UnstableApi public Bundle toBundle() { Bundle bundle = new Bundle(); @@ -141,6 +147,7 @@ public final class VideoSize { } /** Restores a {@code VideoSize} from a {@link Bundle}. */ + @SuppressWarnings("deprecation") // Parsing deprecated field from bundle @UnstableApi public static VideoSize fromBundle(Bundle bundle) { int width = bundle.getInt(FIELD_WIDTH, DEFAULT_WIDTH); diff --git a/libraries/common/src/test/java/androidx/media3/common/VideoSizeTest.java b/libraries/common/src/test/java/androidx/media3/common/VideoSizeTest.java index ad0e31bc27..213ad58e20 100644 --- a/libraries/common/src/test/java/androidx/media3/common/VideoSizeTest.java +++ b/libraries/common/src/test/java/androidx/media3/common/VideoSizeTest.java @@ -32,6 +32,7 @@ public final class VideoSizeTest { } @Test + @SuppressWarnings("deprecation") // Testing bundling of deprecated field. public void roundTripViaBundle_ofArbitraryVideoSize_yieldsEqualInstance() { VideoSize videoSize = new VideoSize( diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java index c53a02f0c3..f7d8558d8b 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/mediacodec/MediaCodecRenderer.java @@ -58,7 +58,6 @@ import androidx.media3.common.util.TimedValueQueue; import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; -import androidx.media3.container.NalUnitUtil; import androidx.media3.decoder.CryptoConfig; import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException; @@ -170,7 +169,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { format.sampleMimeType, secureDecoderRequired, mediaCodecInfo, - Util.SDK_INT >= 21 ? getDiagnosticInfoV21(cause) : null, + (cause instanceof CodecException) ? ((CodecException) cause).getDiagnosticInfo() : null, /* fallbackDecoderInitializationException= */ null); } @@ -203,15 +202,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { fallbackException); } - @RequiresApi(21) - @Nullable - private static String getDiagnosticInfoV21(@Nullable Throwable cause) { - if (cause instanceof CodecException) { - return ((CodecException) cause).getDiagnosticInfo(); - } - return null; - } - private static String buildCustomDiagnosticInfo(int errorCode) { String sign = errorCode < 0 ? "neg_" : ""; String packageName = "androidx.media3.exoplayer.mediacodec"; @@ -373,13 +363,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { @Nullable private DecoderInitializationException preferredDecoderInitializationException; @Nullable private MediaCodecInfo codecInfo; private @AdaptationWorkaroundMode int codecAdaptationWorkaroundMode; - private boolean codecNeedsDiscardToSpsWorkaround; - private boolean codecNeedsFlushWorkaround; private boolean codecNeedsSosFlushWorkaround; private boolean codecNeedsEosFlushWorkaround; private boolean codecNeedsEosOutputExceptionWorkaround; - private boolean codecNeedsEosBufferTimestampWorkaround; - private boolean codecNeedsMonoChannelCountWorkaround; private boolean codecNeedsAdaptationWorkaroundBuffer; private boolean shouldSkipAdaptationWorkaroundOutputBuffer; private boolean codecNeedsEosPropagation; @@ -898,9 +884,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } decoderCounters.ensureUpdated(); } catch (IllegalStateException e) { - if (isMediaCodecException(e)) { + if (e instanceof CodecException) { onCodecError(e); - boolean isRecoverable = Util.SDK_INT >= 21 && isRecoverableMediaCodecExceptionV21(e); + boolean isRecoverable = + (e instanceof CodecException) && ((CodecException) e).isRecoverable(); if (isRecoverable) { releaseCodec(); } @@ -945,7 +932,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { return false; } if (codecDrainAction == DRAIN_ACTION_REINITIALIZE - || codecNeedsFlushWorkaround || (codecNeedsSosFlushWorkaround && !codecHasOutputMediaFormat) || (codecNeedsEosFlushWorkaround && codecReceivedEos)) { releaseCodec(); @@ -1020,13 +1006,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { codecHasOutputMediaFormat = false; codecOperatingRate = CODEC_OPERATING_RATE_UNSET; codecAdaptationWorkaroundMode = ADAPTATION_WORKAROUND_MODE_NEVER; - codecNeedsDiscardToSpsWorkaround = false; - codecNeedsFlushWorkaround = false; codecNeedsSosFlushWorkaround = false; codecNeedsEosFlushWorkaround = false; codecNeedsEosOutputExceptionWorkaround = false; - codecNeedsEosBufferTimestampWorkaround = false; - codecNeedsMonoChannelCountWorkaround = false; codecNeedsEosPropagation = false; codecRegisteredOnBufferAvailableListener = false; codecReconfigured = false; @@ -1238,9 +1220,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { TraceUtil.beginSection("createCodec:" + codecName); codec = codecAdapterFactory.createAdapter(configuration); codecRegisteredOnBufferAvailableListener = - Util.SDK_INT >= 21 - && Api21.registerOnBufferAvailableListener( - codec, new MediaCodecRendererCodecAdapterListener()); + codec.registerOnBufferAvailableListener(new MediaCodecRendererCodecAdapterListener()); } finally { TraceUtil.endSection(); } @@ -1258,14 +1238,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer { this.codecOperatingRate = codecOperatingRate; codecInputFormat = inputFormat; codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName); - codecNeedsDiscardToSpsWorkaround = - codecNeedsDiscardToSpsWorkaround(codecName, checkNotNull(codecInputFormat)); - codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName); codecNeedsSosFlushWorkaround = codecNeedsSosFlushWorkaround(codecName); codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName); codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName); - codecNeedsEosBufferTimestampWorkaround = codecNeedsEosBufferTimestampWorkaround(codecName); - codecNeedsMonoChannelCountWorkaround = false; codecNeedsEosPropagation = codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation(); if (checkNotNull(codec).needsReconfiguration()) { @@ -1462,13 +1437,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { if (bufferEncrypted) { buffer.cryptoInfo.increaseClearDataFirstSubSampleBy(adaptiveReconfigurationBytes); } - if (codecNeedsDiscardToSpsWorkaround && !bufferEncrypted) { - NalUnitUtil.discardToSps(checkNotNull(buffer.data)); - if (checkNotNull(buffer.data).position() == 0) { - return true; - } - codecNeedsDiscardToSpsWorkaround = false; - } long presentationTimeUs = buffer.timeUs; @@ -1950,7 +1918,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private boolean drainAndFlushCodec() { if (codecReceivedBuffers) { codecDrainState = DRAIN_STATE_SIGNAL_END_OF_STREAM; - if (codecNeedsFlushWorkaround || codecNeedsEosFlushWorkaround) { + if (codecNeedsEosFlushWorkaround) { codecDrainAction = DRAIN_ACTION_REINITIALIZE; return false; } else { @@ -1973,7 +1941,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer { private boolean drainAndUpdateCodecDrmSessionV23() throws ExoPlaybackException { if (codecReceivedBuffers) { codecDrainState = DRAIN_STATE_SIGNAL_END_OF_STREAM; - if (codecNeedsFlushWorkaround || codecNeedsEosFlushWorkaround) { + if (codecNeedsEosFlushWorkaround) { codecDrainAction = DRAIN_ACTION_REINITIALIZE; return false; } else { @@ -2060,12 +2028,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { outputBuffer.position(outputBufferInfo.offset); outputBuffer.limit(outputBufferInfo.offset + outputBufferInfo.size); } - if (codecNeedsEosBufferTimestampWorkaround - && outputBufferInfo.presentationTimeUs == 0 - && (outputBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 - && largestQueuedPresentationTimeUs != C.TIME_UNSET) { - outputBufferInfo.presentationTimeUs = lastBufferInStreamPresentationTimeUs; - } isDecodeOnlyOutputBuffer = outputBufferInfo.presentationTimeUs < getLastResetPositionUs(); isLastOutputBuffer = lastBufferInStreamPresentationTimeUs != C.TIME_UNSET @@ -2138,9 +2100,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { shouldSkipAdaptationWorkaroundOutputBuffer = true; return; } - if (codecNeedsMonoChannelCountWorkaround) { - mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); - } codecOutputMediaFormat = mediaFormat; codecOutputMediaFormatChanged = true; } @@ -2557,44 +2516,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { /* startTimeUs= */ startTimeUs, /* frameTimeUs= */ frameTimeUs)); } - private static boolean isMediaCodecException(IllegalStateException error) { - if (Util.SDK_INT >= 21 && isMediaCodecExceptionV21(error)) { - return true; - } - StackTraceElement[] stackTrace = error.getStackTrace(); - return stackTrace.length > 0 && stackTrace[0].getClassName().equals("android.media.MediaCodec"); - } - - @RequiresApi(21) - private static boolean isMediaCodecExceptionV21(IllegalStateException error) { - return error instanceof MediaCodec.CodecException; - } - - @RequiresApi(21) - private static boolean isRecoverableMediaCodecExceptionV21(IllegalStateException error) { - if (error instanceof MediaCodec.CodecException) { - return ((MediaCodec.CodecException) error).isRecoverable(); - } - return false; - } - - /** - * Returns whether the decoder is known to fail when flushed. - * - *
If true is returned, the renderer will work around the issue by releasing the decoder and - * instantiating a new one rather than flushing the current instance. - * - *
See [Internal: b/8347958, b/8543366]. - * - * @param name The name of the decoder. - * @return True if the decoder is known to fail when flushed. - */ - private static boolean codecNeedsFlushWorkaround(String name) { - return Util.SDK_INT == 19 - && Util.MODEL.startsWith("SM-G800") - && ("OMX.Exynos.avc.dec".equals(name) || "OMX.Exynos.avc.dec.secure".equals(name)); - } - /** * Returns a mode that specifies when the adaptation workaround should be enabled. * @@ -2628,23 +2549,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { } } - /** - * Returns whether the decoder is an H.264/AVC decoder known to fail if NAL units are queued - * before the codec specific data. - * - *
If true is returned, the renderer will work around the issue by discarding data up to the - * SPS. - * - * @param name The name of the decoder. - * @param format The {@link Format} used to configure the decoder. - * @return True if the decoder is known to fail if NAL units are queued before CSD. - */ - private static boolean codecNeedsDiscardToSpsWorkaround(String name, Format format) { - return Util.SDK_INT < 21 - && format.initializationData.isEmpty() - && "OMX.MTK.VIDEO.DECODER.AVC".equals(name); - } - /** * Returns whether the decoder is known to behave incorrectly if flushed prior to having output a * {@link MediaFormat}. @@ -2708,24 +2612,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer { || "OMX.amlogic.avc.decoder.awesome.secure".equals(name))); } - /** - * Returns whether the decoder may output a non-empty buffer with timestamp 0 as the end of stream - * buffer. - * - *
See GitHub issue #5045.
- */
- private static boolean codecNeedsEosBufferTimestampWorkaround(String codecName) {
- return Util.SDK_INT < 21
- && "OMX.SEC.mp3.dec".equals(codecName)
- && "samsung".equals(Util.MANUFACTURER)
- && (Util.DEVICE.startsWith("baffin")
- || Util.DEVICE.startsWith("grand")
- || Util.DEVICE.startsWith("fortuna")
- || Util.DEVICE.startsWith("gprimelte")
- || Util.DEVICE.startsWith("j2y18lte")
- || Util.DEVICE.startsWith("ms01"));
- }
-
/**
* Returns whether the decoder may throw an {@link IllegalStateException} from {@link
* MediaCodec#dequeueOutputBuffer(MediaCodec.BufferInfo, long)} or {@link
@@ -2763,15 +2649,6 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
- @RequiresApi(21)
- private static final class Api21 {
- @DoNotInline
- public static boolean registerOnBufferAvailableListener(
- MediaCodecAdapter codec, MediaCodecRendererCodecAdapterListener listener) {
- return codec.registerOnBufferAvailableListener(listener);
- }
- }
-
@RequiresApi(31)
private static final class Api31 {
private Api31() {}
diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
index 0890ec10ab..fb02c89f30 100644
--- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
+++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/video/MediaCodecVideoRenderer.java
@@ -1260,7 +1260,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
}
int width;
int height;
- int unappliedRotationDegrees = 0;
float pixelWidthHeightRatio;
if (tunneling) {
@@ -1283,22 +1282,16 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
: mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
}
pixelWidthHeightRatio = format.pixelWidthHeightRatio;
- if (codecAppliesRotation()) {
- // On API level 21 and above the decoder applies the rotation when rendering to the surface.
- // Hence currentUnappliedRotation should always be 0. For 90 and 270 degree rotations, we need
- // to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
- if (format.rotationDegrees == 90 || format.rotationDegrees == 270) {
- int rotatedHeight = width;
- width = height;
- height = rotatedHeight;
- pixelWidthHeightRatio = 1 / pixelWidthHeightRatio;
- }
- } else if (videoSink == null) {
- // Neither the codec nor the video sink applies the rotation.
- unappliedRotationDegrees = format.rotationDegrees;
+ // The decoder applies the rotation when rendering to the surface. For 90 and 270 degree
+ // rotations, we need to flip the width, height and pixel aspect ratio to reflect the rotation
+ // that was applied.
+ if (format.rotationDegrees == 90 || format.rotationDegrees == 270) {
+ int rotatedHeight = width;
+ width = height;
+ height = rotatedHeight;
+ pixelWidthHeightRatio = 1 / pixelWidthHeightRatio;
}
- decodedVideoSize =
- new VideoSize(width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
+ decodedVideoSize = new VideoSize(width, height, pixelWidthHeightRatio);
if (videoSink != null && videoSinkNeedsRegisterInputStream) {
onReadyToRegisterVideoSinkInputStream();
@@ -1308,7 +1301,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
.buildUpon()
.setWidth(width)
.setHeight(height)
- .setRotationDegrees(unappliedRotationDegrees)
.setPixelWidthHeightRatio(pixelWidthHeightRatio)
.build());
} else {
@@ -1455,7 +1447,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
case VideoFrameReleaseControl.FRAME_RELEASE_TRY_AGAIN_LATER:
return false;
case VideoFrameReleaseControl.FRAME_RELEASE_SCHEDULED:
- return maybeReleaseFrame(checkStateNotNull(codec), bufferIndex, presentationTimeUs, format);
+ releaseFrame(checkStateNotNull(codec), bufferIndex, presentationTimeUs, format);
+ return true;
default:
throw new IllegalStateException(String.valueOf(frameReleaseAction));
}
@@ -1469,46 +1462,22 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
return -startPositionUs;
}
- private boolean maybeReleaseFrame(
+ private void releaseFrame(
MediaCodecAdapter codec, int bufferIndex, long presentationTimeUs, Format format) {
long releaseTimeNs = videoFrameReleaseInfo.getReleaseTimeNs();
long earlyUs = videoFrameReleaseInfo.getEarlyUs();
- if (Util.SDK_INT >= 21) {
- // Let the underlying framework time the release.
- if (shouldSkipBuffersWithIdenticalReleaseTime() && releaseTimeNs == lastFrameReleaseTimeNs) {
- // This frame should be displayed on the same vsync with the previous released frame. We
- // are likely rendering frames at a rate higher than the screen refresh rate. Skip
- // this buffer so that it's returned to MediaCodec sooner otherwise MediaCodec may not
- // be able to keep decoding with this rate [b/263454203].
- skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
- } else {
- notifyFrameMetadataListener(presentationTimeUs, releaseTimeNs, format);
- renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, releaseTimeNs);
- }
- updateVideoFrameProcessingOffsetCounters(earlyUs);
- lastFrameReleaseTimeNs = releaseTimeNs;
- return true;
- } else if (earlyUs < 30000) {
- // We need to time the release ourselves.
- if (earlyUs > 11000) {
- // We're a little too early to render the frame. Sleep until the frame can be rendered.
- // Note: The 11ms threshold was chosen fairly arbitrarily.
- try {
- // Subtracting 10000 rather than 11000 ensures the sleep time will be at least 1ms.
- Thread.sleep((earlyUs - 10000) / 1000);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- return false;
- }
- }
- notifyFrameMetadataListener(presentationTimeUs, releaseTimeNs, format);
- renderOutputBuffer(codec, bufferIndex, presentationTimeUs);
- updateVideoFrameProcessingOffsetCounters(earlyUs);
- return true;
+ if (shouldSkipBuffersWithIdenticalReleaseTime() && releaseTimeNs == lastFrameReleaseTimeNs) {
+ // This frame should be displayed on the same vsync with the previous released frame. We
+ // are likely rendering frames at a rate higher than the screen refresh rate. Skip
+ // this buffer so that it's returned to MediaCodec sooner otherwise MediaCodec may not
+ // be able to keep decoding with this rate [b/263454203].
+ skipOutputBuffer(codec, bufferIndex, presentationTimeUs);
} else {
- // Too soon.
- return false;
+ notifyFrameMetadataListener(presentationTimeUs, releaseTimeNs, format);
+ renderOutputBufferV21(codec, bufferIndex, presentationTimeUs, releaseTimeNs);
}
+ updateVideoFrameProcessingOffsetCounters(earlyUs);
+ lastFrameReleaseTimeNs = releaseTimeNs;
}
private void notifyFrameMetadataListener(
@@ -1715,21 +1684,14 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
*/
private void renderOutputBuffer(
MediaCodecAdapter codec, int index, long presentationTimeUs, long releaseTimeNs) {
- if (Util.SDK_INT >= 21) {
- renderOutputBufferV21(codec, index, presentationTimeUs, releaseTimeNs);
- } else {
- renderOutputBuffer(codec, index, presentationTimeUs);
- }
+ renderOutputBufferV21(codec, index, presentationTimeUs, releaseTimeNs);
}
/**
- * Renders the output buffer with the specified index. This method is only called if the platform
- * API version of the device is less than 21.
- *
- * @param codec The codec that owns the output buffer.
- * @param index The index of the output buffer to drop.
- * @param presentationTimeUs The presentation time of the output buffer, in microseconds.
+ * @deprecated Override {@link #renderOutputBufferV21} instead. The library has min SDK 21, so
+ * this method is never called.
*/
+ @Deprecated
protected void renderOutputBuffer(MediaCodecAdapter codec, int index, long presentationTimeUs) {
TraceUtil.beginSection("releaseOutputBuffer");
codec.releaseOutputBuffer(index, true);
@@ -1751,7 +1713,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
* @param presentationTimeUs The presentation time of the output buffer, in microseconds.
* @param releaseTimeNs The wallclock time at which the frame should be displayed, in nanoseconds.
*/
- @RequiresApi(21)
protected void renderOutputBufferV21(
MediaCodecAdapter codec, int index, long presentationTimeUs, long releaseTimeNs) {
TraceUtil.beginSection("releaseOutputBuffer");
@@ -1903,12 +1864,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
codec.setOutputSurface(surface);
}
- @RequiresApi(21)
- private static void configureTunnelingV21(MediaFormat mediaFormat, int tunnelingAudioSessionId) {
- mediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
- mediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelingAudioSessionId);
- }
-
/**
* Returns the framework {@link MediaFormat} that should be used to configure the decoder.
*
@@ -1924,7 +1879,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
* @return The framework {@link MediaFormat} that should be used to configure the decoder.
*/
@SuppressLint("InlinedApi")
- @TargetApi(21) // tunnelingAudioSessionId is unset if Util.SDK_INT < 21
protected MediaFormat getMediaFormat(
Format format,
String codecMimeType,
@@ -1968,7 +1922,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
mediaFormat.setInteger("auto-frc", 0);
}
if (tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET) {
- configureTunnelingV21(mediaFormat, tunnelingAudioSessionId);
+ mediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
+ mediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelingAudioSessionId);
}
if (Util.SDK_INT >= 35) {
mediaFormat.setInteger(MediaFormat.KEY_IMPORTANCE, max(0, -rendererPriority));
@@ -2066,7 +2021,7 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
if (longEdgePx <= formatLongEdgePx || shortEdgePx <= formatShortEdgePx) {
// Don't return a size not larger than the format for which the codec is being configured.
return null;
- } else if (Util.SDK_INT >= 21) {
+ } else {
Point alignedSize =
codecInfo.alignVideoSizeV21(
isVerticalVideo ? shortEdgePx : longEdgePx,
@@ -2076,20 +2031,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
&& codecInfo.isVideoSizeAndRateSupportedV21(alignedSize.x, alignedSize.y, frameRate)) {
return alignedSize;
}
- } else {
- try {
- // Conservatively assume the codec requires 16px width and height alignment.
- longEdgePx = Util.ceilDivide(longEdgePx, 16) * 16;
- shortEdgePx = Util.ceilDivide(shortEdgePx, 16) * 16;
- if (longEdgePx * shortEdgePx <= MediaCodecUtil.maxH264DecodableFrameSize()) {
- return new Point(
- isVerticalVideo ? shortEdgePx : longEdgePx,
- isVerticalVideo ? longEdgePx : shortEdgePx);
- }
- } catch (DecoderQueryException e) {
- // We tried our best. Give up!
- return null;
- }
}
}
return null;
@@ -2118,10 +2059,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer
}
}
- private static boolean codecAppliesRotation() {
- return Util.SDK_INT >= 21;
- }
-
/**
* Returns whether the device is known to do post processing by default that isn't compatible with
* ExoPlayer.
diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
index 12d8fee2ab..2c330bbe6a 100644
--- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
+++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/video/MediaCodecVideoRendererTest.java
@@ -636,6 +636,7 @@ public class MediaCodecVideoRendererTest {
}
@Test
+ @SuppressWarnings("deprecation") // Testing propagation of deprecated unappliedRotationDegrees.
public void render_sendsVideoSizeChangeWithCurrentFormatValues() throws Exception {
FakeSampleStream fakeSampleStream =
new FakeSampleStream(
diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java
index aa9ee66fe2..050e0dfda2 100644
--- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java
+++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerListenerTest.java
@@ -2649,7 +2649,7 @@ public class MediaControllerListenerTest {
@Test
public void onVideoSizeChanged() throws Exception {
- VideoSize defaultVideoSize = MediaTestUtils.createDefaultVideoSize();
+ VideoSize defaultVideoSize = MediaTestUtils.getDefaultVideoSize();
RemoteMediaSession session = createRemoteMediaSession(TEST_ON_VIDEO_SIZE_CHANGED);
MediaController controller = controllerTestRule.createController(session.getToken());
List