Move createCodecProfileLevel() to MediaCodecUtil and simplify usages

This is a non-functional change.

PiperOrigin-RevId: 736534306
This commit is contained in:
ivanbuper 2025-03-13 09:32:42 -07:00 committed by Copybara-Service
parent 816d5cb86b
commit d777a11840
7 changed files with 65 additions and 61 deletions

View File

@ -30,6 +30,7 @@ import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_YES_
import static androidx.media3.exoplayer.DecoderReuseEvaluation.REUSE_RESULT_YES_WITH_RECONFIGURATION;
import static androidx.media3.exoplayer.mediacodec.MediaCodecPerformancePointCoverageProvider.COVERAGE_RESULT_NO;
import static androidx.media3.exoplayer.mediacodec.MediaCodecPerformancePointCoverageProvider.COVERAGE_RESULT_YES;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import android.graphics.Point;
import android.media.MediaCodec;
@ -775,12 +776,8 @@ public final class MediaCodecInfo {
level = CodecProfileLevel.VP9Level1;
}
CodecProfileLevel profileLevel = new CodecProfileLevel();
// Since this method is for legacy devices only, assume that only profile 0 is supported.
profileLevel.profile = CodecProfileLevel.VP9Profile0;
profileLevel.level = level;
return new CodecProfileLevel[] {profileLevel};
return new CodecProfileLevel[] {createCodecProfileLevel(CodecProfileLevel.VP9Profile0, level)};
}
/**

View File

@ -322,6 +322,18 @@ public final class MediaCodecUtil {
return maxH264DecodableFrameSize;
}
/**
* Returns a {@link CodecProfileLevel} configured with the provided {@code profile} and {@code
* level}.
*/
@UnstableApi
public static CodecProfileLevel createCodecProfileLevel(int profile, int level) {
CodecProfileLevel profileLevel = new CodecProfileLevel();
profileLevel.profile = profile;
profileLevel.level = level;
return profileLevel;
}
/**
* @deprecated Use {@link CodecSpecificDataUtil#getCodecProfileAndLevel(Format)}.
*/

View File

