Transformer: Input decoder output color to VideoSampleExporter.

Previously, the track format was used in VideoSampleExporter. Now, we use a
simulated decoder output format.

As the last expected change for this bug, also adds release notes

PiperOrigin-RevId: 609080629
This commit is contained in:
huangdarwin 2024-02-21 12:12:18 -08:00 committed by Copybara-Service
parent bb5c688543
commit fde6a32156
6 changed files with 32 additions and 29 deletions

View File

@ -11,6 +11,7 @@
* Add workaround for exception thrown due to `MediaMuxer` not supporting * Add workaround for exception thrown due to `MediaMuxer` not supporting
negative presentation timestamps before API 30. negative presentation timestamps before API 30.
* Relax trim optimization H.264 level checks. * Relax trim optimization H.264 level checks.
* Add support for changing between SDR and HDR input media in a sequence.
* Track Selection: * Track Selection:
* Extractors: * Extractors:
* Audio: * Audio:

View File

@ -83,7 +83,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
protected Format overrideOutputFormat(Format format) { protected Format overrideOutputFormat(Format format) {
// Gets the expected output color from the decoder, based on the input track format, if // Gets the expected output color from the decoder, based on the input track format, if
// tone-mapping is applied. // tone-mapping is applied.
ColorInfo validColor = VideoSampleExporter.getValidColor(format.colorInfo); ColorInfo validColor = TransformerUtil.getValidColor(format.colorInfo);
boolean isDecoderToneMappingRequested = boolean isDecoderToneMappingRequested =
hdrMode == Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC; hdrMode == Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
ColorInfo outputColor = getDecoderOutputColor(validColor, isDecoderToneMappingRequested); ColorInfo outputColor = getDecoderOutputColor(validColor, isDecoderToneMappingRequested);

View File

@ -22,6 +22,7 @@ import static androidx.media3.transformer.SampleConsumer.INPUT_RESULT_END_OF_STR
import static androidx.media3.transformer.SampleConsumer.INPUT_RESULT_TRY_AGAIN_LATER; import static androidx.media3.transformer.SampleConsumer.INPUT_RESULT_TRY_AGAIN_LATER;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
import static androidx.media3.transformer.TransformerUtil.getValidColor;
import static java.lang.Math.round; import static java.lang.Math.round;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -83,7 +84,7 @@ public final class TextureAssetLoader implements AssetLoader {
this.format = this.format =
format format
.buildUpon() .buildUpon()
.setColorInfo(VideoSampleExporter.getValidColor(format.colorInfo)) .setColorInfo(getValidColor(format.colorInfo))
.setSampleMimeType(MimeTypes.VIDEO_RAW) .setSampleMimeType(MimeTypes.VIDEO_RAW)
.build(); .build();
this.frameProcessedListener = frameProcessedListener; this.frameProcessedListener = frameProcessedListener;

View File

@ -23,11 +23,14 @@ import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.contains; 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_DECODED;
import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
import static androidx.media3.transformer.ExoAssetLoaderVideoRenderer.getDecoderOutputColor;
import static androidx.media3.transformer.ExportException.ERROR_CODE_FAILED_RUNTIME_CHECK; 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.ExportException.ERROR_CODE_MUXING_FAILED;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_AVAILABLE;
import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED; import static androidx.media3.transformer.Transformer.PROGRESS_STATE_NOT_STARTED;
import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType; import static androidx.media3.transformer.TransformerUtil.getProcessedTrackType;
import static androidx.media3.transformer.TransformerUtil.getValidColor;
import static androidx.media3.transformer.TransformerUtil.maybeSetMuxerWrapperAdditionalRotationDegrees; import static androidx.media3.transformer.TransformerUtil.maybeSetMuxerWrapperAdditionalRotationDegrees;
import static androidx.media3.transformer.TransformerUtil.shouldTranscodeAudio; import static androidx.media3.transformer.TransformerUtil.shouldTranscodeAudio;
import static androidx.media3.transformer.TransformerUtil.shouldTranscodeVideo; import static androidx.media3.transformer.TransformerUtil.shouldTranscodeVideo;
@ -45,6 +48,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.IntRange; import androidx.annotation.IntRange;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.ColorInfo;
import androidx.media3.common.DebugViewProvider; import androidx.media3.common.DebugViewProvider;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
@ -642,11 +646,18 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
fallbackListener)); fallbackListener));
} else { } else {
// TODO(b/267301878): Pass firstAssetLoaderOutputFormat once surface creation not in VSP. // TODO(b/267301878): Pass firstAssetLoaderOutputFormat once surface creation not in VSP.
boolean isMediaCodecToneMappingRequested =
transformationRequest.hdrMode == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
ColorInfo decoderOutputColor =
getDecoderOutputColor(
getValidColor(firstAssetLoaderInputFormat.colorInfo),
isMediaCodecToneMappingRequested);
assetLoaderInputTracker.registerSampleExporter( assetLoaderInputTracker.registerSampleExporter(
C.TRACK_TYPE_VIDEO, C.TRACK_TYPE_VIDEO,
new VideoSampleExporter( new VideoSampleExporter(
context, context,
firstAssetLoaderInputFormat, firstAssetLoaderInputFormat.buildUpon().setColorInfo(decoderOutputColor).build(),
transformationRequest, transformationRequest,
composition.videoCompositorSettings, composition.videoCompositorSettings,
composition.effects.videoEffects, composition.effects.videoEffects,

View File

@ -22,6 +22,7 @@ import static java.lang.Math.round;
import android.media.MediaCodec; import android.media.MediaCodec;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.ColorInfo;
import androidx.media3.common.Effect; import androidx.media3.common.Effect;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.Metadata; import androidx.media3.common.Metadata;
@ -208,4 +209,15 @@ import com.google.common.collect.ImmutableList;
muxerWrapper.setAdditionalRotationDegrees(360 - round(rotationDegrees)); muxerWrapper.setAdditionalRotationDegrees(360 - round(rotationDegrees));
} }
} }
/**
* Adjust for invalid {@link ColorInfo} values, by defaulting to {@link
* ColorInfo#SDR_BT709_LIMITED}.
*/
public static ColorInfo getValidColor(@Nullable ColorInfo colorInfo) {
if (colorInfo == null || !colorInfo.isDataSpaceValid()) {
return ColorInfo.SDR_BT709_LIMITED;
}
return colorInfo;
}
} }

