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