2 * Copyright (C) 2012, Collabora Ltd.
3 * Author: Sebastian Dröge <sebastian.droege@collabora.co.uk>
4 * Copyright (C) 2013, Fluendo S.A.
5 * Author: Andoni Morales <amorales@fluendo.com>
6 * Copyright (C) 2014, Sebastian Dröge <sebastian@centricular.com>
7 * Copyright (C) 2014, Collabora Ltd.
8 * Author: Matthieu Bouron <matthieu.bouron@collabora.com>
9 * Copyright (C) 2015, Sebastian Dröge <sebastian@centricular.com>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation
14 * version 2.1 of the License.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
35 #include "gstjniutils.h"
37 static GModule *java_module;
38 static jint (*get_created_java_vms) (JavaVM ** vmBuf, jsize bufLen,
40 static jint (*create_java_vm) (JavaVM ** p_vm, JNIEnv ** p_env, void *vm_args);
41 static JavaVM *java_vm;
42 static gboolean started_java_vm = FALSE;
43 static pthread_key_t current_jni_env;
44 static jobject (*get_class_loader) (void);
49 jmethodID get_limit, get_position;
50 jmethodID set_limit, set_position;
55 gst_amc_jni_get_class (JNIEnv * env, GError ** err, const gchar * name)
57 jclass tmp, ret = NULL;
59 GST_DEBUG ("Retrieving Java class %s", name);
61 tmp = (*env)->FindClass (env, name);
62 if ((*env)->ExceptionCheck (env) || !tmp) {
63 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
64 GST_LIBRARY_ERROR_FAILED, "Failed to find class %s", name);
68 ret = (*env)->NewGlobalRef (env, tmp);
70 GST_ERROR ("Failed to get %s class global reference", name);
75 (*env)->DeleteLocalRef (env, tmp);
82 gst_amc_jni_get_method_id (JNIEnv * env, GError ** err, jclass klass,
83 const gchar * name, const gchar * signature)
87 ret = (*env)->GetMethodID (env, klass, name, signature);
88 if ((*env)->ExceptionCheck (env) || !ret) {
89 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
90 GST_LIBRARY_ERROR_FAILED, "Failed to get method ID %s (%s)", name,
97 gst_amc_jni_get_static_method_id (JNIEnv * env, GError ** err, jclass klass,
98 const gchar * name, const gchar * signature)
102 ret = (*env)->GetStaticMethodID (env, klass, name, signature);
103 if ((*env)->ExceptionCheck (env) || !ret) {
104 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
105 GST_LIBRARY_ERROR_FAILED, "Failed to get static method ID %s (%s)",
112 gst_amc_jni_get_field_id (JNIEnv * env, GError ** err, jclass klass,
113 const gchar * name, const gchar * type)
117 ret = (*env)->GetFieldID (env, klass, name, type);
118 if ((*env)->ExceptionCheck (env) || !ret) {
119 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
120 GST_LIBRARY_ERROR_FAILED, "Failed to get field ID %s (%s)", name, type);
126 gst_amc_jni_get_static_field_id (JNIEnv * env, GError ** err, jclass klass,
127 const gchar * name, const gchar * type)
131 ret = (*env)->GetStaticFieldID (env, klass, name, type);
132 if ((*env)->ExceptionCheck (env) || !ret) {
133 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
134 GST_LIBRARY_ERROR_FAILED, "Failed to get static field ID %s (%s)", name,
141 gst_amc_jni_new_object (JNIEnv * env, GError ** err, gboolean global,
142 jclass klass, jmethodID constructor, ...)
147 va_start (args, constructor);
148 tmp = (*env)->NewObjectV (env, klass, constructor, args);
151 if ((*env)->ExceptionCheck (env) || !tmp) {
152 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
153 GST_LIBRARY_ERROR_FAILED, "Failed to create object");
158 return gst_amc_jni_object_make_global (env, tmp);
164 gst_amc_jni_new_object_from_static (JNIEnv * env, GError ** err,
165 gboolean global, jclass klass, jmethodID method, ...)
170 va_start (args, method);
171 tmp = (*env)->CallStaticObjectMethodV (env, klass, method, args);
174 if ((*env)->ExceptionCheck (env) || !tmp) {
175 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
176 GST_LIBRARY_ERROR_FAILED, "Failed to create object");
181 return gst_amc_jni_object_make_global (env, tmp);
187 gst_amc_jni_object_make_global (JNIEnv * env, jobject object)
191 ret = (*env)->NewGlobalRef (env, object);
193 GST_ERROR ("Failed to create global reference");
195 gst_amc_jni_object_local_unref (env, object);
201 gst_amc_jni_object_ref (JNIEnv * env, jobject object)
205 ret = (*env)->NewGlobalRef (env, object);
207 GST_ERROR ("Failed to create global reference");
213 gst_amc_jni_object_unref (JNIEnv * env, jobject object)
215 g_return_if_fail (object != NULL);
217 (*env)->DeleteGlobalRef (env, object);
221 gst_amc_jni_object_local_unref (JNIEnv * env, jobject object)
223 g_return_if_fail (object != NULL);
225 (*env)->DeleteLocalRef (env, object);
229 gst_amc_jni_string_from_gchar (JNIEnv * env, GError ** err,
230 gboolean global, const gchar * string)
234 tmp = (*env)->NewStringUTF (env, string);
235 if ((*env)->ExceptionCheck (env)) {
236 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
237 GST_LIBRARY_ERROR_FAILED, "Failed to call Java method");
242 return gst_amc_jni_object_make_global (env, tmp);
248 gst_amc_jni_string_to_gchar (JNIEnv * env, jstring string, gboolean release)
250 const gchar *s = NULL;
253 s = (*env)->GetStringUTFChars (env, string, NULL);
255 GST_ERROR ("Failed to convert string to UTF8");
260 (*env)->ReleaseStringUTFChars (env, string, s);
264 (*env)->DeleteLocalRef (env, string);
269 /* getExceptionSummary() and getStackTrace() taken from Android's
270 * platform/libnativehelper/JNIHelp.cpp
271 * Modified to work with normal C strings and without C++.
273 * Copyright (C) 2006 The Android Open Source Project
275 * Licensed under the Apache License, Version 2.0 (the "License");
276 * you may not use this file except in compliance with the License.
277 * You may obtain a copy of the License at
279 * http://www.apache.org/licenses/LICENSE-2.0
281 * Unless required by applicable law or agreed to in writing, software
282 * distributed under the License is distributed on an "AS IS" BASIS,
283 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
284 * See the License for the specific language governing permissions and
285 * limitations under the License.
289 * Returns a human-readable summary of an exception object. The buffer will
290 * be populated with the "binary" class name and, if present, the
294 getExceptionSummary (JNIEnv * env, jthrowable exception)
296 GString *gs = g_string_new ("");
297 jclass exceptionClass = NULL, classClass = NULL;
298 jmethodID classGetNameMethod, getMessage;
299 jstring classNameStr = NULL, messageStr = NULL;
300 const char *classNameChars, *messageChars;
302 /* get the name of the exception's class */
303 exceptionClass = (*env)->GetObjectClass (env, exception);
304 classClass = (*env)->GetObjectClass (env, exceptionClass);
306 (*env)->GetMethodID (env, classClass, "getName", "()Ljava/lang/String;");
309 (jstring) (*env)->CallObjectMethod (env, exceptionClass,
312 if (classNameStr == NULL) {
313 if ((*env)->ExceptionCheck (env))
314 (*env)->ExceptionClear (env);
315 g_string_append (gs, "<error getting class name>");
319 classNameChars = (*env)->GetStringUTFChars (env, classNameStr, NULL);
320 if (classNameChars == NULL) {
321 if ((*env)->ExceptionCheck (env))
322 (*env)->ExceptionClear (env);
323 g_string_append (gs, "<error getting class name UTF-8>");
327 g_string_append (gs, classNameChars);
329 (*env)->ReleaseStringUTFChars (env, classNameStr, classNameChars);
331 /* if the exception has a detail message, get that */
333 (*env)->GetMethodID (env, exceptionClass, "getMessage",
334 "()Ljava/lang/String;");
335 messageStr = (jstring) (*env)->CallObjectMethod (env, exception, getMessage);
336 if (messageStr == NULL) {
337 if ((*env)->ExceptionCheck (env))
338 (*env)->ExceptionClear (env);
341 g_string_append (gs, ": ");
343 messageChars = (*env)->GetStringUTFChars (env, messageStr, NULL);
344 if (messageChars != NULL) {
345 g_string_append (gs, messageChars);
346 (*env)->ReleaseStringUTFChars (env, messageStr, messageChars);
348 if ((*env)->ExceptionCheck (env))
349 (*env)->ExceptionClear (env);
350 g_string_append (gs, "<error getting message>");
355 (*env)->DeleteLocalRef (env, exceptionClass);
357 (*env)->DeleteLocalRef (env, classClass);
359 (*env)->DeleteLocalRef (env, classNameStr);
361 (*env)->DeleteLocalRef (env, messageStr);
363 return g_string_free (gs, FALSE);
367 * Returns an exception (with stack trace) as a string.
370 getStackTrace (JNIEnv * env, jthrowable exception)
372 GString *gs = g_string_new ("");
373 jclass stringWriterClass = NULL, printWriterClass = NULL;
374 jclass exceptionClass = NULL;
375 jmethodID stringWriterCtor, stringWriterToStringMethod;
376 jmethodID printWriterCtor, printStackTraceMethod;
377 jobject stringWriter = NULL, printWriter = NULL;
378 jstring messageStr = NULL;
379 const char *utfChars;
381 stringWriterClass = (*env)->FindClass (env, "java/io/StringWriter");
383 if (stringWriterClass == NULL) {
384 g_string_append (gs, "<error getting java.io.StringWriter class>");
389 (*env)->GetMethodID (env, stringWriterClass, "<init>", "()V");
390 stringWriterToStringMethod =
391 (*env)->GetMethodID (env, stringWriterClass, "toString",
392 "()Ljava/lang/String;");
394 printWriterClass = (*env)->FindClass (env, "java/io/PrintWriter");
395 if (printWriterClass == NULL) {
396 g_string_append (gs, "<error getting java.io.PrintWriter class>");
401 (*env)->GetMethodID (env, printWriterClass, "<init>",
402 "(Ljava/io/Writer;)V");
403 stringWriter = (*env)->NewObject (env, stringWriterClass, stringWriterCtor);
404 if (stringWriter == NULL) {
405 if ((*env)->ExceptionCheck (env))
406 (*env)->ExceptionClear (env);
407 g_string_append (gs, "<error creating new StringWriter instance>");
412 (*env)->NewObject (env, printWriterClass, printWriterCtor, stringWriter);
413 if (printWriter == NULL) {
414 if ((*env)->ExceptionCheck (env))
415 (*env)->ExceptionClear (env);
416 g_string_append (gs, "<error creating new PrintWriter instance>");
420 exceptionClass = (*env)->GetObjectClass (env, exception);
421 printStackTraceMethod =
422 (*env)->GetMethodID (env, exceptionClass, "printStackTrace",
423 "(Ljava/io/PrintWriter;)V");
424 (*env)->CallVoidMethod (env, exception, printStackTraceMethod, printWriter);
425 if ((*env)->ExceptionCheck (env)) {
426 (*env)->ExceptionClear (env);
427 g_string_append (gs, "<exception while printing stack trace>");
431 messageStr = (jstring) (*env)->CallObjectMethod (env, stringWriter,
432 stringWriterToStringMethod);
433 if (messageStr == NULL) {
434 if ((*env)->ExceptionCheck (env))
435 (*env)->ExceptionClear (env);
436 g_string_append (gs, "<failed to call StringWriter.toString()>");
440 utfChars = (*env)->GetStringUTFChars (env, messageStr, NULL);
441 if (utfChars == NULL) {
442 if ((*env)->ExceptionCheck (env))
443 (*env)->ExceptionClear (env);
444 g_string_append (gs, "<failed to get UTF chars for message>");
448 g_string_append (gs, utfChars);
450 (*env)->ReleaseStringUTFChars (env, messageStr, utfChars);
453 if (stringWriterClass)
454 (*env)->DeleteLocalRef (env, stringWriterClass);
455 if (printWriterClass)
456 (*env)->DeleteLocalRef (env, printWriterClass);
458 (*env)->DeleteLocalRef (env, exceptionClass);
460 (*env)->DeleteLocalRef (env, stringWriter);
462 (*env)->DeleteLocalRef (env, printWriter);
464 (*env)->DeleteLocalRef (env, messageStr);
466 return g_string_free (gs, FALSE);
470 gst_amc_jni_attach_current_thread (void)
473 JavaVMAttachArgs args;
476 GST_DEBUG ("Attaching thread %p", g_thread_self ());
477 args.version = JNI_VERSION_1_6;
481 if ((ret = (*java_vm)->AttachCurrentThread (java_vm, &env, &args)) != JNI_OK) {
482 GST_ERROR ("Failed to attach current thread: %d", ret);
490 gst_amc_jni_detach_current_thread (void *env)
494 GST_DEBUG ("Detaching thread %p", g_thread_self ());
495 if ((ret = (*java_vm)->DetachCurrentThread (java_vm)) != JNI_OK) {
496 GST_DEBUG ("Failed to detach current thread: %d", ret);
501 get_application_java_vm (void)
503 GModule *module = NULL;
504 JavaVM *(*get_java_vm) (void);
507 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
513 if (g_module_symbol (module, "gst_android_get_java_vm",
514 (gpointer *) & get_java_vm) && get_java_vm) {
518 g_module_close (module);
524 check_nativehelper (void)
527 void **jni_invocation = NULL;
528 gboolean ret = FALSE;
530 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
534 /* Check if libnativehelper is loaded in the process and if
535 * it has these awful wrappers for JNI_CreateJavaVM and
536 * JNI_GetCreatedJavaVMs that crash the app if you don't
537 * create a JniInvocation instance first. If it isn't we
538 * just fail here and don't initialize anything.
539 * See this code for reference:
540 * https://android.googlesource.com/platform/libnativehelper/+/master/JniInvocation.cpp
542 if (!g_module_symbol (module, "_ZN13JniInvocation15jni_invocation_E",
543 (gpointer *) & jni_invocation)) {
546 ret = (jni_invocation != NULL && *jni_invocation != NULL);
549 g_module_close (module);
555 load_java_module (const gchar * name)
557 java_module = g_module_open (name, G_MODULE_BIND_LOCAL);
561 if (!g_module_symbol (java_module, "JNI_CreateJavaVM",
562 (gpointer *) & create_java_vm)) {
563 GST_ERROR ("Could not find 'JNI_CreateJavaVM' in '%s': %s",
564 GST_STR_NULL (name), g_module_error ());
565 create_java_vm = NULL;
568 if (!g_module_symbol (java_module, "JNI_GetCreatedJavaVMs",
569 (gpointer *) & get_created_java_vms))
576 GST_ERROR ("Failed to load Java module '%s': %s", GST_STR_NULL (name),
582 GST_ERROR ("Failed to locate required JNI symbols in '%s': %s",
583 GST_STR_NULL (name), g_module_error ());
584 g_module_close (java_module);
591 check_application_class_loader (void)
594 GModule *module = NULL;
596 module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
600 if (!g_module_symbol (module, "gst_android_get_application_class_loader",
601 (gpointer *) & get_class_loader)) {
605 g_module_close (module);
611 initialize_classes (void)
616 env = gst_amc_jni_get_env ();
618 java_nio_buffer.klass = gst_amc_jni_get_class (env, &err, "java/nio/Buffer");
619 if (!java_nio_buffer.klass) {
620 GST_ERROR ("Failed to get java.nio.Buffer class: %s", err->message);
621 g_clear_error (&err);
625 java_nio_buffer.get_limit =
626 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit",
628 if (!java_nio_buffer.get_limit) {
629 GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message);
630 g_clear_error (&err);
634 java_nio_buffer.get_position =
635 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position",
637 if (!java_nio_buffer.get_position) {
638 GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message);
639 g_clear_error (&err);
643 java_nio_buffer.set_limit =
644 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "limit",
645 "(I)Ljava/nio/Buffer;");
646 if (!java_nio_buffer.set_limit) {
647 GST_ERROR ("Failed to get java.nio.Buffer limit(): %s", err->message);
648 g_clear_error (&err);
652 java_nio_buffer.set_position =
653 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "position",
654 "(I)Ljava/nio/Buffer;");
655 if (!java_nio_buffer.set_position) {
656 GST_ERROR ("Failed to get java.nio.Buffer position(): %s", err->message);
657 g_clear_error (&err);
661 java_nio_buffer.clear =
662 gst_amc_jni_get_method_id (env, &err, java_nio_buffer.klass, "clear",
663 "()Ljava/nio/Buffer;");
664 if (!java_nio_buffer.clear) {
665 GST_ERROR ("Failed to get java.nio.Buffer clear(): %s", err->message);
666 g_clear_error (&err);
670 if (!check_application_class_loader ()) {
671 GST_ERROR ("Could not find application class loader provider");
679 gst_amc_jni_initialize_java_vm (void)
685 GST_DEBUG ("Java VM already provided by the application");
686 return initialize_classes ();
689 java_vm = get_application_java_vm ();
691 GST_DEBUG ("Java VM successfully requested from the application");
692 return initialize_classes ();
695 /* Returns TRUE if we can safely
696 * a) get the current VMs and
697 * b) start a VM if none is started yet
699 * FIXME: On Android >= 4.4 we won't be able to safely start a
700 * VM on our own without using private C++ API!
702 if (!check_nativehelper ()) {
703 GST_ERROR ("Can't safely check for VMs or start a VM");
707 if (!load_java_module (NULL)) {
708 if (!load_java_module ("libdvm"))
713 if ((ret = get_created_java_vms (&java_vm, 1, &n_vms)) != JNI_OK)
714 goto get_created_failed;
717 GST_DEBUG ("Successfully got existing Java VM %p", java_vm);
718 } else if (create_java_vm) {
720 JavaVMInitArgs vm_args;
721 JavaVMOption options[4];
723 GST_DEBUG ("Found no existing Java VM, trying to start one");
725 options[0].optionString = "-verbose:jni";
726 options[1].optionString = "-verbose:gc";
727 options[2].optionString = "-Xcheck:jni";
728 options[3].optionString = "-Xdebug";
730 vm_args.version = JNI_VERSION_1_4;
731 vm_args.options = options;
732 vm_args.nOptions = 4;
733 vm_args.ignoreUnrecognized = JNI_TRUE;
734 if ((ret = create_java_vm (&java_vm, &env, &vm_args)) != JNI_OK)
736 GST_DEBUG ("Successfully created Java VM %p", java_vm);
738 started_java_vm = TRUE;
740 GST_ERROR ("JNI_CreateJavaVM not available");
747 return initialize_classes ();
751 GST_ERROR ("Failed to get already created VMs: %d", ret);
752 g_module_close (java_module);
758 GST_ERROR ("Failed to create a Java VM: %d", ret);
759 g_module_close (java_module);
766 gst_amc_jni_set_error_string (JNIEnv * env, GError ** err, GQuark domain,
767 gint code, const gchar * message)
769 jthrowable exception;
772 if ((*env)->ExceptionCheck (env))
773 (*env)->ExceptionClear (env);
777 if ((*env)->ExceptionCheck (env)) {
778 if ((exception = (*env)->ExceptionOccurred (env))) {
779 gchar *exception_description, *exception_stacktrace;
781 /* Clear exception so that we can call Java methods again */
782 (*env)->ExceptionClear (env);
784 exception_description = getExceptionSummary (env, exception);
785 exception_stacktrace = getStackTrace (env, exception);
786 g_set_error (err, domain, code, "%s: %s\n%s", message,
787 exception_description, exception_stacktrace);
788 g_free (exception_description);
789 g_free (exception_stacktrace);
791 (*env)->DeleteLocalRef (env, exception);
793 (*env)->ExceptionClear (env);
794 g_set_error (err, domain, code, "%s", message);
797 g_set_error (err, domain, code, "%s", message);
802 void gst_amc_jni_set_error (JNIEnv * env, GError ** err, GQuark domain,
803 gint code, const gchar * format, ...)
808 va_start (var_args, format);
809 message = g_strdup_vprintf (format, var_args);
812 gst_amc_jni_set_error_string (env, err, domain, code, message);
818 gst_amc_jni_initialize_internal (gpointer data)
820 pthread_key_create (¤t_jni_env, gst_amc_jni_detach_current_thread);
821 return gst_amc_jni_initialize_java_vm ()? GINT_TO_POINTER (1) : NULL;
824 /* Allow the application to set the Java VM */
826 gst_amc_jni_set_java_vm (JavaVM * vm)
828 GST_DEBUG ("Application provides Java VM %p", vm);
833 gst_amc_jni_initialize (void)
835 GOnce once = G_ONCE_INIT;
837 g_once (&once, gst_amc_jni_initialize_internal, NULL);
838 return once.retval != NULL;
842 gst_amc_jni_get_env (void)
846 if ((env = pthread_getspecific (current_jni_env)) == NULL) {
847 env = gst_amc_jni_attach_current_thread ();
848 pthread_setspecific (current_jni_env, env);
855 gst_amc_jni_is_vm_started (void)
857 return started_java_vm;
861 gst_amc_jni_get_application_class (JNIEnv * env, const gchar * name,
866 jstring name_jstr = NULL;
868 jobject class_loader = NULL;
869 jclass class_loader_cls = NULL;
870 jmethodID load_class_id = 0;
872 GST_LOG ("attempting to retrieve class %s", name);
874 if (!get_class_loader) {
875 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
876 "Could not retreive application class loader function");
880 class_loader = get_class_loader ();
882 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
883 "Could not retreive application class loader");
887 class_loader_cls = (*env)->GetObjectClass (env, class_loader);
888 if (!class_loader_cls) {
889 g_set_error (err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
890 "Could not retreive application class loader java class");
895 gst_amc_jni_get_method_id (env, err, class_loader_cls, "loadClass",
896 "(Ljava/lang/String;)Ljava/lang/Class;");
897 if (!load_class_id) {
901 name_jstr = gst_amc_jni_string_from_gchar (env, err, FALSE, name);
906 if (gst_amc_jni_call_object_method (env, err, class_loader,
907 load_class_id, &tmp, name_jstr)) {
908 class = gst_amc_jni_object_make_global (env, tmp);
912 gst_amc_jni_object_local_unref (env, name_jstr);
913 gst_amc_jni_object_local_unref (env, class_loader_cls);
918 #define CALL_STATIC_TYPE_METHOD(_type, _name, _jname) \
919 gboolean gst_amc_jni_call_static_##_name##_method (JNIEnv *env, GError ** err, jclass klass, jmethodID methodID, _type * value, ...) \
921 gboolean ret = TRUE; \
923 va_start(args, value); \
924 *value = (*env)->CallStatic##_jname##MethodV(env, klass, methodID, args); \
925 if ((*env)->ExceptionCheck (env)) { \
926 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
927 "Failed to call static Java method"); \
934 CALL_STATIC_TYPE_METHOD (gboolean, boolean, Boolean);
935 CALL_STATIC_TYPE_METHOD (gint8, byte, Byte);
936 CALL_STATIC_TYPE_METHOD (gshort, short, Short);
937 CALL_STATIC_TYPE_METHOD (gint, int, Int);
938 CALL_STATIC_TYPE_METHOD (gchar, char, Char);
939 CALL_STATIC_TYPE_METHOD (gint64, long, Long);
940 CALL_STATIC_TYPE_METHOD (gfloat, float, Float);
941 CALL_STATIC_TYPE_METHOD (gdouble, double, Double);
942 CALL_STATIC_TYPE_METHOD (jobject, object, Object);
945 gst_amc_jni_call_static_void_method (JNIEnv * env, GError ** err, jclass klass,
946 jmethodID methodID, ...)
950 va_start (args, methodID);
952 (*env)->CallStaticVoidMethodV (env, klass, methodID, args);
953 if ((*env)->ExceptionCheck (env)) {
954 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
955 GST_LIBRARY_ERROR_FAILED, "Failed to call static Java method");
962 #define CALL_TYPE_METHOD(_type, _name, _jname) \
963 gboolean gst_amc_jni_call_##_name##_method (JNIEnv *env, GError ** err, jobject obj, jmethodID methodID, _type *value, ...) \
965 gboolean ret = TRUE; \
967 va_start(args, value); \
968 *value = (*env)->Call##_jname##MethodV(env, obj, methodID, args); \
969 if ((*env)->ExceptionCheck (env)) { \
970 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
971 "Failed to call Java method"); \
978 CALL_TYPE_METHOD (gboolean, boolean, Boolean);
979 CALL_TYPE_METHOD (gint8, byte, Byte);
980 CALL_TYPE_METHOD (gshort, short, Short);
981 CALL_TYPE_METHOD (gint, int, Int);
982 CALL_TYPE_METHOD (gchar, char, Char);
983 CALL_TYPE_METHOD (gint64, long, Long);
984 CALL_TYPE_METHOD (gfloat, float, Float);
985 CALL_TYPE_METHOD (gdouble, double, Double);
986 CALL_TYPE_METHOD (jobject, object, Object);
989 gst_amc_jni_call_void_method (JNIEnv * env, GError ** err, jobject obj,
990 jmethodID methodID, ...)
994 va_start (args, methodID);
996 (*env)->CallVoidMethodV (env, obj, methodID, args);
997 if ((*env)->ExceptionCheck (env)) {
998 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
999 GST_LIBRARY_ERROR_FAILED, "Failed to call Java method");
1006 #define GET_TYPE_FIELD(_type, _name, _jname) \
1007 gboolean gst_amc_jni_get_##_name##_field (JNIEnv *env, GError ** err, jobject obj, jfieldID fieldID, _type *value) \
1009 gboolean ret = TRUE; \
1011 *value = (*env)->Get##_jname##Field(env, obj, fieldID); \
1012 if ((*env)->ExceptionCheck (env)) { \
1013 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
1014 "Failed to get Java field"); \
1020 GET_TYPE_FIELD (gboolean, boolean, Boolean);
1021 GET_TYPE_FIELD (gint8, byte, Byte);
1022 GET_TYPE_FIELD (gshort, short, Short);
1023 GET_TYPE_FIELD (gint, int, Int);
1024 GET_TYPE_FIELD (gchar, char, Char);
1025 GET_TYPE_FIELD (gint64, long, Long);
1026 GET_TYPE_FIELD (gfloat, float, Float);
1027 GET_TYPE_FIELD (gdouble, double, Double);
1028 GET_TYPE_FIELD (jobject, object, Object);
1030 #define GET_STATIC_TYPE_FIELD(_type, _name, _jname) \
1031 gboolean gst_amc_jni_get_static_##_name##_field (JNIEnv *env, GError ** err, jclass klass, jfieldID fieldID, _type *value) \
1033 gboolean ret = TRUE; \
1035 *value = (*env)->GetStatic##_jname##Field(env, klass, fieldID); \
1036 if ((*env)->ExceptionCheck (env)) { \
1037 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED, \
1038 "Failed to get static Java field"); \
1044 GET_STATIC_TYPE_FIELD (gboolean, boolean, Boolean);
1045 GET_STATIC_TYPE_FIELD (gint8, byte, Byte);
1046 GET_STATIC_TYPE_FIELD (gshort, short, Short);
1047 GET_STATIC_TYPE_FIELD (gint, int, Int);
1048 GET_STATIC_TYPE_FIELD (gchar, char, Char);
1049 GET_STATIC_TYPE_FIELD (gint64, long, Long);
1050 GET_STATIC_TYPE_FIELD (gfloat, float, Float);
1051 GET_STATIC_TYPE_FIELD (gdouble, double, Double);
1052 GET_STATIC_TYPE_FIELD (jobject, object, Object);
1055 gst_amc_jni_get_buffer_array (JNIEnv * env, GError ** err, jobject array,
1056 GstAmcBuffer ** buffers, gsize * n_buffers)
1060 *n_buffers = (*env)->GetArrayLength (env, array);
1061 *buffers = g_new0 (GstAmcBuffer, *n_buffers);
1063 for (i = 0; i < *n_buffers; i++) {
1064 jobject buffer = NULL;
1066 buffer = (*env)->GetObjectArrayElement (env, array, i);
1067 if ((*env)->ExceptionCheck (env)) {
1068 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
1069 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer %d", i);
1073 /* NULL buffers are not a problem and are happening when we configured
1074 * a surface as input/output */
1078 (*buffers)[i].object = gst_amc_jni_object_make_global (env, buffer);
1079 if (!(*buffers)[i].object) {
1080 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
1081 GST_LIBRARY_ERROR_FAILED,
1082 "Failed to create global buffer reference %d", i);
1086 (*buffers)[i].data =
1087 (*env)->GetDirectBufferAddress (env, (*buffers)[i].object);
1088 if (!(*buffers)[i].data) {
1089 gst_amc_jni_set_error (env, err, GST_LIBRARY_ERROR,
1090 GST_LIBRARY_ERROR_FAILED, "Failed to get buffer address %d", i);
1093 (*buffers)[i].size =
1094 (*env)->GetDirectBufferCapacity (env, (*buffers)[i].object);
1101 gst_amc_jni_free_buffer_array (env, *buffers, *n_buffers);
1108 gst_amc_jni_free_buffer_array (JNIEnv * env, GstAmcBuffer * buffers,
1113 g_return_if_fail (buffers != NULL);
1115 for (i = 0; i < n_buffers; i++) {
1116 if (buffers[i].object)
1117 gst_amc_jni_object_unref (env, buffers[i].object);
1123 gst_amc_buffer_free (GstAmcBuffer * buffer)
1127 g_return_if_fail (buffer != NULL);
1129 env = gst_amc_jni_get_env ();
1132 gst_amc_jni_object_unref (env, buffer->object);
1137 gst_amc_buffer_copy (GstAmcBuffer * buffer)
1142 g_return_val_if_fail (buffer != NULL, NULL);
1144 env = gst_amc_jni_get_env ();
1146 ret = g_new0 (GstAmcBuffer, 1);
1148 ret->object = gst_amc_jni_object_ref (env, buffer->object);
1149 ret->data = buffer->data;
1150 ret->size = buffer->size;
1156 gst_amc_buffer_get_position_and_limit (GstAmcBuffer * buffer, GError ** err,
1157 gint * position, gint * limit)
1161 g_return_val_if_fail (buffer != NULL, FALSE);
1162 g_return_val_if_fail (buffer->object != NULL, FALSE);
1164 env = gst_amc_jni_get_env ();
1166 if (!gst_amc_jni_call_int_method (env, err, buffer->object,
1167 java_nio_buffer.get_position, position))
1170 if (!gst_amc_jni_call_int_method (env, err, buffer->object,
1171 java_nio_buffer.get_limit, limit))
1178 gst_amc_buffer_set_position_and_limit (GstAmcBuffer * buffer, GError ** err,
1179 gint position, gint limit)
1184 g_return_val_if_fail (buffer != NULL, FALSE);
1185 g_return_val_if_fail (buffer->object != NULL, FALSE);
1187 env = gst_amc_jni_get_env ();
1189 if (!gst_amc_jni_call_object_method (env, err, buffer->object,
1190 java_nio_buffer.set_limit, &tmp, limit))
1193 gst_amc_jni_object_local_unref (env, tmp);
1195 if (!gst_amc_jni_call_object_method (env, err, buffer->object,
1196 java_nio_buffer.set_position, &tmp, position))
1199 gst_amc_jni_object_local_unref (env, tmp);
1205 gst_amc_buffer_clear (GstAmcBuffer * buffer, GError ** err)
1210 g_return_val_if_fail (buffer != NULL, FALSE);
1211 g_return_val_if_fail (buffer->object != NULL, FALSE);
1213 env = gst_amc_jni_get_env ();
1215 if (!gst_amc_jni_call_object_method (env, err, buffer->object,
1216 java_nio_buffer.clear, &tmp))
1219 gst_amc_jni_object_local_unref (env, tmp);