View File

@ -22,7 +22,6 @@ import static androidx.media3.common.ColorInfo.isTransferHdr;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR; import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL; import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
import static androidx.media3.transformer.EncoderUtil.getSupportedEncodersForHdrEditing; import static androidx.media3.transformer.EncoderUtil.getSupportedEncodersForHdrEditing;
@ -74,18 +73,6 @@ import org.checkerframework.dataflow.qual.Pure;
private boolean hasMuxedTimestampZero; private boolean hasMuxedTimestampZero;
// TODO: b/307952514 - Move this method to a color utility.
/**
* Adjust for invalid {@link ColorInfo} values, by defaulting to {@link
* ColorInfo#SDR_BT709_LIMITED}.
*/
public static ColorInfo getValidColor(@Nullable ColorInfo colorInfo) {
if (colorInfo == null || !colorInfo.isDataSpaceValid()) {
return ColorInfo.SDR_BT709_LIMITED;
}
return colorInfo;
}
public VideoSampleExporter( public VideoSampleExporter(
Context context, Context context,
Format firstInputFormat, Format firstInputFormat,
@ -107,29 +94,20 @@ import org.checkerframework.dataflow.qual.Pure;
this.initialTimestampOffsetUs = initialTimestampOffsetUs; this.initialTimestampOffsetUs = initialTimestampOffsetUs;
finalFramePresentationTimeUs = C.TIME_UNSET; finalFramePresentationTimeUs = C.TIME_UNSET;
ColorInfo decoderInputColor = getValidColor(firstInputFormat.colorInfo);
encoderWrapper = encoderWrapper =
new EncoderWrapper( new EncoderWrapper(
encoderFactory, encoderFactory,
firstInputFormat.buildUpon().setColorInfo(decoderInputColor).build(), firstInputFormat,
muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_VIDEO), muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_VIDEO),
transformationRequest, transformationRequest,
fallbackListener); fallbackListener);
encoderOutputBuffer = encoderOutputBuffer =
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED); new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
@Composition.HdrMode int hdrModeAfterFallback = encoderWrapper.getHdrModeAfterFallback(); ColorInfo videoGraphInputColor = checkNotNull(firstInputFormat.colorInfo);
boolean isMediaCodecToneMappingRequested =
hdrModeAfterFallback == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
// TODO: b/278259383 - After solving the bug, we can use the decoder output format, and no
// longer need to import this color conversion method.
ColorInfo videoGraphInputColor =
ExoAssetLoaderVideoRenderer.getDecoderOutputColor(
decoderInputColor, isMediaCodecToneMappingRequested);
boolean isGlToneMapping = boolean isGlToneMapping =
hdrModeAfterFallback == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL encoderWrapper.getHdrModeAfterFallback() == HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL
&& ColorInfo.isTransferHdr(decoderInputColor); && ColorInfo.isTransferHdr(videoGraphInputColor);
ColorInfo videoGraphOutputColor; ColorInfo videoGraphOutputColor;
if (videoGraphInputColor.colorTransfer == C.COLOR_TRANSFER_SRGB) { if (videoGraphInputColor.colorTransfer == C.COLOR_TRANSFER_SRGB) {
// The sRGB color transfer is only used for images, so when an image gets transcoded into a // The sRGB color transfer is only used for images, so when an image gets transcoded into a