gstreamer_android-1.0.c.in 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #include <jni.h>
  2. #include <gst/gst.h>
  3. #include <gio/gio.h>
  4. #include <android/log.h>
  5. #include <string.h>
  6. /* XXX: Workaround for Android <21 making signal() an inline function
  7. * around bsd_signal(), and Android >= 21 not having any bsd_signal()
  8. * symbol but only signal().
  9. * See https://bugzilla.gnome.org/show_bug.cgi?id=766235
  10. */
  11. static gpointer
  12. load_real_signal (gpointer data)
  13. {
  14. GModule *module;
  15. gpointer ret = NULL;
  16. module = g_module_open ("libc.so", G_MODULE_BIND_LOCAL);
  17. g_module_symbol (module, "signal", &ret);
  18. /* As fallback, let's try bsd_signal */
  19. if (ret == NULL) {
  20. g_warning ("Can't find signal(3) in libc.so!");
  21. g_module_symbol (module, "bsd_signal", &ret);
  22. }
  23. g_module_close (module);
  24. return ret;
  25. }
  26. __sighandler_t bsd_signal(int signum, __sighandler_t handler) __attribute__((weak));
  27. __sighandler_t bsd_signal(int signum, __sighandler_t handler)
  28. {
  29. static GOnce gonce = G_ONCE_INIT;
  30. __sighandler_t (*real_signal) (int signum, __sighandler_t handler);
  31. g_once (&gonce, load_real_signal, NULL);
  32. real_signal = gonce.retval;
  33. g_assert (real_signal != NULL);
  34. return real_signal(signum, handler);
  35. }
  36. static jobject _context = NULL;
  37. static jobject _class_loader = NULL;
  38. static JavaVM *_java_vm = NULL;
  39. static GstClockTime _priv_gst_info_start_time;
  40. #define GST_G_IO_MODULE_DECLARE(name) \
  41. extern void G_PASTE(g_io_, G_PASTE(name, _load)) (gpointer data)
  42. #define GST_G_IO_MODULE_LOAD(name) \
  43. G_PASTE(g_io_, G_PASTE(name, _load)) (NULL)
  44. /* Declaration of static plugins */
  45. @PLUGINS_DECLARATION@
  46. /* Declaration of static gio modules */
  47. @G_IO_MODULES_DECLARE@
  48. /* This is called by gst_init() to register static plugins */
  49. void
  50. gst_init_static_plugins (void)
  51. {
  52. @PLUGINS_REGISTRATION@
  53. }
  54. /* Call this function to load GIO modules */
  55. void
  56. gst_android_load_gio_modules (void)
  57. {
  58. GTlsBackend *backend;
  59. const gchar *ca_certs;
  60. @G_IO_MODULES_LOAD@
  61. ca_certs = g_getenv ("CA_CERTIFICATES");
  62. backend = g_tls_backend_get_default ();
  63. if (backend && ca_certs) {
  64. GTlsDatabase *db;
  65. GError *error = NULL;
  66. db = g_tls_file_database_new (ca_certs, &error);
  67. if (db) {
  68. g_tls_backend_set_default_database (backend, db);
  69. g_object_unref (db);
  70. } else {
  71. g_warning ("Failed to create a database from file: %s",
  72. error ? error->message : "Unknown");
  73. }
  74. }
  75. }
  76. static void
  77. glib_print_handler (const gchar * string)
  78. {
  79. __android_log_print (ANDROID_LOG_INFO, "GLib+stdout", "%s", string);
  80. }
  81. static void
  82. glib_printerr_handler (const gchar * string)
  83. {
  84. __android_log_print (ANDROID_LOG_ERROR, "GLib+stderr", "%s", string);
  85. }
  86. /* Based on GLib's default handler */
  87. #define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || \
  88. (wc == 0x7f) || \
  89. (wc >= 0x80 && wc < 0xa0)))
  90. #define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
  91. #define STRING_BUFFER_SIZE (FORMAT_UNSIGNED_BUFSIZE + 32)
  92. #define ALERT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
  93. #define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
  94. #define INFO_LEVELS (G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG)
  95. static void
  96. escape_string (GString * string)
  97. {
  98. const char *p = string->str;
  99. gunichar wc;
  100. while (p < string->str + string->len) {
  101. gboolean safe;
  102. wc = g_utf8_get_char_validated (p, -1);
  103. if (wc == (gunichar) - 1 || wc == (gunichar) - 2) {
  104. gchar *tmp;
  105. guint pos;
  106. pos = p - string->str;
  107. /* Emit invalid UTF-8 as hex escapes
  108. */
  109. tmp = g_strdup_printf ("\\x%02x", (guint) (guchar) * p);
  110. g_string_erase (string, pos, 1);
  111. g_string_insert (string, pos, tmp);
  112. p = string->str + (pos + 4); /* Skip over escape sequence */
  113. g_free (tmp);
  114. continue;
  115. }
  116. if (wc == '\r') {
  117. safe = *(p + 1) == '\n';
  118. } else {
  119. safe = CHAR_IS_SAFE (wc);
  120. }
  121. if (!safe) {
  122. gchar *tmp;
  123. guint pos;
  124. pos = p - string->str;
  125. /* Largest char we escape is 0x0a, so we don't have to worry
  126. * about 8-digit \Uxxxxyyyy
  127. */
  128. tmp = g_strdup_printf ("\\u%04x", wc);
  129. g_string_erase (string, pos, g_utf8_next_char (p) - p);
  130. g_string_insert (string, pos, tmp);
  131. g_free (tmp);
  132. p = string->str + (pos + 6); /* Skip over escape sequence */
  133. } else
  134. p = g_utf8_next_char (p);
  135. }
  136. }
  137. static void
  138. glib_log_handler (const gchar * log_domain, GLogLevelFlags log_level,
  139. const gchar * message, gpointer user_data)
  140. {
  141. gchar *string;
  142. GString *gstring;
  143. const gchar *domains;
  144. gint android_log_level;
  145. gchar *tag;
  146. if ((log_level & DEFAULT_LEVELS) || (log_level >> G_LOG_LEVEL_USER_SHIFT))
  147. goto emit;
  148. domains = g_getenv ("G_MESSAGES_DEBUG");
  149. if (((log_level & INFO_LEVELS) == 0) ||
  150. domains == NULL ||
  151. (strcmp (domains, "all") != 0 && (!log_domain
  152. || !strstr (domains, log_domain))))
  153. return;
  154. emit:
  155. if (log_domain)
  156. tag = g_strdup_printf ("GLib+%s", log_domain);
  157. else
  158. tag = g_strdup ("GLib");
  159. switch (log_level & G_LOG_LEVEL_MASK) {
  160. case G_LOG_LEVEL_ERROR:
  161. android_log_level = ANDROID_LOG_ERROR;
  162. break;
  163. case G_LOG_LEVEL_CRITICAL:
  164. android_log_level = ANDROID_LOG_ERROR;
  165. break;
  166. case G_LOG_LEVEL_WARNING:
  167. android_log_level = ANDROID_LOG_WARN;
  168. break;
  169. case G_LOG_LEVEL_MESSAGE:
  170. android_log_level = ANDROID_LOG_INFO;
  171. break;
  172. case G_LOG_LEVEL_INFO:
  173. android_log_level = ANDROID_LOG_INFO;
  174. break;
  175. case G_LOG_LEVEL_DEBUG:
  176. android_log_level = ANDROID_LOG_DEBUG;
  177. break;
  178. default:
  179. android_log_level = ANDROID_LOG_INFO;
  180. break;
  181. }
  182. gstring = g_string_new (NULL);
  183. if (!message) {
  184. g_string_append (gstring, "(NULL) message");
  185. } else {
  186. GString * msg = g_string_new (message);
  187. escape_string (msg);
  188. g_string_append (gstring, msg->str);
  189. g_string_free (msg, TRUE);
  190. }
  191. string = g_string_free (gstring, FALSE);
  192. __android_log_print (android_log_level, tag, "%s", string);
  193. g_free (string);
  194. g_free (tag);
  195. }
  196. static void
  197. gst_debug_logcat (GstDebugCategory * category, GstDebugLevel level,
  198. const gchar * file, const gchar * function, gint line,
  199. GObject * object, GstDebugMessage * message, gpointer unused)
  200. {
  201. GstClockTime elapsed;
  202. gint android_log_level;
  203. gchar *tag;
  204. if (level > gst_debug_category_get_threshold (category))
  205. return;
  206. elapsed = GST_CLOCK_DIFF (_priv_gst_info_start_time,
  207. gst_util_get_timestamp ());
  208. switch (level) {
  209. case GST_LEVEL_ERROR:
  210. android_log_level = ANDROID_LOG_ERROR;
  211. break;
  212. case GST_LEVEL_WARNING:
  213. android_log_level = ANDROID_LOG_WARN;
  214. break;
  215. case GST_LEVEL_INFO:
  216. android_log_level = ANDROID_LOG_INFO;
  217. break;
  218. case GST_LEVEL_DEBUG:
  219. android_log_level = ANDROID_LOG_DEBUG;
  220. break;
  221. default:
  222. android_log_level = ANDROID_LOG_VERBOSE;
  223. break;
  224. }
  225. tag = g_strdup_printf ("GStreamer+%s",
  226. gst_debug_category_get_name (category));
  227. if (object) {
  228. gchar *obj;
  229. if (GST_IS_PAD (object) && GST_OBJECT_NAME (object)) {
  230. obj = g_strdup_printf ("<%s:%s>", GST_DEBUG_PAD_NAME (object));
  231. } else if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object)) {
  232. obj = g_strdup_printf ("<%s>", GST_OBJECT_NAME (object));
  233. } else if (G_IS_OBJECT (object)) {
  234. obj = g_strdup_printf ("<%s@%p>", G_OBJECT_TYPE_NAME (object), object);
  235. } else {
  236. obj = g_strdup_printf ("<%p>", object);
  237. }
  238. __android_log_print (android_log_level, tag,
  239. "%" GST_TIME_FORMAT " %p %s:%d:%s:%s %s\n",
  240. GST_TIME_ARGS (elapsed), g_thread_self (),
  241. file, line, function, obj, gst_debug_message_get (message));
  242. g_free (obj);
  243. } else {
  244. __android_log_print (android_log_level, tag,
  245. "%" GST_TIME_FORMAT " %p %s:%d:%s %s\n",
  246. GST_TIME_ARGS (elapsed), g_thread_self (),
  247. file, line, function, gst_debug_message_get (message));
  248. }
  249. g_free (tag);
  250. }
  251. static gboolean
  252. get_application_dirs (JNIEnv * env, jobject context, gchar ** cache_dir,
  253. gchar ** files_dir)
  254. {
  255. jclass context_class;
  256. jmethodID get_cache_dir_id, get_files_dir_id;
  257. jclass file_class;
  258. jmethodID get_absolute_path_id;
  259. jobject dir;
  260. jstring abs_path;
  261. const gchar *abs_path_str;
  262. *cache_dir = *files_dir = NULL;
  263. context_class = (*env)->GetObjectClass (env, context);
  264. if (!context_class) {
  265. return FALSE;
  266. }
  267. get_cache_dir_id =
  268. (*env)->GetMethodID (env, context_class, "getCacheDir",
  269. "()Ljava/io/File;");
  270. get_files_dir_id =
  271. (*env)->GetMethodID (env, context_class, "getFilesDir",
  272. "()Ljava/io/File;");
  273. if (!get_cache_dir_id || !get_files_dir_id) {
  274. (*env)->DeleteLocalRef (env, context_class);
  275. return FALSE;
  276. }
  277. file_class = (*env)->FindClass (env, "java/io/File");
  278. if (!file_class) {
  279. (*env)->DeleteLocalRef (env, context_class);
  280. return FALSE;
  281. }
  282. get_absolute_path_id =
  283. (*env)->GetMethodID (env, file_class, "getAbsolutePath",
  284. "()Ljava/lang/String;");
  285. if (!get_absolute_path_id) {
  286. (*env)->DeleteLocalRef (env, context_class);
  287. (*env)->DeleteLocalRef (env, file_class);
  288. return FALSE;
  289. }
  290. dir = (*env)->CallObjectMethod (env, context, get_cache_dir_id);
  291. if ((*env)->ExceptionCheck (env)) {
  292. (*env)->ExceptionDescribe (env);
  293. (*env)->ExceptionClear (env);
  294. (*env)->DeleteLocalRef (env, context_class);
  295. (*env)->DeleteLocalRef (env, file_class);
  296. return FALSE;
  297. }
  298. if (dir) {
  299. abs_path = (*env)->CallObjectMethod (env, dir, get_absolute_path_id);
  300. if ((*env)->ExceptionCheck (env)) {
  301. (*env)->ExceptionDescribe (env);
  302. (*env)->ExceptionClear (env);
  303. (*env)->DeleteLocalRef (env, dir);
  304. (*env)->DeleteLocalRef (env, context_class);
  305. (*env)->DeleteLocalRef (env, file_class);
  306. return FALSE;
  307. }
  308. abs_path_str = (*env)->GetStringUTFChars (env, abs_path, NULL);
  309. if ((*env)->ExceptionCheck (env)) {
  310. (*env)->ExceptionDescribe (env);
  311. (*env)->ExceptionClear (env);
  312. (*env)->DeleteLocalRef (env, abs_path);
  313. (*env)->DeleteLocalRef (env, dir);
  314. (*env)->DeleteLocalRef (env, context_class);
  315. (*env)->DeleteLocalRef (env, file_class);
  316. return FALSE;
  317. }
  318. *cache_dir = abs_path ? g_strdup (abs_path_str) : NULL;
  319. (*env)->ReleaseStringUTFChars (env, abs_path, abs_path_str);
  320. (*env)->DeleteLocalRef (env, abs_path);
  321. (*env)->DeleteLocalRef (env, dir);
  322. }
  323. dir = (*env)->CallObjectMethod (env, context, get_files_dir_id);
  324. if ((*env)->ExceptionCheck (env)) {
  325. (*env)->ExceptionDescribe (env);
  326. (*env)->ExceptionClear (env);
  327. (*env)->DeleteLocalRef (env, context_class);
  328. (*env)->DeleteLocalRef (env, file_class);
  329. return FALSE;
  330. }
  331. if (dir) {
  332. abs_path = (*env)->CallObjectMethod (env, dir, get_absolute_path_id);
  333. if ((*env)->ExceptionCheck (env)) {
  334. (*env)->ExceptionDescribe (env);
  335. (*env)->ExceptionClear (env);
  336. (*env)->DeleteLocalRef (env, dir);
  337. (*env)->DeleteLocalRef (env, context_class);
  338. (*env)->DeleteLocalRef (env, file_class);
  339. return FALSE;
  340. }
  341. abs_path_str = (*env)->GetStringUTFChars (env, abs_path, NULL);
  342. if ((*env)->ExceptionCheck (env)) {
  343. (*env)->ExceptionDescribe (env);
  344. (*env)->ExceptionClear (env);
  345. (*env)->DeleteLocalRef (env, abs_path);
  346. (*env)->DeleteLocalRef (env, dir);
  347. (*env)->DeleteLocalRef (env, context_class);
  348. (*env)->DeleteLocalRef (env, file_class);
  349. return FALSE;
  350. }
  351. *files_dir = files_dir ? g_strdup (abs_path_str) : NULL;
  352. (*env)->ReleaseStringUTFChars (env, abs_path, abs_path_str);
  353. (*env)->DeleteLocalRef (env, abs_path);
  354. (*env)->DeleteLocalRef (env, dir);
  355. }
  356. (*env)->DeleteLocalRef (env, file_class);
  357. (*env)->DeleteLocalRef (env, context_class);
  358. return TRUE;
  359. }
  360. jobject
  361. gst_android_get_application_context (void)
  362. {
  363. return _context;
  364. }
  365. jobject
  366. gst_android_get_application_class_loader (void)
  367. {
  368. return _class_loader;
  369. }
  370. JavaVM *
  371. gst_android_get_java_vm (void)
  372. {
  373. return _java_vm;
  374. }
  375. static gboolean
  376. init (JNIEnv *env, jobject context)
  377. {
  378. jclass context_cls = NULL;
  379. jmethodID get_class_loader_id = 0;
  380. jobject class_loader = NULL;
  381. context_cls = (*env)->GetObjectClass (env, context);
  382. if (!context_cls) {
  383. return FALSE;
  384. }
  385. get_class_loader_id = (*env)->GetMethodID (env, context_cls,
  386. "getClassLoader", "()Ljava/lang/ClassLoader;");
  387. if ((*env)->ExceptionCheck (env)) {
  388. (*env)->ExceptionDescribe (env);
  389. (*env)->ExceptionClear (env);
  390. return FALSE;
  391. }
  392. class_loader = (*env)->CallObjectMethod (env, context, get_class_loader_id);
  393. if ((*env)->ExceptionCheck (env)) {
  394. (*env)->ExceptionDescribe (env);
  395. (*env)->ExceptionClear (env);
  396. return FALSE;
  397. }
  398. if (_context) {
  399. (*env)->DeleteGlobalRef (env, _context);
  400. }
  401. _context = (*env)->NewGlobalRef (env, context);
  402. if (_class_loader) {
  403. (*env)->DeleteGlobalRef (env, _class_loader);
  404. }
  405. _class_loader = (*env)->NewGlobalRef (env, class_loader);
  406. return TRUE;
  407. }
  408. void
  409. gst_android_init (JNIEnv * env, jobject context)
  410. {
  411. gchar *cache_dir;
  412. gchar *files_dir;
  413. gchar *registry;
  414. GError *error = NULL;
  415. if (!init (env, context)) {
  416. __android_log_print (ANDROID_LOG_INFO, "GStreamer",
  417. "GStreamer failed to initialize");
  418. }
  419. if (gst_is_initialized ()) {
  420. __android_log_print (ANDROID_LOG_INFO, "GStreamer",
  421. "GStreamer already initialized");
  422. return;
  423. }
  424. if (!get_application_dirs (env, context, &cache_dir, &files_dir)) {
  425. __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
  426. "Failed to get application dirs");
  427. }
  428. if (cache_dir) {
  429. g_setenv ("TMP", cache_dir, TRUE);
  430. g_setenv ("TEMP", cache_dir, TRUE);
  431. g_setenv ("TMPDIR", cache_dir, TRUE);
  432. g_setenv ("XDG_RUNTIME_DIR", cache_dir, TRUE);
  433. g_setenv ("XDG_CACHE_HOME", cache_dir, TRUE);
  434. registry = g_build_filename (cache_dir, "registry.bin", NULL);
  435. g_setenv ("GST_REGISTRY", registry, TRUE);
  436. g_free (registry);
  437. g_setenv ("GST_REGISTRY_REUSE_PLUGIN_SCANNER", "no", TRUE);
  438. /* TODO: Should probably also set GST_PLUGIN_SCANNER and GST_PLUGIN_SYSTEM_PATH */
  439. }
  440. if (files_dir) {
  441. gchar *fontconfig, *certs;
  442. g_setenv ("HOME", files_dir, TRUE);
  443. g_setenv ("XDG_DATA_DIRS", files_dir, TRUE);
  444. g_setenv ("XDG_CONFIG_DIRS", files_dir, TRUE);
  445. g_setenv ("XDG_CONFIG_HOME", files_dir, TRUE);
  446. g_setenv ("XDG_DATA_HOME", files_dir, TRUE);
  447. fontconfig = g_build_filename (files_dir, "fontconfig", NULL);
  448. g_setenv ("FONTCONFIG_PATH", fontconfig, TRUE);
  449. g_free (fontconfig);
  450. certs = g_build_filename (files_dir, "ssl", "certs", "ca-certificates.crt", NULL);
  451. g_setenv ("CA_CERTIFICATES", certs, TRUE);
  452. g_free (certs);
  453. }
  454. g_free (cache_dir);
  455. g_free (files_dir);
  456. /* Set GLib print handlers */
  457. g_set_print_handler (glib_print_handler);
  458. g_set_printerr_handler (glib_printerr_handler);
  459. g_log_set_default_handler (glib_log_handler, NULL);
  460. /* Disable this for releases if performance is important
  461. * or increase the threshold to get more information */
  462. gst_debug_set_active (TRUE);
  463. gst_debug_set_default_threshold (GST_LEVEL_WARNING);
  464. gst_debug_remove_log_function (gst_debug_log_default);
  465. gst_debug_add_log_function ((GstLogFunction) gst_debug_logcat, NULL, NULL);
  466. /* get time we started for debugging messages */
  467. _priv_gst_info_start_time = gst_util_get_timestamp ();
  468. if (!gst_init_check (NULL, NULL, &error)) {
  469. gchar *message = g_strdup_printf ("GStreamer initialization failed: %s",
  470. error && error->message ? error->message : "(no message)");
  471. jclass exception_class = (*env)->FindClass (env, "java/lang/Exception");
  472. __android_log_print (ANDROID_LOG_ERROR, "GStreamer", "%s", message);
  473. (*env)->ThrowNew (env, exception_class, message);
  474. g_free (message);
  475. return;
  476. }
  477. gst_android_load_gio_modules ();
  478. __android_log_print (ANDROID_LOG_INFO, "GStreamer",
  479. "GStreamer initialization complete");
  480. }
  481. static void
  482. gst_android_init_jni (JNIEnv * env, jobject gstreamer, jobject context)
  483. {
  484. gst_android_init (env, context);
  485. }
  486. static JNINativeMethod native_methods[] = {
  487. {"nativeInit", "(Landroid/content/Context;)V", (void *) gst_android_init_jni}
  488. };
  489. jint
  490. JNI_OnLoad (JavaVM * vm, void * reserved)
  491. {
  492. JNIEnv *env = NULL;
  493. GModule *module;
  494. if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
  495. __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
  496. "Could not retrieve JNIEnv");
  497. return 0;
  498. }
  499. jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/GStreamer");
  500. if (!klass) {
  501. __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
  502. "Could not retrieve class org.freedesktop.gstreamer.GStreamer");
  503. return 0;
  504. }
  505. if ((*env)->RegisterNatives (env, klass, native_methods,
  506. G_N_ELEMENTS (native_methods))) {
  507. __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
  508. "Could not register native methods for org.freedesktop.gstreamer.GStreamer");
  509. return 0;
  510. }
  511. /* Remember Java VM */
  512. _java_vm = vm;
  513. /* Tell the androidmedia plugin about the Java VM if we can */
  514. module = g_module_open (NULL, G_MODULE_BIND_LOCAL);
  515. if (module) {
  516. void (*set_java_vm) (JavaVM *) = NULL;
  517. if (g_module_symbol (module, "gst_amc_jni_set_java_vm",
  518. (gpointer *) & set_java_vm) && set_java_vm) {
  519. set_java_vm (vm);
  520. }
  521. g_module_close (module);
  522. }
  523. return JNI_VERSION_1_4;
  524. }
  525. void
  526. JNI_OnUnload (JavaVM * vm, void * reversed)
  527. {
  528. JNIEnv *env = NULL;
  529. if ((*vm)->GetEnv (vm, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
  530. __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
  531. "Could not retrieve JNIEnv");
  532. return;
  533. }
  534. if (_context) {
  535. (*env)->DeleteGlobalRef (env, _context);
  536. _context = NULL;
  537. }
  538. if (_class_loader) {
  539. (*env)->DeleteGlobalRef (env, _class_loader);
  540. _class_loader = NULL;
  541. }
  542. _java_vm = NULL;
  543. }