Deprecate Transformer.Builder.setTransformationRequest()

Usages will be removed in follow-up changes.

PiperOrigin-RevId: 543654397
This commit is contained in:
kimvde 2023-06-27 07:03:44 +00:00 committed by Tianyi Feng
parent 140c83ce7e
commit f8491fc61f
3 changed files with 203 additions and 70 deletions

View File

@ -16,12 +16,18 @@
package androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkArgument;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import androidx.annotation.IntDef;
import androidx.media3.common.MediaItem;
import androidx.media3.common.audio.AudioProcessor;
import androidx.media3.common.util.UnstableApi;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.List;
/**
@ -42,6 +48,7 @@ public final class Composition {
private boolean forceAudioTrack;
private boolean transmuxAudio;
private boolean transmuxVideo;
private @HdrMode int hdrMode;
/**
* Creates an instance.
@ -96,8 +103,8 @@ public final class Composition {
* the {@link Composition} export doesn't produce any audio.
*
* <p>The MIME type of the output's audio track can be set using {@link
* TransformationRequest.Builder#setAudioMimeType(String)}. The sample rate and channel count
* can be set by passing relevant {@link AudioProcessor} instances to the {@link Composition}.
* Transformer.Builder#setAudioMimeType(String)}. The sample rate and channel count can be set
* by passing relevant {@link AudioProcessor} instances to the {@link Composition}.
*
* <p>Forcing an audio track and {@linkplain #setTransmuxAudio(boolean) requesting audio
* transmuxing} are not allowed together because generating silence requires transcoding.
@ -163,12 +170,101 @@ public final class Composition {
return this;
}
/**
* Sets the {@link HdrMode} for HDR video input.
*
* <p>The default value is {@link #HDR_MODE_KEEP_HDR}.
*
* @param hdrMode The {@link HdrMode} used.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder setHdrMode(@HdrMode int hdrMode) {
this.hdrMode = hdrMode;
return this;
}
/** Builds a {@link Composition} instance. */
public Composition build() {
return new Composition(sequences, effects, forceAudioTrack, transmuxAudio, transmuxVideo);
return new Composition(
sequences, effects, forceAudioTrack, transmuxAudio, transmuxVideo, hdrMode);
}
}
/**
* The strategy to use to transcode or edit High Dynamic Range (HDR) input video.
*
* <p>One of {@link #HDR_MODE_KEEP_HDR}, {@link #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC},
* {@link #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL}, or {@link
* #HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}.
*
* <p>Standard Dynamic Range (SDR) input video is unaffected by these settings.
*/
@Documented
@Retention(SOURCE)
@Target(TYPE_USE)
@IntDef({
HDR_MODE_KEEP_HDR,
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC,
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL,
HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR,
})
public @interface HdrMode {}
/**
* Processes HDR input as HDR, to generate HDR output.
*
* <p>The HDR output format (ex. color transfer) will be the same as the HDR input format.
*
* <p>Supported on API 31+, by some device and HDR format combinations.
*
* <p>If not supported, {@link Transformer} will attempt to use {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}.
*/
public static final int HDR_MODE_KEEP_HDR = 0;
/**
* Tone map HDR input to SDR before processing, to generate SDR output, using the {@link
* android.media.MediaCodec} decoder tone-mapper.
*
* <p>Supported on API 31+, by some device and HDR format combinations. Tone-mapping is only
* guaranteed to be supported on API 33+, on devices with HDR capture support.
*
* <p>If not supported, {@link Transformer} throws an {@link ExportException}.
*/
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC = 1;
/**
* Tone map HDR input to SDR before processing, to generate SDR output, using an OpenGL
* tone-mapper.
*
* <p>Supported on API 29+.
*
* <p>This may exhibit mild differences from {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}, depending on the device's tone-mapping
* implementation, but should have much wider support and have more consistent results across
* devices.
*
* <p>If not supported, {@link Transformer} throws an {@link ExportException}.
*/
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL = 2;
/**
* Interpret HDR input as SDR, likely with a washed out look.
*
* <p>This is much more widely supported than {@link #HDR_MODE_KEEP_HDR} and {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}. However, as HDR transfer functions and
* metadata will be ignored, contents will be displayed incorrectly, likely with a washed out
* look.
*
* <p>Using this API may lead to codec errors before API 29.
*
* <p>Use of this flag may result in {@code ERROR_CODE_DECODING_FORMAT_UNSUPPORTED}.
*
* <p>This field is experimental, and will be renamed or removed in a future release.
*/
public static final int HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR = 3;
/**
* The {@link EditedMediaItemSequence} instances to compose.
*
@ -200,12 +296,20 @@ public final class Composition {
*/
public final boolean transmuxVideo;
/**
* The {@link HdrMode} specifying how to handle HDR input video.
*
* <p>For more information, see {@link Builder#setHdrMode(int)}.
*/
public final @HdrMode int hdrMode;
private Composition(
List<EditedMediaItemSequence> sequences,
Effects effects,
boolean forceAudioTrack,
boolean transmuxAudio,
boolean transmuxVideo) {
boolean transmuxVideo,
@HdrMode int hdrMode) {
checkArgument(
!transmuxAudio || !forceAudioTrack,
"Audio transmuxing and audio track forcing are not allowed together.");
@ -214,5 +318,6 @@ public final class Composition {
this.transmuxAudio = transmuxAudio;
this.transmuxVideo = transmuxVideo;
this.forceAudioTrack = forceAudioTrack;
this.hdrMode = hdrMode;
}
}

