mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Align ASP and VSP on findSupportedMimeTypeForEncoder/Muxer logic.
* Moved the logic to SamplePipeline. * Pass the requested values via Format. * Moved exception throwing inside the methods. * Build up the mimeTypesToCheck as a set - removing possible duplicate checks. * Simplified logic that calls the findSupportedMimeType method. * Improved javadoc. PiperOrigin-RevId: 509594062
This commit is contained in:
parent
ccd8856dac
commit
d91afa063a
@ -33,7 +33,6 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
|
import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
|
||||||
@ -119,36 +118,32 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
|
|
||||||
audioProcessingPipeline.flush();
|
audioProcessingPipeline.flush();
|
||||||
|
|
||||||
String requestedMimeType =
|
Format requestedEncoderFormat =
|
||||||
transformationRequest.audioMimeType != null
|
|
||||||
? transformationRequest.audioMimeType
|
|
||||||
: checkNotNull(firstInputFormat.sampleMimeType);
|
|
||||||
Format requestedOutputFormat =
|
|
||||||
new Format.Builder()
|
new Format.Builder()
|
||||||
.setSampleMimeType(requestedMimeType)
|
.setSampleMimeType(
|
||||||
|
transformationRequest.audioMimeType != null
|
||||||
|
? transformationRequest.audioMimeType
|
||||||
|
: checkNotNull(firstInputFormat.sampleMimeType))
|
||||||
.setSampleRate(encoderInputAudioFormat.sampleRate)
|
.setSampleRate(encoderInputAudioFormat.sampleRate)
|
||||||
.setChannelCount(encoderInputAudioFormat.channelCount)
|
.setChannelCount(encoderInputAudioFormat.channelCount)
|
||||||
.setAverageBitrate(DEFAULT_ENCODER_BITRATE)
|
.setAverageBitrate(DEFAULT_ENCODER_BITRATE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
ImmutableList<String> muxerSupportedMimeTypes =
|
|
||||||
muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_AUDIO);
|
|
||||||
|
|
||||||
// TODO(b/259570024): investigate overhauling fallback.
|
|
||||||
@Nullable
|
|
||||||
String supportedMimeType =
|
|
||||||
findSupportedMimeTypeForEncoderAndMuxer(requestedMimeType, muxerSupportedMimeTypes);
|
|
||||||
if (supportedMimeType == null) {
|
|
||||||
throw createNoSupportedMimeTypeException(requestedOutputFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder =
|
encoder =
|
||||||
encoderFactory.createForAudioEncoding(
|
encoderFactory.createForAudioEncoding(
|
||||||
requestedOutputFormat.buildUpon().setSampleMimeType(supportedMimeType).build());
|
requestedEncoderFormat
|
||||||
checkState(supportedMimeType.equals(encoder.getConfigurationFormat().sampleMimeType));
|
.buildUpon()
|
||||||
|
.setSampleMimeType(
|
||||||
|
findSupportedMimeTypeForEncoderAndMuxer(
|
||||||
|
requestedEncoderFormat,
|
||||||
|
muxerWrapper.getSupportedSampleMimeTypes(C.TRACK_TYPE_AUDIO)))
|
||||||
|
.build());
|
||||||
|
|
||||||
fallbackListener.onTransformationRequestFinalized(
|
fallbackListener.onTransformationRequestFinalized(
|
||||||
createFallbackTransformationRequest(
|
createFallbackTransformationRequest(
|
||||||
transformationRequest, requestedOutputFormat, encoder.getConfigurationFormat()));
|
transformationRequest,
|
||||||
|
requestedEncoderFormat,
|
||||||
|
/* actualFormat= */ encoder.getConfigurationFormat()));
|
||||||
|
|
||||||
// Use the same stream offset as the input stream for encoder input buffers.
|
// Use the same stream offset as the input stream for encoder input buffers.
|
||||||
nextEncoderInputBufferTimeUs = streamOffsetUs;
|
nextEncoderInputBufferTimeUs = streamOffsetUs;
|
||||||
@ -350,23 +345,6 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
encoder.queueInputBuffer(encoderInputBuffer);
|
encoder.queueInputBuffer(encoderInputBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String findSupportedMimeTypeForEncoderAndMuxer(
|
|
||||||
String preferredMimeType, List<String> muxerSupportedMimeTypes) {
|
|
||||||
if (!EncoderUtil.getSupportedEncoders(preferredMimeType).isEmpty()) {
|
|
||||||
return preferredMimeType;
|
|
||||||
} else {
|
|
||||||
// No encoder supports the preferred MIME type.
|
|
||||||
for (int i = 0; i < muxerSupportedMimeTypes.size(); i++) {
|
|
||||||
String mimeType = muxerSupportedMimeTypes.get(i);
|
|
||||||
if (!EncoderUtil.getSupportedEncoders(mimeType).isEmpty()) {
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pure
|
@Pure
|
||||||
private static TransformationRequest createFallbackTransformationRequest(
|
private static TransformationRequest createFallbackTransformationRequest(
|
||||||
TransformationRequest transformationRequest, Format requestedFormat, Format actualFormat) {
|
TransformationRequest transformationRequest, Format requestedFormat, Format actualFormat) {
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
|
|
||||||
package com.google.android.exoplayer2.transformer;
|
package com.google.android.exoplayer2.transformer;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.transformer.EncoderUtil.getSupportedEncoders;
|
||||||
|
import static com.google.android.exoplayer2.transformer.EncoderUtil.getSupportedEncodersForHdrEditing;
|
||||||
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
|
import static com.google.android.exoplayer2.util.Assertions.checkStateNotNull;
|
||||||
|
import static com.google.android.exoplayer2.video.ColorInfo.isTransferHdr;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
@ -24,6 +28,9 @@ import com.google.android.exoplayer2.Format;
|
|||||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import com.google.android.exoplayer2.video.ColorInfo;
|
import com.google.android.exoplayer2.video.ColorInfo;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pipeline for processing media data.
|
* Pipeline for processing media data.
|
||||||
@ -48,23 +55,6 @@ import com.google.android.exoplayer2.video.ColorInfo;
|
|||||||
: MimeTypes.getTrackType(firstInputFormat.sampleMimeType);
|
: MimeTypes.getTrackType(firstInputFormat.sampleMimeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static TransformationException createNoSupportedMimeTypeException(Format format) {
|
|
||||||
String errorMessage = "No MIME type is supported by both encoder and muxer.";
|
|
||||||
int errorCode = TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED;
|
|
||||||
boolean isVideo = MimeTypes.isVideo(format.sampleMimeType);
|
|
||||||
|
|
||||||
if (isVideo && ColorInfo.isTransferHdr(format.colorInfo)) {
|
|
||||||
errorMessage += " Requested HDR colorInfo: " + format.colorInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TransformationException.createForCodec(
|
|
||||||
new IllegalArgumentException(errorMessage),
|
|
||||||
errorCode,
|
|
||||||
isVideo,
|
|
||||||
/* isDecoder= */ false,
|
|
||||||
format);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean expectsDecodedData() {
|
public boolean expectsDecodedData() {
|
||||||
return true;
|
return true;
|
||||||
@ -143,4 +133,72 @@ import com.google.android.exoplayer2.video.ColorInfo;
|
|||||||
releaseMuxerInputBuffer();
|
releaseMuxerInputBuffer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a {@linkplain MimeTypes MIME type} that is supported by the encoder and the muxer.
|
||||||
|
*
|
||||||
|
* <p>The {@linkplain Format requestedFormat} determines what support is checked.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>The {@link Format#sampleMimeType} determines whether audio or video mime types are
|
||||||
|
* considered. See {@link MimeTypes#isAudio} and {@link MimeTypes#isVideo} for more details.
|
||||||
|
* <li>The {@link Format#sampleMimeType} must be populated with the preferred {@linkplain
|
||||||
|
* MimeTypes MIME type}. This mime type will be the first checked.
|
||||||
|
* <li>When checking video support, if the HDR {@link Format#colorInfo} is set, only encoders
|
||||||
|
* that support that {@link ColorInfo} will be considered.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param requestedFormat The {@link Format} requested.
|
||||||
|
* @param muxerSupportedMimeTypes The list of sample {@linkplain MimeTypes MIME types} that the
|
||||||
|
* muxer supports.
|
||||||
|
* @return A supported {@linkplain MimeTypes MIME type}.
|
||||||
|
* @throws TransformationException If there are no supported {@linkplain MimeTypes MIME types}.
|
||||||
|
*/
|
||||||
|
protected static String findSupportedMimeTypeForEncoderAndMuxer(
|
||||||
|
Format requestedFormat, List<String> muxerSupportedMimeTypes) throws TransformationException {
|
||||||
|
boolean isVideo = MimeTypes.isVideo(checkNotNull(requestedFormat.sampleMimeType));
|
||||||
|
|
||||||
|
ImmutableSet.Builder<String> mimeTypesToCheckSetBuilder =
|
||||||
|
new ImmutableSet.Builder<String>().add(requestedFormat.sampleMimeType);
|
||||||
|
if (isVideo) {
|
||||||
|
mimeTypesToCheckSetBuilder.add(MimeTypes.VIDEO_H265).add(MimeTypes.VIDEO_H264);
|
||||||
|
}
|
||||||
|
mimeTypesToCheckSetBuilder.addAll(muxerSupportedMimeTypes);
|
||||||
|
ImmutableList<String> mimeTypesToCheck = mimeTypesToCheckSetBuilder.build().asList();
|
||||||
|
|
||||||
|
for (int i = 0; i < mimeTypesToCheck.size(); i++) {
|
||||||
|
String mimeType = mimeTypesToCheck.get(i);
|
||||||
|
|
||||||
|
if (!muxerSupportedMimeTypes.contains(mimeType)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVideo && isTransferHdr(requestedFormat.colorInfo)) {
|
||||||
|
if (!getSupportedEncodersForHdrEditing(mimeType, requestedFormat.colorInfo).isEmpty()) {
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
} else if (!getSupportedEncoders(mimeType).isEmpty()) {
|
||||||
|
return mimeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw createNoSupportedMimeTypeException(requestedFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransformationException createNoSupportedMimeTypeException(Format format) {
|
||||||
|
String errorMessage = "No MIME type is supported by both encoder and muxer.";
|
||||||
|
int errorCode = TransformationException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED;
|
||||||
|
boolean isVideo = MimeTypes.isVideo(format.sampleMimeType);
|
||||||
|
|
||||||
|
if (isVideo && isTransferHdr(format.colorInfo)) {
|
||||||
|
errorMessage += " Requested HDR colorInfo: " + format.colorInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransformationException.createForCodec(
|
||||||
|
new IllegalArgumentException(errorMessage),
|
||||||
|
errorCode,
|
||||||
|
isVideo,
|
||||||
|
/* isDecoder= */ false,
|
||||||
|
format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
package com.google.android.exoplayer2.transformer;
|
package com.google.android.exoplayer2.transformer;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.transformer.EncoderUtil.getSupportedEncoders;
|
|
||||||
import static com.google.android.exoplayer2.transformer.EncoderUtil.getSupportedEncodersForHdrEditing;
|
import static com.google.android.exoplayer2.transformer.EncoderUtil.getSupportedEncodersForHdrEditing;
|
||||||
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
|
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
|
||||||
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_KEEP_HDR;
|
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_KEEP_HDR;
|
||||||
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
|
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
|
||||||
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
|
import static com.google.android.exoplayer2.transformer.TransformationRequest.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||||
import static com.google.android.exoplayer2.util.Assertions.checkState;
|
|
||||||
import static com.google.android.exoplayer2.util.Util.SDK_INT;
|
import static com.google.android.exoplayer2.util.Util.SDK_INT;
|
||||||
import static com.google.android.exoplayer2.video.ColorInfo.isTransferHdr;
|
import static com.google.android.exoplayer2.video.ColorInfo.isTransferHdr;
|
||||||
|
|
||||||
@ -425,20 +423,16 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
.setColorInfo(getSupportedInputColor())
|
.setColorInfo(getSupportedInputColor())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@Nullable
|
|
||||||
String supportedMimeType =
|
|
||||||
findSupportedMimeTypeForEncoderAndMuxer(
|
|
||||||
requestedOutputMimeType, muxerSupportedMimeTypes, requestedEncoderFormat.colorInfo);
|
|
||||||
if (supportedMimeType == null) {
|
|
||||||
throw createNoSupportedMimeTypeException(requestedEncoderFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder =
|
encoder =
|
||||||
encoderFactory.createForVideoEncoding(
|
encoderFactory.createForVideoEncoding(
|
||||||
requestedEncoderFormat.buildUpon().setSampleMimeType(supportedMimeType).build());
|
requestedEncoderFormat
|
||||||
|
.buildUpon()
|
||||||
|
.setSampleMimeType(
|
||||||
|
findSupportedMimeTypeForEncoderAndMuxer(
|
||||||
|
requestedEncoderFormat, muxerSupportedMimeTypes))
|
||||||
|
.build());
|
||||||
|
|
||||||
Format encoderSupportedFormat = encoder.getConfigurationFormat();
|
Format actualEncoderFormat = encoder.getConfigurationFormat();
|
||||||
checkState(supportedMimeType.equals(encoderSupportedFormat.sampleMimeType));
|
|
||||||
|
|
||||||
boolean isInputToneMapped =
|
boolean isInputToneMapped =
|
||||||
isTransferHdr(inputFormat.colorInfo) && !isTransferHdr(requestedEncoderFormat.colorInfo);
|
isTransferHdr(inputFormat.colorInfo) && !isTransferHdr(requestedEncoderFormat.colorInfo);
|
||||||
@ -456,14 +450,14 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
transformationRequest,
|
transformationRequest,
|
||||||
/* hasOutputFormatRotation= */ outputRotationDegrees != 0,
|
/* hasOutputFormatRotation= */ outputRotationDegrees != 0,
|
||||||
requestedEncoderFormat,
|
requestedEncoderFormat,
|
||||||
encoderSupportedFormat,
|
actualEncoderFormat,
|
||||||
supportedFallbackHdrMode));
|
supportedFallbackHdrMode));
|
||||||
|
|
||||||
encoderSurfaceInfo =
|
encoderSurfaceInfo =
|
||||||
new SurfaceInfo(
|
new SurfaceInfo(
|
||||||
encoder.getInputSurface(),
|
encoder.getInputSurface(),
|
||||||
encoderSupportedFormat.width,
|
actualEncoderFormat.width,
|
||||||
encoderSupportedFormat.height,
|
actualEncoderFormat.height,
|
||||||
outputRotationDegrees);
|
outputRotationDegrees);
|
||||||
|
|
||||||
if (releaseEncoder) {
|
if (releaseEncoder) {
|
||||||
@ -516,52 +510,5 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
}
|
}
|
||||||
releaseEncoder = true;
|
releaseEncoder = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds a {@linkplain MimeTypes MIME type} that is supported by the encoder and the muxer.
|
|
||||||
*
|
|
||||||
* <p>HDR editing support is checked if the {@link ColorInfo} is HDR.
|
|
||||||
*
|
|
||||||
* @param preferredMimeType The preferred {@linkplain MimeTypes MIME type}, returned if
|
|
||||||
* supported.
|
|
||||||
* @param muxerSupportedMimeTypes The list of sample {@linkplain MimeTypes MIME types} that the
|
|
||||||
* muxer supports.
|
|
||||||
* @param colorInfo The optional encoding {@link ColorInfo}. If a HDR color info is provided,
|
|
||||||
* only encoders that support it will be considered.
|
|
||||||
* @return A {@linkplain MimeTypes MIME type} that is supported by an encoder and the muxer, or
|
|
||||||
* {@code null} if no such {@linkplain MimeTypes MIME type} exists.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
private static String findSupportedMimeTypeForEncoderAndMuxer(
|
|
||||||
String preferredMimeType,
|
|
||||||
List<String> muxerSupportedMimeTypes,
|
|
||||||
@Nullable ColorInfo colorInfo) {
|
|
||||||
ImmutableList<String> mimeTypesToCheck =
|
|
||||||
new ImmutableList.Builder<String>()
|
|
||||||
.add(preferredMimeType)
|
|
||||||
.add(MimeTypes.VIDEO_H265)
|
|
||||||
.add(MimeTypes.VIDEO_H264)
|
|
||||||
.addAll(muxerSupportedMimeTypes)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
for (int i = 0; i < mimeTypesToCheck.size(); i++) {
|
|
||||||
String mimeType = mimeTypesToCheck.get(i);
|
|
||||||
if (mimeTypeAndColorAreSupported(mimeType, muxerSupportedMimeTypes, colorInfo)) {
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean mimeTypeAndColorAreSupported(
|
|
||||||
String mimeType, List<String> muxerSupportedMimeTypes, @Nullable ColorInfo colorInfo) {
|
|
||||||
if (!muxerSupportedMimeTypes.contains(mimeType)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isTransferHdr(colorInfo)
|
|
||||||
? !getSupportedEncodersForHdrEditing(mimeType, colorInfo).isEmpty()
|
|
||||||
: !getSupportedEncoders(mimeType).isEmpty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user