Re: Video preview on android with Qt app

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello!

The problem with finding PjCamera class is solved.
PjClass is searched in "pjproject-2.5.5\pjmedia\src\pjmedia-videodev\android_dev.c" file in jni_init_ids() function. This function is normally called in thread which loaded this lib, so this function have access to class loader and everything is working fine, But when you starting use Qt for GUI, QApplication is started in its own thread and the system class loader is available from this context, so jni_init_ids() can't find PjCamera with FindClass.
The simplest solution is find PjCamera in JNI_OnLoad() function, defined in "pjproject-2.5.5\pjlib\src\pj\os_core_unix.c" and cache the results. This function is called when library is loaded and class loader is available.
To do so the two things should be done:
1. Move some code from jni_init_ids() to JNI_OnLoad().
2. use __android_log_print instead of PJ_LOG macro (because log facility is not inited at this point).

I've made a patch (git diff), hope it will be usefull.

15.08.2016, 14:26, "Анцев Александр" <a.antsev@xxxxxxxxx>:
> Hello!
>
> I'm trying to build an app for android with GUI written on Qt. Now I'm working on video preview. What i've done already:
> 1. Build OpenH264 lib.
> 2. Build pjsip with video support.
> 3. Copy PjCamera.java and PjCameraInfo.java into my app folder (src\org\pjsip\).
>
> The problem is that pjsip unable to find class name PjCamera from JVM. I have this debug log:
> .............
> I/pjsua (16412): 22:52:38.159 android_jni_de ..Android JNI sound library initialized
> I/pjsua (16412): 22:52:38.162 pjlib ..select() I/O Queue created (0xb861b48c)
> I/pjsua (16412): 22:52:38.182 pjsua_vid.c ..Initializing video subsystem..
> I/pjsua (16412): 22:52:38.183 openh264.cpp ...OpenH264 codec initialized
> I/pjsua (16412): 22:52:38.183 opengl_dev.c ...OpenGL device initialized
> I/pjsua (16412): 22:52:38.184 android_dev.c ...[JNI] Unable to find class 'PjCamera'
> .............
>
> And when I'm trying to create preview video program crashes. (I'm not sure that I'm creating video preview with correct device and maybe this is another error).
> My code:
>     vidPrev = new VideoPreview(PJMEDIA_VID_DEFAULT_RENDER_DEV);
>     VideoPreviewOpParam param;
>     vidPrev->start(param); // <-- crash here
>     VideoWindow prev = vidPrev->getVideoWindow();
>
> Crash log:
> I/pjsua (16412): 22:52:39.511 pjsua_vid.c !Starting preview for cap_dev=-2, show=1
> I/pjsua (16412): 22:52:39.511 pjsua_vid.c .Creating video window: type=preview, cap_id=-2, rend_id=-2
> I/pjsua (16412): 22:52:39.511 pjsua_vid.c ..Window 0: destroying..
> I/pjsua (16412): 22:52:39.511 media.cpp pjsua_vid_preview_start(devId, &prm) error: Invalid video device (PJMEDIA_EVID_INVDEV) (status=520004) [../src/pjsua2/media.cpp:1185]
> F/libc (16412): Fatal signal 6 (SIGABRT), code -6 in tid 16638 (QtThread)
> I/DEBUG ( 288): pid: 16412, tid: 16638, name: QtThread >>> org.qtproject.example <<<
> D/InputDispatcher( 984): Focus left window: 16412
> E/lowmemorykiller( 255): Error writing /proc/16412/oom_score_adj; errno=22
> I/Zygote ( 317): Process 16412 exited due to signal (6)
> I/ActivityManager( 984): Process org.qtproject.example (pid 16412)(adj 1) has died.(63,298)
>
> Does anybody faced with such error before?
>
> --
> С уважением,
> Александр Анцев
>
> _______________________________________________
> Visit our blog: http://blog.pjsip.org
>
> pjsip mailing list
> pjsip@xxxxxxxxxxxxxxx
> http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

