Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 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 | |
Martin Storsjo | 93077a2 | 2012-09-25 11:55:25 +0300 | [diff] [blame] | 19 | import android.media.MediaCodecInfo; |
| 20 | import android.media.MediaCodecList; |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 21 | import android.media.MediaCrypto; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 22 | import android.media.MediaFormat; |
Lajos Molnar | 8a39021 | 2013-09-17 18:58:14 -0700 | [diff] [blame] | 23 | import android.os.Bundle; |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 24 | import android.os.Handler; |
| 25 | import android.os.Looper; |
| 26 | import android.os.Message; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 27 | import android.view.Surface; |
Lajos Molnar | 8a39021 | 2013-09-17 18:58:14 -0700 | [diff] [blame] | 28 | |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 29 | import java.io.IOException; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 30 | import java.nio.ByteBuffer; |
Marco Nelissen | e20a6d5 | 2013-04-08 14:28:55 -0700 | [diff] [blame] | 31 | import java.util.Arrays; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 32 | import java.util.Map; |
| 33 | |
| 34 | /** |
| 35 | * MediaCodec class can be used to access low-level media codec, i.e. |
| 36 | * encoder/decoder components. |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 37 | * |
| 38 | * <p>MediaCodec is generally used like this: |
| 39 | * <pre> |
| 40 | * MediaCodec codec = MediaCodec.createDecoderByType(type); |
| 41 | * codec.configure(format, ...); |
| 42 | * codec.start(); |
| 43 | * ByteBuffer[] inputBuffers = codec.getInputBuffers(); |
| 44 | * ByteBuffer[] outputBuffers = codec.getOutputBuffers(); |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 45 | * for (;;) { |
| 46 | * int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs); |
| 47 | * if (inputBufferIndex >= 0) { |
| 48 | * // fill inputBuffers[inputBufferIndex] with valid data |
| 49 | * ... |
| 50 | * codec.queueInputBuffer(inputBufferIndex, ...); |
| 51 | * } |
| 52 | * |
| 53 | * int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs); |
| 54 | * if (outputBufferIndex >= 0) { |
| 55 | * // outputBuffer is ready to be processed or rendered. |
| 56 | * ... |
| 57 | * codec.releaseOutputBuffer(outputBufferIndex, ...); |
| 58 | * } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { |
| 59 | * outputBuffers = codec.getOutputBuffers(); |
| 60 | * } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
| 61 | * // Subsequent data will conform to new format. |
Martin Storsjo | b529e4c | 2012-07-13 12:57:13 +0300 | [diff] [blame] | 62 | * MediaFormat format = codec.getOutputFormat(); |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 63 | * ... |
| 64 | * } |
| 65 | * } |
| 66 | * codec.stop(); |
| 67 | * codec.release(); |
| 68 | * codec = null; |
| 69 | * </pre> |
| 70 | * |
| 71 | * Each codec maintains a number of input and output buffers that are |
| 72 | * referred to by index in API calls. |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 73 | * The contents of these buffers are represented by the ByteBuffer[] arrays |
| 74 | * accessible through {@link #getInputBuffers} and {@link #getOutputBuffers}. |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 75 | * |
| 76 | * After a successful call to {@link #start} the client "owns" neither |
| 77 | * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer} |
| 78 | * and {@link #dequeueOutputBuffer} then transfer ownership from the codec |
| 79 | * to the client.<p> |
| 80 | * The client is not required to resubmit/release buffers immediately |
| 81 | * to the codec, the sample code above simply does this for simplicity's sake.<p> |
| 82 | * Once the client has an input buffer available it can fill it with data |
| 83 | * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p> |
| 84 | * The codec in turn will return an output buffer to the client in response |
| 85 | * to {@link #dequeueOutputBuffer}. After the output buffer has been processed |
| 86 | * a call to {@link #releaseOutputBuffer} will return it to the codec. |
| 87 | * If a video surface has been provided in the call to {@link #configure}, |
| 88 | * {@link #releaseOutputBuffer} optionally allows rendering of the buffer |
| 89 | * to the surface.<p> |
| 90 | * |
| 91 | * Input buffers (for decoders) and Output buffers (for encoders) contain |
| 92 | * encoded data according to the format's type. For video types this data |
| 93 | * is all the encoded data representing a single moment in time, for audio |
| 94 | * data this is slightly relaxed in that a buffer may contain multiple |
| 95 | * encoded frames of audio. In either case, buffers do not start and end on |
| 96 | * arbitrary byte boundaries, this is not a stream of bytes, it's a stream |
| 97 | * of access units.<p> |
| 98 | * |
| 99 | * Most formats also require the actual data to be prefixed by a number |
| 100 | * of buffers containing setup data, or codec specific data, i.e. the |
| 101 | * first few buffers submitted to the codec object after starting it must |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 102 | * be codec specific data marked as such using the flag {@link #BUFFER_FLAG_CODEC_CONFIG} |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 103 | * in a call to {@link #queueInputBuffer}. |
| 104 | * |
Andreas Huber | 8aa735f | 2012-05-08 11:33:12 -0700 | [diff] [blame] | 105 | * Codec specific data included in the format passed to {@link #configure} |
| 106 | * (in ByteBuffer entries with keys "csd-0", "csd-1", ...) is automatically |
| 107 | * submitted to the codec, this data MUST NOT be submitted explicitly by the |
| 108 | * client. |
| 109 | * |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 110 | * Once the client reaches the end of the input data it signals the end of |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 111 | * the input stream by specifying a flag of {@link #BUFFER_FLAG_END_OF_STREAM} in the call to |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 112 | * {@link #queueInputBuffer}. The codec will continue to return output buffers |
| 113 | * until it eventually signals the end of the output stream by specifying |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 114 | * the same flag ({@link #BUFFER_FLAG_END_OF_STREAM}) on the BufferInfo returned in |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 115 | * {@link #dequeueOutputBuffer}. |
| 116 | * |
| 117 | * In order to start decoding data that's not adjacent to previously submitted |
| 118 | * data (i.e. after a seek) it is necessary to {@link #flush} the decoder. |
| 119 | * Any input or output buffers the client may own at the point of the flush are |
| 120 | * immediately revoked, i.e. after a call to {@link #flush} the client does not |
| 121 | * own any buffers anymore. |
| 122 | * Note that the format of the data submitted after a flush must not change, |
| 123 | * flush does not support format discontinuities, |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 124 | * for this a full {@link #stop}, {@link #configure}, {@link #start} |
| 125 | * cycle is necessary. |
| 126 | * |
| 127 | * <p> The factory methods |
| 128 | * {@link #createByCodecName}, |
| 129 | * {@link #createDecoderByType}, |
| 130 | * and {@link #createEncoderByType} |
| 131 | * throw {@link java.io.IOException} on failure which |
| 132 | * the caller must catch or declare to pass up. |
| 133 | * Other methods will throw {@link java.lang.IllegalStateException} |
| 134 | * if the codec is in an Uninitialized, Invalid, or Error state (e.g. not |
| 135 | * initialized properly). Exceptions are thrown elsewhere as noted. </p> |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 136 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 137 | */ |
Andreas Huber | 8240d92 | 2012-04-04 14:06:32 -0700 | [diff] [blame] | 138 | final public class MediaCodec { |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 139 | /** |
| 140 | * Per buffer metadata includes an offset and size specifying |
| 141 | * the range of valid data in the associated codec buffer. |
| 142 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 143 | public final static class BufferInfo { |
| 144 | public void set( |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 145 | int newOffset, int newSize, long newTimeUs, int newFlags) { |
| 146 | offset = newOffset; |
| 147 | size = newSize; |
| 148 | presentationTimeUs = newTimeUs; |
| 149 | flags = newFlags; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 150 | } |
| 151 | |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 152 | public int offset; |
| 153 | public int size; |
| 154 | public long presentationTimeUs; |
| 155 | public int flags; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 156 | }; |
| 157 | |
Andreas Huber | 9e6bcce | 2012-04-06 12:14:47 -0700 | [diff] [blame] | 158 | // The follow flag constants MUST stay in sync with their equivalents |
| 159 | // in MediaCodec.h ! |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 160 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 161 | /** |
| 162 | * This indicates that the buffer marked as such contains the data |
| 163 | * for a sync frame. |
| 164 | */ |
| 165 | public static final int BUFFER_FLAG_SYNC_FRAME = 1; |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 166 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 167 | /** |
| 168 | * This indicated that the buffer marked as such contains codec |
| 169 | * initialization / codec specific data instead of media data. |
| 170 | */ |
| 171 | public static final int BUFFER_FLAG_CODEC_CONFIG = 2; |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 172 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 173 | /** |
| 174 | * This signals the end of stream, i.e. no buffers will be available |
| 175 | * after this, unless of course, {@link #flush} follows. |
| 176 | */ |
| 177 | public static final int BUFFER_FLAG_END_OF_STREAM = 4; |
Andreas Huber | 9e6bcce | 2012-04-06 12:14:47 -0700 | [diff] [blame] | 178 | |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 179 | private EventHandler mEventHandler; |
Andreas Huber | 329eec5 | 2014-01-27 16:30:09 -0800 | [diff] [blame] | 180 | private volatile NotificationCallback mNotificationCallback; |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 181 | |
| 182 | static final int EVENT_NOTIFY = 1; |
| 183 | |
| 184 | private class EventHandler extends Handler { |
| 185 | private MediaCodec mCodec; |
| 186 | |
| 187 | public EventHandler(MediaCodec codec, Looper looper) { |
| 188 | super(looper); |
| 189 | mCodec = codec; |
| 190 | } |
| 191 | |
| 192 | @Override |
| 193 | public void handleMessage(Message msg) { |
| 194 | switch (msg.what) { |
| 195 | case EVENT_NOTIFY: |
| 196 | { |
Andreas Huber | 329eec5 | 2014-01-27 16:30:09 -0800 | [diff] [blame] | 197 | NotificationCallback cb = mNotificationCallback; |
| 198 | if (cb != null) { |
| 199 | cb.onCodecNotify(mCodec); |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 200 | } |
| 201 | break; |
| 202 | } |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 207 | /** |
| 208 | * Instantiate a decoder supporting input data of the given mime type. |
Andreas Huber | 68b1a6e | 2012-06-25 13:53:43 -0700 | [diff] [blame] | 209 | * |
| 210 | * The following is a partial list of defined mime types and their semantics: |
| 211 | * <ul> |
hkuang | 63a6473 | 2013-06-25 17:26:54 -0700 | [diff] [blame] | 212 | * <li>"video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm) |
| 213 | * <li>"video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm) |
Andreas Huber | 68b1a6e | 2012-06-25 13:53:43 -0700 | [diff] [blame] | 214 | * <li>"video/avc" - H.264/AVC video |
| 215 | * <li>"video/mp4v-es" - MPEG4 video |
| 216 | * <li>"video/3gpp" - H.263 video |
| 217 | * <li>"audio/3gpp" - AMR narrowband audio |
| 218 | * <li>"audio/amr-wb" - AMR wideband audio |
| 219 | * <li>"audio/mpeg" - MPEG1/2 audio layer III |
Martin Storsjo | d2aaff5 | 2013-02-26 14:03:47 +0200 | [diff] [blame] | 220 | * <li>"audio/mp4a-latm" - AAC audio (note, this is raw AAC packets, not packaged in LATM!) |
Andreas Huber | 68b1a6e | 2012-06-25 13:53:43 -0700 | [diff] [blame] | 221 | * <li>"audio/vorbis" - vorbis audio |
| 222 | * <li>"audio/g711-alaw" - G.711 alaw audio |
| 223 | * <li>"audio/g711-mlaw" - G.711 ulaw audio |
| 224 | * </ul> |
| 225 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 226 | * @param type The mime type of the input data. |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 227 | * @throws IOException if the codec cannot be created. |
| 228 | * @throws IllegalArgumentException if type is null. |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 229 | */ |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 230 | public static MediaCodec createDecoderByType(String type) |
| 231 | throws IOException { |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 232 | return new MediaCodec(type, true /* nameIsType */, false /* encoder */); |
| 233 | } |
| 234 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 235 | /** |
| 236 | * Instantiate an encoder supporting output data of the given mime type. |
| 237 | * @param type The desired mime type of the output data. |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 238 | * @throws IOException if the codec cannot be created. |
| 239 | * @throws IllegalArgumentException if type is null. |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 240 | */ |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 241 | public static MediaCodec createEncoderByType(String type) |
| 242 | throws IOException { |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 243 | return new MediaCodec(type, true /* nameIsType */, true /* encoder */); |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 244 | } |
| 245 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 246 | /** |
| 247 | * If you know the exact name of the component you want to instantiate |
| 248 | * use this method to instantiate it. Use with caution. |
| 249 | * Likely to be used with information obtained from {@link android.media.MediaCodecList} |
| 250 | * @param name The name of the codec to be instantiated. |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 251 | * @throws IOException if the codec cannot be created. |
| 252 | * @throws IllegalArgumentException if name is null. |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 253 | */ |
Andy Hung | 83511d2 | 2014-01-16 10:10:38 -0800 | [diff] [blame] | 254 | public static MediaCodec createByCodecName(String name) |
| 255 | throws IOException { |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 256 | return new MediaCodec( |
| 257 | name, false /* nameIsType */, false /* unused */); |
| 258 | } |
| 259 | |
| 260 | private MediaCodec( |
| 261 | String name, boolean nameIsType, boolean encoder) { |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 262 | Looper looper; |
| 263 | if ((looper = Looper.myLooper()) != null) { |
| 264 | mEventHandler = new EventHandler(this, looper); |
| 265 | } else if ((looper = Looper.getMainLooper()) != null) { |
| 266 | mEventHandler = new EventHandler(this, looper); |
| 267 | } else { |
| 268 | mEventHandler = null; |
| 269 | } |
| 270 | |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 271 | native_setup(name, nameIsType, encoder); |
| 272 | } |
| 273 | |
| 274 | @Override |
| 275 | protected void finalize() { |
| 276 | native_finalize(); |
| 277 | } |
| 278 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 279 | /** |
| 280 | * Make sure you call this when you're done to free up any opened |
| 281 | * component instance instead of relying on the garbage collector |
| 282 | * to do this for you at some point in the future. |
| 283 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 284 | public native final void release(); |
| 285 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 286 | /** |
| 287 | * If this codec is to be used as an encoder, pass this flag. |
| 288 | */ |
| 289 | public static final int CONFIGURE_FLAG_ENCODE = 1; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 290 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 291 | /** |
| 292 | * Configures a component. |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 293 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 294 | * @param format The format of the input data (decoder) or the desired |
| 295 | * format of the output data (encoder). |
| 296 | * @param surface Specify a surface on which to render the output of this |
| 297 | * decoder. |
| 298 | * @param crypto Specify a crypto object to facilitate secure decryption |
| 299 | * of the media data. |
| 300 | * @param flags Specify {@link #CONFIGURE_FLAG_ENCODE} to configure the |
| 301 | * component as an encoder. |
| 302 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 303 | public void configure( |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 304 | MediaFormat format, |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 305 | Surface surface, MediaCrypto crypto, int flags) { |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 306 | Map<String, Object> formatMap = format.getMap(); |
| 307 | |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 308 | String[] keys = null; |
| 309 | Object[] values = null; |
| 310 | |
| 311 | if (format != null) { |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 312 | keys = new String[formatMap.size()]; |
| 313 | values = new Object[formatMap.size()]; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 314 | |
| 315 | int i = 0; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 316 | for (Map.Entry<String, Object> entry: formatMap.entrySet()) { |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 317 | keys[i] = entry.getKey(); |
| 318 | values[i] = entry.getValue(); |
| 319 | ++i; |
| 320 | } |
| 321 | } |
| 322 | |
Andreas Huber | 8240d92 | 2012-04-04 14:06:32 -0700 | [diff] [blame] | 323 | native_configure(keys, values, surface, crypto, flags); |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 324 | } |
| 325 | |
| 326 | private native final void native_configure( |
Andreas Huber | 8240d92 | 2012-04-04 14:06:32 -0700 | [diff] [blame] | 327 | String[] keys, Object[] values, |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 328 | Surface surface, MediaCrypto crypto, int flags); |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 329 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 330 | /** |
Andy McFadden | 47a2db4 | 2013-03-07 17:56:40 -0800 | [diff] [blame] | 331 | * Requests a Surface to use as the input to an encoder, in place of input buffers. This |
| 332 | * may only be called after {@link #configure} and before {@link #start}. |
Andy McFadden | 2621e40 | 2013-02-19 07:29:21 -0800 | [diff] [blame] | 333 | * <p> |
| 334 | * The application is responsible for calling release() on the Surface when |
| 335 | * done. |
Andy McFadden | 2621e40 | 2013-02-19 07:29:21 -0800 | [diff] [blame] | 336 | */ |
| 337 | public native final Surface createInputSurface(); |
| 338 | |
| 339 | /** |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 340 | * After successfully configuring the component, call start. On return |
| 341 | * you can query the component for its input/output buffers. |
| 342 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 343 | public native final void start(); |
| 344 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 345 | /** |
| 346 | * Finish the decode/encode session, note that the codec instance |
| 347 | * remains active and ready to be {@link #start}ed again. |
| 348 | * To ensure that it is available to other client call {@link #release} |
| 349 | * and don't just rely on garbage collection to eventually do this for you. |
| 350 | */ |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 351 | public final void stop() { |
| 352 | native_stop(); |
| 353 | |
| 354 | if (mEventHandler != null) { |
| 355 | mEventHandler.removeMessages(EVENT_NOTIFY); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | private native final void native_stop(); |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 360 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 361 | /** |
| 362 | * Flush both input and output ports of the component, all indices |
| 363 | * previously returned in calls to {@link #dequeueInputBuffer} and |
| 364 | * {@link #dequeueOutputBuffer} become invalid. |
| 365 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 366 | public native final void flush(); |
| 367 | |
Jeff Tinker | b6f0f96 | 2013-09-13 15:32:08 -0700 | [diff] [blame] | 368 | /** |
| 369 | * Thrown when a crypto error occurs while queueing a secure input buffer. |
| 370 | */ |
Andreas Huber | bfc56f4 | 2012-04-19 12:47:07 -0700 | [diff] [blame] | 371 | public final static class CryptoException extends RuntimeException { |
| 372 | public CryptoException(int errorCode, String detailMessage) { |
| 373 | super(detailMessage); |
| 374 | mErrorCode = errorCode; |
| 375 | } |
| 376 | |
Jeff Tinker | 3ed3826 | 2013-08-02 23:24:51 -0700 | [diff] [blame] | 377 | /** |
| 378 | * This indicates that no key has been set to perform the requested |
| 379 | * decrypt operation. |
| 380 | */ |
| 381 | public static final int ERROR_NO_KEY = 1; |
| 382 | |
| 383 | /** |
| 384 | * This indicates that the key used for decryption is no longer |
| 385 | * valid due to license term expiration. |
| 386 | */ |
| 387 | public static final int ERROR_KEY_EXPIRED = 2; |
| 388 | |
| 389 | /** |
| 390 | * This indicates that a required crypto resource was not able to be |
| 391 | * allocated while attempting the requested operation. |
| 392 | */ |
| 393 | public static final int ERROR_RESOURCE_BUSY = 3; |
| 394 | |
Jeff Tinker | b6f0f96 | 2013-09-13 15:32:08 -0700 | [diff] [blame] | 395 | /** |
| 396 | * Retrieve the error code associated with a CryptoException |
| 397 | */ |
Andreas Huber | bfc56f4 | 2012-04-19 12:47:07 -0700 | [diff] [blame] | 398 | public int getErrorCode() { |
| 399 | return mErrorCode; |
| 400 | } |
| 401 | |
| 402 | private int mErrorCode; |
| 403 | } |
| 404 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 405 | /** |
| 406 | * After filling a range of the input buffer at the specified index |
| 407 | * submit it to the component. |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 408 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 409 | * Many decoders require the actual compressed data stream to be |
| 410 | * preceded by "codec specific data", i.e. setup data used to initialize |
| 411 | * the codec such as PPS/SPS in the case of AVC video or code tables |
| 412 | * in the case of vorbis audio. |
| 413 | * The class {@link android.media.MediaExtractor} provides codec |
| 414 | * specific data as part of |
| 415 | * the returned track format in entries named "csd-0", "csd-1" ... |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 416 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 417 | * These buffers should be submitted using the flag {@link #BUFFER_FLAG_CODEC_CONFIG}. |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 418 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 419 | * To indicate that this is the final piece of input data (or rather that |
| 420 | * no more input data follows unless the decoder is subsequently flushed) |
| 421 | * specify the flag {@link #BUFFER_FLAG_END_OF_STREAM}. |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 422 | * |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 423 | * @param index The index of a client-owned input buffer previously returned |
| 424 | * in a call to {@link #dequeueInputBuffer}. |
| 425 | * @param offset The byte offset into the input buffer at which the data starts. |
| 426 | * @param size The number of bytes of valid input data. |
| 427 | * @param presentationTimeUs The time at which this buffer should be rendered. |
| 428 | * @param flags A bitmask of flags {@link #BUFFER_FLAG_SYNC_FRAME}, |
| 429 | * {@link #BUFFER_FLAG_CODEC_CONFIG} or {@link #BUFFER_FLAG_END_OF_STREAM}. |
| 430 | * @throws CryptoException if a crypto object has been specified in |
| 431 | * {@link #configure} |
| 432 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 433 | public native final void queueInputBuffer( |
| 434 | int index, |
Andreas Huber | bfc56f4 | 2012-04-19 12:47:07 -0700 | [diff] [blame] | 435 | int offset, int size, long presentationTimeUs, int flags) |
| 436 | throws CryptoException; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 437 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 438 | // The following mode constants MUST stay in sync with their equivalents |
| 439 | // in media/hardware/CryptoAPI.h ! |
| 440 | public static final int CRYPTO_MODE_UNENCRYPTED = 0; |
| 441 | public static final int CRYPTO_MODE_AES_CTR = 1; |
| 442 | |
| 443 | /** |
| 444 | * Metadata describing the structure of a (at least partially) encrypted |
| 445 | * input sample. |
| 446 | * A buffer's data is considered to be partitioned into "subSamples", |
| 447 | * each subSample starts with a (potentially empty) run of plain, |
| 448 | * unencrypted bytes followed by a (also potentially empty) run of |
| 449 | * encrypted bytes. |
| 450 | * numBytesOfClearData can be null to indicate that all data is encrypted. |
| 451 | * This information encapsulates per-sample metadata as outlined in |
| 452 | * ISO/IEC FDIS 23001-7:2011 "Common encryption in ISO base media file format files". |
| 453 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 454 | public final static class CryptoInfo { |
| 455 | public void set( |
| 456 | int newNumSubSamples, |
| 457 | int[] newNumBytesOfClearData, |
| 458 | int[] newNumBytesOfEncryptedData, |
| 459 | byte[] newKey, |
| 460 | byte[] newIV, |
| 461 | int newMode) { |
| 462 | numSubSamples = newNumSubSamples; |
| 463 | numBytesOfClearData = newNumBytesOfClearData; |
| 464 | numBytesOfEncryptedData = newNumBytesOfEncryptedData; |
| 465 | key = newKey; |
| 466 | iv = newIV; |
| 467 | mode = newMode; |
| 468 | } |
| 469 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 470 | /** |
| 471 | * The number of subSamples that make up the buffer's contents. |
| 472 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 473 | public int numSubSamples; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 474 | /** |
| 475 | * The number of leading unencrypted bytes in each subSample. |
| 476 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 477 | public int[] numBytesOfClearData; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 478 | /** |
| 479 | * The number of trailing encrypted bytes in each subSample. |
| 480 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 481 | public int[] numBytesOfEncryptedData; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 482 | /** |
| 483 | * A 16-byte opaque key |
| 484 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 485 | public byte[] key; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 486 | /** |
| 487 | * A 16-byte initialization vector |
| 488 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 489 | public byte[] iv; |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 490 | /** |
| 491 | * The type of encryption that has been applied, |
| 492 | * see {@link #CRYPTO_MODE_UNENCRYPTED} and {@link #CRYPTO_MODE_AES_CTR}. |
| 493 | */ |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 494 | public int mode; |
Marco Nelissen | e20a6d5 | 2013-04-08 14:28:55 -0700 | [diff] [blame] | 495 | |
| 496 | @Override |
| 497 | public String toString() { |
| 498 | StringBuilder builder = new StringBuilder(); |
| 499 | builder.append(numSubSamples + " subsamples, key ["); |
| 500 | String hexdigits = "0123456789abcdef"; |
| 501 | for (int i = 0; i < key.length; i++) { |
| 502 | builder.append(hexdigits.charAt((key[i] & 0xf0) >> 4)); |
| 503 | builder.append(hexdigits.charAt(key[i] & 0x0f)); |
| 504 | } |
| 505 | builder.append("], iv ["); |
| 506 | for (int i = 0; i < key.length; i++) { |
| 507 | builder.append(hexdigits.charAt((iv[i] & 0xf0) >> 4)); |
| 508 | builder.append(hexdigits.charAt(iv[i] & 0x0f)); |
| 509 | } |
| 510 | builder.append("], clear "); |
| 511 | builder.append(Arrays.toString(numBytesOfClearData)); |
| 512 | builder.append(", encrypted "); |
| 513 | builder.append(Arrays.toString(numBytesOfEncryptedData)); |
| 514 | return builder.toString(); |
| 515 | } |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 516 | }; |
| 517 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 518 | /** |
| 519 | * Similar to {@link #queueInputBuffer} but submits a buffer that is |
| 520 | * potentially encrypted. |
| 521 | * @param index The index of a client-owned input buffer previously returned |
| 522 | * in a call to {@link #dequeueInputBuffer}. |
| 523 | * @param offset The byte offset into the input buffer at which the data starts. |
| 524 | * @param info Metadata required to facilitate decryption, the object can be |
| 525 | * reused immediately after this call returns. |
| 526 | * @param presentationTimeUs The time at which this buffer should be rendered. |
| 527 | * @param flags A bitmask of flags {@link #BUFFER_FLAG_SYNC_FRAME}, |
| 528 | * {@link #BUFFER_FLAG_CODEC_CONFIG} or {@link #BUFFER_FLAG_END_OF_STREAM}. |
Jeff Tinker | b6f0f96 | 2013-09-13 15:32:08 -0700 | [diff] [blame] | 529 | * @throws CryptoException if an error occurs while attempting to decrypt the buffer. |
| 530 | * An error code associated with the exception helps identify the |
| 531 | * reason for the failure. |
Andreas Huber | 9e6bcce | 2012-04-06 12:14:47 -0700 | [diff] [blame] | 532 | */ |
| 533 | public native final void queueSecureInputBuffer( |
| 534 | int index, |
| 535 | int offset, |
Andreas Huber | 91befdc | 2012-04-18 12:19:51 -0700 | [diff] [blame] | 536 | CryptoInfo info, |
Andreas Huber | 9e6bcce | 2012-04-06 12:14:47 -0700 | [diff] [blame] | 537 | long presentationTimeUs, |
Andreas Huber | bfc56f4 | 2012-04-19 12:47:07 -0700 | [diff] [blame] | 538 | int flags) throws CryptoException; |
Andreas Huber | 9e6bcce | 2012-04-06 12:14:47 -0700 | [diff] [blame] | 539 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 540 | /** |
| 541 | * Returns the index of an input buffer to be filled with valid data |
| 542 | * or -1 if no such buffer is currently available. |
| 543 | * This method will return immediately if timeoutUs == 0, wait indefinitely |
| 544 | * for the availability of an input buffer if timeoutUs < 0 or wait up |
| 545 | * to "timeoutUs" microseconds if timeoutUs > 0. |
| 546 | * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite". |
| 547 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 548 | public native final int dequeueInputBuffer(long timeoutUs); |
| 549 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 550 | /** |
| 551 | * If a non-negative timeout had been specified in the call |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 552 | * to {@link #dequeueOutputBuffer}, indicates that the call timed out. |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 553 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 554 | public static final int INFO_TRY_AGAIN_LATER = -1; |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 555 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 556 | /** |
| 557 | * The output format has changed, subsequent data will follow the new |
| 558 | * format. {@link #getOutputFormat} returns the new format. |
| 559 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 560 | public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; |
Andreas Huber | 07ea426 | 2012-04-11 12:21:20 -0700 | [diff] [blame] | 561 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 562 | /** |
| 563 | * The output buffers have changed, the client must refer to the new |
| 564 | * set of output buffers returned by {@link #getOutputBuffers} from |
| 565 | * this point on. |
| 566 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 567 | public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; |
| 568 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 569 | /** |
| 570 | * Dequeue an output buffer, block at most "timeoutUs" microseconds. |
| 571 | * Returns the index of an output buffer that has been successfully |
| 572 | * decoded or one of the INFO_* constants below. |
| 573 | * @param info Will be filled with buffer meta data. |
| 574 | * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite". |
| 575 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 576 | public native final int dequeueOutputBuffer( |
| 577 | BufferInfo info, long timeoutUs); |
| 578 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 579 | /** |
| 580 | * If you are done with a buffer, use this call to return the buffer to |
| 581 | * the codec. If you previously specified a surface when configuring this |
| 582 | * video decoder you can optionally render the buffer. |
| 583 | * @param index The index of a client-owned output buffer previously returned |
| 584 | * in a call to {@link #dequeueOutputBuffer}. |
| 585 | * @param render If a valid surface was specified when configuring the codec, |
| 586 | * passing true renders this output buffer to the surface. |
| 587 | */ |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 588 | public native final void releaseOutputBuffer(int index, boolean render); |
| 589 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 590 | /** |
Andy McFadden | 2621e40 | 2013-02-19 07:29:21 -0800 | [diff] [blame] | 591 | * Signals end-of-stream on input. Equivalent to submitting an empty buffer with |
| 592 | * {@link #BUFFER_FLAG_END_OF_STREAM} set. This may only be used with |
| 593 | * encoders receiving input from a Surface created by {@link #createInputSurface}. |
Andy McFadden | 2621e40 | 2013-02-19 07:29:21 -0800 | [diff] [blame] | 594 | */ |
| 595 | public native final void signalEndOfInputStream(); |
| 596 | |
| 597 | /** |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 598 | * Call this after dequeueOutputBuffer signals a format change by returning |
| 599 | * {@link #INFO_OUTPUT_FORMAT_CHANGED} |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 600 | */ |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 601 | public final MediaFormat getOutputFormat() { |
| 602 | return new MediaFormat(getOutputFormatNative()); |
| 603 | } |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 604 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 605 | private native final Map<String, Object> getOutputFormatNative(); |
| 606 | |
| 607 | /** |
| 608 | * Call this after start() returns. |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 609 | */ |
| 610 | public ByteBuffer[] getInputBuffers() { |
| 611 | return getBuffers(true /* input */); |
| 612 | } |
| 613 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 614 | /** |
| 615 | * Call this after start() returns and whenever dequeueOutputBuffer |
| 616 | * signals an output buffer change by returning |
| 617 | * {@link #INFO_OUTPUT_BUFFERS_CHANGED} |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 618 | */ |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 619 | public ByteBuffer[] getOutputBuffers() { |
| 620 | return getBuffers(false /* input */); |
| 621 | } |
| 622 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 623 | /** |
| 624 | * The content is scaled to the surface dimensions |
| 625 | */ |
Andreas Huber | 48dc91b | 2012-05-01 11:50:30 -0700 | [diff] [blame] | 626 | public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; |
Andreas Huber | b12a539 | 2012-04-30 14:18:33 -0700 | [diff] [blame] | 627 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 628 | /** |
| 629 | * The content is scaled, maintaining its aspect ratio, the whole |
| 630 | * surface area is used, content may be cropped |
| 631 | */ |
Andreas Huber | b12a539 | 2012-04-30 14:18:33 -0700 | [diff] [blame] | 632 | public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; |
| 633 | |
Andreas Huber | 60d610b | 2012-05-02 16:06:09 -0700 | [diff] [blame] | 634 | /** |
| 635 | * If a surface has been specified in a previous call to {@link #configure} |
| 636 | * specifies the scaling mode to use. The default is "scale to fit". |
| 637 | */ |
Andreas Huber | b12a539 | 2012-04-30 14:18:33 -0700 | [diff] [blame] | 638 | public native final void setVideoScalingMode(int mode); |
| 639 | |
Martin Storsjo | 056ef2e | 2012-09-25 11:53:04 +0300 | [diff] [blame] | 640 | /** |
| 641 | * Get the component name. If the codec was created by createDecoderByType |
| 642 | * or createEncoderByType, what component is chosen is not known beforehand. |
| 643 | */ |
| 644 | public native final String getName(); |
| 645 | |
Martin Storsjo | 93077a2 | 2012-09-25 11:55:25 +0300 | [diff] [blame] | 646 | /** |
Andreas Huber | 226065b | 2013-08-12 10:14:11 -0700 | [diff] [blame] | 647 | * Change a video encoder's target bitrate on the fly. The value is an |
| 648 | * Integer object containing the new bitrate in bps. |
| 649 | */ |
Lajos Molnar | 8a39021 | 2013-09-17 18:58:14 -0700 | [diff] [blame] | 650 | public static final String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate"; |
Andreas Huber | 226065b | 2013-08-12 10:14:11 -0700 | [diff] [blame] | 651 | |
| 652 | /** |
| 653 | * Temporarily suspend/resume encoding of input data. While suspended |
| 654 | * input data is effectively discarded instead of being fed into the |
| 655 | * encoder. This parameter really only makes sense to use with an encoder |
| 656 | * in "surface-input" mode, as the client code has no control over the |
| 657 | * input-side of the encoder in that case. |
| 658 | * The value is an Integer object containing the value 1 to suspend |
| 659 | * or the value 0 to resume. |
| 660 | */ |
| 661 | public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames"; |
| 662 | |
| 663 | /** |
| 664 | * Request that the encoder produce a sync frame "soon". |
| 665 | * Provide an Integer with the value 0. |
| 666 | */ |
| 667 | public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync"; |
| 668 | |
| 669 | /** |
| 670 | * Communicate additional parameter changes to the component instance. |
| 671 | */ |
Lajos Molnar | 8a39021 | 2013-09-17 18:58:14 -0700 | [diff] [blame] | 672 | public final void setParameters(Bundle params) { |
Andreas Huber | 226065b | 2013-08-12 10:14:11 -0700 | [diff] [blame] | 673 | if (params == null) { |
| 674 | return; |
| 675 | } |
| 676 | |
| 677 | String[] keys = new String[params.size()]; |
| 678 | Object[] values = new Object[params.size()]; |
| 679 | |
| 680 | int i = 0; |
Lajos Molnar | 8a39021 | 2013-09-17 18:58:14 -0700 | [diff] [blame] | 681 | for (final String key: params.keySet()) { |
| 682 | keys[i] = key; |
| 683 | values[i] = params.get(key); |
Andreas Huber | 226065b | 2013-08-12 10:14:11 -0700 | [diff] [blame] | 684 | ++i; |
| 685 | } |
| 686 | |
| 687 | setParameters(keys, values); |
| 688 | } |
| 689 | |
Andreas Huber | aba6713 | 2013-10-22 12:40:01 -0700 | [diff] [blame] | 690 | public void setNotificationCallback(NotificationCallback cb) { |
| 691 | mNotificationCallback = cb; |
| 692 | } |
| 693 | |
| 694 | public interface NotificationCallback { |
| 695 | void onCodecNotify(MediaCodec codec); |
| 696 | } |
| 697 | |
| 698 | private void postEventFromNative( |
| 699 | int what, int arg1, int arg2, Object obj) { |
| 700 | if (mEventHandler != null) { |
| 701 | Message msg = mEventHandler.obtainMessage(what, arg1, arg2, obj); |
| 702 | mEventHandler.sendMessage(msg); |
| 703 | } |
| 704 | } |
| 705 | |
Andreas Huber | 226065b | 2013-08-12 10:14:11 -0700 | [diff] [blame] | 706 | private native final void setParameters(String[] keys, Object[] values); |
| 707 | |
| 708 | /** |
Martin Storsjo | 93077a2 | 2012-09-25 11:55:25 +0300 | [diff] [blame] | 709 | * Get the codec info. If the codec was created by createDecoderByType |
| 710 | * or createEncoderByType, what component is chosen is not known beforehand, |
| 711 | * and thus the caller does not have the MediaCodecInfo. |
| 712 | */ |
| 713 | public MediaCodecInfo getCodecInfo() { |
| 714 | return MediaCodecList.getCodecInfoAt( |
| 715 | MediaCodecList.findCodecByName(getName())); |
| 716 | } |
| 717 | |
Andreas Huber | c52b980 | 2012-03-12 14:04:01 -0700 | [diff] [blame] | 718 | private native final ByteBuffer[] getBuffers(boolean input); |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 719 | |
| 720 | private static native final void native_init(); |
| 721 | |
| 722 | private native final void native_setup( |
| 723 | String name, boolean nameIsType, boolean encoder); |
| 724 | |
| 725 | private native final void native_finalize(); |
| 726 | |
| 727 | static { |
| 728 | System.loadLibrary("media_jni"); |
| 729 | native_init(); |
| 730 | } |
| 731 | |
Ashok Bhat | 075e9a1 | 2014-01-06 13:45:09 +0000 | [diff] [blame] | 732 | private long mNativeContext; |
Andreas Huber | 88572f7 | 2012-02-21 11:47:18 -0800 | [diff] [blame] | 733 | } |