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