--
С уважением,
Александр Анцев
diff --git a/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c b/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c
index 0fe05eb..bf2ddf8 100644
--- a/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c
+++ b/3rd part/pjproject-2.5.5/pjlib/src/pj/os_core_unix.c
@@ -56,13 +56,161 @@
 #if defined(PJ_JNI_HAS_JNI_ONLOAD) && PJ_JNI_HAS_JNI_ONLOAD != 0
 
 #include <jni.h>
+#include <android/log.h>
 
 JavaVM *pj_jni_jvm = NULL;
 
+#define PJ_CAMERA_CLASS_PATH		"org/pjsip/PjCamera"
+#define PJ_CAMERA_INFO_CLASS_PATH	"org/pjsip/PjCameraInfo"
+
+struct jni_objs_t
+{
+    struct {
+        jclass		 cls;
+        jmethodID	 m_init;
+        jmethodID	 m_start;
+        jmethodID	 m_stop;
+        jmethodID	 m_switch;
+    } cam;
+
+    struct {
+        jclass		 cls;
+        jmethodID	 m_get_cnt;
+        jmethodID	 m_get_info;
+        jfieldID	 f_facing;
+        jfieldID	 f_orient;
+        jfieldID	 f_sup_size;
+        jfieldID	 f_sup_fmt;
+        jfieldID	 f_sup_fps;
+    } cam_info;
+
+};
+
+struct jni_objs_t jobjs;
+
+static pj_bool_t jni_get_env(JNIEnv **jni_env)
+{
+    pj_bool_t with_attach = PJ_FALSE;
+    if ((*pj_jni_jvm)->GetEnv(pj_jni_jvm, (void **)jni_env,
+                              JNI_VERSION_1_4) < 0)
+    {
+        if ((*pj_jni_jvm)->AttachCurrentThread(pj_jni_jvm, jni_env, NULL) < 0)
+        {
+            *jni_env = NULL;
+        } else {
+            with_attach = PJ_TRUE;
+        }
+    }
+
+    return with_attach;
+}
+
+static void jni_detach_env(pj_bool_t need_detach)
+{
+    if (need_detach)
+        (*pj_jni_jvm)->DetachCurrentThread(pj_jni_jvm);
+}
+
+
+/* Get Java object IDs (via FindClass, GetMethodID, GetFieldID, etc).
+ * Note that this function should be called from library-loader thread,
+ * otherwise FindClass, etc, may fail, see:
+ * http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
+ */
+
+static pj_status_t jni_init_ids()
+{
+    JNIEnv *jni_env;
+    pj_status_t status = PJ_SUCCESS;
+    pj_bool_t with_attach = jni_get_env(&jni_env);
+
+#define GET_CLASS(class_path, class_name, cls) \
+    cls = (*jni_env)->FindClass(jni_env, class_path); \
+    if (cls == NULL || (*jni_env)->ExceptionCheck(jni_env)) { \
+        (*jni_env)->ExceptionClear(jni_env); \
+        __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find class '" class_name "'"); \
+        status = PJ_EINVAL; \
+        goto on_return; \
+    } else { \
+        jclass tmp = cls; \
+        cls = (jclass)(*jni_env)->NewGlobalRef(jni_env, tmp); \
+        (*jni_env)->DeleteLocalRef(jni_env, tmp); \
+        if (cls == NULL) { \
+            __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to get global ref for class '" class_name "'"); \
+            status = PJ_EINVAL; \
+            goto on_return; \
+        } \
+    }
+#define GET_METHOD_ID(cls, class_name, method_name, signature, id) \
+    id = (*jni_env)->GetMethodID(jni_env, cls, method_name, signature); \
+    if (id == 0) { \
+        __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find method '" method_name "' in class '" class_name "'"); \
+        status = PJ_EINVAL; \
+        goto on_return; \
+    }
+#define GET_SMETHOD_ID(cls, class_name, method_name, signature, id) \
+    id = (*jni_env)->GetStaticMethodID(jni_env, cls, method_name, signature); \
+    if (id == 0) { \
+        __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find static method '" method_name "' in class '" class_name "'"); \
+        status = PJ_EINVAL; \
+        goto on_return; \
+    }
+#define GET_FIELD_ID(cls, class_name, field_name, signature, id) \
+    id = (*jni_env)->GetFieldID(jni_env, cls, field_name, signature); \
+    if (id == 0) { \
+        __android_log_print(ANDROID_LOG_INFO, "THIS_FILE", "[JNI] Unable to find field '" field_name "' in class '" class_name "'"); \
+        status = PJ_EINVAL; \
+        goto on_return; \
+    }
+
+    /* PjCamera class info */
+    GET_CLASS(PJ_CAMERA_CLASS_PATH, "PjCamera", jobjs.cam.cls);
+    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "<init>",
+                  "(IIIIIJLandroid/view/SurfaceView;)V",
+                  jobjs.cam.m_init);
+    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Start", "()I",
+                  jobjs.cam.m_start);
+    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Stop", "()V",
+                  jobjs.cam.m_stop);
+    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "SwitchDevice", "(I)I",
+                  jobjs.cam.m_switch);
+
+    /* PjCameraInfo class info */
+    GET_CLASS(PJ_CAMERA_INFO_CLASS_PATH, "PjCameraInfo", jobjs.cam_info.cls);
+    GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraCount", "()I",
+                   jobjs.cam_info.m_get_cnt);
+    GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraInfo",
+                   "(I)L" PJ_CAMERA_INFO_CLASS_PATH ";",
+                   jobjs.cam_info.m_get_info);
+    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "facing", "I",
+                 jobjs.cam_info.f_facing);
+    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "orient", "I",
+                 jobjs.cam_info.f_orient);
+    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedSize", "[I",
+                 jobjs.cam_info.f_sup_size);
+    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFormat", "[I",
+                 jobjs.cam_info.f_sup_fmt);
+    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFps1000", "[I",
+                 jobjs.cam_info.f_sup_fps);
+
+#undef GET_CLASS_ID
+#undef GET_METHOD_ID
+#undef GET_SMETHOD_ID
+#undef GET_FIELD_ID
+
+on_return:
+    jni_detach_env(with_attach);
+    return status;
+}
+
 JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
 {
+    __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "JNI_OnLoad started");
     pj_jni_jvm = vm;
