File indexing completed on 2024-05-12 05:53:13

0001 #include <android/log.h>
0002 #include <gio/gio.h>
0003 #include <gst/gst.h>
0004 #include <jni.h>
0005 
0006 static jobject _context;
0007 static jobject _class_loader;
0008 static JavaVM *_java_vm;
0009 static GstClockTime _priv_gst_info_start_time;
0010 
0011 #define GST_G_IO_MODULE_DECLARE(name) extern void G_PASTE(g_io_module_, G_PASTE(name, _load_static))(void)
0012 
0013 #define GST_G_IO_MODULE_LOAD(name) G_PASTE(g_io_module_, G_PASTE(name, _load_static))()
0014 
0015 /* Declaration of static plugins */
0016 GST_PLUGIN_STATIC_DECLARE(coreelements);
0017 GST_PLUGIN_STATIC_DECLARE(typefindfunctions);
0018 GST_PLUGIN_STATIC_DECLARE(videotestsrc);
0019 GST_PLUGIN_STATIC_DECLARE(videoparsersbad);
0020 GST_PLUGIN_STATIC_DECLARE(androidmedia);
0021 GST_PLUGIN_STATIC_DECLARE(libav);
0022 GST_PLUGIN_STATIC_DECLARE(x264);
0023 GST_PLUGIN_STATIC_DECLARE(udp);
0024 GST_PLUGIN_STATIC_DECLARE(rtp);
0025 GST_PLUGIN_STATIC_DECLARE(rtpmanager);
0026 GST_PLUGIN_STATIC_DECLARE(playback);
0027 GST_PLUGIN_STATIC_DECLARE(opengl);
0028 GST_PLUGIN_STATIC_DECLARE(qmlgl);
0029 
0030 /* Declaration of static gio modules */
0031 /* GST_G_IO_MODULE_DECLARE(name) */
0032 
0033 /* Call this function to register static plugins */
0034 void gst_android_register_static_plugins(void)
0035 {
0036     GST_PLUGIN_STATIC_REGISTER(coreelements);
0037     GST_PLUGIN_STATIC_REGISTER(typefindfunctions);
0038     GST_PLUGIN_STATIC_REGISTER(videotestsrc);
0039     GST_PLUGIN_STATIC_REGISTER(videoparsersbad);
0040     GST_PLUGIN_STATIC_REGISTER(androidmedia);
0041     GST_PLUGIN_STATIC_REGISTER(libav);
0042     GST_PLUGIN_STATIC_REGISTER(x264);
0043     GST_PLUGIN_STATIC_REGISTER(udp);
0044     GST_PLUGIN_STATIC_REGISTER(rtp);
0045     GST_PLUGIN_STATIC_REGISTER(rtpmanager);
0046     GST_PLUGIN_STATIC_REGISTER(playback);
0047     GST_PLUGIN_STATIC_REGISTER(opengl);
0048     GST_PLUGIN_STATIC_REGISTER(qmlgl);
0049 }
0050 
0051 /* Call this function to load GIO modules */
0052 void gst_android_load_gio_modules(void)
0053 {
0054 }
0055 
0056 void glib_print_handler(const gchar *string)
0057 {
0058     __android_log_print(ANDROID_LOG_INFO, "GLib+stdout", "%s", string);
0059 }
0060 
0061 void glib_printerr_handler(const gchar *string)
0062 {
0063     __android_log_print(ANDROID_LOG_ERROR, "GLib+stderr", "%s", string);
0064 }
0065 
0066 /* Based on GLib's default handler */
0067 #define CHAR_IS_SAFE(wc) (!((wc < 0x20 && wc != '\t' && wc != '\n' && wc != '\r') || (wc == 0x7f) || (wc >= 0x80 && wc < 0xa0)))
0068 #define FORMAT_UNSIGNED_BUFSIZE ((GLIB_SIZEOF_LONG * 3) + 3)
0069 #define STRING_BUFFER_SIZE (FORMAT_UNSIGNED_BUFSIZE + 32)
0070 #define ALERT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)
0071 #define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
0072 #define INFO_LEVELS (G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG)
0073 
0074 static void escape_string(GString *string)
0075 {
0076     const char *p = string->str;
0077     gunichar wc;
0078 
0079     while (p < string->str + string->len) {
0080         gboolean safe;
0081 
0082         wc = g_utf8_get_char_validated(p, -1);
0083         if (wc == (gunichar)-1 || wc == (gunichar)-2) {
0084             gchar *tmp;
0085             guint pos;
0086 
0087             pos = p - string->str;
0088 
0089             /* Emit invalid UTF-8 as hex escapes
0090              */
0091             tmp = g_strdup_printf("\\x%02x", (guint)(guchar)*p);
0092             g_string_erase(string, pos, 1);
0093             g_string_insert(string, pos, tmp);
0094 
0095             p = string->str + (pos + 4); /* Skip over escape sequence */
0096 
0097             g_free(tmp);
0098             continue;
0099         }
0100         if (wc == '\r') {
0101             safe = *(p + 1) == '\n';
0102         } else {
0103             safe = CHAR_IS_SAFE(wc);
0104         }
0105 
0106         if (!safe) {
0107             gchar *tmp;
0108             guint pos;
0109 
0110             pos = p - string->str;
0111 
0112             /* Largest char we escape is 0x0a, so we don't have to worry
0113              * about 8-digit \Uxxxxyyyy
0114              */
0115             tmp = g_strdup_printf("\\u%04x", wc);
0116             g_string_erase(string, pos, g_utf8_next_char(p) - p);
0117             g_string_insert(string, pos, tmp);
0118             g_free(tmp);
0119 
0120             p = string->str + (pos + 6); /* Skip over escape sequence */
0121         } else
0122             p = g_utf8_next_char(p);
0123     }
0124 }
0125 
0126 void glib_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
0127 {
0128     gchar *string;
0129     GString *gstring;
0130     const gchar *domains;
0131     gint android_log_level;
0132     gchar *tag;
0133 
0134     if ((log_level & DEFAULT_LEVELS) || (log_level >> G_LOG_LEVEL_USER_SHIFT))
0135         goto emit;
0136 
0137     domains = g_getenv("G_MESSAGES_DEBUG");
0138     if (((log_level & INFO_LEVELS) == 0) || domains == NULL || (strcmp(domains, "all") != 0 && (!log_domain || !strstr(domains, log_domain))))
0139         return;
0140 
0141 emit:
0142 
0143     if (log_domain)
0144         tag = g_strdup_printf("GLib+%s", log_domain);
0145     else
0146         tag = g_strdup("GLib");
0147 
0148     switch (log_level & G_LOG_LEVEL_MASK) {
0149     case G_LOG_LEVEL_ERROR:
0150         android_log_level = ANDROID_LOG_ERROR;
0151         break;
0152     case G_LOG_LEVEL_CRITICAL:
0153         android_log_level = ANDROID_LOG_ERROR;
0154         break;
0155     case G_LOG_LEVEL_WARNING:
0156         android_log_level = ANDROID_LOG_WARN;
0157         break;
0158     case G_LOG_LEVEL_MESSAGE:
0159         android_log_level = ANDROID_LOG_INFO;
0160         break;
0161     case G_LOG_LEVEL_INFO:
0162         android_log_level = ANDROID_LOG_INFO;
0163         break;
0164     case G_LOG_LEVEL_DEBUG:
0165         android_log_level = ANDROID_LOG_DEBUG;
0166         break;
0167     default:
0168         android_log_level = ANDROID_LOG_INFO;
0169         break;
0170     }
0171 
0172     gstring = g_string_new(NULL);
0173     if (!message) {
0174         g_string_append(gstring, "(NULL) message");
0175     } else {
0176         GString *msg = g_string_new(message);
0177         escape_string(msg);
0178         g_string_append(gstring, msg->str);
0179         g_string_free(msg, TRUE);
0180     }
0181     string = g_string_free(gstring, FALSE);
0182 
0183     __android_log_print(android_log_level, tag, "%s", string);
0184 
0185     g_free(string);
0186     g_free(tag);
0187 }
0188 
0189 void gst_debug_logcat(GstDebugCategory *category, GstDebugLevel level, const gchar *file, const gchar *function, gint line, GObject *object, GstDebugMessage *message, gpointer unused)
0190 {
0191     GstClockTime elapsed;
0192     gint android_log_level;
0193     gchar *tag;
0194 
0195     if (level > gst_debug_category_get_threshold(category))
0196         return;
0197 
0198     elapsed = GST_CLOCK_DIFF(_priv_gst_info_start_time, gst_util_get_timestamp());
0199 
0200     switch (level) {
0201     case GST_LEVEL_ERROR:
0202         android_log_level = ANDROID_LOG_ERROR;
0203         break;
0204     case GST_LEVEL_WARNING:
0205         android_log_level = ANDROID_LOG_WARN;
0206         break;
0207     case GST_LEVEL_INFO:
0208         android_log_level = ANDROID_LOG_INFO;
0209         break;
0210     case GST_LEVEL_DEBUG:
0211         android_log_level = ANDROID_LOG_DEBUG;
0212         break;
0213     default:
0214         android_log_level = ANDROID_LOG_VERBOSE;
0215         break;
0216     }
0217 
0218     tag = g_strdup_printf("GStreamer+%s", gst_debug_category_get_name(category));
0219 
0220     if (object) {
0221         gchar *obj;
0222 
0223         if (GST_IS_PAD(object) && GST_OBJECT_NAME(object)) {
0224             obj = g_strdup_printf("<%s:%s>", GST_DEBUG_PAD_NAME(object));
0225         } else if (GST_IS_OBJECT(object) && GST_OBJECT_NAME(object)) {
0226             obj = g_strdup_printf("<%s>", GST_OBJECT_NAME(object));
0227         } else if (G_IS_OBJECT(object)) {
0228             obj = g_strdup_printf("<%s@%p>", G_OBJECT_TYPE_NAME(object), object);
0229         } else {
0230             obj = g_strdup_printf("<%p>", object);
0231         }
0232 
0233         __android_log_print(android_log_level, tag, "%" GST_TIME_FORMAT " %p %s:%d:%s:%s %s\n", GST_TIME_ARGS(elapsed), g_thread_self(), file, line, function, obj, gst_debug_message_get(message));
0234 
0235         g_free(obj);
0236     } else {
0237         __android_log_print(android_log_level, tag, "%" GST_TIME_FORMAT " %p %s:%d:%s %s\n", GST_TIME_ARGS(elapsed), g_thread_self(), file, line, function, gst_debug_message_get(message));
0238     }
0239     g_free(tag);
0240 }
0241 
0242 static gboolean get_application_dirs(JNIEnv *env, jobject context, gchar **cache_dir, gchar **files_dir)
0243 {
0244     jclass context_class;
0245     jmethodID get_cache_dir_id, get_files_dir_id;
0246     jclass file_class;
0247     jmethodID get_absolute_path_id;
0248     jobject dir;
0249     jstring abs_path;
0250     const gchar *abs_path_str;
0251 
0252     *cache_dir = *files_dir = NULL;
0253 
0254     context_class = (*env)->GetObjectClass(env, context);
0255     if (!context_class) {
0256         return FALSE;
0257     }
0258     get_cache_dir_id = (*env)->GetMethodID(env, context_class, "getCacheDir", "()Ljava/io/File;");
0259     get_files_dir_id = (*env)->GetMethodID(env, context_class, "getFilesDir", "()Ljava/io/File;");
0260     if (!get_cache_dir_id || !get_files_dir_id) {
0261         (*env)->DeleteLocalRef(env, context_class);
0262         return FALSE;
0263     }
0264 
0265     file_class = (*env)->FindClass(env, "java/io/File");
0266     if (!file_class) {
0267         (*env)->DeleteLocalRef(env, context_class);
0268         return FALSE;
0269     }
0270     get_absolute_path_id = (*env)->GetMethodID(env, file_class, "getAbsolutePath", "()Ljava/lang/String;");
0271     if (!get_absolute_path_id) {
0272         (*env)->DeleteLocalRef(env, context_class);
0273         (*env)->DeleteLocalRef(env, file_class);
0274         return FALSE;
0275     }
0276 
0277     dir = (*env)->CallObjectMethod(env, context, get_cache_dir_id);
0278     if ((*env)->ExceptionCheck(env)) {
0279         (*env)->ExceptionDescribe(env);
0280         (*env)->ExceptionClear(env);
0281         (*env)->DeleteLocalRef(env, context_class);
0282         (*env)->DeleteLocalRef(env, file_class);
0283         return FALSE;
0284     }
0285 
0286     if (dir) {
0287         abs_path = (*env)->CallObjectMethod(env, dir, get_absolute_path_id);
0288         if ((*env)->ExceptionCheck(env)) {
0289             (*env)->ExceptionDescribe(env);
0290             (*env)->ExceptionClear(env);
0291             (*env)->DeleteLocalRef(env, dir);
0292             (*env)->DeleteLocalRef(env, context_class);
0293             (*env)->DeleteLocalRef(env, file_class);
0294             return FALSE;
0295         }
0296         abs_path_str = (*env)->GetStringUTFChars(env, abs_path, NULL);
0297         if ((*env)->ExceptionCheck(env)) {
0298             (*env)->ExceptionDescribe(env);
0299             (*env)->ExceptionClear(env);
0300             (*env)->DeleteLocalRef(env, abs_path);
0301             (*env)->DeleteLocalRef(env, dir);
0302             (*env)->DeleteLocalRef(env, context_class);
0303             (*env)->DeleteLocalRef(env, file_class);
0304             return FALSE;
0305         }
0306         *cache_dir = abs_path ? g_strdup(abs_path_str) : NULL;
0307 
0308         (*env)->ReleaseStringUTFChars(env, abs_path, abs_path_str);
0309         (*env)->DeleteLocalRef(env, abs_path);
0310         (*env)->DeleteLocalRef(env, dir);
0311     }
0312 
0313     dir = (*env)->CallObjectMethod(env, context, get_files_dir_id);
0314     if ((*env)->ExceptionCheck(env)) {
0315         (*env)->ExceptionDescribe(env);
0316         (*env)->ExceptionClear(env);
0317         (*env)->DeleteLocalRef(env, context_class);
0318         (*env)->DeleteLocalRef(env, file_class);
0319         return FALSE;
0320     }
0321     if (dir) {
0322         abs_path = (*env)->CallObjectMethod(env, dir, get_absolute_path_id);
0323         if ((*env)->ExceptionCheck(env)) {
0324             (*env)->ExceptionDescribe(env);
0325             (*env)->ExceptionClear(env);
0326             (*env)->DeleteLocalRef(env, dir);
0327             (*env)->DeleteLocalRef(env, context_class);
0328             (*env)->DeleteLocalRef(env, file_class);
0329             return FALSE;
0330         }
0331         abs_path_str = (*env)->GetStringUTFChars(env, abs_path, NULL);
0332         if ((*env)->ExceptionCheck(env)) {
0333             (*env)->ExceptionDescribe(env);
0334             (*env)->ExceptionClear(env);
0335             (*env)->DeleteLocalRef(env, abs_path);
0336             (*env)->DeleteLocalRef(env, dir);
0337             (*env)->DeleteLocalRef(env, context_class);
0338             (*env)->DeleteLocalRef(env, file_class);
0339             return FALSE;
0340         }
0341         *files_dir = files_dir ? g_strdup(abs_path_str) : NULL;
0342 
0343         (*env)->ReleaseStringUTFChars(env, abs_path, abs_path_str);
0344         (*env)->DeleteLocalRef(env, abs_path);
0345         (*env)->DeleteLocalRef(env, dir);
0346     }
0347 
0348     (*env)->DeleteLocalRef(env, file_class);
0349     (*env)->DeleteLocalRef(env, context_class);
0350 
0351     return TRUE;
0352 }
0353 
0354 jobject gst_android_get_application_context(void)
0355 {
0356     __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "get_application_context %p", _context);
0357     return _context;
0358 }
0359 
0360 jobject gst_android_get_application_class_loader(void)
0361 {
0362     __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "get_application_class_loader %p", _class_loader);
0363     return _class_loader;
0364 }
0365 
0366 JavaVM *gst_android_get_java_vm(void)
0367 {
0368     __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "get_java_vm %p", _java_vm);
0369     return _java_vm;
0370 }
0371 
0372 static gboolean init(JNIEnv *env, jobject context)
0373 {
0374     jclass context_cls = NULL;
0375     jmethodID get_class_loader_id = 0;
0376 
0377     jobject class_loader = NULL;
0378 
0379     context_cls = (*env)->GetObjectClass(env, context);
0380     if (!context_cls) {
0381         return FALSE;
0382     }
0383 
0384     get_class_loader_id = (*env)->GetMethodID(env, context_cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
0385     if ((*env)->ExceptionCheck(env)) {
0386         (*env)->ExceptionDescribe(env);
0387         (*env)->ExceptionClear(env);
0388         return FALSE;
0389     }
0390 
0391     class_loader = (*env)->CallObjectMethod(env, context, get_class_loader_id);
0392     if ((*env)->ExceptionCheck(env)) {
0393         (*env)->ExceptionDescribe(env);
0394         (*env)->ExceptionClear(env);
0395         return FALSE;
0396     }
0397 
0398     if (_context) {
0399         (*env)->DeleteGlobalRef(env, _context);
0400     }
0401     _context = (*env)->NewGlobalRef(env, context);
0402 
0403     if (_class_loader) {
0404         (*env)->DeleteGlobalRef(env, _class_loader);
0405     }
0406     _class_loader = (*env)->NewGlobalRef(env, class_loader);
0407 
0408     return TRUE;
0409 }
0410 
0411 void gst_android_init(JNIEnv *env, jclass klass, jobject context)
0412 {
0413     gchar *cache_dir;
0414     gchar *files_dir;
0415     gchar *registry;
0416     GError *error = NULL;
0417 
0418     if (!init(env, context)) {
0419         __android_log_print(ANDROID_LOG_INFO, "GStreamer", "GStreamer failed to initialize");
0420     }
0421 
0422     if (gst_is_initialized()) {
0423         __android_log_print(ANDROID_LOG_INFO, "GStreamer", "GStreamer already initialized");
0424         return;
0425     }
0426 
0427     if (!get_application_dirs(env, context, &cache_dir, &files_dir)) {
0428         __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "Failed to get application dirs");
0429     }
0430 
0431     if (cache_dir) {
0432         g_setenv("TMP", cache_dir, TRUE);
0433         g_setenv("TEMP", cache_dir, TRUE);
0434         g_setenv("TMPDIR", cache_dir, TRUE);
0435         g_setenv("XDG_RUNTIME_DIR", cache_dir, TRUE);
0436         g_setenv("XDG_CACHE_HOME", cache_dir, TRUE);
0437         registry = g_build_filename(cache_dir, "registry.bin", NULL);
0438         g_setenv("GST_REGISTRY", registry, TRUE);
0439         g_free(registry);
0440         g_setenv("GST_REUSE_PLUGIN_SCANNER", "no", TRUE);
0441         /* TODO: Should probably also set GST_PLUGIN_SCANNER and GST_PLUGIN_SYSTEM_PATH */
0442     }
0443     if (files_dir) {
0444         gchar *fontconfig, *certs;
0445 
0446         g_setenv("HOME", files_dir, TRUE);
0447         g_setenv("XDG_DATA_DIRS", files_dir, TRUE);
0448         g_setenv("XDG_CONFIG_DIRS", files_dir, TRUE);
0449         g_setenv("XDG_CONFIG_HOME", files_dir, TRUE);
0450         g_setenv("XDG_DATA_HOME", files_dir, TRUE);
0451 
0452         fontconfig = g_build_filename(files_dir, "fontconfig", NULL);
0453         g_setenv("FONTCONFIG_PATH", fontconfig, TRUE);
0454         g_free(fontconfig);
0455 
0456         certs = g_build_filename(files_dir, "ssl", "certs", "ca-certificates.crt", NULL);
0457         g_setenv("CA_CERTIFICATES", certs, TRUE);
0458         g_free(certs);
0459     }
0460     g_free(cache_dir);
0461     g_free(files_dir);
0462 
0463     /* Set GLib print handlers */
0464     g_set_print_handler(glib_print_handler);
0465     g_set_printerr_handler(glib_printerr_handler);
0466     g_log_set_default_handler(glib_log_handler, NULL);
0467 
0468     /* Disable this for releases if performance is important
0469      * or increase the threshold to get more information */
0470     gst_debug_set_active(TRUE);
0471     gst_debug_set_default_threshold(GST_LEVEL_FIXME);
0472     gst_debug_remove_log_function(gst_debug_log_default);
0473     gst_debug_add_log_function((GstLogFunction)gst_debug_logcat, NULL, NULL);
0474 
0475     /* get time we started for debugging messages */
0476     _priv_gst_info_start_time = gst_util_get_timestamp();
0477 
0478     if (!gst_init_check(NULL, NULL, &error)) {
0479         gchar *message = g_strdup_printf("GStreamer initialization failed: %s", error && error->message ? error->message : "(no message)");
0480         jclass exception_class = (*env)->FindClass(env, "java/lang/Exception");
0481         __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "%s", message);
0482         (*env)->ThrowNew(env, exception_class, message);
0483         g_free(message);
0484         return;
0485     }
0486     gst_debug_set_threshold_for_name("amc*", GST_LEVEL_TRACE);
0487     gst_android_register_static_plugins();
0488     gst_android_load_gio_modules();
0489     __android_log_print(ANDROID_LOG_INFO, "GStreamer", "GStreamer initialization complete");
0490 }
0491 #if 0
0492 static JNINativeMethod native_methods[] = {
0493   {"nativeInit", "(Landroid/content/Context;)V", (void *) gst_android_init}
0494 };
0495 #endif
0496 jint JNI_OnLoad(JavaVM *vm, void *reserved)
0497 {
0498     JNIEnv *env = NULL;
0499 
0500     __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "JNI_OnLoad");
0501 
0502     if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK) {
0503         __android_log_print(ANDROID_LOG_ERROR, "GStreamer", "Could not retrieve JNIEnv");
0504         return 0;
0505     }
0506 
0507     _java_vm = vm;
0508 #if 0
0509   jclass klass = (*env)->FindClass (env, "org/freedesktop/gstreamer/GStreamer");
0510   if (!klass) {
0511     __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
0512         "Could not retrieve class org.freedesktop.gstreamer.GStreamer");
0513     return 0;
0514   }
0515   if ((*env)->RegisterNatives (env, klass, native_methods,
0516           G_N_ELEMENTS (native_methods))) {
0517     __android_log_print (ANDROID_LOG_ERROR, "GStreamer",
0518         "Could not register native methods for org.freedesktop.gstreamer.GStreamer");
0519     return 0;
0520   }
0521 #endif
0522     return JNI_VERSION_1_4;
0523 }