Transformer: Plumb hdrMode into AssetLoaders instead of forceInterpret.

This allows us to also plumb whether we're doing MediaCodec tone-mapping,
which will be used in a follow-up CL in the ExoAssetLoaderVideoRenderer.

PiperOrigin-RevId: 601774435
This commit is contained in:
huangdarwin 2024-01-26 08:32:37 -08:00 committed by Copybara-Service
parent 373822ce45
commit b1c1c2a6dd
7 changed files with 48 additions and 50 deletions

View File

@ -118,7 +118,7 @@ public class ForceEndOfStreamTest {
new DefaultAssetLoaderFactory( new DefaultAssetLoaderFactory(
context, context,
new FrameDroppingDecoderFactory(context, MP4_ASSET_FRAME_COUNT, framesToSkip), new FrameDroppingDecoderFactory(context, MP4_ASSET_FRAME_COUNT, framesToSkip),
/* forceInterpretHdrAsSdr= */ false, Composition.HDR_MODE_KEEP_HDR,
Clock.DEFAULT)) Clock.DEFAULT))
.build(); .build();
} }

View File

@ -46,7 +46,7 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
private final Context context; private final Context context;
private final Codec.DecoderFactory decoderFactory; private final Codec.DecoderFactory decoderFactory;
private final boolean forceInterpretHdrAsSdr; private final @Composition.HdrMode int hdrMode;
private final Clock clock; private final Clock clock;
private final MediaSource.@MonotonicNonNull Factory mediaSourceFactory; private final MediaSource.@MonotonicNonNull Factory mediaSourceFactory;
private final BitmapLoader bitmapLoader; private final BitmapLoader bitmapLoader;
@ -64,19 +64,22 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
* @param context The {@link Context}. * @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if * @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary). * necessary).
* @param forceInterpretHdrAsSdr Whether to apply {@link * @param hdrMode The {@link Composition.HdrMode} to apply. Only {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. * Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC} and {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR} are applied in this
* component.
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing. * testing.
*/ */
public DefaultAssetLoaderFactory( public DefaultAssetLoaderFactory(
Context context, Context context,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Clock clock) { Clock clock) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; // TODO: b/307952514 - MediaCodec tone-mapping information isn't actually used yet. Use it.
this.hdrMode = hdrMode;
this.clock = clock; this.clock = clock;
this.mediaSourceFactory = null; this.mediaSourceFactory = null;
@Nullable BitmapFactory.Options options = null; @Nullable BitmapFactory.Options options = null;
@ -98,15 +101,16 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
* The frame loaded is determined by the {@link BitmapLoader} implementation. * The frame loaded is determined by the {@link BitmapLoader} implementation.
* *
* @param context The {@link Context}. * @param context The {@link Context}.
* @param forceInterpretHdrAsSdr Whether to apply {@link * @param hdrMode The {@link Composition.HdrMode} to apply. Only {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. * Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC} and {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR} are applied.
* @param bitmapLoader The {@link BitmapLoader} to use to load and decode images. * @param bitmapLoader The {@link BitmapLoader} to use to load and decode images.
*/ */
public DefaultAssetLoaderFactory( public DefaultAssetLoaderFactory(
Context context, boolean forceInterpretHdrAsSdr, BitmapLoader bitmapLoader) { Context context, @Composition.HdrMode int hdrMode, BitmapLoader bitmapLoader) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.decoderFactory = new DefaultDecoderFactory(context); this.decoderFactory = new DefaultDecoderFactory(context);
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
this.clock = Clock.DEFAULT; this.clock = Clock.DEFAULT;
this.mediaSourceFactory = null; this.mediaSourceFactory = null;
this.bitmapLoader = bitmapLoader; this.bitmapLoader = bitmapLoader;
@ -118,8 +122,9 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
* @param context The {@link Context}. * @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if * @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary). * necessary).
* @param forceInterpretHdrAsSdr Whether to apply {@link * @param hdrMode The {@link Composition.HdrMode} to apply. Only {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. * Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC} and {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR} are applied.
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing. * testing.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to * @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
@ -129,13 +134,13 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
public DefaultAssetLoaderFactory( public DefaultAssetLoaderFactory(
Context context, Context context,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Clock clock, Clock clock,
MediaSource.Factory mediaSourceFactory, MediaSource.Factory mediaSourceFactory,
BitmapLoader bitmapLoader) { BitmapLoader bitmapLoader) {
this.context = context.getApplicationContext(); this.context = context.getApplicationContext();
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
this.clock = clock; this.clock = clock;
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactory = mediaSourceFactory;
this.bitmapLoader = bitmapLoader; this.bitmapLoader = bitmapLoader;
@ -155,9 +160,8 @@ public final class DefaultAssetLoaderFactory implements AssetLoader.Factory {
exoPlayerAssetLoaderFactory = exoPlayerAssetLoaderFactory =
mediaSourceFactory != null mediaSourceFactory != null
? new ExoPlayerAssetLoader.Factory( ? new ExoPlayerAssetLoader.Factory(
context, decoderFactory, forceInterpretHdrAsSdr, clock, mediaSourceFactory) context, decoderFactory, hdrMode, clock, mediaSourceFactory)
: new ExoPlayerAssetLoader.Factory( : new ExoPlayerAssetLoader.Factory(context, decoderFactory, hdrMode, clock);
context, decoderFactory, forceInterpretHdrAsSdr, clock);
} }
return exoPlayerAssetLoaderFactory.createAssetLoader(editedMediaItem, looper, listener); return exoPlayerAssetLoaderFactory.createAssetLoader(editedMediaItem, looper, listener);
} }

View File

@ -37,7 +37,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private final boolean flattenForSlowMotion; private final boolean flattenForSlowMotion;
private final Codec.DecoderFactory decoderFactory; private final Codec.DecoderFactory decoderFactory;
private final boolean forceInterpretHdrAsSdr; private final @Composition.HdrMode int hdrMode;
private final List<Long> decodeOnlyPresentationTimestamps; private final List<Long> decodeOnlyPresentationTimestamps;
private @MonotonicNonNull SefSlowMotionFlattener sefVideoSlowMotionFlattener; private @MonotonicNonNull SefSlowMotionFlattener sefVideoSlowMotionFlattener;
@ -46,13 +46,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
public ExoAssetLoaderVideoRenderer( public ExoAssetLoaderVideoRenderer(
boolean flattenForSlowMotion, boolean flattenForSlowMotion,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
TransformerMediaClock mediaClock, TransformerMediaClock mediaClock,
AssetLoader.Listener assetLoaderListener) { AssetLoader.Listener assetLoaderListener) {
super(C.TRACK_TYPE_VIDEO, mediaClock, assetLoaderListener); super(C.TRACK_TYPE_VIDEO, mediaClock, assetLoaderListener);
this.flattenForSlowMotion = flattenForSlowMotion; this.flattenForSlowMotion = flattenForSlowMotion;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
decodeOnlyPresentationTimestamps = new ArrayList<>(); decodeOnlyPresentationTimestamps = new ArrayList<>();
} }
@ -63,7 +63,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
@Override @Override
protected Format overrideFormat(Format inputFormat) { protected Format overrideFormat(Format inputFormat) {
if (forceInterpretHdrAsSdr && ColorInfo.isTransferHdr(inputFormat.colorInfo)) { if (hdrMode == Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR
&& ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
return inputFormat.buildUpon().setColorInfo(ColorInfo.SDR_BT709_LIMITED).build(); return inputFormat.buildUpon().setColorInfo(ColorInfo.SDR_BT709_LIMITED).build();
} }
return inputFormat; return inputFormat;

View File

@ -65,7 +65,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
private final Context context; private final Context context;
private final Codec.DecoderFactory decoderFactory; private final Codec.DecoderFactory decoderFactory;
private final boolean forceInterpretHdrAsSdr; private final @Composition.HdrMode int hdrMode;
private final Clock clock; private final Clock clock;
@Nullable private final MediaSource.Factory mediaSourceFactory; @Nullable private final MediaSource.Factory mediaSourceFactory;
@ -75,19 +75,20 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
* @param context The {@link Context}. * @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if * @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary). * necessary).
* @param forceInterpretHdrAsSdr Whether to apply {@link * @param hdrMode The {@link Composition.HdrMode} to apply. Only {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. * Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC} and {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR} are applied.
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing. * testing.
*/ */
public Factory( public Factory(
Context context, Context context,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Clock clock) { Clock clock) {
this.context = context; this.context = context;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
this.clock = clock; this.clock = clock;
this.mediaSourceFactory = null; this.mediaSourceFactory = null;
} }
@ -98,8 +99,9 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
* @param context The {@link Context}. * @param context The {@link Context}.
* @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if * @param decoderFactory The {@link Codec.DecoderFactory} to use to decode the samples (if
* necessary). * necessary).
* @param forceInterpretHdrAsSdr Whether to apply {@link * @param hdrMode The {@link Composition.HdrMode} to apply. Only {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. * Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC} and {@link
* Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR} are applied.
* @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for * @param clock The {@link Clock} to use. It should always be {@link Clock#DEFAULT}, except for
* testing. * testing.
* @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to * @param mediaSourceFactory The {@link MediaSource.Factory} to use to retrieve the samples to
@ -108,12 +110,12 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
public Factory( public Factory(
Context context, Context context,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Clock clock, Clock clock,
MediaSource.Factory mediaSourceFactory) { MediaSource.Factory mediaSourceFactory) {
this.context = context; this.context = context;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
this.clock = clock; this.clock = clock;
this.mediaSourceFactory = mediaSourceFactory; this.mediaSourceFactory = mediaSourceFactory;
} }
@ -134,7 +136,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
editedMediaItem, editedMediaItem,
mediaSourceFactory, mediaSourceFactory,
decoderFactory, decoderFactory,
forceInterpretHdrAsSdr, hdrMode,
looper, looper,
listener, listener,
clock); clock);
@ -158,7 +160,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
EditedMediaItem editedMediaItem, EditedMediaItem editedMediaItem,
MediaSource.Factory mediaSourceFactory, MediaSource.Factory mediaSourceFactory,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Looper looper, Looper looper,
Listener listener, Listener listener,
Clock clock) { Clock clock) {
@ -188,7 +190,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
editedMediaItem.removeVideo, editedMediaItem.removeVideo,
editedMediaItem.flattenForSlowMotion, editedMediaItem.flattenForSlowMotion,
this.decoderFactory, this.decoderFactory,
forceInterpretHdrAsSdr, hdrMode,
listener)) listener))
.setMediaSourceFactory(mediaSourceFactory) .setMediaSourceFactory(mediaSourceFactory)
.setTrackSelector(trackSelector) .setTrackSelector(trackSelector)
@ -252,7 +254,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
private final boolean removeVideo; private final boolean removeVideo;
private final boolean flattenForSlowMotion; private final boolean flattenForSlowMotion;
private final Codec.DecoderFactory decoderFactory; private final Codec.DecoderFactory decoderFactory;
private final boolean forceInterpretHdrAsSdr; private final @Composition.HdrMode int hdrMode;
private final Listener assetLoaderListener; private final Listener assetLoaderListener;
public RenderersFactoryImpl( public RenderersFactoryImpl(
@ -260,13 +262,13 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
boolean removeVideo, boolean removeVideo,
boolean flattenForSlowMotion, boolean flattenForSlowMotion,
Codec.DecoderFactory decoderFactory, Codec.DecoderFactory decoderFactory,
boolean forceInterpretHdrAsSdr, @Composition.HdrMode int hdrMode,
Listener assetLoaderListener) { Listener assetLoaderListener) {
this.removeAudio = removeAudio; this.removeAudio = removeAudio;
this.removeVideo = removeVideo; this.removeVideo = removeVideo;
this.flattenForSlowMotion = flattenForSlowMotion; this.flattenForSlowMotion = flattenForSlowMotion;
this.decoderFactory = decoderFactory; this.decoderFactory = decoderFactory;
this.forceInterpretHdrAsSdr = forceInterpretHdrAsSdr; this.hdrMode = hdrMode;
this.assetLoaderListener = assetLoaderListener; this.assetLoaderListener = assetLoaderListener;
mediaClock = new TransformerMediaClock(); mediaClock = new TransformerMediaClock();
} }
@ -289,11 +291,7 @@ public final class ExoPlayerAssetLoader implements AssetLoader {
if (!removeVideo) { if (!removeVideo) {
renderers[index] = renderers[index] =
new ExoAssetLoaderVideoRenderer( new ExoAssetLoaderVideoRenderer(
flattenForSlowMotion, flattenForSlowMotion, decoderFactory, hdrMode, mediaClock, assetLoaderListener);
decoderFactory,
forceInterpretHdrAsSdr,
mediaClock,
assetLoaderListener);
index++; index++;
} }
return renderers; return renderers;

View File

@ -20,7 +20,6 @@ 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.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.extractor.AacUtil.AAC_LC_AUDIO_SAMPLE_COUNT; import static androidx.media3.extractor.AacUtil.AAC_LC_AUDIO_SAMPLE_COUNT;
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM; import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_KEYFRAME_PLACEMENT_OPTIMAL_FOR_TRIM;
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_OTHER; import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_OTHER;
import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_TRIM_AND_TRANSCODING_TRANSFORMATION_REQUESTED; import static androidx.media3.transformer.ExportResult.OPTIMIZATION_ABANDONED_TRIM_AND_TRANSCODING_TRANSFORMATION_REQUESTED;
@ -1532,11 +1531,7 @@ public final class Transformer {
if (assetLoaderFactory == null) { if (assetLoaderFactory == null) {
assetLoaderFactory = assetLoaderFactory =
new DefaultAssetLoaderFactory( new DefaultAssetLoaderFactory(
context, context, new DefaultDecoderFactory(context), transformationRequest.hdrMode, clock);
new DefaultDecoderFactory(context),
/* forceInterpretHdrAsSdr= */ transformationRequest.hdrMode
== HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR,
clock);
} }
DebugTraceUtil.reset(); DebugTraceUtil.reset();
transformerInternal = transformerInternal =

View File

@ -144,7 +144,7 @@ public class ExoPlayerAssetLoaderTest {
EditedMediaItem editedMediaItem = EditedMediaItem editedMediaItem =
new EditedMediaItem.Builder(MediaItem.fromUri("asset:///media/mp4/sample.mp4")).build(); new EditedMediaItem.Builder(MediaItem.fromUri("asset:///media/mp4/sample.mp4")).build();
return new ExoPlayerAssetLoader.Factory( return new ExoPlayerAssetLoader.Factory(
context, decoderFactory, /* forceInterpretHdrAsSdr= */ false, clock) context, decoderFactory, Composition.HDR_MODE_KEEP_HDR, clock)
.createAssetLoader(editedMediaItem, Looper.myLooper(), listener); .createAssetLoader(editedMediaItem, Looper.myLooper(), listener);
} }

View File

@ -872,7 +872,7 @@ public final class MediaItemExportTest {
new ExoPlayerAssetLoader.Factory( new ExoPlayerAssetLoader.Factory(
context, context,
decoderFactory, decoderFactory,
/* forceInterpretHdrAsSdr= */ false, Composition.HDR_MODE_KEEP_HDR,
new FakeClock(/* isAutoAdvancing= */ true), new FakeClock(/* isAutoAdvancing= */ true),
mediaSourceFactory); mediaSourceFactory);
CapturingMuxer.Factory muxerFactory = CapturingMuxer.Factory muxerFactory =