Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2012 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.content.res.AssetFileDescriptor;
     22 import android.content.res.Resources;
     23 import android.media.MediaCodec;
     24 import android.media.MediaCodecInfo;
     25 import android.media.MediaExtractor;
     26 import android.media.MediaFormat;
     27 import android.util.Log;
     28 import android.view.Surface;
     29 
     30 import java.io.BufferedInputStream;
     31 import java.io.IOException;
     32 import java.io.InputStream;
     33 import java.nio.ByteBuffer;
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.zip.CRC32;
     37 
     38 public class DecoderTest extends MediaPlayerTestBase {
     39     private static final String TAG = "DecoderTest";
     40 
     41     private static final int RESET_MODE_NONE = 0;
     42     private static final int RESET_MODE_RECONFIGURE = 1;
     43     private static final int RESET_MODE_FLUSH = 2;
     44 
     45     private Resources mResources;
     46     short[] mMasterBuffer;
     47 
     48     @Override
     49     protected void setUp() throws Exception {
     50         super.setUp();
     51         mResources = mContext.getResources();
     52 
     53         // read master file into memory
     54         AssetFileDescriptor masterFd = mResources.openRawResourceFd(R.raw.sinesweepraw);
     55         long masterLength = masterFd.getLength();
     56         mMasterBuffer = new short[(int) (masterLength / 2)];
     57         InputStream is = masterFd.createInputStream();
     58         BufferedInputStream bis = new BufferedInputStream(is);
     59         for (int i = 0; i < mMasterBuffer.length; i++) {
     60             int lo = bis.read();
     61             int hi = bis.read();
     62             if (hi >= 128) {
     63                 hi -= 256;
     64             }
     65             int sample = hi * 256 + lo;
     66             mMasterBuffer[i] = (short) sample;
     67         }
     68         bis.close();
     69         masterFd.close();
     70     }
     71 
     72     // The allowed errors in the following tests are the actual maximum measured
     73     // errors with the standard decoders, plus 10%.
     74     // This should allow for some variation in decoders, while still detecting
     75     // phase and delay errors, channel swap, etc.
     76     public void testDecodeMp3Lame() throws Exception {
     77         decode(R.raw.sinesweepmp3lame, 804.f);
     78     }
     79     public void testDecodeMp3Smpb() throws Exception {
     80         decode(R.raw.sinesweepmp3smpb, 413.f);
     81     }
     82     public void testDecodeM4a() throws Exception {
     83         decode(R.raw.sinesweepm4a, 124.f);
     84     }
     85     public void testDecodeOgg() throws Exception {
     86         decode(R.raw.sinesweepogg, 168.f);
     87     }
     88     public void testDecodeWav() throws Exception {
     89         decode(R.raw.sinesweepwav, 0.0f);
     90     }
     91     public void testDecodeFlac() throws Exception {
     92         decode(R.raw.sinesweepflac, 0.0f);
     93     }
     94 
     95     public void testDecodeMonoMp3() throws Exception {
     96         monoTest(R.raw.monotestmp3);
     97     }
     98 
     99     public void testDecodeMonoM4a() throws Exception {
    100         monoTest(R.raw.monotestm4a);
    101     }
    102 
    103     public void testDecodeMonoOgg() throws Exception {
    104         monoTest(R.raw.monotestogg);
    105     }
    106 
    107     private void monoTest(int res) throws Exception {
    108         short [] mono = decodeToMemory(res, RESET_MODE_NONE);
    109         if (mono.length == 44100) {
    110             // expected
    111         } else if (mono.length == 88200) {
    112             // the decoder output 2 channels instead of 1, check that the left and right channel
    113             // are identical
    114             for (int i = 0; i < mono.length; i += 2) {
    115                 assertEquals("mismatched samples at " + i, mono[i], mono[i+1]);
    116             }
    117         } else {
    118             fail("wrong number of samples: " + mono.length);
    119         }
    120 
    121         // we should get the same data when reconfiguring the codec
    122         short [] mono2 = decodeToMemory(res, RESET_MODE_RECONFIGURE);
    123         assertTrue(Arrays.equals(mono, mono2));
    124 
    125         // NOTE: coming soon
    126         // and when flushing it
    127 //        short [] mono3 = decodeToMemory(res, RESET_MODE_FLUSH);
    128 //        assertTrue(Arrays.equals(mono, mono3));
    129     }
    130 
    131     /**
    132      * @param testinput the file to decode
    133      * @param maxerror the maximum allowed root mean squared error
    134      * @throws IOException
    135      */
    136     private void decode(int testinput, float maxerror) throws IOException {
    137 
    138         short [] decoded = decodeToMemory(testinput, RESET_MODE_NONE);
    139 
    140         assertEquals("wrong data size", mMasterBuffer.length, decoded.length);
    141 
    142         long totalErrorSquared = 0;
    143 
    144         for (int i = 0; i < decoded.length; i++) {
    145             short sample = decoded[i];
    146             short mastersample = mMasterBuffer[i];
    147             int d = sample - mastersample;
    148             totalErrorSquared += d * d;
    149         }
    150 
    151         long avgErrorSquared = (totalErrorSquared / decoded.length);
    152         double rmse = Math.sqrt(avgErrorSquared);
    153         assertTrue("decoding error too big: " + rmse, rmse <= maxerror);
    154 
    155         short [] decoded2 = decodeToMemory(testinput, RESET_MODE_RECONFIGURE);
    156         assertEquals("count different with reconfigure", decoded.length, decoded2.length);
    157         for (int i = 0; i < decoded.length; i++) {
    158             assertEquals("samples don't match", decoded[i], decoded2[i]);
    159         }
    160 
    161         // NOTE: coming soon
    162 //        short [] decoded3 = decodeToMemory(testinput, RESET_MODE_FLUSH);
    163 //        assertEquals("count different with flush", decoded.length, decoded3.length);
    164 //        for (int i = 0; i < decoded.length; i++) {
    165 //            assertEquals("samples don't match", decoded[i], decoded3[i]);
    166 //        }
    167     }
    168 
    169     private short[] decodeToMemory(int testinput, int resetMode) throws IOException {
    170 
    171         short [] decoded = new short[0];
    172         int decodedIdx = 0;
    173 
    174         AssetFileDescriptor testFd = mResources.openRawResourceFd(testinput);
    175 
    176         MediaExtractor extractor;
    177         MediaCodec codec;
    178         ByteBuffer[] codecInputBuffers;
    179         ByteBuffer[] codecOutputBuffers;
    180 
    181         extractor = new MediaExtractor();
    182         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
    183                 testFd.getLength());
    184         testFd.close();
    185 
    186         assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
    187         MediaFormat format = extractor.getTrackFormat(0);
    188         String mime = format.getString(MediaFormat.KEY_MIME);
    189         assertTrue("not an audio file", mime.startsWith("audio/"));
    190 
    191         codec = MediaCodec.createDecoderByType(mime);
    192         codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
    193         codec.start();
    194         codecInputBuffers = codec.getInputBuffers();
    195         codecOutputBuffers = codec.getOutputBuffers();
    196 
    197         if (resetMode == RESET_MODE_RECONFIGURE) {
    198             codec.stop();
    199             codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
    200             codec.start();
    201             codecInputBuffers = codec.getInputBuffers();
    202             codecOutputBuffers = codec.getOutputBuffers();
    203         } else if (resetMode == RESET_MODE_FLUSH) {
    204             codec.flush();
    205         }
    206 
    207         extractor.selectTrack(0);
    208 
    209         // start decoding
    210         final long kTimeOutUs = 5000;
    211         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    212         boolean sawInputEOS = false;
    213         boolean sawOutputEOS = false;
    214         int noOutputCounter = 0;
    215         while (!sawOutputEOS && noOutputCounter < 50) {
    216             noOutputCounter++;
    217             if (!sawInputEOS) {
    218                 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
    219 
    220                 if (inputBufIndex >= 0) {
    221                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
    222 
    223                     int sampleSize =
    224                         extractor.readSampleData(dstBuf, 0 /* offset */);
    225 
    226                     long presentationTimeUs = 0;
    227 
    228                     if (sampleSize < 0) {
    229                         Log.d(TAG, "saw input EOS.");
    230                         sawInputEOS = true;
    231                         sampleSize = 0;
    232                     } else {
    233                         presentationTimeUs = extractor.getSampleTime();
    234                     }
    235 
    236                     codec.queueInputBuffer(
    237                             inputBufIndex,
    238                             0 /* offset */,
    239                             sampleSize,
    240                             presentationTimeUs,
    241                             sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
    242 
    243                     if (!sawInputEOS) {
    244                         extractor.advance();
    245                     }
    246                 }
    247             }
    248 
    249             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
    250 
    251             if (res >= 0) {
    252                 //Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
    253 
    254                 if (info.size > 0) {
    255                     noOutputCounter = 0;
    256                 }
    257                 if (info.size > 0 && resetMode != RESET_MODE_NONE) {
    258                     // once we've gotten some data out of the decoder, reset and start again
    259                     if (resetMode == RESET_MODE_RECONFIGURE) {
    260                         codec.stop();
    261                         codec.configure(format, null /* surface */, null /* crypto */,
    262                                 0 /* flags */);
    263                         codec.start();
    264                         codecInputBuffers = codec.getInputBuffers();
    265                         codecOutputBuffers = codec.getOutputBuffers();
    266                     } else /* resetMode == RESET_MODE_FLUSH */ {
    267                         codec.flush();
    268                     }
    269                     resetMode = RESET_MODE_NONE;
    270                     extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
    271                     sawInputEOS = false;
    272                     continue;
    273                 }
    274 
    275                 int outputBufIndex = res;
    276                 ByteBuffer buf = codecOutputBuffers[outputBufIndex];
    277 
    278                 if (decodedIdx + (info.size / 2) >= decoded.length) {
    279                     decoded = Arrays.copyOf(decoded, decodedIdx + (info.size / 2));
    280                 }
    281 
    282                 for (int i = 0; i < info.size; i += 2) {
    283                     decoded[decodedIdx++] = buf.getShort(i);
    284                 }
    285 
    286                 codec.releaseOutputBuffer(outputBufIndex, false /* render */);
    287 
    288                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
    289                     Log.d(TAG, "saw output EOS.");
    290                     sawOutputEOS = true;
    291                 }
    292             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
    293                 codecOutputBuffers = codec.getOutputBuffers();
    294 
    295                 Log.d(TAG, "output buffers have changed.");
    296             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    297                 MediaFormat oformat = codec.getOutputFormat();
    298 
    299                 Log.d(TAG, "output format has changed to " + oformat);
    300             } else {
    301                 Log.d(TAG, "dequeueOutputBuffer returned " + res);
    302             }
    303         }
    304 
    305         codec.stop();
    306         codec.release();
    307         return decoded;
    308     }
    309 
    310     public void testCodecBasicH264() throws Exception {
    311         Surface s = getActivity().getSurfaceHolder().getSurface();
    312         int frames1 = countFrames(
    313                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
    314                 RESET_MODE_NONE, -1 /* eosframe */, s);
    315         assertEquals("wrong number of frames decoded", 240, frames1);
    316 
    317         int frames2 = countFrames(
    318                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
    319                 RESET_MODE_NONE, -1 /* eosframe */, null);
    320         assertEquals("different number of frames when using Surface", frames1, frames2);
    321     }
    322 
    323     public void testCodecBasicH263() throws Exception {
    324         Surface s = getActivity().getSurfaceHolder().getSurface();
    325         int frames1 = countFrames(
    326                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
    327                 RESET_MODE_NONE, -1 /* eosframe */, s);
    328         assertEquals("wrong number of frames decoded", 122, frames1);
    329 
    330         int frames2 = countFrames(
    331                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
    332                 RESET_MODE_NONE, -1 /* eosframe */, null);
    333         assertEquals("different number of frames when using Surface", frames1, frames2);
    334     }
    335 
    336     public void testCodecBasicMpeg4() throws Exception {
    337         Surface s = getActivity().getSurfaceHolder().getSurface();
    338         int frames1 = countFrames(
    339                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
    340                 RESET_MODE_NONE, -1 /* eosframe */, s);
    341         assertEquals("wrong number of frames decoded", 249, frames1);
    342 
    343         int frames2 = countFrames(
    344                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
    345                 RESET_MODE_NONE, -1 /* eosframe */, null);
    346         assertEquals("different number of frames when using Surface", frames1, frames2);
    347     }
    348 
    349     public void testCodecBasicVP8() throws Exception {
    350         Surface s = getActivity().getSurfaceHolder().getSurface();
    351         int frames1 = countFrames(
    352                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    353                 RESET_MODE_NONE, -1 /* eosframe */, s);
    354         assertEquals("wrong number of frames decoded", 240, frames1);
    355 
    356         int frames2 = countFrames(
    357                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    358                 RESET_MODE_NONE, -1 /* eosframe */, null);
    359         assertEquals("different number of frames when using Surface", frames1, frames2);
    360     }
    361 
    362     public void testCodecBasicVP9() throws Exception {
    363         Surface s = getActivity().getSurfaceHolder().getSurface();
    364         int frames1 = countFrames(
    365                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    366                 RESET_MODE_NONE, -1 /* eosframe */, s);
    367         assertEquals("wrong number of frames decoded", 240, frames1);
    368 
    369         int frames2 = countFrames(
    370                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    371                 RESET_MODE_NONE, -1 /* eosframe */, null);
    372         assertEquals("different number of frames when using Surface", frames1, frames2);
    373     }
    374 
    375     public void testCodecEarlyEOSH263() throws Exception {
    376         Surface s = getActivity().getSurfaceHolder().getSurface();
    377         int frames1 = countFrames(
    378                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
    379                 RESET_MODE_NONE, 64 /* eosframe */, s);
    380         assertEquals("wrong number of frames decoded", 64, frames1);
    381     }
    382 
    383     public void testCodecEarlyEOSH264() throws Exception {
    384         Surface s = getActivity().getSurfaceHolder().getSurface();
    385         int frames1 = countFrames(
    386                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
    387                 RESET_MODE_NONE, 120 /* eosframe */, s);
    388         assertEquals("wrong number of frames decoded", 120, frames1);
    389     }
    390 
    391     public void testCodecEarlyEOSMpeg4() throws Exception {
    392         Surface s = getActivity().getSurfaceHolder().getSurface();
    393         int frames1 = countFrames(
    394                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
    395                 RESET_MODE_NONE, 120 /* eosframe */, s);
    396         assertEquals("wrong number of frames decoded", 120, frames1);
    397     }
    398 
    399     public void testCodecEarlyEOSVP8() throws Exception {
    400         Surface s = getActivity().getSurfaceHolder().getSurface();
    401         int frames1 = countFrames(
    402                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    403                 RESET_MODE_NONE, 120 /* eosframe */, s);
    404         assertEquals("wrong number of frames decoded", 120, frames1);
    405     }
    406 
    407     public void testCodecEarlyEOSVP9() throws Exception {
    408         Surface s = getActivity().getSurfaceHolder().getSurface();
    409         int frames1 = countFrames(
    410                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz,
    411                 RESET_MODE_NONE, 120 /* eosframe */, s);
    412         assertEquals("wrong number of frames decoded", 120, frames1);
    413     }
    414 
    415     public void testCodecResetsH264WithoutSurface() throws Exception {
    416         testCodecResets(
    417                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, null);
    418     }
    419 
    420     public void testCodecResetsH264WithSurface() throws Exception {
    421         Surface s = getActivity().getSurfaceHolder().getSurface();
    422         testCodecResets(
    423                 R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, s);
    424     }
    425 
    426     public void testCodecResetsH263WithoutSurface() throws Exception {
    427         testCodecResets(
    428                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, null);
    429     }
    430 
    431     public void testCodecResetsH263WithSurface() throws Exception {
    432         Surface s = getActivity().getSurfaceHolder().getSurface();
    433         testCodecResets(
    434                 R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, s);
    435     }
    436 
    437     public void testCodecResetsMpeg4WithoutSurface() throws Exception {
    438         testCodecResets(
    439                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, null);
    440     }
    441 
    442     public void testCodecResetsMpeg4WithSurface() throws Exception {
    443         Surface s = getActivity().getSurfaceHolder().getSurface();
    444         testCodecResets(
    445                 R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, s);
    446     }
    447 
    448     public void testCodecResetsVP8WithoutSurface() throws Exception {
    449         testCodecResets(
    450                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, null);
    451     }
    452 
    453     public void testCodecResetsVP8WithSurface() throws Exception {
    454         Surface s = getActivity().getSurfaceHolder().getSurface();
    455         testCodecResets(
    456                 R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, s);
    457     }
    458 
    459     public void testCodecResetsVP9WithoutSurface() throws Exception {
    460         testCodecResets(
    461                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, null);
    462     }
    463 
    464     public void testCodecResetsVP9WithSurface() throws Exception {
    465         Surface s = getActivity().getSurfaceHolder().getSurface();
    466         testCodecResets(
    467                 R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, s);
    468     }
    469 
    470 //    public void testCodecResetsOgg() throws Exception {
    471 //        testCodecResets(R.raw.sinesweepogg, null);
    472 //    }
    473 
    474     public void testCodecResetsMp3() throws Exception {
    475         testCodecReconfig(R.raw.sinesweepmp3lame, null);
    476         // NOTE: replacing testCodecReconfig call soon
    477 //        testCodecResets(R.raw.sinesweepmp3lame, null);
    478     }
    479 
    480     public void testCodecResetsM4a() throws Exception {
    481         testCodecReconfig(R.raw.sinesweepm4a, null);
    482         // NOTE: replacing testCodecReconfig call soon
    483 //        testCodecResets(R.raw.sinesweepm4a, null);
    484     }
    485 
    486     private void testCodecReconfig(int video, Surface s) throws Exception {
    487         int frames1 = countFrames(video, RESET_MODE_NONE, -1 /* eosframe */, s);
    488         int frames2 = countFrames(video, RESET_MODE_RECONFIGURE, -1 /* eosframe */, s);
    489         assertEquals("different number of frames when using reconfigured codec", frames1, frames2);
    490     }
    491 
    492     private void testCodecResets(int video, Surface s) throws Exception {
    493         int frames1 = countFrames(video, RESET_MODE_NONE, -1 /* eosframe */, s);
    494         int frames2 = countFrames(video, RESET_MODE_RECONFIGURE, -1 /* eosframe */, s);
    495         int frames3 = countFrames(video, RESET_MODE_FLUSH, -1 /* eosframe */, s);
    496         assertEquals("different number of frames when using reconfigured codec", frames1, frames2);
    497         assertEquals("different number of frames when using flushed codec", frames1, frames3);
    498     }
    499 
    500     private MediaCodec createDecoder(String mime) {
    501         if (false) {
    502             // change to force testing software codecs
    503             if (mime.contains("avc")) {
    504                 return MediaCodec.createByCodecName("OMX.google.h264.decoder");
    505             } else if (mime.contains("3gpp")) {
    506                 return MediaCodec.createByCodecName("OMX.google.h263.decoder");
    507             } else if (mime.contains("mp4v")) {
    508                 return MediaCodec.createByCodecName("OMX.google.mpeg4.decoder");
    509             } else if (mime.contains("vp8")) {
    510                 return MediaCodec.createByCodecName("OMX.google.vp8.decoder");
    511             } else if (mime.contains("vp9")) {
    512                 return MediaCodec.createByCodecName("OMX.google.vp9.decoder");
    513             }
    514         }
    515         return MediaCodec.createDecoderByType(mime);
    516     }
    517 
    518     private int countFrames(int video, int resetMode, int eosframe, Surface s)
    519             throws Exception {
    520         int numframes = 0;
    521 
    522         AssetFileDescriptor testFd = mResources.openRawResourceFd(video);
    523 
    524         MediaExtractor extractor;
    525         MediaCodec codec = null;
    526         ByteBuffer[] codecInputBuffers;
    527         ByteBuffer[] codecOutputBuffers;
    528 
    529         extractor = new MediaExtractor();
    530         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
    531                 testFd.getLength());
    532 
    533         MediaFormat format = extractor.getTrackFormat(0);
    534         String mime = format.getString(MediaFormat.KEY_MIME);
    535         boolean isAudio = mime.startsWith("audio/");
    536 
    537         codec = createDecoder(mime);
    538 
    539         assertNotNull("couldn't find codec", codec);
    540         Log.i("@@@@", "using codec: " + codec.getName());
    541         codec.configure(format, s /* surface */, null /* crypto */, 0 /* flags */);
    542         codec.start();
    543         codecInputBuffers = codec.getInputBuffers();
    544         codecOutputBuffers = codec.getOutputBuffers();
    545 
    546         if (resetMode == RESET_MODE_RECONFIGURE) {
    547             codec.stop();
    548             codec.configure(format, s /* surface */, null /* crypto */, 0 /* flags */);
    549             codec.start();
    550             codecInputBuffers = codec.getInputBuffers();
    551             codecOutputBuffers = codec.getOutputBuffers();
    552         } else if (resetMode == RESET_MODE_FLUSH) {
    553             codec.flush();
    554         }
    555 
    556         Log.i("@@@@", "format: " + format);
    557 
    558         extractor.selectTrack(0);
    559 
    560         // start decoding
    561         final long kTimeOutUs = 5000;
    562         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    563         boolean sawInputEOS = false;
    564         boolean sawOutputEOS = false;
    565         int deadDecoderCounter = 0;
    566         int samplecounter = 0;
    567         ArrayList<Long> timestamps = new ArrayList<Long>();
    568         while (!sawOutputEOS && deadDecoderCounter < 100) {
    569             if (!sawInputEOS) {
    570                 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
    571 
    572                 if (inputBufIndex >= 0) {
    573                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
    574 
    575                     int sampleSize =
    576                         extractor.readSampleData(dstBuf, 0 /* offset */);
    577 
    578                     long presentationTimeUs = 0;
    579 
    580                     if (sampleSize < 0) {
    581                         Log.d(TAG, "saw input EOS.");
    582                         sawInputEOS = true;
    583                         sampleSize = 0;
    584                     } else {
    585                         presentationTimeUs = extractor.getSampleTime();
    586                         samplecounter++;
    587                         if (samplecounter == eosframe) {
    588                             sawInputEOS = true;
    589                         }
    590                     }
    591 
    592                     timestamps.add(presentationTimeUs);
    593 
    594                     int flags = extractor.getSampleFlags();
    595 
    596                     codec.queueInputBuffer(
    597                             inputBufIndex,
    598                             0 /* offset */,
    599                             sampleSize,
    600                             presentationTimeUs,
    601                             sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
    602 
    603                     if (!sawInputEOS) {
    604                         extractor.advance();
    605                     }
    606                 }
    607             }
    608 
    609             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
    610 
    611             deadDecoderCounter++;
    612             if (res >= 0) {
    613                 //Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
    614 
    615                 // Some decoders output a 0-sized buffer at the end. Disregard those.
    616                 if (info.size > 0) {
    617                     deadDecoderCounter = 0;
    618                     if (resetMode != RESET_MODE_NONE) {
    619                         // once we've gotten some data out of the decoder, reset and start again
    620                         if (resetMode == RESET_MODE_RECONFIGURE) {
    621                             codec.stop();
    622                             codec.configure(format, s /* surface */, null /* crypto */,
    623                                     0 /* flags */);
    624                             codec.start();
    625                             codecInputBuffers = codec.getInputBuffers();
    626                             codecOutputBuffers = codec.getOutputBuffers();
    627                         } else /* resetMode == RESET_MODE_FLUSH */ {
    628                             codec.flush();
    629                         }
    630                         resetMode = RESET_MODE_NONE;
    631                         extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
    632                         sawInputEOS = false;
    633                         numframes = 0;
    634                         timestamps.clear();
    635                         continue;
    636                     }
    637 
    638                     if (isAudio) {
    639                         // for audio, count the number of bytes that were decoded, not the number
    640                         // of access units
    641                         numframes += info.size;
    642                     } else {
    643                         // for video, count the number of video frames and check the timestamp
    644                         numframes++;
    645                         assertTrue("invalid timestamp", timestamps.remove(info.presentationTimeUs));
    646                     }
    647                 }
    648                 int outputBufIndex = res;
    649                 codec.releaseOutputBuffer(outputBufIndex, true /* render */);
    650 
    651                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
    652                     Log.d(TAG, "saw output EOS.");
    653                     sawOutputEOS = true;
    654                 }
    655             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
    656                 codecOutputBuffers = codec.getOutputBuffers();
    657 
    658                 Log.d(TAG, "output buffers have changed.");
    659             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    660                 MediaFormat oformat = codec.getOutputFormat();
    661 
    662                 Log.d(TAG, "output format has changed to " + oformat);
    663             } else {
    664                 Log.d(TAG, "no output");
    665             }
    666         }
    667 
    668         codec.stop();
    669         codec.release();
    670         testFd.close();
    671         return numframes;
    672     }
    673 
    674     public void testEOSBehaviorH264() throws Exception {
    675         // this video has an I frame at 44
    676         testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 44);
    677         testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 45);
    678         testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz, 55);
    679     }
    680 
    681     public void testEOSBehaviorH263() throws Exception {
    682         // this video has an I frame every 12 frames.
    683         testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 24);
    684         testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 25);
    685         testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 48);
    686         testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz, 50);
    687     }
    688 
    689     public void testEOSBehaviorMpeg4() throws Exception {
    690         // this video has an I frame every 12 frames
    691         testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 24);
    692         testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 25);
    693         testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 48);
    694         testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 50);
    695         testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz, 2);
    696     }
    697 
    698     public void testEOSBehaviorVP8() throws Exception {
    699         // this video has an I frame at 46
    700         testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 46);
    701         testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 47);
    702         testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 57);
    703         testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 45);
    704     }
    705 
    706     public void testEOSBehaviorVP9() throws Exception {
    707         // this video has an I frame at 44
    708         testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 44);
    709         testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 45);
    710         testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 55);
    711         testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_44100hz, 43);
    712     }
    713 
    714     private void testEOSBehavior(int movie, int stopatsample) throws Exception {
    715 
    716         int numframes = 0;
    717 
    718         long [] checksums = new long[stopatsample];
    719 
    720         AssetFileDescriptor testFd = mResources.openRawResourceFd(movie);
    721 
    722         MediaExtractor extractor;
    723         MediaCodec codec = null;
    724         ByteBuffer[] codecInputBuffers;
    725         ByteBuffer[] codecOutputBuffers;
    726 
    727         extractor = new MediaExtractor();
    728         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
    729                 testFd.getLength());
    730 
    731         MediaFormat format = extractor.getTrackFormat(0);
    732         String mime = format.getString(MediaFormat.KEY_MIME);
    733         boolean isAudio = mime.startsWith("audio/");
    734 
    735         codec = createDecoder(mime);
    736 
    737         assertNotNull("couldn't find codec", codec);
    738         Log.i("@@@@", "using codec: " + codec.getName());
    739         codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
    740         codec.start();
    741         codecInputBuffers = codec.getInputBuffers();
    742         codecOutputBuffers = codec.getOutputBuffers();
    743 
    744         extractor.selectTrack(0);
    745 
    746         // start decoding
    747         final long kTimeOutUs = 5000;
    748         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    749         boolean sawInputEOS = false;
    750         boolean sawOutputEOS = false;
    751         int deadDecoderCounter = 0;
    752         int samplenum = 0;
    753         boolean dochecksum = false;
    754         while (!sawOutputEOS && deadDecoderCounter < 100) {
    755             if (!sawInputEOS) {
    756                 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
    757 
    758                 if (inputBufIndex >= 0) {
    759                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
    760 
    761                     int sampleSize =
    762                         extractor.readSampleData(dstBuf, 0 /* offset */);
    763 //                    Log.i("@@@@", "read sample " + samplenum + ":" + extractor.getSampleFlags()
    764 //                            + " @ " + extractor.getSampleTime() + " size " + sampleSize);
    765                     samplenum++;
    766 
    767                     long presentationTimeUs = 0;
    768 
    769                     if (sampleSize < 0 || samplenum >= (stopatsample + 100)) {
    770                         Log.d(TAG, "saw input EOS.");
    771                         sawInputEOS = true;
    772                         sampleSize = 0;
    773                     } else {
    774                         presentationTimeUs = extractor.getSampleTime();
    775                     }
    776 
    777                     int flags = extractor.getSampleFlags();
    778 
    779                     codec.queueInputBuffer(
    780                             inputBufIndex,
    781                             0 /* offset */,
    782                             sampleSize,
    783                             presentationTimeUs,
    784                             sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
    785 
    786                     if (!sawInputEOS) {
    787                         extractor.advance();
    788                     }
    789                 }
    790             }
    791 
    792             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
    793 
    794             deadDecoderCounter++;
    795             if (res >= 0) {
    796 
    797                 // Some decoders output a 0-sized buffer at the end. Disregard those.
    798                 if (info.size > 0) {
    799                     deadDecoderCounter = 0;
    800 
    801                     if (isAudio) {
    802                         // for audio, count the number of bytes that were decoded, not the number
    803                         // of access units
    804                         numframes += info.size;
    805                     } else {
    806                         // for video, count the number of video frames
    807                         long sum = dochecksum ? checksum(codecOutputBuffers[res], info.size) : 0;
    808                         if (numframes < checksums.length) {
    809                             checksums[numframes] = sum;
    810                         }
    811                         numframes++;
    812                     }
    813                 }
    814 //                Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs +
    815 //                        "/" + numframes + "/" + info.flags);
    816 
    817                 int outputBufIndex = res;
    818                 codec.releaseOutputBuffer(outputBufIndex, true /* render */);
    819 
    820                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
    821                     Log.d(TAG, "saw output EOS.");
    822                     sawOutputEOS = true;
    823                 }
    824             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
    825                 codecOutputBuffers = codec.getOutputBuffers();
    826 
    827                 Log.d(TAG, "output buffers have changed.");
    828             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    829                 MediaFormat oformat = codec.getOutputFormat();
    830                 int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
    831                 dochecksum = isRecognizedFormat(colorFormat);
    832                 Log.d(TAG, "output format has changed to " + oformat);
    833             } else {
    834                 Log.d(TAG, "no output");
    835             }
    836         }
    837 
    838         codec.stop();
    839         codec.release();
    840         extractor.release();
    841 
    842 
    843         // We now have checksums for every frame.
    844         // Now decode again, but signal EOS right before an index frame, and ensure the frames
    845         // prior to that are the same.
    846 
    847         extractor = new MediaExtractor();
    848         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
    849                 testFd.getLength());
    850 
    851         codec = createDecoder(mime);
    852         codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
    853         codec.start();
    854         codecInputBuffers = codec.getInputBuffers();
    855         codecOutputBuffers = codec.getOutputBuffers();
    856 
    857         extractor.selectTrack(0);
    858 
    859         // start decoding
    860         info = new MediaCodec.BufferInfo();
    861         sawInputEOS = false;
    862         sawOutputEOS = false;
    863         deadDecoderCounter = 0;
    864         samplenum = 0;
    865         numframes = 0;
    866         dochecksum = false;
    867         while (!sawOutputEOS && deadDecoderCounter < 100) {
    868             if (!sawInputEOS) {
    869                 int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
    870 
    871                 if (inputBufIndex >= 0) {
    872                     ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
    873 
    874                     int sampleSize =
    875                         extractor.readSampleData(dstBuf, 0 /* offset */);
    876 //                    Log.i("@@@@", "read sample " + samplenum + ":" + extractor.getSampleFlags()
    877 //                            + " @ " + extractor.getSampleTime() + " size " + sampleSize);
    878                     samplenum++;
    879 
    880                     long presentationTimeUs = extractor.getSampleTime();
    881 
    882                     if (sampleSize < 0 || samplenum >= stopatsample) {
    883                         Log.d(TAG, "saw input EOS.");
    884                         sawInputEOS = true;
    885                         if (sampleSize < 0) {
    886                             sampleSize = 0;
    887                         }
    888                     }
    889 
    890                     int flags = extractor.getSampleFlags();
    891 
    892                     codec.queueInputBuffer(
    893                             inputBufIndex,
    894                             0 /* offset */,
    895                             sampleSize,
    896                             presentationTimeUs,
    897                             sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
    898 
    899                     if (!sawInputEOS) {
    900                         extractor.advance();
    901                     }
    902                 }
    903             }
    904 
    905             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
    906 
    907             deadDecoderCounter++;
    908             if (res >= 0) {
    909 
    910                 // Some decoders output a 0-sized buffer at the end. Disregard those.
    911                 if (info.size > 0) {
    912                     deadDecoderCounter = 0;
    913 
    914                     if (isAudio) {
    915                         // for audio, count the number of bytes that were decoded, not the number
    916                         // of access units
    917                         numframes += info.size;
    918                     } else {
    919                         // for video, count the number of video frames
    920                         long sum = dochecksum ? checksum(codecOutputBuffers[res], info.size) : 0;
    921                         if (numframes < checksums.length) {
    922                             assertEquals("frame data mismatch at frame " + numframes,
    923                                     checksums[numframes], sum);
    924                         }
    925                         numframes++;
    926                     }
    927                 }
    928 //                Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs +
    929 //                        "/" + numframes + "/" + info.flags);
    930 
    931                 int outputBufIndex = res;
    932                 codec.releaseOutputBuffer(outputBufIndex, true /* render */);
    933 
    934                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
    935                     Log.d(TAG, "saw output EOS.");
    936                     sawOutputEOS = true;
    937                 }
    938             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
    939                 codecOutputBuffers = codec.getOutputBuffers();
    940 
    941                 Log.d(TAG, "output buffers have changed.");
    942             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
    943                 MediaFormat oformat = codec.getOutputFormat();
    944                 int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
    945                 dochecksum = isRecognizedFormat(colorFormat);
    946                 Log.d(TAG, "output format has changed to " + oformat);
    947             } else {
    948                 Log.d(TAG, "no output");
    949             }
    950         }
    951 
    952         codec.stop();
    953         codec.release();
    954         extractor.release();
    955 
    956         assertEquals("I!=O", samplenum, numframes);
    957         assertTrue("last frame didn't have EOS", sawOutputEOS);
    958         assertEquals(stopatsample, numframes);
    959 
    960         testFd.close();
    961     }
    962 
    963     /* from EncodeDecodeTest */
    964     private static boolean isRecognizedFormat(int colorFormat) {
    965         switch (colorFormat) {
    966             // these are the formats we know how to handle for this test
    967             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar:
    968             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar:
    969             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar:
    970             case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar:
    971             case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar:
    972                 return true;
    973             default:
    974                 return false;
    975         }
    976     }
    977 
    978     private long checksum(ByteBuffer buf, int size) {
    979         assertTrue(size != 0);
    980         assertTrue(size <= buf.capacity());
    981         CRC32 crc = new CRC32();
    982         int pos = buf.position();
    983         buf.rewind();
    984         for (int i = 0; i < buf.capacity(); i++) {
    985             crc.update(buf.get());
    986         }
    987         buf.position(pos);
    988         return crc.getValue();
    989     }
    990 
    991     public void testFlush() throws Exception {
    992         testFlush(R.raw.loudsoftwav);
    993         testFlush(R.raw.loudsoftogg);
    994         testFlush(R.raw.loudsoftmp3);
    995         testFlush(R.raw.loudsoftaac);
    996         testFlush(R.raw.loudsoftfaac);
    997         testFlush(R.raw.loudsoftitunes);
    998     }
    999 
   1000     private void testFlush(int resource) throws Exception {
   1001 
   1002         AssetFileDescriptor testFd = mResources.openRawResourceFd(resource);
   1003 
   1004         MediaExtractor extractor;
   1005         MediaCodec codec;
   1006         ByteBuffer[] codecInputBuffers;
   1007         ByteBuffer[] codecOutputBuffers;
   1008 
   1009         extractor = new MediaExtractor();
   1010         extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
   1011                 testFd.getLength());
   1012         testFd.close();
   1013 
   1014         assertEquals("wrong number of tracks", 1, extractor.getTrackCount());
   1015         MediaFormat format = extractor.getTrackFormat(0);
   1016         String mime = format.getString(MediaFormat.KEY_MIME);
   1017         assertTrue("not an audio file", mime.startsWith("audio/"));
   1018 
   1019         codec = MediaCodec.createDecoderByType(mime);
   1020         codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
   1021         codec.start();
   1022         codecInputBuffers = codec.getInputBuffers();
   1023         codecOutputBuffers = codec.getOutputBuffers();
   1024 
   1025         extractor.selectTrack(0);
   1026 
   1027         // decode a bit of the first part of the file, and verify the amplitude
   1028         short maxvalue1 = getAmplitude(extractor, codec);
   1029 
   1030         // flush the codec and seek the extractor a different position, then decode a bit more
   1031         // and check the amplitude
   1032         extractor.seekTo(8000000, 0);
   1033         codec.flush();
   1034         short maxvalue2 = getAmplitude(extractor, codec);
   1035 
   1036         assertTrue("first section amplitude too low", maxvalue1 > 20000);
   1037         assertTrue("second section amplitude too high", maxvalue2 < 5000);
   1038         codec.stop();
   1039         codec.release();
   1040 
   1041     }
   1042 
   1043     private short getAmplitude(MediaExtractor extractor, MediaCodec codec) {
   1044         short maxvalue = 0;
   1045         int numBytesDecoded = 0;
   1046         final long kTimeOutUs = 5000;
   1047         ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
   1048         ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
   1049         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
   1050 
   1051         while(numBytesDecoded < 44100 * 2) {
   1052             int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
   1053 
   1054             if (inputBufIndex >= 0) {
   1055                 ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
   1056 
   1057                 int sampleSize = extractor.readSampleData(dstBuf, 0 /* offset */);
   1058                 long presentationTimeUs = extractor.getSampleTime();
   1059 
   1060                 codec.queueInputBuffer(
   1061                         inputBufIndex,
   1062                         0 /* offset */,
   1063                         sampleSize,
   1064                         presentationTimeUs,
   1065                         0 /* flags */);
   1066 
   1067                 extractor.advance();
   1068             }
   1069             int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
   1070 
   1071             if (res >= 0) {
   1072 
   1073                 int outputBufIndex = res;
   1074                 ByteBuffer buf = codecOutputBuffers[outputBufIndex];
   1075 
   1076                 for (int i = 0; i < info.size; i += 2) {
   1077                     short sample = buf.getShort(i);
   1078                     if (maxvalue < sample) {
   1079                         maxvalue = sample;
   1080                     }
   1081                     int idx = (numBytesDecoded + i) / 2;
   1082                 }
   1083 
   1084                 numBytesDecoded += info.size;
   1085 
   1086                 codec.releaseOutputBuffer(outputBufIndex, false /* render */);
   1087             } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
   1088                 codecOutputBuffers = codec.getOutputBuffers();
   1089             } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
   1090                 MediaFormat oformat = codec.getOutputFormat();
   1091             }
   1092         }
   1093         return maxvalue;
   1094     }
   1095 
   1096 }
   1097 
   1098