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 }