View File

@ -35,15 +35,7 @@ import java.lang.annotation.Target;
@UnstableApi
public final class TransformationRequest {
/**
* The strategy to use to transcode or edit High Dynamic Range (HDR) input video.
*
* <p>One of {@link #HDR_MODE_KEEP_HDR}, {@link #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC},
* {@link #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL}, or {@link
* #HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}.
*
* <p>Standard Dynamic Range (SDR) input video is unaffected by these settings.
*/
/** See {@link Composition.HdrMode}. */
@Documented
@Retention(SOURCE)
@Target(TYPE_USE)
@ -55,59 +47,20 @@ public final class TransformationRequest {
})
public @interface HdrMode {}
/**
* Processes HDR input as HDR, to generate HDR output.
*
* <p>The HDR output format (ex. color transfer) will be the same as the HDR input format.
*
* <p>Supported on API 31+, by some device and HDR format combinations.
*
* <p>If not supported, {@link Transformer} will attempt to use {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}.
*/
public static final int HDR_MODE_KEEP_HDR = 0;
/** See {@link Composition#HDR_MODE_KEEP_HDR}. */
public static final int HDR_MODE_KEEP_HDR = Composition.HDR_MODE_KEEP_HDR;
/**
* Tone map HDR input to SDR before processing, to generate SDR output, using the {@link
* android.media.MediaCodec} decoder tone-mapper.
*
* <p>Supported on API 31+, by some device and HDR format combinations. Tone-mapping is only
* guaranteed to be supported on API 33+, on devices with HDR capture support.
*
* <p>If not supported, {@link Transformer} throws an {@link ExportException}.
*/
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC = 1;
/** See {@link Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}. */
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC =
Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
/**
* Tone map HDR input to SDR before processing, to generate SDR output, using an OpenGL
* tone-mapper.
*
* <p>Supported on API 29+.
*
* <p>This may exhibit mild differences from {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}, depending on the device's tone-mapping
* implementation, but should have much wider support and have more consistent results across
* devices.
*
* <p>If not supported, {@link Transformer} throws an {@link ExportException}.
*/
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL = 2;
/** See {@link Composition#HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL}. */
public static final int HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL =
Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
/**
* Interpret HDR input as SDR, likely with a washed out look.
*
* <p>This is much more widely supported than {@link #HDR_MODE_KEEP_HDR} and {@link
* #HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC}. However, as HDR transfer functions and
* metadata will be ignored, contents will be displayed incorrectly, likely with a washed out
* look.
*
* <p>Using this API may lead to codec errors before API 29.
*
* <p>Use of this flag may result in {@code ERROR_CODE_DECODING_FORMAT_UNSUPPORTED}.
*
* <p>This field is experimental, and will be renamed or removed in a future release.
*/
public static final int HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR = 3;
/** See {@link Composition#HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR}. */
public static final int HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR =
Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
/** A builder for {@link TransformationRequest} instances. */
public static final class Builder {

View File

@ -80,7 +80,9 @@ public final class Transformer {
private final Context context;
// Optional fields.
private TransformationRequest transformationRequest;
private @MonotonicNonNull String audioMimeType;
private @MonotonicNonNull String videoMimeType;
private @MonotonicNonNull TransformationRequest transformationRequest;
private ImmutableList<AudioProcessor> audioProcessors;
private ImmutableList<Effect> videoEffects;
private boolean removeAudio;
@ -102,7 +104,6 @@ public final class Transformer {
*/
public Builder(Context context) {
this.context = context.getApplicationContext();
transformationRequest = new TransformationRequest.Builder().build();
audioProcessors = ImmutableList.of();
videoEffects = ImmutableList.of();
videoFrameProcessorFactory = new DefaultVideoFrameProcessor.Factory.Builder().build();
@ -117,6 +118,8 @@ public final class Transformer {
/** Creates a builder with the values of the provided {@link Transformer}. */
private Builder(Transformer transformer) {
this.context = transformer.context;
this.audioMimeType = transformer.transformationRequest.audioMimeType;
this.videoMimeType = transformer.transformationRequest.videoMimeType;
this.transformationRequest = transformer.transformationRequest;
this.audioProcessors = transformer.audioProcessors;
this.videoEffects = transformer.videoEffects;
@ -133,16 +136,72 @@ public final class Transformer {
}
/**
* Sets the {@link TransformationRequest} which configures the editing and transcoding options.
* Sets the audio {@linkplain MimeTypes MIME type} of the output.
*
* <p>Actual applied values may differ, per device capabilities. {@link
* Listener#onFallbackApplied(Composition, TransformationRequest, TransformationRequest)} will
* be invoked with the actual applied values.
* <p>If no audio MIME type is passed, the output audio MIME type is the same as the first
* {@link MediaItem} in the {@link Composition}.
*
* @param transformationRequest The {@link TransformationRequest}.
* <p>Supported MIME types are:
*
* <ul>
* <li>{@link MimeTypes#AUDIO_AAC}
* <li>{@link MimeTypes#AUDIO_AMR_NB}
* <li>{@link MimeTypes#AUDIO_AMR_WB}
* </ul>
*
* If the MIME type is not supported, {@link Transformer} will fallback to a supported MIME type
* and {@link Listener#onFallbackApplied(Composition, TransformationRequest,
* TransformationRequest)} will be invoked with the fallback value.
*
* @param audioMimeType The MIME type of the audio samples in the output.
* @return This builder.
* @throws IllegalArgumentException If the audio MIME type passed is not an audio {@linkplain
* MimeTypes MIME type}.
*/
@CanIgnoreReturnValue
public Builder setAudioMimeType(String audioMimeType) {
checkArgument(MimeTypes.isAudio(audioMimeType), "Not an audio MIME type: " + audioMimeType);
this.audioMimeType = audioMimeType;
return this;
}
/**
* Sets the video {@linkplain MimeTypes MIME type} of the output.
*
* <p>If no video MIME type is passed, the output video MIME type is the same as the first
* {@link MediaItem} in the {@link Composition}.
*
* <p>Supported MIME types are:
*
* <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>
*
* If the MIME type is not supported, {@link Transformer} will fallback to a supported MIME type
* and {@link Listener#onFallbackApplied(Composition, TransformationRequest,
* TransformationRequest)} will be invoked with the fallback value.
*
* @param videoMimeType The MIME type of the video samples in the output.
* @return This builder.
* @throws IllegalArgumentException If the video MIME type passed is not a video {@linkplain
* MimeTypes MIME type}.
*/
@CanIgnoreReturnValue
public Builder setVideoMimeType(String videoMimeType) {
checkArgument(MimeTypes.isVideo(videoMimeType), "Not a video MIME type: " + videoMimeType);
this.videoMimeType = videoMimeType;
return this;
}
/**
* @deprecated Use {@link #setAudioMimeType(String)}, {@link #setVideoMimeType(String)} and
* {@link Composition.Builder#setHdrMode(int)} instead.
*/
@Deprecated
@CanIgnoreReturnValue
public Builder setTransformationRequest(TransformationRequest transformationRequest) {
this.transformationRequest = transformationRequest;
return this;
@ -376,6 +435,17 @@ public final class Transformer {
* type.
*/
public Transformer build() {
TransformationRequest.Builder transformationRequestBuilder =
transformationRequest == null
? new TransformationRequest.Builder()
: transformationRequest.buildUpon();
if (audioMimeType != null) {
transformationRequestBuilder.setAudioMimeType(audioMimeType);
}
if (videoMimeType != null) {
transformationRequestBuilder.setVideoMimeType(videoMimeType);
}
transformationRequest = transformationRequestBuilder.build();
if (transformationRequest.audioMimeType != null) {
checkSampleMimeType(transformationRequest.audioMimeType);
}
@ -720,6 +790,11 @@ public final class Transformer {
TransformerInternalListener transformerInternalListener =
new TransformerInternalListener(composition);
HandlerWrapper applicationHandler = clock.createHandler(looper, /* callback= */ null);
TransformationRequest transformationRequest = this.transformationRequest;
if (composition.hdrMode != Composition.HDR_MODE_KEEP_HDR) {
transformationRequest =
transformationRequest.buildUpon().setHdrMode(composition.hdrMode).build();
}
FallbackListener fallbackListener =
new FallbackListener(composition, listeners, applicationHandler, transformationRequest);
DebugTraceUtil.reset();