From 515398a9ff9111b298eceb12eb32fdec28fc8e64 Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Sat, 10 Nov 2018 16:51:02 -0500 Subject: [PATCH] amc: Move MediaCodec JNI wrapper into its own module This will facilitate adding another implementation based on NdkMediaCodec instead of JNI. --- sys/androidmedia/gstamc-codec.h | 74 ++ sys/androidmedia/gstamc-format.h | 52 ++ sys/androidmedia/gstamc.c | 1261 +--------------------------- sys/androidmedia/gstamc.h | 65 +- sys/androidmedia/gstjniutils.c | 235 ------ sys/androidmedia/gstjniutils.h | 17 - sys/androidmedia/jni/gstamc-codec-jni.c | 936 +++++++++++++++++++++ sys/androidmedia/jni/gstamc-format-jni.c | 571 +++++++++++++ sys/androidmedia/jni/gstamc-internal-jni.h | 49 ++ sys/androidmedia/meson.build | 4 +- 10 files changed, 1692 insertions(+), 1572 deletions(-) create mode 100644 sys/androidmedia/gstamc-codec.h create mode 100644 sys/androidmedia/gstamc-format.h create mode 100644 sys/androidmedia/jni/gstamc-codec-jni.c create mode 100644 sys/androidmedia/jni/gstamc-format-jni.c create mode 100644 sys/androidmedia/jni/gstamc-internal-jni.h diff --git a/sys/androidmedia/gstamc-codec.h b/sys/androidmedia/gstamc-codec.h new file mode 100644 index 0000000..442451aa --- /dev/null +++ b/sys/androidmedia/gstamc-codec.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * + * 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_AMC_CODEC_H__ +#define __GST_AMC_CODEC_H__ + +#include + +#include "gstamc-format.h" + +G_BEGIN_DECLS + +typedef struct _GstAmcBuffer GstAmcBuffer; +typedef struct _GstAmcBufferInfo GstAmcBufferInfo; +typedef struct _GstAmcCodec GstAmcCodec; + +struct _GstAmcBuffer { + guint8 *data; + gsize size; +}; + +struct _GstAmcBufferInfo { + gint flags; + gint offset; + gint64 presentation_time_us; + gint size; +}; + +gboolean gst_amc_codec_static_init (void); + +void gst_amc_buffer_free (GstAmcBuffer * buffer); +gboolean gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err, + gint position, gint limit); + +GstAmcCodec * gst_amc_codec_new (const gchar *name, GError **err); +void gst_amc_codec_free (GstAmcCodec * codec); + +gboolean gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format, jobject surface, gint flags, GError **err); +GstAmcFormat * gst_amc_codec_get_output_format (GstAmcCodec * codec, GError **err); + +gboolean gst_amc_codec_start (GstAmcCodec * codec, GError **err); +gboolean gst_amc_codec_stop (GstAmcCodec * codec, GError **err); +gboolean gst_amc_codec_flush (GstAmcCodec * codec, GError **err); +gboolean gst_amc_codec_release (GstAmcCodec * codec, GError **err); + +GstAmcBuffer * gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError **err); +GstAmcBuffer * gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError **err); + +gint gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs, GError **err); +gint gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, GstAmcBufferInfo *info, gint64 timeoutUs, GError **err); + +gboolean gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index, const GstAmcBufferInfo *info, GError **err); +gboolean gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index, gboolean render, GError **err); + +G_END_DECLS + +#endif /* __GST_AMC_CODEC_H__ */ diff --git a/sys/androidmedia/gstamc-format.h b/sys/androidmedia/gstamc-format.h new file mode 100644 index 0000000..da0cf26 --- /dev/null +++ b/sys/androidmedia/gstamc-format.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * + * 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_AMC_FORMAT_H__ +#define __GST_AMC_FORMAT_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GstAmcFormat GstAmcFormat; +typedef struct _GstAmcColorFormatInfo GstAmcColorFormatInfo; + +gboolean gst_amc_format_static_init (void); + +GstAmcFormat * gst_amc_format_new_audio (const gchar *mime, gint sample_rate, gint channels, GError **err); +GstAmcFormat * gst_amc_format_new_video (const gchar *mime, gint width, gint height, GError **err); +void gst_amc_format_free (GstAmcFormat * format); + +gchar * gst_amc_format_to_string (GstAmcFormat * format, GError **err); + +gboolean gst_amc_format_contains_key (GstAmcFormat *format, const gchar *key, GError **err); + +gboolean gst_amc_format_get_float (GstAmcFormat *format, const gchar *key, gfloat *value, GError **err); +gboolean gst_amc_format_set_float (GstAmcFormat *format, const gchar *key, gfloat value, GError **err); +gboolean gst_amc_format_get_int (GstAmcFormat *format, const gchar *key, gint *value, GError **err); +gboolean gst_amc_format_set_int (GstAmcFormat *format, const gchar *key, gint value, GError **err); +gboolean gst_amc_format_get_string (GstAmcFormat *format, const gchar *key, gchar **value, GError **err); +gboolean gst_amc_format_set_string (GstAmcFormat *format, const gchar *key, const gchar *value, GError **err); +gboolean gst_amc_format_get_buffer (GstAmcFormat *format, const gchar *key, guint8 **data, gsize *size, GError **err); +gboolean gst_amc_format_set_buffer (GstAmcFormat *format, const gchar *key, guint8 *data, gsize size, GError **err); + +G_END_DECLS + +#endif /* __GST_AMC_FORMAT_H__ */ diff --git a/sys/androidmedia/gstamc.c b/sys/androidmedia/gstamc.c index f28dbfd..fbf50d6 100644 --- a/sys/androidmedia/gstamc.c +++ b/sys/androidmedia/gstamc.c @@ -60,1262 +60,6 @@ static gboolean ignore_unknown_color_formats = FALSE; static gboolean accepted_color_formats (GstAmcCodecType * type, gboolean is_encoder); -/* Global cached references */ -static struct -{ - jclass klass; - jmethodID constructor; -} java_string; -static struct -{ - jclass klass; - jmethodID configure; - jmethodID create_by_codec_name; - jmethodID dequeue_input_buffer; - jmethodID dequeue_output_buffer; - jmethodID flush; - jmethodID get_input_buffers; - jmethodID get_input_buffer; - jmethodID get_output_buffers; - jmethodID get_output_buffer; - jmethodID get_output_format; - jmethodID queue_input_buffer; - jmethodID release; - jmethodID release_output_buffer; - jmethodID start; - jmethodID stop; -} media_codec; -static struct -{ - jclass klass; - jmethodID constructor; - jfieldID flags; - jfieldID offset; - jfieldID presentation_time_us; - jfieldID size; -} media_codec_buffer_info; -static struct -{ - jclass klass; - jmethodID create_audio_format; - jmethodID create_video_format; - jmethodID to_string; - jmethodID contains_key; - jmethodID get_float; - jmethodID set_float; - jmethodID get_integer; - jmethodID set_integer; - jmethodID get_string; - jmethodID set_string; - jmethodID get_byte_buffer; - jmethodID set_byte_buffer; -} media_format; - -static GstAmcBuffer *gst_amc_codec_get_input_buffers (GstAmcCodec * codec, - gsize * n_buffers, GError ** err); -static GstAmcBuffer *gst_amc_codec_get_output_buffers (GstAmcCodec * codec, - gsize * n_buffers, GError ** err); - -GstAmcCodec * -gst_amc_codec_new (const gchar * name, GError ** err) -{ - JNIEnv *env; - GstAmcCodec *codec = NULL; - jstring name_str; - jobject object = NULL; - - g_return_val_if_fail (name != NULL, NULL); - - env = gst_amc_jni_get_env (); - - name_str = gst_amc_jni_string_from_gchar (env, err, FALSE, name); - if (!name_str) { - goto error; - } - - codec = g_slice_new0 (GstAmcCodec); - - if (!gst_amc_jni_call_static_object_method (env, err, media_codec.klass, - media_codec.create_by_codec_name, &object, name_str)) - goto error; - - codec->object = gst_amc_jni_object_make_global (env, object); - object = NULL; - - if (!codec->object) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_SETTINGS, "Failed to create global codec reference"); - goto error; - } - -done: - if (name_str) - gst_amc_jni_object_local_unref (env, name_str); - name_str = NULL; - - return codec; - -error: - if (codec) - g_slice_free (GstAmcCodec, codec); - codec = NULL; - goto done; -} - -void -gst_amc_codec_free (GstAmcCodec * codec) -{ - JNIEnv *env; - - g_return_if_fail (codec != NULL); - - env = gst_amc_jni_get_env (); - - if (codec->input_buffers) - gst_amc_jni_free_buffer_array (env, codec->input_buffers, - codec->n_input_buffers); - codec->input_buffers = NULL; - codec->n_input_buffers = 0; - - if (codec->output_buffers) - gst_amc_jni_free_buffer_array (env, codec->output_buffers, - codec->n_output_buffers); - codec->output_buffers = NULL; - codec->n_output_buffers = 0; - - gst_amc_jni_object_unref (env, codec->object); - g_slice_free (GstAmcCodec, codec); -} - -gboolean -gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format, - jobject surface, gint flags, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - g_return_val_if_fail (format != NULL, FALSE); - - env = gst_amc_jni_get_env (); - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.configure, format->object, surface, NULL, flags); -} - -GstAmcFormat * -gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err) -{ - JNIEnv *env; - GstAmcFormat *ret = NULL; - jobject object = NULL; - - g_return_val_if_fail (codec != NULL, NULL); - - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, codec->object, - media_codec.get_output_format, &object)) - goto done; - - ret = g_slice_new0 (GstAmcFormat); - - ret->object = gst_amc_jni_object_make_global (env, object); - if (!ret->object) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_SETTINGS, "Failed to create global format reference"); - g_slice_free (GstAmcFormat, ret); - ret = NULL; - } - -done: - - return ret; -} - -gboolean -gst_amc_codec_start (GstAmcCodec * codec, GError ** err) -{ - JNIEnv *env; - gboolean ret; - - g_return_val_if_fail (codec != NULL, FALSE); - - env = gst_amc_jni_get_env (); - ret = gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.start); - if (!ret) - return ret; - - if (!media_codec.get_input_buffer) { - if (codec->input_buffers) - gst_amc_jni_free_buffer_array (env, codec->input_buffers, - codec->n_input_buffers); - codec->input_buffers = - gst_amc_codec_get_input_buffers (codec, &codec->n_input_buffers, err); - if (!codec->input_buffers) { - gst_amc_codec_stop (codec, NULL); - return FALSE; - } - } - - return ret; -} - -gboolean -gst_amc_codec_stop (GstAmcCodec * codec, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (codec->input_buffers) - gst_amc_jni_free_buffer_array (env, codec->input_buffers, - codec->n_input_buffers); - codec->input_buffers = NULL; - codec->n_input_buffers = 0; - - if (codec->output_buffers) - gst_amc_jni_free_buffer_array (env, codec->output_buffers, - codec->n_output_buffers); - codec->output_buffers = NULL; - codec->n_output_buffers = 0; - - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.stop); -} - -gboolean -gst_amc_codec_flush (GstAmcCodec * codec, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - - env = gst_amc_jni_get_env (); - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.flush); -} - -gboolean -gst_amc_codec_release (GstAmcCodec * codec, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (codec->input_buffers) - gst_amc_jni_free_buffer_array (env, codec->input_buffers, - codec->n_input_buffers); - codec->input_buffers = NULL; - codec->n_input_buffers = 0; - - if (codec->output_buffers) - gst_amc_jni_free_buffer_array (env, codec->output_buffers, - codec->n_output_buffers); - codec->output_buffers = NULL; - codec->n_output_buffers = 0; - - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.release); -} - -static GstAmcBuffer * -gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers, - GError ** err) -{ - JNIEnv *env; - jobject output_buffers = NULL; - GstAmcBuffer *ret = NULL; - - g_return_val_if_fail (codec != NULL, NULL); - g_return_val_if_fail (n_buffers != NULL, NULL); - - *n_buffers = 0; - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, codec->object, - media_codec.get_output_buffers, &output_buffers)) - goto done; - - gst_amc_jni_get_buffer_array (env, err, output_buffers, &ret, n_buffers); - -done: - if (output_buffers) - gst_amc_jni_object_local_unref (env, output_buffers); - - return ret; -} - -GstAmcBuffer * -gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err) -{ - JNIEnv *env; - jobject buffer = NULL; - GstAmcBuffer *ret = NULL; - - g_return_val_if_fail (codec != NULL, NULL); - g_return_val_if_fail (index >= 0, NULL); - - env = gst_amc_jni_get_env (); - - if (!media_codec.get_output_buffer) { - g_return_val_if_fail (index < codec->n_output_buffers && index >= 0, NULL); - if (codec->output_buffers[index].object) - return gst_amc_buffer_copy (&codec->output_buffers[index]); - else - return NULL; - } - - if (!gst_amc_jni_call_object_method (env, err, codec->object, - media_codec.get_output_buffer, &buffer, index)) - goto done; - - if (buffer != NULL) { - ret = g_new0 (GstAmcBuffer, 1); - ret->object = gst_amc_jni_object_make_global (env, buffer); - if (!ret->object) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); - goto error; - } - - ret->data = (*env)->GetDirectBufferAddress (env, ret->object); - if (!ret->data) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); - goto error; - } - ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); - } - -done: - - return ret; - -error: - if (ret->object) - gst_amc_jni_object_unref (env, ret->object); - g_free (ret); - - return NULL; -} - -static GstAmcBuffer * -gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers, - GError ** err) -{ - JNIEnv *env; - jobject input_buffers = NULL; - GstAmcBuffer *ret = NULL; - - g_return_val_if_fail (codec != NULL, NULL); - g_return_val_if_fail (n_buffers != NULL, NULL); - - *n_buffers = 0; - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, codec->object, - media_codec.get_input_buffers, &input_buffers)) - goto done; - - gst_amc_jni_get_buffer_array (env, err, input_buffers, &ret, n_buffers); - -done: - if (input_buffers) - gst_amc_jni_object_local_unref (env, input_buffers); - - return ret; -} - -GstAmcBuffer * -gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err) -{ - JNIEnv *env; - jobject buffer = NULL; - GstAmcBuffer *ret = NULL; - - g_return_val_if_fail (codec != NULL, NULL); - g_return_val_if_fail (index >= 0, NULL); - - env = gst_amc_jni_get_env (); - - if (!media_codec.get_input_buffer) { - g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL); - if (codec->input_buffers[index].object) - return gst_amc_buffer_copy (&codec->input_buffers[index]); - else - return NULL; - } - - if (!gst_amc_jni_call_object_method (env, err, codec->object, - media_codec.get_input_buffer, &buffer, index)) - goto done; - - if (buffer != NULL) { - ret = g_new0 (GstAmcBuffer, 1); - ret->object = gst_amc_jni_object_make_global (env, buffer); - if (!ret->object) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); - goto error; - } - - ret->data = (*env)->GetDirectBufferAddress (env, ret->object); - if (!ret->data) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); - goto error; - } - ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); - } - -done: - - return ret; - -error: - if (ret->object) - gst_amc_jni_object_unref (env, ret->object); - g_free (ret); - - return NULL; -} - -gint -gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs, - GError ** err) -{ - JNIEnv *env; - gint ret = G_MININT; - - g_return_val_if_fail (codec != NULL, G_MININT); - - env = gst_amc_jni_get_env (); - if (!gst_amc_jni_call_int_method (env, err, codec->object, - media_codec.dequeue_input_buffer, &ret, timeoutUs)) - return G_MININT; - - return ret; -} - -static gboolean -gst_amc_codec_fill_buffer_info (JNIEnv * env, jobject buffer_info, - GstAmcBufferInfo * info, GError ** err) -{ - g_return_val_if_fail (buffer_info != NULL, FALSE); - - if (!gst_amc_jni_get_int_field (env, err, buffer_info, - media_codec_buffer_info.flags, &info->flags)) - return FALSE; - - if (!gst_amc_jni_get_int_field (env, err, buffer_info, - media_codec_buffer_info.offset, &info->offset)) - return FALSE; - - if (!gst_amc_jni_get_long_field (env, err, buffer_info, - media_codec_buffer_info.presentation_time_us, - &info->presentation_time_us)) - return FALSE; - - if (!gst_amc_jni_get_int_field (env, err, buffer_info, - media_codec_buffer_info.size, &info->size)) - return FALSE; - - return TRUE; -} - -gint -gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, - GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err) -{ - JNIEnv *env; - gint ret = G_MININT; - jobject info_o = NULL; - - g_return_val_if_fail (codec != NULL, G_MININT); - - env = gst_amc_jni_get_env (); - - info_o = - gst_amc_jni_new_object (env, err, FALSE, media_codec_buffer_info.klass, - media_codec_buffer_info.constructor); - if (!info_o) - goto done; - - if (!gst_amc_jni_call_int_method (env, err, codec->object, - media_codec.dequeue_output_buffer, &ret, info_o, timeoutUs)) { - ret = G_MININT; - goto done; - } - - if (ret == INFO_OUTPUT_BUFFERS_CHANGED || ret == INFO_OUTPUT_FORMAT_CHANGED - || (ret >= 0 && !codec->output_buffers - && !media_codec.get_output_buffer)) { - if (!media_codec.get_output_buffer) { - if (codec->output_buffers) - gst_amc_jni_free_buffer_array (env, codec->output_buffers, - codec->n_output_buffers); - codec->output_buffers = - gst_amc_codec_get_output_buffers (codec, - &codec->n_output_buffers, err); - if (!codec->output_buffers) { - ret = G_MININT; - goto done; - } - } - if (ret == INFO_OUTPUT_BUFFERS_CHANGED) { - gst_amc_jni_object_local_unref (env, info_o); - return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err); - } - } else if (ret < 0) { - goto done; - } - - if (ret >= 0 && !gst_amc_codec_fill_buffer_info (env, info_o, info, err)) { - ret = G_MININT; - goto done; - } - -done: - if (info_o) - gst_amc_jni_object_local_unref (env, info_o); - info_o = NULL; - - return ret; -} - -gboolean -gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index, - const GstAmcBufferInfo * info, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - g_return_val_if_fail (info != NULL, FALSE); - - env = gst_amc_jni_get_env (); - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.queue_input_buffer, index, info->offset, info->size, - info->presentation_time_us, info->flags); -} - -gboolean -gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index, - gboolean render, GError ** err) -{ - JNIEnv *env; - - g_return_val_if_fail (codec != NULL, FALSE); - - env = gst_amc_jni_get_env (); - return gst_amc_jni_call_void_method (env, err, codec->object, - media_codec.release_output_buffer, index, render); -} - -GstAmcFormat * -gst_amc_format_new_audio (const gchar * mime, gint sample_rate, gint channels, - GError ** err) -{ - JNIEnv *env; - GstAmcFormat *format = NULL; - jstring mime_str; - - g_return_val_if_fail (mime != NULL, NULL); - - env = gst_amc_jni_get_env (); - - mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime); - if (!mime_str) - goto error; - - format = g_slice_new0 (GstAmcFormat); - format->object = - gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass, - media_format.create_audio_format, mime_str, sample_rate, channels); - if (!format->object) - goto error; - -done: - if (mime_str) - gst_amc_jni_object_local_unref (env, mime_str); - mime_str = NULL; - - return format; - -error: - if (format) - g_slice_free (GstAmcFormat, format); - format = NULL; - goto done; -} - -GstAmcFormat * -gst_amc_format_new_video (const gchar * mime, gint width, gint height, - GError ** err) -{ - JNIEnv *env; - GstAmcFormat *format = NULL; - jstring mime_str; - - g_return_val_if_fail (mime != NULL, NULL); - - env = gst_amc_jni_get_env (); - - mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime); - if (!mime_str) - goto error; - - format = g_slice_new0 (GstAmcFormat); - format->object = - gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass, - media_format.create_video_format, mime_str, width, height); - if (!format->object) - goto error; - -done: - if (mime_str) - gst_amc_jni_object_local_unref (env, mime_str); - mime_str = NULL; - - return format; - -error: - if (format) - g_slice_free (GstAmcFormat, format); - format = NULL; - goto done; -} - -void -gst_amc_format_free (GstAmcFormat * format) -{ - JNIEnv *env; - - g_return_if_fail (format != NULL); - - env = gst_amc_jni_get_env (); - gst_amc_jni_object_unref (env, format->object); - g_slice_free (GstAmcFormat, format); -} - -gchar * -gst_amc_format_to_string (GstAmcFormat * format, GError ** err) -{ - JNIEnv *env; - jstring v_str = NULL; - gchar *ret = NULL; - - g_return_val_if_fail (format != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, format->object, - media_format.to_string, &v_str)) - goto done; - ret = gst_amc_jni_string_to_gchar (env, v_str, TRUE); - -done: - - return ret; -} - -gboolean -gst_amc_format_contains_key (GstAmcFormat * format, const gchar * key, - GError ** err) -{ - JNIEnv *env; - gboolean ret = FALSE; - jstring key_str = NULL; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_boolean_method (env, err, format->object, - media_format.contains_key, &ret, key_str)) - goto done; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; -} - -gboolean -gst_amc_format_get_float (GstAmcFormat * format, const gchar * key, - gfloat * value, GError ** err) -{ - JNIEnv *env; - gboolean ret = FALSE; - jstring key_str = NULL; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - *value = 0; - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_float_method (env, err, format->object, - media_format.get_float, value, key_str)) - goto done; - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; -} - -gboolean -gst_amc_format_set_float (GstAmcFormat * format, const gchar * key, - gfloat value, GError ** err) -{ - JNIEnv *env; - jstring key_str = NULL; - gboolean ret = FALSE; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_void_method (env, err, format->object, - media_format.set_float, key_str, value)) - goto done; - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; -} - -gboolean -gst_amc_format_get_int (GstAmcFormat * format, const gchar * key, gint * value, - GError ** err) -{ - JNIEnv *env; - gboolean ret = FALSE; - jstring key_str = NULL; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - *value = 0; - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_int_method (env, err, format->object, - media_format.get_integer, value, key_str)) - goto done; - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; - -} - -gboolean -gst_amc_format_set_int (GstAmcFormat * format, const gchar * key, gint value, - GError ** err) -{ - JNIEnv *env; - jstring key_str = NULL; - gboolean ret = FALSE; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_void_method (env, err, format->object, - media_format.set_integer, key_str, value)) - goto done; - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; -} - -gboolean -gst_amc_format_get_string (GstAmcFormat * format, const gchar * key, - gchar ** value, GError ** err) -{ - JNIEnv *env; - gboolean ret = FALSE; - jstring key_str = NULL; - jstring v_str = NULL; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - *value = 0; - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_object_method (env, err, format->object, - media_format.get_string, &v_str, key_str)) - goto done; - - *value = gst_amc_jni_string_to_gchar (env, v_str, TRUE); - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - - return ret; -} - -gboolean -gst_amc_format_set_string (GstAmcFormat * format, const gchar * key, - const gchar * value, GError ** err) -{ - JNIEnv *env; - jstring key_str = NULL; - jstring v_str = NULL; - gboolean ret = FALSE; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - v_str = gst_amc_jni_string_from_gchar (env, err, FALSE, value); - if (!v_str) - goto done; - - if (!gst_amc_jni_call_void_method (env, err, format->object, - media_format.set_string, key_str, v_str)) - goto done; - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - if (v_str) - gst_amc_jni_object_local_unref (env, v_str); - - return ret; -} - -gboolean -gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, - guint8 ** data, gsize * size, GError ** err) -{ - JNIEnv *env; - gboolean ret = FALSE; - jstring key_str = NULL; - jobject v = NULL; - GstAmcBuffer buf = { 0, }; - gint position = 0, limit = 0; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (size != NULL, FALSE); - - *data = NULL; - *size = 0; - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - if (!gst_amc_jni_call_object_method (env, err, format->object, - media_format.get_byte_buffer, &v, key_str)) - goto done; - - *data = (*env)->GetDirectBufferAddress (env, v); - if (*data == NULL) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed get buffer address"); - goto done; - } - *size = (*env)->GetDirectBufferCapacity (env, v); - - buf.object = v; - buf.data = *data; - buf.size = *size; - gst_amc_buffer_get_position_and_limit (&buf, NULL, &position, &limit); - *size = limit; - - *data = g_memdup (*data + position, limit); - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - if (v) - gst_amc_jni_object_local_unref (env, v); - - return ret; -} - -gboolean -gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, - guint8 * data, gsize size, GError ** err) -{ - JNIEnv *env; - jstring key_str = NULL; - jobject v = NULL; - gboolean ret = FALSE; - GstAmcBuffer buf = { 0, }; - - g_return_val_if_fail (format != NULL, FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (data != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); - if (!key_str) - goto done; - - /* FIXME: The memory must remain valid until the codec is stopped */ - v = (*env)->NewDirectByteBuffer (env, data, size); - if (!v) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed create Java byte buffer"); - goto done; - } - - buf.object = v; - buf.data = data; - buf.size = size; - - gst_amc_buffer_set_position_and_limit (&buf, NULL, 0, size); - - if (!gst_amc_jni_call_void_method (env, err, format->object, - media_format.set_byte_buffer, key_str, v)) - goto done; - - ret = TRUE; - -done: - if (key_str) - gst_amc_jni_object_local_unref (env, key_str); - if (v) - gst_amc_jni_object_local_unref (env, v); - - return ret; -} - -static gboolean -get_java_classes (void) -{ - gboolean ret = TRUE; - JNIEnv *env; - jclass tmp; - - GST_DEBUG ("Retrieving Java classes"); - - env = gst_amc_jni_get_env (); - - tmp = (*env)->FindClass (env, "java/lang/String"); - if (!tmp) { - ret = FALSE; - GST_ERROR ("Failed to get string class"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - java_string.klass = (*env)->NewGlobalRef (env, tmp); - if (!java_string.klass) { - ret = FALSE; - GST_ERROR ("Failed to get string class global reference"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - (*env)->DeleteLocalRef (env, tmp); - tmp = NULL; - - java_string.constructor = - (*env)->GetMethodID (env, java_string.klass, "", "([C)V"); - if (!java_string.constructor) { - ret = FALSE; - GST_ERROR ("Failed to get string methods"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - - tmp = (*env)->FindClass (env, "android/media/MediaCodec"); - if (!tmp) { - ret = FALSE; - GST_ERROR ("Failed to get codec class"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - media_codec.klass = (*env)->NewGlobalRef (env, tmp); - if (!media_codec.klass) { - ret = FALSE; - GST_ERROR ("Failed to get codec class global reference"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - (*env)->DeleteLocalRef (env, tmp); - tmp = NULL; - - media_codec.create_by_codec_name = - (*env)->GetStaticMethodID (env, media_codec.klass, "createByCodecName", - "(Ljava/lang/String;)Landroid/media/MediaCodec;"); - media_codec.configure = - (*env)->GetMethodID (env, media_codec.klass, "configure", - "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"); - media_codec.dequeue_input_buffer = - (*env)->GetMethodID (env, media_codec.klass, "dequeueInputBuffer", - "(J)I"); - media_codec.dequeue_output_buffer = - (*env)->GetMethodID (env, media_codec.klass, "dequeueOutputBuffer", - "(Landroid/media/MediaCodec$BufferInfo;J)I"); - media_codec.flush = - (*env)->GetMethodID (env, media_codec.klass, "flush", "()V"); - media_codec.get_input_buffers = - (*env)->GetMethodID (env, media_codec.klass, "getInputBuffers", - "()[Ljava/nio/ByteBuffer;"); - media_codec.get_output_buffers = - (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffers", - "()[Ljava/nio/ByteBuffer;"); - media_codec.get_output_format = - (*env)->GetMethodID (env, media_codec.klass, "getOutputFormat", - "()Landroid/media/MediaFormat;"); - media_codec.queue_input_buffer = - (*env)->GetMethodID (env, media_codec.klass, "queueInputBuffer", - "(IIIJI)V"); - media_codec.release = - (*env)->GetMethodID (env, media_codec.klass, "release", "()V"); - media_codec.release_output_buffer = - (*env)->GetMethodID (env, media_codec.klass, "releaseOutputBuffer", - "(IZ)V"); - media_codec.start = - (*env)->GetMethodID (env, media_codec.klass, "start", "()V"); - media_codec.stop = - (*env)->GetMethodID (env, media_codec.klass, "stop", "()V"); - - if (!media_codec.configure || - !media_codec.create_by_codec_name || - !media_codec.dequeue_input_buffer || - !media_codec.dequeue_output_buffer || - !media_codec.flush || - !media_codec.get_input_buffers || - !media_codec.get_output_buffers || - !media_codec.get_output_format || - !media_codec.queue_input_buffer || - !media_codec.release || - !media_codec.release_output_buffer || - !media_codec.start || !media_codec.stop) { - ret = FALSE; - GST_ERROR ("Failed to get codec methods"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - - /* Android >= 21 */ - media_codec.get_output_buffer = - (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffer", - "(I)Ljava/nio/ByteBuffer;"); - if ((*env)->ExceptionCheck (env)) - (*env)->ExceptionClear (env); - - /* Android >= 21 */ - media_codec.get_input_buffer = - (*env)->GetMethodID (env, media_codec.klass, "getInputBuffer", - "(I)Ljava/nio/ByteBuffer;"); - if ((*env)->ExceptionCheck (env)) - (*env)->ExceptionClear (env); - - tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo"); - if (!tmp) { - ret = FALSE; - (*env)->ExceptionClear (env); - GST_ERROR ("Failed to get codec buffer info class"); - goto done; - } - media_codec_buffer_info.klass = (*env)->NewGlobalRef (env, tmp); - if (!media_codec_buffer_info.klass) { - ret = FALSE; - GST_ERROR ("Failed to get codec buffer info class global reference"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - (*env)->DeleteLocalRef (env, tmp); - tmp = NULL; - - media_codec_buffer_info.constructor = - (*env)->GetMethodID (env, media_codec_buffer_info.klass, "", "()V"); - media_codec_buffer_info.flags = - (*env)->GetFieldID (env, media_codec_buffer_info.klass, "flags", "I"); - media_codec_buffer_info.offset = - (*env)->GetFieldID (env, media_codec_buffer_info.klass, "offset", "I"); - media_codec_buffer_info.presentation_time_us = - (*env)->GetFieldID (env, media_codec_buffer_info.klass, - "presentationTimeUs", "J"); - media_codec_buffer_info.size = - (*env)->GetFieldID (env, media_codec_buffer_info.klass, "size", "I"); - if (!media_codec_buffer_info.constructor || !media_codec_buffer_info.flags - || !media_codec_buffer_info.offset - || !media_codec_buffer_info.presentation_time_us - || !media_codec_buffer_info.size) { - ret = FALSE; - GST_ERROR ("Failed to get buffer info methods and fields"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - - tmp = (*env)->FindClass (env, "android/media/MediaFormat"); - if (!tmp) { - ret = FALSE; - GST_ERROR ("Failed to get format class"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - media_format.klass = (*env)->NewGlobalRef (env, tmp); - if (!media_format.klass) { - ret = FALSE; - GST_ERROR ("Failed to get format class global reference"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - (*env)->DeleteLocalRef (env, tmp); - tmp = NULL; - - media_format.create_audio_format = - (*env)->GetStaticMethodID (env, media_format.klass, "createAudioFormat", - "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); - media_format.create_video_format = - (*env)->GetStaticMethodID (env, media_format.klass, "createVideoFormat", - "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); - media_format.to_string = - (*env)->GetMethodID (env, media_format.klass, "toString", - "()Ljava/lang/String;"); - media_format.contains_key = - (*env)->GetMethodID (env, media_format.klass, "containsKey", - "(Ljava/lang/String;)Z"); - media_format.get_float = - (*env)->GetMethodID (env, media_format.klass, "getFloat", - "(Ljava/lang/String;)F"); - media_format.set_float = - (*env)->GetMethodID (env, media_format.klass, "setFloat", - "(Ljava/lang/String;F)V"); - media_format.get_integer = - (*env)->GetMethodID (env, media_format.klass, "getInteger", - "(Ljava/lang/String;)I"); - media_format.set_integer = - (*env)->GetMethodID (env, media_format.klass, "setInteger", - "(Ljava/lang/String;I)V"); - media_format.get_string = - (*env)->GetMethodID (env, media_format.klass, "getString", - "(Ljava/lang/String;)Ljava/lang/String;"); - media_format.set_string = - (*env)->GetMethodID (env, media_format.klass, "setString", - "(Ljava/lang/String;Ljava/lang/String;)V"); - media_format.get_byte_buffer = - (*env)->GetMethodID (env, media_format.klass, "getByteBuffer", - "(Ljava/lang/String;)Ljava/nio/ByteBuffer;"); - media_format.set_byte_buffer = - (*env)->GetMethodID (env, media_format.klass, "setByteBuffer", - "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"); - if (!media_format.create_audio_format || !media_format.create_video_format - || !media_format.contains_key || !media_format.get_float - || !media_format.set_float || !media_format.get_integer - || !media_format.set_integer || !media_format.get_string - || !media_format.set_string || !media_format.get_byte_buffer - || !media_format.set_byte_buffer) { - ret = FALSE; - GST_ERROR ("Failed to get format methods"); - if ((*env)->ExceptionCheck (env)) { - (*env)->ExceptionDescribe (env); - (*env)->ExceptionClear (env); - } - goto done; - } - -done: - if (tmp) - (*env)->DeleteLocalRef (env, tmp); - tmp = NULL; - - return ret; -} - static gboolean scan_codecs (GstPlugin * plugin) { @@ -3340,7 +2084,10 @@ amc_init (GstPlugin * plugin) gst_amc_codec_info_quark = g_quark_from_static_string ("gst-amc-codec-info"); - if (!get_java_classes ()) + if (!gst_amc_codec_static_init ()) + return FALSE; + + if (!gst_amc_format_static_init ()) return FALSE; /* Set this to TRUE to allow registering decoders that have diff --git a/sys/androidmedia/gstamc.h b/sys/androidmedia/gstamc.h index 383eb42..3700322 100644 --- a/sys/androidmedia/gstamc.h +++ b/sys/androidmedia/gstamc.h @@ -27,15 +27,13 @@ #include #include "gstjniutils.h" +#include "gstamc-codec.h" +#include "gstamc-format.h" G_BEGIN_DECLS -typedef struct _GstAmcCodecInfo GstAmcCodecInfo; typedef struct _GstAmcCodecType GstAmcCodecType; -typedef struct _GstAmcCodec GstAmcCodec; -typedef struct _GstAmcBufferInfo GstAmcBufferInfo; -typedef struct _GstAmcFormat GstAmcFormat; -typedef struct _GstAmcColorFormatInfo GstAmcColorFormatInfo; +typedef struct _GstAmcCodecInfo GstAmcCodecInfo; struct _GstAmcCodecType { gchar *mime; @@ -58,66 +56,9 @@ struct _GstAmcCodecInfo { gint n_supported_types; }; -struct _GstAmcFormat { - /* < private > */ - jobject object; /* global reference */ -}; - -struct _GstAmcCodec { - /* < private > */ - jobject object; /* global reference */ - - GstAmcBuffer *input_buffers, *output_buffers; - gsize n_input_buffers, n_output_buffers; -}; - -struct _GstAmcBufferInfo { - gint flags; - gint offset; - gint64 presentation_time_us; - gint size; -}; extern GQuark gst_amc_codec_info_quark; -GstAmcCodec * gst_amc_codec_new (const gchar *name, GError **err); -void gst_amc_codec_free (GstAmcCodec * codec); - -gboolean gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format, jobject surface, gint flags, GError **err); -GstAmcFormat * gst_amc_codec_get_output_format (GstAmcCodec * codec, GError **err); - -gboolean gst_amc_codec_start (GstAmcCodec * codec, GError **err); -gboolean gst_amc_codec_stop (GstAmcCodec * codec, GError **err); -gboolean gst_amc_codec_flush (GstAmcCodec * codec, GError **err); -gboolean gst_amc_codec_release (GstAmcCodec * codec, GError **err); - -GstAmcBuffer * gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError **err); -GstAmcBuffer * gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError **err); - -gint gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs, GError **err); -gint gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, GstAmcBufferInfo *info, gint64 timeoutUs, GError **err); - -gboolean gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index, const GstAmcBufferInfo *info, GError **err); -gboolean gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index, gboolean render, GError **err); - - -GstAmcFormat * gst_amc_format_new_audio (const gchar *mime, gint sample_rate, gint channels, GError **err); -GstAmcFormat * gst_amc_format_new_video (const gchar *mime, gint width, gint height, GError **err); -void gst_amc_format_free (GstAmcFormat * format); - -gchar * gst_amc_format_to_string (GstAmcFormat * format, GError **err); - -gboolean gst_amc_format_contains_key (GstAmcFormat *format, const gchar *key, GError **err); - -gboolean gst_amc_format_get_float (GstAmcFormat *format, const gchar *key, gfloat *value, GError **err); -gboolean gst_amc_format_set_float (GstAmcFormat *format, const gchar *key, gfloat value, GError **err); -gboolean gst_amc_format_get_int (GstAmcFormat *format, const gchar *key, gint *value, GError **err); -gboolean gst_amc_format_set_int (GstAmcFormat *format, const gchar *key, gint value, GError **err); -gboolean gst_amc_format_get_string (GstAmcFormat *format, const gchar *key, gchar **value, GError **err); -gboolean gst_amc_format_set_string (GstAmcFormat *format, const gchar *key, const gchar *value, GError **err); -gboolean gst_amc_format_get_buffer (GstAmcFormat *format, const gchar *key, guint8 **data, gsize *size, GError **err); -gboolean gst_amc_format_set_buffer (GstAmcFormat *format, const gchar *key, guint8 *data, gsize size, GError **err); - GstVideoFormat gst_amc_color_format_to_video_format (const GstAmcCodecInfo * codec_info, const gchar * mime, gint color_format); gint gst_amc_video_format_to_color_format (const GstAmcCodecInfo * codec_info, const gchar * mime, GstVideoFormat video_format); diff --git a/sys/androidmedia/gstjniutils.c b/sys/androidmedia/gstjniutils.c index 0f2efc2..d7c9da4 100644 --- a/sys/androidmedia/gstjniutils.c +++ b/sys/androidmedia/gstjniutils.c @@ -43,14 +43,6 @@ static gboolean started_java_vm = FALSE; static pthread_key_t current_jni_env; static jobject (*get_class_loader) (void); -static struct -{ - jclass klass; - jmethodID get_limit, get_position; - jmethodID set_limit, set_position; - jmethodID clear; -} java_nio_buffer; - jclass gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name) { @@ -610,63 +602,6 @@ check_application_class_loader (void) static gboolean initialize_classes (void) { - JNIEnv *env; - GError *err = NULL; - - env = gst_amc_jni_get_env (); - - java_nio_buffer.klass = gst_amc_jni_get_class (env, &err, "java/nio/Buffer"); - if (!java_nio_buffer.klass) { - GST_ERROR ("Failed to get java.nio.Buffer class: %s", err->message); - g_clear_error (&err); - return FALSE; - } - - java_nio_buffer.get_limit = - gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", - "()I"); - if (!java_nio_buffer.get_limit) { - GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); - g_clear_error (&err); - return FALSE; - } - - java_nio_buffer.get_position = - gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", - "()I"); - if (!java_nio_buffer.get_position) { - GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); - g_clear_error (&err); - return FALSE; - } - - java_nio_buffer.set_limit = - gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", - "(I)Ljava/nio/Buffer;"); - if (!java_nio_buffer.set_limit) { - GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); - g_clear_error (&err); - return FALSE; - } - - java_nio_buffer.set_position = - gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", - "(I)Ljava/nio/Buffer;"); - if (!java_nio_buffer.set_position) { - GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); - g_clear_error (&err); - return FALSE; - } - - java_nio_buffer.clear = - gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "clear", - "()Ljava/nio/Buffer;"); - if (!java_nio_buffer.clear) { - GST_ERROR ("Failed to get java.nio.Buffer clear(): %s", err->message); - g_clear_error (&err); - return FALSE; - } - if (!check_application_class_loader ()) { GST_ERROR ("Could not find application class loader provider"); return FALSE; @@ -1050,173 +985,3 @@ GET_STATIC_TYPE_FIELD (gint64, long, Long); GET_STATIC_TYPE_FIELD (gfloat, float, Float); GET_STATIC_TYPE_FIELD (gdouble, double, Double); GET_STATIC_TYPE_FIELD (jobject, object, Object); - -gboolean -gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array, - GstAmcBuffer ** buffers, gsize * n_buffers) -{ - jsize i; - - *n_buffers = (*env)->GetArrayLength (env, array); - *buffers = g_new0 (GstAmcBuffer, *n_buffers); - - for (i = 0; i < *n_buffers; i++) { - jobject buffer = NULL; - - buffer = (*env)->GetObjectArrayElement (env, array, i); - if ((*env)->ExceptionCheck (env)) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to get buffer %d", i); - goto error; - } - - /* NULL buffers are not a problem and are happening when we configured - * a surface as input/output */ - if (!buffer) - continue; - - (*buffers)[i].object = gst_amc_jni_object_make_global (env, buffer); - if (!(*buffers)[i].object) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, - "Failed to create global buffer reference %d", i); - goto error; - } - - (*buffers)[i].data = - (*env)->GetDirectBufferAddress (env, (*buffers)[i].object); - if (!(*buffers)[i].data) { - gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, - GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address %d", i); - goto error; - } - (*buffers)[i].size = - (*env)->GetDirectBufferCapacity (env, (*buffers)[i].object); - } - - return TRUE; - -error: - if (*buffers) - gst_amc_jni_free_buffer_array (env, *buffers, *n_buffers); - *buffers = NULL; - *n_buffers = 0; - return FALSE; -} - -void -gst_amc_jni_free_buffer_array (JNIEnv * env, GstAmcBuffer * buffers, - gsize n_buffers) -{ - jsize i; - - g_return_if_fail (buffers != NULL); - - for (i = 0; i < n_buffers; i++) { - if (buffers[i].object) - gst_amc_jni_object_unref (env, buffers[i].object); - } - g_free (buffers); -} - -void -gst_amc_buffer_free (GstAmcBuffer * buffer) -{ - JNIEnv *env; - - g_return_if_fail (buffer != NULL); - - env = gst_amc_jni_get_env (); - - if (buffer->object) - gst_amc_jni_object_unref (env, buffer->object); - g_free (buffer); -} - -GstAmcBuffer * -gst_amc_buffer_copy (GstAmcBuffer * buffer) -{ - JNIEnv *env; - GstAmcBuffer *ret; - - g_return_val_if_fail (buffer != NULL, NULL); - - env = gst_amc_jni_get_env (); - - ret = g_new0 (GstAmcBuffer, 1); - - ret->object = gst_amc_jni_object_ref (env, buffer->object); - ret->data = buffer->data; - ret->size = buffer->size; - - return ret; -} - -gboolean -gst_amc_buffer_get_position_and_limit (GstAmcBuffer * buffer, GError ** err, - gint * position, gint * limit) -{ - JNIEnv *env; - - g_return_val_if_fail (buffer != NULL, FALSE); - g_return_val_if_fail (buffer->object != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_int_method (env, err, buffer->object, - java_nio_buffer.get_position, position)) - return FALSE; - - if (!gst_amc_jni_call_int_method (env, err, buffer->object, - java_nio_buffer.get_limit, limit)) - return FALSE; - - return TRUE; -} - -gboolean -gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err, - gint position, gint limit) -{ - JNIEnv *env; - jobject tmp; - - g_return_val_if_fail (buffer != NULL, FALSE); - g_return_val_if_fail (buffer->object != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, buffer->object, - java_nio_buffer.set_limit, &tmp, limit)) - return FALSE; - - gst_amc_jni_object_local_unref (env, tmp); - - if (!gst_amc_jni_call_object_method (env, err, buffer->object, - java_nio_buffer.set_position, &tmp, position)) - return FALSE; - - gst_amc_jni_object_local_unref (env, tmp); - - return TRUE; -} - -gboolean -gst_amc_buffer_clear (GstAmcBuffer * buffer, GError ** err) -{ - JNIEnv *env; - jobject tmp; - - g_return_val_if_fail (buffer != NULL, FALSE); - g_return_val_if_fail (buffer->object != NULL, FALSE); - - env = gst_amc_jni_get_env (); - - if (!gst_amc_jni_call_object_method (env, err, buffer->object, - java_nio_buffer.clear, &tmp)) - return FALSE; - - gst_amc_jni_object_local_unref (env, tmp); - - return TRUE; -} diff --git a/sys/androidmedia/gstjniutils.h b/sys/androidmedia/gstjniutils.h index c323cf8..1d30edc 100644 --- a/sys/androidmedia/gstjniutils.h +++ b/sys/androidmedia/gstjniutils.h @@ -173,21 +173,4 @@ DEF_GET_STATIC_TYPE_FIELD (gfloat, float, Float); DEF_GET_STATIC_TYPE_FIELD (gdouble, double, Double); DEF_GET_STATIC_TYPE_FIELD (jobject, object, Object); -typedef struct _GstAmcBuffer GstAmcBuffer; - -struct _GstAmcBuffer { - jobject object; /* global reference */ - guint8 *data; - gsize size; -}; - -gboolean gst_amc_buffer_get_position_and_limit (GstAmcBuffer * buffer, GError ** err, gint * position, gint * limit); -gboolean gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err, gint position, gint limit); -gboolean gst_amc_buffer_clear (GstAmcBuffer * buffer, GError ** err); -GstAmcBuffer * gst_amc_buffer_copy (GstAmcBuffer * buffer); -void gst_amc_buffer_free (GstAmcBuffer * buffer); - -gboolean gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array, GstAmcBuffer ** buffers, gsize * n_buffers); -void gst_amc_jni_free_buffer_array (JNIEnv * env, GstAmcBuffer * buffers, gsize n_buffers); - #endif diff --git a/sys/androidmedia/jni/gstamc-codec-jni.c b/sys/androidmedia/jni/gstamc-codec-jni.c new file mode 100644 index 0000000..f6fa010 --- /dev/null +++ b/sys/androidmedia/jni/gstamc-codec-jni.c @@ -0,0 +1,936 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * Copyright (C) 2015, Sebastian Dröge + * + * 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 "../gstjniutils.h" +#include "../gstamc-codec.h" +#include "../gstamc-constants.h" +#include "gstamc-internal-jni.h" + +struct _GstAmcCodec +{ + jobject object; /* global reference */ + + RealBuffer *input_buffers, *output_buffers; + gsize n_input_buffers, n_output_buffers; +}; + +static struct +{ + jclass klass; + jmethodID configure; + jmethodID create_by_codec_name; + jmethodID dequeue_input_buffer; + jmethodID dequeue_output_buffer; + jmethodID flush; + jmethodID get_input_buffers; + jmethodID get_input_buffer; + jmethodID get_output_buffers; + jmethodID get_output_buffer; + jmethodID get_output_format; + jmethodID queue_input_buffer; + jmethodID release; + jmethodID release_output_buffer; + jmethodID start; + jmethodID stop; +} media_codec; + +static struct +{ + jclass klass; + jmethodID constructor; + jfieldID flags; + jfieldID offset; + jfieldID presentation_time_us; + jfieldID size; +} media_codec_buffer_info; + +static struct +{ + jclass klass; + jmethodID get_limit, get_position; + jmethodID set_limit, set_position; + jmethodID clear; +} java_nio_buffer; + +gboolean +gst_amc_codec_static_init (void) +{ + gboolean ret = TRUE; + JNIEnv *env; + jclass tmp; + GError *err = NULL; + + env = gst_amc_jni_get_env (); + + java_nio_buffer.klass = gst_amc_jni_get_class (env, &err, "java/nio/Buffer"); + if (!java_nio_buffer.klass) { + GST_ERROR ("Failed to get java.nio.Buffer class: %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.get_limit = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", + "()I"); + if (!java_nio_buffer.get_limit) { + GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.get_position = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", + "()I"); + if (!java_nio_buffer.get_position) { + GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.set_limit = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit", + "(I)Ljava/nio/Buffer;"); + if (!java_nio_buffer.set_limit) { + GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.set_position = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position", + "(I)Ljava/nio/Buffer;"); + if (!java_nio_buffer.set_position) { + GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + java_nio_buffer.clear = + gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "clear", + "()Ljava/nio/Buffer;"); + if (!java_nio_buffer.clear) { + GST_ERROR ("Failed to get java.nio.Buffer clear(): %s", err->message); + g_clear_error (&err); + return FALSE; + } + + tmp = (*env)->FindClass (env, "android/media/MediaCodec$BufferInfo"); + if (!tmp) { + ret = FALSE; + (*env)->ExceptionClear (env); + GST_ERROR ("Failed to get codec buffer info class"); + goto done; + } + media_codec_buffer_info.klass = (*env)->NewGlobalRef (env, tmp); + if (!media_codec_buffer_info.klass) { + ret = FALSE; + GST_ERROR ("Failed to get codec buffer info class global reference"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + (*env)->DeleteLocalRef (env, tmp); + tmp = NULL; + + media_codec_buffer_info.constructor = + (*env)->GetMethodID (env, media_codec_buffer_info.klass, "", "()V"); + media_codec_buffer_info.flags = + (*env)->GetFieldID (env, media_codec_buffer_info.klass, "flags", "I"); + media_codec_buffer_info.offset = + (*env)->GetFieldID (env, media_codec_buffer_info.klass, "offset", "I"); + media_codec_buffer_info.presentation_time_us = + (*env)->GetFieldID (env, media_codec_buffer_info.klass, + "presentationTimeUs", "J"); + media_codec_buffer_info.size = + (*env)->GetFieldID (env, media_codec_buffer_info.klass, "size", "I"); + if (!media_codec_buffer_info.constructor || !media_codec_buffer_info.flags + || !media_codec_buffer_info.offset + || !media_codec_buffer_info.presentation_time_us + || !media_codec_buffer_info.size) { + ret = FALSE; + GST_ERROR ("Failed to get buffer info methods and fields"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + + tmp = (*env)->FindClass (env, "android/media/MediaCodec"); + if (!tmp) { + ret = FALSE; + GST_ERROR ("Failed to get codec class"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + media_codec.klass = (*env)->NewGlobalRef (env, tmp); + if (!media_codec.klass) { + ret = FALSE; + GST_ERROR ("Failed to get codec class global reference"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + (*env)->DeleteLocalRef (env, tmp); + tmp = NULL; + + media_codec.create_by_codec_name = + (*env)->GetStaticMethodID (env, media_codec.klass, "createByCodecName", + "(Ljava/lang/String;)Landroid/media/MediaCodec;"); + media_codec.configure = + (*env)->GetMethodID (env, media_codec.klass, "configure", + "(Landroid/media/MediaFormat;Landroid/view/Surface;Landroid/media/MediaCrypto;I)V"); + media_codec.dequeue_input_buffer = + (*env)->GetMethodID (env, media_codec.klass, "dequeueInputBuffer", + "(J)I"); + media_codec.dequeue_output_buffer = + (*env)->GetMethodID (env, media_codec.klass, "dequeueOutputBuffer", + "(Landroid/media/MediaCodec$BufferInfo;J)I"); + media_codec.flush = + (*env)->GetMethodID (env, media_codec.klass, "flush", "()V"); + media_codec.get_input_buffers = + (*env)->GetMethodID (env, media_codec.klass, "getInputBuffers", + "()[Ljava/nio/ByteBuffer;"); + media_codec.get_output_buffers = + (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffers", + "()[Ljava/nio/ByteBuffer;"); + media_codec.get_output_format = + (*env)->GetMethodID (env, media_codec.klass, "getOutputFormat", + "()Landroid/media/MediaFormat;"); + media_codec.queue_input_buffer = + (*env)->GetMethodID (env, media_codec.klass, "queueInputBuffer", + "(IIIJI)V"); + media_codec.release = + (*env)->GetMethodID (env, media_codec.klass, "release", "()V"); + media_codec.release_output_buffer = + (*env)->GetMethodID (env, media_codec.klass, "releaseOutputBuffer", + "(IZ)V"); + media_codec.start = + (*env)->GetMethodID (env, media_codec.klass, "start", "()V"); + media_codec.stop = + (*env)->GetMethodID (env, media_codec.klass, "stop", "()V"); + + if (!media_codec.configure || + !media_codec.create_by_codec_name || + !media_codec.dequeue_input_buffer || + !media_codec.dequeue_output_buffer || + !media_codec.flush || + !media_codec.get_input_buffers || + !media_codec.get_output_buffers || + !media_codec.get_output_format || + !media_codec.queue_input_buffer || + !media_codec.release || + !media_codec.release_output_buffer || + !media_codec.start || !media_codec.stop) { + ret = FALSE; + GST_ERROR ("Failed to get codec methods"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + + /* Android >= 21 */ + media_codec.get_output_buffer = + (*env)->GetMethodID (env, media_codec.klass, "getOutputBuffer", + "(I)Ljava/nio/ByteBuffer;"); + if ((*env)->ExceptionCheck (env)) + (*env)->ExceptionClear (env); + + /* Android >= 21 */ + media_codec.get_input_buffer = + (*env)->GetMethodID (env, media_codec.klass, "getInputBuffer", + "(I)Ljava/nio/ByteBuffer;"); + if ((*env)->ExceptionCheck (env)) + (*env)->ExceptionClear (env); + +done: + if (tmp) + (*env)->DeleteLocalRef (env, tmp); + tmp = NULL; + + return ret; +} + +static void +gst_amc_jni_free_buffer_array (JNIEnv * env, RealBuffer * buffers, + gsize n_buffers) +{ + jsize i; + + g_return_if_fail (buffers != NULL); + + for (i = 0; i < n_buffers; i++) { + if (buffers[i].object) + gst_amc_jni_object_unref (env, buffers[i].object); + } + g_free (buffers); +} + +static gboolean +gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array, + RealBuffer ** buffers_, gsize * n_buffers) +{ + RealBuffer **buffers = (RealBuffer **) buffers_; + jsize i; + + *n_buffers = (*env)->GetArrayLength (env, array); + *buffers = g_new0 (RealBuffer, *n_buffers); + + for (i = 0; i < *n_buffers; i++) { + jobject buffer = NULL; + + buffer = (*env)->GetObjectArrayElement (env, array, i); + if ((*env)->ExceptionCheck (env)) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer %d", i); + goto error; + } + + /* NULL buffers are not a problem and are happening when we configured + * a surface as input/output */ + if (!buffer) + continue; + + (*buffers)[i].object = gst_amc_jni_object_make_global (env, buffer); + if (!(*buffers)[i].object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, + "Failed to create global buffer reference %d", i); + goto error; + } + + (*buffers)[i].data = + (*env)->GetDirectBufferAddress (env, (*buffers)[i].object); + if (!(*buffers)[i].data) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address %d", i); + goto error; + } + (*buffers)[i].size = + (*env)->GetDirectBufferCapacity (env, (*buffers)[i].object); + } + + return TRUE; + +error: + if (*buffers) + gst_amc_jni_free_buffer_array (env, *buffers, *n_buffers); + *buffers = NULL; + *n_buffers = 0; + return FALSE; +} + +void +gst_amc_buffer_free (GstAmcBuffer * buffer_) +{ + RealBuffer *buffer = (RealBuffer *) buffer_; + JNIEnv *env; + + g_return_if_fail (buffer != NULL); + + env = gst_amc_jni_get_env (); + + if (buffer->object) + gst_amc_jni_object_unref (env, buffer->object); + g_free (buffer); +} + +static GstAmcBuffer * +gst_amc_buffer_copy (RealBuffer * buffer) +{ + JNIEnv *env; + RealBuffer *ret; + + g_return_val_if_fail (buffer != NULL, NULL); + + env = gst_amc_jni_get_env (); + + ret = g_new0 (RealBuffer, 1); + + ret->object = gst_amc_jni_object_ref (env, buffer->object); + ret->data = buffer->data; + ret->size = buffer->size; + + return (GstAmcBuffer *) ret; +} + +gboolean +gst_amc_buffer_get_position_and_limit (RealBuffer * buffer_, GError ** err, + gint * position, gint * limit) +{ + RealBuffer *buffer = (RealBuffer *) buffer_; + JNIEnv *env; + + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (buffer->object != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_int_method (env, err, buffer->object, + java_nio_buffer.get_position, position)) + return FALSE; + + if (!gst_amc_jni_call_int_method (env, err, buffer->object, + java_nio_buffer.get_limit, limit)) + return FALSE; + + return TRUE; +} + +gboolean +gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer_, GError ** err, + gint position, gint limit) +{ + RealBuffer *buffer = (RealBuffer *) buffer_; + JNIEnv *env; + jobject tmp; + + g_return_val_if_fail (buffer != NULL, FALSE); + g_return_val_if_fail (buffer->object != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, buffer->object, + java_nio_buffer.set_limit, &tmp, limit)) + return FALSE; + + gst_amc_jni_object_local_unref (env, tmp); + + if (!gst_amc_jni_call_object_method (env, err, buffer->object, + java_nio_buffer.set_position, &tmp, position)) + return FALSE; + + gst_amc_jni_object_local_unref (env, tmp); + + return TRUE; +} + +GstAmcCodec * +gst_amc_codec_new (const gchar * name, GError ** err) +{ + JNIEnv *env; + GstAmcCodec *codec = NULL; + jstring name_str; + jobject object = NULL; + + g_return_val_if_fail (name != NULL, NULL); + + env = gst_amc_jni_get_env (); + + name_str = gst_amc_jni_string_from_gchar (env, err, FALSE, name); + if (!name_str) { + goto error; + } + + codec = g_slice_new0 (GstAmcCodec); + + if (!gst_amc_jni_call_static_object_method (env, err, media_codec.klass, + media_codec.create_by_codec_name, &object, name_str)) + goto error; + + codec->object = gst_amc_jni_object_make_global (env, object); + object = NULL; + + if (!codec->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_SETTINGS, "Failed to create global codec reference"); + goto error; + } + +done: + if (name_str) + gst_amc_jni_object_local_unref (env, name_str); + name_str = NULL; + + return codec; + +error: + if (codec) + g_slice_free (GstAmcCodec, codec); + codec = NULL; + goto done; +} + +void +gst_amc_codec_free (GstAmcCodec * codec) +{ + JNIEnv *env; + + g_return_if_fail (codec != NULL); + + env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + + gst_amc_jni_object_unref (env, codec->object); + g_slice_free (GstAmcCodec, codec); +} + +gboolean +gst_amc_codec_configure (GstAmcCodec * codec, GstAmcFormat * format, + jobject surface, gint flags, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + g_return_val_if_fail (format != NULL, FALSE); + + env = gst_amc_jni_get_env (); + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.configure, format->object, surface, NULL, flags); +} + +GstAmcFormat * +gst_amc_codec_get_output_format (GstAmcCodec * codec, GError ** err) +{ + JNIEnv *env; + GstAmcFormat *ret = NULL; + jobject object = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_output_format, &object)) + goto done; + + ret = g_slice_new0 (GstAmcFormat); + + ret->object = gst_amc_jni_object_make_global (env, object); + if (!ret->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_SETTINGS, "Failed to create global format reference"); + g_slice_free (GstAmcFormat, ret); + ret = NULL; + } + +done: + + return ret; +} + +static RealBuffer * +gst_amc_codec_get_input_buffers (GstAmcCodec * codec, gsize * n_buffers, + GError ** err) +{ + JNIEnv *env; + jobject input_buffers = NULL; + RealBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (n_buffers != NULL, NULL); + + *n_buffers = 0; + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_input_buffers, &input_buffers)) + goto done; + + gst_amc_jni_get_buffer_array (env, err, input_buffers, &ret, n_buffers); + +done: + if (input_buffers) + gst_amc_jni_object_local_unref (env, input_buffers); + + return ret; +} + +static RealBuffer * +gst_amc_codec_get_output_buffers (GstAmcCodec * codec, gsize * n_buffers, + GError ** err) +{ + JNIEnv *env; + jobject output_buffers = NULL; + RealBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (n_buffers != NULL, NULL); + + *n_buffers = 0; + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_output_buffers, &output_buffers)) + goto done; + + gst_amc_jni_get_buffer_array (env, err, output_buffers, &ret, n_buffers); + +done: + if (output_buffers) + gst_amc_jni_object_local_unref (env, output_buffers); + + return ret; +} + +gboolean +gst_amc_codec_start (GstAmcCodec * codec, GError ** err) +{ + JNIEnv *env; + gboolean ret; + + g_return_val_if_fail (codec != NULL, FALSE); + + env = gst_amc_jni_get_env (); + ret = gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.start); + if (!ret) + return ret; + + if (!media_codec.get_input_buffer) { + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = + gst_amc_codec_get_input_buffers (codec, &codec->n_input_buffers, err); + if (!codec->input_buffers) { + gst_amc_codec_stop (codec, NULL); + return FALSE; + } + } + + return ret; +} + +gboolean +gst_amc_codec_stop (GstAmcCodec * codec, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.stop); +} + +gboolean +gst_amc_codec_flush (GstAmcCodec * codec, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + + env = gst_amc_jni_get_env (); + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.flush); +} + +gboolean +gst_amc_codec_release (GstAmcCodec * codec, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (codec->input_buffers) + gst_amc_jni_free_buffer_array (env, codec->input_buffers, + codec->n_input_buffers); + codec->input_buffers = NULL; + codec->n_input_buffers = 0; + + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = NULL; + codec->n_output_buffers = 0; + + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.release); +} + +GstAmcBuffer * +gst_amc_codec_get_output_buffer (GstAmcCodec * codec, gint index, GError ** err) +{ + JNIEnv *env; + jobject buffer = NULL; + RealBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (index >= 0, NULL); + + env = gst_amc_jni_get_env (); + + if (!media_codec.get_output_buffer) { + g_return_val_if_fail (index < codec->n_output_buffers && index >= 0, NULL); + if (codec->output_buffers[index].object) + return gst_amc_buffer_copy (&codec->output_buffers[index]); + else + return NULL; + } + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_output_buffer, &buffer, index)) + goto done; + + if (buffer != NULL) { + ret = g_new0 (RealBuffer, 1); + ret->object = gst_amc_jni_object_make_global (env, buffer); + if (!ret->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); + goto error; + } + + ret->data = (*env)->GetDirectBufferAddress (env, ret->object); + if (!ret->data) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); + goto error; + } + ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); + } + +done: + + return (GstAmcBuffer *) ret; + +error: + if (ret->object) + gst_amc_jni_object_unref (env, ret->object); + g_free (ret); + + return NULL; +} + +GstAmcBuffer * +gst_amc_codec_get_input_buffer (GstAmcCodec * codec, gint index, GError ** err) +{ + JNIEnv *env; + jobject buffer = NULL; + RealBuffer *ret = NULL; + + g_return_val_if_fail (codec != NULL, NULL); + g_return_val_if_fail (index >= 0, NULL); + + env = gst_amc_jni_get_env (); + + if (!media_codec.get_input_buffer) { + g_return_val_if_fail (index < codec->n_input_buffers && index >= 0, NULL); + if (codec->input_buffers[index].object) + return gst_amc_buffer_copy (&codec->input_buffers[index]); + else + return NULL; + } + + if (!gst_amc_jni_call_object_method (env, err, codec->object, + media_codec.get_input_buffer, &buffer, index)) + goto done; + + if (buffer != NULL) { + ret = g_new0 (RealBuffer, 1); + ret->object = gst_amc_jni_object_make_global (env, buffer); + if (!ret->object) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to create global buffer reference"); + goto error; + } + + ret->data = (*env)->GetDirectBufferAddress (env, ret->object); + if (!ret->data) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address"); + goto error; + } + ret->size = (*env)->GetDirectBufferCapacity (env, ret->object); + } + +done: + + return (GstAmcBuffer *) ret; + +error: + if (ret->object) + gst_amc_jni_object_unref (env, ret->object); + g_free (ret); + + return NULL; +} + +gint +gst_amc_codec_dequeue_input_buffer (GstAmcCodec * codec, gint64 timeoutUs, + GError ** err) +{ + JNIEnv *env; + gint ret = G_MININT; + + g_return_val_if_fail (codec != NULL, G_MININT); + + env = gst_amc_jni_get_env (); + if (!gst_amc_jni_call_int_method (env, err, codec->object, + media_codec.dequeue_input_buffer, &ret, timeoutUs)) + return G_MININT; + + return ret; +} + +static gboolean +gst_amc_codec_fill_buffer_info (JNIEnv * env, jobject buffer_info, + GstAmcBufferInfo * info, GError ** err) +{ + g_return_val_if_fail (buffer_info != NULL, FALSE); + + if (!gst_amc_jni_get_int_field (env, err, buffer_info, + media_codec_buffer_info.flags, &info->flags)) + return FALSE; + + if (!gst_amc_jni_get_int_field (env, err, buffer_info, + media_codec_buffer_info.offset, &info->offset)) + return FALSE; + + if (!gst_amc_jni_get_long_field (env, err, buffer_info, + media_codec_buffer_info.presentation_time_us, + &info->presentation_time_us)) + return FALSE; + + if (!gst_amc_jni_get_int_field (env, err, buffer_info, + media_codec_buffer_info.size, &info->size)) + return FALSE; + + return TRUE; +} + +gint +gst_amc_codec_dequeue_output_buffer (GstAmcCodec * codec, + GstAmcBufferInfo * info, gint64 timeoutUs, GError ** err) +{ + JNIEnv *env; + gint ret = G_MININT; + jobject info_o = NULL; + + g_return_val_if_fail (codec != NULL, G_MININT); + + env = gst_amc_jni_get_env (); + + info_o = + gst_amc_jni_new_object (env, err, FALSE, media_codec_buffer_info.klass, + media_codec_buffer_info.constructor); + if (!info_o) + goto done; + + if (!gst_amc_jni_call_int_method (env, err, codec->object, + media_codec.dequeue_output_buffer, &ret, info_o, timeoutUs)) { + ret = G_MININT; + goto done; + } + + if (ret == INFO_OUTPUT_BUFFERS_CHANGED || ret == INFO_OUTPUT_FORMAT_CHANGED + || (ret >= 0 && !codec->output_buffers + && !media_codec.get_output_buffer)) { + if (!media_codec.get_output_buffer) { + if (codec->output_buffers) + gst_amc_jni_free_buffer_array (env, codec->output_buffers, + codec->n_output_buffers); + codec->output_buffers = + gst_amc_codec_get_output_buffers (codec, + &codec->n_output_buffers, err); + if (!codec->output_buffers) { + ret = G_MININT; + goto done; + } + } + if (ret == INFO_OUTPUT_BUFFERS_CHANGED) { + gst_amc_jni_object_local_unref (env, info_o); + return gst_amc_codec_dequeue_output_buffer (codec, info, timeoutUs, err); + } + } else if (ret < 0) { + goto done; + } + + if (ret >= 0 && !gst_amc_codec_fill_buffer_info (env, info_o, info, err)) { + ret = G_MININT; + goto done; + } + +done: + if (info_o) + gst_amc_jni_object_local_unref (env, info_o); + info_o = NULL; + + return ret; +} + +gboolean +gst_amc_codec_queue_input_buffer (GstAmcCodec * codec, gint index, + const GstAmcBufferInfo * info, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + g_return_val_if_fail (info != NULL, FALSE); + + env = gst_amc_jni_get_env (); + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.queue_input_buffer, index, info->offset, info->size, + info->presentation_time_us, info->flags); +} + +gboolean +gst_amc_codec_release_output_buffer (GstAmcCodec * codec, gint index, + gboolean render, GError ** err) +{ + JNIEnv *env; + + g_return_val_if_fail (codec != NULL, FALSE); + + env = gst_amc_jni_get_env (); + return gst_amc_jni_call_void_method (env, err, codec->object, + media_codec.release_output_buffer, index, render); +} diff --git a/sys/androidmedia/jni/gstamc-format-jni.c b/sys/androidmedia/jni/gstamc-format-jni.c new file mode 100644 index 0000000..8d37056 --- /dev/null +++ b/sys/androidmedia/jni/gstamc-format-jni.c @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * Copyright (C) 2015, Sebastian Dröge + * + * 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 "../gstjniutils.h" +#include "../gstamc-format.h" +#include "gstamc-internal-jni.h" + +static struct +{ + jclass klass; + jmethodID create_audio_format; + jmethodID create_video_format; + jmethodID to_string; + jmethodID contains_key; + jmethodID get_float; + jmethodID set_float; + jmethodID get_integer; + jmethodID set_integer; + jmethodID get_string; + jmethodID set_string; + jmethodID get_byte_buffer; + jmethodID set_byte_buffer; +} media_format; + +gboolean +gst_amc_format_static_init (void) +{ + gboolean ret = TRUE; + JNIEnv *env; + jclass tmp; + + env = gst_amc_jni_get_env (); + + tmp = (*env)->FindClass (env, "android/media/MediaFormat"); + if (!tmp) { + ret = FALSE; + GST_ERROR ("Failed to get format class"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + media_format.klass = (*env)->NewGlobalRef (env, tmp); + if (!media_format.klass) { + ret = FALSE; + GST_ERROR ("Failed to get format class global reference"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + (*env)->DeleteLocalRef (env, tmp); + tmp = NULL; + + media_format.create_audio_format = + (*env)->GetStaticMethodID (env, media_format.klass, "createAudioFormat", + "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + media_format.create_video_format = + (*env)->GetStaticMethodID (env, media_format.klass, "createVideoFormat", + "(Ljava/lang/String;II)Landroid/media/MediaFormat;"); + media_format.to_string = + (*env)->GetMethodID (env, media_format.klass, "toString", + "()Ljava/lang/String;"); + media_format.contains_key = + (*env)->GetMethodID (env, media_format.klass, "containsKey", + "(Ljava/lang/String;)Z"); + media_format.get_float = + (*env)->GetMethodID (env, media_format.klass, "getFloat", + "(Ljava/lang/String;)F"); + media_format.set_float = + (*env)->GetMethodID (env, media_format.klass, "setFloat", + "(Ljava/lang/String;F)V"); + media_format.get_integer = + (*env)->GetMethodID (env, media_format.klass, "getInteger", + "(Ljava/lang/String;)I"); + media_format.set_integer = + (*env)->GetMethodID (env, media_format.klass, "setInteger", + "(Ljava/lang/String;I)V"); + media_format.get_string = + (*env)->GetMethodID (env, media_format.klass, "getString", + "(Ljava/lang/String;)Ljava/lang/String;"); + media_format.set_string = + (*env)->GetMethodID (env, media_format.klass, "setString", + "(Ljava/lang/String;Ljava/lang/String;)V"); + media_format.get_byte_buffer = + (*env)->GetMethodID (env, media_format.klass, "getByteBuffer", + "(Ljava/lang/String;)Ljava/nio/ByteBuffer;"); + media_format.set_byte_buffer = + (*env)->GetMethodID (env, media_format.klass, "setByteBuffer", + "(Ljava/lang/String;Ljava/nio/ByteBuffer;)V"); + if (!media_format.create_audio_format || !media_format.create_video_format + || !media_format.contains_key || !media_format.get_float + || !media_format.set_float || !media_format.get_integer + || !media_format.set_integer || !media_format.get_string + || !media_format.set_string || !media_format.get_byte_buffer + || !media_format.set_byte_buffer) { + ret = FALSE; + GST_ERROR ("Failed to get format methods"); + if ((*env)->ExceptionCheck (env)) { + (*env)->ExceptionDescribe (env); + (*env)->ExceptionClear (env); + } + goto done; + } + +done: + if (tmp) + (*env)->DeleteLocalRef (env, tmp); + tmp = NULL; + + return ret; +} + +GstAmcFormat * +gst_amc_format_new_audio (const gchar * mime, gint sample_rate, gint channels, + GError ** err) +{ + JNIEnv *env; + GstAmcFormat *format = NULL; + jstring mime_str; + + g_return_val_if_fail (mime != NULL, NULL); + + env = gst_amc_jni_get_env (); + + mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime); + if (!mime_str) + goto error; + + format = g_slice_new0 (GstAmcFormat); + format->object = + gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass, + media_format.create_audio_format, mime_str, sample_rate, channels); + if (!format->object) + goto error; + +done: + if (mime_str) + gst_amc_jni_object_local_unref (env, mime_str); + mime_str = NULL; + + return format; + +error: + if (format) + g_slice_free (GstAmcFormat, format); + format = NULL; + goto done; +} + +GstAmcFormat * +gst_amc_format_new_video (const gchar * mime, gint width, gint height, + GError ** err) +{ + JNIEnv *env; + GstAmcFormat *format = NULL; + jstring mime_str; + + g_return_val_if_fail (mime != NULL, NULL); + + env = gst_amc_jni_get_env (); + + mime_str = gst_amc_jni_string_from_gchar (env, err, FALSE, mime); + if (!mime_str) + goto error; + + format = g_slice_new0 (GstAmcFormat); + format->object = + gst_amc_jni_new_object_from_static (env, err, TRUE, media_format.klass, + media_format.create_video_format, mime_str, width, height); + if (!format->object) + goto error; + +done: + if (mime_str) + gst_amc_jni_object_local_unref (env, mime_str); + mime_str = NULL; + + return format; + +error: + if (format) + g_slice_free (GstAmcFormat, format); + format = NULL; + goto done; +} + +void +gst_amc_format_free (GstAmcFormat * format) +{ + JNIEnv *env; + + g_return_if_fail (format != NULL); + + env = gst_amc_jni_get_env (); + gst_amc_jni_object_unref (env, format->object); + g_slice_free (GstAmcFormat, format); +} + +gchar * +gst_amc_format_to_string (GstAmcFormat * format, GError ** err) +{ + JNIEnv *env; + jstring v_str = NULL; + gchar *ret = NULL; + + g_return_val_if_fail (format != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + if (!gst_amc_jni_call_object_method (env, err, format->object, + media_format.to_string, &v_str)) + goto done; + ret = gst_amc_jni_string_to_gchar (env, v_str, TRUE); + +done: + + return ret; +} + +gboolean +gst_amc_format_contains_key (GstAmcFormat * format, const gchar * key, + GError ** err) +{ + JNIEnv *env; + gboolean ret = FALSE; + jstring key_str = NULL; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_boolean_method (env, err, format->object, + media_format.contains_key, &ret, key_str)) + goto done; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; +} + +gboolean +gst_amc_format_get_float (GstAmcFormat * format, const gchar * key, + gfloat * value, GError ** err) +{ + JNIEnv *env; + gboolean ret = FALSE; + jstring key_str = NULL; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_float_method (env, err, format->object, + media_format.get_float, value, key_str)) + goto done; + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; +} + +gboolean +gst_amc_format_set_float (GstAmcFormat * format, const gchar * key, + gfloat value, GError ** err) +{ + JNIEnv *env; + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_void_method (env, err, format->object, + media_format.set_float, key_str, value)) + goto done; + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; +} + +gboolean +gst_amc_format_get_int (GstAmcFormat * format, const gchar * key, gint * value, + GError ** err) +{ + JNIEnv *env; + gboolean ret = FALSE; + jstring key_str = NULL; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_int_method (env, err, format->object, + media_format.get_integer, value, key_str)) + goto done; + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; + +} + +gboolean +gst_amc_format_set_int (GstAmcFormat * format, const gchar * key, gint value, + GError ** err) +{ + JNIEnv *env; + jstring key_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_void_method (env, err, format->object, + media_format.set_integer, key_str, value)) + goto done; + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; +} + +gboolean +gst_amc_format_get_string (GstAmcFormat * format, const gchar * key, + gchar ** value, GError ** err) +{ + JNIEnv *env; + gboolean ret = FALSE; + jstring key_str = NULL; + jstring v_str = NULL; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + *value = 0; + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_object_method (env, err, format->object, + media_format.get_string, &v_str, key_str)) + goto done; + + *value = gst_amc_jni_string_to_gchar (env, v_str, TRUE); + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + + return ret; +} + +gboolean +gst_amc_format_set_string (GstAmcFormat * format, const gchar * key, + const gchar * value, GError ** err) +{ + JNIEnv *env; + jstring key_str = NULL; + jstring v_str = NULL; + gboolean ret = FALSE; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + v_str = gst_amc_jni_string_from_gchar (env, err, FALSE, value); + if (!v_str) + goto done; + + if (!gst_amc_jni_call_void_method (env, err, format->object, + media_format.set_string, key_str, v_str)) + goto done; + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + if (v_str) + gst_amc_jni_object_local_unref (env, v_str); + + return ret; +} + +gboolean +gst_amc_format_get_buffer (GstAmcFormat * format, const gchar * key, + guint8 ** data, gsize * size, GError ** err) +{ + JNIEnv *env; + gboolean ret = FALSE; + jstring key_str = NULL; + jobject v = NULL; + RealBuffer buf = { 0, }; + gint position = 0, limit = 0; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (size != NULL, FALSE); + + *data = NULL; + *size = 0; + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + if (!gst_amc_jni_call_object_method (env, err, format->object, + media_format.get_byte_buffer, &v, key_str)) + goto done; + + *data = (*env)->GetDirectBufferAddress (env, v); + if (*data == NULL) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed get buffer address"); + goto done; + } + *size = (*env)->GetDirectBufferCapacity (env, v); + + buf.object = v; + buf.data = *data; + buf.size = *size; + gst_amc_buffer_get_position_and_limit (&buf, NULL, &position, &limit); + *size = limit; + + *data = g_memdup (*data + position, limit); + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + if (v) + gst_amc_jni_object_local_unref (env, v); + + return ret; +} + +gboolean +gst_amc_format_set_buffer (GstAmcFormat * format, const gchar * key, + guint8 * data, gsize size, GError ** err) +{ + JNIEnv *env; + jstring key_str = NULL; + jobject v = NULL; + gboolean ret = FALSE; + RealBuffer buf = { 0, }; + + g_return_val_if_fail (format != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + + env = gst_amc_jni_get_env (); + + key_str = gst_amc_jni_string_from_gchar (env, err, FALSE, key); + if (!key_str) + goto done; + + /* FIXME: The memory must remain valid until the codec is stopped */ + v = (*env)->NewDirectByteBuffer (env, data, size); + if (!v) { + gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, + GST_LIBRARY_ERROR_FAILED, "Failed create Java byte buffer"); + goto done; + } + + buf.object = v; + buf.data = data; + buf.size = size; + + gst_amc_buffer_set_position_and_limit ((GstAmcBuffer *) & buf, NULL, 0, size); + + if (!gst_amc_jni_call_void_method (env, err, format->object, + media_format.set_byte_buffer, key_str, v)) + goto done; + + ret = TRUE; + +done: + if (key_str) + gst_amc_jni_object_local_unref (env, key_str); + if (v) + gst_amc_jni_object_local_unref (env, v); + + return ret; +} diff --git a/sys/androidmedia/jni/gstamc-internal-jni.h b/sys/androidmedia/jni/gstamc-internal-jni.h new file mode 100644 index 0000000..a1c6558 --- /dev/null +++ b/sys/androidmedia/jni/gstamc-internal-jni.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012,2018 Collabora Ltd. + * Author: Sebastian Dröge + * + * 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_AMC_INTERNAL_JNI_H__ +#define __GST_AMC_INTERNAL_JNI_H__ + +#include "../gstamc-codec.h" +#include "../gstamc-format.h" + +G_BEGIN_DECLS + +struct _GstAmcFormat +{ + /* < private > */ + jobject object; /* global reference */ +}; + +typedef struct +{ + guint8 *data; + gsize size; + + jobject object; /* global reference */ +} RealBuffer; + +gboolean +gst_amc_buffer_get_position_and_limit (RealBuffer * buffer_, GError ** err, + gint * position, gint * limit); + +G_END_DECLS + +#endif /* __GST_AMC_INTERNAL_JNI_H__ */ diff --git a/sys/androidmedia/meson.build b/sys/androidmedia/meson.build index d41d399..79bc2f8 100644 --- a/sys/androidmedia/meson.build +++ b/sys/androidmedia/meson.build @@ -10,7 +10,9 @@ androidmedia_sources = [ 'gst-android-graphics-imageformat.c', 'gst-android-hardware-camera.c', 'gst-android-hardware-sensor.c', - 'gstjniutils.c' + 'gstjniutils.c', + 'jni/gstamc-codec-jni.c', + 'jni/gstamc-format-jni.c', ] androidmedia_java_sources = [ -- 2.7.4