mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 09:55:36 +00:00
amc: Move MediaCodec JNI wrapper into its own module
This will facilitate adding another implementation based on NdkMediaCodec instead of JNI.
This commit is contained in:
parent
70a90f0e5e
commit
515398a9ff
10 changed files with 1692 additions and 1572 deletions
74
sys/androidmedia/gstamc-codec.h
Normal file
74
sys/androidmedia/gstamc-codec.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2018 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* 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 <gst/gst.h>
|
||||
|
||||
#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__ */
|
52
sys/androidmedia/gstamc-format.h
Normal file
52
sys/androidmedia/gstamc-format.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2018 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* 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 <gst/gst.h>
|
||||
|
||||
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__ */
|
File diff suppressed because it is too large
Load diff
|
@ -27,15 +27,13 @@
|
|||
#include <jni.h>
|
||||
|
||||
#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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
936
sys/androidmedia/jni/gstamc-codec-jni.c
Normal file
936
sys/androidmedia/jni/gstamc-codec-jni.c
Normal file
|
@ -0,0 +1,936 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2018 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
* Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
|
||||
*
|
||||
* 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, "<init>", "()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);
|
||||
}
|
571
sys/androidmedia/jni/gstamc-format-jni.c
Normal file
571
sys/androidmedia/jni/gstamc-format-jni.c
Normal file
|
@ -0,0 +1,571 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2018 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
* Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
|
||||
*
|
||||
* 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;
|
||||
}
|
49
sys/androidmedia/jni/gstamc-internal-jni.h
Normal file
49
sys/androidmedia/jni/gstamc-internal-jni.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2012,2018 Collabora Ltd.
|
||||
* Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
|
||||
*
|
||||
* 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__ */
|
|
@ -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 = [
|
||||
|
|
Loading…
Reference in a new issue