Merge "Unhide new media related java APIs."
diff --git a/api/current.txt b/api/current.txt
index 0743ad2..cd47769 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10938,6 +10938,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 >= 0) {
+ * // fill inputBuffers[inputBufferIndex] with valid data
+ * ...
+ * codec.queueInputBuffer(inputBufferIndex, ...);
+ * }
+ *
+ * int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
+ * if (outputBufferIndex >= 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 < 0 or wait up
+ * to "timeoutUs" microseconds if timeoutUs > 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 < numTracks; ++i) {
+ * Map%lt;String, Object> format = extractor.getTrackFormat(i);
+ * String mime = (String)format.get("mime");
+ * if (weAreInterestedInThisTrack) {
+ * extractor.selectTrack(i);
+ * }
+ * }
+ * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
+ * while (extractor.readSampleData(inputBuffer, ...) >= 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;