-    
+
+    if (jni_init_ids() != PJ_SUCCESS)
+        __android_log_print(ANDROID_LOG_INFO, THIS_FILE, "Classes caching failed");
+
     return JNI_VERSION_1_4;
 }
 #endif
diff --git a/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c b/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c
index 358c532..9f01a4a 100644
--- a/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c
+++ b/3rd part/pjproject-2.5.5/pjmedia/src/pjmedia-videodev/android_dev.c
@@ -197,10 +197,8 @@ static pjmedia_vid_dev_stream_op stream_op =
  * JNI stuff
  */
 extern JavaVM *pj_jni_jvm;
-#define PJ_CAMERA_CLASS_PATH		"org/pjsip/PjCamera"
-#define PJ_CAMERA_INFO_CLASS_PATH	"org/pjsip/PjCameraInfo"
 
-static struct jni_objs_t
+struct jni_objs_t
 {
     struct {
 	jclass		 cls;
@@ -221,8 +219,9 @@ static struct jni_objs_t
 	jfieldID	 f_sup_fps;
     } cam_info;
 
-} jobjs;
+};
 
+extern struct jni_objs_t jobjs;
 
 static void JNICALL OnGetFrame(JNIEnv *env, jobject obj,
                                jbyteArray data, jint length,
@@ -265,85 +264,6 @@ static pj_status_t jni_init_ids()
     pj_status_t status = PJ_SUCCESS;
     pj_bool_t with_attach = jni_get_env(&jni_env);
 
-#define GET_CLASS(class_path, class_name, cls) \
-    cls = (*jni_env)->FindClass(jni_env, class_path); \
-    if (cls == NULL || (*jni_env)->ExceptionCheck(jni_env)) { \
-	(*jni_env)->ExceptionClear(jni_env); \
-        PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find class '" \
-			      class_name "'")); \
-        status = PJMEDIA_EVID_SYSERR; \
-        goto on_return; \
-    } else { \
-        jclass tmp = cls; \
-	cls = (jclass)(*jni_env)->NewGlobalRef(jni_env, tmp); \
-	(*jni_env)->DeleteLocalRef(jni_env, tmp); \
-	if (cls == NULL) { \
-	    PJ_LOG(3, (THIS_FILE, "[JNI] Unable to get global ref for " \
-				  "class '" class_name "'")); \
-	    status = PJMEDIA_EVID_SYSERR; \
-	    goto on_return; \
-	} \
-    }
-#define GET_METHOD_ID(cls, class_name, method_name, signature, id) \
-    id = (*jni_env)->GetMethodID(jni_env, cls, method_name, signature); \
-    if (id == 0) { \
-        PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find method '" method_name \
-			      "' in class '" class_name "'")); \
-        status = PJMEDIA_EVID_SYSERR; \
-        goto on_return; \
-    }
-#define GET_SMETHOD_ID(cls, class_name, method_name, signature, id) \
-    id = (*jni_env)->GetStaticMethodID(jni_env, cls, method_name, signature); \
-    if (id == 0) { \
-        PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find static method '" \
-			      method_name "' in class '" class_name "'")); \
-        status = PJMEDIA_EVID_SYSERR; \
-        goto on_return; \
-    }
-#define GET_FIELD_ID(cls, class_name, field_name, signature, id) \
-    id = (*jni_env)->GetFieldID(jni_env, cls, field_name, signature); \
-    if (id == 0) { \
-        PJ_LOG(3, (THIS_FILE, "[JNI] Unable to find field '" field_name \
-			      "' in class '" class_name "'")); \
-        status = PJMEDIA_EVID_SYSERR; \
-        goto on_return; \
-    }
-
-    /* PjCamera class info */
-    GET_CLASS(PJ_CAMERA_CLASS_PATH, "PjCamera", jobjs.cam.cls);
-    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "<init>",
-		  "(IIIIIJLandroid/view/SurfaceView;)V",
-		  jobjs.cam.m_init);
-    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Start", "()I",
-		  jobjs.cam.m_start);
-    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "Stop", "()V",
-		  jobjs.cam.m_stop);
-    GET_METHOD_ID(jobjs.cam.cls, "PjCamera", "SwitchDevice", "(I)I",
-		  jobjs.cam.m_switch);
-
-    /* PjCameraInfo class info */
-    GET_CLASS(PJ_CAMERA_INFO_CLASS_PATH, "PjCameraInfo", jobjs.cam_info.cls);
-    GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraCount", "()I",
-		   jobjs.cam_info.m_get_cnt);
-    GET_SMETHOD_ID(jobjs.cam_info.cls, "PjCameraInfo", "GetCameraInfo",
-		   "(I)L" PJ_CAMERA_INFO_CLASS_PATH ";",
-		   jobjs.cam_info.m_get_info);
-    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "facing", "I",
-		 jobjs.cam_info.f_facing);
-    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "orient", "I",
-		 jobjs.cam_info.f_orient);
-    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedSize", "[I",
-		 jobjs.cam_info.f_sup_size);
-    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFormat", "[I",
-		 jobjs.cam_info.f_sup_fmt);
-    GET_FIELD_ID(jobjs.cam_info.cls, "PjCameraInfo", "supportedFps1000", "[I",
-		 jobjs.cam_info.f_sup_fps);
-
-#undef GET_CLASS_ID
-#undef GET_METHOD_ID
-#undef GET_SMETHOD_ID
-#undef GET_FIELD_ID
-
     /* Register native function */
     {
 	JNINativeMethod m = { "PushFrame", "([BIJ)V", (void*)&OnGetFrame };
_______________________________________________
Visit our blog: http://blog.pjsip.org

pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org

[Index of Archives]     [Asterisk Users]     [Asterisk App Development]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [Linux API]
  Powered by Linux