Move shouldTrancodeAudio/Video to static helper methods

PiperOrigin-RevId: 578617730
This commit is contained in:
tofunmi 2023-11-01 13:10:24 -07:00 committed by Copybara-Service
parent a671f4aede
commit de82aa93f0
2 changed files with 147 additions and 113 deletions

View file

@ -23,14 +23,13 @@ import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.contains;
import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_DECODED;
import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK;
import static androidx.media3.transformer.ExportException.ERROR_CODE_MUXING_FAILED;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
import static androidx.media3.transformer.TransformerUtil.areVideoEffectsAllNoOp;
import static androidx.media3.transformer.TransformerUtil.containsSlowMotionData;
import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType;
import static androidx.media3.transformer.TransformerUtil.shouldTranscodeAudio;
import static androidx.media3.transformer.TransformerUtil.shouldTranscodeVideo;
import static java.lang.Math.max;
import static java.lang.annotation.ElementType.TYPE_USE;
@ -45,14 +44,12 @@ import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Effect;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.util.Clock;
import androidx.media3.common.util.ConditionVariable;
import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.effect.ScaleAndRotateTransformation;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -445,7 +442,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final class SequenceAssetLoaderListener implements AssetLoader.Listener {
private final int sequenceIndex;
private final ImmutableList<EditedMediaItem> editedMediaItems;
private final EditedMediaItem firstEditedMediaItem;
private final Composition composition;
private final TransformationRequest transformationRequest;
private final AudioMixer.Factory audioMixerFactory;
@ -463,7 +460,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
FallbackListener fallbackListener,
DebugViewProvider debugViewProvider) {
this.sequenceIndex = sequenceIndex;
this.editedMediaItems = composition.sequences.get(sequenceIndex).editedMediaItems;
this.firstEditedMediaItem = composition.sequences.get(sequenceIndex).editedMediaItems.get(0);
this.composition = composition;
this.transformationRequest = transformationRequest;
this.audioMixerFactory = audioMixerFactory;
@ -535,7 +532,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
}
GraphInput sampleExporterInput =
sampleExporter.getInput(editedMediaItems.get(0), assetLoaderOutputFormat);
sampleExporter.getInput(firstEditedMediaItem, assetLoaderOutputFormat);
OnMediaItemChangedListener onMediaItemChangedListener =
(editedMediaItem, durationUs, trackFormat, isLast) -> {
onMediaItemChanged(trackType, durationUs, isLast);
@ -581,7 +578,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
firstAssetLoaderInputFormat,
/* firstInputFormat= */ assetLoaderOutputFormat,
transformationRequest,
editedMediaItems.get(0),
firstEditedMediaItem,
audioMixerFactory,
encoderFactory,
muxerWrapper,
@ -680,95 +677,29 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (!assetLoaderCanOutputEncoded) {
shouldTranscode = true;
} else if (trackType == TRACK_TYPE_AUDIO) {
shouldTranscode = shouldTranscodeAudio(inputFormat);
shouldTranscode =
shouldTranscodeAudio(
inputFormat,
composition,
sequenceIndex,
transformationRequest,
encoderFactory,
muxerWrapper);
} else if (trackType == C.TRACK_TYPE_VIDEO) {
shouldTranscode = shouldTranscodeVideo(inputFormat);
shouldTranscode =
shouldTranscodeVideo(
inputFormat,
composition,
sequenceIndex,
transformationRequest,
encoderFactory,
muxerWrapper);
}
checkState(!shouldTranscode || assetLoaderCanOutputDecoded);
return shouldTranscode;
}
private boolean shouldTranscodeAudio(Format inputFormat) {
if (composition.sequences.size() > 1 || editedMediaItems.size() > 1) {
return !composition.transmuxAudio;
}
if (encoderFactory.audioNeedsEncoding()) {
return true;
}
if (transformationRequest.audioMimeType != null
&& !transformationRequest.audioMimeType.equals(inputFormat.sampleMimeType)) {
return true;
}
if (transformationRequest.audioMimeType == null
&& !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
return true;
}
EditedMediaItem firstEditedMediaItem = editedMediaItems.get(0);
if (firstEditedMediaItem.flattenForSlowMotion && containsSlowMotionData(inputFormat)) {
return true;
}
if (!firstEditedMediaItem.effects.audioProcessors.isEmpty()) {
return true;
}
return false;
}
private boolean shouldTranscodeVideo(Format inputFormat) {
if (composition.sequences.size() > 1 || editedMediaItems.size() > 1) {
return !composition.transmuxVideo;
}
EditedMediaItem firstEditedMediaItem = editedMediaItems.get(0);
if (firstEditedMediaItem.mediaItem.clippingConfiguration.startPositionMs > 0
&& !firstEditedMediaItem.mediaItem.clippingConfiguration.startsAtKeyFrame) {
return true;
}
if (encoderFactory.videoNeedsEncoding()) {
return true;
}
if (transformationRequest.hdrMode != HDR_MODE_KEEP_HDR) {
return true;
}
if (transformationRequest.videoMimeType != null
&& !transformationRequest.videoMimeType.equals(inputFormat.sampleMimeType)) {
return true;
}
if (transformationRequest.videoMimeType == null
&& !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
return true;
}
if (inputFormat.pixelWidthHeightRatio != 1f) {
return true;
}
ImmutableList<Effect> videoEffects = firstEditedMediaItem.effects.videoEffects;
return !videoEffects.isEmpty()
&& !areVideoEffectsAllNoOp(videoEffects, inputFormat)
&& !hasOnlyRegularRotationEffect(videoEffects);
}
private boolean hasOnlyRegularRotationEffect(ImmutableList<Effect> videoEffects) {
if (videoEffects.size() != 1) {
return false;
}
Effect videoEffect = videoEffects.get(0);
if (!(videoEffect instanceof ScaleAndRotateTransformation)) {
return false;
}
ScaleAndRotateTransformation scaleAndRotateTransformation =
(ScaleAndRotateTransformation) videoEffect;
if (scaleAndRotateTransformation.scaleX != 1f || scaleAndRotateTransformation.scaleY != 1f) {
return false;
}
float rotationDegrees = scaleAndRotateTransformation.rotationDegrees;
if (rotationDegrees == 90f || rotationDegrees == 180f || rotationDegrees == 270f) {
// The MuxerWrapper rotation is clockwise while the ScaleAndRotateTransformation rotation
// is counterclockwise.
muxerWrapper.setAdditionalRotationDegrees(360 - Math.round(rotationDegrees));
return true;
}
return false;
}
}
/** Tracks the inputs and outputs of {@link AssetLoader AssetLoaders}. */

