1 /*
2  * Copyright 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.cts;
18 
19 import android.media.cts.R;
20 
21 import android.media.cts.CodecUtils;
22 
23 import android.graphics.ImageFormat;
24 import android.graphics.SurfaceTexture;
25 import android.media.Image;
26 import android.media.MediaCodec;
27 import android.media.MediaCodec.BufferInfo;
28 import android.media.MediaCodecInfo;
29 import android.media.MediaCodecInfo.CodecCapabilities;
30 import android.media.MediaCodecInfo.VideoCapabilities;
31 import android.media.MediaCodecList;
32 import android.media.MediaExtractor;
33 import android.media.MediaFormat;
34 import android.media.MediaMuxer;
35 import android.net.Uri;
36 import android.util.Log;
37 import android.util.Pair;
38 import android.util.Range;
39 import android.util.Size;
40 import android.view.Surface;
41 
42 import com.android.compatibility.common.util.MediaUtils;
43 
44 import java.io.File;
45 import java.io.IOException;
46 import java.nio.ByteBuffer;
47 import java.util.ArrayList;
48 import java.util.function.Consumer;
49 import java.util.function.Function;
50 import java.util.HashMap;
51 import java.util.HashSet;
52 import java.util.Iterator;
53 import java.util.LinkedList;
54 import java.util.Map;
55 import java.util.Set;
56 
57 public class VideoEncoderTest extends MediaPlayerTestBase {
58     private static final int MAX_SAMPLE_SIZE = 256 * 1024;
59     private static final String TAG = "VideoEncoderTest";
60     private static final long FRAME_TIMEOUT_MS = 1000;
61     // use larger delay before we get first frame, some encoders may need more time
62     private static final long INIT_TIMEOUT_MS = 2000;
63 
64     private static final String SOURCE_URL =
65         "android.resource://android.media.cts/raw/video_480x360_mp4_h264_871kbps_30fps";
66 
67     private final boolean DEBUG = false;
68 
69     class VideoStorage {
70         private LinkedList<Pair<ByteBuffer, BufferInfo>> mStream;
71         private MediaFormat mFormat;
72         private int mInputBufferSize;
73 
VideoStorage()74         public VideoStorage() {
75             mStream = new LinkedList<Pair<ByteBuffer, BufferInfo>>();
76         }
77 
setFormat(MediaFormat format)78         public void setFormat(MediaFormat format) {
79             mFormat = format;
80         }
81 
addBuffer(ByteBuffer buffer, BufferInfo info)82         public void addBuffer(ByteBuffer buffer, BufferInfo info) {
83             ByteBuffer savedBuffer = ByteBuffer.allocate(info.size);
84             savedBuffer.put(buffer);
85             if (info.size > mInputBufferSize) {
86                 mInputBufferSize = info.size;
87             }
88             BufferInfo savedInfo = new BufferInfo();
89             savedInfo.set(0, savedBuffer.position(), info.presentationTimeUs, info.flags);
90             mStream.addLast(Pair.create(savedBuffer, savedInfo));
91         }
92 
play(MediaCodec decoder, Surface surface)93         private void play(MediaCodec decoder, Surface surface) {
94             decoder.reset();
95             final Object condition = new Object();
96             final Iterator<Pair<ByteBuffer, BufferInfo>> it = mStream.iterator();
97             decoder.setCallback(new MediaCodec.Callback() {
98                 public void onOutputBufferAvailable(MediaCodec codec, int ix, BufferInfo info) {
99                     codec.releaseOutputBuffer(ix, info.size > 0);
100                     if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
101                         synchronized (condition) {
102                             condition.notifyAll();
103                         }
104                     }
105                 }
106                 public void onInputBufferAvailable(MediaCodec codec, int ix) {
107                     if (it.hasNext()) {
108                         Pair<ByteBuffer, BufferInfo> el = it.next();
109                         el.first.clear();
110                         try {
111                             codec.getInputBuffer(ix).put(el.first);
112                         } catch (java.nio.BufferOverflowException e) {
113                             Log.e(TAG, "cannot fit " + el.first.limit()
114                                     + "-byte encoded buffer into "
115                                     + codec.getInputBuffer(ix).remaining()
116                                     + "-byte input buffer of " + codec.getName()
117                                     + " configured for " + codec.getInputFormat());
118                             throw e;
119                         }
120                         BufferInfo info = el.second;
121                         codec.queueInputBuffer(
122                                 ix, 0, info.size, info.presentationTimeUs, info.flags);
123                     }
124                 }
125                 public void onError(MediaCodec codec, MediaCodec.CodecException e) {
126                     Log.i(TAG, "got codec exception", e);
127                     fail("received codec error during decode" + e);
128                 }
129                 public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
130                     Log.i(TAG, "got output format " + format);
131                 }
132             });
133             mFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, mInputBufferSize);
134             decoder.configure(mFormat, surface, null /* crypto */, 0 /* flags */);
135             decoder.start();
136             synchronized (condition) {
137                 try {
138                     condition.wait();
139                 } catch (InterruptedException e) {
140                     fail("playback interrupted");
141                 }
142             }
143             decoder.stop();
144         }
145 
playAll(Surface surface)146         public void playAll(Surface surface) {
147             if (mFormat == null) {
148                 Log.i(TAG, "no stream to play");
149                 return;
150             }
151             String mime = mFormat.getString(MediaFormat.KEY_MIME);
152             MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
153             for (MediaCodecInfo info : mcl.getCodecInfos()) {
154                 if (info.isEncoder()) {
155                     continue;
156                 }
157                 MediaCodec codec = null;
158                 try {
159                     CodecCapabilities caps = info.getCapabilitiesForType(mime);
160                     if (!caps.isFormatSupported(mFormat)) {
161                         continue;
162                     }
163                     codec = MediaCodec.createByCodecName(info.getName());
164                 } catch (IllegalArgumentException | IOException e) {
165                     continue;
166                 }
167                 play(codec, surface);
168                 codec.release();
169             }
170         }
171     }
172 
173     abstract class VideoProcessorBase extends MediaCodec.Callback {
174         private static final String TAG = "VideoProcessorBase";
175 
176         /*
177          * Set this to true to save the encoding results to /data/local/tmp
178          * You will need to make /data/local/tmp writeable, run "setenforce 0",
179          * and remove files left from a previous run.
180          */
181         private boolean mSaveResults = false;
182         private static final String FILE_DIR = "/data/local/tmp";
183         protected int mMuxIndex = -1;
184 
185         protected String mProcessorName = "VideoProcessor";
186         private MediaExtractor mExtractor;
187         protected MediaMuxer mMuxer;
188         private ByteBuffer mBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
189         protected int mTrackIndex = -1;
190         private boolean mSignaledDecoderEOS;
191 
192         protected boolean mCompleted;
193         protected boolean mEncoderIsActive;
194         protected boolean mEncodeOutputFormatUpdated;
195         protected final Object mCondition = new Object();
196         protected final Object mCodecLock = new Object();
197 
198         protected MediaFormat mDecFormat;
199         protected MediaCodec mDecoder, mEncoder;
200 
201         private VideoStorage mEncodedStream;
202         protected int mFrameRate = 0;
203         protected int mBitRate = 0;
204 
205         protected Function<MediaFormat, Boolean> mUpdateConfigFormatHook;
206         protected Function<MediaFormat, Boolean> mCheckOutputFormatHook;
207 
setProcessorName(String name)208         public void setProcessorName(String name) {
209             mProcessorName = name;
210         }
211 
setUpdateConfigHook(Function<MediaFormat, Boolean> hook)212         public void setUpdateConfigHook(Function<MediaFormat, Boolean> hook) {
213             mUpdateConfigFormatHook = hook;
214         }
215 
setCheckOutputFormatHook(Function<MediaFormat, Boolean> hook)216         public void setCheckOutputFormatHook(Function<MediaFormat, Boolean> hook) {
217             mCheckOutputFormatHook = hook;
218         }
219 
open(String path)220         protected void open(String path) throws IOException {
221             mExtractor = new MediaExtractor();
222             if (path.startsWith("android.resource://")) {
223                 mExtractor.setDataSource(mContext, Uri.parse(path), null);
224             } else {
225                 mExtractor.setDataSource(path);
226             }
227 
228             for (int i = 0; i < mExtractor.getTrackCount(); i++) {
229                 MediaFormat fmt = mExtractor.getTrackFormat(i);
230                 String mime = fmt.getString(MediaFormat.KEY_MIME).toLowerCase();
231                 if (mime.startsWith("video/")) {
232                     mTrackIndex = i;
233                     mDecFormat = fmt;
234                     mExtractor.selectTrack(i);
235                     break;
236                 }
237             }
238             mEncodedStream = new VideoStorage();
239             assertTrue("file " + path + " has no video", mTrackIndex >= 0);
240         }
241 
242         // returns true if encoder supports the size
initCodecsAndConfigureEncoder( String videoEncName, String outMime, int width, int height, int colorFormat)243         protected boolean initCodecsAndConfigureEncoder(
244                 String videoEncName, String outMime, int width, int height,
245                 int colorFormat) throws IOException {
246             mDecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
247 
248             MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
249             String videoDecName = mcl.findDecoderForFormat(mDecFormat);
250             Log.i(TAG, "decoder for " + mDecFormat + " is " + videoDecName);
251             mDecoder = MediaCodec.createByCodecName(videoDecName);
252             mEncoder = MediaCodec.createByCodecName(videoEncName);
253 
254             mDecoder.setCallback(this);
255             mEncoder.setCallback(this);
256 
257             VideoCapabilities encCaps =
258                 mEncoder.getCodecInfo().getCapabilitiesForType(outMime).getVideoCapabilities();
259             if (!encCaps.isSizeSupported(width, height)) {
260                 Log.i(TAG, videoEncName + " does not support size: " + width + "x" + height);
261                 return false;
262             }
263 
264             MediaFormat outFmt = MediaFormat.createVideoFormat(outMime, width, height);
265             int bitRate = 0;
266             MediaUtils.setMaxEncoderFrameAndBitrates(encCaps, outFmt, 30);
267             if (mFrameRate > 0) {
268                 outFmt.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
269             }
270             if (mBitRate > 0) {
271                 outFmt.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
272             }
273             outFmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
274             outFmt.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
275             // Some extra configure before starting the encoder.
276             if (mUpdateConfigFormatHook != null) {
277                 if (!mUpdateConfigFormatHook.apply(outFmt)) {
278                     return false;
279                 }
280             }
281             mEncoder.configure(outFmt, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
282             Log.i(TAG, "encoder input format " + mEncoder.getInputFormat() + " from " + outFmt);
283             if (mSaveResults) {
284                 try {
285                     String outFileName =
286                             FILE_DIR + mProcessorName + "_" + bitRate + "bps";
287                     if (outMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
288                             outMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
289                         mMuxer = new MediaMuxer(
290                                 outFileName + ".webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
291                     } else {
292                         mMuxer = new MediaMuxer(
293                                 outFileName + ".mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
294                     }
295                     // The track can't be added until we have the codec specific data
296                 } catch (Exception e) {
297                     Log.i(TAG, "couldn't create muxer: " + e);
298                 }
299             }
300             return true;
301         }
302 
close()303         protected void close() {
304             synchronized (mCodecLock) {
305                 if (mDecoder != null) {
306                     mDecoder.release();
307                     mDecoder = null;
308                 }
309                 if (mEncoder != null) {
310                     mEncoder.release();
311                     mEncoder = null;
312                 }
313             }
314             if (mExtractor != null) {
315                 mExtractor.release();
316                 mExtractor = null;
317             }
318             if (mMuxer != null) {
319                 mMuxer.stop();
320                 mMuxer.release();
321                 mMuxer = null;
322             }
323         }
324 
325         // returns true if filled buffer
fillDecoderInputBuffer(int ix)326         protected boolean fillDecoderInputBuffer(int ix) {
327             if (DEBUG) Log.v(TAG, "decoder received input #" + ix);
328             while (!mSignaledDecoderEOS) {
329                 int track = mExtractor.getSampleTrackIndex();
330                 if (track >= 0 && track != mTrackIndex) {
331                     mExtractor.advance();
332                     continue;
333                 }
334                 int size = mExtractor.readSampleData(mBuffer, 0);
335                 if (size < 0) {
336                     // queue decoder input EOS
337                     if (DEBUG) Log.v(TAG, "queuing decoder EOS");
338                     mDecoder.queueInputBuffer(
339                             ix, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
340                     mSignaledDecoderEOS = true;
341                 } else {
342                     mBuffer.limit(size);
343                     mBuffer.position(0);
344                     BufferInfo info = new BufferInfo();
345                     info.set(
346                             0, mBuffer.limit(), mExtractor.getSampleTime(),
347                             mExtractor.getSampleFlags());
348                     mDecoder.getInputBuffer(ix).put(mBuffer);
349                     if (DEBUG) Log.v(TAG, "queing input #" + ix + " for decoder with timestamp "
350                             + info.presentationTimeUs);
351                     mDecoder.queueInputBuffer(
352                             ix, 0, mBuffer.limit(), info.presentationTimeUs, 0);
353                 }
354                 mExtractor.advance();
355                 return true;
356             }
357             return false;
358         }
359 
emptyEncoderOutputBuffer(int ix, BufferInfo info)360         protected void emptyEncoderOutputBuffer(int ix, BufferInfo info) {
361             if (DEBUG) Log.v(TAG, "encoder received output #" + ix
362                      + " (sz=" + info.size + ", f=" + info.flags
363                      + ", ts=" + info.presentationTimeUs + ")");
364             ByteBuffer outputBuffer = mEncoder.getOutputBuffer(ix);
365             mEncodedStream.addBuffer(outputBuffer, info);
366 
367             if (mMuxer != null) {
368                 // reset position as addBuffer() modifies it
369                 outputBuffer.position(info.offset);
370                 outputBuffer.limit(info.offset + info.size);
371                 mMuxer.writeSampleData(mMuxIndex, outputBuffer, info);
372             }
373 
374             if (!mCompleted) {
375                 mEncoder.releaseOutputBuffer(ix, false);
376                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
377                     Log.d(TAG, "encoder received output EOS");
378                     synchronized(mCondition) {
379                         mCompleted = true;
380                         mCondition.notifyAll(); // condition is always satisfied
381                     }
382                 } else {
383                     synchronized(mCondition) {
384                         mEncoderIsActive = true;
385                     }
386                 }
387             }
388         }
389 
saveEncoderFormat(MediaFormat format)390         protected void saveEncoderFormat(MediaFormat format) {
391             mEncodedStream.setFormat(format);
392             if (mCheckOutputFormatHook != null) {
393                 mCheckOutputFormatHook.apply(format);
394             }
395             if (mMuxer != null) {
396                 if (mMuxIndex < 0) {
397                     mMuxIndex = mMuxer.addTrack(format);
398                     mMuxer.start();
399                 }
400             }
401         }
402 
playBack(Surface surface)403         public void playBack(Surface surface) {
404             mEncodedStream.playAll(surface);
405         }
406 
setFrameAndBitRates(int frameRate, int bitRate)407         public void setFrameAndBitRates(int frameRate, int bitRate) {
408             mFrameRate = frameRate;
409             mBitRate = bitRate;
410         }
411 
412         @Override
onInputBufferAvailable(MediaCodec mediaCodec, int ix)413         public void onInputBufferAvailable(MediaCodec mediaCodec, int ix) {
414             synchronized (mCodecLock) {
415                 if (mEncoder != null && mDecoder != null) {
416                     onInputBufferAvailableLocked(mediaCodec, ix);
417                 }
418             }
419         }
420 
421         @Override
onOutputBufferAvailable( MediaCodec mediaCodec, int ix, BufferInfo info)422         public void onOutputBufferAvailable(
423                 MediaCodec mediaCodec, int ix, BufferInfo info) {
424             synchronized (mCodecLock) {
425                 if (mEncoder != null && mDecoder != null) {
426                     onOutputBufferAvailableLocked(mediaCodec, ix, info);
427                 }
428             }
429         }
430 
processLoop( String path, String outMime, String videoEncName, int width, int height, boolean optional)431         public abstract boolean processLoop(
432                 String path, String outMime, String videoEncName,
433                 int width, int height, boolean optional);
onInputBufferAvailableLocked( MediaCodec mediaCodec, int ix)434         protected abstract void onInputBufferAvailableLocked(
435                 MediaCodec mediaCodec, int ix);
onOutputBufferAvailableLocked( MediaCodec mediaCodec, int ix, BufferInfo info)436         protected abstract void onOutputBufferAvailableLocked(
437                 MediaCodec mediaCodec, int ix, BufferInfo info);
438     }
439 
440     class VideoProcessor extends VideoProcessorBase {
441         private static final String TAG = "VideoProcessor";
442         private boolean mWorkInProgress;
443         private boolean mGotDecoderEOS;
444         private boolean mSignaledEncoderEOS;
445 
446         private LinkedList<Pair<Integer, BufferInfo>> mBuffersToRender =
447             new LinkedList<Pair<Integer, BufferInfo>>();
448         private LinkedList<Integer> mEncInputBuffers = new LinkedList<Integer>();
449 
450         private int mEncInputBufferSize = -1;
451 
452         @Override
processLoop( String path, String outMime, String videoEncName, int width, int height, boolean optional)453         public boolean processLoop(
454                  String path, String outMime, String videoEncName,
455                  int width, int height, boolean optional) {
456             boolean skipped = true;
457             try {
458                 open(path);
459                 if (!initCodecsAndConfigureEncoder(
460                         videoEncName, outMime, width, height,
461                         CodecCapabilities.COLOR_FormatYUV420Flexible)) {
462                     assertTrue("could not configure encoder for supported size", optional);
463                     return !skipped;
464                 }
465                 skipped = false;
466 
467                 mDecoder.configure(mDecFormat, null /* surface */, null /* crypto */, 0);
468 
469                 mDecoder.start();
470                 mEncoder.start();
471 
472                 // main loop - process GL ops as only main thread has GL context
473                 while (!mCompleted) {
474                     Pair<Integer, BufferInfo> decBuffer = null;
475                     int encBuffer = -1;
476                     synchronized (mCondition) {
477                         try {
478                             // wait for an encoder input buffer and a decoder output buffer
479                             // Use a timeout to avoid stalling the test if it doesn't arrive.
480                             if (!haveBuffers() && !mCompleted) {
481                                 mCondition.wait(mEncodeOutputFormatUpdated ?
482                                         FRAME_TIMEOUT_MS : INIT_TIMEOUT_MS);
483                             }
484                         } catch (InterruptedException ie) {
485                             fail("wait interrupted");  // shouldn't happen
486                         }
487                         if (mCompleted) {
488                             break;
489                         }
490                         if (!haveBuffers()) {
491                             if (mEncoderIsActive) {
492                                 mEncoderIsActive = false;
493                                 Log.d(TAG, "No more input but still getting output from encoder.");
494                                 continue;
495                             }
496                             fail("timed out after " + mBuffersToRender.size()
497                                     + " decoder output and " + mEncInputBuffers.size()
498                                     + " encoder input buffers");
499                         }
500 
501                         if (DEBUG) Log.v(TAG, "got image");
502                         decBuffer = mBuffersToRender.removeFirst();
503                         encBuffer = mEncInputBuffers.removeFirst();
504                         if (isEOSOnlyBuffer(decBuffer)) {
505                             queueEncoderEOS(decBuffer, encBuffer);
506                             continue;
507                         }
508                         mWorkInProgress = true;
509                     }
510 
511                     if (mWorkInProgress) {
512                         renderDecodedBuffer(decBuffer, encBuffer);
513                         synchronized(mCondition) {
514                             mWorkInProgress = false;
515                         }
516                     }
517                 }
518             } catch (IOException e) {
519                 e.printStackTrace();
520                 fail("received exception " + e);
521             } finally {
522                 close();
523             }
524             return !skipped;
525         }
526 
527         @Override
onInputBufferAvailableLocked(MediaCodec mediaCodec, int ix)528         public void onInputBufferAvailableLocked(MediaCodec mediaCodec, int ix) {
529             if (mediaCodec == mDecoder) {
530                 // fill input buffer from extractor
531                 fillDecoderInputBuffer(ix);
532             } else if (mediaCodec == mEncoder) {
533                 synchronized(mCondition) {
534                     mEncInputBuffers.addLast(ix);
535                     tryToPropagateEOS();
536                     if (haveBuffers()) {
537                         mCondition.notifyAll();
538                     }
539                 }
540             } else {
541                 fail("received input buffer on " + mediaCodec.getName());
542             }
543         }
544 
545         @Override
onOutputBufferAvailableLocked( MediaCodec mediaCodec, int ix, BufferInfo info)546         public void onOutputBufferAvailableLocked(
547                 MediaCodec mediaCodec, int ix, BufferInfo info) {
548             if (mediaCodec == mDecoder) {
549                 if (DEBUG) Log.v(TAG, "decoder received output #" + ix
550                          + " (sz=" + info.size + ", f=" + info.flags
551                          + ", ts=" + info.presentationTimeUs + ")");
552                 // render output buffer from decoder
553                 if (!mGotDecoderEOS) {
554                     boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
555                     // can release empty buffers now
556                     if (info.size == 0) {
557                         mDecoder.releaseOutputBuffer(ix, false /* render */);
558                         ix = -1; // dummy index used by render to not render
559                     }
560                     synchronized(mCondition) {
561                         if (ix < 0 && eos && mBuffersToRender.size() > 0) {
562                             // move lone EOS flag to last buffer to be rendered
563                             mBuffersToRender.peekLast().second.flags |=
564                                 MediaCodec.BUFFER_FLAG_END_OF_STREAM;
565                         } else if (ix >= 0 || eos) {
566                             mBuffersToRender.addLast(Pair.create(ix, info));
567                         }
568                         if (eos) {
569                             tryToPropagateEOS();
570                             mGotDecoderEOS = true;
571                         }
572                         if (haveBuffers()) {
573                             mCondition.notifyAll();
574                         }
575                     }
576                 }
577             } else if (mediaCodec == mEncoder) {
578                 emptyEncoderOutputBuffer(ix, info);
579             } else {
580                 fail("received output buffer on " + mediaCodec.getName());
581             }
582         }
583 
renderDecodedBuffer(Pair<Integer, BufferInfo> decBuffer, int encBuffer)584         private void renderDecodedBuffer(Pair<Integer, BufferInfo> decBuffer, int encBuffer) {
585             // process heavyweight actions under instance lock
586             Image encImage = mEncoder.getInputImage(encBuffer);
587             Image decImage = mDecoder.getOutputImage(decBuffer.first);
588             assertNotNull("could not get encoder image for " + mEncoder.getInputFormat(), encImage);
589             assertNotNull("could not get decoder image for " + mDecoder.getInputFormat(), decImage);
590             assertEquals("incorrect decoder format",decImage.getFormat(), ImageFormat.YUV_420_888);
591             assertEquals("incorrect encoder format", encImage.getFormat(), ImageFormat.YUV_420_888);
592 
593             CodecUtils.copyFlexYUVImage(encImage, decImage);
594 
595             // TRICKY: need this for queueBuffer
596             if (mEncInputBufferSize < 0) {
597                 mEncInputBufferSize = mEncoder.getInputBuffer(encBuffer).capacity();
598             }
599             Log.d(TAG, "queuing input #" + encBuffer + " for encoder (sz="
600                     + mEncInputBufferSize + ", f=" + decBuffer.second.flags
601                     + ", ts=" + decBuffer.second.presentationTimeUs + ")");
602             mEncoder.queueInputBuffer(
603                     encBuffer, 0, mEncInputBufferSize, decBuffer.second.presentationTimeUs,
604                     decBuffer.second.flags);
605             if ((decBuffer.second.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
606                 mSignaledEncoderEOS = true;
607             }
608             mDecoder.releaseOutputBuffer(decBuffer.first, false /* render */);
609         }
610 
611         @Override
onError(MediaCodec mediaCodec, MediaCodec.CodecException e)612         public void onError(MediaCodec mediaCodec, MediaCodec.CodecException e) {
613             fail("received error on " + mediaCodec.getName() + ": " + e);
614         }
615 
616         @Override
onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat)617         public void onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat) {
618             Log.i(TAG, mediaCodec.getName() + " got new output format " + mediaFormat);
619             if (mediaCodec == mEncoder) {
620                 mEncodeOutputFormatUpdated = true;
621                 saveEncoderFormat(mediaFormat);
622             }
623         }
624 
625         // next methods are synchronized on mCondition
haveBuffers()626         private boolean haveBuffers() {
627             return mEncInputBuffers.size() > 0 && mBuffersToRender.size() > 0
628                     && !mSignaledEncoderEOS;
629         }
630 
isEOSOnlyBuffer(Pair<Integer, BufferInfo> decBuffer)631         private boolean isEOSOnlyBuffer(Pair<Integer, BufferInfo> decBuffer) {
632             return decBuffer.first < 0 || decBuffer.second.size == 0;
633         }
634 
tryToPropagateEOS()635         protected void tryToPropagateEOS() {
636             if (!mWorkInProgress && haveBuffers() && isEOSOnlyBuffer(mBuffersToRender.getFirst())) {
637                 Pair<Integer, BufferInfo> decBuffer = mBuffersToRender.removeFirst();
638                 int encBuffer = mEncInputBuffers.removeFirst();
639                 queueEncoderEOS(decBuffer, encBuffer);
640             }
641         }
642 
queueEncoderEOS(Pair<Integer, BufferInfo> decBuffer, int encBuffer)643         void queueEncoderEOS(Pair<Integer, BufferInfo> decBuffer, int encBuffer) {
644             Log.d(TAG, "signaling encoder EOS");
645             mEncoder.queueInputBuffer(encBuffer, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
646             mSignaledEncoderEOS = true;
647             if (decBuffer.first >= 0) {
648                 mDecoder.releaseOutputBuffer(decBuffer.first, false /* render */);
649             }
650         }
651     }
652 
653 
654     class SurfaceVideoProcessor extends VideoProcessorBase
655             implements SurfaceTexture.OnFrameAvailableListener {
656         private static final String TAG = "SurfaceVideoProcessor";
657         private boolean mFrameAvailable;
658         private boolean mGotDecoderEOS;
659         private boolean mSignaledEncoderEOS;
660 
661         private InputSurface mEncSurface;
662         private OutputSurface mDecSurface;
663         private BufferInfo mInfoOnSurface;
664 
665         private LinkedList<Pair<Integer, BufferInfo>> mBuffersToRender =
666             new LinkedList<Pair<Integer, BufferInfo>>();
667 
668         @Override
processLoop( String path, String outMime, String videoEncName, int width, int height, boolean optional)669         public boolean processLoop(
670                 String path, String outMime, String videoEncName,
671                 int width, int height, boolean optional) {
672             boolean skipped = true;
673             try {
674                 open(path);
675                 if (!initCodecsAndConfigureEncoder(
676                         videoEncName, outMime, width, height,
677                         CodecCapabilities.COLOR_FormatSurface)) {
678                     assertTrue("could not configure encoder for supported size", optional);
679                     return !skipped;
680                 }
681                 skipped = false;
682 
683                 mEncSurface = new InputSurface(mEncoder.createInputSurface());
684                 mEncSurface.makeCurrent();
685 
686                 mDecSurface = new OutputSurface(this);
687                 //mDecSurface.changeFragmentShader(FRAGMENT_SHADER);
688                 mDecoder.configure(mDecFormat, mDecSurface.getSurface(), null /* crypto */, 0);
689 
690                 mDecoder.start();
691                 mEncoder.start();
692 
693                 // main loop - process GL ops as only main thread has GL context
694                 while (!mCompleted) {
695                     BufferInfo info = null;
696                     synchronized (mCondition) {
697                         try {
698                             // wait for mFrameAvailable, which is set by onFrameAvailable().
699                             // Use a timeout to avoid stalling the test if it doesn't arrive.
700                             if (!mFrameAvailable && !mCompleted && !mEncoderIsActive) {
701                                 mCondition.wait(mEncodeOutputFormatUpdated ?
702                                         FRAME_TIMEOUT_MS : INIT_TIMEOUT_MS);
703                             }
704                         } catch (InterruptedException ie) {
705                             fail("wait interrupted");  // shouldn't happen
706                         }
707                         if (mCompleted) {
708                             break;
709                         }
710                         if (mEncoderIsActive) {
711                             mEncoderIsActive = false;
712                             if (DEBUG) Log.d(TAG, "encoder is still active, continue");
713                             continue;
714                         }
715                         assertTrue("still waiting for image", mFrameAvailable);
716                         if (DEBUG) Log.v(TAG, "got image");
717                         info = mInfoOnSurface;
718                     }
719                     if (info == null) {
720                         continue;
721                     }
722                     if (info.size > 0) {
723                         mDecSurface.latchImage();
724                         if (DEBUG) Log.v(TAG, "latched image");
725                         mFrameAvailable = false;
726 
727                         mDecSurface.drawImage();
728                         Log.d(TAG, "encoding frame at " + info.presentationTimeUs * 1000);
729 
730                         mEncSurface.setPresentationTime(info.presentationTimeUs * 1000);
731                         mEncSurface.swapBuffers();
732                     }
733                     if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
734                         mSignaledEncoderEOS = true;
735                         Log.d(TAG, "signaling encoder EOS");
736                         mEncoder.signalEndOfInputStream();
737                     }
738 
739                     synchronized (mCondition) {
740                         mInfoOnSurface = null;
741                         if (mBuffersToRender.size() > 0 && mInfoOnSurface == null) {
742                             if (DEBUG) Log.v(TAG, "handling postponed frame");
743                             Pair<Integer, BufferInfo> nextBuffer = mBuffersToRender.removeFirst();
744                             renderDecodedBuffer(nextBuffer.first, nextBuffer.second);
745                         }
746                     }
747                 }
748             } catch (IOException e) {
749                 e.printStackTrace();
750                 fail("received exception " + e);
751             } finally {
752                 close();
753                 if (mEncSurface != null) {
754                     mEncSurface.release();
755                     mEncSurface = null;
756                 }
757                 if (mDecSurface != null) {
758                     mDecSurface.release();
759                     mDecSurface = null;
760                 }
761             }
762             return !skipped;
763         }
764 
765         @Override
onFrameAvailable(SurfaceTexture st)766         public void onFrameAvailable(SurfaceTexture st) {
767             if (DEBUG) Log.v(TAG, "new frame available");
768             synchronized (mCondition) {
769                 assertFalse("mFrameAvailable already set, frame could be dropped", mFrameAvailable);
770                 mFrameAvailable = true;
771                 mCondition.notifyAll();
772             }
773         }
774 
775         @Override
onInputBufferAvailableLocked(MediaCodec mediaCodec, int ix)776         public void onInputBufferAvailableLocked(MediaCodec mediaCodec, int ix) {
777             if (mediaCodec == mDecoder) {
778                 // fill input buffer from extractor
779                 fillDecoderInputBuffer(ix);
780             } else {
781                 fail("received input buffer on " + mediaCodec.getName());
782             }
783         }
784 
785         @Override
onOutputBufferAvailableLocked( MediaCodec mediaCodec, int ix, BufferInfo info)786         public void onOutputBufferAvailableLocked(
787                 MediaCodec mediaCodec, int ix, BufferInfo info) {
788             if (mediaCodec == mDecoder) {
789                 if (DEBUG) Log.v(TAG, "decoder received output #" + ix
790                          + " (sz=" + info.size + ", f=" + info.flags
791                          + ", ts=" + info.presentationTimeUs + ")");
792                 // render output buffer from decoder
793                 if (!mGotDecoderEOS) {
794                     boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
795                     if (eos) {
796                         mGotDecoderEOS = true;
797                     }
798                     // can release empty buffers now
799                     if (info.size == 0) {
800                         mDecoder.releaseOutputBuffer(ix, false /* render */);
801                         ix = -1; // dummy index used by render to not render
802                     }
803                     if (eos || info.size > 0) {
804                         synchronized(mCondition) {
805                             if (mInfoOnSurface != null || mBuffersToRender.size() > 0) {
806                                 if (DEBUG) Log.v(TAG, "postponing render, surface busy");
807                                 mBuffersToRender.addLast(Pair.create(ix, info));
808                             } else {
809                                 renderDecodedBuffer(ix, info);
810                             }
811                         }
812                     }
813                 }
814             } else if (mediaCodec == mEncoder) {
815                 emptyEncoderOutputBuffer(ix, info);
816                 synchronized(mCondition) {
817                     if (!mCompleted) {
818                         mEncoderIsActive = true;
819                         mCondition.notifyAll();
820                     }
821                 }
822             } else {
823                 fail("received output buffer on " + mediaCodec.getName());
824             }
825         }
826 
renderDecodedBuffer(int ix, BufferInfo info)827         private void renderDecodedBuffer(int ix, BufferInfo info) {
828             boolean eos = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
829             mInfoOnSurface = info;
830             if (info.size > 0) {
831                 Log.d(TAG, "rendering frame #" + ix + " at " + info.presentationTimeUs * 1000
832                         + (eos ? " with EOS" : ""));
833                 mDecoder.releaseOutputBuffer(ix, info.presentationTimeUs * 1000);
834             }
835 
836             if (eos && info.size == 0) {
837                 if (DEBUG) Log.v(TAG, "decoder output EOS available");
838                 mFrameAvailable = true;
839                 mCondition.notifyAll();
840             }
841         }
842 
843         @Override
onError(MediaCodec mediaCodec, MediaCodec.CodecException e)844         public void onError(MediaCodec mediaCodec, MediaCodec.CodecException e) {
845             fail("received error on " + mediaCodec.getName() + ": " + e);
846         }
847 
848         @Override
onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat)849         public void onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat) {
850             Log.i(TAG, mediaCodec.getName() + " got new output format " + mediaFormat);
851             if (mediaCodec == mEncoder) {
852                 mEncodeOutputFormatUpdated = true;
853                 saveEncoderFormat(mediaFormat);
854             }
855         }
856     }
857 
858     class Encoder {
859         final private String mName;
860         final private String mMime;
861         final private CodecCapabilities mCaps;
862         final private VideoCapabilities mVideoCaps;
863 
864         final private Map<Size, Set<Size>> mMinMax;     // extreme sizes
865         final private Map<Size, Set<Size>> mNearMinMax; // sizes near extreme
866         final private Set<Size> mArbitraryW;            // arbitrary widths in the middle
867         final private Set<Size> mArbitraryH;            // arbitrary heights in the middle
868         final private Set<Size> mSizes;                 // all non-specifically tested sizes
869 
870         final private int xAlign;
871         final private int yAlign;
872 
Encoder(String name, String mime, CodecCapabilities caps)873         Encoder(String name, String mime, CodecCapabilities caps) {
874             mName = name;
875             mMime = mime;
876             mCaps = caps;
877             mVideoCaps = caps.getVideoCapabilities();
878 
879             /* calculate min/max sizes */
880             mMinMax = new HashMap<Size, Set<Size>>();
881             mNearMinMax = new HashMap<Size, Set<Size>>();
882             mArbitraryW = new HashSet<Size>();
883             mArbitraryH = new HashSet<Size>();
884             mSizes = new HashSet<Size>();
885 
886             xAlign = mVideoCaps.getWidthAlignment();
887             yAlign = mVideoCaps.getHeightAlignment();
888 
889             initializeSizes();
890         }
891 
initializeSizes()892         private void initializeSizes() {
893             for (int x = 0; x < 2; ++x) {
894                 for (int y = 0; y < 2; ++y) {
895                     addExtremeSizesFor(x, y);
896                 }
897             }
898 
899             // initialize arbitrary sizes
900             for (int i = 1; i <= 7; ++i) {
901                 int j = ((7 * i) % 11) + 1;
902                 int width, height;
903                 try {
904                     width = alignedPointInRange(i * 0.125, xAlign, mVideoCaps.getSupportedWidths());
905                     height = alignedPointInRange(
906                             j * 0.077, yAlign, mVideoCaps.getSupportedHeightsFor(width));
907                     mArbitraryW.add(new Size(width, height));
908                 } catch (IllegalArgumentException e) {
909                 }
910 
911                 try {
912                     height = alignedPointInRange(i * 0.125, yAlign, mVideoCaps.getSupportedHeights());
913                     width = alignedPointInRange(j * 0.077, xAlign, mVideoCaps.getSupportedWidthsFor(height));
914                     mArbitraryH.add(new Size(width, height));
915                 } catch (IllegalArgumentException e) {
916                 }
917             }
918             mArbitraryW.removeAll(mArbitraryH);
919             mArbitraryW.removeAll(mSizes);
920             mSizes.addAll(mArbitraryW);
921             mArbitraryH.removeAll(mSizes);
922             mSizes.addAll(mArbitraryH);
923             if (DEBUG) Log.i(TAG, "arbitrary=" + mArbitraryW + "/" + mArbitraryH);
924         }
925 
addExtremeSizesFor(int x, int y)926         private void addExtremeSizesFor(int x, int y) {
927             Set<Size> minMax = new HashSet<Size>();
928             Set<Size> nearMinMax = new HashSet<Size>();
929 
930             for (int dx = 0; dx <= xAlign; dx += xAlign) {
931                 for (int dy = 0; dy <= yAlign; dy += yAlign) {
932                     Set<Size> bucket = (dx + dy == 0) ? minMax : nearMinMax;
933                     try {
934                         int width = getExtreme(mVideoCaps.getSupportedWidths(), x, dx);
935                         int height = getExtreme(mVideoCaps.getSupportedHeightsFor(width), y, dy);
936                         bucket.add(new Size(width, height));
937 
938                         // try max max with more reasonable ratio if too skewed
939                         if (x + y == 2 && width >= 4 * height) {
940                             Size wideScreen = getLargestSizeForRatio(16, 9);
941                             width = getExtreme(
942                                     mVideoCaps.getSupportedWidths()
943                                             .intersect(0, wideScreen.getWidth()), x, dx);
944                             height = getExtreme(mVideoCaps.getSupportedHeightsFor(width), y, 0);
945                             bucket.add(new Size(width, height));
946                         }
947                     } catch (IllegalArgumentException e) {
948                     }
949 
950                     try {
951                         int height = getExtreme(mVideoCaps.getSupportedHeights(), y, dy);
952                         int width = getExtreme(mVideoCaps.getSupportedWidthsFor(height), x, dx);
953                         bucket.add(new Size(width, height));
954 
955                         // try max max with more reasonable ratio if too skewed
956                         if (x + y == 2 && height >= 4 * width) {
957                             Size wideScreen = getLargestSizeForRatio(9, 16);
958                             height = getExtreme(
959                                     mVideoCaps.getSupportedHeights()
960                                             .intersect(0, wideScreen.getHeight()), y, dy);
961                             width = getExtreme(mVideoCaps.getSupportedWidthsFor(height), x, dx);
962                             bucket.add(new Size(width, height));
963                         }
964                     } catch (IllegalArgumentException e) {
965                     }
966                 }
967             }
968 
969             // keep unique sizes
970             minMax.removeAll(mSizes);
971             mSizes.addAll(minMax);
972             nearMinMax.removeAll(mSizes);
973             mSizes.addAll(nearMinMax);
974 
975             mMinMax.put(new Size(x, y), minMax);
976             mNearMinMax.put(new Size(x, y), nearMinMax);
977             if (DEBUG) Log.i(TAG, x + "x" + y + ": minMax=" + mMinMax + ", near=" + mNearMinMax);
978         }
979 
alignInRange(double value, int align, Range<Integer> range)980         private int alignInRange(double value, int align, Range<Integer> range) {
981             return range.clamp(align * (int)Math.round(value / align));
982         }
983 
984         /* point should be between 0. and 1. */
alignedPointInRange(double point, int align, Range<Integer> range)985         private int alignedPointInRange(double point, int align, Range<Integer> range) {
986             return alignInRange(
987                     range.getLower() + point * (range.getUpper() - range.getLower()), align, range);
988         }
989 
getExtreme(Range<Integer> range, int i, int delta)990         private int getExtreme(Range<Integer> range, int i, int delta) {
991             int dim = i == 1 ? range.getUpper() - delta : range.getLower() + delta;
992             if (delta == 0
993                     || (dim > range.getLower() && dim < range.getUpper())) {
994                 return dim;
995             }
996             throw new IllegalArgumentException();
997         }
998 
getLargestSizeForRatio(int x, int y)999         private Size getLargestSizeForRatio(int x, int y) {
1000             Range<Integer> widthRange = mVideoCaps.getSupportedWidths();
1001             Range<Integer> heightRange = mVideoCaps.getSupportedHeightsFor(widthRange.getUpper());
1002             final int xAlign = mVideoCaps.getWidthAlignment();
1003             final int yAlign = mVideoCaps.getHeightAlignment();
1004 
1005             // scale by alignment
1006             int width = alignInRange(
1007                     Math.sqrt(widthRange.getUpper() * heightRange.getUpper() * (double)x / y),
1008                     xAlign, widthRange);
1009             int height = alignInRange(
1010                     width * (double)y / x, yAlign, mVideoCaps.getSupportedHeightsFor(width));
1011             return new Size(width, height);
1012         }
1013 
1014 
testExtreme(int x, int y, boolean flexYUV, boolean near)1015         public boolean testExtreme(int x, int y, boolean flexYUV, boolean near) {
1016             boolean skipped = true;
1017             for (Size s : (near ? mNearMinMax : mMinMax).get(new Size(x, y))) {
1018                 if (test(s.getWidth(), s.getHeight(), false /* optional */, flexYUV)) {
1019                     skipped = false;
1020                 }
1021             }
1022             return !skipped;
1023         }
1024 
testArbitrary(boolean flexYUV, boolean widths)1025         public boolean testArbitrary(boolean flexYUV, boolean widths) {
1026             boolean skipped = true;
1027             for (Size s : (widths ? mArbitraryW : mArbitraryH)) {
1028                 if (test(s.getWidth(), s.getHeight(), false /* optional */, flexYUV)) {
1029                     skipped = false;
1030                 }
1031             }
1032             return !skipped;
1033         }
1034 
testSpecific(int width, int height, boolean flexYUV)1035         public boolean testSpecific(int width, int height, boolean flexYUV) {
1036             // already tested by one of the min/max tests
1037             if (mSizes.contains(new Size(width, height))) {
1038                 return false;
1039             }
1040             return test(width, height, true /* optional */, flexYUV);
1041         }
1042 
testIntraRefresh(int width, int height)1043         public boolean testIntraRefresh(int width, int height) {
1044             if (!mCaps.isFeatureSupported(CodecCapabilities.FEATURE_IntraRefresh)) {
1045                 return false;
1046             }
1047 
1048             final int refreshPeriod[] = new int[] {10, 13, 17, 22, 29, 38, 50, 60};
1049 
1050             // Test the support of refresh periods in the range of 10 - 60 frames
1051             for (int period : refreshPeriod) {
1052                 Function<MediaFormat, Boolean> updateConfigFormatHook =
1053                 new Function<MediaFormat, Boolean>() {
1054                     public Boolean apply(MediaFormat fmt) {
1055                         // set i-frame-interval to 10000 so encoded video only has 1 i-frame.
1056                         fmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10000);
1057                         fmt.setInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD, period);
1058                         return true;
1059                     }
1060                 };
1061 
1062                 Function<MediaFormat, Boolean> checkOutputFormatHook =
1063                 new Function<MediaFormat, Boolean>() {
1064                     public Boolean apply(MediaFormat fmt) {
1065                         int intraPeriod = fmt.getInteger(MediaFormat.KEY_INTRA_REFRESH_PERIOD);
1066                         // Make sure intra period is correct and carried in the output format.
1067                         // intraPeriod must be larger than 0 and operate within 20% of refresh period.
1068                         if (intraPeriod > 1.2 * period || intraPeriod < 0.8 * period) {
1069                             throw new RuntimeException("Intra period mismatch");
1070                         }
1071                         return true;
1072                     }
1073                 };
1074 
1075                 String testName =
1076                 mName + '_' + width + "x" + height + '_' + "flexYUV_intraRefresh";
1077 
1078                 Consumer<VideoProcessorBase> configureVideoProcessor =
1079                 new Consumer<VideoProcessorBase>() {
1080                     public void accept(VideoProcessorBase processor) {
1081                         processor.setProcessorName(testName);
1082                         processor.setUpdateConfigHook(updateConfigFormatHook);
1083                         processor.setCheckOutputFormatHook(checkOutputFormatHook);
1084                     }
1085                 };
1086 
1087                 if (!test(width, height, 0 /* frameRate */, 0 /* bitRate */, true /* optional */,
1088                     true /* flex */, configureVideoProcessor)) {
1089                     return false;
1090                 }
1091             }
1092 
1093             return true;
1094         }
1095 
testDetailed( int width, int height, int frameRate, int bitRate, boolean flexYUV)1096         public boolean testDetailed(
1097                 int width, int height, int frameRate, int bitRate, boolean flexYUV) {
1098             String testName =
1099                     mName + '_' + width + "x" + height + '_' + (flexYUV ? "flexYUV" : " surface");
1100             Consumer<VideoProcessorBase> configureVideoProcessor =
1101                     new Consumer<VideoProcessorBase>() {
1102                 public void accept(VideoProcessorBase processor) {
1103                     processor.setProcessorName(testName);
1104                 }
1105             };
1106             return test(width, height, frameRate, bitRate, true /* optional */, flexYUV,
1107                     configureVideoProcessor);
1108         }
1109 
testSupport(int width, int height, int frameRate, int bitRate)1110         public boolean testSupport(int width, int height, int frameRate, int bitRate) {
1111             return mVideoCaps.areSizeAndRateSupported(width, height, frameRate) &&
1112                     mVideoCaps.getBitrateRange().contains(bitRate);
1113         }
1114 
test( int width, int height, boolean optional, boolean flexYUV)1115         private boolean test(
1116                 int width, int height, boolean optional, boolean flexYUV) {
1117             String testName =
1118                     mName + '_' + width + "x" + height + '_' + (flexYUV ? "flexYUV" : " surface");
1119             Consumer<VideoProcessorBase> configureVideoProcessor =
1120                     new Consumer<VideoProcessorBase>() {
1121                 public void accept(VideoProcessorBase processor) {
1122                     processor.setProcessorName(testName);
1123                 }
1124             };
1125             return test(width, height, 0 /* frameRate */, 0 /* bitRate */,
1126                     optional, flexYUV, configureVideoProcessor);
1127         }
1128 
test( int width, int height, int frameRate, int bitRate, boolean optional, boolean flexYUV, Consumer<VideoProcessorBase> configureVideoProcessor)1129         private boolean test(
1130                 int width, int height, int frameRate, int bitRate, boolean optional,
1131                 boolean flexYUV, Consumer<VideoProcessorBase> configureVideoProcessor) {
1132             Log.i(TAG, "testing " + mMime + " on " + mName + " for " + width + "x" + height
1133                     + (flexYUV ? " flexYUV" : " surface"));
1134 
1135             VideoProcessorBase processor =
1136                 flexYUV ? new VideoProcessor() : new SurfaceVideoProcessor();
1137 
1138             processor.setFrameAndBitRates(frameRate, bitRate);
1139             configureVideoProcessor.accept(processor);
1140 
1141             // We are using a resource URL as an example
1142             boolean success = processor.processLoop(
1143                     SOURCE_URL, mMime, mName, width, height, optional);
1144             if (success) {
1145                 processor.playBack(getActivity().getSurfaceHolder().getSurface());
1146             }
1147             return success;
1148         }
1149     }
1150 
googH265()1151     private Encoder[] googH265()  { return goog(MediaFormat.MIMETYPE_VIDEO_HEVC); }
googH264()1152     private Encoder[] googH264()  { return goog(MediaFormat.MIMETYPE_VIDEO_AVC); }
googH263()1153     private Encoder[] googH263()  { return goog(MediaFormat.MIMETYPE_VIDEO_H263); }
googMpeg4()1154     private Encoder[] googMpeg4() { return goog(MediaFormat.MIMETYPE_VIDEO_MPEG4); }
googVP8()1155     private Encoder[] googVP8()   { return goog(MediaFormat.MIMETYPE_VIDEO_VP8); }
googVP9()1156     private Encoder[] googVP9()   { return goog(MediaFormat.MIMETYPE_VIDEO_VP9); }
1157 
otherH265()1158     private Encoder[] otherH265()  { return other(MediaFormat.MIMETYPE_VIDEO_HEVC); }
otherH264()1159     private Encoder[] otherH264()  { return other(MediaFormat.MIMETYPE_VIDEO_AVC); }
otherH263()1160     private Encoder[] otherH263()  { return other(MediaFormat.MIMETYPE_VIDEO_H263); }
otherMpeg4()1161     private Encoder[] otherMpeg4() { return other(MediaFormat.MIMETYPE_VIDEO_MPEG4); }
otherVP8()1162     private Encoder[] otherVP8()   { return other(MediaFormat.MIMETYPE_VIDEO_VP8); }
otherVP9()1163     private Encoder[] otherVP9()   { return other(MediaFormat.MIMETYPE_VIDEO_VP9); }
1164 
goog(String mime)1165     private Encoder[] goog(String mime) {
1166         return encoders(mime, true /* goog */);
1167     }
1168 
other(String mime)1169     private Encoder[] other(String mime) {
1170         return encoders(mime, false /* goog */);
1171     }
1172 
combineArray(Encoder[] a, Encoder[] b)1173     private Encoder[] combineArray(Encoder[] a, Encoder[] b) {
1174         Encoder[] all = new Encoder[a.length + b.length];
1175         System.arraycopy(a, 0, all, 0, a.length);
1176         System.arraycopy(b, 0, all, a.length, b.length);
1177         return all;
1178     }
1179 
h264()1180     private Encoder[] h264()  {
1181         return combineArray(googH264(), otherH264());
1182     }
1183 
vp8()1184     private Encoder[] vp8()  {
1185         return combineArray(googVP8(), otherVP8());
1186     }
1187 
encoders(String mime, boolean goog)1188     private Encoder[] encoders(String mime, boolean goog) {
1189         MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
1190         ArrayList<Encoder> result = new ArrayList<Encoder>();
1191 
1192         for (MediaCodecInfo info : mcl.getCodecInfos()) {
1193             if (!info.isEncoder()
1194                     || info.getName().toLowerCase().startsWith("omx.google.") != goog) {
1195                 continue;
1196             }
1197             CodecCapabilities caps = null;
1198             try {
1199                 caps = info.getCapabilitiesForType(mime);
1200             } catch (IllegalArgumentException e) { // mime is not supported
1201                 continue;
1202             }
1203             assertNotNull(info.getName() + " capabilties for " + mime + " returned null", caps);
1204             result.add(new Encoder(info.getName(), mime, caps));
1205         }
1206         return result.toArray(new Encoder[result.size()]);
1207     }
1208 
testGoogH265FlexMinMin()1209     public void testGoogH265FlexMinMin()   { minmin(googH265(),   true /* flex */); }
testGoogH265SurfMinMin()1210     public void testGoogH265SurfMinMin()   { minmin(googH265(),   false /* flex */); }
testGoogH264FlexMinMin()1211     public void testGoogH264FlexMinMin()   { minmin(googH264(),   true /* flex */); }
testGoogH264SurfMinMin()1212     public void testGoogH264SurfMinMin()   { minmin(googH264(),   false /* flex */); }
testGoogH263FlexMinMin()1213     public void testGoogH263FlexMinMin()   { minmin(googH263(),   true /* flex */); }
testGoogH263SurfMinMin()1214     public void testGoogH263SurfMinMin()   { minmin(googH263(),   false /* flex */); }
testGoogMpeg4FlexMinMin()1215     public void testGoogMpeg4FlexMinMin()  { minmin(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfMinMin()1216     public void testGoogMpeg4SurfMinMin()  { minmin(googMpeg4(),  false /* flex */); }
testGoogVP8FlexMinMin()1217     public void testGoogVP8FlexMinMin()    { minmin(googVP8(),    true /* flex */); }
testGoogVP8SurfMinMin()1218     public void testGoogVP8SurfMinMin()    { minmin(googVP8(),    false /* flex */); }
testGoogVP9FlexMinMin()1219     public void testGoogVP9FlexMinMin()    { minmin(googVP9(),    true /* flex */); }
testGoogVP9SurfMinMin()1220     public void testGoogVP9SurfMinMin()    { minmin(googVP9(),    false /* flex */); }
1221 
testOtherH265FlexMinMin()1222     public void testOtherH265FlexMinMin()  { minmin(otherH265(),  true /* flex */); }
testOtherH265SurfMinMin()1223     public void testOtherH265SurfMinMin()  { minmin(otherH265(),  false /* flex */); }
testOtherH264FlexMinMin()1224     public void testOtherH264FlexMinMin()  { minmin(otherH264(),  true /* flex */); }
testOtherH264SurfMinMin()1225     public void testOtherH264SurfMinMin()  { minmin(otherH264(),  false /* flex */); }
testOtherH263FlexMinMin()1226     public void testOtherH263FlexMinMin()  { minmin(otherH263(),  true /* flex */); }
testOtherH263SurfMinMin()1227     public void testOtherH263SurfMinMin()  { minmin(otherH263(),  false /* flex */); }
testOtherMpeg4FlexMinMin()1228     public void testOtherMpeg4FlexMinMin() { minmin(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfMinMin()1229     public void testOtherMpeg4SurfMinMin() { minmin(otherMpeg4(), false /* flex */); }
testOtherVP8FlexMinMin()1230     public void testOtherVP8FlexMinMin()   { minmin(otherVP8(),   true /* flex */); }
testOtherVP8SurfMinMin()1231     public void testOtherVP8SurfMinMin()   { minmin(otherVP8(),   false /* flex */); }
testOtherVP9FlexMinMin()1232     public void testOtherVP9FlexMinMin()   { minmin(otherVP9(),   true /* flex */); }
testOtherVP9SurfMinMin()1233     public void testOtherVP9SurfMinMin()   { minmin(otherVP9(),   false /* flex */); }
1234 
testGoogH265FlexMinMax()1235     public void testGoogH265FlexMinMax()   { minmax(googH265(),   true /* flex */); }
testGoogH265SurfMinMax()1236     public void testGoogH265SurfMinMax()   { minmax(googH265(),   false /* flex */); }
testGoogH264FlexMinMax()1237     public void testGoogH264FlexMinMax()   { minmax(googH264(),   true /* flex */); }
testGoogH264SurfMinMax()1238     public void testGoogH264SurfMinMax()   { minmax(googH264(),   false /* flex */); }
testGoogH263FlexMinMax()1239     public void testGoogH263FlexMinMax()   { minmax(googH263(),   true /* flex */); }
testGoogH263SurfMinMax()1240     public void testGoogH263SurfMinMax()   { minmax(googH263(),   false /* flex */); }
testGoogMpeg4FlexMinMax()1241     public void testGoogMpeg4FlexMinMax()  { minmax(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfMinMax()1242     public void testGoogMpeg4SurfMinMax()  { minmax(googMpeg4(),  false /* flex */); }
testGoogVP8FlexMinMax()1243     public void testGoogVP8FlexMinMax()    { minmax(googVP8(),    true /* flex */); }
testGoogVP8SurfMinMax()1244     public void testGoogVP8SurfMinMax()    { minmax(googVP8(),    false /* flex */); }
testGoogVP9FlexMinMax()1245     public void testGoogVP9FlexMinMax()    { minmax(googVP9(),    true /* flex */); }
testGoogVP9SurfMinMax()1246     public void testGoogVP9SurfMinMax()    { minmax(googVP9(),    false /* flex */); }
1247 
testOtherH265FlexMinMax()1248     public void testOtherH265FlexMinMax()  { minmax(otherH265(),  true /* flex */); }
testOtherH265SurfMinMax()1249     public void testOtherH265SurfMinMax()  { minmax(otherH265(),  false /* flex */); }
testOtherH264FlexMinMax()1250     public void testOtherH264FlexMinMax()  { minmax(otherH264(),  true /* flex */); }
testOtherH264SurfMinMax()1251     public void testOtherH264SurfMinMax()  { minmax(otherH264(),  false /* flex */); }
testOtherH263FlexMinMax()1252     public void testOtherH263FlexMinMax()  { minmax(otherH263(),  true /* flex */); }
testOtherH263SurfMinMax()1253     public void testOtherH263SurfMinMax()  { minmax(otherH263(),  false /* flex */); }
testOtherMpeg4FlexMinMax()1254     public void testOtherMpeg4FlexMinMax() { minmax(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfMinMax()1255     public void testOtherMpeg4SurfMinMax() { minmax(otherMpeg4(), false /* flex */); }
testOtherVP8FlexMinMax()1256     public void testOtherVP8FlexMinMax()   { minmax(otherVP8(),   true /* flex */); }
testOtherVP8SurfMinMax()1257     public void testOtherVP8SurfMinMax()   { minmax(otherVP8(),   false /* flex */); }
testOtherVP9FlexMinMax()1258     public void testOtherVP9FlexMinMax()   { minmax(otherVP9(),   true /* flex */); }
testOtherVP9SurfMinMax()1259     public void testOtherVP9SurfMinMax()   { minmax(otherVP9(),   false /* flex */); }
1260 
testGoogH265FlexMaxMin()1261     public void testGoogH265FlexMaxMin()   { maxmin(googH265(),   true /* flex */); }
testGoogH265SurfMaxMin()1262     public void testGoogH265SurfMaxMin()   { maxmin(googH265(),   false /* flex */); }
testGoogH264FlexMaxMin()1263     public void testGoogH264FlexMaxMin()   { maxmin(googH264(),   true /* flex */); }
testGoogH264SurfMaxMin()1264     public void testGoogH264SurfMaxMin()   { maxmin(googH264(),   false /* flex */); }
testGoogH263FlexMaxMin()1265     public void testGoogH263FlexMaxMin()   { maxmin(googH263(),   true /* flex */); }
testGoogH263SurfMaxMin()1266     public void testGoogH263SurfMaxMin()   { maxmin(googH263(),   false /* flex */); }
testGoogMpeg4FlexMaxMin()1267     public void testGoogMpeg4FlexMaxMin()  { maxmin(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfMaxMin()1268     public void testGoogMpeg4SurfMaxMin()  { maxmin(googMpeg4(),  false /* flex */); }
testGoogVP8FlexMaxMin()1269     public void testGoogVP8FlexMaxMin()    { maxmin(googVP8(),    true /* flex */); }
testGoogVP8SurfMaxMin()1270     public void testGoogVP8SurfMaxMin()    { maxmin(googVP8(),    false /* flex */); }
testGoogVP9FlexMaxMin()1271     public void testGoogVP9FlexMaxMin()    { maxmin(googVP9(),    true /* flex */); }
testGoogVP9SurfMaxMin()1272     public void testGoogVP9SurfMaxMin()    { maxmin(googVP9(),    false /* flex */); }
1273 
testOtherH265FlexMaxMin()1274     public void testOtherH265FlexMaxMin()  { maxmin(otherH265(),  true /* flex */); }
testOtherH265SurfMaxMin()1275     public void testOtherH265SurfMaxMin()  { maxmin(otherH265(),  false /* flex */); }
testOtherH264FlexMaxMin()1276     public void testOtherH264FlexMaxMin()  { maxmin(otherH264(),  true /* flex */); }
testOtherH264SurfMaxMin()1277     public void testOtherH264SurfMaxMin()  { maxmin(otherH264(),  false /* flex */); }
testOtherH263FlexMaxMin()1278     public void testOtherH263FlexMaxMin()  { maxmin(otherH263(),  true /* flex */); }
testOtherH263SurfMaxMin()1279     public void testOtherH263SurfMaxMin()  { maxmin(otherH263(),  false /* flex */); }
testOtherMpeg4FlexMaxMin()1280     public void testOtherMpeg4FlexMaxMin() { maxmin(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfMaxMin()1281     public void testOtherMpeg4SurfMaxMin() { maxmin(otherMpeg4(), false /* flex */); }
testOtherVP8FlexMaxMin()1282     public void testOtherVP8FlexMaxMin()   { maxmin(otherVP8(),   true /* flex */); }
testOtherVP8SurfMaxMin()1283     public void testOtherVP8SurfMaxMin()   { maxmin(otherVP8(),   false /* flex */); }
testOtherVP9FlexMaxMin()1284     public void testOtherVP9FlexMaxMin()   { maxmin(otherVP9(),   true /* flex */); }
testOtherVP9SurfMaxMin()1285     public void testOtherVP9SurfMaxMin()   { maxmin(otherVP9(),   false /* flex */); }
1286 
testGoogH265FlexMaxMax()1287     public void testGoogH265FlexMaxMax()   { maxmax(googH265(),   true /* flex */); }
testGoogH265SurfMaxMax()1288     public void testGoogH265SurfMaxMax()   { maxmax(googH265(),   false /* flex */); }
testGoogH264FlexMaxMax()1289     public void testGoogH264FlexMaxMax()   { maxmax(googH264(),   true /* flex */); }
testGoogH264SurfMaxMax()1290     public void testGoogH264SurfMaxMax()   { maxmax(googH264(),   false /* flex */); }
testGoogH263FlexMaxMax()1291     public void testGoogH263FlexMaxMax()   { maxmax(googH263(),   true /* flex */); }
testGoogH263SurfMaxMax()1292     public void testGoogH263SurfMaxMax()   { maxmax(googH263(),   false /* flex */); }
testGoogMpeg4FlexMaxMax()1293     public void testGoogMpeg4FlexMaxMax()  { maxmax(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfMaxMax()1294     public void testGoogMpeg4SurfMaxMax()  { maxmax(googMpeg4(),  false /* flex */); }
testGoogVP8FlexMaxMax()1295     public void testGoogVP8FlexMaxMax()    { maxmax(googVP8(),    true /* flex */); }
testGoogVP8SurfMaxMax()1296     public void testGoogVP8SurfMaxMax()    { maxmax(googVP8(),    false /* flex */); }
testGoogVP9FlexMaxMax()1297     public void testGoogVP9FlexMaxMax()    { maxmax(googVP9(),    true /* flex */); }
testGoogVP9SurfMaxMax()1298     public void testGoogVP9SurfMaxMax()    { maxmax(googVP9(),    false /* flex */); }
1299 
testOtherH265FlexMaxMax()1300     public void testOtherH265FlexMaxMax()  { maxmax(otherH265(),  true /* flex */); }
testOtherH265SurfMaxMax()1301     public void testOtherH265SurfMaxMax()  { maxmax(otherH265(),  false /* flex */); }
testOtherH264FlexMaxMax()1302     public void testOtherH264FlexMaxMax()  { maxmax(otherH264(),  true /* flex */); }
testOtherH264SurfMaxMax()1303     public void testOtherH264SurfMaxMax()  { maxmax(otherH264(),  false /* flex */); }
testOtherH263FlexMaxMax()1304     public void testOtherH263FlexMaxMax()  { maxmax(otherH263(),  true /* flex */); }
testOtherH263SurfMaxMax()1305     public void testOtherH263SurfMaxMax()  { maxmax(otherH263(),  false /* flex */); }
testOtherMpeg4FlexMaxMax()1306     public void testOtherMpeg4FlexMaxMax() { maxmax(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfMaxMax()1307     public void testOtherMpeg4SurfMaxMax() { maxmax(otherMpeg4(), false /* flex */); }
testOtherVP8FlexMaxMax()1308     public void testOtherVP8FlexMaxMax()   { maxmax(otherVP8(),   true /* flex */); }
testOtherVP8SurfMaxMax()1309     public void testOtherVP8SurfMaxMax()   { maxmax(otherVP8(),   false /* flex */); }
testOtherVP9FlexMaxMax()1310     public void testOtherVP9FlexMaxMax()   { maxmax(otherVP9(),   true /* flex */); }
testOtherVP9SurfMaxMax()1311     public void testOtherVP9SurfMaxMax()   { maxmax(otherVP9(),   false /* flex */); }
1312 
testGoogH265FlexNearMinMin()1313     public void testGoogH265FlexNearMinMin()   { nearminmin(googH265(),   true /* flex */); }
testGoogH265SurfNearMinMin()1314     public void testGoogH265SurfNearMinMin()   { nearminmin(googH265(),   false /* flex */); }
testGoogH264FlexNearMinMin()1315     public void testGoogH264FlexNearMinMin()   { nearminmin(googH264(),   true /* flex */); }
testGoogH264SurfNearMinMin()1316     public void testGoogH264SurfNearMinMin()   { nearminmin(googH264(),   false /* flex */); }
testGoogH263FlexNearMinMin()1317     public void testGoogH263FlexNearMinMin()   { nearminmin(googH263(),   true /* flex */); }
testGoogH263SurfNearMinMin()1318     public void testGoogH263SurfNearMinMin()   { nearminmin(googH263(),   false /* flex */); }
testGoogMpeg4FlexNearMinMin()1319     public void testGoogMpeg4FlexNearMinMin()  { nearminmin(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfNearMinMin()1320     public void testGoogMpeg4SurfNearMinMin()  { nearminmin(googMpeg4(),  false /* flex */); }
testGoogVP8FlexNearMinMin()1321     public void testGoogVP8FlexNearMinMin()    { nearminmin(googVP8(),    true /* flex */); }
testGoogVP8SurfNearMinMin()1322     public void testGoogVP8SurfNearMinMin()    { nearminmin(googVP8(),    false /* flex */); }
testGoogVP9FlexNearMinMin()1323     public void testGoogVP9FlexNearMinMin()    { nearminmin(googVP9(),    true /* flex */); }
testGoogVP9SurfNearMinMin()1324     public void testGoogVP9SurfNearMinMin()    { nearminmin(googVP9(),    false /* flex */); }
1325 
testOtherH265FlexNearMinMin()1326     public void testOtherH265FlexNearMinMin()  { nearminmin(otherH265(),  true /* flex */); }
testOtherH265SurfNearMinMin()1327     public void testOtherH265SurfNearMinMin()  { nearminmin(otherH265(),  false /* flex */); }
testOtherH264FlexNearMinMin()1328     public void testOtherH264FlexNearMinMin()  { nearminmin(otherH264(),  true /* flex */); }
testOtherH264SurfNearMinMin()1329     public void testOtherH264SurfNearMinMin()  { nearminmin(otherH264(),  false /* flex */); }
testOtherH263FlexNearMinMin()1330     public void testOtherH263FlexNearMinMin()  { nearminmin(otherH263(),  true /* flex */); }
testOtherH263SurfNearMinMin()1331     public void testOtherH263SurfNearMinMin()  { nearminmin(otherH263(),  false /* flex */); }
testOtherMpeg4FlexNearMinMin()1332     public void testOtherMpeg4FlexNearMinMin() { nearminmin(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfNearMinMin()1333     public void testOtherMpeg4SurfNearMinMin() { nearminmin(otherMpeg4(), false /* flex */); }
testOtherVP8FlexNearMinMin()1334     public void testOtherVP8FlexNearMinMin()   { nearminmin(otherVP8(),   true /* flex */); }
testOtherVP8SurfNearMinMin()1335     public void testOtherVP8SurfNearMinMin()   { nearminmin(otherVP8(),   false /* flex */); }
testOtherVP9FlexNearMinMin()1336     public void testOtherVP9FlexNearMinMin()   { nearminmin(otherVP9(),   true /* flex */); }
testOtherVP9SurfNearMinMin()1337     public void testOtherVP9SurfNearMinMin()   { nearminmin(otherVP9(),   false /* flex */); }
1338 
testGoogH265FlexNearMinMax()1339     public void testGoogH265FlexNearMinMax()   { nearminmax(googH265(),   true /* flex */); }
testGoogH265SurfNearMinMax()1340     public void testGoogH265SurfNearMinMax()   { nearminmax(googH265(),   false /* flex */); }
testGoogH264FlexNearMinMax()1341     public void testGoogH264FlexNearMinMax()   { nearminmax(googH264(),   true /* flex */); }
testGoogH264SurfNearMinMax()1342     public void testGoogH264SurfNearMinMax()   { nearminmax(googH264(),   false /* flex */); }
testGoogH263FlexNearMinMax()1343     public void testGoogH263FlexNearMinMax()   { nearminmax(googH263(),   true /* flex */); }
testGoogH263SurfNearMinMax()1344     public void testGoogH263SurfNearMinMax()   { nearminmax(googH263(),   false /* flex */); }
testGoogMpeg4FlexNearMinMax()1345     public void testGoogMpeg4FlexNearMinMax()  { nearminmax(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfNearMinMax()1346     public void testGoogMpeg4SurfNearMinMax()  { nearminmax(googMpeg4(),  false /* flex */); }
testGoogVP8FlexNearMinMax()1347     public void testGoogVP8FlexNearMinMax()    { nearminmax(googVP8(),    true /* flex */); }
testGoogVP8SurfNearMinMax()1348     public void testGoogVP8SurfNearMinMax()    { nearminmax(googVP8(),    false /* flex */); }
testGoogVP9FlexNearMinMax()1349     public void testGoogVP9FlexNearMinMax()    { nearminmax(googVP9(),    true /* flex */); }
testGoogVP9SurfNearMinMax()1350     public void testGoogVP9SurfNearMinMax()    { nearminmax(googVP9(),    false /* flex */); }
1351 
testOtherH265FlexNearMinMax()1352     public void testOtherH265FlexNearMinMax()  { nearminmax(otherH265(),  true /* flex */); }
testOtherH265SurfNearMinMax()1353     public void testOtherH265SurfNearMinMax()  { nearminmax(otherH265(),  false /* flex */); }
testOtherH264FlexNearMinMax()1354     public void testOtherH264FlexNearMinMax()  { nearminmax(otherH264(),  true /* flex */); }
testOtherH264SurfNearMinMax()1355     public void testOtherH264SurfNearMinMax()  { nearminmax(otherH264(),  false /* flex */); }
testOtherH263FlexNearMinMax()1356     public void testOtherH263FlexNearMinMax()  { nearminmax(otherH263(),  true /* flex */); }
testOtherH263SurfNearMinMax()1357     public void testOtherH263SurfNearMinMax()  { nearminmax(otherH263(),  false /* flex */); }
testOtherMpeg4FlexNearMinMax()1358     public void testOtherMpeg4FlexNearMinMax() { nearminmax(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfNearMinMax()1359     public void testOtherMpeg4SurfNearMinMax() { nearminmax(otherMpeg4(), false /* flex */); }
testOtherVP8FlexNearMinMax()1360     public void testOtherVP8FlexNearMinMax()   { nearminmax(otherVP8(),   true /* flex */); }
testOtherVP8SurfNearMinMax()1361     public void testOtherVP8SurfNearMinMax()   { nearminmax(otherVP8(),   false /* flex */); }
testOtherVP9FlexNearMinMax()1362     public void testOtherVP9FlexNearMinMax()   { nearminmax(otherVP9(),   true /* flex */); }
testOtherVP9SurfNearMinMax()1363     public void testOtherVP9SurfNearMinMax()   { nearminmax(otherVP9(),   false /* flex */); }
1364 
testGoogH265FlexNearMaxMin()1365     public void testGoogH265FlexNearMaxMin()   { nearmaxmin(googH265(),   true /* flex */); }
testGoogH265SurfNearMaxMin()1366     public void testGoogH265SurfNearMaxMin()   { nearmaxmin(googH265(),   false /* flex */); }
testGoogH264FlexNearMaxMin()1367     public void testGoogH264FlexNearMaxMin()   { nearmaxmin(googH264(),   true /* flex */); }
testGoogH264SurfNearMaxMin()1368     public void testGoogH264SurfNearMaxMin()   { nearmaxmin(googH264(),   false /* flex */); }
testGoogH263FlexNearMaxMin()1369     public void testGoogH263FlexNearMaxMin()   { nearmaxmin(googH263(),   true /* flex */); }
testGoogH263SurfNearMaxMin()1370     public void testGoogH263SurfNearMaxMin()   { nearmaxmin(googH263(),   false /* flex */); }
testGoogMpeg4FlexNearMaxMin()1371     public void testGoogMpeg4FlexNearMaxMin()  { nearmaxmin(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfNearMaxMin()1372     public void testGoogMpeg4SurfNearMaxMin()  { nearmaxmin(googMpeg4(),  false /* flex */); }
testGoogVP8FlexNearMaxMin()1373     public void testGoogVP8FlexNearMaxMin()    { nearmaxmin(googVP8(),    true /* flex */); }
testGoogVP8SurfNearMaxMin()1374     public void testGoogVP8SurfNearMaxMin()    { nearmaxmin(googVP8(),    false /* flex */); }
testGoogVP9FlexNearMaxMin()1375     public void testGoogVP9FlexNearMaxMin()    { nearmaxmin(googVP9(),    true /* flex */); }
testGoogVP9SurfNearMaxMin()1376     public void testGoogVP9SurfNearMaxMin()    { nearmaxmin(googVP9(),    false /* flex */); }
1377 
testOtherH265FlexNearMaxMin()1378     public void testOtherH265FlexNearMaxMin()  { nearmaxmin(otherH265(),  true /* flex */); }
testOtherH265SurfNearMaxMin()1379     public void testOtherH265SurfNearMaxMin()  { nearmaxmin(otherH265(),  false /* flex */); }
testOtherH264FlexNearMaxMin()1380     public void testOtherH264FlexNearMaxMin()  { nearmaxmin(otherH264(),  true /* flex */); }
testOtherH264SurfNearMaxMin()1381     public void testOtherH264SurfNearMaxMin()  { nearmaxmin(otherH264(),  false /* flex */); }
testOtherH263FlexNearMaxMin()1382     public void testOtherH263FlexNearMaxMin()  { nearmaxmin(otherH263(),  true /* flex */); }
testOtherH263SurfNearMaxMin()1383     public void testOtherH263SurfNearMaxMin()  { nearmaxmin(otherH263(),  false /* flex */); }
testOtherMpeg4FlexNearMaxMin()1384     public void testOtherMpeg4FlexNearMaxMin() { nearmaxmin(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfNearMaxMin()1385     public void testOtherMpeg4SurfNearMaxMin() { nearmaxmin(otherMpeg4(), false /* flex */); }
testOtherVP8FlexNearMaxMin()1386     public void testOtherVP8FlexNearMaxMin()   { nearmaxmin(otherVP8(),   true /* flex */); }
testOtherVP8SurfNearMaxMin()1387     public void testOtherVP8SurfNearMaxMin()   { nearmaxmin(otherVP8(),   false /* flex */); }
testOtherVP9FlexNearMaxMin()1388     public void testOtherVP9FlexNearMaxMin()   { nearmaxmin(otherVP9(),   true /* flex */); }
testOtherVP9SurfNearMaxMin()1389     public void testOtherVP9SurfNearMaxMin()   { nearmaxmin(otherVP9(),   false /* flex */); }
1390 
testGoogH265FlexNearMaxMax()1391     public void testGoogH265FlexNearMaxMax()   { nearmaxmax(googH265(),   true /* flex */); }
testGoogH265SurfNearMaxMax()1392     public void testGoogH265SurfNearMaxMax()   { nearmaxmax(googH265(),   false /* flex */); }
testGoogH264FlexNearMaxMax()1393     public void testGoogH264FlexNearMaxMax()   { nearmaxmax(googH264(),   true /* flex */); }
testGoogH264SurfNearMaxMax()1394     public void testGoogH264SurfNearMaxMax()   { nearmaxmax(googH264(),   false /* flex */); }
testGoogH263FlexNearMaxMax()1395     public void testGoogH263FlexNearMaxMax()   { nearmaxmax(googH263(),   true /* flex */); }
testGoogH263SurfNearMaxMax()1396     public void testGoogH263SurfNearMaxMax()   { nearmaxmax(googH263(),   false /* flex */); }
testGoogMpeg4FlexNearMaxMax()1397     public void testGoogMpeg4FlexNearMaxMax()  { nearmaxmax(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfNearMaxMax()1398     public void testGoogMpeg4SurfNearMaxMax()  { nearmaxmax(googMpeg4(),  false /* flex */); }
testGoogVP8FlexNearMaxMax()1399     public void testGoogVP8FlexNearMaxMax()    { nearmaxmax(googVP8(),    true /* flex */); }
testGoogVP8SurfNearMaxMax()1400     public void testGoogVP8SurfNearMaxMax()    { nearmaxmax(googVP8(),    false /* flex */); }
testGoogVP9FlexNearMaxMax()1401     public void testGoogVP9FlexNearMaxMax()    { nearmaxmax(googVP9(),    true /* flex */); }
testGoogVP9SurfNearMaxMax()1402     public void testGoogVP9SurfNearMaxMax()    { nearmaxmax(googVP9(),    false /* flex */); }
1403 
testOtherH265FlexNearMaxMax()1404     public void testOtherH265FlexNearMaxMax()  { nearmaxmax(otherH265(),  true /* flex */); }
testOtherH265SurfNearMaxMax()1405     public void testOtherH265SurfNearMaxMax()  { nearmaxmax(otherH265(),  false /* flex */); }
testOtherH264FlexNearMaxMax()1406     public void testOtherH264FlexNearMaxMax()  { nearmaxmax(otherH264(),  true /* flex */); }
testOtherH264SurfNearMaxMax()1407     public void testOtherH264SurfNearMaxMax()  { nearmaxmax(otherH264(),  false /* flex */); }
testOtherH263FlexNearMaxMax()1408     public void testOtherH263FlexNearMaxMax()  { nearmaxmax(otherH263(),  true /* flex */); }
testOtherH263SurfNearMaxMax()1409     public void testOtherH263SurfNearMaxMax()  { nearmaxmax(otherH263(),  false /* flex */); }
testOtherMpeg4FlexNearMaxMax()1410     public void testOtherMpeg4FlexNearMaxMax() { nearmaxmax(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfNearMaxMax()1411     public void testOtherMpeg4SurfNearMaxMax() { nearmaxmax(otherMpeg4(), false /* flex */); }
testOtherVP8FlexNearMaxMax()1412     public void testOtherVP8FlexNearMaxMax()   { nearmaxmax(otherVP8(),   true /* flex */); }
testOtherVP8SurfNearMaxMax()1413     public void testOtherVP8SurfNearMaxMax()   { nearmaxmax(otherVP8(),   false /* flex */); }
testOtherVP9FlexNearMaxMax()1414     public void testOtherVP9FlexNearMaxMax()   { nearmaxmax(otherVP9(),   true /* flex */); }
testOtherVP9SurfNearMaxMax()1415     public void testOtherVP9SurfNearMaxMax()   { nearmaxmax(otherVP9(),   false /* flex */); }
1416 
testGoogH265FlexArbitraryW()1417     public void testGoogH265FlexArbitraryW()   { arbitraryw(googH265(),   true /* flex */); }
testGoogH265SurfArbitraryW()1418     public void testGoogH265SurfArbitraryW()   { arbitraryw(googH265(),   false /* flex */); }
testGoogH264FlexArbitraryW()1419     public void testGoogH264FlexArbitraryW()   { arbitraryw(googH264(),   true /* flex */); }
testGoogH264SurfArbitraryW()1420     public void testGoogH264SurfArbitraryW()   { arbitraryw(googH264(),   false /* flex */); }
testGoogH263FlexArbitraryW()1421     public void testGoogH263FlexArbitraryW()   { arbitraryw(googH263(),   true /* flex */); }
testGoogH263SurfArbitraryW()1422     public void testGoogH263SurfArbitraryW()   { arbitraryw(googH263(),   false /* flex */); }
testGoogMpeg4FlexArbitraryW()1423     public void testGoogMpeg4FlexArbitraryW()  { arbitraryw(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfArbitraryW()1424     public void testGoogMpeg4SurfArbitraryW()  { arbitraryw(googMpeg4(),  false /* flex */); }
testGoogVP8FlexArbitraryW()1425     public void testGoogVP8FlexArbitraryW()    { arbitraryw(googVP8(),    true /* flex */); }
testGoogVP8SurfArbitraryW()1426     public void testGoogVP8SurfArbitraryW()    { arbitraryw(googVP8(),    false /* flex */); }
testGoogVP9FlexArbitraryW()1427     public void testGoogVP9FlexArbitraryW()    { arbitraryw(googVP9(),    true /* flex */); }
testGoogVP9SurfArbitraryW()1428     public void testGoogVP9SurfArbitraryW()    { arbitraryw(googVP9(),    false /* flex */); }
1429 
testOtherH265FlexArbitraryW()1430     public void testOtherH265FlexArbitraryW()  { arbitraryw(otherH265(),  true /* flex */); }
testOtherH265SurfArbitraryW()1431     public void testOtherH265SurfArbitraryW()  { arbitraryw(otherH265(),  false /* flex */); }
testOtherH264FlexArbitraryW()1432     public void testOtherH264FlexArbitraryW()  { arbitraryw(otherH264(),  true /* flex */); }
testOtherH264SurfArbitraryW()1433     public void testOtherH264SurfArbitraryW()  { arbitraryw(otherH264(),  false /* flex */); }
testOtherH263FlexArbitraryW()1434     public void testOtherH263FlexArbitraryW()  { arbitraryw(otherH263(),  true /* flex */); }
testOtherH263SurfArbitraryW()1435     public void testOtherH263SurfArbitraryW()  { arbitraryw(otherH263(),  false /* flex */); }
testOtherMpeg4FlexArbitraryW()1436     public void testOtherMpeg4FlexArbitraryW() { arbitraryw(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfArbitraryW()1437     public void testOtherMpeg4SurfArbitraryW() { arbitraryw(otherMpeg4(), false /* flex */); }
testOtherVP8FlexArbitraryW()1438     public void testOtherVP8FlexArbitraryW()   { arbitraryw(otherVP8(),   true /* flex */); }
testOtherVP8SurfArbitraryW()1439     public void testOtherVP8SurfArbitraryW()   { arbitraryw(otherVP8(),   false /* flex */); }
testOtherVP9FlexArbitraryW()1440     public void testOtherVP9FlexArbitraryW()   { arbitraryw(otherVP9(),   true /* flex */); }
testOtherVP9SurfArbitraryW()1441     public void testOtherVP9SurfArbitraryW()   { arbitraryw(otherVP9(),   false /* flex */); }
1442 
testGoogH265FlexArbitraryH()1443     public void testGoogH265FlexArbitraryH()   { arbitraryh(googH265(),   true /* flex */); }
testGoogH265SurfArbitraryH()1444     public void testGoogH265SurfArbitraryH()   { arbitraryh(googH265(),   false /* flex */); }
testGoogH264FlexArbitraryH()1445     public void testGoogH264FlexArbitraryH()   { arbitraryh(googH264(),   true /* flex */); }
testGoogH264SurfArbitraryH()1446     public void testGoogH264SurfArbitraryH()   { arbitraryh(googH264(),   false /* flex */); }
testGoogH263FlexArbitraryH()1447     public void testGoogH263FlexArbitraryH()   { arbitraryh(googH263(),   true /* flex */); }
testGoogH263SurfArbitraryH()1448     public void testGoogH263SurfArbitraryH()   { arbitraryh(googH263(),   false /* flex */); }
testGoogMpeg4FlexArbitraryH()1449     public void testGoogMpeg4FlexArbitraryH()  { arbitraryh(googMpeg4(),  true /* flex */); }
testGoogMpeg4SurfArbitraryH()1450     public void testGoogMpeg4SurfArbitraryH()  { arbitraryh(googMpeg4(),  false /* flex */); }
testGoogVP8FlexArbitraryH()1451     public void testGoogVP8FlexArbitraryH()    { arbitraryh(googVP8(),    true /* flex */); }
testGoogVP8SurfArbitraryH()1452     public void testGoogVP8SurfArbitraryH()    { arbitraryh(googVP8(),    false /* flex */); }
testGoogVP9FlexArbitraryH()1453     public void testGoogVP9FlexArbitraryH()    { arbitraryh(googVP9(),    true /* flex */); }
testGoogVP9SurfArbitraryH()1454     public void testGoogVP9SurfArbitraryH()    { arbitraryh(googVP9(),    false /* flex */); }
1455 
testOtherH265FlexArbitraryH()1456     public void testOtherH265FlexArbitraryH()  { arbitraryh(otherH265(),  true /* flex */); }
testOtherH265SurfArbitraryH()1457     public void testOtherH265SurfArbitraryH()  { arbitraryh(otherH265(),  false /* flex */); }
testOtherH264FlexArbitraryH()1458     public void testOtherH264FlexArbitraryH()  { arbitraryh(otherH264(),  true /* flex */); }
testOtherH264SurfArbitraryH()1459     public void testOtherH264SurfArbitraryH()  { arbitraryh(otherH264(),  false /* flex */); }
testOtherH263FlexArbitraryH()1460     public void testOtherH263FlexArbitraryH()  { arbitraryh(otherH263(),  true /* flex */); }
testOtherH263SurfArbitraryH()1461     public void testOtherH263SurfArbitraryH()  { arbitraryh(otherH263(),  false /* flex */); }
testOtherMpeg4FlexArbitraryH()1462     public void testOtherMpeg4FlexArbitraryH() { arbitraryh(otherMpeg4(), true /* flex */); }
testOtherMpeg4SurfArbitraryH()1463     public void testOtherMpeg4SurfArbitraryH() { arbitraryh(otherMpeg4(), false /* flex */); }
testOtherVP8FlexArbitraryH()1464     public void testOtherVP8FlexArbitraryH()   { arbitraryh(otherVP8(),   true /* flex */); }
testOtherVP8SurfArbitraryH()1465     public void testOtherVP8SurfArbitraryH()   { arbitraryh(otherVP8(),   false /* flex */); }
testOtherVP9FlexArbitraryH()1466     public void testOtherVP9FlexArbitraryH()   { arbitraryh(otherVP9(),   true /* flex */); }
testOtherVP9SurfArbitraryH()1467     public void testOtherVP9SurfArbitraryH()   { arbitraryh(otherVP9(),   false /* flex */); }
1468 
testGoogH265FlexQCIF()1469     public void testGoogH265FlexQCIF()   { specific(googH265(),   176, 144, true /* flex */); }
testGoogH265SurfQCIF()1470     public void testGoogH265SurfQCIF()   { specific(googH265(),   176, 144, false /* flex */); }
testGoogH264FlexQCIF()1471     public void testGoogH264FlexQCIF()   { specific(googH264(),   176, 144, true /* flex */); }
testGoogH264SurfQCIF()1472     public void testGoogH264SurfQCIF()   { specific(googH264(),   176, 144, false /* flex */); }
testGoogH263FlexQCIF()1473     public void testGoogH263FlexQCIF()   { specific(googH263(),   176, 144, true /* flex */); }
testGoogH263SurfQCIF()1474     public void testGoogH263SurfQCIF()   { specific(googH263(),   176, 144, false /* flex */); }
testGoogMpeg4FlexQCIF()1475     public void testGoogMpeg4FlexQCIF()  { specific(googMpeg4(),  176, 144, true /* flex */); }
testGoogMpeg4SurfQCIF()1476     public void testGoogMpeg4SurfQCIF()  { specific(googMpeg4(),  176, 144, false /* flex */); }
testGoogVP8FlexQCIF()1477     public void testGoogVP8FlexQCIF()    { specific(googVP8(),    176, 144, true /* flex */); }
testGoogVP8SurfQCIF()1478     public void testGoogVP8SurfQCIF()    { specific(googVP8(),    176, 144, false /* flex */); }
testGoogVP9FlexQCIF()1479     public void testGoogVP9FlexQCIF()    { specific(googVP9(),    176, 144, true /* flex */); }
testGoogVP9SurfQCIF()1480     public void testGoogVP9SurfQCIF()    { specific(googVP9(),    176, 144, false /* flex */); }
1481 
testOtherH265FlexQCIF()1482     public void testOtherH265FlexQCIF()  { specific(otherH265(),  176, 144, true /* flex */); }
testOtherH265SurfQCIF()1483     public void testOtherH265SurfQCIF()  { specific(otherH265(),  176, 144, false /* flex */); }
testOtherH264FlexQCIF()1484     public void testOtherH264FlexQCIF()  { specific(otherH264(),  176, 144, true /* flex */); }
testOtherH264SurfQCIF()1485     public void testOtherH264SurfQCIF()  { specific(otherH264(),  176, 144, false /* flex */); }
testOtherH263FlexQCIF()1486     public void testOtherH263FlexQCIF()  { specific(otherH263(),  176, 144, true /* flex */); }
testOtherH263SurfQCIF()1487     public void testOtherH263SurfQCIF()  { specific(otherH263(),  176, 144, false /* flex */); }
testOtherMpeg4FlexQCIF()1488     public void testOtherMpeg4FlexQCIF() { specific(otherMpeg4(), 176, 144, true /* flex */); }
testOtherMpeg4SurfQCIF()1489     public void testOtherMpeg4SurfQCIF() { specific(otherMpeg4(), 176, 144, false /* flex */); }
testOtherVP8FlexQCIF()1490     public void testOtherVP8FlexQCIF()   { specific(otherVP8(),   176, 144, true /* flex */); }
testOtherVP8SurfQCIF()1491     public void testOtherVP8SurfQCIF()   { specific(otherVP8(),   176, 144, false /* flex */); }
testOtherVP9FlexQCIF()1492     public void testOtherVP9FlexQCIF()   { specific(otherVP9(),   176, 144, true /* flex */); }
testOtherVP9SurfQCIF()1493     public void testOtherVP9SurfQCIF()   { specific(otherVP9(),   176, 144, false /* flex */); }
1494 
testGoogH265Flex480p()1495     public void testGoogH265Flex480p()   { specific(googH265(),   720, 480, true /* flex */); }
testGoogH265Surf480p()1496     public void testGoogH265Surf480p()   { specific(googH265(),   720, 480, false /* flex */); }
testGoogH264Flex480p()1497     public void testGoogH264Flex480p()   { specific(googH264(),   720, 480, true /* flex */); }
testGoogH264Surf480p()1498     public void testGoogH264Surf480p()   { specific(googH264(),   720, 480, false /* flex */); }
testGoogH263Flex480p()1499     public void testGoogH263Flex480p()   { specific(googH263(),   720, 480, true /* flex */); }
testGoogH263Surf480p()1500     public void testGoogH263Surf480p()   { specific(googH263(),   720, 480, false /* flex */); }
testGoogMpeg4Flex480p()1501     public void testGoogMpeg4Flex480p()  { specific(googMpeg4(),  720, 480, true /* flex */); }
testGoogMpeg4Surf480p()1502     public void testGoogMpeg4Surf480p()  { specific(googMpeg4(),  720, 480, false /* flex */); }
testGoogVP8Flex480p()1503     public void testGoogVP8Flex480p()    { specific(googVP8(),    720, 480, true /* flex */); }
testGoogVP8Surf480p()1504     public void testGoogVP8Surf480p()    { specific(googVP8(),    720, 480, false /* flex */); }
testGoogVP9Flex480p()1505     public void testGoogVP9Flex480p()    { specific(googVP9(),    720, 480, true /* flex */); }
testGoogVP9Surf480p()1506     public void testGoogVP9Surf480p()    { specific(googVP9(),    720, 480, false /* flex */); }
1507 
testOtherH265Flex480p()1508     public void testOtherH265Flex480p()  { specific(otherH265(),  720, 480, true /* flex */); }
testOtherH265Surf480p()1509     public void testOtherH265Surf480p()  { specific(otherH265(),  720, 480, false /* flex */); }
testOtherH264Flex480p()1510     public void testOtherH264Flex480p()  { specific(otherH264(),  720, 480, true /* flex */); }
testOtherH264Surf480p()1511     public void testOtherH264Surf480p()  { specific(otherH264(),  720, 480, false /* flex */); }
testOtherH263Flex480p()1512     public void testOtherH263Flex480p()  { specific(otherH263(),  720, 480, true /* flex */); }
testOtherH263Surf480p()1513     public void testOtherH263Surf480p()  { specific(otherH263(),  720, 480, false /* flex */); }
testOtherMpeg4Flex480p()1514     public void testOtherMpeg4Flex480p() { specific(otherMpeg4(), 720, 480, true /* flex */); }
testOtherMpeg4Surf480p()1515     public void testOtherMpeg4Surf480p() { specific(otherMpeg4(), 720, 480, false /* flex */); }
testOtherVP8Flex480p()1516     public void testOtherVP8Flex480p()   { specific(otherVP8(),   720, 480, true /* flex */); }
testOtherVP8Surf480p()1517     public void testOtherVP8Surf480p()   { specific(otherVP8(),   720, 480, false /* flex */); }
testOtherVP9Flex480p()1518     public void testOtherVP9Flex480p()   { specific(otherVP9(),   720, 480, true /* flex */); }
testOtherVP9Surf480p()1519     public void testOtherVP9Surf480p()   { specific(otherVP9(),   720, 480, false /* flex */); }
1520 
1521     // even though H.263 and MPEG-4 are not defined for 720p or 1080p
1522     // test for it, in case device claims support for it.
1523 
testGoogH265Flex720p()1524     public void testGoogH265Flex720p()   { specific(googH265(),   1280, 720, true /* flex */); }
testGoogH265Surf720p()1525     public void testGoogH265Surf720p()   { specific(googH265(),   1280, 720, false /* flex */); }
testGoogH264Flex720p()1526     public void testGoogH264Flex720p()   { specific(googH264(),   1280, 720, true /* flex */); }
testGoogH264Surf720p()1527     public void testGoogH264Surf720p()   { specific(googH264(),   1280, 720, false /* flex */); }
testGoogH263Flex720p()1528     public void testGoogH263Flex720p()   { specific(googH263(),   1280, 720, true /* flex */); }
testGoogH263Surf720p()1529     public void testGoogH263Surf720p()   { specific(googH263(),   1280, 720, false /* flex */); }
testGoogMpeg4Flex720p()1530     public void testGoogMpeg4Flex720p()  { specific(googMpeg4(),  1280, 720, true /* flex */); }
testGoogMpeg4Surf720p()1531     public void testGoogMpeg4Surf720p()  { specific(googMpeg4(),  1280, 720, false /* flex */); }
testGoogVP8Flex720p()1532     public void testGoogVP8Flex720p()    { specific(googVP8(),    1280, 720, true /* flex */); }
testGoogVP8Surf720p()1533     public void testGoogVP8Surf720p()    { specific(googVP8(),    1280, 720, false /* flex */); }
testGoogVP9Flex720p()1534     public void testGoogVP9Flex720p()    { specific(googVP9(),    1280, 720, true /* flex */); }
testGoogVP9Surf720p()1535     public void testGoogVP9Surf720p()    { specific(googVP9(),    1280, 720, false /* flex */); }
1536 
testOtherH265Flex720p()1537     public void testOtherH265Flex720p()  { specific(otherH265(),  1280, 720, true /* flex */); }
testOtherH265Surf720p()1538     public void testOtherH265Surf720p()  { specific(otherH265(),  1280, 720, false /* flex */); }
testOtherH264Flex720p()1539     public void testOtherH264Flex720p()  { specific(otherH264(),  1280, 720, true /* flex */); }
testOtherH264Surf720p()1540     public void testOtherH264Surf720p()  { specific(otherH264(),  1280, 720, false /* flex */); }
testOtherH263Flex720p()1541     public void testOtherH263Flex720p()  { specific(otherH263(),  1280, 720, true /* flex */); }
testOtherH263Surf720p()1542     public void testOtherH263Surf720p()  { specific(otherH263(),  1280, 720, false /* flex */); }
testOtherMpeg4Flex720p()1543     public void testOtherMpeg4Flex720p() { specific(otherMpeg4(), 1280, 720, true /* flex */); }
testOtherMpeg4Surf720p()1544     public void testOtherMpeg4Surf720p() { specific(otherMpeg4(), 1280, 720, false /* flex */); }
testOtherVP8Flex720p()1545     public void testOtherVP8Flex720p()   { specific(otherVP8(),   1280, 720, true /* flex */); }
testOtherVP8Surf720p()1546     public void testOtherVP8Surf720p()   { specific(otherVP8(),   1280, 720, false /* flex */); }
testOtherVP9Flex720p()1547     public void testOtherVP9Flex720p()   { specific(otherVP9(),   1280, 720, true /* flex */); }
testOtherVP9Surf720p()1548     public void testOtherVP9Surf720p()   { specific(otherVP9(),   1280, 720, false /* flex */); }
1549 
testGoogH265Flex1080p()1550     public void testGoogH265Flex1080p()   { specific(googH265(),   1920, 1080, true /* flex */); }
testGoogH265Surf1080p()1551     public void testGoogH265Surf1080p()   { specific(googH265(),   1920, 1080, false /* flex */); }
testGoogH264Flex1080p()1552     public void testGoogH264Flex1080p()   { specific(googH264(),   1920, 1080, true /* flex */); }
testGoogH264Surf1080p()1553     public void testGoogH264Surf1080p()   { specific(googH264(),   1920, 1080, false /* flex */); }
testGoogH263Flex1080p()1554     public void testGoogH263Flex1080p()   { specific(googH263(),   1920, 1080, true /* flex */); }
testGoogH263Surf1080p()1555     public void testGoogH263Surf1080p()   { specific(googH263(),   1920, 1080, false /* flex */); }
testGoogMpeg4Flex1080p()1556     public void testGoogMpeg4Flex1080p()  { specific(googMpeg4(),  1920, 1080, true /* flex */); }
testGoogMpeg4Surf1080p()1557     public void testGoogMpeg4Surf1080p()  { specific(googMpeg4(),  1920, 1080, false /* flex */); }
testGoogVP8Flex1080p()1558     public void testGoogVP8Flex1080p()    { specific(googVP8(),    1920, 1080, true /* flex */); }
testGoogVP8Surf1080p()1559     public void testGoogVP8Surf1080p()    { specific(googVP8(),    1920, 1080, false /* flex */); }
testGoogVP9Flex1080p()1560     public void testGoogVP9Flex1080p()    { specific(googVP9(),    1920, 1080, true /* flex */); }
testGoogVP9Surf1080p()1561     public void testGoogVP9Surf1080p()    { specific(googVP9(),    1920, 1080, false /* flex */); }
1562 
testOtherH265Flex1080p()1563     public void testOtherH265Flex1080p()  { specific(otherH265(),  1920, 1080, true /* flex */); }
testOtherH265Surf1080p()1564     public void testOtherH265Surf1080p()  { specific(otherH265(),  1920, 1080, false /* flex */); }
testOtherH264Flex1080p()1565     public void testOtherH264Flex1080p()  { specific(otherH264(),  1920, 1080, true /* flex */); }
testOtherH264Surf1080p()1566     public void testOtherH264Surf1080p()  { specific(otherH264(),  1920, 1080, false /* flex */); }
testOtherH263Flex1080p()1567     public void testOtherH263Flex1080p()  { specific(otherH263(),  1920, 1080, true /* flex */); }
testOtherH263Surf1080p()1568     public void testOtherH263Surf1080p()  { specific(otherH263(),  1920, 1080, false /* flex */); }
testOtherMpeg4Flex1080p()1569     public void testOtherMpeg4Flex1080p() { specific(otherMpeg4(), 1920, 1080, true /* flex */); }
testOtherMpeg4Surf1080p()1570     public void testOtherMpeg4Surf1080p() { specific(otherMpeg4(), 1920, 1080, false /* flex */); }
testOtherVP8Flex1080p()1571     public void testOtherVP8Flex1080p()   { specific(otherVP8(),   1920, 1080, true /* flex */); }
testOtherVP8Surf1080p()1572     public void testOtherVP8Surf1080p()   { specific(otherVP8(),   1920, 1080, false /* flex */); }
testOtherVP9Flex1080p()1573     public void testOtherVP9Flex1080p()   { specific(otherVP9(),   1920, 1080, true /* flex */); }
testOtherVP9Surf1080p()1574     public void testOtherVP9Surf1080p()   { specific(otherVP9(),   1920, 1080, false /* flex */); }
1575 
testGoogH265Flex360pWithIntraRefresh()1576     public void testGoogH265Flex360pWithIntraRefresh() {
1577         intraRefresh(googH265(), 480, 360);
1578     }
1579 
testGoogH264Flex360pWithIntraRefresh()1580     public void testGoogH264Flex360pWithIntraRefresh() {
1581         intraRefresh(googH264(), 480, 360);
1582     }
1583 
testGoogH263Flex360pWithIntraRefresh()1584     public void testGoogH263Flex360pWithIntraRefresh() {
1585         intraRefresh(googH263(), 480, 360);
1586     }
1587 
testGoogMpeg4Flex360pWithIntraRefresh()1588     public void testGoogMpeg4Flex360pWithIntraRefresh() {
1589         intraRefresh(googMpeg4(), 480, 360);
1590     }
1591 
testGoogVP8Flex360pWithIntraRefresh()1592     public void testGoogVP8Flex360pWithIntraRefresh() {
1593         intraRefresh(googVP8(), 480, 360);
1594     }
1595 
testOtherH265Flex360pWithIntraRefresh()1596     public void testOtherH265Flex360pWithIntraRefresh() {
1597         intraRefresh(otherH265(), 480, 360);
1598     }
1599 
testOtherH264Flex360pWithIntraRefresh()1600     public void testOtherH264Flex360pWithIntraRefresh() {
1601         intraRefresh(otherH264(), 480, 360);
1602     }
1603 
testOtherH263FlexQCIFWithIntraRefresh()1604     public void testOtherH263FlexQCIFWithIntraRefresh() {
1605         intraRefresh(otherH263(), 176, 120);
1606     }
1607 
testOtherMpeg4Flex360pWithIntraRefresh()1608     public void testOtherMpeg4Flex360pWithIntraRefresh() {
1609         intraRefresh(otherMpeg4(), 480, 360);
1610     }
1611 
testOtherVP8Flex360pWithIntraRefresh()1612     public void testOtherVP8Flex360pWithIntraRefresh() {
1613         intraRefresh(otherVP8(), 480, 360);
1614     }
1615 
1616     // Tests encoder profiles required by CDD.
1617     // H264
testH264LowQualitySDSupport()1618     public void testH264LowQualitySDSupport()   {
1619         support(h264(), 320, 240, 20, 384 * 1000);
1620     }
1621 
testH264HighQualitySDSupport()1622     public void testH264HighQualitySDSupport()   {
1623         support(h264(), 720, 480, 30, 2 * 1000000);
1624     }
1625 
testH264FlexQVGA20fps384kbps()1626     public void testH264FlexQVGA20fps384kbps()   {
1627         detailed(h264(), 320, 240, 20, 384 * 1000, true /* flex */);
1628     }
1629 
testH264SurfQVGA20fps384kbps()1630     public void testH264SurfQVGA20fps384kbps()   {
1631         detailed(h264(), 320, 240, 20, 384 * 1000, false /* flex */);
1632     }
1633 
testH264Flex480p30fps2Mbps()1634     public void testH264Flex480p30fps2Mbps()   {
1635         detailed(h264(), 720, 480, 30, 2 * 1000000, true /* flex */);
1636     }
1637 
testH264Surf480p30fps2Mbps()1638     public void testH264Surf480p30fps2Mbps()   {
1639         detailed(h264(), 720, 480, 30, 2 * 1000000, false /* flex */);
1640     }
1641 
testH264Flex720p30fps4Mbps()1642     public void testH264Flex720p30fps4Mbps()   {
1643         detailed(h264(), 1280, 720, 30, 4 * 1000000, true /* flex */);
1644     }
1645 
testH264Surf720p30fps4Mbps()1646     public void testH264Surf720p30fps4Mbps()   {
1647         detailed(h264(), 1280, 720, 30, 4 * 1000000, false /* flex */);
1648     }
1649 
testH264Flex1080p30fps10Mbps()1650     public void testH264Flex1080p30fps10Mbps()   {
1651         detailed(h264(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
1652     }
1653 
testH264Surf1080p30fps10Mbps()1654     public void testH264Surf1080p30fps10Mbps()   {
1655         detailed(h264(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
1656     }
1657 
1658     // VP8
testVP8LowQualitySDSupport()1659     public void testVP8LowQualitySDSupport()   {
1660         support(vp8(), 320, 180, 30, 800 * 1000);
1661     }
1662 
testVP8HighQualitySDSupport()1663     public void testVP8HighQualitySDSupport()   {
1664         support(vp8(), 640, 360, 30, 2 * 1000000);
1665     }
1666 
testVP8Flex180p30fps800kbps()1667     public void testVP8Flex180p30fps800kbps()   {
1668         detailed(vp8(), 320, 180, 30, 800 * 1000, true /* flex */);
1669     }
1670 
testVP8Surf180p30fps800kbps()1671     public void testVP8Surf180p30fps800kbps()   {
1672         detailed(vp8(), 320, 180, 30, 800 * 1000, false /* flex */);
1673     }
1674 
testVP8Flex360p30fps2Mbps()1675     public void testVP8Flex360p30fps2Mbps()   {
1676         detailed(vp8(), 640, 360, 30, 2 * 1000000, true /* flex */);
1677     }
1678 
testVP8Surf360p30fps2Mbps()1679     public void testVP8Surf360p30fps2Mbps()   {
1680         detailed(vp8(), 640, 360, 30, 2 * 1000000, false /* flex */);
1681     }
1682 
testVP8Flex720p30fps4Mbps()1683     public void testVP8Flex720p30fps4Mbps()   {
1684         detailed(vp8(), 1280, 720, 30, 4 * 1000000, true /* flex */);
1685     }
1686 
testVP8Surf720p30fps4Mbps()1687     public void testVP8Surf720p30fps4Mbps()   {
1688         detailed(vp8(), 1280, 720, 30, 4 * 1000000, false /* flex */);
1689     }
1690 
testVP8Flex1080p30fps10Mbps()1691     public void testVP8Flex1080p30fps10Mbps()   {
1692         detailed(vp8(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
1693     }
1694 
testVP8Surf1080p30fps10Mbps()1695     public void testVP8Surf1080p30fps10Mbps()   {
1696         detailed(vp8(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
1697     }
1698 
minmin(Encoder[] encoders, boolean flexYUV)1699     private void minmin(Encoder[] encoders, boolean flexYUV) {
1700         extreme(encoders, 0 /* x */, 0 /* y */, flexYUV, false /* near */);
1701     }
1702 
minmax(Encoder[] encoders, boolean flexYUV)1703     private void minmax(Encoder[] encoders, boolean flexYUV) {
1704         extreme(encoders, 0 /* x */, 1 /* y */, flexYUV, false /* near */);
1705     }
1706 
maxmin(Encoder[] encoders, boolean flexYUV)1707     private void maxmin(Encoder[] encoders, boolean flexYUV) {
1708         extreme(encoders, 1 /* x */, 0 /* y */, flexYUV, false /* near */);
1709     }
1710 
maxmax(Encoder[] encoders, boolean flexYUV)1711     private void maxmax(Encoder[] encoders, boolean flexYUV) {
1712         extreme(encoders, 1 /* x */, 1 /* y */, flexYUV, false /* near */);
1713     }
1714 
nearminmin(Encoder[] encoders, boolean flexYUV)1715     private void nearminmin(Encoder[] encoders, boolean flexYUV) {
1716         extreme(encoders, 0 /* x */, 0 /* y */, flexYUV, true /* near */);
1717     }
1718 
nearminmax(Encoder[] encoders, boolean flexYUV)1719     private void nearminmax(Encoder[] encoders, boolean flexYUV) {
1720         extreme(encoders, 0 /* x */, 1 /* y */, flexYUV, true /* near */);
1721     }
1722 
nearmaxmin(Encoder[] encoders, boolean flexYUV)1723     private void nearmaxmin(Encoder[] encoders, boolean flexYUV) {
1724         extreme(encoders, 1 /* x */, 0 /* y */, flexYUV, true /* near */);
1725     }
1726 
nearmaxmax(Encoder[] encoders, boolean flexYUV)1727     private void nearmaxmax(Encoder[] encoders, boolean flexYUV) {
1728         extreme(encoders, 1 /* x */, 1 /* y */, flexYUV, true /* near */);
1729     }
1730 
extreme(Encoder[] encoders, int x, int y, boolean flexYUV, boolean near)1731     private void extreme(Encoder[] encoders, int x, int y, boolean flexYUV, boolean near) {
1732         boolean skipped = true;
1733         if (encoders.length == 0) {
1734             MediaUtils.skipTest("no such encoder present");
1735             return;
1736         }
1737         for (Encoder encoder: encoders) {
1738             if (encoder.testExtreme(x, y, flexYUV, near)) {
1739                 skipped = false;
1740             }
1741         }
1742         if (skipped) {
1743             MediaUtils.skipTest("duplicate resolution extreme");
1744         }
1745     }
1746 
arbitrary(Encoder[] encoders, boolean flexYUV, boolean widths)1747     private void arbitrary(Encoder[] encoders, boolean flexYUV, boolean widths) {
1748         boolean skipped = true;
1749         if (encoders.length == 0) {
1750             MediaUtils.skipTest("no such encoder present");
1751             return;
1752         }
1753         for (Encoder encoder: encoders) {
1754             if (encoder.testArbitrary(flexYUV, widths)) {
1755                 skipped = false;
1756             }
1757         }
1758         if (skipped) {
1759             MediaUtils.skipTest("duplicate resolution");
1760         }
1761     }
1762 
arbitraryw(Encoder[] encoders, boolean flexYUV)1763     private void arbitraryw(Encoder[] encoders, boolean flexYUV) {
1764         arbitrary(encoders, flexYUV, true /* widths */);
1765     }
1766 
arbitraryh(Encoder[] encoders, boolean flexYUV)1767     private void arbitraryh(Encoder[] encoders, boolean flexYUV) {
1768         arbitrary(encoders, flexYUV, false /* widths */);
1769     }
1770 
1771     /* test specific size */
specific(Encoder[] encoders, int width, int height, boolean flexYUV)1772     private void specific(Encoder[] encoders, int width, int height, boolean flexYUV) {
1773         boolean skipped = true;
1774         if (encoders.length == 0) {
1775             MediaUtils.skipTest("no such encoder present");
1776             return;
1777         }
1778         for (Encoder encoder : encoders) {
1779             if (encoder.testSpecific(width, height, flexYUV)) {
1780                 skipped = false;
1781             }
1782         }
1783         if (skipped) {
1784             MediaUtils.skipTest("duplicate or unsupported resolution");
1785         }
1786     }
1787 
1788     /* test intra refresh with flexYUV */
intraRefresh(Encoder[] encoders, int width, int height)1789     private void intraRefresh(Encoder[] encoders, int width, int height) {
1790         boolean skipped = true;
1791         if (encoders.length == 0) {
1792             MediaUtils.skipTest("no such encoder present");
1793             return;
1794         }
1795         for (Encoder encoder : encoders) {
1796             if (encoder.testIntraRefresh(width, height)) {
1797                 skipped = false;
1798             }
1799         }
1800         if (skipped) {
1801             MediaUtils.skipTest("intra-refresh unsupported");
1802         }
1803     }
1804 
1805     /* test size, frame rate and bit rate */
detailed( Encoder[] encoders, int width, int height, int frameRate, int bitRate, boolean flexYUV)1806     private void detailed(
1807             Encoder[] encoders, int width, int height, int frameRate, int bitRate,
1808             boolean flexYUV) {
1809         if (encoders.length == 0) {
1810             MediaUtils.skipTest("no such encoder present");
1811             return;
1812         }
1813         boolean skipped = true;
1814         for (Encoder encoder : encoders) {
1815             if (encoder.testSupport(width, height, frameRate, bitRate)) {
1816                 skipped = false;
1817                 encoder.testDetailed(width, height, frameRate, bitRate, flexYUV);
1818             }
1819         }
1820         if (skipped) {
1821             MediaUtils.skipTest("unsupported resolution and rate");
1822         }
1823     }
1824 
1825     /* test size and rate are supported */
support(Encoder[] encoders, int width, int height, int frameRate, int bitRate)1826     private void support(Encoder[] encoders, int width, int height, int frameRate, int bitRate) {
1827         boolean supported = false;
1828         if (encoders.length == 0) {
1829             MediaUtils.skipTest("no such encoder present");
1830             return;
1831         }
1832         for (Encoder encoder : encoders) {
1833             if (encoder.testSupport(width, height, frameRate, bitRate)) {
1834                 supported = true;
1835                 break;
1836             }
1837         }
1838         if (!supported) {
1839             fail("unsupported format " + width + "x" + height + " " +
1840                     frameRate + "fps " + bitRate + "bps");
1841         }
1842     }
1843 }
1844