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