summaryrefslogtreecommitdiff
path: root/tests/media/src/android/mediav2/cts/CodecInfoTest.java
blob: e42835e2c9f05ffafadb2dd4a28088b324fe5ee0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * Copyright (C) 2022 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 android.hardware.display.DisplayManager;
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.os.Build;
import android.util.Log;
import android.view.Display;

import androidx.test.filters.SmallTest;

import com.android.compatibility.common.util.ApiTest;

import org.junit.Assert;
import org.junit.Assume;
import org.junit.Ignore;
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.List;
import java.util.stream.IntStream;

import static android.media.MediaCodecInfo.CodecCapabilities.*;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static android.mediav2.cts.CodecTestBase.*;
import static android.view.Display.HdrCapabilities.*;
import static org.junit.Assert.*;

@SmallTest
@RunWith(Parameterized.class)
public class CodecInfoTest {
    private static final String LOG_TAG = CodecInfoTest.class.getSimpleName();
    private static final int[] DISPLAY_HDR_TYPES;

    public String mMediaType;
    public String mCodecName;
    public MediaCodecInfo mCodecInfo;

    static {
        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
        DISPLAY_HDR_TYPES =
                displayManager.getDisplay(Display.DEFAULT_DISPLAY).getHdrCapabilities()
                        .getSupportedHdrTypes();
    }

    public CodecInfoTest(String mediaType, String codecName, MediaCodecInfo codecInfo) {
        mMediaType = mediaType;
        mCodecName = codecName;
        mCodecInfo = codecInfo;
    }

