1 /*
2  * Copyright (C) 2021 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.video.cts;
18 
19 import android.media.MediaFormat;
20 import android.util.Log;
21 
22 import androidx.test.filters.LargeTest;
23 
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.junit.runners.Parameterized;
27 
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.List;
33 
34 import static org.junit.Assert.assertTrue;
35 
36 /**
37  * Operating rate is expected to be met by encoder only in surface mode and not in byte buffer mode.
38  * As camera has limited frame rates and resolutions, it is not possible to test encoder
39  * operating rate alone. So we are going ahead with transcode tests as a way to verify
40  * encoder performances. This test calls decoder to decode to a surface that is coupled to encoder.
41  * This assumes encoder will not be faster than decode and expects half the operating rate
42  * to be met for encoders.
43  */
44 @RunWith(Parameterized.class)
45 public class CodecEncoderPerformanceTest extends CodecEncoderPerformanceTestBase {
46     private static final String LOG_TAG = CodecEncoderPerformanceTest.class.getSimpleName();
47 
CodecEncoderPerformanceTest(String decoderName, String testFile, String encoderMime, String encoderName, int bitrate, int keyPriority, float scalingFactor)48     public CodecEncoderPerformanceTest(String decoderName, String testFile, String encoderMime,
49             String encoderName, int bitrate, int keyPriority, float scalingFactor) {
50         super(decoderName, testFile, encoderMime, encoderName, bitrate, keyPriority, scalingFactor);
51     }
52 
53     @Parameterized.Parameters(name = "{index}({0}_{2}_{3}_{5}_{6})")
input()54     public static Collection<Object[]> input() throws IOException {
55         final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
56                 // Filename, Recommended AVC bitrate
57                 {"crowd_run_720x480_30fps_avc.mp4", 2000000},
58                 {"crowd_run_1280x720_30fps_avc.mp4", 4000000},
59                 {"crowd_run_1920x1080_30fps_avc.mp4", 8000000},
60                 {"crowd_run_3840x2160_30fps_hevc.mp4", 20000000},
61                 // TODO (b/194721211) Enable 8k tests
62                 //{"crowd_run_7680x4320_30fps_hevc.mp4", 40000000},
63         });
64         // Prepares the params list with the supported Hardware decoder, encoders in the device
65         // combined with the key priority and scaling factor
66         final List<Object[]> argsList = new ArrayList<>();
67         for (Object[] arg : exhaustiveArgsList) {
68             // Gets the format for the first video track found
69             MediaFormat format = getVideoFormat((String) arg[0]);
70             if (format == null) {
71                 Log.e(LOG_TAG, "Test vector is ignored as it has no video tracks present " +
72                         "in the file: " + ((String) arg[0]));
73                 continue;
74             }
75             String decoderMime = format.getString(MediaFormat.KEY_MIME);
76             ArrayList<MediaFormat> formatsList = new ArrayList<>();
77             formatsList.add(format);
78             ArrayList<String> listOfDecoders = selectHardwareCodecs(decoderMime, formatsList,
79                     null, false);
80             if (listOfDecoders.size() == 0) continue;
81             String decoder = listOfDecoders.get(0);
82             for (String encoderMime : getMimesOfAvailableHardwareVideoEncoders()) {
83                 // Calculate the bitrate based on the encode mime.
84                 int bitrate = (int)(((int) arg[1]) * getBitrateScalingFactor(encoderMime));
85                 MediaFormat mockFmt = setUpEncoderFormat(format, encoderMime, bitrate);
86                 ArrayList<MediaFormat> mockFmtList = new ArrayList<>();
87                 mockFmtList.add(mockFmt);
88                 ArrayList<String> listOfEncoders = selectHardwareCodecs(encoderMime, mockFmtList,
89                         null, true);
90                 for (String encoder : listOfEncoders) {
91                     for (int keyPriority : KEY_PRIORITIES_LIST) {
92                         for (float scalingFactor : SCALING_FACTORS_LIST) {
93                             if (keyPriority == 1 || (scalingFactor > 0.0 && scalingFactor <= 1.0)) {
94                                 argsList.add(new Object[]{decoder, arg[0], encoderMime, encoder,
95                                         bitrate, keyPriority, scalingFactor});
96                             }
97                         }
98                     }
99                 }
100             }
101         }
102         return argsList;
103     }
104 
105     /**
106      * Validates performance of hardware accelerated video encoders
107      */
108     @LargeTest
109     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
testPerformanceOfHardwareVideoEncoders()110     public void testPerformanceOfHardwareVideoEncoders() throws IOException {
111         encode();
112         String log = String.format("DecodeMime: %s, Decoder: %s, resolution: %dp, EncodeMime: %s," +
113                 " Encoder: %s, Key-priority: %d :: ", mDecoderMime, mDecoderName, mHeight,
114                 mEncoderMime, mEncoderName, mKeyPriority);
115         int maxExpectedFps = getMaxExpectedFps(mWidth, mHeight);
116         double expectedFps =
117                 Math.min(mOperatingRateExpected * FPS_TOLERANCE_FACTOR, maxExpectedFps);
118         Log.d(LOG_TAG, log + "act/exp fps: " + mAchievedFps + "/" + expectedFps);
119         assertTrue("Unable to achieve the expected rate. " + log + "act/exp fps: " + mAchievedFps
120                 + "/" + expectedFps, mAchievedFps >= expectedFps);
121     }
122 }
123