universal7580: camera: defer start_preview until surface is valid
authorBenoît Laniel <nels+git@pgroupe.net>
Fri, 24 Mar 2017 21:33:03 +0000 (22:33 +0100)
committerJan Altensen <info@stricted.net>
Fri, 16 Aug 2019 21:18:44 +0000 (23:18 +0200)
Some apps like Snap start preview very early to setup camera while initializing
UI. It then calls setPreviewDisplay (set_preview_window) to define the surface
used for preview.

According to https://developer.android.com/reference/android/hardware/Camera.html#setPreviewDisplay%28android.view.SurfaceHolder%29
"This allows camera setup and surface creation to happen in parallel, saving time."

But https://developer.android.com/reference/android/hardware/Camera.html#startPreview%28%29
"Preview will not actually start until a surface is supplied with setPreviewDisplay(SurfaceHolder) or setPreviewTexture(SurfaceTexture)."

However, hero camera hal starts preview with an internal buffer when surface
is not valid / null.

[CAM_ID(0)][]-WARN(setPreviewWindow[204]):Preview window is NULL, create internal buffer for preview
[CAM_ID(0)][]-INFO(startPreview[519]):setBuffersThread is run

On the next set_preview_window call (the one defining the surface), camera hal
restarts preview since it is already running using the internal buffer.

[CAM_ID(0)][]-WRN(setPreviewWindow[187]):Preview is started, we forcely re-start preview

Problem with this is that it deadlocks quite often. It loops here

[CAM_ID(0)][]-INFO(m_mainThreadQSetup3AA[1078]):m_flagThreadStop(1)

Let's handle the situation in the wrapper so no restart is done by the hal.

Change-Id: I762af781e5af96b52407387aa9ae67874a8ab8b6

camera/Camera2Wrapper.cpp

index 0079c872bf9f77348ed88b080808f7b920754ae3..2fa813d1a84d1f95d1ec2a8a7ae89ff016727b03 100644 (file)
@@ -37,6 +37,8 @@ typedef struct wrapper_camera2_device {
 #define CAMERA_ID(device) (((wrapper_camera2_device_t *)(device))->id)
 
 static camera_module_t *gVendorModule = 0;
+static preview_stream_ops *gPreviewWindow = 0;
+static bool gPreviewStartDeferred = false;
 
 static int check_vendor_module()
 {
@@ -112,12 +114,25 @@ static char * camera2_fixup_setparams(int id __unused, const char * settings)
 static int camera2_set_preview_window(struct camera_device * device,
         struct preview_stream_ops *window)
 {
+    int rc = 0;
     ALOGV("%s->%08X->%08X", __FUNCTION__, (uintptr_t)device, (uintptr_t)(((wrapper_camera2_device_t*)device)->vendor));
 
-    if(!device || !window)
+    if(!device)
         return -EINVAL;
 
-    return VENDOR_CALL(device, set_preview_window, window);
+    gPreviewWindow = window;
+
+    if (gPreviewWindow != 0) {
+        rc = VENDOR_CALL(device, set_preview_window, window);
+
+        if (gPreviewStartDeferred) {
+            ALOGV("%s call deferred start_preview", __FUNCTION__);
+            gPreviewStartDeferred = false;
+            VENDOR_CALL(device, start_preview);
+        }
+    }
+
+    return rc;
 }
 
 static void camera2_set_callbacks(struct camera_device * device,
@@ -173,7 +188,13 @@ static int camera2_start_preview(struct camera_device * device)
     if(!device)
         return -EINVAL;
 
-    rc = VENDOR_CALL(device, start_preview);
+    if (gPreviewWindow != 0) {
+        rc = VENDOR_CALL(device, start_preview);
+    } else {
+        ALOGV("%s invalid preview window, defer start_preview", __FUNCTION__);
+        gPreviewStartDeferred = true;
+    }
+
     return rc;
 }
 
@@ -194,7 +215,12 @@ static int camera2_preview_enabled(struct camera_device * device)
     if(!device)
         return -EINVAL;
 
-    return VENDOR_CALL(device, preview_enabled);
+    if (gPreviewStartDeferred) {
+        ALOGV("%s deferred start_preview, return 1", __FUNCTION__);
+        return 1;
+    } else {
+        return VENDOR_CALL(device, preview_enabled);
+    }
 }
 
 static int camera2_store_meta_data_in_buffers(struct camera_device * device, int enable)
@@ -381,6 +407,8 @@ static int camera2_device_close(hw_device_t* device)
         free(wrapper_dev->base.ops);
     free(wrapper_dev);
 done:
+    gPreviewWindow = 0;
+    gPreviewStartDeferred = false;
     return ret;
 }