View file

@ -16,6 +16,8 @@
package androidx.media3.transformer;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import android.media.MediaCodec;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
@ -24,6 +26,7 @@ import androidx.media3.common.Format;
import androidx.media3.common.Metadata;
import androidx.media3.common.MimeTypes;
import androidx.media3.effect.GlEffect;
import androidx.media3.effect.ScaleAndRotateTransformation;
import androidx.media3.extractor.metadata.mp4.SlowMotionData;
import com.google.common.collect.ImmutableList;
@ -45,6 +48,110 @@ import com.google.common.collect.ImmutableList;
return trackType == C.TRACK_TYPE_IMAGE ? C.TRACK_TYPE_VIDEO : trackType;
}
/** Returns {@link MediaCodec} flags corresponding to {@link C.BufferFlags}. */
public static int getMediaCodecFlags(@C.BufferFlags int flags) {
int mediaCodecFlags = 0;
if ((flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME) {
mediaCodecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
}
if ((flags & C.BUFFER_FLAG_END_OF_STREAM) == C.BUFFER_FLAG_END_OF_STREAM) {
mediaCodecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
}
return mediaCodecFlags;
}
/** Returns whether the audio track should be transcoded. */
public static boolean shouldTranscodeAudio(
Format inputFormat,
Composition composition,
int sequenceIndex,
TransformationRequest transformationRequest,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper) {
if (composition.sequences.size() > 1
|| composition.sequences.get(sequenceIndex).editedMediaItems.size() > 1) {
return !composition.transmuxAudio;
}
if (encoderFactory.audioNeedsEncoding()) {
return true;
}
if (transformationRequest.audioMimeType != null
&& !transformationRequest.audioMimeType.equals(inputFormat.sampleMimeType)) {
return true;
}
if (transformationRequest.audioMimeType == null
&& !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
return true;
}
EditedMediaItem firstEditedMediaItem =
composition.sequences.get(sequenceIndex).editedMediaItems.get(0);
if (firstEditedMediaItem.flattenForSlowMotion && containsSlowMotionData(inputFormat)) {
return true;
}
if (!firstEditedMediaItem.effects.audioProcessors.isEmpty()) {
return true;
}
return false;
}
/**
* Returns whether the {@link Format} contains {@linkplain SlowMotionData slow motion metadata}.
*/
private static boolean containsSlowMotionData(Format format) {
@Nullable Metadata metadata = format.metadata;
if (metadata == null) {
return false;
}
for (int i = 0; i < metadata.length(); i++) {
if (metadata.get(i) instanceof SlowMotionData) {
return true;
}
}
return false;
}
/** Returns whether the video track should be transcoded. */
public static boolean shouldTranscodeVideo(
Format inputFormat,
Composition composition,
int sequenceIndex,
TransformationRequest transformationRequest,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper) {
if (composition.sequences.size() > 1
|| composition.sequences.get(sequenceIndex).editedMediaItems.size() > 1) {
return !composition.transmuxVideo;
}
EditedMediaItem firstEditedMediaItem =
composition.sequences.get(sequenceIndex).editedMediaItems.get(0);
if (firstEditedMediaItem.mediaItem.clippingConfiguration.startPositionMs > 0
&& !firstEditedMediaItem.mediaItem.clippingConfiguration.startsAtKeyFrame) {
return true;
}
if (encoderFactory.videoNeedsEncoding()) {
return true;
}
if (transformationRequest.hdrMode != HDR_MODE_KEEP_HDR) {
return true;
}
if (transformationRequest.videoMimeType != null
&& !transformationRequest.videoMimeType.equals(inputFormat.sampleMimeType)) {
return true;
}
if (transformationRequest.videoMimeType == null
&& !muxerWrapper.supportsSampleMimeType(inputFormat.sampleMimeType)) {
return true;
}
if (inputFormat.pixelWidthHeightRatio != 1f) {
return true;
}
ImmutableList<Effect> videoEffects = firstEditedMediaItem.effects.videoEffects;
return !videoEffects.isEmpty()
&& !areVideoEffectsAllNoOp(videoEffects, inputFormat)
&& !hasOnlyRegularRotationEffect(videoEffects, muxerWrapper);
}
/**
* Returns whether the collection of {@code videoEffects} would be a {@linkplain
* GlEffect#isNoOp(int, int) no-op}, if queued samples of this {@link Format}.
@ -70,31 +177,27 @@ import com.google.common.collect.ImmutableList;
return true;
}
/**
* Returns whether the {@link Format} contains {@linkplain SlowMotionData slow motion metadata}.
*/
public static boolean containsSlowMotionData(Format format) {
@Nullable Metadata metadata = format.metadata;
if (metadata == null) {
private static boolean hasOnlyRegularRotationEffect(
ImmutableList<Effect> videoEffects, MuxerWrapper muxerWrapper) {
if (videoEffects.size() != 1) {
return false;
}
for (int i = 0; i < metadata.length(); i++) {
if (metadata.get(i) instanceof SlowMotionData) {
return true;
}
Effect videoEffect = videoEffects.get(0);
if (!(videoEffect instanceof ScaleAndRotateTransformation)) {
return false;
}
ScaleAndRotateTransformation scaleAndRotateTransformation =
(ScaleAndRotateTransformation) videoEffect;
if (scaleAndRotateTransformation.scaleX != 1f || scaleAndRotateTransformation.scaleY != 1f) {
return false;
}
float rotationDegrees = scaleAndRotateTransformation.rotationDegrees;
if (rotationDegrees == 90f || rotationDegrees == 180f || rotationDegrees == 270f) {
// The MuxerWrapper rotation is clockwise while the ScaleAndRotateTransformation rotation
// is counterclockwise.
muxerWrapper.setAdditionalRotationDegrees(360 - Math.round(rotationDegrees));
return true;
}
return false;
}
/** Returns {@link MediaCodec} flags corresponding to {@link C.BufferFlags}. */
public static int getMediaCodecFlags(@C.BufferFlags int flags) {
int mediaCodecFlags = 0;
if ((flags & C.BUFFER_FLAG_KEY_FRAME) == C.BUFFER_FLAG_KEY_FRAME) {
mediaCodecFlags |= MediaCodec.BUFFER_FLAG_KEY_FRAME;
}
if ((flags & C.BUFFER_FLAG_END_OF_STREAM) == C.BUFFER_FLAG_END_OF_STREAM) {
mediaCodecFlags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
}
return mediaCodecFlags;
}
}