mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add support for explicit passthrough and encoder shadow codec configs
This is a step towards unifying ShadowMediaCodecConfig structure to accomodate both ExoPlayer and Transcoding codecs configuration. ExoPlayer's `CodecConfig.Codec` implementation, due to b/174737370, discards all audio samples. This issue is only applicable for ExoPlayer tests and doesn't impact transcoding tests. To accomodate for having transcoding codecs, 2 fields were added to CodecImpl: `isPassThrough` that specifies whether we want to drop frames/samples or not, and `isEncoder` that specifies whether we are configuring a decoder or an encoder. This is a non-functional refactor. PiperOrigin-RevId: 739112659
This commit is contained in:
parent
3f5019b908
commit
3be1d5646f
@ -23,7 +23,6 @@ import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecPro
|
|||||||
import android.media.MediaCodecInfo;
|
import android.media.MediaCodecInfo;
|
||||||
import android.media.MediaCodecInfo.CodecProfileLevel;
|
import android.media.MediaCodecInfo.CodecProfileLevel;
|
||||||
import android.media.MediaFormat;
|
import android.media.MediaFormat;
|
||||||
import androidx.media3.common.C;
|
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
|
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
|
||||||
@ -150,7 +149,9 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
|
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
|
||||||
MediaCodecInfo.CodecProfileLevel.AVCLevel62)),
|
MediaCodecInfo.CodecProfileLevel.AVCLevel62)),
|
||||||
/* colorFormats= */ ImmutableList.of(
|
/* colorFormats= */ ImmutableList.of(
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible),
|
||||||
|
/* isPassthrough= */ true,
|
||||||
|
/* isEncoder= */ false));
|
||||||
codecs.put(
|
codecs.put(
|
||||||
MimeTypes.VIDEO_H265,
|
MimeTypes.VIDEO_H265,
|
||||||
new CodecImpl(
|
new CodecImpl(
|
||||||
@ -160,7 +161,9 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
createCodecProfileLevel(
|
createCodecProfileLevel(
|
||||||
CodecProfileLevel.HEVCProfileMain, CodecProfileLevel.HEVCMainTierLevel61)),
|
CodecProfileLevel.HEVCProfileMain, CodecProfileLevel.HEVCMainTierLevel61)),
|
||||||
/* colorFormats= */ ImmutableList.of(
|
/* colorFormats= */ ImmutableList.of(
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible),
|
||||||
|
/* isPassthrough= */ true,
|
||||||
|
/* isEncoder= */ false));
|
||||||
codecs.put(
|
codecs.put(
|
||||||
MimeTypes.VIDEO_MPEG2,
|
MimeTypes.VIDEO_MPEG2,
|
||||||
new CodecImpl(
|
new CodecImpl(
|
||||||
@ -171,7 +174,9 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain,
|
MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain,
|
||||||
MediaCodecInfo.CodecProfileLevel.MPEG2LevelML)),
|
MediaCodecInfo.CodecProfileLevel.MPEG2LevelML)),
|
||||||
/* colorFormats= */ ImmutableList.of(
|
/* colorFormats= */ ImmutableList.of(
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible),
|
||||||
|
/* isPassthrough= */ true,
|
||||||
|
/* isEncoder= */ false));
|
||||||
codecs.put(
|
codecs.put(
|
||||||
MimeTypes.VIDEO_VP9,
|
MimeTypes.VIDEO_VP9,
|
||||||
new CodecImpl(
|
new CodecImpl(
|
||||||
@ -179,7 +184,9 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
/* mimeType= */ MimeTypes.VIDEO_VP9,
|
/* mimeType= */ MimeTypes.VIDEO_VP9,
|
||||||
/* profileLevels= */ ImmutableList.of(),
|
/* profileLevels= */ ImmutableList.of(),
|
||||||
/* colorFormats= */ ImmutableList.of(
|
/* colorFormats= */ ImmutableList.of(
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible),
|
||||||
|
/* isPassthrough= */ true,
|
||||||
|
/* isEncoder= */ false));
|
||||||
codecs.put(
|
codecs.put(
|
||||||
MimeTypes.VIDEO_AV1,
|
MimeTypes.VIDEO_AV1,
|
||||||
new CodecImpl(
|
new CodecImpl(
|
||||||
@ -187,9 +194,11 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
/* mimeType= */ MimeTypes.VIDEO_AV1,
|
/* mimeType= */ MimeTypes.VIDEO_AV1,
|
||||||
/* profileLevels= */ ImmutableList.of(),
|
/* profileLevels= */ ImmutableList.of(),
|
||||||
/* colorFormats= */ ImmutableList.of(
|
/* colorFormats= */ ImmutableList.of(
|
||||||
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
|
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible),
|
||||||
|
/* isPassthrough= */ true,
|
||||||
|
/* isEncoder= */ false));
|
||||||
|
|
||||||
// Audio codecs
|
// Frame-dropping audio decoders.
|
||||||
codecs.put(
|
codecs.put(
|
||||||
MimeTypes.AUDIO_AAC,
|
MimeTypes.AUDIO_AAC,
|
||||||
new CodecImpl(/* codecName= */ "exotest.audio.aac", /* mimeType= */ MimeTypes.AUDIO_AAC));
|
new CodecImpl(/* codecName= */ "exotest.audio.aac", /* mimeType= */ MimeTypes.AUDIO_AAC));
|
||||||
@ -234,10 +243,8 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ShadowMediaCodec.CodecConfig.Codec} that passes data through without modifying it.
|
* A {@link ShadowMediaCodec.CodecConfig.Codec} that provides pass-through or frame dropping
|
||||||
*
|
* encoders and decoders.
|
||||||
* <p>Note: This currently drops all audio data - removing this restriction is tracked in
|
|
||||||
* [internal b/174737370].
|
|
||||||
*/
|
*/
|
||||||
private static final class CodecImpl implements ShadowMediaCodec.CodecConfig.Codec {
|
private static final class CodecImpl implements ShadowMediaCodec.CodecConfig.Codec {
|
||||||
|
|
||||||
@ -245,26 +252,53 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
private final String mimeType;
|
private final String mimeType;
|
||||||
private final ImmutableList<MediaCodecInfo.CodecProfileLevel> profileLevels;
|
private final ImmutableList<MediaCodecInfo.CodecProfileLevel> profileLevels;
|
||||||
private final ImmutableList<Integer> colorFormats;
|
private final ImmutableList<Integer> colorFormats;
|
||||||
private final @C.TrackType int trackType;
|
private final boolean isPassthrough;
|
||||||
|
private final boolean isEncoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a frame dropping decoder with the specified {@code codecName} and {@code mimeType}.
|
||||||
|
*
|
||||||
|
* <p>This method is equivalent to {@code new CodecImpl(codecName, mimeType, ImmutableList.of(),
|
||||||
|
* ImmutableList.of(), false, false)}.
|
||||||
|
*
|
||||||
|
* @param codecName The name of the codec.
|
||||||
|
* @param mimeType The MIME type of the codec.
|
||||||
|
*/
|
||||||
public CodecImpl(String codecName, String mimeType) {
|
public CodecImpl(String codecName, String mimeType) {
|
||||||
this(
|
this(
|
||||||
codecName,
|
codecName,
|
||||||
mimeType,
|
mimeType,
|
||||||
/* profileLevels= */ ImmutableList.of(),
|
/* profileLevels= */ ImmutableList.of(),
|
||||||
/* colorFormats= */ ImmutableList.of());
|
/* colorFormats= */ ImmutableList.of(),
|
||||||
|
/* isPassthrough= */ false,
|
||||||
|
/* isEncoder= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance.
|
||||||
|
*
|
||||||
|
* @param codecName The name of the codec.
|
||||||
|
* @param mimeType The MIME type of the codec.
|
||||||
|
* @param profileLevels A list of profiles and levels supported by the codec.
|
||||||
|
* @param colorFormats A list of color formats supported by the codec.
|
||||||
|
* @param isPassthrough If {@code true}, the codec acts as a pass-through codec, directly
|
||||||
|
* copying input data to the output. If {@code false}, the codec drops frames.
|
||||||
|
* @param isEncoder If {@code true}, the codec is an encoder. If {@code false}, the codec is a
|
||||||
|
* decoder.
|
||||||
|
*/
|
||||||
public CodecImpl(
|
public CodecImpl(
|
||||||
String codecName,
|
String codecName,
|
||||||
String mimeType,
|
String mimeType,
|
||||||
ImmutableList<CodecProfileLevel> profileLevels,
|
ImmutableList<CodecProfileLevel> profileLevels,
|
||||||
ImmutableList<Integer> colorFormats) {
|
ImmutableList<Integer> colorFormats,
|
||||||
|
boolean isPassthrough,
|
||||||
|
boolean isEncoder) {
|
||||||
this.codecName = codecName;
|
this.codecName = codecName;
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
this.profileLevels = profileLevels;
|
this.profileLevels = profileLevels;
|
||||||
this.colorFormats = colorFormats;
|
this.colorFormats = colorFormats;
|
||||||
trackType = MimeTypes.getTrackType(mimeType);
|
this.isPassthrough = isPassthrough;
|
||||||
|
this.isEncoder = isEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configure() {
|
public void configure() {
|
||||||
@ -274,7 +308,7 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
configureShadowMediaCodec(
|
configureShadowMediaCodec(
|
||||||
codecName,
|
codecName,
|
||||||
mimeType,
|
mimeType,
|
||||||
/* isEncoder= */ false,
|
isEncoder,
|
||||||
profileLevels,
|
profileLevels,
|
||||||
colorFormats,
|
colorFormats,
|
||||||
new ShadowMediaCodec.CodecConfig(
|
new ShadowMediaCodec.CodecConfig(
|
||||||
@ -285,12 +319,12 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(ByteBuffer in, ByteBuffer out) {
|
public void process(ByteBuffer in, ByteBuffer out) {
|
||||||
|
// TODO(internal b/174737370): Output audio bytes as well.
|
||||||
|
if (isPassthrough) {
|
||||||
|
out.put(in);
|
||||||
|
} else {
|
||||||
byte[] bytes = new byte[in.remaining()];
|
byte[] bytes = new byte[in.remaining()];
|
||||||
in.get(bytes);
|
in.get(bytes);
|
||||||
|
|
||||||
// TODO(internal b/174737370): Output audio bytes as well.
|
|
||||||
if (trackType != C.TRACK_TYPE_AUDIO) {
|
|
||||||
out.put(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user