1 /*
2  * Copyright 2023 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.media.mediaediting.cts;
18 
19 import static androidx.media3.common.MimeTypes.VIDEO_H264;
20 import static androidx.media3.common.MimeTypes.VIDEO_H265;
21 import static androidx.media3.common.util.Assertions.checkState;
22 import static androidx.media3.common.util.Assertions.checkStateNotNull;
23 
24 import android.media.MediaExtractor;
25 import android.media.MediaFormat;
26 
27 import androidx.annotation.Nullable;
28 import androidx.media3.common.C;
29 import androidx.media3.common.ColorInfo;
30 import androidx.media3.common.Format;
31 import androidx.media3.common.MimeTypes;
32 
33 import java.io.IOException;
34 
35 /** Utilities for Media Editing tests. */
36 public final class MediaEditingUtil {
37 
38   public static final String MP4_ASSET_H264_WITH_INCREASING_TIMESTAMPS_1920W_1080H_1S_URI_STRING =
39     "sample_with_increasing_timestamps_1920x1080_30fps_avc.mp4";
40 
41   /** Baseline profile level 3.0 H.264 stream, which should be supported on all devices. */
42   public static final String MP4_ASSET_H264_WITH_INCREASING_TIMESTAMPS_320W_240H_5S_URI_STRING =
43     "sample_with_increasing_timestamps_320x240_30fps_avc.mp4";
44 
45   public static final String MP4_ASSET_H264_WITH_INCREASING_TIMESTAMPS_642W_642H_3S_URI_STRING =
46     "bbb_642x642_1mbps_30fps_avc.mp4";
47 
48   public static final String MKV_ASSET_H264_340W_280H_10BIT =
49       "cosmat_340x280_24fps_crf22_avc_10bit.mkv";
50   public static final Format MKV_ASSET_H264_340W_280H_10BIT_FORMAT =
51       new Format.Builder()
52           .setSampleMimeType(VIDEO_H264)
53           .setWidth(340)
54           .setHeight(280)
55           .setFrameRate(24f)
56           .setColorInfo(
57               new ColorInfo.Builder()
58                   .setColorSpace(C.COLOR_SPACE_BT2020)
59                   .setColorRange(C.COLOR_RANGE_LIMITED)
60                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
61                   .build())
62           .setCodecs("avc1.6E000D")
63           .build();
64 
65   public static final String MKV_ASSET_H264_520W_390H_10BIT =
66       "cosmat_520x390_24fps_crf22_avc_10bit.mkv";
67   public static final Format MKV_ASSET_H264_520W_390H_10BIT_FORMAT =
68       new Format.Builder()
69           .setSampleMimeType(VIDEO_H264)
70           .setWidth(520)
71           .setHeight(390)
72           .setFrameRate(24f)
73           .setColorInfo(
74               new ColorInfo.Builder()
75                   .setColorSpace(C.COLOR_SPACE_BT2020)
76                   .setColorRange(C.COLOR_RANGE_LIMITED)
77                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
78                   .build())
79           .setCodecs("avc1.6E0016")
80           .build();
81 
82   public static final String MKV_ASSET_H264_640W_360H_10BIT =
83       "cosmat_640x360_24fps_crf22_avc_10bit_nob.mkv";
84   public static final Format MKV_ASSET_H264_640W_360H_10BIT_FORMAT =
85       new Format.Builder()
86           .setSampleMimeType(VIDEO_H264)
87           .setWidth(640)
88           .setHeight(360)
89           .setFrameRate(24f)
90           .setColorInfo(
91               new ColorInfo.Builder()
92                   .setColorSpace(C.COLOR_SPACE_BT2020)
93                   .setColorRange(C.COLOR_RANGE_LIMITED)
94                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
95                   .build())
96           .setCodecs("avc1.6E001E")
97           .build();
98 
99   public static final String MKV_ASSET_H264_800W_640H_10BIT =
100       "cosmat_800x640_24fps_crf22_avc_10bit_nob.mkv";
101   public static final Format MKV_ASSET_H264_800W_640H_10BIT_FORMAT =
102       new Format.Builder()
103           .setSampleMimeType(VIDEO_H264)
104           .setWidth(800)
105           .setHeight(640)
106           .setFrameRate(24f)
107           .setColorInfo(
108               new ColorInfo.Builder()
109                   .setColorSpace(C.COLOR_SPACE_BT2020)
110                   .setColorRange(C.COLOR_RANGE_LIMITED)
111                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
112                   .build())
113           .setCodecs("avc1.6E001F")
114           .build();
115 
116   public static final String MKV_ASSET_H264_1280W_720H_10BIT =
117       "cosmat_1280x720_24fps_crf22_avc_10bit_nob.mkv";
118   public static final Format MKV_ASSET_H264_1280W_720H_HDR10_FORMAT =
119       new Format.Builder()
120           .setSampleMimeType(VIDEO_H264)
121           .setWidth(1280)
122           .setHeight(720)
123           .setFrameRate(24f)
124           .setColorInfo(
125               new ColorInfo.Builder()
126                   .setColorSpace(C.COLOR_SPACE_BT2020)
127                   .setColorRange(C.COLOR_RANGE_LIMITED)
128                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
129                   .build())
130           .setCodecs("avc1.6E001F")
131           .build();
132 
133   public static final String MP4_ASSET_HEVC_WITH_INCREASING_TIMESTAMPS_1920_1080_1S_URI_STRING =
134     "bbb_1920x1080_30fps_hevc_main_l40.mp4";
135 
136   public static final String MP4_ASSET_HEVC_WITH_INCREASING_TIMESTAMPS_720W_480H_1S_URI_STRING =
137     "bbb_720x480_30fps_hevc_main_l3.mp4";
138 
139   public static final String MP4_ASSET_HEVC_WITH_INCREASING_TIMESTAMPS_642W_642H_3S_URI_STRING =
140     "bbb_642x642_768kbps_30fps_hevc.mp4";
141 
142   public static final String MKV_ASSET_HEVC_340W_280H_5S_10BIT =
143       "cosmat_340x280_24fps_crf22_hevc_10bit.mkv";
144   public static final Format MKV_ASSET_HEVC_340W_280H_10BIT_FORMAT =
145       new Format.Builder()
146           .setSampleMimeType(VIDEO_H265)
147           .setWidth(340)
148           .setHeight(280)
149           .setFrameRate(24f)
150           .setColorInfo(
151               new ColorInfo.Builder()
152                   .setColorSpace(C.COLOR_SPACE_BT2020)
153                   .setColorRange(C.COLOR_RANGE_LIMITED)
154                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
155                   .build())
156           .setCodecs("hvc1.2.4.L60.90")
157           .build();
158 
159   public static final String MKV_ASSET_HEVC_520W_390H_5S_10BIT =
160       "cosmat_520x390_24fps_crf22_hevc_10bit.mkv";
161   public static final Format MKV_ASSET_HEVC_520W_390H_10BIT_FORMAT =
162       new Format.Builder()
163           .setSampleMimeType(VIDEO_H265)
164           .setWidth(520)
165           .setHeight(390)
166           .setFrameRate(24f)
167           .setColorInfo(
168               new ColorInfo.Builder()
169                   .setColorSpace(C.COLOR_SPACE_BT2020)
170                   .setColorRange(C.COLOR_RANGE_LIMITED)
171                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
172                   .build())
173           .setCodecs("hvc1.2.4.L63.90")
174           .build();
175 
176   public static final String MKV_ASSET_HEVC_640W_360H_5S_10BIT =
177       "cosmat_640x360_24fps_crf22_hevc_10bit_nob.mkv";
178   public static final Format MKV_ASSET_HEVC_640W_360H_10BIT_FORMAT =
179       new Format.Builder()
180           .setSampleMimeType(VIDEO_H265)
181           .setWidth(640)
182           .setHeight(360)
183           .setFrameRate(24f)
184           .setColorInfo(
185               new ColorInfo.Builder()
186                   .setColorSpace(C.COLOR_SPACE_BT2020)
187                   .setColorRange(C.COLOR_RANGE_LIMITED)
188                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
189                   .build())
190           .setCodecs("hvc1.2.4.L63.90")
191           .build();
192 
193   public static final String MKV_ASSET_HEVC_800W_640H_5S_10BIT =
194       "cosmat_800x640_24fps_crf22_hevc_10bit_nob.mkv";
195   public static final Format MKV_ASSET_HEVC_800W_640H_10BIT_FORMAT =
196       new Format.Builder()
197           .setSampleMimeType(VIDEO_H265)
198           .setWidth(800)
199           .setHeight(640)
200           .setFrameRate(24f)
201           .setColorInfo(
202               new ColorInfo.Builder()
203                   .setColorSpace(C.COLOR_SPACE_BT2020)
204                   .setColorRange(C.COLOR_RANGE_LIMITED)
205                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
206                   .build())
207           .setCodecs("hvc1.2.4.L90.90")
208           .build();
209 
210   public static final String MKV_ASSET_HEVC_1280W_720H_5S_10BIT =
211       "cosmat_1280x720_24fps_crf22_hevc_10bit_nob.mkv";
212   public static final Format MKV_ASSET_HEVC_1280W_720H_10BIT_FORMAT =
213       new Format.Builder()
214           .setSampleMimeType(VIDEO_H265)
215           .setWidth(1280)
216           .setHeight(720)
217           .setFrameRate(24f)
218           .setColorInfo(
219               new ColorInfo.Builder()
220                   .setColorSpace(C.COLOR_SPACE_BT2020)
221                   .setColorRange(C.COLOR_RANGE_LIMITED)
222                   .setColorTransfer(C.COLOR_TRANSFER_HLG)
223                   .build())
224           .setCodecs("hvc1.2.4.L93.90")
225           .build();
226 
227   /**
228    * Returns the {@link Format} of the given test asset.
229    *
230    * @param uri The string {@code uri} to the test file. The {@code uri} must be defined in this
231    *     file.
232    * @throws IllegalArgumentException If the given {@code uri} is not defined in this file.
233    */
getFormatForTestFile(String uri)234   public static Format getFormatForTestFile(String uri) {
235     switch (uri) {
236       case MKV_ASSET_H264_340W_280H_10BIT:
237         return MKV_ASSET_H264_340W_280H_10BIT_FORMAT;
238       case MKV_ASSET_H264_520W_390H_10BIT:
239         return MKV_ASSET_H264_520W_390H_10BIT_FORMAT;
240       case MKV_ASSET_H264_640W_360H_10BIT:
241         return MKV_ASSET_H264_640W_360H_10BIT_FORMAT;
242       case MKV_ASSET_H264_800W_640H_10BIT:
243         return MKV_ASSET_H264_800W_640H_10BIT_FORMAT;
244       case MKV_ASSET_H264_1280W_720H_10BIT:
245         return MKV_ASSET_H264_1280W_720H_HDR10_FORMAT;
246       case MKV_ASSET_HEVC_340W_280H_5S_10BIT:
247         return MKV_ASSET_HEVC_340W_280H_10BIT_FORMAT;
248       case MKV_ASSET_HEVC_520W_390H_5S_10BIT:
249         return MKV_ASSET_HEVC_520W_390H_10BIT_FORMAT;
250       case MKV_ASSET_HEVC_640W_360H_5S_10BIT:
251         return MKV_ASSET_HEVC_640W_360H_10BIT_FORMAT;
252       case MKV_ASSET_HEVC_800W_640H_5S_10BIT:
253         return MKV_ASSET_HEVC_800W_640H_10BIT_FORMAT;
254       case MKV_ASSET_HEVC_1280W_720H_5S_10BIT:
255         return MKV_ASSET_HEVC_1280W_720H_10BIT_FORMAT;
256       default:
257         throw new IllegalArgumentException("The format for the given uri is not found.");
258     }
259   }
260 
261   public static final String MP4_ASSET_HEVC_WITH_INCREASING_TIMESTAMPS_608W_1080H_4S_URI_STRING =
262       "video_decode_accuracy_and_capability-hevc_608x1080_30fps.mp4";
263 
getMuxedWidthHeight(String filePath)264   public static Format getMuxedWidthHeight(String filePath) throws IOException {
265     MediaExtractor mediaExtractor = new MediaExtractor();
266     mediaExtractor.setDataSource(filePath);
267     @Nullable MediaFormat mediaFormat = null;
268     for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
269       if (MimeTypes.isVideo(mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME))) {
270         mediaFormat = mediaExtractor.getTrackFormat(i);
271         mediaExtractor.selectTrack(i);
272         break;
273       }
274     }
275 
276     checkStateNotNull(mediaFormat);
277     checkState(mediaFormat.containsKey(MediaFormat.KEY_WIDTH));
278     checkState(mediaFormat.containsKey(MediaFormat.KEY_HEIGHT));
279 
280     int rotationDegree = 0;
281     if (mediaFormat.containsKey(MediaFormat.KEY_ROTATION)) {
282       rotationDegree = mediaFormat.getInteger(MediaFormat.KEY_ROTATION);
283     }
284     return new Format.Builder()
285         .setWidth(mediaFormat.getInteger(MediaFormat.KEY_WIDTH))
286         .setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT))
287         .setRotationDegrees(rotationDegree)
288         .build();
289   }
290 
getMuxedOutputProfile(String filePath)291   public static int getMuxedOutputProfile(String filePath) throws IOException {
292     MediaExtractor mediaExtractor = new MediaExtractor();
293     mediaExtractor.setDataSource(filePath);
294     @Nullable MediaFormat mediaFormat = null;
295     for (int i = 0; i < mediaExtractor.getTrackCount(); i++) {
296       if (MimeTypes.isVideo(mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME))) {
297         mediaFormat = mediaExtractor.getTrackFormat(i);
298         mediaExtractor.selectTrack(i);
299         break;
300       }
301     }
302 
303     checkStateNotNull(mediaFormat);
304     checkState(mediaFormat.containsKey(MediaFormat.KEY_PROFILE));
305     return mediaFormat.getInteger(MediaFormat.KEY_PROFILE, -1);
306   }
307 }
308