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: + * + *