/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.mediav2.cts;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.mediav2.common.cts.EncoderConfigParams;
import android.mediav2.common.cts.EncoderProfileLevelTestBase;
import android.mediav2.common.cts.OutputManager;
import android.util.Log;
import com.android.compatibility.common.util.ApiTest;
import com.android.compatibility.common.util.CddTest;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
/**
* EncoderProfileLevelTest validates the profile, level information advertised by the component
* in its codec capabilities. The test sets profile and level keys in media format and uses it
* during encoder configuration. Upon successful configuration, frames are queued for encoding
* (byte buffer mode) and the encoded output (bitstream) is expected to contain the same profile
* that was used during configure. The level shall be at least the input configured level.
*
* NOTE: The test configures level information basing on standard guidelines, not arbitrarily so
* encoders are expected to maintain at least the input configured level
*
* The test parses the bitstream (csd or frame header) and determines profile and level
* information. This serves as reference for further validation. The test checks if the output
* format returned by component contains same profile and level information as the bitstream. The
* output of encoder is muxed and is extracted. The extracted format is expected to contain same
* profile and level information as the bitstream.
*
* As per cdd, if a device contains an encoder capable of encoding a profile/level combination
* then it should contain a decoder capable of decoding the same profile/level combination. This
* is verified.
*
* If device implementations support encoding in a media type, then as per cdd they are expected to
* handle certain profile and level configurations. This is verified.
*/
@RunWith(Parameterized.class)
public class EncoderProfileLevelTest extends EncoderProfileLevelTestBase {
private static final String LOG_TAG = EncoderProfileLevelTest.class.getSimpleName();
private static final HashMap CDD_REQUIREMENTS_MAP = new HashMap<>();
private static class CddRequirements {
private int[] mProfiles;
private int mLevel;
private int mHeight;
private int mWidth;
CddRequirements(int[] profiles, int level, int width, int height) {
mProfiles = profiles;
mLevel = level;
mWidth = width;
mHeight = height;
}
CddRequirements(int[] profiles) {
this(profiles, -1 /* level */, -1 /* width */, -1 /* height */);
}
CddRequirements(int[] profiles, int level) {
this(profiles, level, -1 /* width */, -1 /* height */);
}
public int[] getProfiles() {
return mProfiles;
}
public int getLevel() {
return mLevel;
}
public int getWidth() {
return mWidth;
}
public int getHeight() {
return mHeight;
}
}
public EncoderProfileLevelTest(String encoder, String mediaType,
EncoderConfigParams[] encCfgParams, @SuppressWarnings("unused") String testLabel,
String allTestParams) {
super(encoder, mediaType, encCfgParams, allTestParams);
}
private static List prepareTestArgs(Object[] arg, int[] profiles, int colorFormat) {
List argsList = new ArrayList<>();
final int[] maxBFrames = {0, 2};
final String mediaType = (String) arg[0];
boolean isVideo = mediaType.startsWith("video/");
final int br = (int) arg[1];
final int param1 = (int) arg[2];
final int param2 = (int) arg[3];
final int fps = (int) arg[4];
final int level = (int) arg[5];
boolean[] boolStates = {false, true};
if (isVideo) {
for (int maxBframe : maxBFrames) {
if (maxBframe != 0) {
if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)
&& !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)) {
continue;
}
}
// test each resolution in both landscape and portrait orientation
for (boolean rotate : boolStates) {
int width, height;
if (rotate) {
width = param2;
height = param1;
} else {
width = param1;
height = param2;
}
// H.263 doesn't support portait mode, so skip cases where width is smaller
// than height.
if (mediaType.equals(MediaFormat.MIMETYPE_VIDEO_H263) && width <= height) {
continue;
}
Object[] testArgs = new Object[3];
testArgs[0] = arg[0];
testArgs[1] = getVideoEncoderCfgParams(mediaType, br, width, height, fps,
colorFormat, maxBframe, profiles, level);
testArgs[2] = String.format("%dkbps_%dx%d_%dfps_%s_%d_%d-bframes", br / 1000,
width, height, fps, colorFormatToString(colorFormat, -1),
level, maxBframe);
argsList.add(testArgs);
}
}
} else {
Object[] testArgs = new Object[3];
testArgs[0] = arg[0];
testArgs[1] = getAudioEncoderCfgParams(mediaType, br, param1, param2, profiles);
testArgs[2] = String.format("%dkbps_%dkHz_%dch", br / 1000, param1 / 1000, param2);
argsList.add(testArgs);
}
return argsList;
}
private static EncoderConfigParams[] getVideoEncoderCfgParams(String mediaType, int bitRate,
int width, int height, int frameRate, int colorFormat, int maxBframe, int[] profiles,
int level) {
ArrayList cfgParams = new ArrayList<>();
for (int profile : profiles) {
if (maxBframe != 0) {
if (mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC) && (
profile == AVCProfileBaseline
|| profile == AVCProfileConstrainedBaseline)) {
continue;
}
}
cfgParams.add(new EncoderConfigParams.Builder(mediaType)
.setBitRate(bitRate)
.setWidth(width)
.setHeight(height)
.setFrameRate(frameRate)
.setMaxBFrames(maxBframe)
.setProfile(profile)
.setLevel(level)
.setColorFormat(colorFormat)
.build());
}
return cfgParams.toArray(new EncoderConfigParams[0]);
}
private static EncoderConfigParams[] getAudioEncoderCfgParams(String mediaType, int bitRate,
int sampleRate, int channelCount, int[] profiles) {
EncoderConfigParams[] cfgParams = new EncoderConfigParams[profiles.length];
for (int i = 0; i < profiles.length; i++) {
cfgParams[i] = new EncoderConfigParams.Builder(mediaType)
.setBitRate(bitRate)
.setSampleRate(sampleRate)
.setChannelCount(channelCount)
.setProfile(profiles[i])
.build();
}
return cfgParams;
}
@Parameterized.Parameters(name = "{index}_{0}_{1}_{3}")
public static Collection input() {
final boolean isEncoder = true;
final boolean needAudio = true;
final boolean needVideo = true;
final Object[][] exhaustiveArgsList = new Object[][]{
// Audio - CodecMediaType, bit-rate, sample rate, channel count, level
{MediaFormat.MIMETYPE_AUDIO_AAC, 64000, 48000, 1, -1, -1},
{MediaFormat.MIMETYPE_AUDIO_AAC, 128000, 48000, 2, -1, -1},
// Video - CodecMediaType, bit-rate, width, height, frame-rate, level
// ITU-T H.264
// Table A-6 – Maximum frame rates (frames per second) for some example frame sizes
{MediaFormat.MIMETYPE_VIDEO_AVC, 64000, 176, 144, 15, AVCLevel1},
{MediaFormat.MIMETYPE_VIDEO_AVC, 128000, 176, 144, 15, AVCLevel1b},
{MediaFormat.MIMETYPE_VIDEO_AVC, 192000, 352, 288, 7, AVCLevel11},
{MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 352, 288, 15, AVCLevel12},
{MediaFormat.MIMETYPE_VIDEO_AVC, 512000, 352, 288, 30, AVCLevel13},
{MediaFormat.MIMETYPE_VIDEO_AVC, 832000, 352, 288, 30, AVCLevel2},
{MediaFormat.MIMETYPE_VIDEO_AVC, 1000000, 352, 576, 25, AVCLevel21},
{MediaFormat.MIMETYPE_VIDEO_AVC, 1500000, 720, 576, 12, AVCLevel22},
{MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 720, 576, 25, AVCLevel3},
{MediaFormat.MIMETYPE_VIDEO_AVC, 3000000, 1280, 720, 30, AVCLevel31},
{MediaFormat.MIMETYPE_VIDEO_AVC, 6000000, 1280, 1024, 42, AVCLevel32},
{MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 2048, 1024, 30, AVCLevel4},
{MediaFormat.MIMETYPE_VIDEO_AVC, 25000000, 2048, 1024, 30, AVCLevel41},
{MediaFormat.MIMETYPE_VIDEO_AVC, 50000000, 2048, 1088, 60, AVCLevel42},
{MediaFormat.MIMETYPE_VIDEO_AVC, 60000000, 3680, 1526, 26, AVCLevel5},
{MediaFormat.MIMETYPE_VIDEO_AVC, 80000000, 4096, 2304, 26, AVCLevel51},
{MediaFormat.MIMETYPE_VIDEO_AVC, 120000000, 4096, 2304, 56, AVCLevel52},
{MediaFormat.MIMETYPE_VIDEO_AVC, 240000000, 8192, 4320, 30, AVCLevel6},
{MediaFormat.MIMETYPE_VIDEO_AVC, 480000000, 8192, 4320, 60, AVCLevel61},
{MediaFormat.MIMETYPE_VIDEO_AVC, 800000000, 8192, 4320, 120, AVCLevel62},
// The entries below have width being twice that of the widths and height being
// half of the heights in Table A-6
// Since AVC specification has level limits in terms MacroBlocks and not in terms
// of pixels, the height is floored to multiple of 16 to fit within the level being
// tested
{MediaFormat.MIMETYPE_VIDEO_AVC, 64000, 352, 64, 15, AVCLevel1},
{MediaFormat.MIMETYPE_VIDEO_AVC, 128000, 352, 64, 15, AVCLevel1b},
{MediaFormat.MIMETYPE_VIDEO_AVC, 192000, 704, 144, 7, AVCLevel11},
{MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 704, 144, 15, AVCLevel12},
{MediaFormat.MIMETYPE_VIDEO_AVC, 512000, 704, 144, 30, AVCLevel13},
{MediaFormat.MIMETYPE_VIDEO_AVC, 832000, 704, 144, 30, AVCLevel2},
{MediaFormat.MIMETYPE_VIDEO_AVC, 1000000, 704, 288, 25, AVCLevel21},
{MediaFormat.MIMETYPE_VIDEO_AVC, 1500000, 1440, 288, 12, AVCLevel22},
{MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 1440, 288, 25, AVCLevel3},
{MediaFormat.MIMETYPE_VIDEO_AVC, 3000000, 2560, 352, 30, AVCLevel31},
{MediaFormat.MIMETYPE_VIDEO_AVC, 6000000, 2560, 512, 42, AVCLevel32},
{MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 4096, 512, 30, AVCLevel4},
{MediaFormat.MIMETYPE_VIDEO_AVC, 25000000, 4096, 512, 30, AVCLevel41},
{MediaFormat.MIMETYPE_VIDEO_AVC, 50000000, 4096, 544, 60, AVCLevel42},
{MediaFormat.MIMETYPE_VIDEO_AVC, 60000000, 7360, 752, 26, AVCLevel5},
{MediaFormat.MIMETYPE_VIDEO_AVC, 80000000, 8192, 1152, 26, AVCLevel51},
{MediaFormat.MIMETYPE_VIDEO_AVC, 120000000, 8192, 1152, 56, AVCLevel52},
{MediaFormat.MIMETYPE_VIDEO_AVC, 240000000, 16384, 2160, 30, AVCLevel6},
{MediaFormat.MIMETYPE_VIDEO_AVC, 480000000, 16384, 2160, 60, AVCLevel61},
{MediaFormat.MIMETYPE_VIDEO_AVC, 800000000, 16384, 2160, 120, AVCLevel62},
// Resolutions listed in CDD Section 5.2
{MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 320, 240, 20, AVCLevel12},
{MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 720, 480, 30, AVCLevel3},
{MediaFormat.MIMETYPE_VIDEO_AVC, 4000000, 1280, 720, 30, AVCLevel31},
{MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 1920, 1088, 30, AVCLevel4},
// Clips at Maximum frame rates and bitrates
{MediaFormat.MIMETYPE_VIDEO_AVC, 64000, 128, 96, 30, AVCLevel1},
{MediaFormat.MIMETYPE_VIDEO_AVC, 128000, 128, 96, 30, AVCLevel1b},
{MediaFormat.MIMETYPE_VIDEO_AVC, 192000, 128, 96, 62, AVCLevel11},
{MediaFormat.MIMETYPE_VIDEO_AVC, 384000, 128, 96, 125, AVCLevel12},
{MediaFormat.MIMETYPE_VIDEO_AVC, 768000, 128, 96, 172, AVCLevel13},
{MediaFormat.MIMETYPE_VIDEO_AVC, 2000000, 128, 96, 172, AVCLevel2},
// Following entry covers level 2.1 and 2.2
{MediaFormat.MIMETYPE_VIDEO_AVC, 4000000, 176, 144, 172, AVCLevel21},
{MediaFormat.MIMETYPE_VIDEO_AVC, 10000000, 176, 144, 172, AVCLevel3},
{MediaFormat.MIMETYPE_VIDEO_AVC, 14000000, 352, 288, 172, AVCLevel31},
{MediaFormat.MIMETYPE_VIDEO_AVC, 20000000, 640, 480, 172, AVCLevel32},
{MediaFormat.MIMETYPE_VIDEO_AVC, 20000000, 720, 480, 172, AVCLevel4},
{MediaFormat.MIMETYPE_VIDEO_AVC, 50000000, 720, 480, 172, AVCLevel41},
{MediaFormat.MIMETYPE_VIDEO_AVC, 50000000, 800, 600, 172, AVCLevel42},
{MediaFormat.MIMETYPE_VIDEO_AVC, 135000000, 1024, 768, 172, AVCLevel5},
{MediaFormat.MIMETYPE_VIDEO_AVC, 240000000, 1408, 960, 172, AVCLevel51},
{MediaFormat.MIMETYPE_VIDEO_AVC, 240000000, 2048, 1088, 172, AVCLevel52},
{MediaFormat.MIMETYPE_VIDEO_AVC, 240000000, 2048, 1526, 300, AVCLevel6},
{MediaFormat.MIMETYPE_VIDEO_AVC, 480000000, 3680, 1536, 300, AVCLevel61},
{MediaFormat.MIMETYPE_VIDEO_AVC, 800000000, 4096, 2304, 300, AVCLevel62},
{MediaFormat.MIMETYPE_VIDEO_MPEG2, 4000000, 352, 288, 30, MPEG2LevelLL},
{MediaFormat.MIMETYPE_VIDEO_MPEG2, 15000000, 720, 480, 30, MPEG2LevelML},
{MediaFormat.MIMETYPE_VIDEO_MPEG2, 60000000, 1440, 1088, 30, MPEG2LevelH14},
{MediaFormat.MIMETYPE_VIDEO_MPEG2, 80000000, 1920, 1088, 30, MPEG2LevelHL},
{MediaFormat.MIMETYPE_VIDEO_MPEG2, 80000000, 1920, 1088, 60, MPEG2LevelHP},
// Resolutions listed in https://www.webmproject.org/vp9/levels/
{MediaFormat.MIMETYPE_VIDEO_VP9, 200000, 256, 144, 15, VP9Level1},
{MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 384, 192, 30, VP9Level11},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1000000, 480, 256, 30, VP9Level2},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1500000, 640, 384, 30, VP9Level21},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1600000, 1080, 512, 30, VP9Level3},
{MediaFormat.MIMETYPE_VIDEO_VP9, 4000000, 1280, 768, 30, VP9Level31},
{MediaFormat.MIMETYPE_VIDEO_VP9, 5000000, 2048, 1088, 30, VP9Level4},
{MediaFormat.MIMETYPE_VIDEO_VP9, 16000000, 2048, 1088, 60, VP9Level41},
{MediaFormat.MIMETYPE_VIDEO_VP9, 20000000, 4096, 2176, 30, VP9Level5},
{MediaFormat.MIMETYPE_VIDEO_VP9, 80000000, 4096, 2176, 60, VP9Level51},
{MediaFormat.MIMETYPE_VIDEO_VP9, 160000000, 4096, 2176, 120, VP9Level52},
{MediaFormat.MIMETYPE_VIDEO_VP9, 180000000, 8192, 4352, 30, VP9Level6},
{MediaFormat.MIMETYPE_VIDEO_VP9, 240000000, 8192, 4352, 60, VP9Level61},
{MediaFormat.MIMETYPE_VIDEO_VP9, 480000000, 8192, 4352, 120, VP9Level62},
// The entries below have width being twice that of the widths and height being
// half of the heights in https://www.webmproject.org/vp9/levels/
// Some of the cases where max dimension is limited by specification, width is
// clipped.
{MediaFormat.MIMETYPE_VIDEO_VP9, 200000, 512, 72, 15, VP9Level1},
{MediaFormat.MIMETYPE_VIDEO_VP9, 512000, 768, 96, 30, VP9Level11},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1000000, 960, 128, 30, VP9Level2},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1500000, 1280, 192, 30, VP9Level21},
{MediaFormat.MIMETYPE_VIDEO_VP9, 1600000, 2048, 256, 30, VP9Level3},
{MediaFormat.MIMETYPE_VIDEO_VP9, 4000000, 2560, 384, 30, VP9Level31},
{MediaFormat.MIMETYPE_VIDEO_VP9, 5000000, 4096, 544, 30, VP9Level4},
{MediaFormat.MIMETYPE_VIDEO_VP9, 16000000, 4096, 544, 60, VP9Level41},
{MediaFormat.MIMETYPE_VIDEO_VP9, 20000000, 8192, 1088, 30, VP9Level5},
{MediaFormat.MIMETYPE_VIDEO_VP9, 80000000, 8192, 1088, 60, VP9Level51},
{MediaFormat.MIMETYPE_VIDEO_VP9, 160000000, 8192, 1088, 120, VP9Level52},
{MediaFormat.MIMETYPE_VIDEO_VP9, 180000000, 16384, 2176, 30, VP9Level6},
{MediaFormat.MIMETYPE_VIDEO_VP9, 240000000, 16384, 2176, 60, VP9Level61},
{MediaFormat.MIMETYPE_VIDEO_VP9, 480000000, 16384, 2176, 120, VP9Level62},
// Resolutions listed in CDD Section 5.2
{MediaFormat.MIMETYPE_VIDEO_VP9, 1600000, 720, 480, 30, VP9Level3},
{MediaFormat.MIMETYPE_VIDEO_VP9, 4000000, 1280, 720, 30, VP9Level31},
{MediaFormat.MIMETYPE_VIDEO_VP9, 5000000, 1920, 1080, 30, VP9Level4},
{MediaFormat.MIMETYPE_VIDEO_VP9, 20000000, 3840, 2160, 30, VP9Level5},
// ITU-T H.263
// Table X.2/H.263 − Levels of operation
// This also includes 176x144 which is the CDD
{MediaFormat.MIMETYPE_VIDEO_H263, 64000, 176, 144, 15, H263Level10},
{MediaFormat.MIMETYPE_VIDEO_H263, 128000, 176, 144, 15, H263Level45},
{MediaFormat.MIMETYPE_VIDEO_H263, 128000, 352, 288, 15, H263Level20},
{MediaFormat.MIMETYPE_VIDEO_H263, 384000, 352, 288, 30, H263Level30},
{MediaFormat.MIMETYPE_VIDEO_H263, 2048000, 352, 288, 30, H263Level40},
{MediaFormat.MIMETYPE_VIDEO_H263, 4096000, 352, 240, 60, H263Level50},
{MediaFormat.MIMETYPE_VIDEO_H263, 8192000, 720, 240, 60, H263Level60},
{MediaFormat.MIMETYPE_VIDEO_H263, 16384000, 720, 576, 50, H263Level70},
// From ITU-T H.265
// Table A.11 – Maximum picture rates (pictures per second) at level 1 to 4.1 for
// some example picture sizes when MinCbSizeY is equal to 64
{MediaFormat.MIMETYPE_VIDEO_HEVC, 128000, 176, 144, 15, HEVCMainTierLevel1},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 352, 288, 30, HEVCMainTierLevel2},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1000000, 640, 360, 30, HEVCMainTierLevel21},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1600000, 960, 540, 30, HEVCMainTierLevel3},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 4000000, 1280, 720, 33, HEVCMainTierLevel31},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 6000000, 2048, 1080, 30, HEVCMainTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 16000000, 2048, 1080, 30, HEVCHighTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 2048, 1080, 60, HEVCMainTierLevel41},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 30000000, 2048, 1080, 60, HEVCHighTierLevel41},
// From ITU-T H.265
// Table A.12 – Maximum picture rates (pictures per second) at level 5 to 6.2 for
// some example picture sizes when MinCbSizeY is equal to 64
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 4096, 2160, 30, HEVCMainTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 4096, 2160, 30, HEVCHighTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 40000000, 4096, 2160, 60, HEVCMainTierLevel51},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 80000000, 4096, 2160, 60, HEVCHighTierLevel51},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 4096, 2160, 120, HEVCMainTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 100000000, 4096, 2160, 120, HEVCHighTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 8192, 4320, 30, HEVCMainTierLevel6},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 80000000, 8192, 4320, 30, HEVCHighTierLevel6},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 100000000, 8192, 4320, 60, HEVCMainTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 240000000, 8192, 4320, 60, HEVCHighTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 200000000, 8192, 4320, 120, HEVCMainTierLevel62},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 360000000, 8192, 4320, 120, HEVCHighTierLevel62},
// The entries below have width being twice that of the widths and height being
// half of the heights in Table A.11 and A.12
{MediaFormat.MIMETYPE_VIDEO_HEVC, 128000, 352, 72, 15, HEVCMainTierLevel1},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 512000, 704, 144, 30, HEVCMainTierLevel2},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1000000, 1280, 180, 30, HEVCMainTierLevel21},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1600000, 1920, 270, 30, HEVCMainTierLevel3},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 4000000, 2560, 360, 33, HEVCMainTierLevel31},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 6000000, 4096, 540, 30, HEVCMainTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 16000000, 4096, 540, 30, HEVCHighTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 4096, 540, 60, HEVCMainTierLevel41},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 30000000, 4096, 540, 60, HEVCHighTierLevel41},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 8192, 1080, 30, HEVCMainTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 8192, 1080, 30, HEVCHighTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 40000000, 8192, 1080, 60, HEVCMainTierLevel51},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 80000000, 8192, 1080, 60, HEVCHighTierLevel51},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 8192, 1080, 120, HEVCMainTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 100000000, 8192, 1080, 120, HEVCHighTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 16384, 2160, 30, HEVCMainTierLevel6},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 80000000, 16384, 2160, 30, HEVCHighTierLevel6},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 100000000, 16384, 2160, 60, HEVCMainTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 240000000, 16384, 2160, 60, HEVCHighTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 200000000, 16384, 2160, 120, HEVCMainTierLevel62},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 360000000, 16384, 2160, 120, HEVCHighTierLevel62},
// Resolutions listed in CDD Section 5.2
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1000000, 512, 512, 30, HEVCMainTierLevel3},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1600000, 720, 480, 30, HEVCMainTierLevel3},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 4000000, 1280, 720, 30, HEVCMainTierLevel31},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 5000000, 1920, 1080, 30, HEVCMainTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 3840, 2160, 30, HEVCMainTierLevel5},
// Clips at Maximum frame rates and bitrates
{MediaFormat.MIMETYPE_VIDEO_HEVC, 128000, 128, 96, 33, HEVCMainTierLevel1},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 1500000, 128, 96, 225, HEVCMainTierLevel2},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 3000000, 128, 96, 300, HEVCMainTierLevel21},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 6000000, 176, 144, 300, HEVCMainTierLevel3},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 10000000, 352, 240, 300, HEVCMainTierLevel31},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 12000000, 352, 576, 300, HEVCMainTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 30000000, 352, 576, 300, HEVCHighTierLevel4},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 20000000, 720, 576, 300, HEVCMainTierLevel41},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 50000000, 720, 576, 300, HEVCHighTierLevel41},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 25000000, 1024, 768, 300, HEVCMainTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 100000000, 1024, 768, 300, HEVCHighTierLevel5},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 40000000, 1408, 1152, 300, HEVCMainTierLevel51},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 160000000, 1408, 1152, 300, HEVCHighTierLevel51},
// Following two entries cover Level 5.2 and Level 6.0
{MediaFormat.MIMETYPE_VIDEO_HEVC, 60000000, 2048, 1526, 300, HEVCMainTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 240000000, 2048, 1526, 300, HEVCHighTierLevel52},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 120000000, 3672, 1536, 300, HEVCMainTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 480000000, 3672, 1536, 300, HEVCHighTierLevel61},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 240000000, 4096, 3072, 300, HEVCMainTierLevel62},
{MediaFormat.MIMETYPE_VIDEO_HEVC, 800000000, 4096, 3072, 300, HEVCHighTierLevel62},
// Resolutions listed in https://aomedia.org/av1/specification/annex-a/#levels
{MediaFormat.MIMETYPE_VIDEO_AV1, 1500000, 426, 240, 30, AV1Level2},
{MediaFormat.MIMETYPE_VIDEO_AV1, 3000000, 640, 360, 30, AV1Level21},
{MediaFormat.MIMETYPE_VIDEO_AV1, 6000000, 854, 480, 30, AV1Level3},
{MediaFormat.MIMETYPE_VIDEO_AV1, 10000000, 1280, 720, 30, AV1Level31},
{MediaFormat.MIMETYPE_VIDEO_AV1, 12000000, 1920, 1080, 30, AV1Level4},
{MediaFormat.MIMETYPE_VIDEO_AV1, 20000000, 1920, 1080, 60, AV1Level41},
{MediaFormat.MIMETYPE_VIDEO_AV1, 30000000, 3840, 2160, 30, AV1Level5},
{MediaFormat.MIMETYPE_VIDEO_AV1, 40000000, 3840, 2160, 60, AV1Level51},
{MediaFormat.MIMETYPE_VIDEO_AV1, 60000000, 3840, 2160, 120, AV1Level52},
{MediaFormat.MIMETYPE_VIDEO_AV1, 60000000, 7680, 4320, 30, AV1Level6},
{MediaFormat.MIMETYPE_VIDEO_AV1, 100000000, 7680, 4320, 60, AV1Level61},
{MediaFormat.MIMETYPE_VIDEO_AV1, 160000000, 7680, 4320, 120, AV1Level62},
// The entries below have width being twice that of the widths and height being
// half of the heights in https://aomedia.org/av1/specification/annex-a/#levels
{MediaFormat.MIMETYPE_VIDEO_AV1, 1500000, 852, 120, 30, AV1Level2},
{MediaFormat.MIMETYPE_VIDEO_AV1, 3000000, 1280, 180, 30, AV1Level21},
{MediaFormat.MIMETYPE_VIDEO_AV1, 6000000, 1708, 240, 30, AV1Level3},
{MediaFormat.MIMETYPE_VIDEO_AV1, 10000000, 2560, 360, 30, AV1Level31},
{MediaFormat.MIMETYPE_VIDEO_AV1, 12000000, 3840, 540, 30, AV1Level4},
{MediaFormat.MIMETYPE_VIDEO_AV1, 20000000, 3840, 540, 60, AV1Level41},
{MediaFormat.MIMETYPE_VIDEO_AV1, 30000000, 7680, 1080, 30, AV1Level5},
{MediaFormat.MIMETYPE_VIDEO_AV1, 40000000, 7680, 1080, 60, AV1Level51},
{MediaFormat.MIMETYPE_VIDEO_AV1, 60000000, 7680, 1080, 120, AV1Level52},
{MediaFormat.MIMETYPE_VIDEO_AV1, 60000000, 15360, 2160, 30, AV1Level6},
{MediaFormat.MIMETYPE_VIDEO_AV1, 100000000, 15360, 2160, 60, AV1Level61},
{MediaFormat.MIMETYPE_VIDEO_AV1, 160000000, 15360, 2160, 120, AV1Level62},
// Resolutions listed in CDD Section 5.2
{MediaFormat.MIMETYPE_VIDEO_AV1, 5000000, 720, 480, 30, AV1Level3},
{MediaFormat.MIMETYPE_VIDEO_AV1, 8000000, 1280, 720, 30, AV1Level31},
{MediaFormat.MIMETYPE_VIDEO_AV1, 16000000, 1920, 1080, 30, AV1Level4},
{MediaFormat.MIMETYPE_VIDEO_AV1, 50000000, 3840, 2160, 30, AV1Level5},
};
final List argsList = new ArrayList<>();
for (Object[] arg : exhaustiveArgsList) {
final String mediaType = (String) arg[0];
argsList.addAll(prepareTestArgs(arg,
Objects.requireNonNull(PROFILE_SDR_MAP.get(mediaType)),
COLOR_FormatYUV420Flexible));
// P010 support was added in Android T, hence limit the following tests to Android
// T and above
if (IS_AT_LEAST_T && PROFILE_HLG_MAP.get(mediaType) != null) {
argsList.addAll(prepareTestArgs(arg,
Objects.requireNonNull(PROFILE_HLG_MAP.get(mediaType)),
COLOR_FormatYUVP010));
}
}
final Object[][] mpeg4SimpleProfileArgsList = new Object[][]{
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 64000, 176, 144, 15, MPEG4Level0},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 128000, 176, 144, 15, MPEG4Level0b},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 64000, 128, 96, 30, MPEG4Level1},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 128000, 352, 288, 15, MPEG4Level2},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 384000, 352, 288, 30, MPEG4Level3},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 4000000, 640, 480, 30, MPEG4Level4a},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 8000000, 720, 576, 24, MPEG4Level5},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 12000000, 1280, 720, 30, MPEG4Level6},
};
for (Object[] arg : mpeg4SimpleProfileArgsList) {
argsList.addAll(prepareTestArgs(arg, new int[]{MPEG4ProfileSimple},
COLOR_FormatYUV420Flexible));
}
final Object[][] mpeg4AdvSimpleProfileArgsList = new Object[][]{
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 128000, 176, 144, 30, MPEG4Level1},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 384000, 352, 288, 15, MPEG4Level2},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 768000, 352, 288, 30, MPEG4Level3},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 1500000, 352, 288, 30, MPEG4Level3b},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 3000000, 704, 576, 15, MPEG4Level4},
{MediaFormat.MIMETYPE_VIDEO_MPEG4, 8000000, 720, 576, 30, MPEG4Level5},
};
for (Object[] arg : mpeg4AdvSimpleProfileArgsList) {
argsList.addAll(prepareTestArgs(arg, new int[]{MPEG4ProfileAdvancedSimple},
COLOR_FormatYUV420Flexible));
}
return prepareParamList(argsList, isEncoder, needAudio, needVideo, false);
}
static {
// Following lists profiles, level, maxWidth and maxHeight mandated by the CDD.
// CodecMediaType, profiles, level, maxWidth, maxHeight
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC,
new CddRequirements(new int[]{AACObjectLC, AACObjectHE, AACObjectELD}));
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263,
new CddRequirements(new int[]{H263ProfileBaseline}, H263Level45));
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC,
new CddRequirements(new int[]{AVCProfileBaseline}, AVCLevel3));
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC,
new CddRequirements(new int[]{HEVCProfileMain}, HEVCMainTierLevel3, 512, 512));
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9,
new CddRequirements(new int[]{VP9Profile0}, VP9Level3));
if (IS_AT_LEAST_U) {
CDD_REQUIREMENTS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1,
new CddRequirements(new int[]{AV1ProfileMain8, AV1ProfileMain10}));
}
}
void checkIfTrackFormatIsOk(MediaFormat trackFormat) {
assertEquals("Input media type and extracted media type are not identical " + mTestEnv
+ mTestConfig, mActiveEncCfg.mMediaType,
trackFormat.getString(MediaFormat.KEY_MIME));
if (mIsVideo) {
assertEquals("Input width and extracted width are not same " + mTestEnv + mTestConfig,
mActiveEncCfg.mWidth, getWidth(trackFormat));
assertEquals("Input height and extracted height are not same " + mTestEnv + mTestConfig,
mActiveEncCfg.mHeight, getHeight(trackFormat));
} else {
int expSampleRate = mActiveEncCfg.mProfile != AACObjectHE ? mActiveEncCfg.mSampleRate
: mActiveEncCfg.mSampleRate / 2;
int expChCount = mActiveEncCfg.mProfile != AACObjectHE_PS ? mActiveEncCfg.mChannelCount
: mActiveEncCfg.mChannelCount / 2;
assertEquals("Input sample rate and extracted sample rate are not same " + mTestEnv
+ mTestConfig, expSampleRate,
trackFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE));
assertEquals("Input channe count and extracted channel count are not same " + mTestEnv
+ mTestConfig, expChCount,
trackFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
}
}
private boolean shallSupportProfileAndLevel(EncoderConfigParams cfg) {
CddRequirements requirement =
Objects.requireNonNull(CDD_REQUIREMENTS_MAP.get(cfg.mMediaType));
int[] profileCdd = requirement.getProfiles();
int levelCdd = requirement.getLevel();
int widthCdd = requirement.getWidth();
int heightCdd = requirement.getHeight();
// Check if CDD doesn't require support beyond certain resolutions.
if (widthCdd != -1 && mActiveEncCfg.mWidth > widthCdd) {
return false;
}
if (heightCdd != -1 && mActiveEncCfg.mHeight > heightCdd) {
return false;
}
for (int cddProfile : profileCdd) {
if (cfg.mProfile == cddProfile) {
if (!cfg.mIsAudio) {
if (cfg.mLevel <= levelCdd) {
if (cfg.mMediaType.equalsIgnoreCase(MediaFormat.MIMETYPE_VIDEO_H263)
&& cfg.mLevel != MediaCodecInfo.CodecProfileLevel.H263Level45
&& cfg.mLevel > MediaCodecInfo.CodecProfileLevel.H263Level10) {
continue;
}
} else {
continue;
}
}
return true;
}
}
return false;
}
/**
* Check description of class {@link EncoderProfileLevelTest}
*/
@CddTest(requirements = {"2.2.2/5.1/H-0-3", "2.2.2/5.1/H-0-4", "2.2.2/5.1/H-0-5", "5/C-0-3",
"5.2.1/C-1-1", "5.2.2/C-1-1", "5.2.4/C-1-2", "5.2.5/C-1-1", "5.2.6/C-1-1"})
@ApiTest(apis = {"android.media.MediaFormat#KEY_PROFILE",
"android.media.MediaFormat#KEY_AAC_PROFILE",
"android.media.MediaFormat#KEY_LEVEL"})
@Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
public void testValidateProfileLevel() throws IOException, InterruptedException {
int minLevel = getMinLevel(mMediaType, mEncCfgParams[0].mWidth, mEncCfgParams[0].mHeight,
mEncCfgParams[0].mFrameRate, mEncCfgParams[0].mBitRate, mEncCfgParams[0].mProfile);
boolean validateMinLevel = true;
// MPEG4 and AV1 have independent checks on width and height and because of that,
// level limits that are passed to landscape resolution in the test table, do not
// match the minimum level computed later. For such cases, disable the minLevel check.
if ((mMediaType.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4)
|| mMediaType.equals(MediaFormat.MIMETYPE_VIDEO_AV1))
&& (mEncCfgParams[0].mWidth < mEncCfgParams[0].mHeight)) {
validateMinLevel = false;
}
if (validateMinLevel) {
assertEquals("Calculated minimum acceptable level does not match the entry in test "
+ "table " + mTestConfig, mEncCfgParams[0].mLevel, minLevel);
}
if (mIsVideo && mEncCfgParams[0].mInputBitDepth != 8) {
Assume.assumeTrue(mCodecName + " doesn't support " + colorFormatToString(
mEncCfgParams[0].mColorFormat, mEncCfgParams[0].mInputBitDepth),
hasSupportForColorFormat(mCodecName, mMediaType,
mEncCfgParams[0].mColorFormat));
}
boolean cddSupportedMediaType = CDD_REQUIREMENTS_MAP.get(mMediaType) != null;
{
mActiveRawRes = EncoderInput.getRawResource(mEncCfgParams[0]);
assertNotNull("no raw resource found for testing config : "
+ mEncCfgParams[0] + mTestConfig + mTestEnv, mActiveRawRes);
setUpSource(mActiveRawRes.mFileName);
mSaveToMem = true;
mMuxOutput = true;
mOutputBuff = new OutputManager();
mCodec = MediaCodec.createByCodecName(mCodecName);
MediaCodecInfo.CodecCapabilities codecCapabilities =
mCodec.getCodecInfo().getCapabilitiesForType(mMediaType);
int configsTested = 0;
for (EncoderConfigParams cfg : mEncCfgParams) {
mActiveEncCfg = cfg;
MediaFormat format = cfg.getFormat();
if (!codecCapabilities.isFormatSupported(format)) {
if (cddSupportedMediaType) {
if (shallSupportProfileAndLevel(cfg)) {
ArrayList formats = new ArrayList<>();
formats.add(format);
assertFalse("No components present on the device supports cdd "
+ "required encode format:- " + format + mTestConfig + mTestEnv,
selectCodecs(mMediaType, formats, null, true).isEmpty());
}
Log.d(LOG_TAG, mCodecName + " doesn't support format: " + format);
}
continue;
}
mOutputBuff.reset();
configureCodec(format, false, true, true);
mCodec.start();
doWork(5);
queueEOS();
waitForAllOutputs();
mCodec.reset();
MediaFormat trackFormat = validateProfileAndLevel();
deleteMuxedFile();
// validate extracted format for mandatory keys
if (trackFormat != null) checkIfTrackFormatIsOk(trackFormat);
// Verify if device has an equivalent decoder for the current format
ArrayList formatList = new ArrayList<>();
if (mProfileLevel != null && mProfileLevel.second != -1
&& cfg.mLevel != mProfileLevel.second) {
format.setInteger(MediaFormat.KEY_LEVEL, mProfileLevel.second);
}
formatList.add(format);
assertTrue("Device advertises support for encoding " + format + " but cannot"
+ " decode it. \n" + mTestConfig + mTestEnv,
selectCodecs(mMediaType, formatList, null, false).size() > 0);
configsTested++;
}
mCodec.release();
Assume.assumeTrue("skipping test, formats not supported by component",
configsTested > 0);
}
}
}