Home | History | Annotate | Download | only in media
      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;
     18 
     19 import android.graphics.ImageFormat;
     20 import android.graphics.Rect;
     21 import android.media.Image;
     22 import android.media.Image.Plane;
     23 import android.media.MediaCodecInfo;
     24 import android.media.MediaCodecList;
     25 import android.media.MediaCrypto;
     26 import android.media.MediaFormat;
     27 import android.os.Bundle;
     28 import android.os.Handler;
     29 import android.os.Looper;
     30 import android.os.Message;
     31 import android.view.Surface;
     32 
     33 import java.io.IOException;
     34 import java.nio.ByteBuffer;
     35 import java.nio.ReadOnlyBufferException;
     36 import java.util.Arrays;
     37 import java.util.HashMap;
     38 import java.util.Map;
     39 
     40 /**
     41  * MediaCodec class can be used to access low-level media codec, i.e.
     42  * encoder/decoder components.
     43  *
     44  * <p>MediaCodec is generally used like this:
     45  * <pre>
     46  * MediaCodec codec = MediaCodec.createDecoderByType(type);
     47  * codec.configure(format, ...);
     48  * codec.start();
     49  *
     50  * // if API level <= 20, get input and output buffer arrays here
     51  * ByteBuffer[] inputBuffers = codec.getInputBuffers();
     52  * ByteBuffer[] outputBuffers = codec.getOutputBuffers();
     53  * for (;;) {
     54  *   int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
     55  *   if (inputBufferIndex &gt;= 0) {
     56  *     // if API level >= 21, get input buffer here
     57  *     ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferIndex);
     58  *     // fill inputBuffers[inputBufferIndex] with valid data
     59  *     ...
     60  *     codec.queueInputBuffer(inputBufferIndex, ...);
     61  *   }
     62  *
     63  *   int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
     64  *   if (outputBufferIndex &gt;= 0) {
     65  *     // if API level >= 21, get output buffer here
     66  *     ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferIndex);
     67  *     // outputBuffer is ready to be processed or rendered.
     68  *     ...
     69  *     codec.releaseOutputBuffer(outputBufferIndex, ...);
     70  *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
     71  *     // no needed to handle if API level >= 21 and using getOutputBuffer(int)
     72  *     outputBuffers = codec.getOutputBuffers();
     73  *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
     74  *     // Subsequent data will conform to new format.
     75  *     // can ignore if API level >= 21 and using getOutputFormat(outputBufferIndex)
     76  *     MediaFormat format = codec.getOutputFormat();
     77  *     ...
     78  *   }
     79  * }
     80  * codec.stop();
     81  * codec.release();
     82  * codec = null;
     83  * </pre>
     84  *
     85  * Each codec maintains a number of input and output buffers that are
     86  * referred to by index in API calls.
     87  * <p>
     88  * For API levels 20 and below:
     89  * The contents of these buffers are represented by the ByteBuffer[] arrays
     90  * accessible through {@link #getInputBuffers} and {@link #getOutputBuffers}.
     91  * <p>
     92  * After a successful call to {@link #start} the client "owns" neither
     93  * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer}
     94  * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
     95  * to the client.<p>
     96  * The client is not required to resubmit/release buffers immediately
     97  * to the codec, the sample code above simply does this for simplicity's sake.
     98  * Nonetheless, it is possible that a codec may hold off on generating
     99  * output buffers until all outstanding buffers have been
    100  * released/resubmitted.
    101  * <p>
    102  * Once the client has an input buffer available it can fill it with data
    103  * and submit it it to the codec via a call to {@link #queueInputBuffer}.
    104  * Do not submit multiple input buffers with the same timestamp (unless
    105  * it is codec-specific data marked as such using the flag
    106  * {@link #BUFFER_FLAG_CODEC_CONFIG}).
    107  * <p>
    108  * The codec in turn will return an output buffer to the client in response
    109  * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
    110  * a call to {@link #releaseOutputBuffer} will return it to the codec.
    111  * If a video surface has been provided in the call to {@link #configure},
    112  * {@link #releaseOutputBuffer} optionally allows rendering of the buffer
    113  * to the surface.<p>
    114  *
    115  * Input buffers (for decoders) and Output buffers (for encoders) contain
    116  * encoded data according to the format's type. For video types this data
    117  * is all the encoded data representing a single moment in time, for audio
    118  * data this is slightly relaxed in that a buffer may contain multiple
    119  * encoded frames of audio. In either case, buffers do not start and end on
    120  * arbitrary byte boundaries, this is not a stream of bytes, it's a stream
    121  * of access units.<p>
    122  *
    123  * Most formats also require the actual data to be prefixed by a number
    124  * of buffers containing setup data, or codec specific data, i.e. the
    125  * first few buffers submitted to the codec object after starting it must
    126  * be codec specific data marked as such using the flag {@link #BUFFER_FLAG_CODEC_CONFIG}
    127  * in a call to {@link #queueInputBuffer}.
    128  * <p>
    129  * Codec specific data included in the format passed to {@link #configure}
    130  * (in ByteBuffer entries with keys "csd-0", "csd-1", ...) is automatically
    131  * submitted to the codec, this data MUST NOT be submitted explicitly by the
    132  * client.
    133  * <p>
    134  * Once the client reaches the end of the input data it signals the end of
    135  * the input stream by specifying a flag of {@link #BUFFER_FLAG_END_OF_STREAM} in the call to
    136  * {@link #queueInputBuffer}. The codec will continue to return output buffers
    137  * until it eventually signals the end of the output stream by specifying
    138  * the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in
    139  * {@link #dequeueOutputBuffer}.  Do not submit additional input buffers after
    140  * signaling the end of the input stream, unless the codec has been flushed,
    141  * or stopped and restarted.
    142  * <p>
    143  * <h3>Seeking &amp; Adaptive Playback Support</h3>
    144  *
    145  * You can check if a decoder supports adaptive playback via {@link
    146  * MediaCodecInfo.CodecCapabilities#isFeatureSupported}.  Adaptive playback
    147  * is only supported if you configure the codec to decode onto a {@link
    148  * android.view.Surface}.
    149  *
    150  * <h4>For decoders that do not support adaptive playback (including
    151  * when not decoding onto a Surface)</h4>
    152  *
    153  * In order to start decoding data that's not adjacent to previously submitted
    154  * data (i.e. after a seek) <em>one must</em> {@link #flush} the decoder.
    155  * Any input or output buffers the client may own at the point of the flush are
    156  * immediately revoked, i.e. after a call to {@link #flush} the client does not
    157  * own any buffers anymore.
    158  * <p>
    159  * It is important that the input data after a flush starts at a suitable
    160  * stream boundary.  The first frame must be able to be decoded completely on
    161  * its own (for most codecs this means an I-frame), and that no frames should
    162  * refer to frames before that first new frame.
    163  * Note that the format of the data submitted after a flush must not change,
    164  * flush does not support format discontinuities,
    165  * for this a full {@link #stop}, {@link #configure configure()}, {@link #start}
    166  * cycle is necessary.
    167  *
    168  * <h4>For decoders that support adaptive playback</h4>
    169  *
    170  * In order to start decoding data that's not adjacent to previously submitted
    171  * data (i.e. after a seek) it is <em>not necessary</em> to {@link #flush} the
    172  * decoder.
    173  * <p>
    174  * It is still important that the input data after the discontinuity starts
    175  * at a suitable stream boundary (e.g. I-frame), and that no new frames refer
    176  * to frames before the first frame of the new input data segment.
    177  * <p>
    178  * For some video formats it is also possible to change the picture size
    179  * mid-stream.  To do this for H.264, the new Sequence Parameter Set (SPS) and
    180  * Picture Parameter Set (PPS) values must be packaged together with an
    181  * Instantaneous Decoder Refresh (IDR) frame in a single buffer, which then
    182  * can be enqueued as a regular input buffer.
    183  * The client will receive an {@link #INFO_OUTPUT_FORMAT_CHANGED} return
    184  * value from {@link #dequeueOutputBuffer dequeueOutputBuffer()} or
    185  * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable()}
    186  * just after the picture-size change takes place and before any
    187  * frames with the new size have been returned.
    188  * <p>
    189  * Be careful when calling {@link #flush} shortly after you have changed
    190  * the picture size.  If you have not received confirmation of the picture
    191  * size change, you will need to repeat the request for the new picture size.
    192  * E.g. for H.264 you will need to prepend the PPS/SPS to the new IDR
    193  * frame to ensure that the codec receives the picture size change request.
    194  *
    195  * <h3>States and error handling</h3>
    196  *
    197  * <p> During its life, a codec conceptually exists in one of the following states:
    198  * Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
    199  * between them). When created by one of the factory methods,
    200  * the codec is in the Initialized state; {@link #configure} brings it to the
    201  * Configured state; {@link #start} brings it to the Executing state.
    202  * In the Executing state, decoding or encoding occurs through the buffer queue
    203  * manipulation described above. The method {@link #stop}
    204  * returns the codec to the Initialized state, whereupon it may be configured again,
    205  * and {@link #release} brings the codec to the terminal Uninitialized state.  When
    206  * a codec error occurs, the codec moves to the Error state.  Use {@link #reset} to
    207  * bring the codec back to the Initialized state, or {@link #release} to move it
    208  * to the Uninitialized state.
    209  *
    210  * <p> The factory methods
    211  * {@link #createByCodecName},
    212  * {@link #createDecoderByType},
    213  * and {@link #createEncoderByType}
    214  * throw {@link java.io.IOException} on failure which
    215  * the caller must catch or declare to pass up.
    216  * MediaCodec methods throw {@link java.lang.IllegalStateException}
    217  * when the method is called from a codec state that does not allow it;
    218  * this is typically due to incorrect application API usage.
    219  * Methods involving secure buffers may throw
    220  * {@link MediaCodec.CryptoException#MediaCodec.CryptoException}, which
    221  * has further error information obtainable from {@link MediaCodec.CryptoException#getErrorCode}.
    222  *
    223  * <p> Internal codec errors result in a {@link MediaCodec.CodecException},
    224  * which may be due to media content corruption, hardware failure, resource exhaustion,
    225  * and so forth, even when the application is correctly using the API.
    226  * The recommended action when receiving a {@link MediaCodec.CodecException} can be determined by
    227  * calling {@link MediaCodec.CodecException#isRecoverable} and
    228  * {@link MediaCodec.CodecException#isTransient}.
    229  * If {@link MediaCodec.CodecException#isRecoverable} returns true,
    230  * then a {@link #stop}, {@link #configure}, and {@link #start} can be performed to recover.
    231  * If {@link MediaCodec.CodecException#isTransient} returns true,
    232  * then resources are temporarily unavailable and the method may be retried at a later time.
    233  * If both {@link MediaCodec.CodecException#isRecoverable}
    234  * and {@link MediaCodec.CodecException#isTransient} return false,
    235  * then the {@link MediaCodec.CodecException} is fatal and the codec must be
    236  * {@link #reset reset} or {@link #release released}.
    237  * Both {@link MediaCodec.CodecException#isRecoverable} and
    238  * {@link MediaCodec.CodecException#isTransient} do not return true at the same time.
    239  */
    240 final public class MediaCodec {
    241     /**
    242      * Per buffer metadata includes an offset and size specifying
    243      * the range of valid data in the associated codec (output) buffer.
    244      */
    245     public final static class BufferInfo {
    246         /**
    247          * Update the buffer metadata information.
    248          *
    249          * @param newOffset the start-offset of the data in the buffer.
    250          * @param newSize   the amount of data (in bytes) in the buffer.
    251          * @param newTimeUs the presentation timestamp in microseconds.
    252          * @param newFlags  buffer flags associated with the buffer.  This
    253          * should be a combination of  {@link #BUFFER_FLAG_KEY_FRAME} and
    254          * {@link #BUFFER_FLAG_END_OF_STREAM}.
    255          */
    256         public void set(
    257                 int newOffset, int newSize, long newTimeUs, int newFlags) {
    258             offset = newOffset;
    259             size = newSize;
    260             presentationTimeUs = newTimeUs;
    261             flags = newFlags;
    262         }
    263 
    264         /**
    265          * The start-offset of the data in the buffer.
    266          */
    267         public int offset;
    268 
    269         /**
    270          * The amount of data (in bytes) in the buffer.  If this is {@code 0},
    271          * the buffer has no data in it and can be discarded.  The only
    272          * use of a 0-size buffer is to carry the end-of-stream marker.
    273          */
    274         public int size;
    275 
    276         /**
    277          * The presentation timestamp in microseconds for the buffer.
    278          * This is derived from the presentation timestamp passed in
    279          * with the corresponding input buffer.  This should be ignored for
    280          * a 0-sized buffer.
    281          */
    282         public long presentationTimeUs;
    283 
    284         /**
    285          * Buffer flags associated with the buffer.  A combination of
    286          * {@link #BUFFER_FLAG_KEY_FRAME} and {@link #BUFFER_FLAG_END_OF_STREAM}.
    287          *
    288          * <p>Encoded buffers that are key frames are marked with
    289          * {@link #BUFFER_FLAG_KEY_FRAME}.
    290          *
    291          * <p>The last output buffer corresponding to the input buffer
    292          * marked with {@link #BUFFER_FLAG_END_OF_STREAM} will also be marked
    293          * with {@link #BUFFER_FLAG_END_OF_STREAM}. In some cases this could
    294          * be an empty buffer, whose sole purpose is to carry the end-of-stream
    295          * marker.
    296          */
    297         public int flags;
    298     };
    299 
    300     // The follow flag constants MUST stay in sync with their equivalents
    301     // in MediaCodec.h !
    302 
    303     /**
    304      * This indicates that the (encoded) buffer marked as such contains
    305      * the data for a key frame.
    306      *
    307      * @deprecated Use {@link #BUFFER_FLAG_KEY_FRAME} instead.
    308      */
    309     public static final int BUFFER_FLAG_SYNC_FRAME = 1;
    310 
    311     /**
    312      * This indicates that the (encoded) buffer marked as such contains
    313      * the data for a key frame.
    314      */
    315     public static final int BUFFER_FLAG_KEY_FRAME = 1;
    316 
    317     /**
    318      * This indicated that the buffer marked as such contains codec
    319      * initialization / codec specific data instead of media data.
    320      */
    321     public static final int BUFFER_FLAG_CODEC_CONFIG = 2;
    322 
    323     /**
    324      * This signals the end of stream, i.e. no buffers will be available
    325      * after this, unless of course, {@link #flush} follows.
    326      */
    327     public static final int BUFFER_FLAG_END_OF_STREAM = 4;
    328 
    329     private EventHandler mEventHandler;
    330     private Callback mCallback;
    331 
    332     private static final int EVENT_CALLBACK = 1;
    333     private static final int EVENT_SET_CALLBACK = 2;
    334 
    335     private static final int CB_INPUT_AVAILABLE = 1;
    336     private static final int CB_OUTPUT_AVAILABLE = 2;
    337     private static final int CB_ERROR = 3;
    338     private static final int CB_OUTPUT_FORMAT_CHANGE = 4;
    339 
    340     private class EventHandler extends Handler {
    341         private MediaCodec mCodec;
    342 
    343         public EventHandler(MediaCodec codec, Looper looper) {
    344             super(looper);
    345             mCodec = codec;
    346         }
    347 
    348         @Override
    349         public void handleMessage(Message msg) {
    350             switch (msg.what) {
    351                 case EVENT_CALLBACK:
    352                 {
    353                     handleCallback(msg);
    354                     break;
    355                 }
    356                 case EVENT_SET_CALLBACK:
    357                 {
    358                     mCallback = (MediaCodec.Callback) msg.obj;
    359                     break;
    360                 }
    361                 default:
    362                 {
    363                     break;
    364                 }
    365             }
    366         }
    367 
    368         private void handleCallback(Message msg) {
    369             if (mCallback == null) {
    370                 return;
    371             }
    372 
    373             switch (msg.arg1) {
    374                 case CB_INPUT_AVAILABLE:
    375                 {
    376                     int index = msg.arg2;
    377                     synchronized(mBufferLock) {
    378                         validateInputByteBuffer(mCachedInputBuffers, index);
    379                     }
    380                     mCallback.onInputBufferAvailable(mCodec, index);
    381                     break;
    382                 }
    383 
    384                 case CB_OUTPUT_AVAILABLE:
    385                 {
    386                     int index = msg.arg2;
    387                     BufferInfo info = (MediaCodec.BufferInfo) msg.obj;
    388                     synchronized(mBufferLock) {
    389                         validateOutputByteBuffer(mCachedOutputBuffers, index, info);
    390                     }
    391                     mCallback.onOutputBufferAvailable(
    392                             mCodec, index, info);
    393                     break;
    394                 }
    395 
    396                 case CB_ERROR:
    397                 {
    398                     mCallback.onError(mCodec, (MediaCodec.CodecException) msg.obj);
    399                     break;
    400                 }
    401 
    402                 case CB_OUTPUT_FORMAT_CHANGE:
    403                 {
    404                     mCallback.onOutputFormatChanged(mCodec,
    405                             new MediaFormat((Map<String, Object>) msg.obj));
    406                     break;
    407                 }
    408 
    409                 default:
    410                 {
    411                     break;
    412                 }
    413             }
    414         }
    415     }
    416 
    417     /**
    418      * Instantiate a decoder supporting input data of the given mime type.
    419      *
    420      * The following is a partial list of defined mime types and their semantics:
    421      * <ul>
    422      * <li>"video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm)
    423      * <li>"video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm)
    424      * <li>"video/avc" - H.264/AVC video
    425      * <li>"video/hevc" - H.265/HEVC video
    426      * <li>"video/mp4v-es" - MPEG4 video
    427      * <li>"video/3gpp" - H.263 video
    428      * <li>"audio/3gpp" - AMR narrowband audio
    429      * <li>"audio/amr-wb" - AMR wideband audio
    430      * <li>"audio/mpeg" - MPEG1/2 audio layer III
    431      * <li>"audio/mp4a-latm" - AAC audio (note, this is raw AAC packets, not packaged in LATM!)
    432      * <li>"audio/vorbis" - vorbis audio
    433      * <li>"audio/g711-alaw" - G.711 alaw audio
    434      * <li>"audio/g711-mlaw" - G.711 ulaw audio
    435      * </ul>
    436      *
    437      * @param type The mime type of the input data.
    438      * @throws IOException if the codec cannot be created.
    439      * @throws IllegalArgumentException if type is not a valid mime type.
    440      * @throws NullPointerException if type is null.
    441      */
    442     public static MediaCodec createDecoderByType(String type)
    443             throws IOException {
    444         return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
    445     }
    446 
    447     /**
    448      * Instantiate an encoder supporting output data of the given mime type.
    449      * @param type The desired mime type of the output data.
    450      * @throws IOException if the codec cannot be created.
    451      * @throws IllegalArgumentException if type is not a valid mime type.
    452      * @throws NullPointerException if type is null.
    453      */
    454     public static MediaCodec createEncoderByType(String type)
    455             throws IOException {
    456         return new MediaCodec(type, true /* nameIsType */, true /* encoder */);
    457     }
    458 
    459     /**
    460      * If you know the exact name of the component you want to instantiate
    461      * use this method to instantiate it. Use with caution.
    462      * Likely to be used with information obtained from {@link android.media.MediaCodecList}
    463      * @param name The name of the codec to be instantiated.
    464      * @throws IOException if the codec cannot be created.
    465      * @throws IllegalArgumentException if name is not valid.
    466      * @throws NullPointerException if name is null.
    467      */
    468     public static MediaCodec createByCodecName(String name)
    469             throws IOException {
    470         return new MediaCodec(
    471                 name, false /* nameIsType */, false /* unused */);
    472     }
    473 
    474     private MediaCodec(
    475             String name, boolean nameIsType, boolean encoder) {
    476         Looper looper;
    477         if ((looper = Looper.myLooper()) != null) {
    478             mEventHandler = new EventHandler(this, looper);
    479         } else if ((looper = Looper.getMainLooper()) != null) {
    480             mEventHandler = new EventHandler(this, looper);
    481         } else {
    482             mEventHandler = null;
    483         }
    484         mBufferLock = new Object();
    485 
    486         native_setup(name, nameIsType, encoder);
    487     }
    488 
    489     @Override
    490     protected void finalize() {
    491         native_finalize();
    492     }
    493 
    494     /**
    495      * Returns the codec to its initial (Initialized) state.
    496      *
    497      * Call this if an {@link MediaCodec.CodecException#isRecoverable unrecoverable}
    498      * error has occured to reset the codec to its initial state after creation.
    499      *
    500      * @throws CodecException if an unrecoverable error has occured and the codec
    501      * could not be reset.
    502      * @throws IllegalStateException if in the Uninitialized state.
    503      */
    504     public final void reset() {
    505         freeAllTrackedBuffers(); // free buffers first
    506         native_reset();
    507     }
    508 
    509     private native final void native_reset();
    510 
    511     /**
    512      * Make sure you call this when you're done to free up any opened
    513      * component instance instead of relying on the garbage collector
    514      * to do this for you at some point in the future.
    515      */
    516     public final void release() {
    517         freeAllTrackedBuffers(); // free buffers first
    518         native_release();
    519     }
    520 
    521     private native final void native_release();
    522 
    523     /**
    524      * If this codec is to be used as an encoder, pass this flag.
    525      */
    526     public static final int CONFIGURE_FLAG_ENCODE = 1;
    527 
    528     /**
    529      * Configures a component.
    530      *
    531      * @param format The format of the input data (decoder) or the desired
    532      *               format of the output data (encoder).
    533      * @param surface Specify a surface on which to render the output of this
    534      *                decoder.
    535      * @param crypto  Specify a crypto object to facilitate secure decryption
    536      *                of the media data.
    537      * @param flags   Specify {@link #CONFIGURE_FLAG_ENCODE} to configure the
    538      *                component as an encoder.
    539      * @throws IllegalArgumentException if the surface has been released (or is invalid),
    540      * or the format is unacceptable (e.g. missing a mandatory key),
    541      * or the flags are not set properly
    542      * (e.g. missing {@link #CONFIGURE_FLAG_ENCODE} for an encoder).
    543      * @throws IllegalStateException if not in the Initialized state.
    544      */
    545     public void configure(
    546             MediaFormat format,
    547             Surface surface, MediaCrypto crypto, int flags) {
    548         Map<String, Object> formatMap = format.getMap();
    549 
    550         String[] keys = null;
    551         Object[] values = null;
    552 
    553         if (format != null) {
    554             keys = new String[formatMap.size()];
    555             values = new Object[formatMap.size()];
    556 
    557             int i = 0;
    558             for (Map.Entry<String, Object> entry: formatMap.entrySet()) {
    559                 if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
    560                     int sessionId = 0;
    561                     try {
    562                         sessionId = (Integer)entry.getValue();
    563                     }
    564                     catch (Exception e) {
    565                         throw new IllegalArgumentException("Wrong Session ID Parameter!");
    566                     }
    567                     keys[i] = "audio-hw-sync";
    568                     values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
    569                 } else {
    570                     keys[i] = entry.getKey();
    571                     values[i] = entry.getValue();
    572                 }
    573                 ++i;
    574             }
    575         }
    576 
    577         native_configure(keys, values, surface, crypto, flags);
    578     }
    579 
    580     private native final void native_setCallback(Callback cb);
    581 
    582     private native final void native_configure(
    583             String[] keys, Object[] values,
    584             Surface surface, MediaCrypto crypto, int flags);
    585 
    586     /**
    587      * Requests a Surface to use as the input to an encoder, in place of input buffers.  This
    588      * may only be called after {@link #configure} and before {@link #start}.
    589      * <p>
    590      * The application is responsible for calling release() on the Surface when
    591      * done.
    592      * <p>
    593      * The Surface must be rendered with a hardware-accelerated API, such as OpenGL ES.
    594      * {@link android.view.Surface#lockCanvas(android.graphics.Rect)} may fail or produce
    595      * unexpected results.
    596      * @throws IllegalStateException if not in the Configured state.
    597      */
    598     public native final Surface createInputSurface();
    599 
    600     /**
    601      * After successfully configuring the component, call {@code start}.
    602      * <p>
    603      * Call {@code start} also if the codec is configured in asynchronous mode,
    604      * and it has just been flushed, to resume requesting input buffers.
    605      * @throws IllegalStateException if not in the Configured state
    606      *         or just after {@link #flush} for a codec that is configured
    607      *         in asynchronous mode.
    608      * @throws MediaCodec.CodecException upon codec error. Note that some codec errors
    609      * for start may be attributed to future method calls.
    610      */
    611     public final void start() {
    612         native_start();
    613         synchronized(mBufferLock) {
    614             cacheBuffers(true /* input */);
    615             cacheBuffers(false /* input */);
    616         }
    617     }
    618     private native final void native_start();
    619 
    620     /**
    621      * Finish the decode/encode session, note that the codec instance
    622      * remains active and ready to be {@link #start}ed again.
    623      * To ensure that it is available to other client call {@link #release}
    624      * and don't just rely on garbage collection to eventually do this for you.
    625      * @throws IllegalStateException if in the Uninitialized state.
    626      */
    627     public final void stop() {
    628         native_stop();
    629         freeAllTrackedBuffers();
    630 
    631         if (mEventHandler != null) {
    632             mEventHandler.removeMessages(EVENT_CALLBACK);
    633             mEventHandler.removeMessages(EVENT_SET_CALLBACK);
    634         }
    635     }
    636 
    637     private native final void native_stop();
    638 
    639     /**
    640      * Flush both input and output ports of the component, all indices
    641      * previously returned in calls to {@link #dequeueInputBuffer} and
    642      * {@link #dequeueOutputBuffer} become invalid.
    643      * <p>
    644      * If codec is configured in asynchronous mode, call {@link #start}
    645      * after {@code flush} has returned to resume codec operations. The
    646      * codec will not request input buffers until this has happened.
    647      * <p>
    648      * If codec is configured in synchronous mode, codec will resume
    649      * automatically if an input surface was created.  Otherwise, it
    650      * will resume when {@link #dequeueInputBuffer} is called.
    651      *
    652      * @throws IllegalStateException if not in the Executing state.
    653      * @throws MediaCodec.CodecException upon codec error.
    654      */
    655     public final void flush() {
    656         synchronized(mBufferLock) {
    657             invalidateByteBuffers(mCachedInputBuffers);
    658             invalidateByteBuffers(mCachedOutputBuffers);
    659             mDequeuedInputBuffers.clear();
    660             mDequeuedOutputBuffers.clear();
    661         }
    662         native_flush();
    663     }
    664 
    665     private native final void native_flush();
    666 
    667     /**
    668      * Thrown when an internal codec error occurs.
    669      */
    670     public final static class CodecException extends IllegalStateException {
    671         CodecException(int errorCode, int actionCode, String detailMessage) {
    672             super(detailMessage);
    673             mErrorCode = errorCode;
    674             mActionCode = actionCode;
    675 
    676             // TODO get this from codec
    677             final String sign = errorCode < 0 ? "neg_" : "";
    678             mDiagnosticInfo =
    679                 "android.media.MediaCodec.error_" + sign + Math.abs(errorCode);
    680         }
    681 
    682         /**
    683          * Returns true if the codec exception is a transient issue,
    684          * perhaps due to resource constraints, and that the method
    685          * (or encoding/decoding) may be retried at a later time.
    686          */
    687         public boolean isTransient() {
    688             return mActionCode == ACTION_TRANSIENT;
    689         }
    690 
    691         /**
    692          * Returns true if the codec cannot proceed further,
    693          * but can be recovered by stopping, configuring,
    694          * and starting again.
    695          */
    696         public boolean isRecoverable() {
    697             return mActionCode == ACTION_RECOVERABLE;
    698         }
    699 
    700         /**
    701          * Retrieve the error code associated with a CodecException.
    702          * This is opaque diagnostic information and may depend on
    703          * hardware or API level.
    704          *
    705          * @hide
    706          */
    707         public int getErrorCode() {
    708             return mErrorCode;
    709         }
    710 
    711         /**
    712          * Retrieve a developer-readable diagnostic information string
    713          * associated with the exception. Do not show this to end-users,
    714          * since this string will not be localized or generally
    715          * comprehensible to end-users.
    716          */
    717         public String getDiagnosticInfo() {
    718             return mDiagnosticInfo;
    719         }
    720 
    721         /* Must be in sync with android_media_MediaCodec.cpp */
    722         private final static int ACTION_TRANSIENT = 1;
    723         private final static int ACTION_RECOVERABLE = 2;
    724 
    725         private final String mDiagnosticInfo;
    726         private final int mErrorCode;
    727         private final int mActionCode;
    728     }
    729 
    730     /**
    731      * Thrown when a crypto error occurs while queueing a secure input buffer.
    732      */
    733     public final static class CryptoException extends RuntimeException {
    734         public CryptoException(int errorCode, String detailMessage) {
    735             super(detailMessage);
    736             mErrorCode = errorCode;
    737         }
    738 
    739         /**
    740          * This indicates that no key has been set to perform the requested
    741          * decrypt operation.  The operation can be retried after adding
    742          * a decryption key.
    743          */
    744         public static final int ERROR_NO_KEY = 1;
    745 
    746         /**
    747          * This indicates that the key used for decryption is no longer
    748          * valid due to license term expiration.  The operation can be retried
    749          * after updating the expired keys.
    750          */
    751         public static final int ERROR_KEY_EXPIRED = 2;
    752 
    753         /**
    754          * This indicates that a required crypto resource was not able to be
    755          * allocated while attempting the requested operation.  The operation
    756          * can be retried if the app is able to release resources.
    757          */
    758         public static final int ERROR_RESOURCE_BUSY = 3;
    759 
    760         /**
    761          * This indicates that the output protection levels supported by the
    762          * device are not sufficient to meet the requirements set by the
    763          * content owner in the license policy.
    764          */
    765         public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4;
    766 
    767         /**
    768          * Retrieve the error code associated with a CryptoException
    769          */
    770         public int getErrorCode() {
    771             return mErrorCode;
    772         }
    773 
    774         private int mErrorCode;
    775     }
    776 
    777     /**
    778      * After filling a range of the input buffer at the specified index
    779      * submit it to the component. Once an input buffer is queued to
    780      * the codec, it MUST NOT be used until it is later retrieved by
    781      * {@link #getInputBuffer} in response to a {@link #dequeueInputBuffer}
    782      * return value or a {@link Callback#onInputBufferAvailable}
    783      * callback.
    784      * <p>
    785      * Many decoders require the actual compressed data stream to be
    786      * preceded by "codec specific data", i.e. setup data used to initialize
    787      * the codec such as PPS/SPS in the case of AVC video or code tables
    788      * in the case of vorbis audio.
    789      * The class {@link android.media.MediaExtractor} provides codec
    790      * specific data as part of
    791      * the returned track format in entries named "csd-0", "csd-1" ...
    792      * <p>
    793      * These buffers can be submitted directly after {@link #start} or
    794      * {@link #flush} by specifying the flag {@link
    795      * #BUFFER_FLAG_CODEC_CONFIG}.  However, if you configure the
    796      * codec with a {@link MediaFormat} containing these keys, they
    797      * will be automatically submitted by MediaCodec directly after
    798      * start.  Therefore, the use of {@link
    799      * #BUFFER_FLAG_CODEC_CONFIG} flag is discouraged and is
    800      * recommended only for advanced users.
    801      * <p>
    802      * To indicate that this is the final piece of input data (or rather that
    803      * no more input data follows unless the decoder is subsequently flushed)
    804      * specify the flag {@link #BUFFER_FLAG_END_OF_STREAM}.
    805      *
    806      * @param index The index of a client-owned input buffer previously returned
    807      *              in a call to {@link #dequeueInputBuffer}.
    808      * @param offset The byte offset into the input buffer at which the data starts.
    809      * @param size The number of bytes of valid input data.
    810      * @param presentationTimeUs The presentation timestamp in microseconds for this
    811      *                           buffer. This is normally the media time at which this
    812      *                           buffer should be presented (rendered).
    813      * @param flags A bitmask of flags
    814      *              {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
    815      *              While not prohibited, most codecs do not use the
    816      *              {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
    817      * @throws IllegalStateException if not in the Executing state.
    818      * @throws MediaCodec.CodecException upon codec error.
    819      * @throws CryptoException if a crypto object has been specified in
    820      *         {@link #configure}
    821      */
    822     public final void queueInputBuffer(
    823             int index,
    824             int offset, int size, long presentationTimeUs, int flags)
    825         throws CryptoException {
    826         synchronized(mBufferLock) {
    827             invalidateByteBuffer(mCachedInputBuffers, index);
    828             mDequeuedInputBuffers.remove(index);
    829         }
    830         try {
    831             native_queueInputBuffer(
    832                     index, offset, size, presentationTimeUs, flags);
    833         } catch (CryptoException | IllegalStateException e) {
    834             revalidateByteBuffer(mCachedInputBuffers, index);
    835             throw e;
    836         }
    837     }
    838 
    839     private native final void native_queueInputBuffer(
    840             int index,
    841             int offset, int size, long presentationTimeUs, int flags)
    842         throws CryptoException;
    843 
    844     // The following mode constants MUST stay in sync with their equivalents
    845     // in media/hardware/CryptoAPI.h !
    846     public static final int CRYPTO_MODE_UNENCRYPTED = 0;
    847     public static final int CRYPTO_MODE_AES_CTR     = 1;
    848 
    849     /**
    850      * Metadata describing the structure of a (at least partially) encrypted
    851      * input sample.
    852      * A buffer's data is considered to be partitioned into "subSamples",
    853      * each subSample starts with a (potentially empty) run of plain,
    854      * unencrypted bytes followed by a (also potentially empty) run of
    855      * encrypted bytes.
    856      * numBytesOfClearData can be null to indicate that all data is encrypted.
    857      * This information encapsulates per-sample metadata as outlined in
    858      * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files".
    859      */
    860     public final static class CryptoInfo {
    861         public void set(
    862                 int newNumSubSamples,
    863                 int[] newNumBytesOfClearData,
    864                 int[] newNumBytesOfEncryptedData,
    865                 byte[] newKey,
    866                 byte[] newIV,
    867                 int newMode) {
    868             numSubSamples = newNumSubSamples;
    869             numBytesOfClearData = newNumBytesOfClearData;
    870             numBytesOfEncryptedData = newNumBytesOfEncryptedData;
    871             key = newKey;
    872             iv = newIV;
    873             mode = newMode;
    874         }
    875 
    876         /**
    877          * The number of subSamples that make up the buffer's contents.
    878          */
    879         public int numSubSamples;
    880         /**
    881          * The number of leading unencrypted bytes in each subSample.
    882          */
    883         public int[] numBytesOfClearData;
    884         /**
    885          * The number of trailing encrypted bytes in each subSample.
    886          */
    887         public int[] numBytesOfEncryptedData;
    888         /**
    889          * A 16-byte opaque key
    890          */
    891         public byte[] key;
    892         /**
    893          * A 16-byte initialization vector
    894          */
    895         public byte[] iv;
    896         /**
    897          * The type of encryption that has been applied,
    898          * see {@link #CRYPTO_MODE_UNENCRYPTED} and {@link #CRYPTO_MODE_AES_CTR}.
    899          */
    900         public int mode;
    901 
    902         @Override
    903         public String toString() {
    904             StringBuilder builder = new StringBuilder();
    905             builder.append(numSubSamples + " subsamples, key [");
    906             String hexdigits = "0123456789abcdef";
    907             for (int i = 0; i < key.length; i++) {
    908                 builder.append(hexdigits.charAt((key[i] & 0xf0) >> 4));
    909                 builder.append(hexdigits.charAt(key[i] & 0x0f));
    910             }
    911             builder.append("], iv [");
    912             for (int i = 0; i < key.length; i++) {
    913                 builder.append(hexdigits.charAt((iv[i] & 0xf0) >> 4));
    914                 builder.append(hexdigits.charAt(iv[i] & 0x0f));
    915             }
    916             builder.append("], clear ");
    917             builder.append(Arrays.toString(numBytesOfClearData));
    918             builder.append(", encrypted ");
    919             builder.append(Arrays.toString(numBytesOfEncryptedData));
    920             return builder.toString();
    921         }
    922     };
    923 
    924     /**
    925      * Similar to {@link #queueInputBuffer} but submits a buffer that is
    926      * potentially encrypted.
    927      * @param index The index of a client-owned input buffer previously returned
    928      *              in a call to {@link #dequeueInputBuffer}.
    929      * @param offset The byte offset into the input buffer at which the data starts.
    930      * @param info Metadata required to facilitate decryption, the object can be
    931      *             reused immediately after this call returns.
    932      * @param presentationTimeUs The presentation timestamp in microseconds for this
    933      *                           buffer. This is normally the media time at which this
    934      *                           buffer should be presented (rendered).
    935      * @param flags A bitmask of flags
    936      *              {@link #BUFFER_FLAG_CODEC_CONFIG} and {@link #BUFFER_FLAG_END_OF_STREAM}.
    937      *              While not prohibited, most codecs do not use the
    938      *              {@link #BUFFER_FLAG_KEY_FRAME} flag for input buffers.
    939      * @throws IllegalStateException if not in the Executing state.
    940      * @throws MediaCodec.CodecException upon codec error.
    941      * @throws CryptoException if an error occurs while attempting to decrypt the buffer.
    942      *              An error code associated with the exception helps identify the
    943      *              reason for the failure.
    944      */
    945     public final void queueSecureInputBuffer(
    946             int index,
    947             int offset,
    948             CryptoInfo info,
    949             long presentationTimeUs,
    950             int flags) throws CryptoException {
    951         synchronized(mBufferLock) {
    952             invalidateByteBuffer(mCachedInputBuffers, index);
    953             mDequeuedInputBuffers.remove(index);
    954         }
    955         try {
    956             native_queueSecureInputBuffer(
    957                     index, offset, info, presentationTimeUs, flags);
    958         } catch (CryptoException | IllegalStateException e) {
    959             revalidateByteBuffer(mCachedInputBuffers, index);
    960             throw e;
    961         }
    962     }
    963 
    964     private native final void native_queueSecureInputBuffer(
    965             int index,
    966             int offset,
    967             CryptoInfo info,
    968             long presentationTimeUs,
    969             int flags) throws CryptoException;
    970 
    971     /**
    972      * Returns the index of an input buffer to be filled with valid data
    973      * or -1 if no such buffer is currently available.
    974      * This method will return immediately if timeoutUs == 0, wait indefinitely
    975      * for the availability of an input buffer if timeoutUs &lt; 0 or wait up
    976      * to "timeoutUs" microseconds if timeoutUs &gt; 0.
    977      * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
    978      * @throws IllegalStateException if not in the Executing state,
    979      *         or codec is configured in asynchronous mode.
    980      * @throws MediaCodec.CodecException upon codec error.
    981      */
    982     public final int dequeueInputBuffer(long timeoutUs) {
    983         int res = native_dequeueInputBuffer(timeoutUs);
    984         if (res >= 0) {
    985             synchronized(mBufferLock) {
    986                 validateInputByteBuffer(mCachedInputBuffers, res);
    987             }
    988         }
    989         return res;
    990     }
    991 
    992     private native final int native_dequeueInputBuffer(long timeoutUs);
    993 
    994     /**
    995      * If a non-negative timeout had been specified in the call
    996      * to {@link #dequeueOutputBuffer}, indicates that the call timed out.
    997      */
    998     public static final int INFO_TRY_AGAIN_LATER        = -1;
    999 
   1000     /**
   1001      * The output format has changed, subsequent data will follow the new
   1002      * format. {@link #getOutputFormat()} returns the new format.  Note, that
   1003      * you can also use the new {@link #getOutputFormat(int)} method to
   1004      * get the format for a specific output buffer.  This frees you from
   1005      * having to track output format changes.
   1006      */
   1007     public static final int INFO_OUTPUT_FORMAT_CHANGED  = -2;
   1008 
   1009     /**
   1010      * The output buffers have changed, the client must refer to the new
   1011      * set of output buffers returned by {@link #getOutputBuffers} from
   1012      * this point on.
   1013      *
   1014      * @deprecated This return value can be ignored as {@link
   1015      * #getOutputBuffers} has been deprecated.  Client should
   1016      * request a current buffer using on of the get-buffer or
   1017      * get-image methods each time one has been dequeued.
   1018      */
   1019     public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3;
   1020 
   1021     /**
   1022      * Dequeue an output buffer, block at most "timeoutUs" microseconds.
   1023      * Returns the index of an output buffer that has been successfully
   1024      * decoded or one of the INFO_* constants below.
   1025      * @param info Will be filled with buffer meta data.
   1026      * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
   1027      * @throws IllegalStateException if not in the Executing state,
   1028      *         or codec is configured in asynchronous mode.
   1029      * @throws MediaCodec.CodecException upon codec error.
   1030      */
   1031     public final int dequeueOutputBuffer(
   1032             BufferInfo info, long timeoutUs) {
   1033         int res = native_dequeueOutputBuffer(info, timeoutUs);
   1034         synchronized(mBufferLock) {
   1035             if (res == INFO_OUTPUT_BUFFERS_CHANGED) {
   1036                 cacheBuffers(false /* input */);
   1037             } else if (res >= 0) {
   1038                 validateOutputByteBuffer(mCachedOutputBuffers, res, info);
   1039             }
   1040         }
   1041         return res;
   1042     }
   1043 
   1044     private native final int native_dequeueOutputBuffer(
   1045             BufferInfo info, long timeoutUs);
   1046 
   1047     /**
   1048      * If you are done with a buffer, use this call to return the buffer to
   1049      * the codec. If you previously specified a surface when configuring this
   1050      * video decoder you can optionally render the buffer.
   1051      *
   1052      * Once an output buffer is released to the codec, it MUST NOT
   1053      * be used until it is later retrieved by {@link #getOutputBuffer} in response
   1054      * to a {@link #dequeueOutputBuffer} return value or a
   1055      * {@link Callback#onOutputBufferAvailable} callback.
   1056      *
   1057      * @param index The index of a client-owned output buffer previously returned
   1058      *              from a call to {@link #dequeueOutputBuffer}.
   1059      * @param render If a valid surface was specified when configuring the codec,
   1060      *               passing true renders this output buffer to the surface.
   1061      * @throws IllegalStateException if not in the Executing state.
   1062      * @throws MediaCodec.CodecException upon codec error.
   1063      */
   1064     public final void releaseOutputBuffer(int index, boolean render) {
   1065         synchronized(mBufferLock) {
   1066             invalidateByteBuffer(mCachedOutputBuffers, index);
   1067             mDequeuedOutputBuffers.remove(index);
   1068         }
   1069         releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
   1070     }
   1071 
   1072     /**
   1073      * If you are done with a buffer, use this call to update its surface timestamp
   1074      * and return it to the codec to render it on the output surface. If you
   1075      * have not specified an output surface when configuring this video codec,
   1076      * this call will simply return the buffer to the codec.<p>
   1077      *
   1078      * The timestamp may have special meaning depending on the destination surface.
   1079      *
   1080      * <table>
   1081      * <tr><th>SurfaceView specifics</th></tr>
   1082      * <tr><td>
   1083      * If you render your buffer on a {@link android.view.SurfaceView},
   1084      * you can use the timestamp to render the buffer at a specific time (at the
   1085      * VSYNC at or after the buffer timestamp).  For this to work, the timestamp
   1086      * needs to be <i>reasonably close</i> to the current {@link System#nanoTime}.
   1087      * Currently, this is set as within one (1) second. A few notes:
   1088      *
   1089      * <ul>
   1090      * <li>the buffer will not be returned to the codec until the timestamp
   1091      * has passed and the buffer is no longer used by the {@link android.view.Surface}.
   1092      * <li>buffers are processed sequentially, so you may block subsequent buffers to
   1093      * be displayed on the {@link android.view.Surface}.  This is important if you
   1094      * want to react to user action, e.g. stop the video or seek.
   1095      * <li>if multiple buffers are sent to the {@link android.view.Surface} to be
   1096      * rendered at the same VSYNC, the last one will be shown, and the other ones
   1097      * will be dropped.
   1098      * <li>if the timestamp is <em>not</em> "reasonably close" to the current system
   1099      * time, the {@link android.view.Surface} will ignore the timestamp, and
   1100      * display the buffer at the earliest feasible time.  In this mode it will not
   1101      * drop frames.
   1102      * <li>for best performance and quality, call this method when you are about
   1103      * two VSYNCs' time before the desired render time.  For 60Hz displays, this is
   1104      * about 33 msec.
   1105      * </ul>
   1106      * </td></tr>
   1107      * </table>
   1108      *
   1109      * Once an output buffer is released to the codec, it MUST NOT
   1110      * be used until it is later retrieved by {@link #getOutputBuffer} in response
   1111      * to a {@link #dequeueOutputBuffer} return value or a
   1112      * {@link Callback#onOutputBufferAvailable} callback.
   1113      *
   1114      * @param index The index of a client-owned output buffer previously returned
   1115      *              from a call to {@link #dequeueOutputBuffer}.
   1116      * @param renderTimestampNs The timestamp to associate with this buffer when
   1117      *              it is sent to the Surface.
   1118      * @throws IllegalStateException if not in the Executing state.
   1119      * @throws MediaCodec.CodecException upon codec error.
   1120      */
   1121     public final void releaseOutputBuffer(int index, long renderTimestampNs) {
   1122         synchronized(mBufferLock) {
   1123             invalidateByteBuffer(mCachedOutputBuffers, index);
   1124             mDequeuedOutputBuffers.remove(index);
   1125         }
   1126         releaseOutputBuffer(
   1127                 index, true /* render */, true /* updatePTS */, renderTimestampNs);
   1128     }
   1129 
   1130     private native final void releaseOutputBuffer(
   1131             int index, boolean render, boolean updatePTS, long timeNs);
   1132 
   1133     /**
   1134      * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
   1135      * {@link #BUFFER_FLAG_END_OF_STREAM} set.  This may only be used with
   1136      * encoders receiving input from a Surface created by {@link #createInputSurface}.
   1137      * @throws IllegalStateException if not in the Executing state.
   1138      * @throws MediaCodec.CodecException upon codec error.
   1139      */
   1140     public native final void signalEndOfInputStream();
   1141 
   1142     /**
   1143      * Call this after dequeueOutputBuffer signals a format change by returning
   1144      * {@link #INFO_OUTPUT_FORMAT_CHANGED}.
   1145      * You can also call this after {@link #configure} returns
   1146      * successfully to get the output format initially configured
   1147      * for the codec.  Do this to determine what optional
   1148      * configuration parameters were supported by the codec.
   1149      *
   1150      * @throws IllegalStateException if not in the Executing or
   1151      *                               Configured state.
   1152      * @throws MediaCodec.CodecException upon codec error.
   1153      */
   1154     public final MediaFormat getOutputFormat() {
   1155         return new MediaFormat(getFormatNative(false /* input */));
   1156     }
   1157 
   1158     /**
   1159      * Call this after {@link #configure} returns successfully to
   1160      * get the input format accepted by the codec. Do this to
   1161      * determine what optional configuration parameters were
   1162      * supported by the codec.
   1163      *
   1164      * @throws IllegalStateException if not in the Executing or
   1165      *                               Configured state.
   1166      * @throws MediaCodec.CodecException upon codec error.
   1167      */
   1168     public final MediaFormat getInputFormat() {
   1169         return new MediaFormat(getFormatNative(true /* input */));
   1170     }
   1171 
   1172     /**
   1173      * Returns the output format for a specific output buffer.
   1174      *
   1175      * @param index The index of a client-owned input buffer previously
   1176      *              returned from a call to {@link #dequeueInputBuffer}.
   1177      *
   1178      * @return the format for the output buffer, or null if the index
   1179      * is not a dequeued output buffer.
   1180      */
   1181     public final MediaFormat getOutputFormat(int index) {
   1182         return new MediaFormat(getOutputFormatNative(index));
   1183     }
   1184 
   1185     private native final Map<String, Object> getFormatNative(boolean input);
   1186 
   1187     private native final Map<String, Object> getOutputFormatNative(int index);
   1188 
   1189     // used to track dequeued buffers
   1190     private static class BufferMap {
   1191         // various returned representations of the codec buffer
   1192         private static class CodecBuffer {
   1193             private Image mImage;
   1194             private ByteBuffer mByteBuffer;
   1195 
   1196             public void free() {
   1197                 if (mByteBuffer != null) {
   1198                     // all of our ByteBuffers are direct
   1199                     java.nio.NioUtils.freeDirectBuffer(mByteBuffer);
   1200                     mByteBuffer = null;
   1201                 }
   1202                 if (mImage != null) {
   1203                     mImage.close();
   1204                     mImage = null;
   1205                 }
   1206             }
   1207 
   1208             public void setImage(Image image) {
   1209                 free();
   1210                 mImage = image;
   1211             }
   1212 
   1213             public void setByteBuffer(ByteBuffer buffer) {
   1214                 free();
   1215                 mByteBuffer = buffer;
   1216             }
   1217         }
   1218 
   1219         private final Map<Integer, CodecBuffer> mMap =
   1220             new HashMap<Integer, CodecBuffer>();
   1221 
   1222         public void remove(int index) {
   1223             CodecBuffer buffer = mMap.get(index);
   1224             if (buffer != null) {
   1225                 buffer.free();
   1226                 mMap.remove(index);
   1227             }
   1228         }
   1229 
   1230         public void put(int index, ByteBuffer newBuffer) {
   1231             CodecBuffer buffer = mMap.get(index);
   1232             if (buffer == null) { // likely
   1233                 buffer = new CodecBuffer();
   1234                 mMap.put(index, buffer);
   1235             }
   1236             buffer.setByteBuffer(newBuffer);
   1237         }
   1238 
   1239         public void put(int index, Image newImage) {
   1240             CodecBuffer buffer = mMap.get(index);
   1241             if (buffer == null) { // likely
   1242                 buffer = new CodecBuffer();
   1243                 mMap.put(index, buffer);
   1244             }
   1245             buffer.setImage(newImage);
   1246         }
   1247 
   1248         public void clear() {
   1249             for (CodecBuffer buffer: mMap.values()) {
   1250                 buffer.free();
   1251             }
   1252             mMap.clear();
   1253         }
   1254     }
   1255 
   1256     private ByteBuffer[] mCachedInputBuffers;
   1257     private ByteBuffer[] mCachedOutputBuffers;
   1258     private final BufferMap mDequeuedInputBuffers = new BufferMap();
   1259     private final BufferMap mDequeuedOutputBuffers = new BufferMap();
   1260     final private Object mBufferLock;
   1261 
   1262     private final void invalidateByteBuffer(
   1263             ByteBuffer[] buffers, int index) {
   1264         if (buffers != null && index >= 0 && index < buffers.length) {
   1265             ByteBuffer buffer = buffers[index];
   1266             if (buffer != null) {
   1267                 buffer.setAccessible(false);
   1268             }
   1269         }
   1270     }
   1271 
   1272     private final void validateInputByteBuffer(
   1273             ByteBuffer[] buffers, int index) {
   1274         if (buffers != null && index >= 0 && index < buffers.length) {
   1275             ByteBuffer buffer = buffers[index];
   1276             if (buffer != null) {
   1277                 buffer.setAccessible(true);
   1278                 buffer.clear();
   1279             }
   1280         }
   1281     }
   1282 
   1283     private final void revalidateByteBuffer(
   1284             ByteBuffer[] buffers, int index) {
   1285         synchronized(mBufferLock) {
   1286             if (buffers != null && index >= 0 && index < buffers.length) {
   1287                 ByteBuffer buffer = buffers[index];
   1288                 if (buffer != null) {
   1289                     buffer.setAccessible(true);
   1290                 }
   1291             }
   1292         }
   1293     }
   1294 
   1295     private final void validateOutputByteBuffer(
   1296             ByteBuffer[] buffers, int index, BufferInfo info) {
   1297         if (buffers != null && index >= 0 && index < buffers.length) {
   1298             ByteBuffer buffer = buffers[index];
   1299             if (buffer != null) {
   1300                 buffer.setAccessible(true);
   1301                 buffer.limit(info.offset + info.size).position(info.offset);
   1302             }
   1303         }
   1304     }
   1305 
   1306     private final void invalidateByteBuffers(ByteBuffer[] buffers) {
   1307         if (buffers != null) {
   1308             for (ByteBuffer buffer: buffers) {
   1309                 if (buffer != null) {
   1310                     buffer.setAccessible(false);
   1311                 }
   1312             }
   1313         }
   1314     }
   1315 
   1316     private final void freeByteBuffer(ByteBuffer buffer) {
   1317         if (buffer != null /* && buffer.isDirect() */) {
   1318             // all of our ByteBuffers are direct
   1319             java.nio.NioUtils.freeDirectBuffer(buffer);
   1320         }
   1321     }
   1322 
   1323     private final void freeByteBuffers(ByteBuffer[] buffers) {
   1324         if (buffers != null) {
   1325             for (ByteBuffer buffer: buffers) {
   1326                 freeByteBuffer(buffer);
   1327             }
   1328         }
   1329     }
   1330 
   1331     private final void freeAllTrackedBuffers() {
   1332         synchronized(mBufferLock) {
   1333             freeByteBuffers(mCachedInputBuffers);
   1334             freeByteBuffers(mCachedOutputBuffers);
   1335             mCachedInputBuffers = null;
   1336             mCachedOutputBuffers = null;
   1337             mDequeuedInputBuffers.clear();
   1338             mDequeuedOutputBuffers.clear();
   1339         }
   1340     }
   1341 
   1342     private final void cacheBuffers(boolean input) {
   1343         ByteBuffer[] buffers = null;
   1344         try {
   1345             buffers = getBuffers(input);
   1346             invalidateByteBuffers(buffers);
   1347         } catch (IllegalStateException e) {
   1348             // we don't get buffers in async mode
   1349         }
   1350         if (input) {
   1351             mCachedInputBuffers = buffers;
   1352         } else {
   1353             mCachedOutputBuffers = buffers;
   1354         }
   1355     }
   1356 
   1357     /**
   1358      * Retrieve the set of input buffers.  Call this after start()
   1359      * returns. After calling this method, any ByteBuffers
   1360      * previously returned by an earlier call to this method MUST no
   1361      * longer be used.
   1362      *
   1363      * @deprecated Use the new {@link #getInputBuffer} method instead
   1364      * each time an input buffer is dequeued.
   1365      *
   1366      * <b>Note:</b>As of API 21, dequeued input buffers are
   1367      * automatically {@link java.nio.Buffer#clear cleared}.
   1368      *
   1369      * @throws IllegalStateException if not in the Executing state,
   1370      *         or codec is configured in asynchronous mode.
   1371      * @throws MediaCodec.CodecException upon codec error.
   1372      */
   1373     public ByteBuffer[] getInputBuffers() {
   1374         if (mCachedInputBuffers == null) {
   1375             throw new IllegalStateException();
   1376         }
   1377         // FIXME: check codec status
   1378         return mCachedInputBuffers;
   1379     }
   1380 
   1381     /**
   1382      * Retrieve the set of output buffers.  Call this after start()
   1383      * returns and whenever dequeueOutputBuffer signals an output
   1384      * buffer change by returning {@link
   1385      * #INFO_OUTPUT_BUFFERS_CHANGED}. After calling this method, any
   1386      * ByteBuffers previously returned by an earlier call to this
   1387      * method MUST no longer be used.
   1388      *
   1389      * @deprecated Use the new {@link #getOutputBuffer} method instead
   1390      * each time an output buffer is dequeued.  This method is not
   1391      * supported if codec is configured in asynchronous mode.
   1392      *
   1393      * <b>Note:</b>As of API 21, the position and limit of output
   1394      * buffers that are dequeued will be set to the valid data
   1395      * range.
   1396      *
   1397      * @throws IllegalStateException if not in the Executing state,
   1398      *         or codec is configured in asynchronous mode.
   1399      * @throws MediaCodec.CodecException upon codec error.
   1400      */
   1401     public ByteBuffer[] getOutputBuffers() {
   1402         if (mCachedOutputBuffers == null) {
   1403             throw new IllegalStateException();
   1404         }
   1405         // FIXME: check codec status
   1406         return mCachedOutputBuffers;
   1407     }
   1408 
   1409     /**
   1410      * Returns a {@link java.nio.Buffer#clear cleared}, writable ByteBuffer
   1411      * object for a dequeued input buffer index to contain the input data.
   1412      *
   1413      * After calling this method any ByteBuffer or Image object
   1414      * previously returned for the same input index MUST no longer
   1415      * be used.
   1416      *
   1417      * @param index The index of a client-owned input buffer previously
   1418      *              returned from a call to {@link #dequeueInputBuffer},
   1419      *              or received via an onInputBufferAvailable callback.
   1420      *
   1421      * @return the input buffer, or null if the index is not a dequeued
   1422      * input buffer, or if the codec is configured for surface input.
   1423      *
   1424      * @throws IllegalStateException if not in the Executing state.
   1425      * @throws MediaCodec.CodecException upon codec error.
   1426      */
   1427     public ByteBuffer getInputBuffer(int index) {
   1428         ByteBuffer newBuffer = getBuffer(true /* input */, index);
   1429         synchronized(mBufferLock) {
   1430             invalidateByteBuffer(mCachedInputBuffers, index);
   1431             mDequeuedInputBuffers.put(index, newBuffer);
   1432         }
   1433         return newBuffer;
   1434     }
   1435 
   1436     /**
   1437      * Returns a writable Image object for a dequeued input buffer
   1438      * index to contain the raw input video frame.
   1439      *
   1440      * After calling this method any ByteBuffer or Image object
   1441      * previously returned for the same input index MUST no longer
   1442      * be used.
   1443      *
   1444      * @param index The index of a client-owned input buffer previously
   1445      *              returned from a call to {@link #dequeueInputBuffer},
   1446      *              or received via an onInputBufferAvailable callback.
   1447      *
   1448      * @return the input image, or null if the index is not a
   1449      * dequeued input buffer, or not a ByteBuffer that contains a
   1450      * raw image.
   1451      *
   1452      * @throws IllegalStateException if not in the Executing state.
   1453      * @throws MediaCodec.CodecException upon codec error.
   1454      */
   1455     public Image getInputImage(int index) {
   1456         Image newImage = getImage(true /* input */, index);
   1457         synchronized(mBufferLock) {
   1458             invalidateByteBuffer(mCachedInputBuffers, index);
   1459             mDequeuedInputBuffers.put(index, newImage);
   1460         }
   1461         return newImage;
   1462     }
   1463 
   1464     /**
   1465      * Returns a read-only ByteBuffer for a dequeued output buffer
   1466      * index. The position and limit of the returned buffer are set
   1467      * to the valid output data.
   1468      *
   1469      * After calling this method, any ByteBuffer or Image object
   1470      * previously returned for the same output index MUST no longer
   1471      * be used.
   1472      *
   1473      * @param index The index of a client-owned output buffer previously
   1474      *              returned from a call to {@link #dequeueOutputBuffer},
   1475      *              or received via an onOutputBufferAvailable callback.
   1476      *
   1477      * @return the output buffer, or null if the index is not a dequeued
   1478      * output buffer, or the codec is configured with an output surface.
   1479      *
   1480      * @throws IllegalStateException if not in the Executing state.
   1481      * @throws MediaCodec.CodecException upon codec error.
   1482      */
   1483     public ByteBuffer getOutputBuffer(int index) {
   1484         ByteBuffer newBuffer = getBuffer(false /* input */, index);
   1485         synchronized(mBufferLock) {
   1486             invalidateByteBuffer(mCachedOutputBuffers, index);
   1487             mDequeuedOutputBuffers.put(index, newBuffer);
   1488         }
   1489         return newBuffer;
   1490     }
   1491 
   1492     /**
   1493      * Returns a read-only Image object for a dequeued output buffer
   1494      * index that contains the raw video frame.
   1495      *
   1496      * After calling this method, any ByteBuffer or Image object previously
   1497      * returned for the same output index MUST no longer be used.
   1498      *
   1499      * @param index The index of a client-owned output buffer previously
   1500      *              returned from a call to {@link #dequeueOutputBuffer},
   1501      *              or received via an onOutputBufferAvailable callback.
   1502      *
   1503      * @return the output image, or null if the index is not a
   1504      * dequeued output buffer, not a raw video frame, or if the codec
   1505      * was configured with an output surface.
   1506      *
   1507      * @throws IllegalStateException if not in the Executing state.
   1508      * @throws MediaCodec.CodecException upon codec error.
   1509      */
   1510     public Image getOutputImage(int index) {
   1511         Image newImage = getImage(false /* input */, index);
   1512         synchronized(mBufferLock) {
   1513             invalidateByteBuffer(mCachedOutputBuffers, index);
   1514             mDequeuedOutputBuffers.put(index, newImage);
   1515         }
   1516         return newImage;
   1517     }
   1518 
   1519     /**
   1520      * The content is scaled to the surface dimensions
   1521      */
   1522     public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT               = 1;
   1523 
   1524     /**
   1525      * The content is scaled, maintaining its aspect ratio, the whole
   1526      * surface area is used, content may be cropped
   1527      */
   1528     public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2;
   1529 
   1530     /**
   1531      * If a surface has been specified in a previous call to {@link #configure}
   1532      * specifies the scaling mode to use. The default is "scale to fit".
   1533      * @throws IllegalArgumentException if mode is not recognized.
   1534      * @throws IllegalStateException if in the Uninitialized state.
   1535      */
   1536     public native final void setVideoScalingMode(int mode);
   1537 
   1538     /**
   1539      * Get the component name. If the codec was created by createDecoderByType
   1540      * or createEncoderByType, what component is chosen is not known beforehand.
   1541      * @throws IllegalStateException if in the Uninitialized state.
   1542      */
   1543     public native final String getName();
   1544 
   1545     /**
   1546      * Change a video encoder's target bitrate on the fly. The value is an
   1547      * Integer object containing the new bitrate in bps.
   1548      */
   1549     public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
   1550 
   1551     /**
   1552      * Temporarily suspend/resume encoding of input data. While suspended
   1553      * input data is effectively discarded instead of being fed into the
   1554      * encoder. This parameter really only makes sense to use with an encoder
   1555      * in "surface-input" mode, as the client code has no control over the
   1556      * input-side of the encoder in that case.
   1557      * The value is an Integer object containing the value 1 to suspend
   1558      * or the value 0 to resume.
   1559      */
   1560     public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
   1561 
   1562     /**
   1563      * Request that the encoder produce a sync frame "soon".
   1564      * Provide an Integer with the value 0.
   1565      */
   1566     public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
   1567 
   1568     /**
   1569      * Communicate additional parameter changes to the component instance.
   1570      * @throws IllegalStateException if in the Uninitialized state.
   1571      */
   1572     public final void setParameters(Bundle params) {
   1573         if (params == null) {
   1574             return;
   1575         }
   1576 
   1577         String[] keys = new String[params.size()];
   1578         Object[] values = new Object[params.size()];
   1579 
   1580         int i = 0;
   1581         for (final String key: params.keySet()) {
   1582             keys[i] = key;
   1583             values[i] = params.get(key);
   1584             ++i;
   1585         }
   1586 
   1587         setParameters(keys, values);
   1588     }
   1589 
   1590     /**
   1591      * Sets an asynchronous callback for actionable MediaCodec events.
   1592      *
   1593      * If the client intends to use the component in asynchronous mode,
   1594      * a valid callback should be provided before {@link #configure} is called.
   1595      *
   1596      * When asynchronous callback is enabled, the client should not call
   1597      * {@link #getInputBuffers}, {@link #getOutputBuffers},
   1598      * {@link #dequeueInputBuffer(long)} or {@link #dequeueOutputBuffer(BufferInfo, long)}.
   1599      * <p>
   1600      * Also, {@link #flush} behaves differently in asynchronous mode.  After calling
   1601      * {@code flush}, you must call {@link #start} to "resume" receiving input buffers,
   1602      * even if an input surface was created.
   1603      *
   1604      * @param cb The callback that will run.
   1605      */
   1606     public void setCallback(/* MediaCodec. */ Callback cb) {
   1607         if (mEventHandler != null) {
   1608             // set java callback on handler
   1609             Message msg = mEventHandler.obtainMessage(EVENT_SET_CALLBACK, 0, 0, cb);
   1610             mEventHandler.sendMessage(msg);
   1611 
   1612             // set native handler here, don't post to handler because
   1613             // it may cause the callback to be delayed and set in a wrong state,
   1614             // and MediaCodec is already doing it on looper.
   1615             native_setCallback(cb);
   1616         }
   1617     }
   1618 
   1619     /**
   1620      * MediaCodec callback interface. Used to notify the user asynchronously
   1621      * of various MediaCodec events.
   1622      */
   1623     public static abstract class Callback {
   1624         /**
   1625          * Called when an input buffer becomes available.
   1626          *
   1627          * @param codec The MediaCodec object.
   1628          * @param index The index of the available input buffer.
   1629          */
   1630         public abstract void onInputBufferAvailable(MediaCodec codec, int index);
   1631 
   1632         /**
   1633          * Called when an output buffer becomes available.
   1634          *
   1635          * @param codec The MediaCodec object.
   1636          * @param index The index of the available output buffer.
   1637          * @param info Info regarding the available output buffer {@link MediaCodec.BufferInfo}.
   1638          */
   1639         public abstract void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info);
   1640 
   1641         /**
   1642          * Called when the MediaCodec encountered an error
   1643          *
   1644          * @param codec The MediaCodec object.
   1645          * @param e The {@link MediaCodec.CodecException} object describing the error.
   1646          */
   1647         public abstract void onError(MediaCodec codec, CodecException e);
   1648 
   1649         /**
   1650          * Called when the output format has changed
   1651          *
   1652          * @param codec The MediaCodec object.
   1653          * @param format The new output format.
   1654          */
   1655         public abstract void onOutputFormatChanged(MediaCodec codec, MediaFormat format);
   1656     }
   1657 
   1658     private void postEventFromNative(
   1659             int what, int arg1, int arg2, Object obj) {
   1660         if (mEventHandler != null) {
   1661             Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj);
   1662             mEventHandler.sendMessage(msg);
   1663         }
   1664     }
   1665 
   1666     private native final void setParameters(String[] keys, Object[] values);
   1667 
   1668     /**
   1669      * Get the codec info. If the codec was created by createDecoderByType
   1670      * or createEncoderByType, what component is chosen is not known beforehand,
   1671      * and thus the caller does not have the MediaCodecInfo.
   1672      * @throws IllegalStateException if in the Uninitialized state.
   1673      */
   1674     public MediaCodecInfo getCodecInfo() {
   1675         return MediaCodecList.getInfoFor(getName());
   1676     }
   1677 
   1678     private native final ByteBuffer[] getBuffers(boolean input);
   1679 
   1680     private native final ByteBuffer getBuffer(boolean input, int index);
   1681 
   1682     private native final Image getImage(boolean input, int index);
   1683 
   1684     private static native final void native_init();
   1685 
   1686     private native final void native_setup(
   1687             String name, boolean nameIsType, boolean encoder);
   1688 
   1689     private native final void native_finalize();
   1690 
   1691     static {
   1692         System.loadLibrary("media_jni");
   1693         native_init();
   1694     }
   1695 
   1696     private long mNativeContext;
   1697 
   1698     /** @hide */
   1699     public static class MediaImage extends Image {
   1700         private final boolean mIsReadOnly;
   1701         private boolean mIsValid;
   1702         private final int mWidth;
   1703         private final int mHeight;
   1704         private final int mFormat;
   1705         private long mTimestamp;
   1706         private final Plane[] mPlanes;
   1707         private final ByteBuffer mBuffer;
   1708         private final ByteBuffer mInfo;
   1709         private final int mXOffset;
   1710         private final int mYOffset;
   1711 
   1712         private final static int TYPE_YUV = 1;
   1713 
   1714         public int getFormat() {
   1715             checkValid();
   1716             return mFormat;
   1717         }
   1718 
   1719         public int getHeight() {
   1720             checkValid();
   1721             return mHeight;
   1722         }
   1723 
   1724         public int getWidth() {
   1725             checkValid();
   1726             return mWidth;
   1727         }
   1728 
   1729         public long getTimestamp() {
   1730             checkValid();
   1731             return mTimestamp;
   1732         }
   1733 
   1734         public Plane[] getPlanes() {
   1735             checkValid();
   1736             return Arrays.copyOf(mPlanes, mPlanes.length);
   1737         }
   1738 
   1739         public void close() {
   1740             if (mIsValid) {
   1741                 java.nio.NioUtils.freeDirectBuffer(mBuffer);
   1742                 mIsValid = false;
   1743             }
   1744         }
   1745 
   1746         /**
   1747          * Set the crop rectangle associated with this frame.
   1748          * <p>
   1749          * The crop rectangle specifies the region of valid pixels in the image,
   1750          * using coordinates in the largest-resolution plane.
   1751          */
   1752         public void setCropRect(Rect cropRect) {
   1753             if (mIsReadOnly) {
   1754                 throw new ReadOnlyBufferException();
   1755             }
   1756             super.setCropRect(cropRect);
   1757         }
   1758 
   1759         private void checkValid() {
   1760             if (!mIsValid) {
   1761                 throw new IllegalStateException("Image is already released");
   1762             }
   1763         }
   1764 
   1765         private int readInt(ByteBuffer buffer, boolean asLong) {
   1766             if (asLong) {
   1767                 return (int)buffer.getLong();
   1768             } else {
   1769                 return buffer.getInt();
   1770             }
   1771         }
   1772 
   1773         public MediaImage(
   1774                 ByteBuffer buffer, ByteBuffer info, boolean readOnly,
   1775                 long timestamp, int xOffset, int yOffset, Rect cropRect) {
   1776             mFormat = ImageFormat.YUV_420_888;
   1777             mTimestamp = timestamp;
   1778             mIsValid = true;
   1779             mIsReadOnly = buffer.isReadOnly();
   1780             mBuffer = buffer.duplicate();
   1781 
   1782             // save offsets and info
   1783             mXOffset = xOffset;
   1784             mYOffset = yOffset;
   1785             mInfo = info;
   1786 
   1787             // read media-info.  the size of media info can be 80 or 156/160 depending on
   1788             // whether it was created on a 32- or 64-bit process.  See MediaImage
   1789             if (info.remaining() == 80 || info.remaining() == 156 || info.remaining() == 160) {
   1790                 boolean sizeIsLong = info.remaining() != 80;
   1791                 int type = readInt(info, info.remaining() == 160);
   1792                 if (type != TYPE_YUV) {
   1793                     throw new UnsupportedOperationException("unsupported type: " + type);
   1794                 }
   1795                 int numPlanes = readInt(info, sizeIsLong);
   1796                 if (numPlanes != 3) {
   1797                     throw new RuntimeException("unexpected number of planes: " + numPlanes);
   1798                 }
   1799                 mWidth = readInt(info, sizeIsLong);
   1800                 mHeight = readInt(info, sizeIsLong);
   1801                 if (mWidth < 1 || mHeight < 1) {
   1802                     throw new UnsupportedOperationException(
   1803                             "unsupported size: " + mWidth + "x" + mHeight);
   1804                 }
   1805                 int bitDepth = readInt(info, sizeIsLong);
   1806                 if (bitDepth != 8) {
   1807                     throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
   1808                 }
   1809                 mPlanes = new MediaPlane[numPlanes];
   1810                 for (int ix = 0; ix < numPlanes; ix++) {
   1811                     int planeOffset = readInt(info, sizeIsLong);
   1812                     int colInc = readInt(info, sizeIsLong);
   1813                     int rowInc = readInt(info, sizeIsLong);
   1814                     int horiz = readInt(info, sizeIsLong);
   1815                     int vert = readInt(info, sizeIsLong);
   1816                     if (horiz != vert || horiz != (ix == 0 ? 1 : 2)) {
   1817                         throw new UnsupportedOperationException("unexpected subsampling: "
   1818                                 + horiz + "x" + vert + " on plane " + ix);
   1819                     }
   1820 
   1821                     buffer.clear();
   1822                     buffer.position(mBuffer.position() + planeOffset
   1823                             + (xOffset / horiz) * colInc + (yOffset / vert) * rowInc);
   1824                     buffer.limit(buffer.position() + Utils.divUp(bitDepth, 8)
   1825                             + (mHeight / vert - 1) * rowInc + (mWidth / horiz - 1) * colInc);
   1826                     mPlanes[ix] = new MediaPlane(buffer.slice(), rowInc, colInc);
   1827                 }
   1828             } else {
   1829                 throw new UnsupportedOperationException(
   1830                         "unsupported info length: " + info.remaining());
   1831             }
   1832 
   1833             if (cropRect == null) {
   1834                 cropRect = new Rect(0, 0, mWidth, mHeight);
   1835             }
   1836             cropRect.offset(-xOffset, -yOffset);
   1837             super.setCropRect(cropRect);
   1838         }
   1839 
   1840         private class MediaPlane extends Plane {
   1841             public MediaPlane(ByteBuffer buffer, int rowInc, int colInc) {
   1842                 mData = buffer;
   1843                 mRowInc = rowInc;
   1844                 mColInc = colInc;
   1845             }
   1846 
   1847             @Override
   1848             public int getRowStride() {
   1849                 checkValid();
   1850                 return mRowInc;
   1851             }
   1852 
   1853             @Override
   1854             public int getPixelStride() {
   1855                 checkValid();
   1856                 return mColInc;
   1857             }
   1858 
   1859             @Override
   1860             public ByteBuffer getBuffer() {
   1861                 checkValid();
   1862                 return mData;
   1863             }
   1864 
   1865             private final int mRowInc;
   1866             private final int mColInc;
   1867             private final ByteBuffer mData;
   1868         }
   1869     }
   1870 }
   1871