• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.mediav2.common.cts;
18 
19 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_HdrEditing;
20 import static android.media.MediaCodecInfo.CodecCapabilities.FEATURE_HlgEditing;
21 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
22 
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 
29 import android.app.ActivityManager;
30 import android.content.Context;
31 import android.hardware.camera2.CameraAccessException;
32 import android.hardware.camera2.CameraCharacteristics;
33 import android.hardware.camera2.CameraManager;
34 import android.hardware.camera2.CameraMetadata;
35 import android.hardware.camera2.params.DynamicRangeProfiles;
36 import android.hardware.display.DisplayManager;
37 import android.media.MediaCodec;
38 import android.media.MediaCodecInfo;
39 import android.media.MediaCodecInfo.CodecCapabilities;
40 import android.media.MediaCodecInfo.CodecProfileLevel;
41 import android.media.MediaCodecList;
42 import android.media.MediaFormat;
43 import android.media.cts.TestUtils;
44 import android.os.Build;
45 import android.os.Bundle;
46 import android.os.PersistableBundle;
47 import android.os.SystemProperties;
48 import android.platform.test.flag.junit.CheckFlagsRule;
49 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
50 import android.util.Log;
51 import android.util.Pair;
52 import android.view.Display;
53 import android.view.Surface;
54 
55 import androidx.test.platform.app.InstrumentationRegistry;
56 
57 import com.android.compatibility.common.util.ApiLevelUtil;
58 import com.android.compatibility.common.util.MediaUtils;
59 
60 import org.junit.After;
61 import org.junit.Assume;
62 import org.junit.Before;
63 import org.junit.Rule;
64 import org.junit.rules.TestName;
65 
66 import java.io.IOException;
67 import java.nio.ByteBuffer;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.Comparator;
71 import java.util.HashMap;
72 import java.util.HashSet;
73 import java.util.List;
74 import java.util.Locale;
75 import java.util.Map;
76 import java.util.Set;
77 import java.util.function.Function;
78 import java.util.regex.Matcher;
79 import java.util.regex.Pattern;
80 import java.util.stream.IntStream;
81 import java.util.stream.Stream;
82 
83 /**
84  * This class comprises of routines that are generic to media codec component trying and testing.
85  * <p>
86  * A media codec component essentially processes input data to generate output data. The
87  * component uses a set of input and output buffers. At a simplistic level, the client requests
88  * (or receive) an empty input buffer, fills it up with data and sends it to the codec for
89  * processing. The codec uses up the data and transforms it into one of its empty output
90  * buffers. Finally, the client asks (or receive) a filled output buffer, consume its contents and
91  * release it back to the codec.
92  * <p>
93  * The type of data that a component receives and sends is dependent on the component. For
94  * instance video encoders expect raw yuv/rgb data and send compressed data. A video decoder
95  * receives compressed access-unit and sends reconstructed yuv. But the processes surrounding
96  * this enqueue and dequeue remain common to all components. Operations like configure, requesting
97  * the component for an empty input buffer, feeding the component a filled input buffer,
98  * requesting the component for an output buffer, releasing the processed output buffer, Sending
99  * state transition commands, waiting on component to send all outputs, closing the component and
100  * releasing the resources, ... remain more or less identical to all components. The routines
101  * that manage these generic processes are maintained by this class. Not only the methods that
102  * are responsible for component trying but also methods that test its functionality are covered
103  * here. A video component is expected to give same number of outputs as inputs. The output
104  * buffer timestamps of an audio component or a decoder component is expected to be strictly
105  * increasing. The routines that enforce these generic rules of all components at all times are
106  * part of this class. Besides these, mediaType specific constants, helper utilities to test
107  * specific components or mediaTypes are covered here.
108  * <p>
109  * enqueueInput and dequeueOutput are routines responsible for filling the input buffer and
110  * handing the received output buffer respectively. These shall be component specific, hence they
111  * are abstract methods. Any client intending to use this class shall implement these methods
112  * basing on the component under test.
113  * <p>
114  * In simple terms, the CodecTestBase is a wrapper class comprising generic routines for
115  * component trying and testing.
116  */
117 public abstract class CodecTestBase {
118     public static final boolean IS_Q = ApiLevelUtil.getApiLevel() == Build.VERSION_CODES.Q;
119     public static final boolean IS_AT_LEAST_R = ApiLevelUtil.isAtLeast(Build.VERSION_CODES.R);
120     public static final boolean IS_AT_LEAST_T =
121             ApiLevelUtil.isAtLeast(Build.VERSION_CODES.TIRAMISU);
122     public static final boolean IS_AT_LEAST_U =
123             ApiLevelUtil.isAtLeast(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
124     public static final boolean IS_BEFORE_U = !IS_AT_LEAST_U;
125     //TODO(b/248315681) Remove codenameEquals() check once devices return correct version for V
126     public static final boolean IS_AT_LEAST_V =
127             ApiLevelUtil.isAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
128                 || ApiLevelUtil.codenameEquals("VanillaIceCream");
129     //TODO(b/248315681) Change to a proper condition
130     public static final boolean IS_AT_LEAST_B =
131             ApiLevelUtil.isAfter(Build.VERSION_CODES.VANILLA_ICE_CREAM)
132                 || ApiLevelUtil.codenameEquals("Baklava");
133     public static final boolean FIRST_SDK_IS_AT_LEAST_T =
134             ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU);
135     public static final boolean FIRST_SDK_IS_AT_LEAST_V =
136             ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM);
137     public static final boolean VNDK_IS_AT_LEAST_T =
138             SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT)
139                     >= Build.VERSION_CODES.TIRAMISU;
140     public static final boolean VNDK_IS_AT_LEAST_U =
141             SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT)
142                     >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
143     public static final boolean VNDK_IS_BEFORE_U =
144             SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT)
145                     < Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
146     public static final boolean VNDK_IS_AT_MOST_U =
147             SystemProperties.getInt("ro.vndk.version", Build.VERSION_CODES.CUR_DEVELOPMENT)
148                     <= Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
149     public static final boolean BOARD_SDK_IS_AT_LEAST_T =
150             SystemProperties.getInt("ro.board.api_level", Build.VERSION_CODES.CUR_DEVELOPMENT)
151                     >= Build.VERSION_CODES.TIRAMISU;
152     public static final boolean BOARD_SDK_IS_BEFORE_U =
153             SystemProperties.getInt("ro.board.api_level", Build.VERSION_CODES.CUR_DEVELOPMENT)
154                     < Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
155     public static final int ANDROID_VENDOR_API_202404 = 202404;
156     public static final int ANDROID_VENDOR_API_202504 = 202504;
157     // ro.vendor.api_level is guaranteed to be set on devices running in Android T and above,
158     // so using a default of 0 when not defined is safe to detect devices launching with 202404.
159     // These tests run on older versions where ro.vendor.api_level is not defined. So this
160     // needs to use default of 0 to ensure that this does't get treated as >= 202404 on those
161     // builds.
162     public static final boolean BOARD_FIRST_SDK_IS_AT_LEAST_202404 =
163             SystemProperties.getInt("ro.vendor.api_level", 0) >= ANDROID_VENDOR_API_202404;
164     public static final boolean BOARD_FIRST_SDK_IS_AT_LEAST_202504 =
165             SystemProperties.getInt("ro.vendor.api_level", 0) >= ANDROID_VENDOR_API_202504;
166     public static final boolean IS_HDR_EDITING_SUPPORTED;
167     public static final boolean IS_HLG_EDITING_SUPPORTED;
168     public static final boolean IS_HDR_CAPTURE_SUPPORTED;
169     private static final String LOG_TAG = CodecTestBase.class.getSimpleName();
170     // Reduce the max concurrent codec instances on Low Ram devices to 8 to avoid getting into
171     // low memory issues.
172     private static final int LOW_RAM_DEVICE_MAX_INSTANCES = 8;
173 
174     public static final ArrayList<String> HDR_INFO_IN_BITSTREAM_CODECS = new ArrayList<>();
175     public static final String HDR_STATIC_INFO =
176             "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
177     public static final String HDR_STATIC_ALTERNATE_INFO =
178             "00 d0 84 80 3e c2 33 c4 86 4c 1d b8 0b 13 3d 42 40 e8 03 32 00 00 00 00 00";
179     public static final String HDR_STATIC_INCORRECT_INFO =
180             "00 d0 84 80 3e c2 33 c4 86 10 27 d0 07 13 3d 42 40 a0 0f 32 00 10 27 df 0d";
181     public static final String CODEC_PREFIX_KEY = "codec-prefix";
182     public static final String CODEC_FILTER_KEY = "codec-filter";
183     public static final String MEDIA_TYPE_PREFIX_KEY = "media-type-prefix";
184     public static final String MEDIA_TYPE_SEL_KEY = "media-type-sel";
185     public static final Map<String, String> CODEC_SEL_KEY_MEDIA_TYPE_MAP = new HashMap<>();
186     public static final Map<String, String> DEFAULT_ENCODERS = new HashMap<>();
187     public static final Map<String, String> DEFAULT_DECODERS = new HashMap<>();
188     public static final HashMap<String, int[]> PROFILE_MAP = new HashMap<>();
189     public static final HashMap<String, int[]> PROFILE_SDR_MAP = new HashMap<>();
190     public static final HashMap<String, int[]> PROFILE_HLG_MAP = new HashMap<>();
191     public static final HashMap<String, int[]> PROFILE_HDR10_MAP = new HashMap<>();
192     public static final HashMap<String, int[]> PROFILE_HDR10_PLUS_MAP = new HashMap<>();
193     public static final HashMap<String, int[]> PROFILE_HDR_MAP = new HashMap<>();
194     public static final boolean ENABLE_LOGS = false;
195     public static final int PER_TEST_TIMEOUT_LARGE_TEST_MS = 300000;
196     public static final int PER_TEST_TIMEOUT_SMALL_TEST_MS = 60000;
197     public static final int UNSPECIFIED = 0;
198     // Maintain Timeouts in sync with their counterpart in NativeMediaCommon.h
199     // block at most 5ms while looking for io buffers
200     public static final long Q_DEQ_TIMEOUT_US = 5000;
201     // max poll counter before test aborts and returns error
202     public static final int RETRY_LIMIT = 100;
203     public static final String INVALID_CODEC = "unknown.codec_";
204     public static final String MIMETYPE_VIDEO_VC1 = "video/wvc1";
205     public static final String MIMETYPE_VIDEO_WMV = "video/x-ms-wmv";
206     static final int[] MPEG2_PROFILES = new int[]{MPEG2ProfileSimple, MPEG2ProfileMain,
207             MPEG2Profile422, MPEG2ProfileSNR, MPEG2ProfileSpatial, MPEG2ProfileHigh};
208     static final int[] MPEG4_PROFILES = new int[]{MPEG4ProfileSimple, MPEG4ProfileSimpleScalable,
209             MPEG4ProfileCore, MPEG4ProfileMain, MPEG4ProfileNbit, MPEG4ProfileScalableTexture,
210             MPEG4ProfileSimpleFace, MPEG4ProfileSimpleFBA, MPEG4ProfileBasicAnimated,
211             MPEG4ProfileHybrid, MPEG4ProfileAdvancedRealTime, MPEG4ProfileCoreScalable,
212             MPEG4ProfileAdvancedCoding, MPEG4ProfileAdvancedCore, MPEG4ProfileAdvancedScalable,
213             MPEG4ProfileAdvancedSimple};
214     static final int[] H263_PROFILES = new int[]{H263ProfileBaseline, H263ProfileH320Coding,
215             H263ProfileBackwardCompatible, H263ProfileISWV2, H263ProfileISWV3,
216             H263ProfileHighCompression, H263ProfileInternet, H263ProfileInterlace,
217             H263ProfileHighLatency};
218     static final int[] VP8_PROFILES = new int[]{VP8ProfileMain};
219     static final int[] AVC_SDR_PROFILES = new int[]{AVCProfileBaseline, AVCProfileMain,
220             AVCProfileExtended, AVCProfileHigh, AVCProfileConstrainedBaseline,
221             AVCProfileConstrainedHigh};
222     static final int[] AVC_HLG_PROFILES = new int[]{AVCProfileHigh10};
223     static final int[] AVC_HDR_PROFILES = AVC_HLG_PROFILES;
224     static final int[] AVC_PROFILES = combine(AVC_SDR_PROFILES, AVC_HDR_PROFILES);
225     static final int[] VP9_SDR_PROFILES = new int[]{VP9Profile0};
226     static final int[] VP9_HLG_PROFILES = new int[]{VP9Profile2};
227     static final int[] VP9_HDR10_PROFILES = new int[]{VP9Profile2HDR};
228     static final int[] VP9_HDR10_PLUS_PROFILES = new int[]{VP9Profile2HDR10Plus};
229     static final int[] VP9_HDR_PROFILES =
230             combine(VP9_HLG_PROFILES, combine(VP9_HDR10_PROFILES, VP9_HDR10_PLUS_PROFILES));
231     static final int[] VP9_PROFILES = combine(VP9_SDR_PROFILES, VP9_HDR_PROFILES);
232     static final int[] HEVC_SDR_PROFILES = new int[]{HEVCProfileMain};
233     static final int[] HEVC_HLG_PROFILES = new int[]{HEVCProfileMain10};
234     static final int[] HEVC_HDR10_PROFILES = new int[]{HEVCProfileMain10HDR10};
235     static final int[] HEVC_HDR10_PLUS_PROFILES = new int[]{HEVCProfileMain10HDR10Plus};
236     static final int[] HEVC_HDR_PROFILES =
237             combine(HEVC_HLG_PROFILES, combine(HEVC_HDR10_PROFILES, HEVC_HDR10_PLUS_PROFILES));
238     static final int[] HEVC_PROFILES = combine(HEVC_SDR_PROFILES, HEVC_HDR_PROFILES);
239     static final int[] AV1_SDR_PROFILES = new int[]{AV1ProfileMain8};
240     static final int[] AV1_HLG_PROFILES = new int[]{AV1ProfileMain10};
241     static final int[] APV_HLG_PROFILES = new int[]{APVProfile422_10};
242     static final int[] AV1_HDR10_PROFILES = new int[]{AV1ProfileMain10HDR10};
243     static final int[] APV_HDR10_PROFILES = new int[]{APVProfile422_10HDR10};
244     static final int[] AV1_HDR10_PLUS_PROFILES = new int[]{AV1ProfileMain10HDR10Plus};
245     static final int[] APV_HDR10_PLUS_PROFILES = new int[]{APVProfile422_10HDR10Plus};
246     static final int[] AV1_HDR_PROFILES =
247             combine(AV1_HLG_PROFILES, combine(AV1_HDR10_PROFILES, AV1_HDR10_PLUS_PROFILES));
248     static final int[] APV_HDR_PROFILES =
249             combine(APV_HLG_PROFILES, combine(APV_HDR10_PROFILES, APV_HDR10_PLUS_PROFILES));
250     static final int[] AV1_PROFILES = combine(AV1_SDR_PROFILES, AV1_HDR_PROFILES);
251     static final int[] DOLBY_VISION_HDR_PROFILES = new int[]{DolbyVisionProfileDvavPer,
252             DolbyVisionProfileDvavPen, DolbyVisionProfileDvheDer, DolbyVisionProfileDvheDen,
253             DolbyVisionProfileDvheDtr, DolbyVisionProfileDvheStn, DolbyVisionProfileDvheDth,
254             DolbyVisionProfileDvheDtb, DolbyVisionProfileDvheSt, DolbyVisionProfileDvavSe,
255             DolbyVisionProfileDvav110};
256     static final int[] AAC_PROFILES = new int[]{AACObjectMain, AACObjectLC, AACObjectSSR,
257             AACObjectLTP, AACObjectHE, AACObjectScalable, AACObjectERLC, AACObjectERScalable,
258             AACObjectLD, AACObjectELD, AACObjectXHE};
259     public static final Context CONTEXT =
260             InstrumentationRegistry.getInstrumentation().getTargetContext();
261 
262     public static final int MAX_DISPLAY_HEIGHT_CURRENT =
263             Arrays.stream(CONTEXT.getSystemService(DisplayManager.class).getDisplays())
264                     .map(Display::getSupportedModes)
265                     .flatMap(Stream::of)
266                     .max(Comparator.comparing(Display.Mode::getPhysicalHeight))
267                     .orElseThrow(() -> new RuntimeException("Failed to determine max height"))
268                     .getPhysicalHeight();
269     public static final int MAX_DISPLAY_WIDTH_CURRENT =
270             Arrays.stream(CONTEXT.getSystemService(DisplayManager.class).getDisplays())
271                     .map(Display::getSupportedModes)
272                     .flatMap(Stream::of)
273                     .max(Comparator.comparing(Display.Mode::getPhysicalHeight))
274                     .orElseThrow(() -> new RuntimeException("Failed to determine max height"))
275                     .getPhysicalWidth();
276     public static final int MAX_DISPLAY_WIDTH_LAND =
277             Math.max(MAX_DISPLAY_WIDTH_CURRENT, MAX_DISPLAY_HEIGHT_CURRENT);
278     public static final int MAX_DISPLAY_HEIGHT_LAND =
279             Math.min(MAX_DISPLAY_WIDTH_CURRENT, MAX_DISPLAY_HEIGHT_CURRENT);
280 
281     public static final String HDR10_INFO_SCENE_A =
282             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
283                     + "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
284                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
285                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00";
286     public static final String HDR10_ALTERNATE_INFO_SCENE_A =
287             "b5 00 3c 00 01 04 01 40  00 0c 80 00 00 03 00 00"
288                     + "03 00 00 03 00 00 24 08  00 00 28 00 00 50 03 fc"
289                     + "c8 00 01 90 00 02 58 00  02 d0 00 02 f8 00 03 18"
290                     + "00 00 03 00 40 00 00 24  66 33 53 36 6a 00 99 ac"
291                     + "dc cf 9a 00";
292     public static final String HDR10_INFO_SCENE_B =
293             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
294                     + "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
295                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
296                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00";
297     public static final String HDR10_ALTERNATE_INFO_SCENE_B =
298             "b5 00 3c 00 01 04 01 40  00 0c 80 00 00 03 00 00"
299                     + "03 00 00 03 00 00 24 08  00 00 28 00 00 50 90 00"
300                     + "02 58 00 03 fc c8 00 01  02 d0 00 02 f8 00 03 18"
301                     + "00 00 03 00 40 00 00 24  66 33 53 36 6a 00 99 ac"
302                     + "dc cf 9a 00";
303     public static final String HDR10_INFO_SCENE_C =
304             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
305                     + "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
306                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
307                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00";
308     public static final String HDR10_ALTERNATE_INFO_SCENE_C =
309             "b5 00 3c 00 01 04 01 40  00 0c 80 00 00 03 00 00"
310                     + "00 24 08 00 00 03 00 00  03 00 28 00 00 50 90 00"
311                     + "02 58 00 03 fc c8 00 01  02 d0 00 02 f8 00 03 18"
312                     + "00 00 03 00 40 00 00 24  66 33 53 36 6a 00 99 ac"
313                     + "dc cf 9a 00";
314     public static final String HDR10_INFO_SCENE_D =
315             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
316                     + "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
317                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
318                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00";
319 
320     public static final String HDR10_INCORRECT_INFO_SCENE_A =
321             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
322                     + "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
323                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
324                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 00";
325     public static final String HDR10_INCORRECT_INFO_SCENE_B =
326             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
327                     + "0a 00 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
328                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
329                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 01";
330     public static final String HDR10_INCORRECT_INFO_SCENE_C =
331             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
332                     + "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
333                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
334                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 02";
335     public static final String HDR10_INCORRECT_INFO_SCENE_D =
336             "b5 00 3c 00 01 04 00 40  00 0c 80 4e 20 27 10 00"
337                     + "0e 80 00 24 08 00 00 28  00 00 50 00 28 c8 00 c9"
338                     + "90 02 aa 58 05 ca d0 0c  0a f8 16 83 18 9c 18 00"
339                     + "40 78 13 64 d5 7c 2e 2c  c3 59 de 79 6e c3 c2 03";
340 
341     public static String mediaTypeSelKeys;
342     public static String codecPrefix;
343     public static String mediaTypePrefix;
344     public static Pattern codecFilter;
345 
346     public enum SupportClass {
347         CODEC_ALL, // All codecs must support
348         CODEC_ANY, // At least one codec must support
349         CODEC_DEFAULT, // Default codec must support
350         CODEC_HW, // If the component is hardware, then it must support
351         CODEC_SHOULD, // Codec support is optional, but recommended
352         CODEC_HW_RECOMMENDED, // Codec support is optional, but strongly recommended if component
353         // is hardware accelerated
354         CODEC_OPTIONAL; // Codec support is optional
355 
toString(SupportClass supportRequirements)356         public static String toString(SupportClass supportRequirements) {
357             switch (supportRequirements) {
358                 case CODEC_ALL:
359                     return "CODEC_ALL";
360                 case CODEC_ANY:
361                     return "CODEC_ANY";
362                 case CODEC_DEFAULT:
363                     return "CODEC_DEFAULT";
364                 case CODEC_HW:
365                     return "CODEC_HW";
366                 case CODEC_SHOULD:
367                     return "CODEC_SHOULD";
368                 case CODEC_HW_RECOMMENDED:
369                     return "CODEC_HW_RECOMMENDED";
370                 case CODEC_OPTIONAL:
371                     return "CODEC_OPTIONAL";
372                 default:
373                     return "Unknown support class";
374             }
375         }
376     }
377 
378     public enum ComponentClass {
379         ALL,
380         SOFTWARE,
381         HARDWARE;
382 
toString(ComponentClass selectSwitch)383         public static String toString(ComponentClass selectSwitch) {
384             switch (selectSwitch) {
385                 case ALL:
386                     return "all";
387                 case SOFTWARE:
388                     return "software only";
389                 case HARDWARE:
390                     return "hardware accelerated";
391                 default:
392                     return "Unknown select switch";
393             }
394         }
395     }
396 
CodecTestBase(String encoder, String mediaType, String allTestParams)397     public CodecTestBase(String encoder, String mediaType, String allTestParams) {
398         mCodecName = encoder;
399         mMediaType = mediaType;
400         mAllTestParams = allTestParams;
401         mAsyncHandle = new CodecAsyncHandler();
402         mIsAudio = mMediaType.startsWith("audio/");
403         mIsVideo = mMediaType.startsWith("video/");
404     }
405 
406     protected final String mCodecName;
407     protected final String mMediaType;
408     protected final String mAllTestParams;  // logging
409 
410     protected final boolean mIsAudio;
411     protected final boolean mIsVideo;
412     protected CodecAsyncHandler mAsyncHandle;
413     protected boolean mIsCodecInAsyncMode;
414     protected boolean mSawInputEOS;
415     protected boolean mSawOutputEOS;
416     protected boolean mSignalEOSWithLastFrame;
417     protected int mInputCount;
418     protected int mOutputCount;
419     protected long mPrevOutputPts;
420     protected boolean mSignalledOutFormatChanged;
421     protected MediaFormat mOutFormat;
422 
423     protected StringBuilder mTestConfig = new StringBuilder();
424     protected StringBuilder mTestEnv = new StringBuilder();
425 
426     protected boolean mSaveToMem;
427     protected OutputManager mOutputBuff;
428 
429     protected MediaCodec mCodec;
430     protected Surface mSurface;
431     // NOTE: mSurface is a place holder of current Surface used by the CodecTestBase.
432     // This doesn't own the handle. The ownership with instances that manage
433     // SurfaceView or TextureView, ... They hold the responsibility of calling release().
434     protected CodecTestActivity mActivity;
435     protected ImageSurface mImageSurface;
436 
437     public static final MediaCodecList MEDIA_CODEC_LIST_ALL;
438     public static final MediaCodecList MEDIA_CODEC_LIST_REGULAR;
439     static {
440         MEDIA_CODEC_LIST_ALL = new MediaCodecList(MediaCodecList.ALL_CODECS);
441         MEDIA_CODEC_LIST_REGULAR = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
442         IS_HDR_CAPTURE_SUPPORTED = isHDRCaptureSupported();
443         IS_HDR_EDITING_SUPPORTED = isEncoderFeatureSupported(FEATURE_HdrEditing);
444         IS_HLG_EDITING_SUPPORTED = (IS_AT_LEAST_V && android.media.codec.Flags.hlgEditing())
445                 ? isEncoderFeatureSupported(FEATURE_HlgEditing) : false;
446         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vp8", MediaFormat.MIMETYPE_VIDEO_VP8);
447         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vp9", MediaFormat.MIMETYPE_VIDEO_VP9);
448         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("av1", MediaFormat.MIMETYPE_VIDEO_AV1);
449         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("apv", MediaFormat.MIMETYPE_VIDEO_APV);
450         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("avc", MediaFormat.MIMETYPE_VIDEO_AVC);
451         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("hevc", MediaFormat.MIMETYPE_VIDEO_HEVC);
452         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mpeg4", MediaFormat.MIMETYPE_VIDEO_MPEG4);
453         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("h263", MediaFormat.MIMETYPE_VIDEO_H263);
454         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mpeg2", MediaFormat.MIMETYPE_VIDEO_MPEG2);
455         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vraw", MediaFormat.MIMETYPE_VIDEO_RAW);
456         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("amrnb", MediaFormat.MIMETYPE_AUDIO_AMR_NB);
457         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("amrwb", MediaFormat.MIMETYPE_AUDIO_AMR_WB);
458         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("mp3", MediaFormat.MIMETYPE_AUDIO_MPEG);
459         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("aac", MediaFormat.MIMETYPE_AUDIO_AAC);
460         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("vorbis", MediaFormat.MIMETYPE_AUDIO_VORBIS);
461         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("opus", MediaFormat.MIMETYPE_AUDIO_OPUS);
462         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("g711alaw", MediaFormat.MIMETYPE_AUDIO_G711_ALAW);
463         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("g711mlaw", MediaFormat.MIMETYPE_AUDIO_G711_MLAW);
464         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("araw", MediaFormat.MIMETYPE_AUDIO_RAW);
465         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("flac", MediaFormat.MIMETYPE_AUDIO_FLAC);
466         CODEC_SEL_KEY_MEDIA_TYPE_MAP.put("gsm", MediaFormat.MIMETYPE_AUDIO_MSGSM);
467 
468         android.os.Bundle args = InstrumentationRegistry.getArguments();
469         mediaTypeSelKeys = args.getString(MEDIA_TYPE_SEL_KEY);
470         codecPrefix = args.getString(CODEC_PREFIX_KEY);
471         mediaTypePrefix = args.getString(MEDIA_TYPE_PREFIX_KEY);
472         String codecFilterStr = args.getString(CODEC_FILTER_KEY);
473         if (codecFilterStr != null) {
474             codecFilter = Pattern.compile(codecFilterStr);
475         }
476 
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_SDR_PROFILES)477         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_SDR_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_SDR_PROFILES)478         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_SDR_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES)479         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES)480         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES)481         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES)482         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_SDR_PROFILES)483         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_SDR_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES)484         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_SDR_PROFILES);
PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES)485         PROFILE_SDR_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES);
486 
PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES)487         PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HLG_PROFILES);
PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES)488         PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HLG_PROFILES);
PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES)489         PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HLG_PROFILES);
PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES)490         PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HLG_PROFILES);
PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HLG_PROFILES)491         PROFILE_HLG_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HLG_PROFILES);
492 
PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES)493         PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PROFILES);
PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES)494         PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PROFILES);
PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES)495         PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PROFILES);
PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR10_PROFILES)496         PROFILE_HDR10_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR10_PROFILES);
497 
PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PLUS_PROFILES)498         PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR10_PLUS_PROFILES);
PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PLUS_PROFILES)499         PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR10_PLUS_PROFILES);
PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PLUS_PROFILES)500         PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR10_PLUS_PROFILES);
PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR10_PLUS_PROFILES)501         PROFILE_HDR10_PLUS_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR10_PLUS_PROFILES);
502 
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES)503         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_HDR_PROFILES);
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES)504         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_HDR_PROFILES);
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES)505         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_HDR_PROFILES);
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR_PROFILES)506         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_HDR_PROFILES);
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR_PROFILES)507         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR_PROFILES);
PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, DOLBY_VISION_HDR_PROFILES)508         PROFILE_HDR_MAP.put(MediaFormat.MIMETYPE_VIDEO_DOLBY_VISION, DOLBY_VISION_HDR_PROFILES);
509 
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_PROFILES)510         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AVC, AVC_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_PROFILES)511         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_HEVC, HEVC_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES)512         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_H263, H263_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES)513         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG2, MPEG2_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES)514         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_MPEG4, MPEG4_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES)515         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP8, VP8_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_PROFILES)516         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_VP9, VP9_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_PROFILES)517         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_AV1, AV1_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR_PROFILES)518         PROFILE_MAP.put(MediaFormat.MIMETYPE_VIDEO_APV, APV_HDR_PROFILES);
PROFILE_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES)519         PROFILE_MAP.put(MediaFormat.MIMETYPE_AUDIO_AAC, AAC_PROFILES);
520 
521         HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AV1);
522         HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_AVC);
523         HDR_INFO_IN_BITSTREAM_CODECS.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
524     }
525 
combine(int[] first, int[] second)526     static int[] combine(int[] first, int[] second) {
527         int[] result = Arrays.copyOf(first, first.length + second.length);
528         System.arraycopy(second, 0, result, first.length, second.length);
529         return result;
530     }
531 
isMediaTypeLossless(String mediaType)532     public static boolean isMediaTypeLossless(String mediaType) {
533         if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) return true;
534         if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)) return true;
535         return false;
536     }
537 
538     // some media types decode a pre-roll amount before playback. This would mean that decoding
539     // after seeking may not return the exact same values as would be obtained by decoding the
540     // stream straight through
isMediaTypeOutputUnAffectedBySeek(String mediaType)541     public static boolean isMediaTypeOutputUnAffectedBySeek(String mediaType) {
542         if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) return true;
543         if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_RAW)) return true;
544         if (mediaType.startsWith("video/")) return true;
545         return false;
546     }
547 
hasDecoder(String mediaType)548     public static boolean hasDecoder(String mediaType) {
549         return CodecTestBase.selectCodecs(mediaType, null, null, false).size() != 0;
550     }
551 
hasEncoder(String mediaType)552     public static boolean hasEncoder(String mediaType) {
553         return CodecTestBase.selectCodecs(mediaType, null, null, true).size() != 0;
554     }
555 
checkFormatSupport(String codecName, String mediaType, boolean isEncoder, ArrayList<MediaFormat> formats, String[] features, SupportClass supportRequirements)556     public static void checkFormatSupport(String codecName, String mediaType, boolean isEncoder,
557             ArrayList<MediaFormat> formats, String[] features, SupportClass supportRequirements)
558             throws IOException {
559         boolean hasSupport = true;
560         if (formats != null) {
561             hasSupport &= areFormatsSupported(codecName, mediaType, formats);
562         }
563         if (features != null) {
564             for (String feature : features) {
565                 hasSupport &= isFeatureSupported(codecName, mediaType, feature);
566             }
567         }
568         if (!hasSupport) {
569             switch (supportRequirements) {
570                 case CODEC_ALL:
571                     fail("format(s) not supported by codec: " + codecName + " for mediaType : "
572                             + mediaType + " formats: " + formats);
573                     break;
574                 case CODEC_ANY:
575                     if (selectCodecs(mediaType, formats, features, isEncoder).isEmpty()) {
576                         fail("format(s) not supported by any component for mediaType : " + mediaType
577                                 + " formats: " + formats);
578                     }
579                     break;
580                 case CODEC_DEFAULT:
581                     if (isDefaultCodec(codecName, mediaType, isEncoder)) {
582                         fail("format(s) not supported by default codec : " + codecName
583                                 + "for mediaType : " + mediaType + " formats: " + formats);
584                     }
585                     break;
586                 case CODEC_HW:
587                     if (isHardwareAcceleratedCodec(codecName)) {
588                         fail("format(s) not supported by codec: " + codecName + " for mediaType : "
589                                 + mediaType + " formats: " + formats);
590                     }
591                     break;
592                 case CODEC_SHOULD:
593                     Assume.assumeTrue(String.format("format(s) not supported by codec: %s for"
594                             + " mediaType : %s. It is recommended to support it",
595                             codecName, mediaType), false);
596                     break;
597                 case CODEC_HW_RECOMMENDED:
598                     Assume.assumeTrue(String.format(
599                             "format(s) not supported by codec: %s for mediaType : %s. It is %s "
600                                     + "recommended to support it", codecName, mediaType,
601                             isHardwareAcceleratedCodec(codecName) ? "strongly" : ""), false);
602                     break;
603                 case CODEC_OPTIONAL:
604                 default:
605                     // the later assumeTrue() ensures we skip the test for unsupported codecs
606                     break;
607             }
608             Assume.assumeTrue("format(s) not supported by codec: " + codecName + " for mediaType : "
609                     + mediaType, false);
610         }
611     }
612 
isFeatureSupported(String name, String mediaType, String feature)613     public static boolean isFeatureSupported(String name, String mediaType, String feature) {
614         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
615             if (name.equals(codecInfo.getName())) {
616                 return codecInfo.getCapabilitiesForType(mediaType).isFeatureSupported(feature);
617             }
618         }
619         return false;
620     }
621 
isHDRCaptureSupported()622     public static boolean isHDRCaptureSupported() {
623         // If the device supports HDR, hlg support should always return true
624         if (!MediaUtils.hasCamera()) return false;
625         CameraManager cm = CONTEXT.getSystemService(CameraManager.class);
626         try {
627             String[] cameraIds = cm.getCameraIdList();
628             for (String id : cameraIds) {
629                 CameraCharacteristics ch = cm.getCameraCharacteristics(id);
630                 int[] caps = ch.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
631                 if (IntStream.of(caps).anyMatch(x -> x
632                         == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT)) {
633                     Set<Long> profiles =
634                             ch.get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES)
635                                     .getSupportedProfiles();
636                     if (profiles.contains(DynamicRangeProfiles.HLG10)) return true;
637                 }
638             }
639         } catch (CameraAccessException e) {
640             Log.e(LOG_TAG, "encountered " + e.getMessage()
641                     + " marking hdr capture to be available to catch your attention");
642             return true;
643         }
644         return false;
645     }
646 
647     /**
648      * Check if any encoder on the device supports the given feature
649      */
isEncoderFeatureSupported(String feature)650     public static boolean isEncoderFeatureSupported(String feature) {
651         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_REGULAR.getCodecInfos()) {
652             if (!codecInfo.isEncoder()) {
653                 continue;
654             }
655             for (String mediaType : codecInfo.getSupportedTypes()) {
656                 CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType);
657                 if (caps != null && caps.isFeatureSupported(feature)) {
658                     return true;
659                 }
660             }
661         }
662         return false;
663     }
664 
doesAnyFormatHaveHDRProfile(String mediaType, ArrayList<MediaFormat> formats)665     public static boolean doesAnyFormatHaveHDRProfile(String mediaType,
666             ArrayList<MediaFormat> formats) {
667         int[] profileArray = PROFILE_HDR_MAP.get(mediaType);
668         if (profileArray != null) {
669             for (MediaFormat format : formats) {
670                 assertEquals(mediaType, format.getString(MediaFormat.KEY_MIME));
671                 int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1);
672                 if (IntStream.of(profileArray).anyMatch(x -> x == profile)) return true;
673             }
674         }
675         return false;
676     }
677 
doesCodecSupportHDRProfile(String codecName, String mediaType)678     public static boolean doesCodecSupportHDRProfile(String codecName, String mediaType) {
679         int[] hdrProfiles = PROFILE_HDR_MAP.get(mediaType);
680         if (hdrProfiles == null) {
681             return false;
682         }
683         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_REGULAR.getCodecInfos()) {
684             if (!codecName.equals(codecInfo.getName())) {
685                 continue;
686             }
687             CodecCapabilities caps = codecInfo.getCapabilitiesForType(mediaType);
688             if (caps == null) {
689                 return false;
690             }
691             for (CodecProfileLevel pl : caps.profileLevels) {
692                 if (IntStream.of(hdrProfiles).anyMatch(x -> x == pl.profile)) {
693                     return true;
694                 }
695             }
696         }
697         return false;
698     }
699 
canDisplaySupportHDRContent()700     public static boolean canDisplaySupportHDRContent() {
701         DisplayManager displayManager = CONTEXT.getSystemService(DisplayManager.class);
702         return displayManager.getDisplay(Display.DEFAULT_DISPLAY).getHdrCapabilities()
703                 .getSupportedHdrTypes().length > 0;
704     }
705 
isFormatSupported(String name, String mediaType, MediaFormat format)706     public static boolean isFormatSupported(String name, String mediaType, MediaFormat format) {
707         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
708             if (name.equals(codecInfo.getName())) {
709                 MediaCodecInfo.CodecCapabilities cap = codecInfo.getCapabilitiesForType(mediaType);
710                 boolean isSupported = true;
711                 if (format != null) {
712                     isSupported = cap.isFormatSupported(format);
713                 }
714                 if (isSupported) return true;
715             }
716         }
717         return false;
718     }
719 
areFormatsSupported(String name, String mediaType, List<MediaFormat> formats)720     public static boolean areFormatsSupported(String name, String mediaType,
721             List<MediaFormat> formats) throws IOException {
722         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
723             if (name.equals(codecInfo.getName())) {
724                 MediaCodecInfo.CodecCapabilities cap = codecInfo.getCapabilitiesForType(mediaType);
725                 boolean isSupported = true;
726                 if (formats != null) {
727                     for (int i = 0; i < formats.size() && isSupported; i++) {
728                         isSupported = cap.isFormatSupported(formats.get(i));
729                     }
730                 }
731                 if (isSupported) return true;
732             }
733         }
734         return false;
735     }
736 
hasSupportForColorFormat(String name, String mediaType, int colorFormat)737     public static boolean hasSupportForColorFormat(String name, String mediaType, int colorFormat) {
738         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
739             if (name.equals(codecInfo.getName())) {
740                 MediaCodecInfo.CodecCapabilities cap = codecInfo.getCapabilitiesForType(mediaType);
741                 for (int c : cap.colorFormats) {
742                     if (c == colorFormat) {
743                         return true;
744                     }
745                 }
746             }
747         }
748         return false;
749     }
750 
isDefaultCodec(String codecName, String mediaType, boolean isEncoder)751     public static boolean isDefaultCodec(String codecName, String mediaType, boolean isEncoder)
752             throws IOException {
753         Map<String, String> mDefaultCodecs = isEncoder ? DEFAULT_ENCODERS : DEFAULT_DECODERS;
754         if (mDefaultCodecs.containsKey(mediaType)) {
755             return mDefaultCodecs.get(mediaType).equalsIgnoreCase(codecName);
756         }
757         MediaCodec codec = isEncoder ? MediaCodec.createEncoderByType(mediaType)
758                 : MediaCodec.createDecoderByType(mediaType);
759         boolean isDefault = codec.getName().equalsIgnoreCase(codecName);
760         mDefaultCodecs.put(mediaType, codec.getName());
761         codec.release();
762         return isDefault;
763     }
764 
isVendorCodec(String codecName)765     public static boolean isVendorCodec(String codecName) {
766         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
767             if (codecName.equals(codecInfo.getName())) {
768                 return codecInfo.isVendor();
769             }
770         }
771         return false;
772     }
773 
isSoftwareCodec(String codecName)774     public static boolean isSoftwareCodec(String codecName) {
775         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
776             if (codecName.equals(codecInfo.getName())) {
777                 return codecInfo.isSoftwareOnly();
778             }
779         }
780         return false;
781     }
782 
isHardwareAcceleratedCodec(String codecName)783     public static boolean isHardwareAcceleratedCodec(String codecName) {
784         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
785             if (codecName.equals(codecInfo.getName())) {
786                 return codecInfo.isHardwareAccelerated();
787             }
788         }
789         return false;
790     }
791 
isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat)792     public static boolean isFormatSimilar(MediaFormat inpFormat, MediaFormat outFormat) {
793         if (inpFormat == null || outFormat == null) return false;
794         String inpMediaType = inpFormat.getString(MediaFormat.KEY_MIME);
795         String outMediaType = outFormat.getString(MediaFormat.KEY_MIME);
796         // not comparing input and output mediaTypes because for a codec, mediaType is raw on one
797         // side and encoded type on the other
798         if (outMediaType.startsWith("audio/")) {
799             return (inpFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -1)
800                     == outFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT, -2))
801                     && (inpFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE, -1)
802                     == outFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE, -2))
803                     && inpMediaType.startsWith("audio/");
804         } else if (outMediaType.startsWith("video/")) {
805             return getWidth(inpFormat) == getWidth(outFormat)
806                     && getHeight(inpFormat) == getHeight(outFormat)
807                     && inpMediaType.startsWith("video/");
808         }
809         return true;
810     }
811 
isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat)812     public static boolean isCSDIdentical(MediaFormat refFormat, MediaFormat testFormat) {
813         String mediaType = refFormat.getString(MediaFormat.KEY_MIME);
814         for (int i = 0; ; i++) {
815             String csdKey = "csd-" + i;
816             boolean refHasCSD = refFormat.containsKey(csdKey);
817             boolean testHasCSD = testFormat.containsKey(csdKey);
818             if (refHasCSD != testHasCSD) {
819                 if (ENABLE_LOGS) {
820                     Log.w(LOG_TAG, "error, ref fmt has CSD: " + refHasCSD + " test fmt has CSD: " +
821                             testHasCSD);
822                 }
823                 return false;
824             }
825             if (refHasCSD) {
826                 Log.v(LOG_TAG, mediaType + " has " + csdKey);
827                 ByteBuffer r = refFormat.getByteBuffer(csdKey);
828                 ByteBuffer t = testFormat.getByteBuffer(csdKey);
829                 if (!r.equals(t)) {
830                     if (ENABLE_LOGS) {
831                         Log.w(LOG_TAG, "ref CSD and test CSD buffers are not identical");
832                     }
833                     return false;
834                 }
835             } else break;
836         }
837         return true;
838     }
839 
isExtractorFormatSimilar(MediaFormat refFormat, MediaFormat testFormat)840     public static boolean isExtractorFormatSimilar(MediaFormat refFormat, MediaFormat testFormat) {
841         String refMediaType = refFormat.getString(MediaFormat.KEY_MIME);
842         String testMediaType = testFormat.getString(MediaFormat.KEY_MIME);
843 
844         if (!refMediaType.equals(testMediaType)) return false;
845         if (refFormat.getLong(MediaFormat.KEY_DURATION) !=
846                     testFormat.getLong(MediaFormat.KEY_DURATION)) {
847             Log.w(LOG_TAG, "Duration mismatches ref / test = " +
848                                    refFormat.getLong(MediaFormat.KEY_DURATION) + " / " +
849                                    testFormat.getLong(MediaFormat.KEY_DURATION));
850             // TODO (b/163477410)(b/163478168)
851             // return false;
852         }
853         if (!isCSDIdentical(refFormat, testFormat)) return false;
854         return isFormatSimilar(refFormat, testFormat);
855     }
856 
getCodecCapabilities(String codecName, String mediaType)857     public static CodecCapabilities getCodecCapabilities(String codecName, String mediaType) {
858         for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_ALL.getCodecInfos()) {
859             if (codecName.equals(codecInfo.getName())) {
860                 return codecInfo.getCapabilitiesForType(mediaType);
861             }
862         }
863         return null;
864     }
865 
getMaxSupportedInstances(String codecName, String mediaType)866     public static int getMaxSupportedInstances(String codecName, String mediaType) {
867         CodecCapabilities caps = getCodecCapabilities(codecName, mediaType);
868         return caps != null ? caps.getMaxSupportedInstances() : 0;
869     }
870 
getMaxCodecInstances(String codecName, String mediaType)871     public static int getMaxCodecInstances(String codecName, String mediaType) {
872         int maxCodecLimit = 32;
873         boolean isLowRamDevice = CONTEXT.getSystemService(ActivityManager.class).isLowRamDevice();
874         if (isLowRamDevice) {
875             maxCodecLimit = LOW_RAM_DEVICE_MAX_INSTANCES;
876         }
877         return Math.min(getMaxSupportedInstances(codecName, mediaType), maxCodecLimit);
878     }
879 
isFeatureRequired(String codecName, String mediaType, String feature)880     public static boolean isFeatureRequired(String codecName, String mediaType, String feature) {
881         CodecCapabilities caps = getCodecCapabilities(codecName, mediaType);
882         return caps != null && caps.isFeatureRequired(feature);
883     }
884 
885     /**
886      * Stop the current codec session and transfer component to uninitialized state.
887      * <p>
888      * Some legacy OMX components do not properly clear the internal state at stop().
889      * Workaround the issue with resetting the component.
890      */
endCodecSession(MediaCodec codec)891     public static void endCodecSession(MediaCodec codec) {
892         if (codec.getName().toUpperCase(Locale.getDefault()).startsWith("OMX")) {
893             codec.reset();
894         } else {
895             codec.stop();
896         }
897     }
898 
paramToString(Object[] param)899     public static String paramToString(Object[] param) {
900         StringBuilder paramStr = new StringBuilder("[  ");
901         for (int j = 0; j < param.length - 1; j++) {
902             Object o = param[j];
903             if (o == null) {
904                 paramStr.append("null, ");
905             } else if (o instanceof String[]) {
906                 int length = Math.min(((String[]) o).length, 3);
907                 paramStr.append("{");
908                 for (int i = 0; i < length; i++) {
909                     paramStr.append(((String[]) o)[i]).append(", ");
910                 }
911                 paramStr.delete(paramStr.length() - 2, paramStr.length())
912                         .append(length == ((String[]) o).length ? "}, " : ", ... }, ");
913             } else if (o instanceof int[]) {
914                 paramStr.append("{");
915                 for (int i = 0; i < ((int[]) o).length; i++) {
916                     paramStr.append(((int[]) o)[i]).append(", ");
917                 }
918                 paramStr.delete(paramStr.length() - 2, paramStr.length()).append("}, ");
919             } else if (o instanceof Map) {
920                 int length = 0;
921                 paramStr.append("{ ");
922                 Map map = (Map) o;
923                 for (Object key : map.keySet()) {
924                     paramStr.append(key).append(" = ").append(map.get(key)).append(", ");
925                     length++;
926                     if (length > 1) break;
927                 }
928                 paramStr.delete(paramStr.length() - 2, paramStr.length())
929                         .append(length == map.size() ? "}, " : ", ... }, ");
930             } else if (o instanceof EncoderConfigParams[]) {
931                 int length = Math.min(((EncoderConfigParams[]) o).length, 3);
932                 paramStr.append("{");
933                 for (int i = 0; i < ((EncoderConfigParams[]) o).length; i++) {
934                     paramStr.append(((EncoderConfigParams[]) o)[i]).append(", ");
935                 }
936                 paramStr.delete(paramStr.length() - 2, paramStr.length())
937                         .append(length == ((EncoderConfigParams[]) o).length ? "}, " : ", ... }, ");
938             } else paramStr.append(o).append(", ");
939         }
940         paramStr.delete(paramStr.length() - 2, paramStr.length()).append("  ]");
941         return paramStr.toString();
942     }
943 
compileRequiredMediaTypeList(boolean isEncoder, boolean needAudio, boolean needVideo)944     public static ArrayList<String> compileRequiredMediaTypeList(boolean isEncoder,
945             boolean needAudio, boolean needVideo) {
946         Set<String> list = new HashSet<>();
947         if (!isEncoder) {
948             if (MediaUtils.hasAudioOutput() && needAudio) {
949                 // sec 5.1.2
950                 list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
951                 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC);
952                 list.add(MediaFormat.MIMETYPE_AUDIO_MPEG);
953                 list.add(MediaFormat.MIMETYPE_AUDIO_VORBIS);
954                 list.add(MediaFormat.MIMETYPE_AUDIO_RAW);
955                 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS);
956             }
957             if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv()
958                     || MediaUtils.isAutomotive()) {
959                 // sec 2.2.2, 2.3.2, 2.5.2
960                 if (needAudio) {
961                     list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
962                 }
963                 if (needVideo) {
964                     list.add(MediaFormat.MIMETYPE_VIDEO_AVC);
965                     list.add(MediaFormat.MIMETYPE_VIDEO_MPEG4);
966                     list.add(MediaFormat.MIMETYPE_VIDEO_VP8);
967                     list.add(MediaFormat.MIMETYPE_VIDEO_VP9);
968                 }
969             }
970             if (MediaUtils.isHandheld() || MediaUtils.isTablet()) {
971                 // sec 2.2.2
972                 if (needAudio) {
973                     list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
974                     list.add(MediaFormat.MIMETYPE_AUDIO_AMR_WB);
975                 }
976                 if (needVideo) {
977                     list.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
978                     if (IS_AT_LEAST_U) {
979                         list.add(MediaFormat.MIMETYPE_VIDEO_AV1);
980                     }
981                 }
982             }
983             if (MediaUtils.isTv() && needVideo) {
984                 // sec 2.3.2
985                 list.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
986                 list.add(MediaFormat.MIMETYPE_VIDEO_MPEG2);
987                 if (IS_AT_LEAST_U) {
988                     list.add(MediaFormat.MIMETYPE_VIDEO_AV1);
989                 }
990             }
991         } else {
992             if (MediaUtils.hasMicrophone() && needAudio) {
993                 // sec 5.1.1
994                 // TODO(b/154423550)
995                 // list.add(MediaFormat.MIMETYPE_AUDIO_RAW);
996                 list.add(MediaFormat.MIMETYPE_AUDIO_FLAC);
997                 list.add(MediaFormat.MIMETYPE_AUDIO_OPUS);
998             }
999             if (MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv()
1000                     || MediaUtils.isAutomotive()) {
1001                 // sec 2.2.2, 2.3.2, 2.5.2
1002                 if (needAudio) {
1003                     list.add(MediaFormat.MIMETYPE_AUDIO_AAC);
1004                 }
1005                 if (needVideo) {
1006                     if ((MediaUtils.isHandheld() || MediaUtils.isTablet() || MediaUtils.isTv())
1007                             && IS_AT_LEAST_U) {
1008                         list.add(MediaFormat.MIMETYPE_VIDEO_AV1);
1009                     }
1010                     list.add(MediaFormat.MIMETYPE_VIDEO_AVC);
1011                     list.add(MediaFormat.MIMETYPE_VIDEO_VP8);
1012                 }
1013             }
1014             if ((MediaUtils.isHandheld() || MediaUtils.isTablet()) && needAudio) {
1015                 // sec 2.2.2
1016                 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_NB);
1017                 list.add(MediaFormat.MIMETYPE_AUDIO_AMR_WB);
1018             }
1019         }
1020         return new ArrayList<>(list);
1021     }
1022 
compileCompleteTestMediaTypesList(boolean isEncoder, boolean needAudio, boolean needVideo)1023     private static ArrayList<String> compileCompleteTestMediaTypesList(boolean isEncoder,
1024             boolean needAudio, boolean needVideo) {
1025         ArrayList<String> mediaTypes = new ArrayList<>();
1026         if (mediaTypeSelKeys == null) {
1027             ArrayList<String> cddRequiredMediaTypesList =
1028                     compileRequiredMediaTypeList(isEncoder, needAudio, needVideo);
1029             MediaCodecInfo[] codecInfos = MEDIA_CODEC_LIST_REGULAR.getCodecInfos();
1030             for (MediaCodecInfo codecInfo : codecInfos) {
1031                 if (codecInfo.isEncoder() != isEncoder) continue;
1032                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
1033                 String[] types = codecInfo.getSupportedTypes();
1034                 for (String type : types) {
1035                     if (mediaTypePrefix != null && !type.startsWith(mediaTypePrefix)) {
1036                         continue;
1037                     }
1038                     if (!needAudio && type.startsWith("audio/")) continue;
1039                     if (!needVideo && type.startsWith("video/")) continue;
1040                     if (!mediaTypes.contains(type)) {
1041                         mediaTypes.add(type);
1042                     }
1043                 }
1044             }
1045             if (mediaTypePrefix != null) {
1046                 return mediaTypes;
1047             }
1048             // feature_video_output is not exposed to package manager. Testing for video output
1049             // ports, such as VGA, HDMI, DisplayPort, or a wireless port for display is also not
1050             // direct.
1051             /* sec 5.2: device implementations include an embedded screen display with the
1052             diagonal length of at least 2.5 inches or include a video output port or declare the
1053             support of a camera */
1054             if (isEncoder && needVideo
1055                     && (MediaUtils.hasCamera() || MediaUtils.getScreenSizeInInches() >= 2.5)
1056                     && !mediaTypes.contains(MediaFormat.MIMETYPE_VIDEO_AVC)
1057                     && !mediaTypes.contains(MediaFormat.MIMETYPE_VIDEO_VP8)) {
1058                 // Add required cdd mediaTypes here so that respective codec tests fail.
1059                 mediaTypes.add(MediaFormat.MIMETYPE_VIDEO_AVC);
1060                 mediaTypes.add(MediaFormat.MIMETYPE_VIDEO_VP8);
1061                 Log.e(LOG_TAG, "device must support at least one of VP8 or AVC video encoders");
1062             }
1063             for (String mediaType : cddRequiredMediaTypesList) {
1064                 if (!mediaTypes.contains(mediaType)) {
1065                     // Add required cdd mediaTypes here so that respective codec tests fail.
1066                     mediaTypes.add(mediaType);
1067                     Log.e(LOG_TAG, "no codec found for mediaType " + mediaType
1068                             + " as required by cdd");
1069                 }
1070             }
1071         } else {
1072             for (Map.Entry<String, String> entry : CODEC_SEL_KEY_MEDIA_TYPE_MAP.entrySet()) {
1073                 String key = entry.getKey();
1074                 String value = entry.getValue();
1075                 if (mediaTypeSelKeys.contains(key) && !mediaTypes.contains(value)) {
1076                     mediaTypes.add(value);
1077                 }
1078             }
1079         }
1080         return mediaTypes;
1081     }
1082 
prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs)1083     public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList,
1084             boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs) {
1085         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
1086                 mustTestAllCodecs, ComponentClass.ALL, null /* features */,
1087                 false /*ignoreModeDuringSelection*/);
1088     }
1089 
prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, boolean ignoreModeDuringSelection)1090     public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList,
1091             boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs,
1092             boolean ignoreModeDuringSelection) {
1093         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
1094                 mustTestAllCodecs, ComponentClass.ALL, null /* features */,
1095                 ignoreModeDuringSelection);
1096     }
1097 
prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, ComponentClass selectSwitch)1098     public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList,
1099             boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs,
1100             ComponentClass selectSwitch) {
1101         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
1102                 mustTestAllCodecs, selectSwitch, null, false);
1103     }
1104 
prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, ComponentClass selectSwitch, String[] features)1105     public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList,
1106             boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs,
1107             ComponentClass selectSwitch, String[] features) {
1108         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo,
1109                 mustTestAllCodecs, selectSwitch, features, false);
1110     }
1111 
prepareParamList(List<Object[]> exhaustiveArgsList, boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs, ComponentClass selectSwitch, String[] features, boolean ignoreModeDuringSelection)1112     public static List<Object[]> prepareParamList(List<Object[]> exhaustiveArgsList,
1113             boolean isEncoder, boolean needAudio, boolean needVideo, boolean mustTestAllCodecs,
1114             ComponentClass selectSwitch, String[] features, boolean ignoreModeDuringSelection) {
1115         ArrayList<String> mediaTypes = compileCompleteTestMediaTypesList(isEncoder,
1116                 needAudio, needVideo);
1117         ArrayList<String> cddRequiredMediaTypesList =
1118                 compileRequiredMediaTypeList(isEncoder, needAudio, needVideo);
1119         final List<Object[]> argsList = new ArrayList<>();
1120         int argLength = exhaustiveArgsList.get(0).length;
1121         for (String mediaType : mediaTypes) {
1122             ArrayList<String> totalListOfCodecs =
1123                     selectCodecs(mediaType, null /* formats */, features, isEncoder, selectSwitch);
1124             ArrayList<String> listOfCodecs = new ArrayList<>();
1125 
1126             // when mustTestAllCodecs, verify that we start with a non-empty list of
1127             // codecs to test.  If there are no codecs, the system is broken. We will
1128             // usually trim that list (e.g. as part of CTS/MCTS partitioning) to get the
1129             // set of codecs that we will actually run in this mode.
1130             //
1131             if (mustTestAllCodecs && totalListOfCodecs.size() == 0) {
1132                 listOfCodecs.add(INVALID_CODEC + mediaType);
1133             }
1134 
1135             for (String codec : totalListOfCodecs) {
1136                 if (!ignoreModeDuringSelection) {
1137                     // general mode exclusions
1138                     if (!TestUtils.isTestableCodecInCurrentMode(codec)) {
1139                         Log.v(LOG_TAG, "codec " + codec + " skipped in mode "
1140                                         + TestUtils.currentTestModeName());
1141                         continue;
1142                     }
1143                 }
1144                 // and then prefix checking exclusions
1145                 if (codecPrefix != null && !codec.startsWith(codecPrefix)) {
1146                     Log.v(LOG_TAG, "codec " + codec + " skipped, doesn't match prefix "
1147                                     + codecPrefix);
1148                     continue;
1149                 }
1150                 if (codecFilter != null && !codecFilter.matcher(codec).matches()) {
1151                     Log.v(LOG_TAG, "codec " + codec + " skipped, doesn't match pattern");
1152                     continue;
1153                 }
1154                 listOfCodecs.add(codec);
1155             }
1156 
1157             // we excluded eligible codecs all the way down to nothing.
1158             // So we don't need to mess with adding to argsList.
1159             // we trimmed the candidates down to an empty list; go look at the
1160             // next mediatype
1161             if (listOfCodecs.size() == 0) {
1162                 continue;
1163             }
1164 
1165             boolean miss = true;
1166             for (Object[] arg : exhaustiveArgsList) {
1167                 if (mediaType.equals(arg[0])) {
1168                     for (String codec : listOfCodecs) {
1169                         Object[] argUpdate = new Object[argLength + 2];
1170                         argUpdate[0] = codec;
1171                         System.arraycopy(arg, 0, argUpdate, 1, argLength);
1172                         argUpdate[argLength + 1] = paramToString(argUpdate);
1173                         argsList.add(argUpdate);
1174                     }
1175                     miss = false;
1176                 }
1177             }
1178 
1179             // when we're testing exhaustively... see if we are looking at a media type
1180             // that has no test vectors.
1181             // This means
1182             // -- we're looking at an optional or new media type.
1183             // -- our test suite is broken, we *should* have an asset for this type.
1184             //
1185             if (miss && mustTestAllCodecs) {
1186                 if (!cddRequiredMediaTypesList.contains(mediaType)) {
1187                     Log.w(LOG_TAG, "no test vectors available for optional mediaType type "
1188                             + mediaType);
1189                     continue;
1190                 }
1191 
1192                 // create a fake codec name that indicates the
1193                 // brokenness of this particular test case
1194                 // (since it's painful to fail within the parameterization calculation)
1195                 //
1196                 Object[] argUpdate = new Object[argLength + 2];
1197                 argUpdate[0] = "No.Test.Assets.Exist.For." + mediaType;
1198                 argUpdate[1] = mediaType;
1199                 // skipping the initial 'mediatype' slot in the args list
1200                 System.arraycopy(exhaustiveArgsList.get(0), 1, argUpdate, 2, argLength - 1);
1201                 argUpdate[argLength + 1] = paramToString(argUpdate);
1202                 argsList.add(argUpdate);
1203             }
1204         }
1205         return argsList;
1206     }
1207 
selectCodecs(String mediaType, ArrayList<MediaFormat> formats, String[] features, boolean isEncoder)1208     public static ArrayList<String> selectCodecs(String mediaType, ArrayList<MediaFormat> formats,
1209             String[] features, boolean isEncoder) {
1210         return selectCodecs(mediaType, formats, features, isEncoder, ComponentClass.ALL);
1211     }
1212 
selectCodecs(String mediaType, ArrayList<MediaFormat> formats, String[] features, boolean isEncoder, ComponentClass selectSwitch)1213     public static ArrayList<String> selectCodecs(String mediaType, ArrayList<MediaFormat> formats,
1214             String[] features, boolean isEncoder, ComponentClass selectSwitch) {
1215         MediaCodecInfo[] codecInfos = MEDIA_CODEC_LIST_REGULAR.getCodecInfos();
1216         ArrayList<String> listOfCodecs = new ArrayList<>();
1217         for (MediaCodecInfo codecInfo : codecInfos) {
1218             if (codecInfo.isEncoder() != isEncoder) continue;
1219             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) continue;
1220             if (selectSwitch == ComponentClass.HARDWARE && !codecInfo.isHardwareAccelerated()) {
1221                 continue;
1222             } else if (selectSwitch == ComponentClass.SOFTWARE && !codecInfo.isSoftwareOnly()) {
1223                 continue;
1224             }
1225             String[] types = codecInfo.getSupportedTypes();
1226             for (String type : types) {
1227                 if (type.equalsIgnoreCase(mediaType)) {
1228                     boolean isOk = true;
1229                     MediaCodecInfo.CodecCapabilities codecCapabilities =
1230                             codecInfo.getCapabilitiesForType(type);
1231                     if (formats != null) {
1232                         for (MediaFormat format : formats) {
1233                             if (!codecCapabilities.isFormatSupported(format)) {
1234                                 isOk = false;
1235                                 break;
1236                             }
1237                         }
1238                     }
1239                     if (features != null) {
1240                         for (String feature : features) {
1241                             if (!codecCapabilities.isFeatureSupported(feature)) {
1242                                 isOk = false;
1243                                 break;
1244                             }
1245                         }
1246                     }
1247                     if (isOk) listOfCodecs.add(codecInfo.getName());
1248                 }
1249             }
1250         }
1251         return listOfCodecs;
1252     }
1253 
getWidth(MediaFormat format)1254     public static int getWidth(MediaFormat format) {
1255         int width = format.getInteger(MediaFormat.KEY_WIDTH, -1);
1256         if (format.containsKey("crop-left") && format.containsKey("crop-right")) {
1257             width = format.getInteger("crop-right") + 1 - format.getInteger("crop-left");
1258         }
1259         return width;
1260     }
1261 
getHeight(MediaFormat format)1262     public static int getHeight(MediaFormat format) {
1263         int height = format.getInteger(MediaFormat.KEY_HEIGHT, -1);
1264         if (format.containsKey("crop-top") && format.containsKey("crop-bottom")) {
1265             height = format.getInteger("crop-bottom") + 1 - format.getInteger("crop-top");
1266         }
1267         return height;
1268     }
1269 
loadByteArrayFromString(final String str)1270     public static byte[] loadByteArrayFromString(final String str) {
1271         if (str == null) {
1272             return null;
1273         }
1274         Pattern pattern = Pattern.compile("[0-9a-fA-F]{2}");
1275         Matcher matcher = pattern.matcher(str);
1276         // allocate a large enough byte array first
1277         byte[] tempArray = new byte[str.length() / 2];
1278         int i = 0;
1279         while (matcher.find()) {
1280             tempArray[i++] = (byte) Integer.parseInt(matcher.group(), 16);
1281         }
1282         return Arrays.copyOfRange(tempArray, 0, i);
1283     }
1284 
byteArrayToHexString(byte[] bytes)1285     public static String byteArrayToHexString(byte[] bytes) {
1286         final char[] hexArray =
1287                 {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
1288         char[] hexChars = new char[bytes.length * 3];
1289         int v;
1290         for (int j = 0; j < bytes.length; j++) {
1291             v = bytes[j] & 0xFF;
1292             hexChars[j * 3] = hexArray[v >>> 4];
1293             hexChars[j * 3 + 1] = hexArray[v & 0x0F];
1294             hexChars[j * 3 + 2] = ' ';
1295         }
1296         return new String(hexChars);
1297     }
1298 
enqueueInput(int bufferIndex)1299     protected abstract void enqueueInput(int bufferIndex) throws IOException;
1300 
dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info)1301     protected abstract void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info);
1302 
1303     @Rule
1304     public final TestName mTestName = new TestName();
1305 
1306     @Rule
1307     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
1308 
1309     @Before
setUpCodecTestBase()1310     public void setUpCodecTestBase() {
1311         mTestConfig.setLength(0);
1312         mTestConfig.append("\n##################       Test Details        ####################\n");
1313         mTestConfig.append("Test Name :- ").append(mTestName.getMethodName()).append("\n");
1314         mTestConfig.append("Test Parameters :- ").append(mAllTestParams).append("\n");
1315         if (mCodecName != null && mCodecName.startsWith(INVALID_CODEC)) {
1316             fail("no valid component available for current test \n" + mTestConfig);
1317         }
1318     }
1319 
1320     @After
tearDownCodecTestBase()1321     public void tearDownCodecTestBase() {
1322         mSurface = null;
1323         if (mActivity != null) {
1324             mActivity.finish();
1325             mActivity = null;
1326         }
1327         if (mImageSurface != null) {
1328             mImageSurface.release();
1329             mImageSurface = null;
1330         }
1331         if (mCodec != null) {
1332             mCodec.release();
1333             mCodec = null;
1334         }
1335     }
1336 
1337     // reusable portions of configureCodec(...) are handled here
1338     // As configureCodec is indicative of start of a fresh encoding / decoding operation,
1339     // initializations that were made for a different session MUST not be used. To ensure the
1340     // same, resetContext() is called here. This default initializes all the fields of the test
1341     // before configuring the component. If the test intends to use a value different from
1342     // default value then explicit initialization is required.
configureCodecCommon(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame, boolean isEncoder, int flags)1343     protected void configureCodecCommon(MediaFormat format, boolean isAsync,
1344             boolean signalEOSWithLastFrame, boolean isEncoder, int flags) {
1345         resetContext(isAsync, signalEOSWithLastFrame);
1346         mAsyncHandle.setCallBack(mCodec, isAsync);
1347 
1348         mTestEnv.setLength(0);
1349         mTestEnv.append("###################      Test Environment       #####################\n");
1350         mTestEnv.append(String.format("Component under test :- %s \n", mCodecName));
1351         mTestEnv.append("Format under test :- ").append(format).append("\n");
1352         mTestEnv.append(String.format("Component operating in :- %s mode \n",
1353                 (isAsync ? "asynchronous" : "synchronous")));
1354         mTestEnv.append(String.format("Component received input eos :- %s \n",
1355                 (signalEOSWithLastFrame ? "with full buffer" : "with empty buffer")));
1356         mTestEnv.append(String.format("Component is :- %s \n",
1357                 (isEncoder ? "encoder" : "decoder")));
1358         mTestEnv.append("Component configure flags :- ").append(flags).append("\n");
1359     }
1360 
configureCodec(MediaFormat format, boolean isAsync, boolean cryptoCallAndSignalEosWithLastFrame, boolean isEncoder)1361     protected void configureCodec(MediaFormat format, boolean isAsync,
1362             boolean cryptoCallAndSignalEosWithLastFrame, boolean isEncoder) {
1363         configureCodec(format, isAsync, cryptoCallAndSignalEosWithLastFrame,
1364                 isEncoder, 0 /* flags */);
1365     }
1366 
configureCodec(MediaFormat format, boolean isAsync, boolean cryptoCallAndSignalEosWithLastFrame, boolean isEncoder, int flags)1367     protected void configureCodec(MediaFormat format, boolean isAsync,
1368             boolean cryptoCallAndSignalEosWithLastFrame, boolean isEncoder, int flags) {
1369         if (IS_AT_LEAST_R && ((flags & MediaCodec.CONFIGURE_FLAG_USE_BLOCK_MODEL) != 0)) {
1370             if (!isAsync) {
1371                 throw new RuntimeException("Block model feature testing requires mode of operation"
1372                         + " to be asynchronous");
1373             }
1374         }
1375 
1376         configureCodecCommon(format, isAsync, cryptoCallAndSignalEosWithLastFrame, isEncoder,
1377                 flags);
1378 
1379         // signalEOS flag has nothing to do with configure. We are using this flag to try all
1380         // available configure apis
1381         if (cryptoCallAndSignalEosWithLastFrame) {
1382             mCodec.configure(format, mSurface, null /* crypto */,
1383                     (isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0) | flags);
1384         } else {
1385             mCodec.configure(format, mSurface,
1386                     (isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0) | flags,
1387                     null /* descrambler */);
1388         }
1389         if (ENABLE_LOGS) {
1390             Log.v(LOG_TAG, "codec configured");
1391         }
1392     }
1393 
configureCodecInDetachedMode(MediaFormat format, boolean isAsync, boolean cryptoCallAndSignalEosWithLastFrame)1394     protected void configureCodecInDetachedMode(MediaFormat format, boolean isAsync,
1395             boolean cryptoCallAndSignalEosWithLastFrame) {
1396         configureCodecCommon(format, isAsync, cryptoCallAndSignalEosWithLastFrame,
1397                 false /* isEncoder */, MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE);
1398 
1399         // signalEOS flag has nothing to do with configure. We are using this flag to try all
1400         // available configure apis
1401         if (cryptoCallAndSignalEosWithLastFrame) {
1402             mCodec.configure(format, null /* surface */, null /* crypto */,
1403                     MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE);
1404         } else {
1405             mCodec.configure(format, null /* surface */,
1406                     MediaCodec.CONFIGURE_FLAG_DETACHED_SURFACE, null /* descrambler */);
1407         }
1408         if (ENABLE_LOGS) {
1409             Log.v(LOG_TAG, "codec configured");
1410         }
1411     }
1412 
getOutputManager()1413     public OutputManager getOutputManager() {
1414         return mOutputBuff;
1415     }
1416 
getOutputFormat()1417     public MediaFormat getOutputFormat() {
1418         return mIsCodecInAsyncMode ? mAsyncHandle.getOutputFormat() : mOutFormat;
1419     }
1420 
getOutputCount()1421     public int getOutputCount() {
1422         return mOutputCount;
1423     }
1424 
flushCodec()1425     protected void flushCodec() {
1426         mCodec.flush();
1427         // TODO(b/147576107): is it ok to clearQueues right away or wait for some signal
1428         mAsyncHandle.clearQueues();
1429         mSawInputEOS = false;
1430         mSawOutputEOS = false;
1431         mInputCount = 0;
1432         mOutputCount = 0;
1433         mPrevOutputPts = Long.MIN_VALUE;
1434         if (ENABLE_LOGS) {
1435             Log.v(LOG_TAG, "codec flushed");
1436         }
1437     }
1438 
reConfigureCodec(MediaFormat format, boolean isAsync, boolean signalEOSWithLastFrame, boolean isEncoder)1439     protected void reConfigureCodec(MediaFormat format, boolean isAsync,
1440             boolean signalEOSWithLastFrame, boolean isEncoder) {
1441         /* TODO(b/147348711) */
1442         if (false) mCodec.stop();
1443         else mCodec.reset();
1444         configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
1445     }
1446 
resetContext(boolean isAsync, boolean signalEOSWithLastFrame)1447     protected void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
1448         mAsyncHandle.resetContext();
1449         mIsCodecInAsyncMode = isAsync;
1450         mSawInputEOS = false;
1451         mSawOutputEOS = false;
1452         mSignalEOSWithLastFrame = signalEOSWithLastFrame;
1453         mInputCount = 0;
1454         mOutputCount = 0;
1455         mPrevOutputPts = Long.MIN_VALUE;
1456         mSignalledOutFormatChanged = false;
1457     }
1458 
enqueueEOS(int bufferIndex)1459     protected void enqueueEOS(int bufferIndex) {
1460         if (!mSawInputEOS) {
1461             mCodec.queueInputBuffer(bufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
1462             mSawInputEOS = true;
1463             if (ENABLE_LOGS) {
1464                 Log.v(LOG_TAG, "Queued End of Stream");
1465             }
1466         }
1467     }
1468 
doWork(int frameLimit)1469     protected void doWork(int frameLimit) throws InterruptedException, IOException {
1470         int frameCount = 0;
1471         if (mIsCodecInAsyncMode) {
1472             // dequeue output after inputEOS is expected to be done in waitForAllOutputs()
1473             while (!mAsyncHandle.hasSeenError() && !mSawInputEOS && frameCount < frameLimit) {
1474                 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
1475                 if (element != null) {
1476                     int bufferID = element.first;
1477                     MediaCodec.BufferInfo info = element.second;
1478                     if (info != null) {
1479                         // <id, info> corresponds to output callback. Handle it accordingly
1480                         dequeueOutput(bufferID, info);
1481                     } else {
1482                         // <id, null> corresponds to input callback. Handle it accordingly
1483                         enqueueInput(bufferID);
1484                         frameCount++;
1485                     }
1486                 }
1487             }
1488         } else {
1489             MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
1490             // dequeue output after inputEOS is expected to be done in waitForAllOutputs()
1491             while (!mSawInputEOS && frameCount < frameLimit) {
1492                 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
1493                 if (outputBufferId >= 0) {
1494                     dequeueOutput(outputBufferId, outInfo);
1495                 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
1496                     mOutFormat = mCodec.getOutputFormat();
1497                     mSignalledOutFormatChanged = true;
1498                 }
1499                 int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
1500                 if (inputBufferId != -1) {
1501                     enqueueInput(inputBufferId);
1502                     frameCount++;
1503                 }
1504             }
1505         }
1506     }
1507 
queueEOS()1508     protected void queueEOS() throws InterruptedException {
1509         if (mIsCodecInAsyncMode) {
1510             while (!mAsyncHandle.hasSeenError() && !mSawInputEOS) {
1511                 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getWork();
1512                 if (element != null) {
1513                     int bufferID = element.first;
1514                     MediaCodec.BufferInfo info = element.second;
1515                     if (info != null) {
1516                         dequeueOutput(bufferID, info);
1517                     } else {
1518                         enqueueEOS(element.first);
1519                     }
1520                 }
1521             }
1522         } else {
1523             MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
1524             while (!mSawInputEOS) {
1525                 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
1526                 if (outputBufferId >= 0) {
1527                     dequeueOutput(outputBufferId, outInfo);
1528                 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
1529                     mOutFormat = mCodec.getOutputFormat();
1530                     mSignalledOutFormatChanged = true;
1531                 }
1532                 int inputBufferId = mCodec.dequeueInputBuffer(Q_DEQ_TIMEOUT_US);
1533                 if (inputBufferId != -1) {
1534                     enqueueEOS(inputBufferId);
1535                 }
1536             }
1537         }
1538     }
1539 
waitForAllOutputs()1540     protected void waitForAllOutputs() throws InterruptedException {
1541         if (mIsCodecInAsyncMode) {
1542             while (!mAsyncHandle.hasSeenError() && !mSawOutputEOS) {
1543                 Pair<Integer, MediaCodec.BufferInfo> element = mAsyncHandle.getOutput();
1544                 if (element != null) {
1545                     dequeueOutput(element.first, element.second);
1546                 }
1547             }
1548         } else {
1549             MediaCodec.BufferInfo outInfo = new MediaCodec.BufferInfo();
1550             while (!mSawOutputEOS) {
1551                 int outputBufferId = mCodec.dequeueOutputBuffer(outInfo, Q_DEQ_TIMEOUT_US);
1552                 if (outputBufferId >= 0) {
1553                     dequeueOutput(outputBufferId, outInfo);
1554                 } else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
1555                     mOutFormat = mCodec.getOutputFormat();
1556                     mSignalledOutFormatChanged = true;
1557                 }
1558             }
1559         }
1560         validateTestState();
1561     }
1562 
validateTestState()1563     protected void validateTestState() {
1564         assertFalse("Encountered error in async mode. \n" + mTestConfig + mTestEnv
1565                 + mAsyncHandle.getErrMsg(), mAsyncHandle.hasSeenError());
1566         if (mInputCount > 0) {
1567             assertTrue(String.format("fed %d input frames, received no output frames \n",
1568                     mInputCount) + mTestConfig + mTestEnv, mOutputCount > 0);
1569         }
1570         /*if (mInputCount == 0 && mInputCount != mOutputCount) {
1571             String msg = String.format("The number of output frames received is not same as number "
1572                             + "of input frames queued. Output count is %d, Input count is %d \n",
1573                     mOutputCount, mInputCount);
1574             // check the pts lists to see what frames are dropped, the below call is needed to
1575             // get useful error messages
1576             mOutputBuff.isOutPtsListIdenticalToInpPtsList(true);
1577             fail(msg + mTestConfig + mTestEnv + mOutputBuff.getErrMsg());
1578         }*/
1579     }
1580 
insertHdrDynamicInfo(byte[] info)1581     protected void insertHdrDynamicInfo(byte[] info) {
1582         final Bundle params = new Bundle();
1583         params.putByteArray(MediaFormat.KEY_HDR10_PLUS_INFO, info);
1584         mCodec.setParameters(params);
1585     }
1586 
validateMetrics(String codec)1587     protected PersistableBundle validateMetrics(String codec) {
1588         PersistableBundle metrics = mCodec.getMetrics();
1589         assertNotNull("error! MediaCodec.getMetrics() returns null \n" + mTestConfig + mTestEnv,
1590                 metrics);
1591         assertEquals("error! metrics#MetricsConstants.CODEC is not as expected \n" + mTestConfig
1592                 + mTestEnv, metrics.getString(MediaCodec.MetricsConstants.CODEC), codec);
1593         assertEquals("error! metrics#MetricsConstants.MODE is not as expected \n" + mTestConfig
1594                         + mTestEnv, mIsAudio ? MediaCodec.MetricsConstants.MODE_AUDIO :
1595                         MediaCodec.MetricsConstants.MODE_VIDEO,
1596                 metrics.getString(MediaCodec.MetricsConstants.MODE));
1597         return metrics;
1598     }
1599 
validateMetrics(String codec, MediaFormat format)1600     protected PersistableBundle validateMetrics(String codec, MediaFormat format) {
1601         PersistableBundle metrics = validateMetrics(codec);
1602         if (mIsVideo) {
1603             assertEquals("error! metrics#MetricsConstants.WIDTH is not as expected\n" + mTestConfig
1604                             + mTestEnv, metrics.getInt(MediaCodec.MetricsConstants.WIDTH),
1605                     getWidth(format));
1606             assertEquals("error! metrics#MetricsConstants.HEIGHT is not as expected\n" + mTestConfig
1607                             + mTestEnv, metrics.getInt(MediaCodec.MetricsConstants.HEIGHT),
1608                     getHeight(format));
1609         }
1610         assertEquals("error! metrics#MetricsConstants.SECURE is not as expected\n" + mTestConfig
1611                 + mTestEnv, 0, metrics.getInt(MediaCodec.MetricsConstants.SECURE));
1612         return metrics;
1613     }
1614 
validateColorAspects(MediaFormat fmt, int range, int standard, int transfer)1615     public void validateColorAspects(MediaFormat fmt, int range, int standard, int transfer) {
1616         int colorRange = fmt.getInteger(MediaFormat.KEY_COLOR_RANGE, UNSPECIFIED);
1617         int colorStandard = fmt.getInteger(MediaFormat.KEY_COLOR_STANDARD, UNSPECIFIED);
1618         int colorTransfer = fmt.getInteger(MediaFormat.KEY_COLOR_TRANSFER, UNSPECIFIED);
1619         if (range > UNSPECIFIED) {
1620             assertEquals("error! color range mismatch \n" + mTestConfig + mTestEnv, range,
1621                     colorRange);
1622         }
1623         if (standard > UNSPECIFIED) {
1624             assertEquals("error! color standard mismatch \n" + mTestConfig + mTestEnv, standard,
1625                     colorStandard);
1626         }
1627         if (transfer > UNSPECIFIED) {
1628             assertEquals("error! color transfer mismatch \n" + mTestConfig + mTestEnv, transfer,
1629                     colorTransfer);
1630         }
1631     }
1632 
validateHDRInfo(String hdrInfoKey, ByteBuffer hdrInfoRef, ByteBuffer hdrInfoTest, Long framePts)1633     protected void validateHDRInfo(String hdrInfoKey, ByteBuffer hdrInfoRef, ByteBuffer hdrInfoTest,
1634             Long framePts) {
1635         if (!hdrInfoRef.equals(hdrInfoTest)) {
1636             StringBuilder msg = new StringBuilder(
1637                     "###################       Error Details         #####################\n");
1638             byte[] ref = new byte[hdrInfoRef.capacity()];
1639             hdrInfoRef.get(ref);
1640             hdrInfoRef.rewind();
1641             byte[] test = new byte[hdrInfoTest.capacity()];
1642             hdrInfoTest.get(test);
1643             hdrInfoTest.rewind();
1644             msg.append("ref info :- \n");
1645             for (byte b : ref) {
1646                 msg.append(String.format("%2x ", b));
1647             }
1648             msg.append("\ntest info :- \n");
1649             for (byte b : test) {
1650                 msg.append(String.format("%2x ", b));
1651             }
1652             fail("Frame pts " + framePts + ": error! mismatch seen between ref and test info of "
1653                     + hdrInfoKey + "\n" + mTestConfig + mTestEnv + msg);
1654         }
1655     }
1656 
validateHDRInfo(MediaFormat fmt, String hdrInfoKey, ByteBuffer hdrInfoRef, Long framePts)1657     protected void validateHDRInfo(MediaFormat fmt, String hdrInfoKey, ByteBuffer hdrInfoRef,
1658             Long framePts) {
1659         ByteBuffer hdrInfo = fmt.getByteBuffer(hdrInfoKey, null);
1660         assertNotNull("error! no " + hdrInfoKey + " present in format : " + fmt + "\n "
1661                 + mTestConfig + mTestEnv, hdrInfo);
1662         validateHDRInfo(hdrInfoKey, hdrInfoRef, hdrInfo, framePts);
1663     }
1664 
setUpSurface(CodecTestActivity activity)1665     protected void setUpSurface(CodecTestActivity activity) throws InterruptedException {
1666         activity.waitTillSurfaceIsCreated();
1667         mSurface = activity.getSurface();
1668         assertNotNull("Surface created is null \n" + mTestConfig + mTestEnv, mSurface);
1669         assertTrue("Surface created is invalid \n" + mTestConfig + mTestEnv, mSurface.isValid());
1670     }
1671 
setUpSurface(int width, int height, int format, int maxImages, int surfaceId, Function<ImageSurface.ImageAndAttributes, Boolean> predicate)1672     protected void setUpSurface(int width, int height, int format, int maxImages,
1673             int surfaceId, Function<ImageSurface.ImageAndAttributes, Boolean> predicate) {
1674         mImageSurface.createSurface(width, height, format, maxImages, surfaceId, predicate);
1675         mSurface = mImageSurface.getSurface();
1676         assertNotNull("Surface created is null \n" + mTestConfig + mTestEnv, mSurface);
1677         assertTrue("Surface created is invalid \n" + mTestConfig + mTestEnv, mSurface.isValid());
1678     }
1679 }
1680