@ -16,8 +16,18 @@
package androidx.media3.exoplayer.video;
import static android.media.MediaCodec.INFO_TRY_AGAIN_LATER;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel42;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCProfileBaseline;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd30;
import static android.media.MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheDtr;
import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCHighTierLevel51;
import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCMainTierLevel41;
import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain;
import static android.media.MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10;
import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.media3.common.util.Util.msToUs;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.format;
import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
@ -139,8 +149,7 @@ public class MediaCodecVideoRendererTest {
/* name= */ "h264-codec-hw",
/* mimeType= */ MimeTypes.VIDEO_H264,
/* codecMimeType= */ MimeTypes.VIDEO_H264,
/* capabilities= */ createCodecCapabilities(
CodecProfileLevel.AVCProfileHigh, CodecProfileLevel.AVCLevel4),
/* capabilities= */ createCodecCapabilities(AVCProfileHigh, CodecProfileLevel.AVCLevel4),
/* hardwareAccelerated= */ true,
/* softwareOnly= */ false,
/* vendor= */ false,
@ -152,8 +161,7 @@ public class MediaCodecVideoRendererTest {
/* name= */ "h264-codec-sw",
/* mimeType= */ MimeTypes.VIDEO_H264,
/* codecMimeType= */ MimeTypes.VIDEO_H264,
/* capabilities= */ createCodecCapabilities(
CodecProfileLevel.AVCProfileHigh, CodecProfileLevel.AVCLevel5),
/* capabilities= */ createCodecCapabilities(AVCProfileHigh, CodecProfileLevel.AVCLevel5),
/* hardwareAccelerated= */ false,
/* softwareOnly= */ true,
/* vendor= */ false,
@ -1817,11 +1825,10 @@ public class MediaCodecVideoRendererTest {
case MimeTypes.VIDEO_H264:
CodecCapabilities capabilitiesH264 = new CodecCapabilities();
capabilitiesH264.profileLevels =
new CodecProfileLevel[] {new CodecProfileLevel(), new CodecProfileLevel()};
capabilitiesH264.profileLevels[0].profile = CodecProfileLevel.AVCProfileBaseline;
capabilitiesH264.profileLevels[0].level = CodecProfileLevel.AVCLevel42;
capabilitiesH264.profileLevels[1].profile = CodecProfileLevel.AVCProfileHigh;
capabilitiesH264.profileLevels[1].level = CodecProfileLevel.AVCLevel42;
new CodecProfileLevel[] {
createCodecProfileLevel(AVCProfileBaseline, AVCLevel42),
createCodecProfileLevel(AVCProfileHigh, AVCLevel42)
};
return ImmutableList.of(
MediaCodecInfo.newInstance(
/* name= */ "h264-codec",
@ -1836,11 +1843,10 @@ public class MediaCodecVideoRendererTest {
case MimeTypes.VIDEO_H265:
CodecCapabilities capabilitiesH265 = new CodecCapabilities();
capabilitiesH265.profileLevels =
new CodecProfileLevel[] {new CodecProfileLevel(), new CodecProfileLevel()};
capabilitiesH265.profileLevels[0].profile = CodecProfileLevel.HEVCProfileMain;
capabilitiesH265.profileLevels[0].level = CodecProfileLevel.HEVCMainTierLevel41;
capabilitiesH265.profileLevels[1].profile = CodecProfileLevel.HEVCProfileMain10;
capabilitiesH265.profileLevels[1].level = CodecProfileLevel.HEVCHighTierLevel51;
new CodecProfileLevel[] {
createCodecProfileLevel(HEVCProfileMain, HEVCMainTierLevel41),
createCodecProfileLevel(HEVCProfileMain10, HEVCHighTierLevel51)
};
return ImmutableList.of(
MediaCodecInfo.newInstance(
/* name= */ "h265-codec",
@ -1899,11 +1905,8 @@ public class MediaCodecVideoRendererTest {
switch (mimeType) {
case MimeTypes.VIDEO_DOLBY_VISION:
{
CodecCapabilities capabilitiesDolby = new CodecCapabilities();
capabilitiesDolby.profileLevels = new CodecProfileLevel[] {new CodecProfileLevel()};
capabilitiesDolby.profileLevels[0].profile =
CodecProfileLevel.DolbyVisionProfileDvheDtr;
capabilitiesDolby.profileLevels[0].level = CodecProfileLevel.DolbyVisionLevelFhd30;
CodecCapabilities capabilitiesDolby =
createCodecCapabilities(DolbyVisionProfileDvheDtr, DolbyVisionLevelFhd30);
return ImmutableList.of(
MediaCodecInfo.newInstance(
/* name= */ "dvhe-codec",
@ -1920,11 +1923,10 @@ public class MediaCodecVideoRendererTest {
{
CodecCapabilities capabilitiesH265 = new CodecCapabilities();
capabilitiesH265.profileLevels =
new CodecProfileLevel[] {new CodecProfileLevel(), new CodecProfileLevel()};
capabilitiesH265.profileLevels[0].profile = CodecProfileLevel.HEVCProfileMain;
capabilitiesH265.profileLevels[0].level = CodecProfileLevel.HEVCMainTierLevel41;
capabilitiesH265.profileLevels[1].profile = CodecProfileLevel.HEVCProfileMain10;
capabilitiesH265.profileLevels[1].level = CodecProfileLevel.HEVCHighTierLevel51;
new CodecProfileLevel[] {
createCodecProfileLevel(HEVCProfileMain, HEVCMainTierLevel41),
createCodecProfileLevel(HEVCProfileMain10, HEVCHighTierLevel51)
};
return ImmutableList.of(
MediaCodecInfo.newInstance(
/* name= */ "h265-codec",
@ -2150,9 +2152,7 @@ public class MediaCodecVideoRendererTest {
private static CodecCapabilities createCodecCapabilities(int profile, int level) {
CodecCapabilities capabilities = new CodecCapabilities();
capabilities.profileLevels = new CodecProfileLevel[] {new CodecProfileLevel()};
capabilities.profileLevels[0].profile = profile;
capabilities.profileLevels[0].level = level;
capabilities.profileLevels = new CodecProfileLevel[] {createCodecProfileLevel(profile, level)};
return capabilities;
}

View File

@ -18,6 +18,7 @@ package androidx.media3.test.utils.robolectric;
import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
@ -145,7 +146,7 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
/* codecName= */ "exotest.video.avc",
/* mimeType= */ MimeTypes.VIDEO_H264,
/* profileLevels= */ ImmutableList.of(
createProfileLevel(
createCodecProfileLevel(
MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
MediaCodecInfo.CodecProfileLevel.AVCLevel62)),
/* colorFormats= */ ImmutableList.of(
@ -156,7 +157,7 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
/* codecName= */ "exotest.video.hevc",
/* mimeType= */ MimeTypes.VIDEO_H265,
/* profileLevels= */ ImmutableList.of(
createProfileLevel(
createCodecProfileLevel(
CodecProfileLevel.HEVCProfileMain, CodecProfileLevel.HEVCMainTierLevel61)),
/* colorFormats= */ ImmutableList.of(
MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible)));
@ -166,7 +167,7 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
/* codecName= */ "exotest.video.mpeg2",
/* mimeType= */ MimeTypes.VIDEO_MPEG2,
/* profileLevels= */ ImmutableList.of(
createProfileLevel(
createCodecProfileLevel(
MediaCodecInfo.CodecProfileLevel.MPEG2ProfileMain,
MediaCodecInfo.CodecProfileLevel.MPEG2LevelML)),
/* colorFormats= */ ImmutableList.of(
@ -232,13 +233,6 @@ public final class ShadowMediaCodecConfig extends ExternalResource {
return codecs.buildOrThrow();
}
private static MediaCodecInfo.CodecProfileLevel createProfileLevel(int profile, int level) {
MediaCodecInfo.CodecProfileLevel profileLevel = new MediaCodecInfo.CodecProfileLevel();
profileLevel.profile = profile;
profileLevel.level = level;
return profileLevel;
}
/**
* A {@link ShadowMediaCodec.CodecConfig.Codec} that passes data through without modifying it.
*

View File

@ -16,6 +16,9 @@
package androidx.media3.transformer;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel4;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import static androidx.media3.transformer.ExportException.ERROR_CODE_ENCODING_FORMAT_UNSUPPORTED;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
@ -23,6 +26,7 @@ import static org.junit.Assert.assertThrows;
import android.content.Context;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaFormat;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
@ -58,11 +62,9 @@ public class DefaultEncoderFactoryTest {
private static void createShadowH264Encoder() {
MediaFormat avcFormat = new MediaFormat();
avcFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
MediaCodecInfo.CodecProfileLevel profileLevel = new MediaCodecInfo.CodecProfileLevel();
profileLevel.profile = MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
// Using Level4 gives us 8192 16x16 blocks. If using width 1920 uses 120 blocks, 8192 / 120 = 68
// blocks will be left for encoding height 1088.
profileLevel.level = MediaCodecInfo.CodecProfileLevel.AVCLevel4;
CodecProfileLevel profileLevel = createCodecProfileLevel(AVCProfileHigh, AVCLevel4);
createShadowVideoEncoder(avcFormat, profileLevel, "test.transformer.avc.encoder");
}
@ -79,16 +81,14 @@ public class DefaultEncoderFactoryTest {
}
private static void createShadowVideoEncoder(
MediaFormat supportedFormat,
MediaCodecInfo.CodecProfileLevel supportedProfileLevel,
String name) {
MediaFormat supportedFormat, CodecProfileLevel supportedProfileLevel, String name) {
MediaCodecInfo.CodecCapabilities capabilities =
MediaCodecInfoBuilder.CodecCapabilitiesBuilder.newBuilder()
.setMediaFormat(supportedFormat)
.setIsEncoder(true)
.setColorFormats(
new int[] {MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible})
.setProfileLevels(new MediaCodecInfo.CodecProfileLevel[] {supportedProfileLevel})
.setProfileLevels(new CodecProfileLevel[] {supportedProfileLevel})
.build();
createShadowEncoder(name, capabilities);
}

View File

@ -16,10 +16,14 @@
package androidx.media3.transformer;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel4;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
import static androidx.media3.common.MimeTypes.VIDEO_H264;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import static com.google.common.truth.Truth.assertThat;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaFormat;
import android.util.Size;
import androidx.annotation.Nullable;
@ -48,11 +52,9 @@ public class EncoderUtilTest {
public void setUp() {
MediaFormat avcFormat = new MediaFormat();
avcFormat.setString(MediaFormat.KEY_MIME, VIDEO_H264);
MediaCodecInfo.CodecProfileLevel profileLevel = new MediaCodecInfo.CodecProfileLevel();
profileLevel.profile = MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
// Using Level4 gives us 8192 16x16 blocks. If using width 1920 uses 120 blocks, 8192 / 120 = 68
// blocks will be left for encoding height 1088.
profileLevel.level = MediaCodecInfo.CodecProfileLevel.AVCLevel4;
CodecProfileLevel profileLevel = createCodecProfileLevel(AVCProfileHigh, AVCLevel4);
ShadowMediaCodecList.addCodec(
MediaCodecInfoBuilder.newBuilder()
@ -64,7 +66,7 @@ public class EncoderUtilTest {
.setIsEncoder(true)
.setColorFormats(
new int[] {MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible})
.setProfileLevels(new MediaCodecInfo.CodecProfileLevel[] {profileLevel})
.setProfileLevels(new CodecProfileLevel[] {profileLevel})
.build())
.build());
}

View File

@ -15,11 +15,15 @@
*/
package androidx.media3.transformer;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCLevel4;
import static android.media.MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
import static androidx.media3.exoplayer.mediacodec.MediaCodecUtil.createCodecProfileLevel;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaFormat;
import android.net.Uri;
import android.os.Looper;
@ -139,19 +143,15 @@ public final class VideoEncoderWrapperTest {
private static void createShadowH264Encoder() {
MediaFormat avcFormat = new MediaFormat();
avcFormat.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_VIDEO_AVC);
MediaCodecInfo.CodecProfileLevel profileLevel = new MediaCodecInfo.CodecProfileLevel();
profileLevel.profile = MediaCodecInfo.CodecProfileLevel.AVCProfileHigh;
// Using Level4 gives us 8192 16x16 blocks. If using width 1920 uses 120 blocks, 8192 / 120 = 68
// blocks will be left for encoding height 1088.
profileLevel.level = MediaCodecInfo.CodecProfileLevel.AVCLevel4;
CodecProfileLevel profileLevel = createCodecProfileLevel(AVCProfileHigh, AVCLevel4);
createShadowVideoEncoder(avcFormat, profileLevel, "test.transformer.avc.encoder");
}
private static void createShadowVideoEncoder(
MediaFormat supportedFormat,
MediaCodecInfo.CodecProfileLevel supportedProfileLevel,
String name) {
MediaFormat supportedFormat, CodecProfileLevel supportedProfileLevel, String name) {
// ShadowMediaCodecList is static. The added encoders will be visible for every test.
ShadowMediaCodecList.addCodec(
MediaCodecInfoBuilder.newBuilder()
@ -163,8 +163,7 @@ public final class VideoEncoderWrapperTest {
.setIsEncoder(true)
.setColorFormats(
new int[] {MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible})
.setProfileLevels(
new MediaCodecInfo.CodecProfileLevel[] {supportedProfileLevel})
.setProfileLevels(new CodecProfileLevel[] {supportedProfileLevel})
.build())
.build());
}