    @Parameterized.Parameters(name = "{index}({0}_{1})")
    public static Collection<Object[]> input() {
        final List<Object[]> argsList = new ArrayList<>();
        MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
        for (MediaCodecInfo codecInfo : codecList.getCodecInfos()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
                continue;
            }
            if (CodecTestBase.codecPrefix != null &&
                    !codecInfo.getName().startsWith(CodecTestBase.codecPrefix)) {
                continue;
            }
            String[] types = codecInfo.getSupportedTypes();
            for (String type : types) {
                argsList.add(new Object[]{type, codecInfo.getName(), codecInfo});
            }
        }
        return argsList;
    }

    /**
     * Tests if the devices on T or later, if decoder for a mediaType supports HDR profiles then
     * it should be capable of displaying the same. Since HLG profiles can't be distinguished from
     * default 10-bit profiles, those are excluded from this test.
     */
    @Test
    // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
    // display capabilities at native level, till then limit the test to vendor codecs
    @NonMediaMainlineTest
    @ApiTest(apis = "MediaCodecInfo.CodecCapabilities#profileLevels")
    public void testHDRDisplayCapabilities() {
        Assume.assumeTrue("Test needs Android 13", IS_AT_LEAST_T);
        Assume.assumeTrue("Test needs VNDK Android 13", VNDK_IS_AT_LEAST_T);
        Assume.assumeTrue("Test needs First SDK Android 13", FIRST_SDK_IS_AT_LEAST_T);
        Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
        // TODO (b/228237404) Remove the following once there is a reliable way to query HDR
        // display capabilities at native level, till then limit the test to vendor codecs
        Assume.assumeTrue("Test is restricted to vendor codecs", isVendorCodec(mCodecName));

        int[] Hdr10Profiles = mProfileHdr10Map.get(mMediaType);
        int[] Hdr10PlusProfiles = mProfileHdr10PlusMap.get(mMediaType);
        Assume.assumeTrue("Test is applicable for codecs with HDR10/HDR10+ profiles",
                Hdr10Profiles != null || Hdr10PlusProfiles != null);

        MediaCodecInfo.CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mMediaType);

        for (CodecProfileLevel pl : caps.profileLevels) {
            boolean isHdr10Profile = Hdr10Profiles != null &&
                    IntStream.of(Hdr10Profiles).anyMatch(x -> x == pl.profile);
            boolean isHdr10PlusProfile = Hdr10PlusProfiles != null &&
                    IntStream.of(Hdr10PlusProfiles).anyMatch(x -> x == pl.profile);
            // TODO (b/228237404) Once there is a way to query support for HDR10/HDR10+ display at
            // native level, separate the following to independent checks for HDR10 and HDR10+
            if (isHdr10Profile || isHdr10PlusProfile) {
                assertTrue(mCodecInfo.getName() + " Advertises support for HDR10/HDR10+ profile " +
                        pl.profile + " without any HDR display", DISPLAY_HDR_TYPES.length > 0);
            }
        }
    }

    /**
     * Tests if the device under test has support for necessary color formats.
     * The test only checks if the decoder/encoder is advertising the required color format. It
     * doesn't validate its support.
     */
    @Test
    public void testColorFormatSupport() throws IOException {
        Assume.assumeTrue("Test is applicable for video codecs", mMediaType.startsWith("video/"));
        MediaCodecInfo.CodecCapabilities caps = mCodecInfo.getCapabilitiesForType(mMediaType);
        assertFalse(mCodecInfo.getName() + " does not support COLOR_FormatYUV420Flexible",
                IntStream.of(caps.colorFormats)
                        .noneMatch(x -> x == COLOR_FormatYUV420Flexible));

        // Encoders that support FEATURE_HdrEditing, must support P010 and ABGR2101010
        // color format and at least one HDR profile
        boolean hdrEditingSupported = caps.isFeatureSupported(FEATURE_HdrEditing);
        if (mCodecInfo.isEncoder() && hdrEditingSupported) {
            boolean abgr2101010Supported =
                    IntStream.of(caps.colorFormats)
                            .anyMatch(x -> x == COLOR_Format32bitABGR2101010);
            boolean p010Supported =
                    IntStream.of(caps.colorFormats).anyMatch(x -> x == COLOR_FormatYUVP010);
            assertTrue(mCodecName + " supports FEATURE_HdrEditing, but does not support " +
                    "COLOR_FormatABGR2101010 and COLOR_FormatYUVP010 color formats.",
                    abgr2101010Supported && p010Supported);
            assertTrue(mCodecName + " supports FEATURE_HdrEditing, but does not support any HDR " +
                    "profiles.", CodecTestBase.doesCodecSupportHDRProfile(mCodecName, mMediaType));
        }

        // COLOR_FormatSurface support is an existing requirement, but we did not
        // test for it before T.  We can not retroactively apply the higher standard to
        // devices that are already certified, so only test on devices luanching with T or later.
        if (FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T) {
            assertFalse(mCodecInfo.getName() + " does not support COLOR_FormatSurface",
                    IntStream.of(caps.colorFormats)
                            .noneMatch(x -> x == COLOR_FormatSurface));
        }

        // For devices launching with Android T, if a codec supports an HDR profile and device
        // supports HDR display, it must advertise P010 support
        int[] HdrProfileArray = mProfileHdrMap.get(mMediaType);
        if (FIRST_SDK_IS_AT_LEAST_T && VNDK_IS_AT_LEAST_T
                        && HdrProfileArray != null && DISPLAY_HDR_TYPES.length > 0) {
            for (CodecProfileLevel pl : caps.profileLevels) {
                if (IntStream.of(HdrProfileArray).anyMatch(x -> x == pl.profile)) {
                    assertFalse(mCodecInfo.getName() + " supports HDR profile " + pl.profile + "," +
                                    " but does not support COLOR_FormatYUVP010",
                            IntStream.of(caps.colorFormats)
                                    .noneMatch(x -> x == COLOR_FormatYUVP010));
                }
            }
        }
    }

    /**
     * Tests if a device supports encoding for a given mediaType, then it must support decoding it
     */
    @Test
    public void testDecoderAvailability() {
        Assume.assumeTrue("Test is applicable only for encoders", mCodecInfo.isEncoder());
        Assume.assumeTrue("Test is applicable for video/audio codecs",
                mMediaType.startsWith("video/") || mMediaType.startsWith("audio/"));
        if (selectCodecs(mMediaType, null, null, true).size() > 0) {
            assertTrue("Device advertises support for encoding " + mMediaType +
                            ", but not decoding it",
                    selectCodecs(mMediaType, null, null, false).size() > 0);
        }
    }
}