Set assumedVideoMinimumCodecOperatingRate for all playbacks
PiperOrigin-RevId: 405736227
This commit is contained in:
parent
933e207b3e
commit
aff15ae9ee
@ -208,7 +208,8 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
/* enableDecoderFallback= */ false,
|
/* enableDecoderFallback= */ false,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
eventListener,
|
eventListener,
|
||||||
maxDroppedFramesToNotify);
|
maxDroppedFramesToNotify,
|
||||||
|
/* assumedMinimumCodecOperatingRate= */ 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -241,12 +242,11 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
enableDecoderFallback,
|
enableDecoderFallback,
|
||||||
eventHandler,
|
eventHandler,
|
||||||
eventListener,
|
eventListener,
|
||||||
maxDroppedFramesToNotify);
|
maxDroppedFramesToNotify,
|
||||||
|
/* assumedMinimumCodecOperatingRate= */ 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* @param context A context.
|
* @param context A context.
|
||||||
* @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link
|
* @param codecAdapterFactory The {@link MediaCodecAdapter.Factory} used to create {@link
|
||||||
* MediaCodecAdapter} instances.
|
* MediaCodecAdapter} instances.
|
||||||
@ -271,12 +271,56 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
@Nullable Handler eventHandler,
|
@Nullable Handler eventHandler,
|
||||||
@Nullable VideoRendererEventListener eventListener,
|
@Nullable VideoRendererEventListener eventListener,
|
||||||
int maxDroppedFramesToNotify) {
|
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(
|
super(
|
||||||
C.TRACK_TYPE_VIDEO,
|
C.TRACK_TYPE_VIDEO,
|
||||||
codecAdapterFactory,
|
codecAdapterFactory,
|
||||||
mediaCodecSelector,
|
mediaCodecSelector,
|
||||||
enableDecoderFallback,
|
enableDecoderFallback,
|
||||||
/* assumedMinimumCodecOperatingRate= */ 30);
|
assumedMinimumCodecOperatingRate);
|
||||||
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
|
this.allowedJoiningTimeMs = allowedJoiningTimeMs;
|
||||||
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
|
@ -1435,7 +1435,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
int esdsAtomPosition =
|
int esdsAtomPosition =
|
||||||
childAtomType == Atom.TYPE_esds
|
childAtomType == Atom.TYPE_esds
|
||||||
? childPosition
|
? childPosition
|
||||||
: findEsdsPosition(parent, childPosition, childAtomSize);
|
: findBoxPosition(parent, Atom.TYPE_esds, childPosition, childAtomSize);
|
||||||
if (esdsAtomPosition != C.POSITION_UNSET) {
|
if (esdsAtomPosition != C.POSITION_UNSET) {
|
||||||
Pair<@NullableType String, byte @NullableType []> mimeTypeAndInitializationData =
|
Pair<@NullableType String, byte @NullableType []> mimeTypeAndInitializationData =
|
||||||
parseEsdsFromParent(parent, esdsAtomPosition);
|
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
|
* Returns the position of the first box with the given {@code boxType} within {@code parent}, or
|
||||||
* box is found
|
* {@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 {
|
throws ParserException {
|
||||||
int childAtomPosition = parent.getPosition();
|
int childAtomPosition = parent.getPosition();
|
||||||
while (childAtomPosition - position < size) {
|
ExtractorUtil.checkContainerInput(childAtomPosition >= parentBoxPosition, /* message= */ null);
|
||||||
|
while (childAtomPosition - parentBoxPosition < parentBoxSize) {
|
||||||
parent.setPosition(childAtomPosition);
|
parent.setPosition(childAtomPosition);
|
||||||
int childAtomSize = parent.readInt();
|
int childAtomSize = parent.readInt();
|
||||||
ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive");
|
ExtractorUtil.checkContainerInput(childAtomSize > 0, "childAtomSize must be positive");
|
||||||
int childType = parent.readInt();
|
int childType = parent.readInt();
|
||||||
if (childType == Atom.TYPE_esds) {
|
if (childType == boxType) {
|
||||||
return childAtomPosition;
|
return childAtomPosition;
|
||||||
}
|
}
|
||||||
childAtomPosition += childAtomSize;
|
childAtomPosition += childAtomSize;
|
||||||
|
@ -102,6 +102,7 @@ public final class TranscodingTransformer {
|
|||||||
private boolean flattenForSlowMotion;
|
private boolean flattenForSlowMotion;
|
||||||
private String outputMimeType;
|
private String outputMimeType;
|
||||||
@Nullable private String audioMimeType;
|
@Nullable private String audioMimeType;
|
||||||
|
@Nullable private String videoMimeType;
|
||||||
private TranscodingTransformer.Listener listener;
|
private TranscodingTransformer.Listener listener;
|
||||||
private Looper looper;
|
private Looper looper;
|
||||||
private Clock clock;
|
private Clock clock;
|
||||||
@ -125,6 +126,7 @@ public final class TranscodingTransformer {
|
|||||||
this.flattenForSlowMotion = transcodingTransformer.transformation.flattenForSlowMotion;
|
this.flattenForSlowMotion = transcodingTransformer.transformation.flattenForSlowMotion;
|
||||||
this.outputMimeType = transcodingTransformer.transformation.outputMimeType;
|
this.outputMimeType = transcodingTransformer.transformation.outputMimeType;
|
||||||
this.audioMimeType = transcodingTransformer.transformation.audioMimeType;
|
this.audioMimeType = transcodingTransformer.transformation.audioMimeType;
|
||||||
|
this.videoMimeType = transcodingTransformer.transformation.videoMimeType;
|
||||||
this.listener = transcodingTransformer.listener;
|
this.listener = transcodingTransformer.listener;
|
||||||
this.looper = transcodingTransformer.looper;
|
this.looper = transcodingTransformer.looper;
|
||||||
this.clock = transcodingTransformer.clock;
|
this.clock = transcodingTransformer.clock;
|
||||||
@ -231,6 +233,33 @@ public final class TranscodingTransformer {
|
|||||||
return this;
|
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:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>when the container MIME type is {@link MimeTypes#VIDEO_MP4}:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link MimeTypes#VIDEO_H263}
|
||||||
|
* <li>{@link MimeTypes#VIDEO_H264}
|
||||||
|
* <li>{@link MimeTypes#VIDEO_H265} from API level 24
|
||||||
|
* <li>{@link MimeTypes#VIDEO_MP4V}
|
||||||
|
* </ul>
|
||||||
|
* <li>when the container MIME type is {@link MimeTypes#VIDEO_WEBM}:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link MimeTypes#VIDEO_VP8}
|
||||||
|
* <li>{@link MimeTypes#VIDEO_VP9} from API level 24
|
||||||
|
* </ul>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @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
|
* Sets the audio MIME type of the output. The default value is to use the same MIME type as the
|
||||||
* input. Supported values are:
|
* input. Supported values are:
|
||||||
@ -331,12 +360,10 @@ public final class TranscodingTransformer {
|
|||||||
muxerFactory.supportsOutputMimeType(outputMimeType),
|
muxerFactory.supportsOutputMimeType(outputMimeType),
|
||||||
"Unsupported output MIME type: " + outputMimeType);
|
"Unsupported output MIME type: " + outputMimeType);
|
||||||
if (audioMimeType != null) {
|
if (audioMimeType != null) {
|
||||||
checkState(
|
checkSampleMimeType(audioMimeType);
|
||||||
muxerFactory.supportsSampleMimeType(audioMimeType, outputMimeType),
|
}
|
||||||
"Unsupported sample MIME type "
|
if (videoMimeType != null) {
|
||||||
+ audioMimeType
|
checkSampleMimeType(videoMimeType);
|
||||||
+ " for container MIME type "
|
|
||||||
+ outputMimeType);
|
|
||||||
}
|
}
|
||||||
Transformation transformation =
|
Transformation transformation =
|
||||||
new Transformation(
|
new Transformation(
|
||||||
@ -345,10 +372,19 @@ public final class TranscodingTransformer {
|
|||||||
flattenForSlowMotion,
|
flattenForSlowMotion,
|
||||||
outputMimeType,
|
outputMimeType,
|
||||||
audioMimeType,
|
audioMimeType,
|
||||||
/* videoMimeType= */ null);
|
videoMimeType);
|
||||||
return new TranscodingTransformer(
|
return new TranscodingTransformer(
|
||||||
context, mediaSourceFactory, muxerFactory, transformation, listener, looper, clock);
|
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. */
|
/** A listener for the transformation events. */
|
||||||
|
@ -58,7 +58,10 @@ import androidx.media3.exoplayer.RendererCapabilities;
|
|||||||
? sampleMimeType
|
? sampleMimeType
|
||||||
: transformation.audioMimeType))
|
: transformation.audioMimeType))
|
||||||
|| (MimeTypes.isVideo(sampleMimeType)
|
|| (MimeTypes.isVideo(sampleMimeType)
|
||||||
&& muxerWrapper.supportsSampleMimeType(sampleMimeType))) {
|
&& muxerWrapper.supportsSampleMimeType(
|
||||||
|
transformation.videoMimeType == null
|
||||||
|
? sampleMimeType
|
||||||
|
: transformation.videoMimeType))) {
|
||||||
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
return RendererCapabilities.create(C.FORMAT_HANDLED);
|
||||||
} else {
|
} else {
|
||||||
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
|
return RendererCapabilities.create(C.FORMAT_UNSUPPORTED_SUBTYPE);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user