From aff15ae9eeb1440e972090667b1eb3ef78e27243 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 26 Oct 2021 22:30:30 +0100 Subject: [PATCH] Set assumedVideoMinimumCodecOperatingRate for all playbacks PiperOrigin-RevId: 405736227 --- .../video/MediaCodecVideoRenderer.java | 54 +++++++++++++++++-- .../media3/extractor/mp4/AtomParsers.java | 22 +++++--- .../transformer/TranscodingTransformer.java | 50 ++++++++++++++--- .../transformer/TransformerBaseRenderer.java | 5 +- 4 files changed, 112 insertions(+), 19 deletions(-) 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 93176cb7fd..f8a63cac61 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 @@ -208,7 +208,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { /* enableDecoderFallback= */ false, eventHandler, eventListener, - maxDroppedFramesToNotify); + maxDroppedFramesToNotify, + /* assumedMinimumCodecOperatingRate= */ 30); } /** @@ -241,12 +242,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { enableDecoderFallback, eventHandler, eventListener, - maxDroppedFramesToNotify); + maxDroppedFramesToNotify, + /* assumedMinimumCodecOperatingRate= */ 30); } /** - * Creates a new instance. - * * @param context A context. * @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link * MediaCodecAdapter} instances. @@ -271,12 +271,56 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer { @Nullable Handler eventHandler, @Nullable VideoRendererEventListener eventListener, int maxDroppedFramesToNotify) { + + this( + context, + codecAdapterFactory, + mediaCodecSelector, + allowedJoiningTimeMs, + enableDecoderFallback, + eventHandler, + eventListener, + maxDroppedFramesToNotify, + /* assumedMinimumCodecOperatingRate= */ 30); + } + + /** + * Creates a new instance. + * + * @param context A context. + * @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link + * MediaCodecAdapter} instances. + * @param mediaCodecSelector A decoder selector. + * @param allowedJoiningTimeMs The maximum duration in milliseconds for which this video renderer + * can attempt to seamlessly join an ongoing playback. + * @param enableDecoderFallback Whether to enable fallback to lower-priority decoders if decoder + * initialization fails. This may result in using a decoder that is slower/less efficient than + * the primary decoder. + * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be + * null if delivery of events is not required. + * @param eventListener A listener of events. May be null if delivery of events is not required. + * @param maxDroppedFramesToNotify The maximum number of frames that can be dropped between + * invocations of {@link VideoRendererEventListener#onDroppedFrames(int, long)}. + * @param assumedMinimumCodecOperatingRate A codec operating rate that all codecs instantiated by + * this renderer are assumed to meet implicitly (i.e. without the operating rate being set + * explicitly using {@link MediaFormat#KEY_OPERATING_RATE}). + */ + public MediaCodecVideoRenderer( + Context context, + MediaCodecAdapter.Factory codecAdapterFactory, + MediaCodecSelector mediaCodecSelector, + long allowedJoiningTimeMs, + boolean enableDecoderFallback, + @Nullable Handler eventHandler, + @Nullable VideoRendererEventListener eventListener, + int maxDroppedFramesToNotify, + float assumedMinimumCodecOperatingRate) { super( C.TRACK_TYPE_VIDEO, codecAdapterFactory, mediaCodecSelector, enableDecoderFallback, - /* assumedMinimumCodecOperatingRate= */ 30); + assumedMinimumCodecOperatingRate); this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.context = context.getApplicationContext(); diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java index 976f8b27bf..5dbb3960c4 100644 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java +++ b/libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java @@ -1435,7 +1435,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; int esdsAtomPosition = childAtomType == Atom.TYPE_esds ? childPosition - : findEsdsPosition(parent, childPosition, childAtomSize); + : findBoxPosition(parent, Atom.TYPE_esds, childPosition, childAtomSize); if (esdsAtomPosition != C.POSITION_UNSET) { Pair<@NullableType String, byte @NullableType []> mimeTypeAndInitializationData = parseEsdsFromParent(parent, esdsAtomPosition); @@ -1537,18 +1537,28 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } /** - * Returns the position of the esds box within a parent, or {@link C#POSITION_UNSET} if no esds - * box is found + * Returns the position of the first box with the given {@code boxType} within {@code parent}, or + * {@link C#POSITION_UNSET} if no such box is found. + * + * @param parent The {@link ParsableByteArray} to search. The search will start from the {@link + * ParsableByteArray#getPosition() current position}. + * @param boxType The box type to search for. + * @param parentBoxPosition The position in {@code parent} of the box we are searching. + * @param parentBoxSize The size of the parent box we are searching in bytes. + * @return The position of the first box with the given {@code boxType} within {@code parent}, or + * {@link C#POSITION_UNSET} if no such box is found. */ - private static int findEsdsPosition(ParsableByteArray parent, int position, int size) + private static int findBoxPosition( + ParsableByteArray parent, int boxType, int parentBoxPosition, int parentBoxSize) throws ParserException { int childAtomPosition = parent.getPosition(); - while (childAtomPosition - position < size) { + ExtractorUtil.checkContainerInput(childAtomPosition >= parentBoxPosition, /* message= */ null); + while (childAtomPosition - parentBoxPosition < parentBoxSize) { parent.setPosition(childAtomPosition); int childAtomSize = parent.readInt(); ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive"); int childType = parent.readInt(); - if (childType == Atom.TYPE_esds) { + if (childType == boxType) { return childAtomPosition; } childAtomPosition += childAtomSize; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TranscodingTransformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TranscodingTransformer.java index a4796c8d37..5ebf54b826 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TranscodingTransformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TranscodingTransformer.java @@ -102,6 +102,7 @@ public final class TranscodingTransformer { private boolean flattenForSlowMotion; private String outputMimeType; @Nullable private String audioMimeType; + @Nullable private String videoMimeType; private TranscodingTransformer.Listener listener; private Looper looper; private Clock clock; @@ -125,6 +126,7 @@ public final class TranscodingTransformer { this.flattenForSlowMotion = transcodingTransformer.transformation.flattenForSlowMotion; this.outputMimeType = transcodingTransformer.transformation.outputMimeType; this.audioMimeType = transcodingTransformer.transformation.audioMimeType; + this.videoMimeType = transcodingTransformer.transformation.videoMimeType; this.listener = transcodingTransformer.listener; this.looper = transcodingTransformer.looper; this.clock = transcodingTransformer.clock; @@ -231,6 +233,33 @@ public final class TranscodingTransformer { return this; } + /** + * Sets the video MIME type of the output. The default value is to use the same MIME type as the + * input. Supported values are: + * + * + * + * @param videoMimeType The MIME type of the video samples in the output. + * @return This builder. + */ + public Builder setVideoMimeType(String videoMimeType) { + this.videoMimeType = videoMimeType; + return this; + } + /** * Sets the audio MIME type of the output. The default value is to use the same MIME type as the * input. Supported values are: @@ -331,12 +360,10 @@ public final class TranscodingTransformer { muxerFactory.supportsOutputMimeType(outputMimeType), "Unsupported output MIME type: " + outputMimeType); if (audioMimeType != null) { - checkState( - muxerFactory.supportsSampleMimeType(audioMimeType, outputMimeType), - "Unsupported sample MIME type " - + audioMimeType - + " for container MIME type " - + outputMimeType); + checkSampleMimeType(audioMimeType); + } + if (videoMimeType != null) { + checkSampleMimeType(videoMimeType); } Transformation transformation = new Transformation( @@ -345,10 +372,19 @@ public final class TranscodingTransformer { flattenForSlowMotion, outputMimeType, audioMimeType, - /* videoMimeType= */ null); + videoMimeType); return new TranscodingTransformer( context, mediaSourceFactory, muxerFactory, transformation, listener, looper, clock); } + + private void checkSampleMimeType(String sampleMimeType) { + checkState( + muxerFactory.supportsSampleMimeType(sampleMimeType, outputMimeType), + "Unsupported sample MIME type " + + sampleMimeType + + " for container MIME type " + + outputMimeType); + } } /** A listener for the transformation events. */ diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerBaseRenderer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerBaseRenderer.java index 7d577507bb..1b41678d37 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerBaseRenderer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerBaseRenderer.java @@ -58,7 +58,10 @@ import androidx.media3.exoplayer.RendererCapabilities; ? sampleMimeType : transformation.audioMimeType)) || (MimeTypes.isVideo(sampleMimeType) - && muxerWrapper.supportsSampleMimeType(sampleMimeType))) { + && muxerWrapper.supportsSampleMimeType( + transformation.videoMimeType == null + ? sampleMimeType + : transformation.videoMimeType))) { return RendererCapabilities.create(C.FORMAT_HANDLED); } else { return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);