Unhide new media related java APIs.

Change-Id: If0b8201eaca74f51f3499b6ecdfb73088586ee24
diff --git a/api/current.txt b/api/current.txt
index e4836a3..ec26e93 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10935,6 +10935,91 @@
     field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
   }
 
+  public final class MediaCodec {
+    method public void configure(java.util.Map<java.lang.String, java.lang.Object>, android.view.Surface, android.media.MediaCrypto, int);
+    method public static android.media.MediaCodec createByCodecName(java.lang.String);
+    method public static android.media.MediaCodec createDecoderByType(java.lang.String);
+    method public static android.media.MediaCodec createEncoderByType(java.lang.String);
+    method public final int dequeueInputBuffer(long);
+    method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
+    method public final void flush();
+    method public java.nio.ByteBuffer[] getInputBuffers();
+    method public java.nio.ByteBuffer[] getOutputBuffers();
+    method public final java.util.Map<java.lang.String, java.lang.Object> getOutputFormat();
+    method public final void queueInputBuffer(int, int, int, long, int);
+    method public final void queueSecureInputBuffer(int, int, int[], int[], int, byte[], byte[], int, long, int);
+    method public final void release();
+    method public final void releaseOutputBuffer(int, boolean);
+    method public final void start();
+    method public final void stop();
+    field public static int CONFIGURE_FLAG_ENCODE;
+    field public static final int FLAG_CODECCONFIG = 2; // 0x2
+    field public static final int FLAG_EOS = 4; // 0x4
+    field public static final int FLAG_SYNCFRAME = 1; // 0x1
+    field public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
+    field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
+    field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
+    field public static final int MODE_AES_CTR = 1; // 0x1
+    field public static final int MODE_UNENCRYPTED = 0; // 0x0
+  }
+
+  public static final class MediaCodec.BufferInfo {
+    ctor public MediaCodec.BufferInfo();
+    method public void set(int, int, long, int);
+    field public int flags;
+    field public int offset;
+    field public long presentationTimeUs;
+    field public int size;
+  }
+
+  public final class MediaCodecList {
+    method public static final int countCodecs();
+    method public static final android.media.MediaCodecList.CodecCapabilities getCodecCapabilities(int, java.lang.String);
+    method public static final java.lang.String getCodecName(int);
+    method public static final java.lang.String[] getSupportedTypes(int);
+    method public static final boolean isEncoder(int);
+  }
+
+  public static final class MediaCodecList.CodecCapabilities {
+    ctor public MediaCodecList.CodecCapabilities();
+    field public int[] colorFormats;
+    field public android.media.MediaCodecList.CodecProfileLevel[] profileLevels;
+  }
+
+  public static final class MediaCodecList.CodecProfileLevel {
+    ctor public MediaCodecList.CodecProfileLevel();
+    field public int level;
+    field public int profile;
+  }
+
+  public final class MediaCrypto {
+    ctor public MediaCrypto(byte[], byte[]);
+    method public static final boolean isCryptoSchemeSupported(byte[]);
+    method public final void release();
+    method public final boolean requiresSecureDecoderComponent(java.lang.String);
+  }
+
+  public final class MediaExtractor {
+    ctor public MediaExtractor();
+    method public boolean advance();
+    method public int countTracks();
+    method public int getSampleFlags();
+    method public long getSampleTime();
+    method public int getSampleTrackIndex();
+    method public java.util.Map<java.lang.String, java.lang.Object> getTrackFormat(int);
+    method public int readSampleData(java.nio.ByteBuffer, int);
+    method public final void release();
+    method public void seekTo(long);
+    method public void selectTrack(int);
+    method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
+    method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+    method public final void setDataSource(java.lang.String);
+    method public final void setDataSource(java.io.FileDescriptor);
+    method public final void setDataSource(java.io.FileDescriptor, long, long);
+    field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+    field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
+  }
+
   public class MediaMetadataRetriever {
     ctor public MediaMetadataRetriever();
     method public java.lang.String extractMetadata(int);
diff --git a/media/java/android/media/Crypto.java b/media/java/android/media/Crypto.java
deleted file mode 100644
index 43e34fb..0000000
--- a/media/java/android/media/Crypto.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-/**
- * Crypto class can be used in conjunction with MediaCodec to decode
- * encrypted media data.
- * @hide
-*/
-public final class Crypto {
-    public static final native boolean isCryptoSchemeSupported(byte[] uuid);
-
-    public Crypto(byte[] uuid, byte[] initData) {
-        native_setup(uuid, initData);
-    }
-
-    public final native boolean requiresSecureDecoderComponent(String mime);
-
-    @Override
-    protected void finalize() {
-        native_finalize();
-    }
-
-    public native final void release();
-    private static native final void native_init();
-    private native final void native_setup(byte[] uuid, byte[] initData);
-    private native final void native_finalize();
-
-    static {
-        System.loadLibrary("media_jni");
-        native_init();
-    }
-
-    private int mNativeContext;
-}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 410383d..a65c2aa 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.media.Crypto;
+import android.media.MediaCrypto;
 import android.view.Surface;
 import java.nio.ByteBuffer;
 import java.util.Map;
@@ -24,7 +24,122 @@
 /**
  * MediaCodec class can be used to access low-level media codec, i.e.
  * encoder/decoder components.
- * @hide
+ *
+ * <p>MediaCodec is generally used like this:
+ * <pre>
+ * MediaCodec codec = MediaCodec.createDecoderByType(type);
+ * codec.configure(format, ...);
+ * codec.start();
+ * ByteBuffer[] inputBuffers = codec.getInputBuffers();
+ * ByteBuffer[] outputBuffers = codec.getOutputBuffers();
+ * Map<String, Object> format = codec.getOutputFormat();
+ * for (;;) {
+ *   int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
+ *   if (inputBufferIndex &gt;= 0) {
+ *     // fill inputBuffers[inputBufferIndex] with valid data
+ *     ...
+ *     codec.queueInputBuffer(inputBufferIndex, ...);
+ *   }
+ *
+ *   int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
+ *   if (outputBufferIndex &gt;= 0) {
+ *     // outputBuffer is ready to be processed or rendered.
+ *     ...
+ *     codec.releaseOutputBuffer(outputBufferIndex, ...);
+ *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ *     outputBuffers = codec.getOutputBuffers();
+ *   } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ *     // Subsequent data will conform to new format.
+ *     format = codec.getOutputFormat();
+ *     ...
+ *   }
+ * }
+ * codec.stop();
+ * codec.release();
+ * codec = null;
+ * </pre>
+ *
+ * Each codec maintains a number of input and output buffers that are
+ * referred to by index in API calls.
+ * The contents of these buffers is represented by the ByteBuffer[] arrays
+ * accessible through getInputBuffers() and getOutputBuffers().
+ *
+ * After a successful call to {@link #start} the client "owns" neither
+ * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer}
+ * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
+ * to the client.<p>
+ * The client is not required to resubmit/release buffers immediately
+ * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * Once the client has an input buffer available it can fill it with data
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * The codec in turn will return an output buffer to the client in response
+ * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
+ * a call to {@link #releaseOutputBuffer} will return it to the codec.
+ * If a video surface has been provided in the call to {@link #configure},
+ * {@link #releaseOutputBuffer} optionally allows rendering of the buffer
+ * to the surface.<p>
+ *
+ * Input buffers (for decoders) and Output buffers (for encoders) contain
+ * encoded data according to the format's type. For video types this data
+ * is all the encoded data representing a single moment in time, for audio
+ * data this is slightly relaxed in that a buffer may contain multiple
+ * encoded frames of audio. In either case, buffers do not start and end on
+ * arbitrary byte boundaries, this is not a stream of bytes, it's a stream
+ * of access units.<p>
+ *
+ * Most formats also require the actual data to be prefixed by a number
+ * of buffers containing setup data, or codec specific data, i.e. the
+ * first few buffers submitted to the codec object after starting it must
+ * be codec specific data marked as such using the flag {@link #FLAG_CODECCONFIG}
+ * in a call to {@link #queueInputBuffer}.
+ *
+ * Once the client reaches the end of the input data it signals the end of
+ * the input stream by specifying a flag of {@link #FLAG_EOS} in the call to
+ * {@link #queueInputBuffer}. The codec will continue to return output buffers
+ * until it eventually signals the end of the output stream by specifying
+ * the same flag ({@link #FLAG_EOS}) on the BufferInfo returned in
+ * {@link #dequeueOutputBuffer}.
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * Any input or output buffers the client may own at the point of the flush are
+ * immediately revoked, i.e. after a call to {@link #flush} the client does not
+ * own any buffers anymore.
+ * Note that the format of the data submitted after a flush must not change,
+ * flush does not support format discontinuities,
+ * for this a full stop(), configure(), start() cycle is necessary.
+ *
+ * The format of the media data is specified as string/value pairs represented
+ * as a Map<String, Object>.<p>
+ *
+ * Fields common to all formats:
+ *
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>mime</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>max-input-size</td><td>Integer</td><td>optional, maximum size of a buffer of input data</td></tr>
+ * <tr><td>bitrate</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr>
+ * </table>
+ *
+ * Video formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>width</td><td>Integer</td><td></td></tr>
+ * <tr><td>height</td><td>Integer</td><td></td></tr>
+ * <tr><td>color-format</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>frame-rate</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>i-frame-interval</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>stride</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to width</td></tr>
+ * <tr><td>slice-height</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to height</td></tr>
+ * </table>
+ *
+ * Audio formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>channel-count</td><td>Integer</td><td></td></tr>
+ * <tr><td>sample-rate</td><td>Integer</td><td></td></tr>
+ * </table>
+ *
 */
 final public class MediaCodec {
     /** Per buffer metadata includes an offset and size specifying
@@ -32,43 +147,62 @@
     */
     public final static class BufferInfo {
         public void set(
-                int offset, int size, long timeUs, int flags) {
-            mOffset = offset;
-            mSize = size;
-            mPresentationTimeUs = timeUs;
-            mFlags = flags;
+                int newOffset, int newSize, long newTimeUs, int newFlags) {
+            offset = newOffset;
+            size = newSize;
+            presentationTimeUs = newTimeUs;
+            flags = newFlags;
         }
 
-        public int mOffset;
-        public int mSize;
-        public long mPresentationTimeUs;
-        public int mFlags;
+        public int offset;
+        public int size;
+        public long presentationTimeUs;
+        public int flags;
     };
 
     // The follow flag constants MUST stay in sync with their equivalents
     // in MediaCodec.h !
-    public static int FLAG_SYNCFRAME   = 1;
-    public static int FLAG_CODECCONFIG = 2;
-    public static int FLAG_EOS         = 4;
+
+    /** This indicates that the buffer marked as such contains the data
+        for a sync frame.
+    */
+    public static final int FLAG_SYNCFRAME   = 1;
+
+    /** This indicated that the buffer marked as such contains codec
+        initialization / codec specific data instead of media data.
+    */
+    public static final int FLAG_CODECCONFIG = 2;
+
+    /** This signals the end of stream, i.e. no buffers will be available
+        after this, unless of course, {@link #flush} follows.
+    */
+    public static final int FLAG_EOS         = 4;
 
     // The following mode constants MUST stay in sync with their equivalents
     // in media/hardware/CryptoAPI.h !
-    public static int MODE_UNENCRYPTED = 0;
-    public static int MODE_AES_CTR     = 1;
+    public static final int MODE_UNENCRYPTED = 0;
+    public static final int MODE_AES_CTR     = 1;
 
-    /** Instantiate a codec component by mime type. For decoder components
-        this is the mime type of media that this decoder should be able to
-        decoder, for encoder components it's the type of media this encoder
-        should encode _to_.
+    /** Instantiate a decoder supporting input data of the given mime type.
+      * @param type The mime type of the input data.
     */
-    public static MediaCodec CreateByType(String type, boolean encoder) {
-        return new MediaCodec(type, true /* nameIsType */, encoder);
+    public static MediaCodec createDecoderByType(String type) {
+        return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
+    }
+
+    /** Instantiate an encoder supporting output data of the given mime type.
+      * @param type The desired mime type of the output data.
+    */
+    public static MediaCodec createEncoderByType(String type) {
+        return new MediaCodec(type, true /* nameIsType */, true /* encoder */);
     }
 
     /** If you know the exact name of the component you want to instantiate
         use this method to instantiate it. Use with caution.
+        Likely to be used with information obtained from {@link android.media.MediaCodecList}
+        @param name The name of the codec to be instantiated.
     */
-    public static MediaCodec CreateByComponentName(String name) {
+    public static MediaCodec createByCodecName(String name) {
         return new MediaCodec(
                 name, false /* nameIsType */, false /* unused */);
     }
@@ -88,35 +222,14 @@
     // to do this for you at some point in the future.
     public native final void release();
 
+    /** If this codec is to be used as an encoder, pass this flag.
+      */
     public static int CONFIGURE_FLAG_ENCODE = 1;
 
     /** Configures a component.
-     *  @param format A map of string/value pairs describing the input format
-     *                (decoder) or the desired output format.
      *
-     *                Video formats have the following fields:
-     *                  "mime"          - String
-     *                  "width"         - Integer
-     *                  "height"        - Integer
-     *                  optional "max-input-size"       - Integer
-     *
-     *                Audio formats have the following fields:
-     *                  "mime"          - String
-     *                  "channel-count" - Integer
-     *                  "sample-rate"   - Integer
-     *                  optional "max-input-size"       - Integer
-     *
-     *                If the format is used to configure an encoder, additional
-     *                fields must be included:
-     *                  "bitrate" - Integer (in bits/sec)
-     *
-     *                for video formats:
-     *                  "color-format"          - Integer
-     *                  "frame-rate"            - Integer or Float
-     *                  "i-frame-interval"      - Integer
-     *                  optional "stride"       - Integer, defaults to "width"
-     *                  optional "slice-height" - Integer, defaults to "height"
-     *
+     *  @param format The format of the input data (decoder) or the desired
+     *                format of the output data (encoder).
      *  @param surface Specify a surface on which to render the output of this
      *                 decoder.
      *  @param crypto  Specify a crypto object to facilitate secure decryption
@@ -126,7 +239,7 @@
     */
     public void configure(
             Map<String, Object> format,
-            Surface surface, Crypto crypto, int flags) {
+            Surface surface, MediaCrypto crypto, int flags) {
         String[] keys = null;
         Object[] values = null;
 
@@ -147,18 +260,23 @@
 
     private native final void native_configure(
             String[] keys, Object[] values,
-            Surface surface, Crypto crypto, int flags);
+            Surface surface, MediaCrypto crypto, int flags);
 
     /** After successfully configuring the component, call start. On return
      *  you can query the component for its input/output buffers.
     */
     public native final void start();
 
+    /** Finish the decode/encode session, note that the codec instance
+      * remains active and ready to be {@link #start}ed again.
+      * To ensure that it is available to other client call {@link #release}
+      * and don't just rely on garbage collection to eventually do this for you.
+    */
     public native final void stop();
 
     /** Flush both input and output ports of the component, all indices
-     *  previously returned in calls to dequeueInputBuffer and
-     *  dequeueOutputBuffer become invalid.
+     *  previously returned in calls to {@link #dequeueInputBuffer} and
+     *  {@link #dequeueOutputBuffer} become invalid.
     */
     public native final void flush();
 
@@ -169,24 +287,36 @@
      *  preceded by "codec specific data", i.e. setup data used to initialize
      *  the codec such as PPS/SPS in the case of AVC video or code tables
      *  in the case of vorbis audio.
-     *  The class MediaExtractor provides codec specific data as part of
+     *  The class {@link android.media.MediaExtractor} provides codec
+     *  specific data as part of
      *  the returned track format in entries named "csd-0", "csd-1" ...
      *
      *  These buffers should be submitted using the flag {@link #FLAG_CODECCONFIG}.
      *
      *  To indicate that this is the final piece of input data (or rather that
      *  no more input data follows unless the decoder is subsequently flushed)
-     *  specify the flag {@link FLAG_EOS}.
+     *  specify the flag {@link #FLAG_EOS}.
+     *
+     *  @param index The index of a client-owned input buffer previously returned
+     *               in a call to {@link #dequeueInputBuffer}.
+     *  @param offset The byte offset into the input buffer at which the data starts.
+     *  @param size The number of bytes of valid input data.
+     *  @param presentationTimeUs The time at which this buffer should be rendered.
+     *  @param flags A bitmask of flags {@link #FLAG_SYNCFRAME},
+     *               {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}.
     */
     public native final void queueInputBuffer(
             int index,
             int offset, int size, long presentationTimeUs, int flags);
 
-    /** Similar to {@link queueInputBuffer} but submits a buffer that is
+    /** Similar to {@link #queueInputBuffer} but submits a buffer that is
      *  potentially encrypted. The buffer's data is considered to be
      *  partitioned into "subSamples", each subSample starts with a
      *  (potentially empty) run of plain, unencrypted bytes followed
      *  by a (also potentially empty) run of encrypted bytes.
+     *  @param index The index of a client-owned input buffer previously returned
+     *               in a call to {@link #dequeueInputBuffer}.
+     *  @param offset The byte offset into the input buffer at which the data starts.
      *  @param numBytesOfClearData The number of leading unencrypted bytes in
      *                             each subSample.
      *  @param numBytesOfEncryptedData The number of trailing encrypted bytes
@@ -212,27 +342,48 @@
             long presentationTimeUs,
             int flags);
 
-    // Returns the index of an input buffer to be filled with valid data
-    // or -1 if no such buffer is currently available.
-    // This method will return immediately if timeoutUs == 0, wait indefinitely
-    // for the availability of an input buffer if timeoutUs < 0 or wait up
-    // to "timeoutUs" microseconds if timeoutUs > 0.
+    /** Returns the index of an input buffer to be filled with valid data
+     *  or -1 if no such buffer is currently available.
+     *  This method will return immediately if timeoutUs == 0, wait indefinitely
+     *  for the availability of an input buffer if timeoutUs &lt; 0 or wait up
+     *  to "timeoutUs" microseconds if timeoutUs &gt; 0.
+     *  @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+    */
     public native final int dequeueInputBuffer(long timeoutUs);
 
-    // Returns the index of an output buffer that has been successfully
-    // decoded or one of the INFO_* constants below.
-    // The provided "info" will be filled with buffer meta data.
+    /** If a non-negative timeout had been specified in the call
+     * to {@link #dequeueOutputBuffer}, indicates that the call timed out.
+    */
     public static final int INFO_TRY_AGAIN_LATER        = -1;
+
+    /** The output format has changed, subsequent data will follow the new
+     *  format. {@link #getOutputFormat} returns the new format.
+    */
     public static final int INFO_OUTPUT_FORMAT_CHANGED  = -2;
+
+    /** The output buffers have changed, the client must refer to the new
+     *  set of output buffers returned by {@link #getOutputBuffers} from
+     *  this point on.
+    */
     public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3;
 
-    /** Dequeue an output buffer, block at most "timeoutUs" microseconds. */
+    /** Dequeue an output buffer, block at most "timeoutUs" microseconds.
+     *  Returns the index of an output buffer that has been successfully
+     *  decoded or one of the INFO_* constants below.
+     *  @param info Will be filled with buffer meta data.
+     *  @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+    */
     public native final int dequeueOutputBuffer(
             BufferInfo info, long timeoutUs);
 
-    // If you are done with a buffer, use this call to return the buffer to
-    // the codec. If you previously specified a surface when configuring this
-    // video decoder you can optionally render the buffer.
+    /** If you are done with a buffer, use this call to return the buffer to
+     *  the codec. If you previously specified a surface when configuring this
+     *  video decoder you can optionally render the buffer.
+     *  @param index The index of a client-owned output buffer previously returned
+     *               in a call to {@link #dequeueOutputBuffer}.
+     *  @param render If a valid surface was specified when configuring the codec,
+     *                passing true renders this output buffer to the surface.
+    */
     public native final void releaseOutputBuffer(int index, boolean render);
 
     /** Call this after dequeueOutputBuffer signals a format change by returning
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index b46ce96..1772e9c 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -20,22 +20,42 @@
  * MediaCodecList class can be used to enumerate available codecs,
  * find a codec supporting a given format and query the capabilities
  * of a given codec.
- * @hide
 */
 final public class MediaCodecList {
+    /** Count the number of available codecs.
+      */
     public static native final int countCodecs();
+
+    /** Retrieve the codec name at the specified index. */
     public static native final String getCodecName(int index);
+
+    /** Query if the codec at the specified index is an encoder. */
     public static native final boolean isEncoder(int index);
+
+    /** Query the media types supported by the codec at the specified index */
     public static native final String[] getSupportedTypes(int index);
 
     public static final class CodecProfileLevel {
-        public int mProfile;
-        public int mLevel;
+        /** Defined in the OpenMAX IL specs, depending on the type of media
+          * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE
+          * or OMX_VIDEO_MPEG4PROFILETYPE.
+        */
+        public int profile;
+
+        /** Defined in the OpenMAX IL specs, depending on the type of media
+          * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
+          * or OMX_VIDEO_MPEG4LEVELTYPE.
+        */
+        public int level;
     };
 
     public static final class CodecCapabilities {
-        public CodecProfileLevel[] mProfileLevels;
-        public int[] mColorFormats;
+        public CodecProfileLevel[] profileLevels;
+
+        /** Defined in the OpenMAX IL specs, color format values are drawn from
+          * OMX_COLOR_FORMATTYPE.
+        */
+        public int[] colorFormats;
     };
     public static native final CodecCapabilities getCodecCapabilities(
             int index, String type);
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
new file mode 100644
index 0000000..0c7f6ef
--- /dev/null
+++ b/media/java/android/media/MediaCrypto.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * MediaCrypto class can be used in conjunction with {@link android.media.MediaCodec}
+ * to decode encrypted media data.
+ *
+ * Crypto schemes are assigned 16 byte UUIDs,
+ * the method {@link #isCryptoSchemeSupported} can be used to query if a given
+ * scheme is supported on the device.
+ *
+*/
+public final class MediaCrypto {
+    /** Query if the given scheme identified by its UUID is supported on
+      * this device.
+      * @param uuid The UUID of the crypto scheme.
+    */
+    public static final native boolean isCryptoSchemeSupported(byte[] uuid);
+
+    /** Instantiate a MediaCrypto object using opaque, crypto scheme specific
+      * data.
+      * @param uuid The UUID of the crypto scheme.
+      * @param initData Opaque initialization data specific to the crypto scheme.
+    */
+    public MediaCrypto(byte[] uuid, byte[] initData) {
+        native_setup(uuid, initData);
+    }
+
+    /** Query if the crypto scheme requires the use of a secure decoder
+      * to decode data of the given mime type.
+      * @param mime The mime type of the media data
+    */
+    public final native boolean requiresSecureDecoderComponent(String mime);
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    public native final void release();
+    private static native final void native_init();
+    private native final void native_setup(byte[] uuid, byte[] initData);
+    private native final void native_finalize();
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    private int mNativeContext;
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 9c3b6a7..3f8b2ca 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -16,63 +16,227 @@
 
 package android.media;
 
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.net.Uri;
+import java.io.FileDescriptor;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Map;
 
 /**
- * MediaExtractor
- * @hide
+ * MediaExtractor facilitates extraction of demuxed, typically encoded,  media data
+ * from a data source.
+ * <p>It is generally used like this:
+ * <pre>
+ * MediaExtractor extractor = new MediaExtractor();
+ * extractor.setDataSource(...);
+ * int numTracks = extractor.countTracks();
+ * for (int i = 0; i &lt; numTracks; ++i) {
+ *   Map%lt;String, Object&gt; format = extractor.getTrackFormat(i);
+ *   String mime = (String)format.get("mime");
+ *   if (weAreInterestedInThisTrack) {
+ *     extractor.selectTrack(i);
+ *   }
+ * }
+ * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
+ * while (extractor.readSampleData(inputBuffer, ...) &gt;= 0) {
+ *   int trackIndex = extractor.getTrackIndex();
+ *   long presentationTimeUs = extractor.getSampleTime();
+ *   ...
+ *   extractor.advance();
+ * }
+ *
+ * extractor.release();
+ * extractor = null;
+ * </pre>
 */
 final public class MediaExtractor {
-    public MediaExtractor(String path) {
-        native_setup(path);
+    public MediaExtractor() {
+        native_setup();
     }
 
+    /**
+     * Sets the data source as a content Uri.
+     *
+     * @param context the Context to use when resolving the Uri
+     * @param uri the Content URI of the data you want to extract from.
+     * @param headers the headers to be sent together with the request for the data
+     */
+    public final void setDataSource(
+            Context context, Uri uri, Map<String, String> headers)
+        throws IOException {
+        String scheme = uri.getScheme();
+        if(scheme == null || scheme.equals("file")) {
+            setDataSource(uri.getPath());
+            return;
+        }
+
+        AssetFileDescriptor fd = null;
+        try {
+            ContentResolver resolver = context.getContentResolver();
+            fd = resolver.openAssetFileDescriptor(uri, "r");
+            if (fd == null) {
+                return;
+            }
+            // Note: using getDeclaredLength so that our behavior is the same
+            // as previous versions when the content provider is returning
+            // a full file.
+            if (fd.getDeclaredLength() < 0) {
+                setDataSource(fd.getFileDescriptor());
+            } else {
+                setDataSource(
+                        fd.getFileDescriptor(),
+                        fd.getStartOffset(),
+                        fd.getDeclaredLength());
+            }
+            return;
+        } catch (SecurityException ex) {
+        } catch (IOException ex) {
+        } finally {
+            if (fd != null) {
+                fd.close();
+            }
+        }
+
+        setDataSource(uri.toString(), headers);
+    }
+
+    /**
+     * Sets the data source (file-path or http URL) to use.
+     *
+     * @param path the path of the file, or the http URL
+     * @param headers the headers associated with the http request for the stream you want to play
+     */
+    public final void setDataSource(String path, Map<String, String> headers) {
+        String[] keys = null;
+        String[] values = null;
+
+        if (headers != null) {
+            keys = new String[headers.size()];
+            values = new String[headers.size()];
+
+            int i = 0;
+            for (Map.Entry<String, String> entry: headers.entrySet()) {
+                keys[i] = entry.getKey();
+                values[i] = entry.getValue();
+                ++i;
+            }
+        }
+        setDataSource(path, keys, values);
+    }
+
+    private native final void setDataSource(
+            String path, String[] keys, String[] values);
+
+    /**
+     * Sets the data source (file-path or http URL) to use.
+     *
+     * @param path the path of the file, or the http URL of the stream
+     *
+     * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
+     * process other than the calling application.  This implies that the pathname
+     * should be an absolute path (as any other process runs with unspecified current working
+     * directory), and that the pathname should reference a world-readable file.
+     * As an alternative, the application could first open the file for reading,
+     * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
+     */
+    public final void setDataSource(String path) {
+        setDataSource(path, null, null);
+    }
+
+    /**
+     * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
+     * to close the file descriptor. It is safe to do so as soon as this call returns.
+     *
+     * @param fd the FileDescriptor for the file you want to extract from.
+     */
+    public final void setDataSource(FileDescriptor fd) {
+        setDataSource(fd, 0, 0x7ffffffffffffffL);
+    }
+
+    /**
+     * Sets the data source (FileDescriptor) to use.  The FileDescriptor must be
+     * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+     * to close the file descriptor. It is safe to do so as soon as this call returns.
+     *
+     * @param fd the FileDescriptor for the file you want to extract from.
+     * @param offset the offset into the file where the data to be extracted starts, in bytes
+     * @param length the length in bytes of the data to be extracted
+     */
+    public native final void setDataSource(
+            FileDescriptor fd, long offset, long length);
+
     @Override
     protected void finalize() {
         native_finalize();
     }
 
-    // Make sure you call this when you're done to free up any resources
-    // instead of relying on the garbage collector to do this for you at
-    // some point in the future.
+    /** Make sure you call this when you're done to free up any resources
+     *  instead of relying on the garbage collector to do this for you at
+     *   some point in the future.
+    */
     public native final void release();
 
+    /** Count the number of tracks found in the data source.
+     */
     public native int countTracks();
+
+    /** Get the track format at the specified index.
+      * More detail on the representation can be found at {@link android.media.MediaCodec}
+    */
     public native Map<String, Object> getTrackFormat(int index);
 
-    // Subsequent calls to "readSampleData", "getSampleTrackIndex" and
-    // "getSampleTime" only retrieve information for the subset of tracks
-    // selected by the call below.
-    // Selecting the same track multiple times has no effect, the track
-    // is only selected once.
+    /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
+     *  {@link #getSampleTime} only retrieve information for the subset of tracks
+     *  selected by the call below.
+     *  Selecting the same track multiple times has no effect, the track
+     *  only selected once.
+     *  Media data will be returned in the order of their timestamps.
+    */
     public native void selectTrack(int index);
 
-    // All selected tracks seek near the requested time. The next sample
-    // returned for each selected track will be a sync sample.
+    /** All selected tracks seek near the requested time. The next sample
+     *  returned for each selected track will be a sync sample.
+    */
     public native void seekTo(long timeUs);
 
+    /** Advance to the next sample. Returns false if no more sample data
+     *  is available (end of stream).
+     */
     public native boolean advance();
 
-    // Retrieve the current encoded sample and store it in the byte buffer
-    // starting at the given offset. Returns the sample size.
+    /** Retrieve the current encoded sample and store it in the byte buffer
+     *  starting at the given offset. Returns the sample size (or -1 if
+     *  no more samples are available).
+    */
     public native int readSampleData(ByteBuffer byteBuf, int offset);
 
-    // Returns the track index the current sample originates from.
+    /** Returns the track index the current sample originates from (or -1
+     *  if no more samples are available)
+    */
     public native int getSampleTrackIndex();
 
-    // Returns the current sample's presentation time in microseconds.
+    /** Returns the current sample's presentation time in microseconds.
+     *  or -1 if no more samples are available.
+    */
     public native long getSampleTime();
 
     // Keep these in sync with their equivalents in NuMediaExtractor.h
+    /** The sample is a sync sample */
     public static final int SAMPLE_FLAG_SYNC      = 1;
+
+    /** The sample is (at least partially) encrypted, see also the documentation
+     *  for {@link android.media.MediaCodec#queueSecureInputBuffer}
+    */
     public static final int SAMPLE_FLAG_ENCRYPTED = 2;
 
-    // Returns the current sample's flags.
+    /** Returns the current sample's flags. */
     public native int getSampleFlags();
 
     private static native final void native_init();
-    private native final void native_setup(String path);
+    private native final void native_setup();
     private native final void native_finalize();
 
     static {
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a3361d4..98e1bc5 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    android_media_Crypto.cpp \
+    android_media_MediaCrypto.cpp \
     android_media_MediaCodec.cpp \
     android_media_MediaCodecList.cpp \
     android_media_MediaExtractor.cpp \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 01d3833..979ffb0 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -20,7 +20,7 @@
 
 #include "android_media_MediaCodec.h"
 
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
 #include "android_media_Utils.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_view_Surface.h"
@@ -656,7 +656,7 @@
 
     { "native_configure",
       "([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
-      "Landroid/media/Crypto;I)V",
+      "Landroid/media/MediaCrypto;I)V",
       (void *)android_media_MediaCodec_native_configure },
 
     { "start", "()V", (void *)android_media_MediaCodec_start },
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 2b8f91e..7139560 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -118,10 +118,10 @@
         env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
 
     jfieldID profileField =
-        env->GetFieldID(profileLevelClazz, "mProfile", "I");
+        env->GetFieldID(profileLevelClazz, "profile", "I");
 
     jfieldID levelField =
-        env->GetFieldID(profileLevelClazz, "mLevel", "I");
+        env->GetFieldID(profileLevelClazz, "level", "I");
 
     for (size_t i = 0; i < profileLevels.size(); ++i) {
         const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
@@ -139,7 +139,7 @@
 
     jfieldID profileLevelsField = env->GetFieldID(
             capsClazz,
-            "mProfileLevels",
+            "profileLevels",
             "[Landroid/media/MediaCodecList$CodecProfileLevel;");
 
     env->SetObjectField(caps, profileLevelsField, profileLevelArray);
@@ -155,7 +155,7 @@
     }
 
     jfieldID colorFormatsField = env->GetFieldID(
-            capsClazz, "mColorFormats", "[I");
+            capsClazz, "colorFormats", "[I");
 
     env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
 
diff --git a/media/jni/android_media_Crypto.cpp b/media/jni/android_media_MediaCrypto.cpp
similarity index 80%
rename from media/jni/android_media_Crypto.cpp
rename to media/jni/android_media_MediaCrypto.cpp
index e1a60a1..b0ba307 100644
--- a/media/jni/android_media_Crypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -15,10 +15,10 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Crypto-JNI"
+#define LOG_TAG "MediaCrypto-JNI"
 #include <utils/Log.h>
 
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
 
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
@@ -124,7 +124,7 @@
 
 // static
 sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
-    jclass clazz = env->FindClass("android/media/Crypto");
+    jclass clazz = env->FindClass("android/media/MediaCrypto");
     CHECK(clazz != NULL);
 
     if (!env->IsInstanceOf(obj, clazz)) {
@@ -158,19 +158,19 @@
     return old;
 }
 
-static void android_media_Crypto_release(JNIEnv *env, jobject thiz) {
+static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
     setCrypto(env, thiz, NULL);
 }
 
-static void android_media_Crypto_native_init(JNIEnv *env) {
-    jclass clazz = env->FindClass("android/media/Crypto");
+static void android_media_MediaCrypto_native_init(JNIEnv *env) {
+    jclass clazz = env->FindClass("android/media/MediaCrypto");
     CHECK(clazz != NULL);
 
     gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
     CHECK(gFields.context != NULL);
 }
 
-static void android_media_Crypto_native_setup(
+static void android_media_MediaCrypto_native_setup(
         JNIEnv *env, jobject thiz,
         jbyteArray uuidObj, jbyteArray initDataObj) {
     jsize uuidLength = env->GetArrayLength(uuidObj);
@@ -186,16 +186,23 @@
     jboolean isCopy;
     jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
 
-    jsize initDataLength = env->GetArrayLength(initDataObj);
-    jbyte *initData = env->GetByteArrayElements(initDataObj, &isCopy);
+    jsize initDataLength = 0;
+    jbyte *initData = NULL;
+
+    if (initDataObj != NULL) {
+        initDataLength = env->GetArrayLength(initDataObj);
+        initData = env->GetByteArrayElements(initDataObj, &isCopy);
+    }
 
     sp<JCrypto> crypto = new JCrypto(
             env, thiz, (const uint8_t *)uuid, initData, initDataLength);
 
     status_t err = crypto->initCheck();
 
-    env->ReleaseByteArrayElements(initDataObj, initData, 0);
-    initData = NULL;
+    if (initDataObj != NULL) {
+        env->ReleaseByteArrayElements(initDataObj, initData, 0);
+        initData = NULL;
+    }
 
     env->ReleaseByteArrayElements(uuidObj, uuid, 0);
     uuid = NULL;
@@ -211,12 +218,12 @@
     setCrypto(env,thiz, crypto);
 }
 
-static void android_media_Crypto_native_finalize(
+static void android_media_MediaCrypto_native_finalize(
         JNIEnv *env, jobject thiz) {
-    android_media_Crypto_release(env, thiz);
+    android_media_MediaCrypto_release(env, thiz);
 }
 
-static jboolean android_media_Crypto_isCryptoSchemeSupported(
+static jboolean android_media_MediaCrypto_isCryptoSchemeSupported(
         JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
     jsize uuidLength = env->GetArrayLength(uuidObj);
 
@@ -239,7 +246,7 @@
     return result;
 }
 
-static jboolean android_media_Crypto_requiresSecureDecoderComponent(
+static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
         JNIEnv *env, jobject thiz, jstring mimeObj) {
     if (mimeObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -268,24 +275,24 @@
 }
 
 static JNINativeMethod gMethods[] = {
-    { "release", "()V", (void *)android_media_Crypto_release },
-    { "native_init", "()V", (void *)android_media_Crypto_native_init },
+    { "release", "()V", (void *)android_media_MediaCrypto_release },
+    { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
 
     { "native_setup", "([B[B)V",
-      (void *)android_media_Crypto_native_setup },
+      (void *)android_media_MediaCrypto_native_setup },
 
     { "native_finalize", "()V",
-      (void *)android_media_Crypto_native_finalize },
+      (void *)android_media_MediaCrypto_native_finalize },
 
     { "isCryptoSchemeSupported", "([B)Z",
-      (void *)android_media_Crypto_isCryptoSchemeSupported },
+      (void *)android_media_MediaCrypto_isCryptoSchemeSupported },
 
     { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
-      (void *)android_media_Crypto_requiresSecureDecoderComponent },
+      (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
 };
 
 int register_android_media_Crypto(JNIEnv *env) {
     return AndroidRuntime::registerNativeMethods(env,
-                "android/media/Crypto", gMethods, NELEM(gMethods));
+                "android/media/MediaCrypto", gMethods, NELEM(gMethods));
 }
 
diff --git a/media/jni/android_media_Crypto.h b/media/jni/android_media_MediaCrypto.h
similarity index 100%
rename from media/jni/android_media_Crypto.h
rename to media/jni/android_media_MediaCrypto.h
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 8c661b7..9883962 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -63,8 +63,13 @@
     mClass = NULL;
 }
 
-status_t JMediaExtractor::setDataSource(const char *path) {
-    return mImpl->setDataSource(path);
+status_t JMediaExtractor::setDataSource(
+        const char *path, const KeyedVector<String8, String8> *headers) {
+    return mImpl->setDataSource(path, headers);
+}
+
+status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+    return mImpl->setDataSource(fd, offset, size);
 }
 
 size_t JMediaExtractor::countTracks() const {
@@ -200,7 +205,7 @@
 
     if (extractor == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
-        return NULL;
+        return -1;
     }
 
     return extractor->countTracks();
@@ -380,24 +385,42 @@
 }
 
 static void android_media_MediaExtractor_native_setup(
-        JNIEnv *env, jobject thiz, jstring path) {
+        JNIEnv *env, jobject thiz) {
     sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
+    setMediaExtractor(env,thiz, extractor);
+}
 
-    if (path == NULL) {
+static void android_media_MediaExtractor_setDataSource(
+        JNIEnv *env, jobject thiz,
+        jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (pathObj == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
         return;
     }
 
-    const char *tmp = env->GetStringUTFChars(path, NULL);
-
-    if (tmp == NULL) {
+    KeyedVector<String8, String8> headers;
+    if (!ConvertKeyValueArraysToKeyedVector(
+                env, keysArray, valuesArray, &headers)) {
         return;
     }
 
-    status_t err = extractor->setDataSource(tmp);
+    const char *path = env->GetStringUTFChars(pathObj, NULL);
 
-    env->ReleaseStringUTFChars(path, tmp);
-    tmp = NULL;
+    if (path == NULL) {
+        return;
+    }
+
+    status_t err = extractor->setDataSource(path, &headers);
+
+    env->ReleaseStringUTFChars(pathObj, path);
+    path = NULL;
 
     if (err != OK) {
         jniThrowException(
@@ -406,8 +429,34 @@
                 "Failed to instantiate extractor.");
         return;
     }
+}
 
-    setMediaExtractor(env,thiz, extractor);
+static void android_media_MediaExtractor_setDataSourceFd(
+        JNIEnv *env, jobject thiz,
+        jobject fileDescObj, jlong offset, jlong length) {
+    sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+    if (extractor == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    if (fileDescObj == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
+
+    status_t err = extractor->setDataSource(fd, offset, length);
+
+    if (err != OK) {
+        jniThrowException(
+                env,
+                "java/io/IOException",
+                "Failed to instantiate extractor.");
+        return;
+    }
 }
 
 static void android_media_MediaExtractor_native_finalize(
@@ -443,11 +492,18 @@
 
     { "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
 
-    { "native_setup", "(Ljava/lang/String;)V",
+    { "native_setup", "()V",
       (void *)android_media_MediaExtractor_native_setup },
 
     { "native_finalize", "()V",
       (void *)android_media_MediaExtractor_native_finalize },
+
+    { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
+                       "[Ljava/lang/String;)V",
+      (void *)android_media_MediaExtractor_setDataSource },
+
+    { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
+      (void *)android_media_MediaExtractor_setDataSourceFd },
 };
 
 int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 49a64d6..1aacea2 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,7 +19,9 @@
 
 #include <media/stagefright/foundation/ABase.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 #include "jni.h"
 
@@ -30,7 +32,11 @@
 struct JMediaExtractor : public RefBase {
     JMediaExtractor(JNIEnv *env, jobject thiz);
 
-    status_t setDataSource(const char *path);
+    status_t setDataSource(
+            const char *path,
+            const KeyedVector<String8, String8> *headers);
+
+    status_t setDataSource(int fd, off64_t offset, off64_t size);
 
     size_t countTracks() const;
     status_t getTrackFormat(size_t index, jobject *format) const;
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 1190448..a4d88ff 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -85,6 +85,16 @@
     return env->NewObject(clazz, integerConstructID, value);
 }
 
+static jobject makeLongObject(JNIEnv *env, int64_t value) {
+    jclass clazz = env->FindClass("java/lang/Long");
+    CHECK(clazz != NULL);
+
+    jmethodID longConstructID = env->GetMethodID(clazz, "<init>", "(J)V");
+    CHECK(longConstructID != NULL);
+
+    return env->NewObject(clazz, longConstructID, value);
+}
+
 static jobject makeFloatObject(JNIEnv *env, float value) {
     jclass clazz = env->FindClass("java/lang/Float");
     CHECK(clazz != NULL);
@@ -158,6 +168,15 @@
                 break;
             }
 
+            case AMessage::kTypeInt64:
+            {
+                int64_t val;
+                CHECK(msg->findInt64(key, &val));
+
+                valueObj = makeLongObject(env, val);
+                break;
+            }
+
             case AMessage::kTypeFloat:
             {
                 float val;