1 /*
2  * Copyright (C) 2013 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.graphics.ImageFormat;
20 import android.graphics.Point;
21 import android.media.Image;
22 import android.media.Image.Plane;
23 import android.media.MediaCodec;
24 import android.media.MediaCodec.BufferInfo;
25 import android.media.MediaCodecInfo;
26 import android.media.MediaCodecInfo.CodecCapabilities;
27 import android.media.MediaFormat;
28 import android.media.cts.CodecImage;
29 import android.media.cts.CodecUtils;
30 import android.media.cts.YUVImage;
31 import android.os.Build;
32 import android.util.Log;
33 import android.util.Pair;
34 import android.util.Range;
35 
36 import com.android.compatibility.common.util.CtsAndroidTestCase;
37 import com.android.compatibility.common.util.DeviceReportLog;
38 import com.android.compatibility.common.util.MediaPerfUtils;
39 import com.android.compatibility.common.util.MediaUtils;
40 import com.android.compatibility.common.util.ResultType;
41 import com.android.compatibility.common.util.ResultUnit;
42 import com.android.compatibility.common.util.Stat;
43 
44 import java.io.IOException;
45 import java.nio.ByteBuffer;
46 import java.util.Arrays;
47 import java.util.LinkedList;
48 import java.util.Random;
49 import java.util.Scanner;
50 
51 /**
52  * This tries to test video encoder / decoder performance by running encoding / decoding
53  * without displaying the raw data. To make things simpler, encoder is used to encode synthetic
54  * data and decoder is used to decode the encoded video. This approach does not work where
55  * there is only decoder. Performance index is total time taken for encoding and decoding
56  * the whole frames.
57  * To prevent sacrificing quality for faster encoding / decoding, randomly selected pixels are
58  * compared with the original image. As the pixel comparison can slow down the decoding process,
59  * only some randomly selected pixels are compared. As there can be only one performance index,
60  * error above certain threshold in pixel value will be treated as an error.
61  */
62 public class VideoEncoderDecoderTest extends CtsAndroidTestCase {
63     private static final String TAG = "VideoEncoderDecoderTest";
64     private static final String REPORT_LOG_NAME = "CtsVideoTestCases";
65     // this wait time affects fps as too big value will work as a blocker if device fps
66     // is not very high.
67     private static final long VIDEO_CODEC_WAIT_TIME_US = 1000;
68     private static final boolean VERBOSE = false;
69     private static final int MAX_FPS = 30; // measure performance at 30fps, this is relevant for
70                                            // the meaning of bitrate
71 
72     private static final String AVC = MediaFormat.MIMETYPE_VIDEO_AVC;
73     private static final String H263 = MediaFormat.MIMETYPE_VIDEO_H263;
74     private static final String HEVC = MediaFormat.MIMETYPE_VIDEO_HEVC;
75     private static final String MPEG2 = MediaFormat.MIMETYPE_VIDEO_MPEG2;
76     private static final String MPEG4 = MediaFormat.MIMETYPE_VIDEO_MPEG4;
77     private static final String VP8 = MediaFormat.MIMETYPE_VIDEO_VP8;
78     private static final String VP9 = MediaFormat.MIMETYPE_VIDEO_VP9;
79 
80     private static final boolean GOOG = true;
81     private static final boolean OTHER = false;
82 
83     // test results:
84 
85     private int mCurrentTestRound = 0;
86     private double[][] mEncoderFrameTimeUsDiff;
87     private double[] mEncoderFpsResults;
88 
89     private double[][] mDecoderFrameTimeUsDiff;
90     private double[] mDecoderFpsResults;
91     private double[] mTotalFpsResults;
92     private double[] mDecoderRmsErrorResults;
93 
94     // i frame interval for encoder
95     private static final int KEY_I_FRAME_INTERVAL = 5;
96     private static final int MAX_TEST_TIMEOUT_MS = 300000;   // 5 minutes
97 
98     private static final int Y_CLAMP_MIN = 16;
99     private static final int Y_CLAMP_MAX = 235;
100     private static final int YUV_PLANE_ADDITIONAL_LENGTH = 200;
101     private ByteBuffer mYBuffer, mYDirectBuffer;
102     private ByteBuffer mUVBuffer, mUVDirectBuffer;
103     private int mSrcColorFormat;
104     private int mDstColorFormat;
105     private int mBufferWidth;
106     private int mBufferHeight;
107     private int mVideoWidth;
108     private int mVideoHeight;
109     private int mVideoStride;
110     private int mVideoVStride;
111     private int mFrameRate;
112 
113     private MediaFormat mEncConfigFormat;
114     private MediaFormat mEncInputFormat;
115     private MediaFormat mEncOutputFormat;
116     private MediaFormat mDecOutputFormat;
117 
118     private LinkedList<Pair<ByteBuffer, BufferInfo>> mEncodedOutputBuffer;
119     // check this many pixels per each decoded frame
120     // checking too many points decreases decoder frame rates a lot.
121     private static final int PIXEL_CHECK_PER_FRAME = 1000;
122     // RMS error in pixel values above this will be treated as error.
123     private static final double PIXEL_RMS_ERROR_MARGIN = 20.0;
124     private double mRmsErrorMargin;
125     private Random mRandom;
126 
127     private class TestConfig {
128         public boolean mTestPixels = true;
129         public boolean mReportFrameTime = false;
130         public int mTotalFrames = 300;
131         public int mMinNumFrames = 300;
132         public int mMaxTimeMs = 120000;  // 2 minutes
133         public int mMinTimeMs = 10000;   // 10 seconds
134         public int mNumberOfRepeat = 10;
135 
initPerfTest()136         public void initPerfTest() {
137             mTestPixels = false;
138             mTotalFrames = 30000;
139             mMinNumFrames = 3000;
140             mNumberOfRepeat = 2;
141         }
142     }
143 
144     private TestConfig mTestConfig;
145 
146     // Performance numbers only make sense on real devices, so skip on non-real devices
frankenDevice()147     public static boolean frankenDevice() throws IOException {
148         String systemBrand = getProperty("ro.product.system.brand");
149         String systemModel = getProperty("ro.product.system.model");
150         String systemProduct = getProperty("ro.product.system.name");
151         if (("Android".equals(systemBrand) || "generic".equals(systemBrand)) &&
152             (systemModel.startsWith("AOSP on ") || systemProduct.startsWith("aosp_"))) {
153             return true;
154         }
155         return false;
156     }
157 
getProperty(String property)158     private static String getProperty(String property) throws IOException {
159         Process process = new ProcessBuilder("getprop", property).start();
160         Scanner scanner = null;
161         String line = "";
162         try {
163             scanner = new Scanner(process.getInputStream());
164             line = scanner.nextLine();
165         } finally {
166             if (scanner != null) {
167                 scanner.close();
168             }
169         }
170         return line;
171     }
172 
173     @Override
setUp()174     protected void setUp() throws Exception {
175         mEncodedOutputBuffer = new LinkedList<Pair<ByteBuffer, BufferInfo>>();
176         mRmsErrorMargin = PIXEL_RMS_ERROR_MARGIN;
177         // Use time as a seed, hoping to prevent checking pixels in the same pattern
178         long now = System.currentTimeMillis();
179         mRandom = new Random(now);
180         mTestConfig = new TestConfig();
181         super.setUp();
182     }
183 
184     @Override
tearDown()185     protected void tearDown() throws Exception {
186         mEncodedOutputBuffer.clear();
187         mEncodedOutputBuffer = null;
188         mYBuffer = null;
189         mUVBuffer = null;
190         mYDirectBuffer = null;
191         mUVDirectBuffer = null;
192         mRandom = null;
193         mTestConfig = null;
194         super.tearDown();
195     }
196 
count(String mime, int width, int height, int numGoog, int numOther)197     private void count(String mime, int width, int height, int numGoog, int numOther)
198             throws Exception {
199         MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
200         MediaUtils.verifyNumCodecs(numGoog,  true /* isEncoder */, true /* isGoog */,  format);
201         MediaUtils.verifyNumCodecs(numOther, true /* isEncoder */, false /* isGoog */, format);
202     }
203 
204     /** run performance test. */
perf(String mimeType, int w, int h, boolean isGoog, int ix)205     private void perf(String mimeType, int w, int h, boolean isGoog, int ix) throws Exception {
206         doTest(mimeType, w, h, true /* isPerf */, isGoog, ix);
207     }
208 
209     /** run quality test. */
qual(String mimeType, int w, int h, boolean isGoog, int ix)210     private void qual(String mimeType, int w, int h, boolean isGoog, int ix) throws Exception {
211         doTest(mimeType, w, h, false /* isPerf */, isGoog, ix);
212     }
213 
214     /** run quality test but do not report error. */
qual(String mimeType, int w, int h, boolean isGoog, int ix, double margin)215     private void qual(String mimeType, int w, int h, boolean isGoog, int ix, double margin)
216             throws Exception {
217         mRmsErrorMargin = margin;
218         doTest(mimeType, w, h, false /* isPerf */, isGoog, ix);
219     }
220 
221     // Poor man's Parametrized test as this test must still run on CTSv1 runner.
222 
223     // The count tests are to ensure this Cts test covers all encoders. Add further
224     // tests and change the count if there can be more encoders.
225 
226     // AVC tests
testAvcCount0320x0240()227     public void testAvcCount0320x0240() throws Exception { count(AVC, 320, 240, 2, 4); }
testAvcGoog0Qual0320x0240()228     public void testAvcGoog0Qual0320x0240() throws Exception { qual(AVC, 320, 240, GOOG, 0); }
testAvcGoog0Perf0320x0240()229     public void testAvcGoog0Perf0320x0240() throws Exception { perf(AVC, 320, 240, GOOG, 0); }
testAvcGoog1Qual0320x0240()230     public void testAvcGoog1Qual0320x0240() throws Exception { qual(AVC, 320, 240, GOOG, 1); }
testAvcGoog1Perf0320x0240()231     public void testAvcGoog1Perf0320x0240() throws Exception { perf(AVC, 320, 240, GOOG, 1); }
232 
testAvcOther0Qual0320x0240()233     public void testAvcOther0Qual0320x0240() throws Exception { qual(AVC, 320, 240, OTHER, 0); }
testAvcOther0Perf0320x0240()234     public void testAvcOther0Perf0320x0240() throws Exception { perf(AVC, 320, 240, OTHER, 0); }
testAvcOther1Qual0320x0240()235     public void testAvcOther1Qual0320x0240() throws Exception { qual(AVC, 320, 240, OTHER, 1); }
testAvcOther1Perf0320x0240()236     public void testAvcOther1Perf0320x0240() throws Exception { perf(AVC, 320, 240, OTHER, 1); }
testAvcOther2Qual0320x0240()237     public void testAvcOther2Qual0320x0240() throws Exception { qual(AVC, 320, 240, OTHER, 2); }
testAvcOther2Perf0320x0240()238     public void testAvcOther2Perf0320x0240() throws Exception { perf(AVC, 320, 240, OTHER, 2); }
testAvcOther3Qual0320x0240()239     public void testAvcOther3Qual0320x0240() throws Exception { qual(AVC, 320, 240, OTHER, 3); }
testAvcOther3Perf0320x0240()240     public void testAvcOther3Perf0320x0240() throws Exception { perf(AVC, 320, 240, OTHER, 3); }
testAvcCount0720x0480()241     public void testAvcCount0720x0480() throws Exception { count(AVC, 720, 480, 2, 4); }
testAvcGoog0Qual0720x0480()242     public void testAvcGoog0Qual0720x0480() throws Exception { qual(AVC, 720, 480, GOOG, 0); }
testAvcGoog0Perf0720x0480()243     public void testAvcGoog0Perf0720x0480() throws Exception { perf(AVC, 720, 480, GOOG, 0); }
testAvcGoog1Qual0720x0480()244     public void testAvcGoog1Qual0720x0480() throws Exception { qual(AVC, 720, 480, GOOG, 1); }
testAvcGoog1Perf0720x0480()245     public void testAvcGoog1Perf0720x0480() throws Exception { perf(AVC, 720, 480, GOOG, 1); }
246 
testAvcOther0Qual0720x0480()247     public void testAvcOther0Qual0720x0480() throws Exception { qual(AVC, 720, 480, OTHER, 0); }
testAvcOther0Perf0720x0480()248     public void testAvcOther0Perf0720x0480() throws Exception { perf(AVC, 720, 480, OTHER, 0); }
testAvcOther1Qual0720x0480()249     public void testAvcOther1Qual0720x0480() throws Exception { qual(AVC, 720, 480, OTHER, 1); }
testAvcOther1Perf0720x0480()250     public void testAvcOther1Perf0720x0480() throws Exception { perf(AVC, 720, 480, OTHER, 1); }
testAvcOther2Qual0720x0480()251     public void testAvcOther2Qual0720x0480() throws Exception { qual(AVC, 720, 480, OTHER, 2); }
testAvcOther2Perf0720x0480()252     public void testAvcOther2Perf0720x0480() throws Exception { perf(AVC, 720, 480, OTHER, 2); }
testAvcOther3Qual0720x0480()253     public void testAvcOther3Qual0720x0480() throws Exception { qual(AVC, 720, 480, OTHER, 3); }
testAvcOther3Perf0720x0480()254     public void testAvcOther3Perf0720x0480() throws Exception { perf(AVC, 720, 480, OTHER, 3); }
testAvcCount1280x0720()255     public void testAvcCount1280x0720() throws Exception { count(AVC, 1280, 720, 2, 4); }
testAvcGoog0Qual1280x0720()256     public void testAvcGoog0Qual1280x0720() throws Exception { qual(AVC, 1280, 720, GOOG, 0); }
testAvcGoog0Perf1280x0720()257     public void testAvcGoog0Perf1280x0720() throws Exception { perf(AVC, 1280, 720, GOOG, 0); }
testAvcGoog1Qual1280x0720()258     public void testAvcGoog1Qual1280x0720() throws Exception { qual(AVC, 1280, 720, GOOG, 1); }
testAvcGoog1Perf1280x0720()259     public void testAvcGoog1Perf1280x0720() throws Exception { perf(AVC, 1280, 720, GOOG, 1); }
260 
testAvcOther0Qual1280x0720()261     public void testAvcOther0Qual1280x0720() throws Exception { qual(AVC, 1280, 720, OTHER, 0); }
testAvcOther0Perf1280x0720()262     public void testAvcOther0Perf1280x0720() throws Exception { perf(AVC, 1280, 720, OTHER, 0); }
testAvcOther1Qual1280x0720()263     public void testAvcOther1Qual1280x0720() throws Exception { qual(AVC, 1280, 720, OTHER, 1); }
testAvcOther1Perf1280x0720()264     public void testAvcOther1Perf1280x0720() throws Exception { perf(AVC, 1280, 720, OTHER, 1); }
testAvcOther2Qual1280x0720()265     public void testAvcOther2Qual1280x0720() throws Exception { qual(AVC, 1280, 720, OTHER, 2); }
testAvcOther2Perf1280x0720()266     public void testAvcOther2Perf1280x0720() throws Exception { perf(AVC, 1280, 720, OTHER, 2); }
testAvcOther3Qual1280x0720()267     public void testAvcOther3Qual1280x0720() throws Exception { qual(AVC, 1280, 720, OTHER, 3); }
testAvcOther3Perf1280x0720()268     public void testAvcOther3Perf1280x0720() throws Exception { perf(AVC, 1280, 720, OTHER, 3); }
testAvcCount1920x1080()269     public void testAvcCount1920x1080() throws Exception { count(AVC, 1920, 1080, 2, 4); }
testAvcGoog0Qual1920x1080()270     public void testAvcGoog0Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, GOOG, 0); }
testAvcGoog0Perf1920x1080()271     public void testAvcGoog0Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, GOOG, 0); }
testAvcGoog1Qual1920x1080()272     public void testAvcGoog1Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, GOOG, 1); }
testAvcGoog1Perf1920x1080()273     public void testAvcGoog1Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, GOOG, 1); }
274 
testAvcOther0Qual1920x1080()275     public void testAvcOther0Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, OTHER, 0); }
testAvcOther0Perf1920x1080()276     public void testAvcOther0Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, OTHER, 0); }
testAvcOther1Qual1920x1080()277     public void testAvcOther1Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, OTHER, 1); }
testAvcOther1Perf1920x1080()278     public void testAvcOther1Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, OTHER, 1); }
testAvcOther2Qual1920x1080()279     public void testAvcOther2Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, OTHER, 2); }
testAvcOther2Perf1920x1080()280     public void testAvcOther2Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, OTHER, 2); }
testAvcOther3Qual1920x1080()281     public void testAvcOther3Qual1920x1080() throws Exception { qual(AVC, 1920, 1080, OTHER, 3); }
testAvcOther3Perf1920x1080()282     public void testAvcOther3Perf1920x1080() throws Exception { perf(AVC, 1920, 1080, OTHER, 3); }
283 
284     // H263 tests
testH263Count0176x0144()285     public void testH263Count0176x0144() throws Exception { count(H263, 176, 144, 2, 2); }
testH263Goog0Qual0176x0144()286     public void testH263Goog0Qual0176x0144() throws Exception { qual(H263, 176, 144, GOOG, 0); }
testH263Goog0Perf0176x0144()287     public void testH263Goog0Perf0176x0144() throws Exception { perf(H263, 176, 144, GOOG, 0); }
testH263Goog1Qual0176x0144()288     public void testH263Goog1Qual0176x0144() throws Exception { qual(H263, 176, 144, GOOG, 1); }
testH263Goog1Perf0176x0144()289     public void testH263Goog1Perf0176x0144() throws Exception { perf(H263, 176, 144, GOOG, 1); }
290 
testH263Other0Qual0176x0144()291     public void testH263Other0Qual0176x0144() throws Exception { qual(H263, 176, 144, OTHER, 0); }
testH263Other0Perf0176x0144()292     public void testH263Other0Perf0176x0144() throws Exception { perf(H263, 176, 144, OTHER, 0); }
testH263Other1Qual0176x0144()293     public void testH263Other1Qual0176x0144() throws Exception { qual(H263, 176, 144, OTHER, 1); }
testH263Other1Perf0176x0144()294     public void testH263Other1Perf0176x0144() throws Exception { perf(H263, 176, 144, OTHER, 1); }
testH263Count0352x0288()295     public void testH263Count0352x0288() throws Exception { count(H263, 352, 288, 2, 2); }
testH263Goog0Qual0352x0288()296     public void testH263Goog0Qual0352x0288() throws Exception { qual(H263, 352, 288, GOOG, 0); }
testH263Goog0Perf0352x0288()297     public void testH263Goog0Perf0352x0288() throws Exception { perf(H263, 352, 288, GOOG, 0); }
testH263Goog1Qual0352x0288()298     public void testH263Goog1Qual0352x0288() throws Exception { qual(H263, 352, 288, GOOG, 1); }
testH263Goog1Perf0352x0288()299     public void testH263Goog1Perf0352x0288() throws Exception { perf(H263, 352, 288, GOOG, 1); }
300 
testH263Other0Qual0352x0288()301     public void testH263Other0Qual0352x0288() throws Exception { qual(H263, 352, 288, OTHER, 0); }
testH263Other0Perf0352x0288()302     public void testH263Other0Perf0352x0288() throws Exception { perf(H263, 352, 288, OTHER, 0); }
testH263Other1Qual0352x0288()303     public void testH263Other1Qual0352x0288() throws Exception { qual(H263, 352, 288, OTHER, 1); }
testH263Other1Perf0352x0288()304     public void testH263Other1Perf0352x0288() throws Exception { perf(H263, 352, 288, OTHER, 1); }
testH263Count0704x0576()305     public void testH263Count0704x0576() throws Exception { count(H263, 704, 576, 2, 2); }
testH263Goog0Qual0704x0576()306     public void testH263Goog0Qual0704x0576() throws Exception { qual(H263, 704, 576, GOOG, 0, 25); }
testH263Goog0Perf0704x0576()307     public void testH263Goog0Perf0704x0576() throws Exception { perf(H263, 704, 576, GOOG, 0); }
testH263Other0Qual0704x0576()308     public void testH263Other0Qual0704x0576() throws Exception { qual(H263, 704, 576, OTHER, 0, 25); }
testH263Other0Perf0704x0576()309     public void testH263Other0Perf0704x0576() throws Exception { perf(H263, 704, 576, OTHER, 0); }
testH263Other1Qual0704x0576()310     public void testH263Other1Qual0704x0576() throws Exception { qual(H263, 704, 576, OTHER, 1, 25); }
testH263Other1Perf0704x0576()311     public void testH263Other1Perf0704x0576() throws Exception { perf(H263, 704, 576, OTHER, 1); }
testH263Count1408x1152()312     public void testH263Count1408x1152() throws Exception { count(H263, 1408, 1152, 2, 2); }
testH263Goog0Qual1408x1152()313     public void testH263Goog0Qual1408x1152() throws Exception { qual(H263, 1408, 1152, GOOG, 0, 25); }
testH263Goog0Perf1408x1152()314     public void testH263Goog0Perf1408x1152() throws Exception { perf(H263, 1408, 1152, GOOG, 0); }
testH263Other0Qual1408x1152()315     public void testH263Other0Qual1408x1152() throws Exception { qual(H263, 1408, 1152, OTHER, 0, 25); }
testH263Other0Perf1408x1152()316     public void testH263Other0Perf1408x1152() throws Exception { perf(H263, 1408, 1152, OTHER, 0); }
testH263Other1Qual1408x1152()317     public void testH263Other1Qual1408x1152() throws Exception { qual(H263, 1408, 1152, OTHER, 1, 25); }
testH263Other1Perf1408x1152()318     public void testH263Other1Perf1408x1152() throws Exception { perf(H263, 1408, 1152, OTHER, 1); }
319 
320     // HEVC tests
testHevcCount0320x0240()321     public void testHevcCount0320x0240() throws Exception { count(HEVC, 320, 240, 2, 4); }
testHevcGoog0Qual0320x0240()322     public void testHevcGoog0Qual0320x0240() throws Exception { qual(HEVC, 320, 240, GOOG, 0); }
testHevcGoog0Perf0320x0240()323     public void testHevcGoog0Perf0320x0240() throws Exception { perf(HEVC, 320, 240, GOOG, 0); }
testHevcGoog1Qual0320x0240()324     public void testHevcGoog1Qual0320x0240() throws Exception { qual(HEVC, 320, 240, GOOG, 1); }
testHevcGoog1Perf0320x0240()325     public void testHevcGoog1Perf0320x0240() throws Exception { perf(HEVC, 320, 240, GOOG, 1); }
326 
testHevcOther0Qual0320x0240()327     public void testHevcOther0Qual0320x0240() throws Exception { qual(HEVC, 320, 240, OTHER, 0); }
testHevcOther0Perf0320x0240()328     public void testHevcOther0Perf0320x0240() throws Exception { perf(HEVC, 320, 240, OTHER, 0); }
testHevcOther1Qual0320x0240()329     public void testHevcOther1Qual0320x0240() throws Exception { qual(HEVC, 320, 240, OTHER, 1); }
testHevcOther1Perf0320x0240()330     public void testHevcOther1Perf0320x0240() throws Exception { perf(HEVC, 320, 240, OTHER, 1); }
testHevcOther2Qual0320x0240()331     public void testHevcOther2Qual0320x0240() throws Exception { qual(HEVC, 320, 240, OTHER, 2); }
testHevcOther2Perf0320x0240()332     public void testHevcOther2Perf0320x0240() throws Exception { perf(HEVC, 320, 240, OTHER, 2); }
testHevcOther3Qual0320x0240()333     public void testHevcOther3Qual0320x0240() throws Exception { qual(HEVC, 320, 240, OTHER, 3); }
testHevcOther3Perf0320x0240()334     public void testHevcOther3Perf0320x0240() throws Exception { perf(HEVC, 320, 240, OTHER, 3); }
testHevcCount0720x0480()335     public void testHevcCount0720x0480() throws Exception { count(HEVC, 720, 480, 2, 4); }
testHevcGoog0Qual0720x0480()336     public void testHevcGoog0Qual0720x0480() throws Exception { qual(HEVC, 720, 480, GOOG, 0); }
testHevcGoog0Perf0720x0480()337     public void testHevcGoog0Perf0720x0480() throws Exception { perf(HEVC, 720, 480, GOOG, 0); }
testHevcGoog1Qual0720x0480()338     public void testHevcGoog1Qual0720x0480() throws Exception { qual(HEVC, 720, 480, GOOG, 1); }
testHevcGoog1Perf0720x0480()339     public void testHevcGoog1Perf0720x0480() throws Exception { perf(HEVC, 720, 480, GOOG, 1); }
340 
testHevcOther0Qual0720x0480()341     public void testHevcOther0Qual0720x0480() throws Exception { qual(HEVC, 720, 480, OTHER, 0); }
testHevcOther0Perf0720x0480()342     public void testHevcOther0Perf0720x0480() throws Exception { perf(HEVC, 720, 480, OTHER, 0); }
testHevcOther1Qual0720x0480()343     public void testHevcOther1Qual0720x0480() throws Exception { qual(HEVC, 720, 480, OTHER, 1); }
testHevcOther1Perf0720x0480()344     public void testHevcOther1Perf0720x0480() throws Exception { perf(HEVC, 720, 480, OTHER, 1); }
testHevcOther2Qual0720x0480()345     public void testHevcOther2Qual0720x0480() throws Exception { qual(HEVC, 720, 480, OTHER, 2); }
testHevcOther2Perf0720x0480()346     public void testHevcOther2Perf0720x0480() throws Exception { perf(HEVC, 720, 480, OTHER, 2); }
testHevcOther3Qual0720x0480()347     public void testHevcOther3Qual0720x0480() throws Exception { qual(HEVC, 720, 480, OTHER, 3); }
testHevcOther3Perf0720x0480()348     public void testHevcOther3Perf0720x0480() throws Exception { perf(HEVC, 720, 480, OTHER, 3); }
testHevcCount1280x0720()349     public void testHevcCount1280x0720() throws Exception { count(HEVC, 1280, 720, 2, 4); }
testHevcGoog0Qual1280x0720()350     public void testHevcGoog0Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, GOOG, 0); }
testHevcGoog0Perf1280x0720()351     public void testHevcGoog0Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, GOOG, 0); }
testHevcGoog1Qual1280x0720()352     public void testHevcGoog1Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, GOOG, 1); }
testHevcGoog1Perf1280x0720()353     public void testHevcGoog1Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, GOOG, 1); }
354 
testHevcOther0Qual1280x0720()355     public void testHevcOther0Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, OTHER, 0); }
testHevcOther0Perf1280x0720()356     public void testHevcOther0Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, OTHER, 0); }
testHevcOther1Qual1280x0720()357     public void testHevcOther1Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, OTHER, 1); }
testHevcOther1Perf1280x0720()358     public void testHevcOther1Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, OTHER, 1); }
testHevcOther2Qual1280x0720()359     public void testHevcOther2Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, OTHER, 2); }
testHevcOther2Perf1280x0720()360     public void testHevcOther2Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, OTHER, 2); }
testHevcOther3Qual1280x0720()361     public void testHevcOther3Qual1280x0720() throws Exception { qual(HEVC, 1280, 720, OTHER, 3); }
testHevcOther3Perf1280x0720()362     public void testHevcOther3Perf1280x0720() throws Exception { perf(HEVC, 1280, 720, OTHER, 3); }
testHevcCount1920x1080()363     public void testHevcCount1920x1080() throws Exception { count(HEVC, 1920, 1080, 2, 4); }
testHevcGoog0Qual1920x1080()364     public void testHevcGoog0Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, GOOG, 0); }
testHevcGoog0Perf1920x1080()365     public void testHevcGoog0Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, GOOG, 0); }
testHevcGoog1Qual1920x1080()366     public void testHevcGoog1Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, GOOG, 1); }
testHevcGoog1Perf1920x1080()367     public void testHevcGoog1Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, GOOG, 1); }
368 
testHevcOther0Qual1920x1080()369     public void testHevcOther0Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, OTHER, 0); }
testHevcOther0Perf1920x1080()370     public void testHevcOther0Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, OTHER, 0); }
testHevcOther1Qual1920x1080()371     public void testHevcOther1Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, OTHER, 1); }
testHevcOther1Perf1920x1080()372     public void testHevcOther1Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, OTHER, 1); }
testHevcOther2Qual1920x1080()373     public void testHevcOther2Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, OTHER, 2); }
testHevcOther2Perf1920x1080()374     public void testHevcOther2Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, OTHER, 2); }
testHevcOther3Qual1920x1080()375     public void testHevcOther3Qual1920x1080() throws Exception { qual(HEVC, 1920, 1080, OTHER, 3); }
testHevcOther3Perf1920x1080()376     public void testHevcOther3Perf1920x1080() throws Exception { perf(HEVC, 1920, 1080, OTHER, 3); }
testHevcCount3840x2160()377     public void testHevcCount3840x2160() throws Exception { count(HEVC, 3840, 2160, 2, 4); }
testHevcGoog0Qual3840x2160()378     public void testHevcGoog0Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, GOOG, 0); }
testHevcGoog0Perf3840x2160()379     public void testHevcGoog0Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, GOOG, 0); }
testHevcGoog1Qual3840x2160()380     public void testHevcGoog1Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, GOOG, 1); }
testHevcGoog1Perf3840x2160()381     public void testHevcGoog1Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, GOOG, 1); }
382 
testHevcOther0Qual3840x2160()383     public void testHevcOther0Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, OTHER, 0); }
testHevcOther0Perf3840x2160()384     public void testHevcOther0Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, OTHER, 0); }
testHevcOther1Qual3840x2160()385     public void testHevcOther1Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, OTHER, 1); }
testHevcOther1Perf3840x2160()386     public void testHevcOther1Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, OTHER, 1); }
testHevcOther2Qual3840x2160()387     public void testHevcOther2Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, OTHER, 2); }
testHevcOther2Perf3840x2160()388     public void testHevcOther2Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, OTHER, 2); }
testHevcOther3Qual3840x2160()389     public void testHevcOther3Qual3840x2160() throws Exception { qual(HEVC, 3840, 2160, OTHER, 3); }
testHevcOther3Perf3840x2160()390     public void testHevcOther3Perf3840x2160() throws Exception { perf(HEVC, 3840, 2160, OTHER, 3); }
391 
392     // MPEG2 tests
testMpeg2Count0176x0144()393     public void testMpeg2Count0176x0144() throws Exception { count(MPEG2, 176, 144, 2, 4); }
testMpeg2Goog0Qual0176x0144()394     public void testMpeg2Goog0Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, GOOG, 0); }
testMpeg2Goog0Perf0176x0144()395     public void testMpeg2Goog0Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, GOOG, 0); }
testMpeg2Goog1Qual0176x0144()396     public void testMpeg2Goog1Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, GOOG, 1); }
testMpeg2Goog1Perf0176x0144()397     public void testMpeg2Goog1Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, GOOG, 1); }
398 
testMpeg2Other0Qual0176x0144()399     public void testMpeg2Other0Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, OTHER, 0); }
testMpeg2Other0Perf0176x0144()400     public void testMpeg2Other0Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, OTHER, 0); }
testMpeg2Other1Qual0176x0144()401     public void testMpeg2Other1Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, OTHER, 1); }
testMpeg2Other1Perf0176x0144()402     public void testMpeg2Other1Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, OTHER, 1); }
testMpeg2Other2Qual0176x0144()403     public void testMpeg2Other2Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, OTHER, 2); }
testMpeg2Other2Perf0176x0144()404     public void testMpeg2Other2Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, OTHER, 2); }
testMpeg2Other3Qual0176x0144()405     public void testMpeg2Other3Qual0176x0144() throws Exception { qual(MPEG2, 176, 144, OTHER, 3); }
testMpeg2Other3Perf0176x0144()406     public void testMpeg2Other3Perf0176x0144() throws Exception { perf(MPEG2, 176, 144, OTHER, 3); }
testMpeg2Count0352x0288()407     public void testMpeg2Count0352x0288() throws Exception { count(MPEG2, 352, 288, 2, 4); }
testMpeg2Goog0Qual0352x0288()408     public void testMpeg2Goog0Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, GOOG, 0); }
testMpeg2Goog0Perf0352x0288()409     public void testMpeg2Goog0Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, GOOG, 0); }
testMpeg2Goog1Qual0352x0288()410     public void testMpeg2Goog1Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, GOOG, 1); }
testMpeg2Goog1Perf0352x0288()411     public void testMpeg2Goog1Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, GOOG, 1); }
412 
testMpeg2Other0Qual0352x0288()413     public void testMpeg2Other0Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, OTHER, 0); }
testMpeg2Other0Perf0352x0288()414     public void testMpeg2Other0Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, OTHER, 0); }
testMpeg2Other1Qual0352x0288()415     public void testMpeg2Other1Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, OTHER, 1); }
testMpeg2Other1Perf0352x0288()416     public void testMpeg2Other1Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, OTHER, 1); }
testMpeg2Other2Qual0352x0288()417     public void testMpeg2Other2Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, OTHER, 2); }
testMpeg2Other2Perf0352x0288()418     public void testMpeg2Other2Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, OTHER, 2); }
testMpeg2Other3Qual0352x0288()419     public void testMpeg2Other3Qual0352x0288() throws Exception { qual(MPEG2, 352, 288, OTHER, 3); }
testMpeg2Other3Perf0352x0288()420     public void testMpeg2Other3Perf0352x0288() throws Exception { perf(MPEG2, 352, 288, OTHER, 3); }
testMpeg2Count0640x0480()421     public void testMpeg2Count0640x0480() throws Exception { count(MPEG2, 640, 480, 2, 4); }
testMpeg2Goog0Qual0640x0480()422     public void testMpeg2Goog0Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, GOOG, 0); }
testMpeg2Goog0Perf0640x0480()423     public void testMpeg2Goog0Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, GOOG, 0); }
testMpeg2Goog1Qual0640x0480()424     public void testMpeg2Goog1Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, GOOG, 1); }
testMpeg2Goog1Perf0640x0480()425     public void testMpeg2Goog1Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, GOOG, 1); }
426 
testMpeg2Other0Qual0640x0480()427     public void testMpeg2Other0Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, OTHER, 0); }
testMpeg2Other0Perf0640x0480()428     public void testMpeg2Other0Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, OTHER, 0); }
testMpeg2Other1Qual0640x0480()429     public void testMpeg2Other1Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, OTHER, 1); }
testMpeg2Other1Perf0640x0480()430     public void testMpeg2Other1Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, OTHER, 1); }
testMpeg2Other2Qual0640x0480()431     public void testMpeg2Other2Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, OTHER, 2); }
testMpeg2Other2Perf0640x0480()432     public void testMpeg2Other2Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, OTHER, 2); }
testMpeg2Other3Qual0640x0480()433     public void testMpeg2Other3Qual0640x0480() throws Exception { qual(MPEG2, 640, 480, OTHER, 3); }
testMpeg2Other3Perf0640x0480()434     public void testMpeg2Other3Perf0640x0480() throws Exception { perf(MPEG2, 640, 480, OTHER, 3); }
testMpeg2Count1280x0720()435     public void testMpeg2Count1280x0720() throws Exception { count(MPEG2, 1280, 720, 2, 4); }
testMpeg2Goog0Qual1280x0720()436     public void testMpeg2Goog0Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, GOOG, 0); }
testMpeg2Goog0Perf1280x0720()437     public void testMpeg2Goog0Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, GOOG, 0); }
testMpeg2Goog1Qual1280x0720()438     public void testMpeg2Goog1Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, GOOG, 1); }
testMpeg2Goog1Perf1280x0720()439     public void testMpeg2Goog1Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, GOOG, 1); }
440 
testMpeg2Other0Qual1280x0720()441     public void testMpeg2Other0Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, OTHER, 0); }
testMpeg2Other0Perf1280x0720()442     public void testMpeg2Other0Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, OTHER, 0); }
testMpeg2Other1Qual1280x0720()443     public void testMpeg2Other1Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, OTHER, 1); }
testMpeg2Other1Perf1280x0720()444     public void testMpeg2Other1Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, OTHER, 1); }
testMpeg2Other2Qual1280x0720()445     public void testMpeg2Other2Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, OTHER, 2); }
testMpeg2Other2Perf1280x0720()446     public void testMpeg2Other2Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, OTHER, 2); }
testMpeg2Other3Qual1280x0720()447     public void testMpeg2Other3Qual1280x0720() throws Exception { qual(MPEG2, 1280, 720, OTHER, 3); }
testMpeg2Other3Perf1280x0720()448     public void testMpeg2Other3Perf1280x0720() throws Exception { perf(MPEG2, 1280, 720, OTHER, 3); }
testMpeg2Count1920x1080()449     public void testMpeg2Count1920x1080() throws Exception { count(MPEG2, 1920, 1080, 2, 4); }
testMpeg2Goog0Qual1920x1080()450     public void testMpeg2Goog0Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, GOOG, 0); }
testMpeg2Goog0Perf1920x1080()451     public void testMpeg2Goog0Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, GOOG, 0); }
testMpeg2Goog1Qual1920x1080()452     public void testMpeg2Goog1Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, GOOG, 1); }
testMpeg2Goog1Perf1920x1080()453     public void testMpeg2Goog1Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, GOOG, 1); }
454 
testMpeg2Other0Qual1920x1080()455     public void testMpeg2Other0Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, OTHER, 0); }
testMpeg2Other0Perf1920x1080()456     public void testMpeg2Other0Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, OTHER, 0); }
testMpeg2Other1Qual1920x1080()457     public void testMpeg2Other1Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, OTHER, 1); }
testMpeg2Other1Perf1920x1080()458     public void testMpeg2Other1Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, OTHER, 1); }
testMpeg2Other2Qual1920x1080()459     public void testMpeg2Other2Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, OTHER, 2); }
testMpeg2Other2Perf1920x1080()460     public void testMpeg2Other2Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, OTHER, 2); }
testMpeg2Other3Qual1920x1080()461     public void testMpeg2Other3Qual1920x1080() throws Exception { qual(MPEG2, 1920, 1080, OTHER, 3); }
testMpeg2Other3Perf1920x1080()462     public void testMpeg2Other3Perf1920x1080() throws Exception { perf(MPEG2, 1920, 1080, OTHER, 3); }
463 
464     // MPEG4 tests
testMpeg4Count0176x0144()465     public void testMpeg4Count0176x0144() throws Exception { count(MPEG4, 176, 144, 2, 4); }
testMpeg4Goog0Qual0176x0144()466     public void testMpeg4Goog0Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, GOOG, 0); }
testMpeg4Goog0Perf0176x0144()467     public void testMpeg4Goog0Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, GOOG, 0); }
testMpeg4Goog1Qual0176x0144()468     public void testMpeg4Goog1Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, GOOG, 1); }
testMpeg4Goog1Perf0176x0144()469     public void testMpeg4Goog1Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, GOOG, 1); }
470 
testMpeg4Other0Qual0176x0144()471     public void testMpeg4Other0Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, OTHER, 0); }
testMpeg4Other0Perf0176x0144()472     public void testMpeg4Other0Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, OTHER, 0); }
testMpeg4Other1Qual0176x0144()473     public void testMpeg4Other1Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, OTHER, 1); }
testMpeg4Other1Perf0176x0144()474     public void testMpeg4Other1Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, OTHER, 1); }
testMpeg4Other2Qual0176x0144()475     public void testMpeg4Other2Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, OTHER, 2); }
testMpeg4Other2Perf0176x0144()476     public void testMpeg4Other2Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, OTHER, 2); }
testMpeg4Other3Qual0176x0144()477     public void testMpeg4Other3Qual0176x0144() throws Exception { qual(MPEG4, 176, 144, OTHER, 3); }
testMpeg4Other3Perf0176x0144()478     public void testMpeg4Other3Perf0176x0144() throws Exception { perf(MPEG4, 176, 144, OTHER, 3); }
testMpeg4Count0352x0288()479     public void testMpeg4Count0352x0288() throws Exception { count(MPEG4, 352, 288, 2, 4); }
testMpeg4Goog0Qual0352x0288()480     public void testMpeg4Goog0Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, GOOG, 0); }
testMpeg4Goog0Perf0352x0288()481     public void testMpeg4Goog0Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, GOOG, 0); }
testMpeg4Goog1Qual0352x0288()482     public void testMpeg4Goog1Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, GOOG, 1); }
testMpeg4Goog1Perf0352x0288()483     public void testMpeg4Goog1Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, GOOG, 1); }
484 
testMpeg4Other0Qual0352x0288()485     public void testMpeg4Other0Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, OTHER, 0); }
testMpeg4Other0Perf0352x0288()486     public void testMpeg4Other0Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, OTHER, 0); }
testMpeg4Other1Qual0352x0288()487     public void testMpeg4Other1Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, OTHER, 1); }
testMpeg4Other1Perf0352x0288()488     public void testMpeg4Other1Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, OTHER, 1); }
testMpeg4Other2Qual0352x0288()489     public void testMpeg4Other2Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, OTHER, 2); }
testMpeg4Other2Perf0352x0288()490     public void testMpeg4Other2Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, OTHER, 2); }
testMpeg4Other3Qual0352x0288()491     public void testMpeg4Other3Qual0352x0288() throws Exception { qual(MPEG4, 352, 288, OTHER, 3); }
testMpeg4Other3Perf0352x0288()492     public void testMpeg4Other3Perf0352x0288() throws Exception { perf(MPEG4, 352, 288, OTHER, 3); }
testMpeg4Count0640x0480()493     public void testMpeg4Count0640x0480() throws Exception { count(MPEG4, 640, 480, 2, 4); }
testMpeg4Goog0Qual0640x0480()494     public void testMpeg4Goog0Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, GOOG, 0); }
testMpeg4Goog0Perf0640x0480()495     public void testMpeg4Goog0Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, GOOG, 0); }
testMpeg4Goog1Qual0640x0480()496     public void testMpeg4Goog1Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, GOOG, 1); }
testMpeg4Goog1Perf0640x0480()497     public void testMpeg4Goog1Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, GOOG, 1); }
498 
testMpeg4Other0Qual0640x0480()499     public void testMpeg4Other0Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, OTHER, 0); }
testMpeg4Other0Perf0640x0480()500     public void testMpeg4Other0Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, OTHER, 0); }
testMpeg4Other1Qual0640x0480()501     public void testMpeg4Other1Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, OTHER, 1); }
testMpeg4Other1Perf0640x0480()502     public void testMpeg4Other1Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, OTHER, 1); }
testMpeg4Other2Qual0640x0480()503     public void testMpeg4Other2Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, OTHER, 2); }
testMpeg4Other2Perf0640x0480()504     public void testMpeg4Other2Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, OTHER, 2); }
testMpeg4Other3Qual0640x0480()505     public void testMpeg4Other3Qual0640x0480() throws Exception { qual(MPEG4, 640, 480, OTHER, 3); }
testMpeg4Other3Perf0640x0480()506     public void testMpeg4Other3Perf0640x0480() throws Exception { perf(MPEG4, 640, 480, OTHER, 3); }
testMpeg4Count1280x0720()507     public void testMpeg4Count1280x0720() throws Exception { count(MPEG4, 1280, 720, 2, 4); }
testMpeg4Goog0Qual1280x0720()508     public void testMpeg4Goog0Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, GOOG, 0); }
testMpeg4Goog0Perf1280x0720()509     public void testMpeg4Goog0Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, GOOG, 0); }
testMpeg4Goog1Qual1280x0720()510     public void testMpeg4Goog1Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, GOOG, 1); }
testMpeg4Goog1Perf1280x0720()511     public void testMpeg4Goog1Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, GOOG, 1); }
512 
testMpeg4Other0Qual1280x0720()513     public void testMpeg4Other0Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, OTHER, 0); }
testMpeg4Other0Perf1280x0720()514     public void testMpeg4Other0Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, OTHER, 0); }
testMpeg4Other1Qual1280x0720()515     public void testMpeg4Other1Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, OTHER, 1); }
testMpeg4Other1Perf1280x0720()516     public void testMpeg4Other1Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, OTHER, 1); }
testMpeg4Other2Qual1280x0720()517     public void testMpeg4Other2Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, OTHER, 2); }
testMpeg4Other2Perf1280x0720()518     public void testMpeg4Other2Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, OTHER, 2); }
testMpeg4Other3Qual1280x0720()519     public void testMpeg4Other3Qual1280x0720() throws Exception { qual(MPEG4, 1280, 720, OTHER, 3); }
testMpeg4Other3Perf1280x0720()520     public void testMpeg4Other3Perf1280x0720() throws Exception { perf(MPEG4, 1280, 720, OTHER, 3); }
521 
522     // VP8 tests
testVp8Count0320x0180()523     public void testVp8Count0320x0180() throws Exception { count(VP8, 320, 180, 2, 2); }
testVp8Goog0Qual0320x0180()524     public void testVp8Goog0Qual0320x0180() throws Exception { qual(VP8, 320, 180, GOOG, 0); }
testVp8Goog0Perf0320x0180()525     public void testVp8Goog0Perf0320x0180() throws Exception { perf(VP8, 320, 180, GOOG, 0); }
testVp8Goog1Qual0320x0180()526     public void testVp8Goog1Qual0320x0180() throws Exception { qual(VP8, 320, 180, GOOG, 1); }
testVp8Goog1Perf0320x0180()527     public void testVp8Goog1Perf0320x0180() throws Exception { perf(VP8, 320, 180, GOOG, 1); }
528 
testVp8Other0Qual0320x0180()529     public void testVp8Other0Qual0320x0180() throws Exception { qual(VP8, 320, 180, OTHER, 0); }
testVp8Other0Perf0320x0180()530     public void testVp8Other0Perf0320x0180() throws Exception { perf(VP8, 320, 180, OTHER, 0); }
testVp8Other1Qual0320x0180()531     public void testVp8Other1Qual0320x0180() throws Exception { qual(VP8, 320, 180, OTHER, 1); }
testVp8Other1Perf0320x0180()532     public void testVp8Other1Perf0320x0180() throws Exception { perf(VP8, 320, 180, OTHER, 1); }
testVp8Count0640x0360()533     public void testVp8Count0640x0360() throws Exception { count(VP8, 640, 360, 2, 2); }
testVp8Goog0Qual0640x0360()534     public void testVp8Goog0Qual0640x0360() throws Exception { qual(VP8, 640, 360, GOOG, 0); }
testVp8Goog0Perf0640x0360()535     public void testVp8Goog0Perf0640x0360() throws Exception { perf(VP8, 640, 360, GOOG, 0); }
testVp8Goog1Qual0640x0360()536     public void testVp8Goog1Qual0640x0360() throws Exception { qual(VP8, 640, 360, GOOG, 1); }
testVp8Goog1Perf0640x0360()537     public void testVp8Goog1Perf0640x0360() throws Exception { perf(VP8, 640, 360, GOOG, 1); }
538 
testVp8Other0Qual0640x0360()539     public void testVp8Other0Qual0640x0360() throws Exception { qual(VP8, 640, 360, OTHER, 0); }
testVp8Other0Perf0640x0360()540     public void testVp8Other0Perf0640x0360() throws Exception { perf(VP8, 640, 360, OTHER, 0); }
testVp8Other1Qual0640x0360()541     public void testVp8Other1Qual0640x0360() throws Exception { qual(VP8, 640, 360, OTHER, 1); }
testVp8Other1Perf0640x0360()542     public void testVp8Other1Perf0640x0360() throws Exception { perf(VP8, 640, 360, OTHER, 1); }
testVp8Count1280x0720()543     public void testVp8Count1280x0720() throws Exception { count(VP8, 1280, 720, 2, 2); }
testVp8Goog0Qual1280x0720()544     public void testVp8Goog0Qual1280x0720() throws Exception { qual(VP8, 1280, 720, GOOG, 0); }
testVp8Goog0Perf1280x0720()545     public void testVp8Goog0Perf1280x0720() throws Exception { perf(VP8, 1280, 720, GOOG, 0); }
testVp8Goog1Qual1280x0720()546     public void testVp8Goog1Qual1280x0720() throws Exception { qual(VP8, 1280, 720, GOOG, 1); }
testVp8Goog1Perf1280x0720()547     public void testVp8Goog1Perf1280x0720() throws Exception { perf(VP8, 1280, 720, GOOG, 1); }
548 
testVp8Other0Qual1280x0720()549     public void testVp8Other0Qual1280x0720() throws Exception { qual(VP8, 1280, 720, OTHER, 0); }
testVp8Other0Perf1280x0720()550     public void testVp8Other0Perf1280x0720() throws Exception { perf(VP8, 1280, 720, OTHER, 0); }
testVp8Other1Qual1280x0720()551     public void testVp8Other1Qual1280x0720() throws Exception { qual(VP8, 1280, 720, OTHER, 1); }
testVp8Other1Perf1280x0720()552     public void testVp8Other1Perf1280x0720() throws Exception { perf(VP8, 1280, 720, OTHER, 1); }
testVp8Count1920x1080()553     public void testVp8Count1920x1080() throws Exception { count(VP8, 1920, 1080, 2, 2); }
testVp8Goog0Qual1920x1080()554     public void testVp8Goog0Qual1920x1080() throws Exception { qual(VP8, 1920, 1080, GOOG, 0); }
testVp8Goog0Perf1920x1080()555     public void testVp8Goog0Perf1920x1080() throws Exception { perf(VP8, 1920, 1080, GOOG, 0); }
testVp8Goog1Qual1920x1080()556     public void testVp8Goog1Qual1920x1080() throws Exception { qual(VP8, 1920, 1080, GOOG, 1); }
testVp8Goog1Perf1920x1080()557     public void testVp8Goog1Perf1920x1080() throws Exception { perf(VP8, 1920, 1080, GOOG, 1); }
558 
testVp8Other0Qual1920x1080()559     public void testVp8Other0Qual1920x1080() throws Exception { qual(VP8, 1920, 1080, OTHER, 0); }
testVp8Other0Perf1920x1080()560     public void testVp8Other0Perf1920x1080() throws Exception { perf(VP8, 1920, 1080, OTHER, 0); }
testVp8Other1Qual1920x1080()561     public void testVp8Other1Qual1920x1080() throws Exception { qual(VP8, 1920, 1080, OTHER, 1); }
testVp8Other1Perf1920x1080()562     public void testVp8Other1Perf1920x1080() throws Exception { perf(VP8, 1920, 1080, OTHER, 1); }
563 
564     // VP9 tests
testVp9Count0320x0180()565     public void testVp9Count0320x0180() throws Exception { count(VP9, 320, 180, 2, 4); }
testVp9Goog0Qual0320x0180()566     public void testVp9Goog0Qual0320x0180() throws Exception { qual(VP9, 320, 180, GOOG, 0); }
testVp9Goog0Perf0320x0180()567     public void testVp9Goog0Perf0320x0180() throws Exception { perf(VP9, 320, 180, GOOG, 0); }
testVp9Goog1Qual0320x0180()568     public void testVp9Goog1Qual0320x0180() throws Exception { qual(VP9, 320, 180, GOOG, 1); }
testVp9Goog1Perf0320x0180()569     public void testVp9Goog1Perf0320x0180() throws Exception { perf(VP9, 320, 180, GOOG, 1); }
570 
testVp9Other0Qual0320x0180()571     public void testVp9Other0Qual0320x0180() throws Exception { qual(VP9, 320, 180, OTHER, 0); }
testVp9Other0Perf0320x0180()572     public void testVp9Other0Perf0320x0180() throws Exception { perf(VP9, 320, 180, OTHER, 0); }
testVp9Other1Qual0320x0180()573     public void testVp9Other1Qual0320x0180() throws Exception { qual(VP9, 320, 180, OTHER, 1); }
testVp9Other1Perf0320x0180()574     public void testVp9Other1Perf0320x0180() throws Exception { perf(VP9, 320, 180, OTHER, 1); }
testVp9Other2Qual0320x0180()575     public void testVp9Other2Qual0320x0180() throws Exception { qual(VP9, 320, 180, OTHER, 2); }
testVp9Other2Perf0320x0180()576     public void testVp9Other2Perf0320x0180() throws Exception { perf(VP9, 320, 180, OTHER, 2); }
testVp9Other3Qual0320x0180()577     public void testVp9Other3Qual0320x0180() throws Exception { qual(VP9, 320, 180, OTHER, 3); }
testVp9Other3Perf0320x0180()578     public void testVp9Other3Perf0320x0180() throws Exception { perf(VP9, 320, 180, OTHER, 3); }
testVp9Count0640x0360()579     public void testVp9Count0640x0360() throws Exception { count(VP9, 640, 360, 2, 4); }
testVp9Goog0Qual0640x0360()580     public void testVp9Goog0Qual0640x0360() throws Exception { qual(VP9, 640, 360, GOOG, 0); }
testVp9Goog0Perf0640x0360()581     public void testVp9Goog0Perf0640x0360() throws Exception { perf(VP9, 640, 360, GOOG, 0); }
testVp9Goog1Qual0640x0360()582     public void testVp9Goog1Qual0640x0360() throws Exception { qual(VP9, 640, 360, GOOG, 1); }
testVp9Goog1Perf0640x0360()583     public void testVp9Goog1Perf0640x0360() throws Exception { perf(VP9, 640, 360, GOOG, 1); }
584 
testVp9Other0Qual0640x0360()585     public void testVp9Other0Qual0640x0360() throws Exception { qual(VP9, 640, 360, OTHER, 0); }
testVp9Other0Perf0640x0360()586     public void testVp9Other0Perf0640x0360() throws Exception { perf(VP9, 640, 360, OTHER, 0); }
testVp9Other1Qual0640x0360()587     public void testVp9Other1Qual0640x0360() throws Exception { qual(VP9, 640, 360, OTHER, 1); }
testVp9Other1Perf0640x0360()588     public void testVp9Other1Perf0640x0360() throws Exception { perf(VP9, 640, 360, OTHER, 1); }
testVp9Other2Qual0640x0360()589     public void testVp9Other2Qual0640x0360() throws Exception { qual(VP9, 640, 360, OTHER, 2); }
testVp9Other2Perf0640x0360()590     public void testVp9Other2Perf0640x0360() throws Exception { perf(VP9, 640, 360, OTHER, 2); }
testVp9Other3Qual0640x0360()591     public void testVp9Other3Qual0640x0360() throws Exception { qual(VP9, 640, 360, OTHER, 3); }
testVp9Other3Perf0640x0360()592     public void testVp9Other3Perf0640x0360() throws Exception { perf(VP9, 640, 360, OTHER, 3); }
testVp9Count1280x0720()593     public void testVp9Count1280x0720() throws Exception { count(VP9, 1280, 720, 2, 4); }
testVp9Goog0Qual1280x0720()594     public void testVp9Goog0Qual1280x0720() throws Exception { qual(VP9, 1280, 720, GOOG, 0); }
testVp9Goog0Perf1280x0720()595     public void testVp9Goog0Perf1280x0720() throws Exception { perf(VP9, 1280, 720, GOOG, 0); }
testVp9Goog1Qual1280x0720()596     public void testVp9Goog1Qual1280x0720() throws Exception { qual(VP9, 1280, 720, GOOG, 1); }
testVp9Goog1Perf1280x0720()597     public void testVp9Goog1Perf1280x0720() throws Exception { perf(VP9, 1280, 720, GOOG, 1); }
598 
testVp9Other0Qual1280x0720()599     public void testVp9Other0Qual1280x0720() throws Exception { qual(VP9, 1280, 720, OTHER, 0); }
testVp9Other0Perf1280x0720()600     public void testVp9Other0Perf1280x0720() throws Exception { perf(VP9, 1280, 720, OTHER, 0); }
testVp9Other1Qual1280x0720()601     public void testVp9Other1Qual1280x0720() throws Exception { qual(VP9, 1280, 720, OTHER, 1); }
testVp9Other1Perf1280x0720()602     public void testVp9Other1Perf1280x0720() throws Exception { perf(VP9, 1280, 720, OTHER, 1); }
testVp9Other2Qual1280x0720()603     public void testVp9Other2Qual1280x0720() throws Exception { qual(VP9, 1280, 720, OTHER, 2); }
testVp9Other2Perf1280x0720()604     public void testVp9Other2Perf1280x0720() throws Exception { perf(VP9, 1280, 720, OTHER, 2); }
testVp9Other3Qual1280x0720()605     public void testVp9Other3Qual1280x0720() throws Exception { qual(VP9, 1280, 720, OTHER, 3); }
testVp9Other3Perf1280x0720()606     public void testVp9Other3Perf1280x0720() throws Exception { perf(VP9, 1280, 720, OTHER, 3); }
testVp9Count1920x1080()607     public void testVp9Count1920x1080() throws Exception { count(VP9, 1920, 1080, 2, 4); }
testVp9Goog0Qual1920x1080()608     public void testVp9Goog0Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, GOOG, 0); }
testVp9Goog0Perf1920x1080()609     public void testVp9Goog0Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, GOOG, 0); }
testVp9Goog1Qual1920x1080()610     public void testVp9Goog1Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, GOOG, 1); }
testVp9Goog1Perf1920x1080()611     public void testVp9Goog1Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, GOOG, 1); }
612 
testVp9Other0Qual1920x1080()613     public void testVp9Other0Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, OTHER, 0); }
testVp9Other0Perf1920x1080()614     public void testVp9Other0Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, OTHER, 0); }
testVp9Other1Qual1920x1080()615     public void testVp9Other1Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, OTHER, 1); }
testVp9Other1Perf1920x1080()616     public void testVp9Other1Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, OTHER, 1); }
testVp9Other2Qual1920x1080()617     public void testVp9Other2Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, OTHER, 2); }
testVp9Other2Perf1920x1080()618     public void testVp9Other2Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, OTHER, 2); }
testVp9Other3Qual1920x1080()619     public void testVp9Other3Qual1920x1080() throws Exception { qual(VP9, 1920, 1080, OTHER, 3); }
testVp9Other3Perf1920x1080()620     public void testVp9Other3Perf1920x1080() throws Exception { perf(VP9, 1920, 1080, OTHER, 3); }
testVp9Count3840x2160()621     public void testVp9Count3840x2160() throws Exception { count(VP9, 3840, 2160, 2, 4); }
testVp9Goog0Qual3840x2160()622     public void testVp9Goog0Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, GOOG, 0); }
testVp9Goog0Perf3840x2160()623     public void testVp9Goog0Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, GOOG, 0); }
testVp9Goog1Qual3840x2160()624     public void testVp9Goog1Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, GOOG, 1); }
testVp9Goog1Perf3840x2160()625     public void testVp9Goog1Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, GOOG, 1); }
626 
testVp9Other0Qual3840x2160()627     public void testVp9Other0Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, OTHER, 0); }
testVp9Other0Perf3840x2160()628     public void testVp9Other0Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, OTHER, 0); }
testVp9Other1Qual3840x2160()629     public void testVp9Other1Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, OTHER, 1); }
testVp9Other1Perf3840x2160()630     public void testVp9Other1Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, OTHER, 1); }
testVp9Other2Qual3840x2160()631     public void testVp9Other2Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, OTHER, 2); }
testVp9Other2Perf3840x2160()632     public void testVp9Other2Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, OTHER, 2); }
testVp9Other3Qual3840x2160()633     public void testVp9Other3Qual3840x2160() throws Exception { qual(VP9, 3840, 2160, OTHER, 3); }
testVp9Other3Perf3840x2160()634     public void testVp9Other3Perf3840x2160() throws Exception { perf(VP9, 3840, 2160, OTHER, 3); }
635 
isSrcSemiPlanar()636     private boolean isSrcSemiPlanar() {
637         return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
638     }
639 
isSrcFlexYUV()640     private boolean isSrcFlexYUV() {
641         return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
642     }
643 
isDstSemiPlanar()644     private boolean isDstSemiPlanar() {
645         return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
646     }
647 
isDstFlexYUV()648     private boolean isDstFlexYUV() {
649         return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
650     }
651 
getColorFormat(CodecInfo info)652     private static int getColorFormat(CodecInfo info) {
653         if (info.mSupportSemiPlanar) {
654             return CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
655         } else if (info.mSupportPlanar) {
656             return CodecCapabilities.COLOR_FormatYUV420Planar;
657         } else {
658             // FlexYUV must be supported
659             return CodecCapabilities.COLOR_FormatYUV420Flexible;
660         }
661     }
662 
663     private static class RunResult {
664         public final int mNumFrames;
665         public final double mDurationMs;
666         public final double mRmsError;
667 
RunResult()668         RunResult() {
669             mNumFrames = 0;
670             mDurationMs = Double.NaN;
671             mRmsError = Double.NaN;
672         }
673 
RunResult(int numFrames, double durationMs)674         RunResult(int numFrames, double durationMs) {
675             mNumFrames = numFrames;
676             mDurationMs = durationMs;
677             mRmsError = Double.NaN;
678         }
679 
RunResult(int numFrames, double durationMs, double rmsError)680         RunResult(int numFrames, double durationMs, double rmsError) {
681             mNumFrames = numFrames;
682             mDurationMs = durationMs;
683             mRmsError = rmsError;
684         }
685     }
686 
doTest(String mimeType, int w, int h, boolean isPerf, boolean isGoog, int ix)687     private void doTest(String mimeType, int w, int h, boolean isPerf, boolean isGoog, int ix)
688             throws Exception {
689         MediaFormat format = MediaFormat.createVideoFormat(mimeType, w, h);
690         String[] encoderNames = MediaUtils.getEncoderNames(isGoog, format);
691         String kind = isGoog ? "Google" : "non-Google";
692         if (encoderNames.length == 0) {
693             MediaUtils.skipTest("No " + kind + " encoders for " + format);
694             return;
695         } else if (encoderNames.length <= ix) {
696             Log.i(TAG, "No more " + kind + " encoders for " + format);
697             return;
698         }
699 
700         if (isPerf) {
701             mTestConfig.initPerfTest();
702         }
703 
704         String encoderName = encoderNames[ix];
705 
706         CodecInfo infoEnc = CodecInfo.getSupportedFormatInfo(encoderName, mimeType, w, h, MAX_FPS);
707         assertNotNull(infoEnc);
708 
709         // Skip decoding pass for performance tests as bitstream complexity is not representative
710         String[] decoderNames = null;  // no decoding pass required by default
711         int codingPasses = 1;  // used for time limit. 1 for encoding pass
712         int numRuns = mTestConfig.mNumberOfRepeat;  // used for result array sizing
713         if (!isPerf) {
714             // consider all decoders for quality tests
715             decoderNames = MediaUtils.getDecoderNames(format);
716             if (decoderNames.length == 0) {
717                 MediaUtils.skipTest("No decoders for " + format);
718                 return;
719             }
720             numRuns *= decoderNames.length; // combine each decoder with the encoder
721             codingPasses += decoderNames.length;
722         }
723 
724         // be a bit conservative
725         mTestConfig.mMaxTimeMs = Math.min(
726                 mTestConfig.mMaxTimeMs, MAX_TEST_TIMEOUT_MS / 5 * 4 / codingPasses
727                         / mTestConfig.mNumberOfRepeat);
728         // reduce test-run on non-real devices
729         if (frankenDevice()) {
730             mTestConfig.mMaxTimeMs /= 10;
731         }
732 
733         mVideoWidth = w;
734         mVideoHeight = h;
735         mSrcColorFormat = getColorFormat(infoEnc);
736         Log.i(TAG, "Testing video resolution " + w + "x" + h + ": enc format " + mSrcColorFormat);
737 
738         initYUVPlane(w + YUV_PLANE_ADDITIONAL_LENGTH, h + YUV_PLANE_ADDITIONAL_LENGTH);
739 
740         // Adjust total number of frames to prevent OOM.
741         Runtime rt = Runtime.getRuntime();
742         long usedMemory = rt.totalMemory() - rt.freeMemory();
743         mTestConfig.mTotalFrames = Math.min(mTestConfig.mTotalFrames,
744                 (int) (rt.maxMemory() - usedMemory) / 4 * 3 /
745                 (infoEnc.mBitRate / 8 / infoEnc.mFps + 1));
746         Log.i(TAG, "Total testing frames " + mTestConfig.mTotalFrames);
747 
748         mEncoderFrameTimeUsDiff = new double[numRuns][mTestConfig.mTotalFrames - 1];
749         mEncoderFpsResults = new double[numRuns];
750 
751         if (decoderNames != null) {
752             mDecoderFrameTimeUsDiff = new double[numRuns][mTestConfig.mTotalFrames - 1];
753             mDecoderFpsResults = new double[numRuns];
754             mTotalFpsResults = new double[numRuns];
755             mDecoderRmsErrorResults = new double[numRuns];
756         }
757 
758         boolean success = true;
759         int runIx = 0;
760         for (int i = 0; i < mTestConfig.mNumberOfRepeat && success; i++) {
761             mCurrentTestRound = runIx;
762             format = new MediaFormat();
763             format.setString(MediaFormat.KEY_MIME, mimeType);
764             format.setInteger(MediaFormat.KEY_BIT_RATE, infoEnc.mBitRate);
765             format.setInteger(MediaFormat.KEY_BITRATE_MODE,
766                     MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
767             format.setInteger(MediaFormat.KEY_WIDTH, w);
768             format.setInteger(MediaFormat.KEY_HEIGHT, h);
769             format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mSrcColorFormat);
770             format.setInteger(MediaFormat.KEY_FRAME_RATE, infoEnc.mFps);
771             mFrameRate = infoEnc.mFps;
772             format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, KEY_I_FRAME_INTERVAL);
773 
774             RunResult encodingResult =
775                 runEncoder(encoderName, format, mTestConfig.mTotalFrames, i);
776             double encodingTime = encodingResult.mDurationMs;
777             int framesEncoded = encodingResult.mNumFrames;
778 
779             if (decoderNames != null && decoderNames.length > 0) {
780                 for (String decoderName : decoderNames) {
781                     CodecInfo infoDec =
782                         CodecInfo.getSupportedFormatInfo(decoderName, mimeType, w, h, MAX_FPS);
783                     assertNotNull(infoDec);
784                     mDstColorFormat = getColorFormat(infoDec);
785 
786                     // re-initialize format for decoder
787                     format = new MediaFormat();
788                     format.setString(MediaFormat.KEY_MIME, mimeType);
789                     format.setInteger(MediaFormat.KEY_WIDTH, w);
790                     format.setInteger(MediaFormat.KEY_HEIGHT, h);
791                     format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mDstColorFormat);
792                     RunResult decoderResult = runDecoder(decoderName, format, i);
793                     if (decoderResult == null) {
794                         success = false;
795                     } else {
796                         double decodingTime = decoderResult.mDurationMs;
797                         mDecoderRmsErrorResults[runIx] = decoderResult.mRmsError;
798                         mEncoderFpsResults[runIx] = framesEncoded / encodingTime;
799                         int framesDecoded = decoderResult.mNumFrames;
800                         mDecoderFpsResults[runIx] = framesDecoded / decodingTime;
801                         if (framesDecoded == framesEncoded) {
802                             mTotalFpsResults[runIx] =
803                                 framesEncoded / (encodingTime + decodingTime);
804                         }
805                     }
806                     ++runIx;
807                 }
808             } else {
809                 mEncoderFpsResults[runIx] = mTestConfig.mTotalFrames / encodingTime;
810                 ++runIx;
811             }
812 
813             // clear things for re-start
814             mEncodedOutputBuffer.clear();
815             // it will be good to clean everything to make every run the same.
816             System.gc();
817         }
818 
819         // log results before verification
820         double[] measuredFps = new double[numRuns];
821         if (isPerf) {
822             for (int i = 0; i < numRuns; i++) {
823                 measuredFps[i] = logPerformanceResults(encoderName, i);
824             }
825         }
826         if (mTestConfig.mTestPixels && decoderNames != null) {
827             logQualityResults(mimeType, encoderName, decoderNames);
828             for (int i = 0; i < numRuns; i++) {
829                 // make sure that rms error is not too big for all runs
830                 if (mDecoderRmsErrorResults[i] >= mRmsErrorMargin) {
831                     fail("rms error is bigger than the limit "
832                             + Arrays.toString(mDecoderRmsErrorResults) + " vs " + mRmsErrorMargin);
833                 }
834             }
835         }
836 
837         if (isPerf) {
838             String error = MediaPerfUtils.verifyAchievableFrameRates(
839                     encoderName, mimeType, w, h, measuredFps);
840             if (frankenDevice() && error != null) {
841                 // ensure there is data, but don't insist that it is correct
842                 assertFalse(error, error.startsWith("Failed to get "));
843             } else {
844                 assertNull(error, error);
845             }
846         }
847         assertTrue(success);
848     }
849 
logQualityResults(String mimeType, String encoderName, String[] decoderNames)850     private void logQualityResults(String mimeType, String encoderName, String[] decoderNames) {
851         String streamName = "video_encoder_decoder_quality";
852         DeviceReportLog log = new DeviceReportLog(REPORT_LOG_NAME, streamName);
853         log.addValue("encoder_name", encoderName, ResultType.NEUTRAL, ResultUnit.NONE);
854         log.addValues("decoder_names", Arrays.asList(decoderNames), ResultType.NEUTRAL, ResultUnit.NONE);
855         log.addValue("mime_type", mimeType, ResultType.NEUTRAL, ResultUnit.NONE);
856         log.addValue("width", mVideoWidth, ResultType.NEUTRAL, ResultUnit.NONE);
857         log.addValue("height", mVideoHeight, ResultType.NEUTRAL, ResultUnit.NONE);
858         log.addValues("encoder_fps", mEncoderFpsResults, ResultType.HIGHER_BETTER,
859                 ResultUnit.FPS);
860         log.addValues("rms_error", mDecoderRmsErrorResults, ResultType.LOWER_BETTER,
861                 ResultUnit.NONE);
862         log.addValues("decoder_fps", mDecoderFpsResults, ResultType.HIGHER_BETTER,
863                 ResultUnit.FPS);
864         log.addValues("encoder_decoder_fps", mTotalFpsResults, ResultType.HIGHER_BETTER,
865                 ResultUnit.FPS);
866         log.addValue("encoder_average_fps", Stat.getAverage(mEncoderFpsResults),
867                 ResultType.HIGHER_BETTER, ResultUnit.FPS);
868         log.addValue("decoder_average_fps", Stat.getAverage(mDecoderFpsResults),
869                 ResultType.HIGHER_BETTER, ResultUnit.FPS);
870         log.setSummary("encoder_decoder_average_fps", Stat.getAverage(mTotalFpsResults),
871                 ResultType.HIGHER_BETTER, ResultUnit.FPS);
872         log.submit(getInstrumentation());
873     }
874 
logPerformanceResults(String encoderName, int round)875     private double logPerformanceResults(String encoderName, int round) {
876         String streamName = "video_encoder_performance";
877         DeviceReportLog log = new DeviceReportLog(REPORT_LOG_NAME, streamName);
878         String message = MediaPerfUtils.addPerformanceHeadersToLog(
879                 log, "encoder stats:", round, encoderName,
880                 mEncConfigFormat, mEncInputFormat, mEncOutputFormat);
881         double[] frameTimeUsDiff = mEncoderFrameTimeUsDiff[round];
882         double fps = MediaPerfUtils.addPerformanceStatsToLog(
883                 log, new MediaUtils.Stats(frameTimeUsDiff), message);
884 
885         if (mTestConfig.mReportFrameTime) {
886             double[] msDiff = new double[frameTimeUsDiff.length];
887             double nowUs = 0, lastMs = 0;
888             for (int i = 0; i < frameTimeUsDiff.length; ++i) {
889                 nowUs += frameTimeUsDiff[i];
890                 double nowMs = Math.round(nowUs) / 1000.;
891                 msDiff[i] = Math.round((nowMs - lastMs) * 1000) / 1000.;
892                 lastMs = nowMs;
893             }
894             log.addValues("encoder_raw_diff", msDiff, ResultType.NEUTRAL, ResultUnit.MS);
895         }
896 
897         log.submit(getInstrumentation());
898         return fps;
899     }
900 
901     /**
902      * run encoder benchmarking
903      * @param encoderName encoder name
904      * @param format format of media to encode
905      * @param totalFrames total number of frames to encode
906      * @return time taken in ms to encode the frames. This does not include initialization time.
907      */
runEncoder( String encoderName, MediaFormat format, int totalFrames, int runId)908     private RunResult runEncoder(
909             String encoderName, MediaFormat format, int totalFrames, int runId) {
910         MediaCodec codec = null;
911         try {
912             codec = MediaCodec.createByCodecName(encoderName);
913             mEncConfigFormat = format;
914             codec.configure(
915                     format,
916                     null /* surface */,
917                     null /* crypto */,
918                     MediaCodec.CONFIGURE_FLAG_ENCODE);
919         } catch (IllegalStateException e) {
920             Log.e(TAG, "codec '" + encoderName + "' failed configuration.");
921             codec.release();
922             assertTrue("codec '" + encoderName + "' failed configuration.", false);
923         } catch (IOException | NullPointerException e) {
924             Log.i(TAG, "could not find codec for " + format);
925             return new RunResult();
926         }
927         codec.start();
928         mEncInputFormat = codec.getInputFormat();
929         ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
930         MediaFormat inputFormat = codec.getInputFormat();
931         mVideoStride = inputFormat.containsKey(MediaFormat.KEY_STRIDE)
932                 ? inputFormat.getInteger(MediaFormat.KEY_STRIDE)
933                 : inputFormat.getInteger(MediaFormat.KEY_WIDTH);
934         mVideoVStride = inputFormat.containsKey(MediaFormat.KEY_SLICE_HEIGHT)
935                 ? inputFormat.getInteger(MediaFormat.KEY_SLICE_HEIGHT)
936                 : inputFormat.getInteger(MediaFormat.KEY_HEIGHT);
937 
938         int numBytesSubmitted = 0;
939         int numBytesDequeued = 0;
940         int inFramesCount = 0;
941         int outFramesCount = 0;
942         long lastOutputTimeUs = 0;
943         long start = System.currentTimeMillis();
944         while (true) {
945             int index;
946 
947             if (inFramesCount < totalFrames) {
948                 index = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
949                 if (index != MediaCodec.INFO_TRY_AGAIN_LATER) {
950                     int size;
951                     long elapsedMs = System.currentTimeMillis() - start;
952                     boolean eos = (inFramesCount == totalFrames - 1
953                             || elapsedMs > mTestConfig.mMaxTimeMs
954                             || (elapsedMs > mTestConfig.mMinTimeMs
955                                     && inFramesCount > mTestConfig.mMinNumFrames));
956 
957                     // when encoder only supports flexYUV, use Image only; otherwise,
958                     // use ByteBuffer & Image each on half of the frames to test both
959                     if (isSrcFlexYUV() || inFramesCount % 2 == 0) {
960                         Image image = codec.getInputImage(index);
961                         // image should always be available
962                         assertTrue(image != null);
963                         size = queueInputImageEncoder(
964                                 codec, image, index, inFramesCount,
965                                 eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0, runId);
966                     } else {
967                         ByteBuffer buffer = codec.getInputBuffer(index);
968                         size = queueInputBufferEncoder(
969                                 codec, buffer, index, inFramesCount,
970                                 eos ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0, runId);
971                     }
972                     inFramesCount++;
973                     numBytesSubmitted += size;
974                     if (VERBOSE) {
975                         Log.d(TAG, "queued " + size + " bytes of input data, frame " +
976                                 (inFramesCount - 1));
977                     }
978                 }
979             }
980             MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
981             index = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
982             if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {
983             } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
984                 mEncOutputFormat = codec.getOutputFormat();
985             } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
986                 codecOutputBuffers = codec.getOutputBuffers();
987             } else if (index >= 0) {
988                 long nowUs = (System.nanoTime() + 500) / 1000;
989                 dequeueOutputBufferEncoder(codec, codecOutputBuffers, index, info);
990                 if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
991                     int pos = outFramesCount - 1;
992                     if (pos >= 0 && pos < mEncoderFrameTimeUsDiff[mCurrentTestRound].length) {
993                         mEncoderFrameTimeUsDiff[mCurrentTestRound][pos] = nowUs - lastOutputTimeUs;
994                     }
995                     lastOutputTimeUs = nowUs;
996 
997                     numBytesDequeued += info.size;
998                     ++outFramesCount;
999                 }
1000                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
1001                     if (VERBOSE) {
1002                         Log.d(TAG, "dequeued output EOS.");
1003                     }
1004                     break;
1005                 }
1006                 if (VERBOSE) {
1007                     Log.d(TAG, "dequeued " + info.size + " bytes of output data.");
1008                 }
1009             }
1010         }
1011         long finish = System.currentTimeMillis();
1012         int validDataNum = Math.min(mEncodedOutputBuffer.size() - 1,
1013                 mEncoderFrameTimeUsDiff[mCurrentTestRound].length);
1014         mEncoderFrameTimeUsDiff[mCurrentTestRound] =
1015                 Arrays.copyOf(mEncoderFrameTimeUsDiff[mCurrentTestRound], validDataNum);
1016         if (VERBOSE) {
1017             Log.d(TAG, "queued a total of " + numBytesSubmitted + "bytes, "
1018                     + "dequeued " + numBytesDequeued + " bytes.");
1019         }
1020         codec.stop();
1021         codec.release();
1022         codec = null;
1023 
1024         mEncOutputFormat.setInteger(MediaFormat.KEY_BIT_RATE,
1025                 format.getInteger(MediaFormat.KEY_BIT_RATE));
1026         mEncOutputFormat.setInteger(MediaFormat.KEY_FRAME_RATE,
1027                 format.getInteger(MediaFormat.KEY_FRAME_RATE));
1028         if (outFramesCount > 0) {
1029             mEncOutputFormat.setInteger(
1030                     "actual-bitrate",
1031                     (int)(numBytesDequeued * 8. * format.getInteger(MediaFormat.KEY_FRAME_RATE)
1032                             / outFramesCount));
1033         }
1034         return new RunResult(outFramesCount, (finish - start) / 1000.);
1035     }
1036 
1037     /**
1038      * Fills input buffer for encoder from YUV buffers.
1039      * @return size of enqueued data.
1040      */
queueInputBufferEncoder( MediaCodec codec, ByteBuffer buffer, int index, int frameCount, int flags, int runId)1041     private int queueInputBufferEncoder(
1042             MediaCodec codec, ByteBuffer buffer, int index, int frameCount, int flags, int runId) {
1043         buffer.clear();
1044 
1045         Point origin = getOrigin(frameCount, runId);
1046         // Y color first
1047         int srcOffsetY = origin.x + origin.y * mBufferWidth;
1048         final byte[] yBuffer = mYBuffer.array();
1049         for (int i = 0; i < mVideoHeight; i++) {
1050             buffer.position(i * mVideoStride);
1051             buffer.put(yBuffer, srcOffsetY, mVideoWidth);
1052             srcOffsetY += mBufferWidth;
1053         }
1054         if (isSrcSemiPlanar()) {
1055             int srcOffsetU = origin.y / 2 * mBufferWidth + origin.x / 2 * 2;
1056             final byte[] uvBuffer = mUVBuffer.array();
1057             for (int i = 0; i < mVideoHeight / 2; i++) {
1058                 buffer.position(mVideoVStride * mVideoStride + i * mVideoStride);
1059                 buffer.put(uvBuffer, srcOffsetU, mVideoWidth);
1060                 srcOffsetU += mBufferWidth;
1061             }
1062         } else {
1063             int srcOffsetU = origin.y / 2 * mBufferWidth / 2 + origin.x / 2;
1064             int srcOffsetV = srcOffsetU + mBufferWidth / 2 * mBufferHeight / 2;
1065             final byte[] uvBuffer = mUVBuffer.array();
1066             for (int i = 0; i < mVideoHeight / 2; i++) { //U only
1067                 buffer.position(mVideoVStride * mVideoStride + i * mVideoStride / 2);
1068                 buffer.put(uvBuffer, srcOffsetU, mVideoWidth / 2);
1069                 srcOffsetU += mBufferWidth / 2;
1070             }
1071             for (int i = 0; i < mVideoHeight / 2; i++) { //V only
1072                 buffer.position(mVideoVStride * mVideoStride * 5 / 4 + i * mVideoStride / 2);
1073                 buffer.put(uvBuffer, srcOffsetV, mVideoWidth / 2);
1074                 srcOffsetV += mBufferWidth / 2;
1075             }
1076         }
1077         // submit till end of stride
1078         int size = /* buffer.position(); */ mVideoStride * (mVideoVStride + mVideoHeight / 2);
1079         long ptsUsec = computePresentationTime(frameCount);
1080 
1081         codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
1082         if (VERBOSE && (frameCount == 0)) {
1083             printByteArray("Y ", mYBuffer.array(), 0, 20);
1084             printByteArray("UV ", mUVBuffer.array(), 0, 20);
1085             printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
1086         }
1087         return size;
1088     }
1089 
1090     /**
1091      * Fills input image for encoder from YUV buffers.
1092      * @return size of enqueued data.
1093      */
queueInputImageEncoder( MediaCodec codec, Image image, int index, int frameCount, int flags, int runId)1094     private int queueInputImageEncoder(
1095             MediaCodec codec, Image image, int index, int frameCount, int flags, int runId) {
1096         assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
1097 
1098 
1099         Point origin = getOrigin(frameCount, runId);
1100 
1101         // Y color first
1102         CodecImage srcImage = new YUVImage(
1103                 origin,
1104                 mVideoWidth, mVideoHeight,
1105                 mBufferWidth, mBufferHeight,
1106                 isSrcSemiPlanar(),
1107                 mYDirectBuffer, mUVDirectBuffer);
1108 
1109         CodecUtils.copyFlexYUVImage(image, srcImage);
1110 
1111         int size = mVideoHeight * mVideoWidth * 3 / 2;
1112         long ptsUsec = computePresentationTime(frameCount);
1113 
1114         codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
1115         if (VERBOSE && (frameCount == 0)) {
1116             printByteArray("Y ", mYBuffer.array(), 0, 20);
1117             printByteArray("UV ", mUVBuffer.array(), 0, 20);
1118             printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
1119         }
1120         return size;
1121     }
1122 
1123     /**
1124      * Dequeue encoded data from output buffer and store for later usage.
1125      */
dequeueOutputBufferEncoder( MediaCodec codec, ByteBuffer[] outputBuffers, int index, MediaCodec.BufferInfo info)1126     private void dequeueOutputBufferEncoder(
1127             MediaCodec codec, ByteBuffer[] outputBuffers,
1128             int index, MediaCodec.BufferInfo info) {
1129         ByteBuffer output = outputBuffers[index];
1130         int l = info.size;
1131         ByteBuffer copied = ByteBuffer.allocate(l);
1132         output.get(copied.array(), 0, l);
1133         BufferInfo savedInfo = new BufferInfo();
1134         savedInfo.set(0, l, info.presentationTimeUs, info.flags);
1135         mEncodedOutputBuffer.addLast(Pair.create(copied, savedInfo));
1136         codec.releaseOutputBuffer(index, false /* render */);
1137     }
1138 
1139     /**
1140      * run decoder benchmarking with encoded stream stored from encoding phase
1141      * @param decoderName decoder name
1142      * @param format format of media to decode
1143      * @return returns length-2 array with 0: time for decoding, 1 : rms error of pixels
1144      */
runDecoder(String decoderName, MediaFormat format, int runId)1145     private RunResult runDecoder(String decoderName, MediaFormat format, int runId) {
1146         MediaCodec codec = null;
1147         try {
1148             codec = MediaCodec.createByCodecName(decoderName);
1149         } catch (IOException | NullPointerException e) {
1150             Log.i(TAG, "could not find decoder for " + format);
1151             return null;
1152         }
1153         codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
1154         codec.start();
1155         ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
1156 
1157         double totalErrorSquared = 0;
1158 
1159         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
1160         boolean sawOutputEOS = false;
1161         int inputLeft = mEncodedOutputBuffer.size();
1162         int inputBufferCount = 0;
1163         int outFrameCount = 0;
1164         YUVValue expected = new YUVValue();
1165         YUVValue decoded = new YUVValue();
1166         long lastOutputTimeUs = 0;
1167         long start = System.currentTimeMillis();
1168         while (!sawOutputEOS) {
1169             if (inputLeft > 0) {
1170                 int inputBufIndex = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US);
1171 
1172                 if (inputBufIndex >= 0) {
1173                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
1174                     dstBuf.clear();
1175                     ByteBuffer src = mEncodedOutputBuffer.get(inputBufferCount).first;
1176                     BufferInfo srcInfo = mEncodedOutputBuffer.get(inputBufferCount).second;
1177                     int writeSize = src.capacity();
1178                     dstBuf.put(src.array(), 0, writeSize);
1179 
1180                     int flags = srcInfo.flags;
1181                     if ((System.currentTimeMillis() - start) > mTestConfig.mMaxTimeMs) {
1182                         flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
1183                     }
1184 
1185                     codec.queueInputBuffer(
1186                             inputBufIndex,
1187                             0 /* offset */,
1188                             writeSize,
1189                             srcInfo.presentationTimeUs,
1190                             flags);
1191                     inputLeft --;
1192                     inputBufferCount ++;
1193                 }
1194             }
1195 
1196             int res = codec.dequeueOutputBuffer(info, VIDEO_CODEC_WAIT_TIME_US);
1197             if (res >= 0) {
1198                 int outputBufIndex = res;
1199 
1200                 // only do YUV compare on EOS frame if the buffer size is none-zero
1201                 if (info.size > 0) {
1202                     long nowUs = (System.nanoTime() + 500) / 1000;
1203                     int pos = outFrameCount - 1;
1204                     if (pos >= 0 && pos < mDecoderFrameTimeUsDiff[mCurrentTestRound].length) {
1205                         mDecoderFrameTimeUsDiff[mCurrentTestRound][pos] = nowUs - lastOutputTimeUs;
1206                     }
1207                     lastOutputTimeUs = nowUs;
1208 
1209                     if (mTestConfig.mTestPixels) {
1210                         Point origin = getOrigin(outFrameCount, runId);
1211                         int i;
1212 
1213                         // if decoder supports planar or semiplanar, check output with
1214                         // ByteBuffer & Image each on half of the points
1215                         int pixelCheckPerFrame = PIXEL_CHECK_PER_FRAME;
1216                         if (!isDstFlexYUV()) {
1217                             pixelCheckPerFrame /= 2;
1218                             ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
1219                             if (VERBOSE && (outFrameCount == 0)) {
1220                                 printByteBuffer("Y ", buf, 0, 20);
1221                                 printByteBuffer("UV ", buf, mVideoWidth * mVideoHeight, 20);
1222                                 printByteBuffer("UV ", buf,
1223                                         mVideoWidth * mVideoHeight + mVideoWidth * 60, 20);
1224                             }
1225                             for (i = 0; i < pixelCheckPerFrame; i++) {
1226                                 int w = mRandom.nextInt(mVideoWidth);
1227                                 int h = mRandom.nextInt(mVideoHeight);
1228                                 getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
1229                                 getPixelValuesFromOutputBuffer(buf, w, h, decoded);
1230                                 if (VERBOSE) {
1231                                     Log.i(TAG, outFrameCount + "-" + i + "- th round: ByteBuffer:"
1232                                             + " expected "
1233                                             + expected.mY + "," + expected.mU + "," + expected.mV
1234                                             + " decoded "
1235                                             + decoded.mY + "," + decoded.mU + "," + decoded.mV);
1236                                 }
1237                                 totalErrorSquared += expected.calcErrorSquared(decoded);
1238                             }
1239                         }
1240 
1241                         Image image = codec.getOutputImage(outputBufIndex);
1242                         assertTrue(image != null);
1243                         for (i = 0; i < pixelCheckPerFrame; i++) {
1244                             int w = mRandom.nextInt(mVideoWidth);
1245                             int h = mRandom.nextInt(mVideoHeight);
1246                             getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
1247                             getPixelValuesFromImage(image, w, h, decoded);
1248                             if (VERBOSE) {
1249                                 Log.i(TAG, outFrameCount + "-" + i + "- th round: FlexYUV:"
1250                                         + " expcted "
1251                                         + expected.mY + "," + expected.mU + "," + expected.mV
1252                                         + " decoded "
1253                                         + decoded.mY + "," + decoded.mU + "," + decoded.mV);
1254                             }
1255                             totalErrorSquared += expected.calcErrorSquared(decoded);
1256                         }
1257                     }
1258                     outFrameCount++;
1259                 }
1260                 codec.releaseOutputBuffer(outputBufIndex, false /* render */);
1261                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
1262                     Log.d(TAG, "saw output EOS.");
1263                     sawOutputEOS = true;
1264                 }
1265             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
1266                 mDecOutputFormat = codec.getOutputFormat();
1267                 Log.d(TAG, "output format has changed to " + mDecOutputFormat);
1268                 int colorFormat = mDecOutputFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
1269                 if (colorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar
1270                         || colorFormat == CodecCapabilities.COLOR_FormatYUV420Planar) {
1271                     mDstColorFormat = colorFormat;
1272                 } else {
1273                     mDstColorFormat = CodecCapabilities.COLOR_FormatYUV420Flexible;
1274                     Log.w(TAG, "output format changed to unsupported one " +
1275                             Integer.toHexString(colorFormat) + ", using FlexYUV");
1276                 }
1277                 mVideoStride = mDecOutputFormat.containsKey(MediaFormat.KEY_STRIDE)
1278                         ? mDecOutputFormat.getInteger(MediaFormat.KEY_STRIDE)
1279                         : mDecOutputFormat.getInteger(MediaFormat.KEY_WIDTH);
1280                 mVideoVStride = mDecOutputFormat.containsKey(MediaFormat.KEY_SLICE_HEIGHT)
1281                         ? mDecOutputFormat.getInteger(MediaFormat.KEY_SLICE_HEIGHT)
1282                         : mDecOutputFormat.getInteger(MediaFormat.KEY_HEIGHT);
1283             }
1284         }
1285         long finish = System.currentTimeMillis();
1286         int validDataNum = Math.min(outFrameCount - 1,
1287                 mDecoderFrameTimeUsDiff[mCurrentTestRound].length);
1288         mDecoderFrameTimeUsDiff[mCurrentTestRound] =
1289                 Arrays.copyOf(mDecoderFrameTimeUsDiff[mCurrentTestRound], validDataNum);
1290         codec.stop();
1291         codec.release();
1292         codec = null;
1293 
1294         // divide by 3 as sum is done for Y, U, V.
1295         double errorRms = Math.sqrt(totalErrorSquared / PIXEL_CHECK_PER_FRAME / outFrameCount / 3);
1296         return new RunResult(outFrameCount, (finish - start) / 1000., errorRms);
1297     }
1298 
1299     /**
1300      *  returns origin in the absolute frame for given frame count.
1301      *  The video scene is moving by moving origin per each frame.
1302      */
getOrigin(int frameCount, int runId)1303     private Point getOrigin(int frameCount, int runId) {
1304         // Translation is basically:
1305         //    x = A * sin(B * t) + C * t
1306         //    y = D * cos(E * t) + F * t
1307         //    'bouncing' in a [0, length] regions (constrained to [0, length] by mirroring at 0
1308         //    and length.)
1309         double x = (1 - Math.sin(frameCount / (7. + (runId % 2)))) * 0.1 + frameCount * 0.005;
1310         double y = (1 - Math.cos(frameCount / (10. + (runId & ~1))))
1311                 + frameCount * (0.01 + runId / 1000.);
1312 
1313         // At every 32nd or 13th frame out of 32, an additional varying offset is added to
1314         // produce a jerk.
1315         if (frameCount % 32 == 0) {
1316             x += ((frameCount % 64) / 32) + 0.3 + y;
1317         }
1318         if (frameCount % 32 == 13) {
1319             y += ((frameCount % 64) / 32) + 0.6 + x;
1320         }
1321 
1322         // constrain to region
1323         int xi = (int)((x % 2) * YUV_PLANE_ADDITIONAL_LENGTH);
1324         int yi = (int)((y % 2) * YUV_PLANE_ADDITIONAL_LENGTH);
1325         if (xi > YUV_PLANE_ADDITIONAL_LENGTH) {
1326             xi = 2 * YUV_PLANE_ADDITIONAL_LENGTH - xi;
1327         }
1328         if (yi > YUV_PLANE_ADDITIONAL_LENGTH) {
1329             yi = 2 * YUV_PLANE_ADDITIONAL_LENGTH - yi;
1330         }
1331         return new Point(xi, yi);
1332     }
1333 
1334     /**
1335      * initialize reference YUV plane
1336      * @param w This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
1337      *          to allow movements
1338      * @param h This should be YUV_PLANE_ADDITIONAL_LENGTH pixels bigger than video resolution
1339      *          to allow movements
1340      * @param semiPlanarEnc
1341      * @param semiPlanarDec
1342      */
initYUVPlane(int w, int h)1343     private void initYUVPlane(int w, int h) {
1344         int bufferSizeY = w * h;
1345         mYBuffer = ByteBuffer.allocate(bufferSizeY);
1346         mUVBuffer = ByteBuffer.allocate(bufferSizeY / 2);
1347         mYDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY);
1348         mUVDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY / 2);
1349         mBufferWidth = w;
1350         mBufferHeight = h;
1351         final byte[] yArray = mYBuffer.array();
1352         final byte[] uvArray = mUVBuffer.array();
1353         for (int i = 0; i < h; i++) {
1354             for (int j = 0; j < w; j++) {
1355                 yArray[i * w + j]  = clampY((i + j) & 0xff);
1356             }
1357         }
1358         if (isSrcSemiPlanar()) {
1359             for (int i = 0; i < h/2; i++) {
1360                 for (int j = 0; j < w/2; j++) {
1361                     uvArray[i * w + 2 * j]  = (byte) (i & 0xff);
1362                     uvArray[i * w + 2 * j + 1]  = (byte) (j & 0xff);
1363                 }
1364             }
1365         } else { // planar, U first, then V
1366             int vOffset = bufferSizeY / 4;
1367             for (int i = 0; i < h/2; i++) {
1368                 for (int j = 0; j < w/2; j++) {
1369                     uvArray[i * w/2 + j]  = (byte) (i & 0xff);
1370                     uvArray[i * w/2 + vOffset + j]  = (byte) (j & 0xff);
1371                 }
1372             }
1373         }
1374         mYDirectBuffer.put(yArray);
1375         mUVDirectBuffer.put(uvArray);
1376         mYDirectBuffer.rewind();
1377         mUVDirectBuffer.rewind();
1378     }
1379 
1380     /**
1381      * class to store pixel values in YUV
1382      *
1383      */
1384     public class YUVValue {
1385         public byte mY;
1386         public byte mU;
1387         public byte mV;
YUVValue()1388         public YUVValue() {
1389         }
1390 
equalTo(YUVValue other)1391         public boolean equalTo(YUVValue other) {
1392             return (mY == other.mY) && (mU == other.mU) && (mV == other.mV);
1393         }
1394 
calcErrorSquared(YUVValue other)1395         public double calcErrorSquared(YUVValue other) {
1396             // Java's byte is signed but here we want to calculate difference in unsigned bytes.
1397             double yDelta = (mY & 0xFF) - (other.mY & 0xFF);
1398             double uDelta = (mU & 0xFF) - (other.mU & 0xFF);
1399             double vDelta = (mV & 0xFF) - (other.mV & 0xFF);
1400             return yDelta * yDelta + uDelta * uDelta + vDelta * vDelta;
1401         }
1402     }
1403 
1404     /**
1405      * Read YUV values from given position (x,y) for given origin (originX, originY)
1406      * The whole data is already available from YBuffer and UVBuffer.
1407      * @param result pass the result via this. This is for avoiding creating / destroying too many
1408      *               instances
1409      */
getPixelValuesFromYUVBuffers(int originX, int originY, int x, int y, YUVValue result)1410     private void getPixelValuesFromYUVBuffers(int originX, int originY, int x, int y,
1411             YUVValue result) {
1412         result.mY = mYBuffer.get((originY + y) * mBufferWidth + (originX + x));
1413         if (isSrcSemiPlanar()) {
1414             int index = (originY + y) / 2 * mBufferWidth + (originX + x) / 2 * 2;
1415             //Log.d(TAG, "YUV " + originX + "," + originY + "," + x + "," + y + "," + index);
1416             result.mU = mUVBuffer.get(index);
1417             result.mV = mUVBuffer.get(index + 1);
1418         } else {
1419             int vOffset = mBufferWidth * mBufferHeight / 4;
1420             int index = (originY + y) / 2 * mBufferWidth / 2 + (originX + x) / 2;
1421             result.mU = mUVBuffer.get(index);
1422             result.mV = mUVBuffer.get(vOffset + index);
1423         }
1424     }
1425 
1426     /**
1427      * Read YUV pixels from decoded output buffer for give (x, y) position
1428      * Output buffer is composed of Y parts followed by U/V
1429      * @param result pass the result via this. This is for avoiding creating / destroying too many
1430      *               instances
1431      */
getPixelValuesFromOutputBuffer(ByteBuffer buffer, int x, int y, YUVValue result)1432     private void getPixelValuesFromOutputBuffer(ByteBuffer buffer, int x, int y, YUVValue result) {
1433         result.mY = buffer.get(y * mVideoStride + x);
1434         if (isDstSemiPlanar()) {
1435             int index = mVideoStride * mVideoVStride + y / 2 * mVideoStride + x / 2 * 2;
1436             //Log.d(TAG, "Decoded " + x + "," + y + "," + index);
1437             result.mU = buffer.get(index);
1438             result.mV = buffer.get(index + 1);
1439         } else {
1440             int vOffset = mVideoStride * mVideoVStride / 4;
1441             int index = mVideoStride * mVideoVStride + y / 2 * mVideoStride / 2 + x / 2;
1442             result.mU = buffer.get(index);
1443             result.mV = buffer.get(index + vOffset);
1444         }
1445     }
1446 
getPixelValuesFromImage(Image image, int x, int y, YUVValue result)1447     private void getPixelValuesFromImage(Image image, int x, int y, YUVValue result) {
1448         assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
1449 
1450         Plane[] planes = image.getPlanes();
1451         assertTrue(planes.length == 3);
1452 
1453         result.mY = getPixelFromPlane(planes[0], x, y);
1454         result.mU = getPixelFromPlane(planes[1], x / 2, y / 2);
1455         result.mV = getPixelFromPlane(planes[2], x / 2, y / 2);
1456     }
1457 
getPixelFromPlane(Plane plane, int x, int y)1458     private byte getPixelFromPlane(Plane plane, int x, int y) {
1459         ByteBuffer buf = plane.getBuffer();
1460         return buf.get(y * plane.getRowStride() + x * plane.getPixelStride());
1461     }
1462 
1463     /**
1464      * Y cannot have full range. clamp it to prevent invalid value.
1465      */
clampY(int y)1466     private byte clampY(int y) {
1467         if (y < Y_CLAMP_MIN) {
1468             y = Y_CLAMP_MIN;
1469         } else if (y > Y_CLAMP_MAX) {
1470             y = Y_CLAMP_MAX;
1471         }
1472         return (byte) (y & 0xff);
1473     }
1474 
1475     // for debugging
printByteArray(String msg, byte[] data, int offset, int len)1476     private void printByteArray(String msg, byte[] data, int offset, int len) {
1477         StringBuilder builder = new StringBuilder();
1478         builder.append(msg);
1479         builder.append(":");
1480         for (int i = offset; i < offset + len; i++) {
1481             builder.append(Integer.toHexString(data[i]));
1482             builder.append(",");
1483         }
1484         builder.deleteCharAt(builder.length() - 1);
1485         Log.i(TAG, builder.toString());
1486     }
1487 
1488     // for debugging
printByteBuffer(String msg, ByteBuffer data, int offset, int len)1489     private void printByteBuffer(String msg, ByteBuffer data, int offset, int len) {
1490         StringBuilder builder = new StringBuilder();
1491         builder.append(msg);
1492         builder.append(":");
1493         for (int i = offset; i < offset + len; i++) {
1494             builder.append(Integer.toHexString(data.get(i)));
1495             builder.append(",");
1496         }
1497         builder.deleteCharAt(builder.length() - 1);
1498         Log.i(TAG, builder.toString());
1499     }
1500 
1501     /**
1502      * Generates the presentation time for frame N, in microseconds.
1503      */
computePresentationTime(int frameIndex)1504     private long computePresentationTime(int frameIndex) {
1505         return 132 + frameIndex * 1000000L / mFrameRate;
1506     }
1507 }
1508