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