From 3ac90867acd483d0de4b916ba8096f7f3d686d33 Mon Sep 17 00:00:00 2001 From: Youness Alaoui Date: Wed, 28 Nov 2012 20:53:51 -0500 Subject: [PATCH] androidmedia: Use gst-dvm and refactor java wrappers (WIP) Moved the java wrapper API into its own files and made use of the gst-dvm macros. Also renamed the API to have the proper naming convention and coding style in order to match the one in androidcamera. This is a work in progress! "android/media/MediaCodecList" is still missing and the actual elements have not been ported to use the new function names. --- .../gst-android-media-mediacodec.c | 533 ++++++++++++++++ .../gst-android-media-mediacodec.h | 89 +++ .../gst-android-media-mediaformat.c | 602 ++++++++++++++++++ .../gst-android-media-mediaformat.h | 75 +++ 4 files changed, 1299 insertions(+) create mode 100644 sys/androidmedia/gst-android-media-mediacodec.c create mode 100644 sys/androidmedia/gst-android-media-mediacodec.h create mode 100644 sys/androidmedia/gst-android-media-mediaformat.c create mode 100644 sys/androidmedia/gst-android-media-mediaformat.h diff --git a/sys/androidmedia/gst-android-media-mediacodec.c b/sys/androidmedia/gst-android-media-mediacodec.c new file mode 100644 index 0000000000..9e9bd2451b --- /dev/null +++ b/sys/androidmedia/gst-android-media-mediacodec.c @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Author: Youness Alaoui + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gst-android-media-mediacodec.h" + + +static struct +{ + jclass klass; + jmethodID constructor; + jfieldID flags; + jfieldID offset; + jfieldID presentationTimeUs; + jfieldID size; +} android_media_mediacodec_bufferinfo; + +static struct +{ + jclass klass; + jmethodID configure; + jmethodID createByCodecName; + jmethodID createDecoderByType; + jmethodID createEncoderByType; + jmethodID dequeueInputBuffer; + jmethodID dequeueOutputBuffer; + jmethodID flush; + jmethodID getInputBuffers; + jmethodID getOutputBuffers; + jmethodID getOutputFormat; + jmethodID queueInputBuffer; + jmethodID release; + jmethodID releaseOutputBuffer; + jmethodID start; + jmethodID stop; +} android_media_mediacodec = { +0}; + + + +static gboolean +_init_classes (void) +{ + JNIEnv *env = gst_dvm_get_env (); + + /* android.media.MediaCodec */ + GST_DVM_GET_CLASS (android_media_mediacodec, "android/media/MediaCodec"); + GST_DVM_GET_STATIC_METHOD (android_media_mediacodec, createByCodecName, + "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + GST_DVM_GET_STATIC_METHOD (android_media_mediacodec, createDecoderByType, + "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + GST_DVM_GET_STATIC_METHOD (android_media_mediacodec, createEncoderByType, + "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + GST_DVM_GET_METHOD (android_media_mediacodec, configure, + "(Landroid/media/MediaFormat;Landroid/view/Surface;" + "Landroid/media/MediaCrypto;I)V"); + GST_DVM_GET_METHOD (android_media_mediacodec, dequeueInputBuffer, "(J)I"); + GST_DVM_GET_METHOD (android_media_mediacodec, dequeueOutputBuffer, + "(Landroid/media/MediaCodec$BufferInfo;J)I"); + GST_DVM_GET_METHOD (android_media_mediacodec, flush, "()V"); + GST_DVM_GET_METHOD (android_media_mediacodec, getInputBuffers, + "()[Ljava/nio/ByteBuffer;"); + GST_DVM_GET_METHOD (android_media_mediacodec, getOutputBuffers, + "()[Ljava/nio/ByteBuffer;"); + GST_DVM_GET_METHOD (android_media_mediacodec, getOutputFormat, + "()Landroid/media/MediaFormat;"); + GST_DVM_GET_METHOD (android_media_mediacodec, queueInputBuffer, "(IIIJI)V"); + GST_DVM_GET_METHOD (android_media_mediacodec, release, "()V"); + GST_DVM_GET_METHOD (android_media_mediacodec, releaseOutputBuffer, "(IZ)V"); + GST_DVM_GET_METHOD (android_media_mediacodec, start, "()V"); + GST_DVM_GET_METHOD (android_media_mediacodec, stop, "()V"); + + /* android.media.MediaCodec.BufferInfo */ + GST_DVM_GET_CLASS (android_media_mediacodec_bufferinfo, + "android/media/MediaCodec$BufferInfo"); + GST_DVM_GET_CONSTRUCTOR (android_media_mediacodec_bufferinfo, constructor, + "()V"); + GST_DVM_GET_FIELD (android_media_mediacodec_bufferinfo, flags, "I"); + GST_DVM_GET_FIELD (android_media_mediacodec_bufferinfo, offset, "I"); + GST_DVM_GET_FIELD (android_media_mediacodec_bufferinfo, presentationTimeUs, + "J"); + GST_DVM_GET_FIELD (android_media_mediacodec_bufferinfo, size, "I"); + + return TRUE; +} + +gboolean +gst_android_media_mediacodec_init (void) +{ + if (!_init_classes ()) { + gst_android_media_mediacodec_deinit (); + return FALSE; + } + + return TRUE; +} + +void +gst_android_media_mediacodec_deinit (void) +{ + JNIEnv *env = gst_dvm_get_env (); + + if (android_media_mediacodec.klass) + (*env)->DeleteGlobalRef (env, android_media_mediacodec.klass); + android_media_mediacodec.klass = NULL; + + if (android_media_mediacodec_bufferinfo.klass) + (*env)->DeleteGlobalRef (env, android_media_mediacodec_bufferinfo.klass); + android_media_mediacodec_bufferinfo.klass = NULL; +} + +/* android.media.MediaCodec */ + +#define AMMC_CALL(error_statement, type, method, ...) \ + GST_DVM_CALL (error_statement, self->object, type, \ + android_media_mediacodec, method, ## __VA_ARGS__); +#define AMMC_STATIC_CALL(error_statement, type, method, ...) \ + GST_DVM_STATIC_CALL (error_statement, type, \ + android_media_mediacodec, method, ## __VA_ARGS__); + +gboolean +gst_am_mediacodec_configure (GstAmMediaCodec * self, GstAmMediaFormat * format, + gint flags) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (format != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, configure, format->object, NULL, NULL, flags); + + return TRUE; +} + +GstAmMediaCodec * +gst_am_mediacodec_create_by_codec_name (const gchar * name) +{ + JNIEnv *env = gst_dvm_get_env (); + GstAmMediaCodec *codec = NULL; + jobject object = NULL; + jstring name_str; + + g_return_val_if_fail (name != NULL, NULL); + + name_str = (*env)->NewStringUTF (env, name); + if (name_str == NULL) + goto done; + + object = AMMC_STATIC_CALL (goto done, Object, createByCodecName, name_str); + if (object) { + codec = g_slice_new0 (GstAmMediaCodec); + codec->object = (*env)->NewGlobalRef (env, object); + (*env)->DeleteLocalRef (env, object); + if (!codec->object) { + GST_ERROR ("Failed to create global reference"); + (*env)->ExceptionClear (env); + g_slice_free (GstAmMediaCodec, codec); + codec = NULL; + } + } + +done: + if (name_str) + (*env)->DeleteLocalRef (env, name_str); + + return codec; +} + + +GstAmMediaFormat * +gst_am_mediacodec_get_output_format (GstAmMediaCodec * self) +{ + JNIEnv *env = gst_dvm_get_env (); + GstAmMediaFormat *format = NULL; + jobject object = NULL; + + g_return_val_if_fail (self != NULL, NULL); + + object = AMMC_CALL (return NULL, Object, getOutputFormat); + if (object) { + format = g_slice_new0 (GstAmMediaFormat); + format->object = (*env)->NewGlobalRef (env, object); + (*env)->DeleteLocalRef (env, object); + if (!format->object) { + GST_ERROR ("Failed to create global reference"); + (*env)->ExceptionClear (env); + g_slice_free (GstAmMediaFormat, format); + return NULL; + } + } + + return format; +} + +gboolean +gst_am_mediacodec_start (GstAmMediaCodec * self) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, start); + + return TRUE; +} + +gboolean +gst_am_mediacodec_stop (GstAmMediaCodec * self) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, stop); + + return TRUE; +} + +gboolean +gst_am_mediacodec_flush (GstAmMediaCodec * self) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, flush); + + return TRUE; +} + +void +gst_am_mediacodec_release (GstAmMediaCodec * self) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_if_fail (self != NULL); + + AMMC_CALL (, Void, release); + + (*env)->DeleteGlobalRef (env, self->object); + g_slice_free (GstAmMediaCodec, self); +} + +void +gst_am_mediacodec_free_buffers (GstAmcBuffer * buffers, gsize n_buffers) +{ + JNIEnv *env = gst_dvm_get_env (); + jsize i; + + g_return_if_fail (buffers != NULL); + + for (i = 0; i < n_buffers; i++) { + if (buffers[i].object) + (*env)->DeleteGlobalRef (env, buffers[i].object); + } + g_free (buffers); +} + +GstAmcBuffer * +gst_am_mediacodec_get_output_buffers (GstAmMediaCodec * self, gsize * n_buffers) +{ + JNIEnv *env = gst_dvm_get_env (); + jobject output_buffers = NULL; + jsize n_output_buffers; + GstAmcBuffer *ret = NULL; + jsize i; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (n_buffers != NULL, NULL); + + *n_buffers = 0; + output_buffers = AMMC_CALL (goto done, Object, getOutputBuffers); + if (!output_buffers) + goto done; + + n_output_buffers = (*env)->GetArrayLength (env, output_buffers); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get output buffers array length"); + goto done; + } + + *n_buffers = n_output_buffers; + ret = g_new0 (GstAmcBuffer, n_output_buffers); + + for (i = 0; i < n_output_buffers; i++) { + jobject buffer = NULL; + + buffer = (*env)->GetObjectArrayElement (env, output_buffers, i); + if ((*env)->ExceptionCheck (env) || !buffer) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get output buffer %d", i); + goto error; + } + + ret[i].object = (*env)->NewGlobalRef (env, buffer); + (*env)->DeleteLocalRef (env, buffer); + if (!ret[i].object) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to create global reference %d", i); + goto error; + } + + ret[i].data = (*env)->GetDirectBufferAddress (env, ret[i].object); + if (!ret[i].data) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer address %d", i); + goto error; + } + ret[i].size = (*env)->GetDirectBufferCapacity (env, ret[i].object); + } + +done: + if (output_buffers) + (*env)->DeleteLocalRef (env, output_buffers); + output_buffers = NULL; + + return ret; +error: + if (ret) + gst_am_mediacodec_free_buffers (ret, n_output_buffers); + ret = NULL; + *n_buffers = 0; + goto done; +} + +GstAmcBuffer * +gst_am_mediacodec_get_input_buffers (GstAmMediaCodec * self, gsize * n_buffers) +{ + JNIEnv *env = gst_dvm_get_env (); + jobject input_buffers = NULL; + jsize n_input_buffers; + GstAmcBuffer *ret = NULL; + jsize i; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (n_buffers != NULL, NULL); + + *n_buffers = 0; + + input_buffers = AMMC_CALL (goto done, Object, getOutputBuffers); + if (!input_buffers) + goto done; + + n_input_buffers = (*env)->GetArrayLength (env, input_buffers); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get input buffers array length"); + goto done; + } + + *n_buffers = n_input_buffers; + ret = g_new0 (GstAmcBuffer, n_input_buffers); + + for (i = 0; i < n_input_buffers; i++) { + jobject buffer = NULL; + + buffer = (*env)->GetObjectArrayElement (env, input_buffers, i); + if ((*env)->ExceptionCheck (env) || !buffer) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get input buffer %d", i); + goto error; + } + + ret[i].object = (*env)->NewGlobalRef (env, buffer); + (*env)->DeleteLocalRef (env, buffer); + if (!ret[i].object) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to create global reference %d", i); + goto error; + } + + ret[i].data = (*env)->GetDirectBufferAddress (env, ret[i].object); + if (!ret[i].data) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer address %d", i); + goto error; + } + ret[i].size = (*env)->GetDirectBufferCapacity (env, ret[i].object); + } + +done: + if (input_buffers) + (*env)->DeleteLocalRef (env, input_buffers); + input_buffers = NULL; + + return ret; +error: + if (ret) + gst_am_mediacodec_free_buffers (ret, n_input_buffers); + ret = NULL; + *n_buffers = 0; + goto done; +} + +gint +gst_am_mediacodec_dequeue_input_buffer (GstAmMediaCodec * self, + gint64 timeoutUs) +{ + JNIEnv *env = gst_dvm_get_env (); + gint ret = G_MININT; + + g_return_val_if_fail (self != NULL, G_MININT); + + ret = AMMC_CALL (return G_MININT, Int, dequeueInputBuffer, timeoutUs); + + return ret; +} + +static gboolean +_fill_buffer_info (JNIEnv * env, jobject buffer_info, GstAmmcBufferInfo * info) +{ + g_return_val_if_fail (buffer_info != NULL, FALSE); + + info->flags = (*env)->GetIntField (env, buffer_info, + android_media_mediacodec_bufferinfo.flags); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer info field"); + return FALSE; + } + + info->offset = (*env)->GetIntField (env, buffer_info, + android_media_mediacodec_bufferinfo.offset); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer info field"); + return FALSE; + } + + info->presentation_time_us = (*env)->GetLongField (env, buffer_info, + android_media_mediacodec_bufferinfo.presentationTimeUs); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer info field"); + return FALSE; + } + + info->size = (*env)->GetIntField (env, buffer_info, + android_media_mediacodec_bufferinfo.size); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer info field"); + return FALSE; + } + + return TRUE; +} + +gint +gst_am_mediacodec_dequeue_output_buffer (GstAmMediaCodec * self, + GstAmmcBufferInfo * info, gint64 timeoutUs) +{ + JNIEnv *env = gst_dvm_get_env (); + gint ret = G_MININT; + jobject info_o = NULL; + + g_return_val_if_fail (self != NULL, G_MININT); + + info_o = (*env)->NewObject (env, android_media_mediacodec_bufferinfo.klass, + android_media_mediacodec_bufferinfo.constructor); + if (!info_o) { + GST_ERROR ("Failed to call Java method"); + (*env)->ExceptionClear (env); + goto done; + } + + ret = AMMC_CALL (goto error, Int, dequeueOutputBuffer, info_o, timeoutUs); + + if (!_fill_buffer_info (env, info_o, info)) + goto error; + +done: + if (info_o) + (*env)->DeleteLocalRef (env, info_o); + info_o = NULL; + + return ret; + +error: + ret = G_MININT; + goto done; +} + +gboolean +gst_am_mediacodec_queue_input_buffer (GstAmMediaCodec * self, gint index, + const GstAmmcBufferInfo * info) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, queueInputBuffer, index, info->offset, + info->size, info->presentation_time_us, info->flags); + + return TRUE; +} + +gboolean +gst_am_mediacodec_release_output_buffer (GstAmMediaCodec * self, gint index) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_val_if_fail (self != NULL, FALSE); + + AMMC_CALL (return FALSE, Void, releaseOutputBuffer, index, JNI_FALSE); + + return TRUE; +} diff --git a/sys/androidmedia/gst-android-media-mediacodec.h b/sys/androidmedia/gst-android-media-mediacodec.h new file mode 100644 index 0000000000..4e242615d7 --- /dev/null +++ b/sys/androidmedia/gst-android-media-mediacodec.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Author: Youness Alaoui + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GST_ANDROID_MEDIA_MEDIACODEC_H__ +#define __GST_ANDROID_MEDIA_MEDIACODEC_H__ + +#include +#include + +#include "gst-android-media-mediaformat.h" + +G_BEGIN_DECLS + +typedef struct _GstAmcBuffer GstAmcBuffer; +typedef struct _GstAmmcBufferInfo GstAmmcBufferInfo; +typedef struct _GstAmMediaCodec GstAmMediaCodec; + +struct _GstAmcBuffer { + guint8 *data; + gsize size; + /*< private >*/ + jobject object; /* global reference */ +}; + +struct _GstAmmcBufferInfo { + gint flags; + gint offset; + gint64 presentation_time_us; + gint size; +}; + +struct _GstAmMediaCodec { + /*< private >*/ + jobject object; /* global reference */ +}; + +gboolean gst_android_media_mediacodec_init (void); +void gst_android_media_mediacodec_deinit (void); + +gboolean gst_am_mediacodec_configure (GstAmMediaCodec * self, + GstAmMediaFormat * format, gint flags); + +GstAmMediaCodec * gst_am_mediacodec_create_by_codec_name (const gchar *name); +GstAmMediaCodec * gst_am_mediacodec_create_decoder_by_type (const gchar *type); +GstAmMediaCodec * gst_am_mediacodec_create_encoder_by_type (const gchar *type); + +gint gst_am_mediacodec_dequeue_input_buffer (GstAmMediaCodec * self, + gint64 timeoutUs); +gint gst_am_mediacodec_dequeue_output_buffer (GstAmMediaCodec * self, + GstAmmcBufferInfo *info, gint64 timeoutUs); +gboolean gst_am_mediacodec_flush (GstAmMediaCodec * self); + +GstAmcBuffer * gst_am_mediacodec_get_input_buffers (GstAmMediaCodec * self, + gsize * n_buffers); +GstAmcBuffer * gst_am_mediacodec_get_output_buffers (GstAmMediaCodec * self, + gsize * n_buffers); +void gst_am_mediacodec_free_buffers (GstAmcBuffer * buffers, gsize n_buffers); +GstAmMediaFormat * gst_am_mediacodec_get_output_format (GstAmMediaCodec * self); + +gboolean gst_am_mediacodec_queue_input_buffer (GstAmMediaCodec * self, + gint index, const GstAmmcBufferInfo *info); +void gst_am_mediacodec_release (GstAmMediaCodec * self); +gboolean gst_am_mediacodec_release_output_buffer (GstAmMediaCodec * self, + gint index); + +gboolean gst_am_mediacodec_start (GstAmMediaCodec * self); +gboolean gst_am_mediacodec_stop (GstAmMediaCodec * self); + +G_END_DECLS + +#endif /* __GST_ANDROID_MEDIA_MEDIACODEC_H__ */ diff --git a/sys/androidmedia/gst-android-media-mediaformat.c b/sys/androidmedia/gst-android-media-mediaformat.c new file mode 100644 index 0000000000..e4e9eadb34 --- /dev/null +++ b/sys/androidmedia/gst-android-media-mediaformat.c @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Author: Youness Alaoui + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gst-android-media-mediaformat.h" + +static struct +{ + jclass klass; + jmethodID constructor; + jmethodID containsKey; + jmethodID createAudioFormat; + jmethodID createVideoFormat; + jmethodID getByteBuffer; + jmethodID getFloat; + jmethodID getInteger; + jmethodID getLong; + jmethodID getString; + jmethodID setByteBuffer; + jmethodID setFloat; + jmethodID setInteger; + jmethodID setLong; + jmethodID setString; + jmethodID toString; +} android_media_mediaformat; + + +static gboolean +_init_classes (void) +{ + JNIEnv *env = gst_dvm_get_env (); + + /* android.media.MediaFormat */ + GST_DVM_GET_CLASS (android_media_mediaformat, "android/media/MediaFormat"); + GST_DVM_GET_CONSTRUCTOR (android_media_mediaformat, constructor, "()V"); + GST_DVM_GET_STATIC_METHOD (android_media_mediaformat, createAudioFormat, + "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + GST_DVM_GET_STATIC_METHOD (android_media_mediaformat, createVideoFormat, + "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + GST_DVM_GET_METHOD (android_media_mediaformat, toString, + "()Ljava/lang/String;"); + GST_DVM_GET_METHOD (android_media_mediaformat, containsKey, + "(Ljava/lang/String;)Z"); + GST_DVM_GET_METHOD (android_media_mediaformat, getFloat, + "(Ljava/lang/String;)F"); + GST_DVM_GET_METHOD (android_media_mediaformat, setFloat, + "(Ljava/lang/String;F)V"); + GST_DVM_GET_METHOD (android_media_mediaformat, getInteger, + "(Ljava/lang/String;)I"); + GST_DVM_GET_METHOD (android_media_mediaformat, setInteger, + "(Ljava/lang/String;I)V"); + GST_DVM_GET_METHOD (android_media_mediaformat, getLong, + "(Ljava/lang/String;)J"); + GST_DVM_GET_METHOD (android_media_mediaformat, setLong, + "(Ljava/lang/String;J)V"); + GST_DVM_GET_METHOD (android_media_mediaformat, getString, + "(Ljava/lang/String;)Ljava/lang/String;"); + GST_DVM_GET_METHOD (android_media_mediaformat, setString, + "(Ljava/lang/String;Ljava/lang/String;)V"); + GST_DVM_GET_METHOD (android_media_mediaformat, getByteBuffer, + "(Ljava/lang/String;)Ljava/nio/ByteBuffer;"); + GST_DVM_GET_METHOD (android_media_mediaformat, setByteBuffer, + "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"); + + return TRUE; +} + +gboolean +gst_android_media_mediaformat_init (void) +{ + if (!_init_classes ()) { + gst_android_media_mediaformat_deinit (); + return FALSE; + } + + return TRUE; +} + +void +gst_android_media_mediaformat_deinit (void) +{ + JNIEnv *env = gst_dvm_get_env (); + + if (android_media_mediaformat.klass) + (*env)->DeleteGlobalRef (env, android_media_mediaformat.klass); + android_media_mediaformat.klass = NULL; +} + +/* android.media.MediaFormat */ +#define AMMF_CALL(error_statement, type, method, ...) \ + GST_DVM_CALL (error_statement, self->object, type, \ + android_media_mediaformat, method, ## __VA_ARGS__); +#define AMMF_STATIC_CALL(error_statement, type, method, ...) \ + GST_DVM_STATIC_CALL (error_statement, type, \ + android_media_mediaformat, method, ## __VA_ARGS__); + +GstAmMediaFormat * +gst_am_mediaformat_new (void) +{ + JNIEnv *env = gst_dvm_get_env (); + GstAmMediaFormat *format = NULL; + jobject object = NULL; + + object = (*env)->NewObject (env, android_media_mediaformat.klass, + android_media_mediaformat.constructor); + if ((*env)->ExceptionCheck (env) || !object) { + GST_ERROR ("Failed to create callback object"); + (*env)->ExceptionClear (env); + return NULL; + } + + format = g_slice_new0 (GstAmMediaFormat); + format->object = (*env)->NewGlobalRef (env, object); + (*env)->DeleteLocalRef (env, object); + if (!format->object) { + GST_ERROR ("Failed to create global reference"); + (*env)->ExceptionClear (env); + g_slice_free (GstAmMediaFormat, format); + return NULL; + } + + return format; +} + +GstAmMediaFormat * +gst_am_mediaformat_create_audio_format (const gchar * mime, + gint sample_rate, gint channels) +{ + JNIEnv *env = gst_dvm_get_env (); + GstAmMediaFormat *format = NULL; + jstring mime_str; + jobject object = NULL; + + g_return_val_if_fail (mime != NULL, NULL); + + mime_str = (*env)->NewStringUTF (env, mime); + if (mime_str == NULL) + goto done; + + object = AMMF_STATIC_CALL (goto done, Object, createAudioFormat, mime_str, + sample_rate, channels); + if (object) { + format = g_slice_new0 (GstAmMediaFormat); + format->object = (*env)->NewGlobalRef (env, object); + (*env)->DeleteLocalRef (env, object); + if (!format->object) { + GST_ERROR ("Failed to create global reference"); + (*env)->ExceptionClear (env); + g_slice_free (GstAmMediaFormat, format); + format = NULL; + } + } + +done: + if (mime_str) + (*env)->DeleteLocalRef (env, mime_str); + + return format; +} + +GstAmMediaFormat * +gst_am_mediaformat_create_video_format (const gchar * mime, + gint width, gint height) +{ + JNIEnv *env = gst_dvm_get_env (); + GstAmMediaFormat *format = NULL; + jstring mime_str; + jobject object = NULL; + + g_return_val_if_fail (mime != NULL, NULL); + + mime_str = (*env)->NewStringUTF (env, mime); + if (mime_str == NULL) + goto done; + + object = AMMF_STATIC_CALL (goto done, Object, createVideoFormat, mime_str, + width, height); + if (object) { + format = g_slice_new0 (GstAmMediaFormat); + format->object = (*env)->NewGlobalRef (env, object); + (*env)->DeleteLocalRef (env, object); + if (!format->object) { + GST_ERROR ("Failed to create global reference"); + (*env)->ExceptionClear (env); + g_slice_free (GstAmMediaFormat, format); + format = NULL; + } + } + +done: + if (mime_str) + (*env)->DeleteLocalRef (env, mime_str); + + return format; +} + +void +gst_am_mediaformat_free (GstAmMediaFormat * self) +{ + JNIEnv *env = gst_dvm_get_env (); + + g_return_if_fail (self != NULL); + + (*env)->DeleteGlobalRef (env, self->object); + g_slice_free (GstAmMediaFormat, self); +} + +gchar * +gst_am_mediaformat_to_string (GstAmMediaFormat * self) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring v_str = NULL; + const gchar *v = NULL; + gchar *ret = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + + v_str = AMMF_CALL (return NULL, Object, toString); + if (v_str) { + v = (*env)->GetStringUTFChars (env, v_str, NULL); + if (!v) { + GST_ERROR ("Failed to convert string to UTF8"); + (*env)->ExceptionClear (env); + goto done; + } + ret = g_strdup (v); + } + +done: + if (v) + (*env)->ReleaseStringUTFChars (env, v_str, v); + if (v_str) + (*env)->DeleteLocalRef (env, v_str); + + return ret; +} + +gboolean +gst_am_mediaformat_contains_key (GstAmMediaFormat * self, const gchar * key) +{ + JNIEnv *env = gst_dvm_get_env (); + gboolean ret = FALSE; + jstring key_str = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + ret = AMMF_CALL (ret = FALSE; goto done, Boolean, containsKey, key_str); + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; +} + +gboolean +gst_am_mediaformat_get_float (GstAmMediaFormat * self, const gchar * key, + gfloat * value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + *value = AMMF_CALL (goto done, Float, getFloat, key_str); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; +} + +gboolean +gst_am_mediaformat_set_float (GstAmMediaFormat * self, const gchar * key, + gfloat value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + AMMF_CALL (goto done, Void, setFloat, key_str, value); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; +} + +gboolean +gst_am_mediaformat_get_int (GstAmMediaFormat * self, const gchar * key, + gint * value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + *value = AMMF_CALL (goto done, Int, getInteger, key_str); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; + +} + +gboolean +gst_am_mediaformat_set_int (GstAmMediaFormat * self, const gchar * key, + gint value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + AMMF_CALL (goto done, Void, setInteger, key_str, value); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; +} + +gboolean +gst_am_mediaformat_get_long (GstAmMediaFormat * self, const gchar * key, + glong * value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + jlong long_value; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + long_value = AMMF_CALL (goto done, Long, getLong, key_str); + *value = long_value; + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; + +} + +gboolean +gst_am_mediaformat_set_long (GstAmMediaFormat * self, const gchar * key, + glong value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + gboolean ret = FALSE; + jlong long_value = value; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + AMMF_CALL (goto done, Void, setLong, key_str, long_value); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + + return ret; +} + +gboolean +gst_am_mediaformat_get_string (GstAmMediaFormat * self, const gchar * key, + gchar ** value) +{ + JNIEnv *env = gst_dvm_get_env (); + gboolean ret = FALSE; + jstring key_str = NULL; + jstring v_str = NULL; + const gchar *v = NULL; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + v_str = AMMF_CALL (goto done, Object, getString, key_str); + + v = (*env)->GetStringUTFChars (env, v_str, NULL); + if (!v) { + GST_ERROR ("Failed to convert string to UTF8"); + (*env)->ExceptionClear (env); + goto done; + } + + *value = g_strdup (v); + + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + if (v) + (*env)->ReleaseStringUTFChars (env, v_str, v); + if (v_str) + (*env)->DeleteLocalRef (env, v_str); + + return ret; +} + +gboolean +gst_am_mediaformat_set_string (GstAmMediaFormat * self, const gchar * key, + const gchar * value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + jstring v_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + v_str = (*env)->NewStringUTF (env, value); + if (!v_str) + goto done; + + AMMF_CALL (goto done, Void, setString, key_str, v_str); + ret = TRUE; +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + if (v_str) + (*env)->DeleteLocalRef (env, v_str); + + return ret; +} + +gboolean +gst_am_mediaformat_get_buffer (GstAmMediaFormat * self, const gchar * key, + GstBuffer ** value) +{ + JNIEnv *env = gst_dvm_get_env (); + gboolean ret = FALSE; + jstring key_str = NULL; + jobject v = NULL; + guint8 *data; + gsize size; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + v = AMMF_CALL (goto done, Object, getByteBuffer, key_str); + + data = (*env)->GetDirectBufferAddress (env, v); + if (!data) { + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get buffer address"); + goto done; + } + size = (*env)->GetDirectBufferCapacity (env, v); + *value = gst_buffer_new_and_alloc (size); + memcpy (GST_BUFFER_DATA (*value), data, size); + + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + if (v) + (*env)->DeleteLocalRef (env, v); + + return ret; +} + +gboolean +gst_am_mediaformat_set_buffer (GstAmMediaFormat * self, const gchar * key, + GstBuffer * value) +{ + JNIEnv *env = gst_dvm_get_env (); + jstring key_str = NULL; + jobject v = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + + key_str = (*env)->NewStringUTF (env, key); + if (!key_str) + goto done; + + /* FIXME: The buffer must remain valid until the codec is stopped */ + v = (*env)->NewDirectByteBuffer (env, GST_BUFFER_DATA (value), + GST_BUFFER_SIZE (value)); + if (!v) + goto done; + + AMMF_CALL (goto done, Void, setByteBuffer, key_str, v); + ret = TRUE; + +done: + if (key_str) + (*env)->DeleteLocalRef (env, key_str); + if (v) + (*env)->DeleteLocalRef (env, v); + + return ret; +} diff --git a/sys/androidmedia/gst-android-media-mediaformat.h b/sys/androidmedia/gst-android-media-mediaformat.h new file mode 100644 index 0000000000..28158fccb1 --- /dev/null +++ b/sys/androidmedia/gst-android-media-mediaformat.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012, Collabora Ltd. + * Author: Sebastian Dröge + * Author: Youness Alaoui + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GST_ANDROID_MEDIA_MEDIAFORMAT_H__ +#define __GST_ANDROID_MEDIA_MEDIAFORMAT_H__ + +#include +#include + +typedef struct _GstAmMediaFormat GstAmMediaFormat; + +struct _GstAmMediaFormat { + /*< private >*/ + jobject object; /* global reference */ +}; + +G_BEGIN_DECLS + +gboolean gst_android_media_mediaformat_init (void); +void gst_android_media_mediaformat_deinit (void); + +GstAmMediaFormat * gst_am_mediaformat_new (void); +GstAmMediaFormat * gst_am_mediaformat_create_audio_format (const gchar *mime, + gint sample_rate, gint channels); +GstAmMediaFormat * gst_am_mediaformat_create_video_format (const gchar *mime, + gint width, gint height); +void gst_am_mediaformat_free (GstAmMediaFormat * self); + +gboolean gst_am_mediaformat_get_float (GstAmMediaFormat * self, + const gchar *key, gfloat *value); +gboolean gst_am_mediaformat_set_float (GstAmMediaFormat * self, + const gchar *key, gfloat value); +gboolean gst_am_mediaformat_get_int (GstAmMediaFormat * self, + const gchar *key, gint *value); +gboolean gst_am_mediaformat_set_int (GstAmMediaFormat * self, + const gchar *key, gint value); +gboolean gst_am_mediaformat_get_long (GstAmMediaFormat * self, + const gchar *key, glong *value); +gboolean gst_am_mediaformat_set_long (GstAmMediaFormat * self, + const gchar *key, glong value); +gboolean gst_am_mediaformat_get_string (GstAmMediaFormat * self, + const gchar *key, gchar **value); +gboolean gst_am_mediaformat_set_string (GstAmMediaFormat * self, + const gchar *key, const gchar *value); +gboolean gst_am_mediaformat_get_buffer (GstAmMediaFormat * self, + const gchar *key, GstBuffer **value); +gboolean gst_am_mediaformat_set_buffer (GstAmMediaFormat * self, + const gchar *key, GstBuffer *value); + + +gboolean gst_am_mediaformat_contains_key (GstAmMediaFormat * self, + const gchar *key); +gchar * gst_am_mediaformat_to_string (GstAmMediaFormat * self); + +G_END_DECLS + +#endif /* __GST_ANDROID_MEDIA_MEDIAFORMAT_H__ */