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