mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Internal-only change
PiperOrigin-RevId: 743468059
This commit is contained in:
parent
bd14b753ee
commit
769aca2e32
@ -501,6 +501,8 @@ public class TransformerEndToEndTest {
|
|||||||
.build()
|
.build()
|
||||||
.run(testId, editedMediaItem);
|
.run(testId, editedMediaItem);
|
||||||
|
|
||||||
|
Format format = retrieveTrackFormat(context, result.filePath, C.TRACK_TYPE_VIDEO);
|
||||||
|
assertThat(format.rotationDegrees).isEqualTo(90);
|
||||||
assertThat(result.exportResult.width).isEqualTo(outputFormat.width);
|
assertThat(result.exportResult.width).isEqualTo(outputFormat.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,6 +529,8 @@ public class TransformerEndToEndTest {
|
|||||||
.build()
|
.build()
|
||||||
.run(testId, editedMediaItem);
|
.run(testId, editedMediaItem);
|
||||||
|
|
||||||
|
Format format = retrieveTrackFormat(context, result.filePath, C.TRACK_TYPE_VIDEO);
|
||||||
|
assertThat(format.rotationDegrees).isEqualTo(0);
|
||||||
assertThat(result.exportResult.width).isEqualTo(inputFormat.width);
|
assertThat(result.exportResult.width).isEqualTo(inputFormat.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,9 @@ public final class Transformer {
|
|||||||
/** A builder for {@link Transformer} instances. */
|
/** A builder for {@link Transformer} instances. */
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
|
private static final ImmutableList<Integer> ALL_ROTATION_DEGREES =
|
||||||
|
ImmutableList.of(0, 90, 180, 270);
|
||||||
|
|
||||||
// Mandatory field.
|
// Mandatory field.
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -109,7 +112,7 @@ public final class Transformer {
|
|||||||
private boolean removeAudio;
|
private boolean removeAudio;
|
||||||
private boolean removeVideo;
|
private boolean removeVideo;
|
||||||
private boolean trimOptimizationEnabled;
|
private boolean trimOptimizationEnabled;
|
||||||
private boolean portraitEncodingEnabled;
|
private ImmutableList<Integer> allowedEncodingRotationDegrees;
|
||||||
private boolean fileStartsOnVideoFrameEnabled;
|
private boolean fileStartsOnVideoFrameEnabled;
|
||||||
private boolean usePlatformDiagnostics;
|
private boolean usePlatformDiagnostics;
|
||||||
private long maxDelayBetweenMuxerSamplesMs;
|
private long maxDelayBetweenMuxerSamplesMs;
|
||||||
@ -150,6 +153,7 @@ public final class Transformer {
|
|||||||
metricsReporterFactory =
|
metricsReporterFactory =
|
||||||
new EditingMetricsCollector.DefaultMetricsReporter.Factory(context);
|
new EditingMetricsCollector.DefaultMetricsReporter.Factory(context);
|
||||||
}
|
}
|
||||||
|
allowedEncodingRotationDegrees = ALL_ROTATION_DEGREES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a builder with the values of the provided {@link Transformer}. */
|
/** Creates a builder with the values of the provided {@link Transformer}. */
|
||||||
@ -163,7 +167,7 @@ public final class Transformer {
|
|||||||
this.removeAudio = transformer.removeAudio;
|
this.removeAudio = transformer.removeAudio;
|
||||||
this.removeVideo = transformer.removeVideo;
|
this.removeVideo = transformer.removeVideo;
|
||||||
this.trimOptimizationEnabled = transformer.trimOptimizationEnabled;
|
this.trimOptimizationEnabled = transformer.trimOptimizationEnabled;
|
||||||
this.portraitEncodingEnabled = transformer.portraitEncodingEnabled;
|
this.allowedEncodingRotationDegrees = transformer.allowedEncodingRotationDegrees;
|
||||||
this.fileStartsOnVideoFrameEnabled = transformer.fileStartsOnVideoFrameEnabled;
|
this.fileStartsOnVideoFrameEnabled = transformer.fileStartsOnVideoFrameEnabled;
|
||||||
this.usePlatformDiagnostics = transformer.usePlatformDiagnostics;
|
this.usePlatformDiagnostics = transformer.usePlatformDiagnostics;
|
||||||
this.maxDelayBetweenMuxerSamplesMs = transformer.maxDelayBetweenMuxerSamplesMs;
|
this.maxDelayBetweenMuxerSamplesMs = transformer.maxDelayBetweenMuxerSamplesMs;
|
||||||
@ -286,7 +290,7 @@ public final class Transformer {
|
|||||||
*/
|
*/
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Builder setPortraitEncodingEnabled(boolean enabled) {
|
public Builder setPortraitEncodingEnabled(boolean enabled) {
|
||||||
portraitEncodingEnabled = enabled;
|
allowedEncodingRotationDegrees = enabled ? ImmutableList.of(0) : ALL_ROTATION_DEGREES;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,7 +601,7 @@ public final class Transformer {
|
|||||||
removeAudio,
|
removeAudio,
|
||||||
removeVideo,
|
removeVideo,
|
||||||
trimOptimizationEnabled,
|
trimOptimizationEnabled,
|
||||||
portraitEncodingEnabled,
|
allowedEncodingRotationDegrees,
|
||||||
fileStartsOnVideoFrameEnabled,
|
fileStartsOnVideoFrameEnabled,
|
||||||
usePlatformDiagnostics,
|
usePlatformDiagnostics,
|
||||||
maxDelayBetweenMuxerSamplesMs,
|
maxDelayBetweenMuxerSamplesMs,
|
||||||
@ -783,7 +787,7 @@ public final class Transformer {
|
|||||||
private final boolean removeAudio;
|
private final boolean removeAudio;
|
||||||
private final boolean removeVideo;
|
private final boolean removeVideo;
|
||||||
private final boolean trimOptimizationEnabled;
|
private final boolean trimOptimizationEnabled;
|
||||||
private final boolean portraitEncodingEnabled;
|
private final ImmutableList<Integer> allowedEncodingRotationDegrees;
|
||||||
private final boolean fileStartsOnVideoFrameEnabled;
|
private final boolean fileStartsOnVideoFrameEnabled;
|
||||||
private final boolean usePlatformDiagnostics;
|
private final boolean usePlatformDiagnostics;
|
||||||
private final long maxDelayBetweenMuxerSamplesMs;
|
private final long maxDelayBetweenMuxerSamplesMs;
|
||||||
@ -825,7 +829,7 @@ public final class Transformer {
|
|||||||
boolean removeAudio,
|
boolean removeAudio,
|
||||||
boolean removeVideo,
|
boolean removeVideo,
|
||||||
boolean trimOptimizationEnabled,
|
boolean trimOptimizationEnabled,
|
||||||
boolean portraitEncodingEnabled,
|
ImmutableList<Integer> allowedEncodingRotationDegrees,
|
||||||
boolean fileStartsOnVideoFrameEnabled,
|
boolean fileStartsOnVideoFrameEnabled,
|
||||||
boolean usePlatformDiagnostics,
|
boolean usePlatformDiagnostics,
|
||||||
long maxDelayBetweenMuxerSamplesMs,
|
long maxDelayBetweenMuxerSamplesMs,
|
||||||
@ -848,7 +852,7 @@ public final class Transformer {
|
|||||||
this.removeAudio = removeAudio;
|
this.removeAudio = removeAudio;
|
||||||
this.removeVideo = removeVideo;
|
this.removeVideo = removeVideo;
|
||||||
this.trimOptimizationEnabled = trimOptimizationEnabled;
|
this.trimOptimizationEnabled = trimOptimizationEnabled;
|
||||||
this.portraitEncodingEnabled = portraitEncodingEnabled;
|
this.allowedEncodingRotationDegrees = allowedEncodingRotationDegrees;
|
||||||
this.fileStartsOnVideoFrameEnabled = fileStartsOnVideoFrameEnabled;
|
this.fileStartsOnVideoFrameEnabled = fileStartsOnVideoFrameEnabled;
|
||||||
this.usePlatformDiagnostics = usePlatformDiagnostics;
|
this.usePlatformDiagnostics = usePlatformDiagnostics;
|
||||||
this.maxDelayBetweenMuxerSamplesMs = maxDelayBetweenMuxerSamplesMs;
|
this.maxDelayBetweenMuxerSamplesMs = maxDelayBetweenMuxerSamplesMs;
|
||||||
@ -1639,7 +1643,7 @@ public final class Transformer {
|
|||||||
audioMixerFactory,
|
audioMixerFactory,
|
||||||
videoFrameProcessorFactory,
|
videoFrameProcessorFactory,
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
portraitEncodingEnabled,
|
allowedEncodingRotationDegrees,
|
||||||
maxFramesInEncoder,
|
maxFramesInEncoder,
|
||||||
muxerWrapper,
|
muxerWrapper,
|
||||||
componentListener,
|
componentListener,
|
||||||
|
@ -148,7 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
private final Object setMaxSequenceDurationUsLock;
|
private final Object setMaxSequenceDurationUsLock;
|
||||||
private final Object progressLock;
|
private final Object progressLock;
|
||||||
private final ProgressHolder internalProgressHolder;
|
private final ProgressHolder internalProgressHolder;
|
||||||
private final boolean portraitEncodingEnabled;
|
private final ImmutableList<Integer> allowedEncodingRotationDegrees;
|
||||||
private final int maxFramesInEncoder;
|
private final int maxFramesInEncoder;
|
||||||
|
|
||||||
private boolean isDrainingExporters;
|
private boolean isDrainingExporters;
|
||||||
@ -194,7 +194,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
AudioMixer.Factory audioMixerFactory,
|
AudioMixer.Factory audioMixerFactory,
|
||||||
VideoFrameProcessor.Factory videoFrameProcessorFactory,
|
VideoFrameProcessor.Factory videoFrameProcessorFactory,
|
||||||
Codec.EncoderFactory encoderFactory,
|
Codec.EncoderFactory encoderFactory,
|
||||||
boolean portraitEncodingEnabled,
|
ImmutableList<Integer> allowedEncodingRotationDegrees,
|
||||||
int maxFramesInEncoder,
|
int maxFramesInEncoder,
|
||||||
MuxerWrapper muxerWrapper,
|
MuxerWrapper muxerWrapper,
|
||||||
Listener listener,
|
Listener listener,
|
||||||
@ -207,7 +207,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.composition = composition;
|
this.composition = composition;
|
||||||
this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
|
this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
|
||||||
this.portraitEncodingEnabled = portraitEncodingEnabled;
|
this.allowedEncodingRotationDegrees = allowedEncodingRotationDegrees;
|
||||||
this.maxFramesInEncoder = maxFramesInEncoder;
|
this.maxFramesInEncoder = maxFramesInEncoder;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.applicationHandler = applicationHandler;
|
this.applicationHandler = applicationHandler;
|
||||||
@ -746,7 +746,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
debugViewProvider,
|
debugViewProvider,
|
||||||
videoSampleTimestampOffsetUs,
|
videoSampleTimestampOffsetUs,
|
||||||
/* hasMultipleInputs= */ assetLoaderInputTracker.hasMultipleConcurrentVideoTracks(),
|
/* hasMultipleInputs= */ assetLoaderInputTracker.hasMultipleConcurrentVideoTracks(),
|
||||||
portraitEncodingEnabled,
|
allowedEncodingRotationDegrees,
|
||||||
maxFramesInEncoder,
|
maxFramesInEncoder,
|
||||||
logSessionId));
|
logSessionId));
|
||||||
}
|
}
|
||||||
|
@ -60,6 +60,7 @@ import androidx.media3.common.util.TimestampIterator;
|
|||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
import androidx.media3.effect.MultipleInputVideoGraph;
|
import androidx.media3.effect.MultipleInputVideoGraph;
|
||||||
import androidx.media3.effect.SingleInputVideoGraph;
|
import androidx.media3.effect.SingleInputVideoGraph;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -99,7 +100,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
DebugViewProvider debugViewProvider,
|
DebugViewProvider debugViewProvider,
|
||||||
long initialTimestampOffsetUs,
|
long initialTimestampOffsetUs,
|
||||||
boolean hasMultipleInputs,
|
boolean hasMultipleInputs,
|
||||||
boolean portraitEncodingEnabled,
|
ImmutableList<Integer> allowedEncodingRotationDegrees,
|
||||||
int maxFramesInEncoder,
|
int maxFramesInEncoder,
|
||||||
@Nullable LogSessionId logSessionId)
|
@Nullable LogSessionId logSessionId)
|
||||||
throws ExportException {
|
throws ExportException {
|
||||||
@ -136,7 +137,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
new EncoderWrapper(
|
new EncoderWrapper(
|
||||||
encoderFactory,
|
encoderFactory,
|
||||||
firstInputFormat.buildUpon().setColorInfo(videoGraphOutputColor).build(),
|
firstInputFormat.buildUpon().setColorInfo(videoGraphOutputColor).build(),
|
||||||
portraitEncodingEnabled,
|
allowedEncodingRotationDegrees,
|
||||||
muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_VIDEO),
|
muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_VIDEO),
|
||||||
transformationRequest,
|
transformationRequest,
|
||||||
fallbackListener,
|
fallbackListener,
|
||||||
@ -249,7 +250,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
|
|
||||||
private final Codec.EncoderFactory encoderFactory;
|
private final Codec.EncoderFactory encoderFactory;
|
||||||
private final Format inputFormat;
|
private final Format inputFormat;
|
||||||
private final boolean portraitEncodingEnabled;
|
private final ImmutableList<Integer> allowedEncodingRotationDegrees;
|
||||||
private final List<String> muxerSupportedMimeTypes;
|
private final List<String> muxerSupportedMimeTypes;
|
||||||
private final TransformationRequest transformationRequest;
|
private final TransformationRequest transformationRequest;
|
||||||
private final FallbackListener fallbackListener;
|
private final FallbackListener fallbackListener;
|
||||||
@ -266,7 +267,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
public EncoderWrapper(
|
public EncoderWrapper(
|
||||||
Codec.EncoderFactory encoderFactory,
|
Codec.EncoderFactory encoderFactory,
|
||||||
Format inputFormat,
|
Format inputFormat,
|
||||||
boolean portraitEncodingEnabled,
|
ImmutableList<Integer> allowedEncodingRotationDegrees,
|
||||||
List<String> muxerSupportedMimeTypes,
|
List<String> muxerSupportedMimeTypes,
|
||||||
TransformationRequest transformationRequest,
|
TransformationRequest transformationRequest,
|
||||||
FallbackListener fallbackListener,
|
FallbackListener fallbackListener,
|
||||||
@ -274,7 +275,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
checkArgument(inputFormat.colorInfo != null);
|
checkArgument(inputFormat.colorInfo != null);
|
||||||
this.encoderFactory = encoderFactory;
|
this.encoderFactory = encoderFactory;
|
||||||
this.inputFormat = inputFormat;
|
this.inputFormat = inputFormat;
|
||||||
this.portraitEncodingEnabled = portraitEncodingEnabled;
|
this.allowedEncodingRotationDegrees = allowedEncodingRotationDegrees;
|
||||||
this.muxerSupportedMimeTypes = muxerSupportedMimeTypes;
|
this.muxerSupportedMimeTypes = muxerSupportedMimeTypes;
|
||||||
this.transformationRequest = transformationRequest;
|
this.transformationRequest = transformationRequest;
|
||||||
this.fallbackListener = fallbackListener;
|
this.fallbackListener = fallbackListener;
|
||||||
@ -319,7 +320,7 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
// frame before encoding, so the encoded frame's width >= height. In this case, the VideoGraph
|
// frame before encoding, so the encoded frame's width >= height. In this case, the VideoGraph
|
||||||
// rotates the decoded video frames counter-clockwise, and the muxer adds a clockwise rotation
|
// rotates the decoded video frames counter-clockwise, and the muxer adds a clockwise rotation
|
||||||
// to the metadata.
|
// to the metadata.
|
||||||
if (requestedWidth < requestedHeight && !portraitEncodingEnabled) {
|
if (requestedWidth < requestedHeight) {
|
||||||
int temp = requestedWidth;
|
int temp = requestedWidth;
|
||||||
requestedWidth = requestedHeight;
|
requestedWidth = requestedHeight;
|
||||||
requestedHeight = temp;
|
requestedHeight = temp;
|
||||||
@ -333,6 +334,22 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
outputRotationDegrees = inputFormat.rotationDegrees;
|
outputRotationDegrees = inputFormat.rotationDegrees;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allowedEncodingRotationDegrees.contains(outputRotationDegrees)) {
|
||||||
|
int alternativeOutputRotationDegreesWithSameWidthAndHeight =
|
||||||
|
(outputRotationDegrees + 180) % 360;
|
||||||
|
if (allowedEncodingRotationDegrees.contains(
|
||||||
|
alternativeOutputRotationDegreesWithSameWidthAndHeight)) {
|
||||||
|
outputRotationDegrees = alternativeOutputRotationDegreesWithSameWidthAndHeight;
|
||||||
|
} else {
|
||||||
|
// No allowed rotation of the same orientation. Swap width and height, and use any allowed
|
||||||
|
// orientation.
|
||||||
|
int temp = requestedWidth;
|
||||||
|
requestedWidth = requestedHeight;
|
||||||
|
requestedHeight = temp;
|
||||||
|
outputRotationDegrees = allowedEncodingRotationDegrees.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rotation is handled by this class. The encoder must see a video with zero degrees rotation.
|
// Rotation is handled by this class. The encoder must see a video with zero degrees rotation.
|
||||||
Format requestedEncoderFormat =
|
Format requestedEncoderFormat =
|
||||||
new Format.Builder()
|
new Format.Builder()
|
||||||
|
@ -73,7 +73,7 @@ public final class VideoEncoderWrapperTest {
|
|||||||
.setSampleMimeType(MimeTypes.VIDEO_H264)
|
.setSampleMimeType(MimeTypes.VIDEO_H264)
|
||||||
.setColorInfo(ColorInfo.SDR_BT709_LIMITED)
|
.setColorInfo(ColorInfo.SDR_BT709_LIMITED)
|
||||||
.build(),
|
.build(),
|
||||||
/* portraitEncodingEnabled= */ false,
|
/* allowedEncodingRotationDegrees= */ ImmutableList.of(0, 90, 180, 270),
|
||||||
/* muxerSupportedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264),
|
/* muxerSupportedMimeTypes= */ ImmutableList.of(MimeTypes.VIDEO_H264),
|
||||||
emptyTransformationRequest,
|
emptyTransformationRequest,
|
||||||
fallbackListener,
|
fallbackListener,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user