Things get better (and autofocus is fixed)
authorPaul Kocialkowski <contact@paulk.fr>
Sat, 26 Jan 2013 19:19:32 +0000 (20:19 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Sat, 26 Jan 2013 19:19:32 +0000 (20:19 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
exynos_camera.c
exynos_camera.h
exynos_v4l2.c

index 3320305..ff8b7eb 100644 (file)
@@ -235,6 +235,7 @@ void exynos_camera_deinit(struct exynos_camera *exynos_camera)
        }
 }
 
+// Preview
 
 int exynos_camera_preview(struct exynos_camera *exynos_camera)
 {
@@ -316,8 +317,10 @@ void *exynos_camera_preview_thread(void *data)
        LOGE("%s: Starting thread", __func__);
        exynos_camera->preview_thread_running = 1;
 
-       // Lock preview lock mutex
-       pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+       if (exynos_camera->preview_window == NULL) {
+               // Lock preview lock mutex
+               pthread_mutex_lock(&exynos_camera->preview_lock_mutex);
+       }
 
        while (exynos_camera->preview_enabled == 1) {
                pthread_mutex_lock(&exynos_camera->preview_mutex);
@@ -338,119 +341,8 @@ void *exynos_camera_preview_thread(void *data)
        return NULL;
 }
 
-
-/*
- * Exynos Camera OPS
- */
-
-int exynos_camera_set_preview_window(struct camera_device *dev,
-       struct preview_stream_ops *w)
-{
-       struct exynos_camera *exynos_camera;
-       buffer_handle_t *buffer;
-       int stride;
-       void *addr = NULL;
-
-       int rc;
-
-       LOGD("%s(%p, %p)", __func__, dev, w);
-
-       if (dev == NULL || dev->priv == NULL)
-               return -EINVAL;
-
-       exynos_camera = (struct exynos_camera *) dev->priv;
-
-       if (w == NULL)
-               return 0;
-
-       pthread_mutex_lock(&exynos_camera->preview_mutex);
-
-       exynos_camera->preview_window = w;
-
-       if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL)
-               return -EINVAL;
-
-       if (exynos_camera->preview_buffers_count <= 0) {
-               LOGE("%s: Invalid preview buffers count", __func__);
-               goto error;
-       }
-
-       rc = w->set_buffer_count(w, exynos_camera->preview_buffers_count);
-       if (rc) {
-               LOGE("%s: Unable to set buffer count (%d)", __func__,
-                       exynos_camera->preview_buffers_count);
-               goto error;
-       }
-
-       rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN);
-       if (rc) {
-               LOGE("%s: Unable to set usage", __func__);
-               goto error;
-       }
-
-       // TODO: Get this from params
-       rc = w->set_buffers_geometry(w, 640, 480, HAL_PIXEL_FORMAT_YCrCb_420_SP);
-       if (rc) {
-               LOGE("%s: Unable to set buffers geometry", __func__);
-               goto error;
-       }
-
-       pthread_mutex_unlock(&exynos_camera->preview_mutex);
-
-       // Unlock preview lock
-       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
-
-       return 0;
-
-error:
-       pthread_mutex_unlock(&exynos_camera->preview_mutex);
-
-       return -1;
-}
-
-void exynos_camera_set_callbacks(struct camera_device *dev,
-       camera_notify_callback notify_cb,
-       camera_data_callback data_cb,
-       camera_data_timestamp_callback data_cb_timestamp,
-       camera_request_memory get_memory,
-       void *user)
-{
-       struct exynos_camera *exynos_camera;
-
-       LOGD("%s(%p, %p)", __func__, dev, user);
-
-       if (dev == NULL || dev->priv == NULL)
-               return;
-
-       exynos_camera = (struct exynos_camera *) dev->priv;
-
-       exynos_camera->callbacks.notify = notify_cb;
-       exynos_camera->callbacks.data = data_cb;
-       exynos_camera->callbacks.data_timestamp = data_cb_timestamp;
-       exynos_camera->callbacks.request_memory = get_memory;
-       exynos_camera->callbacks.user = user;
-}
-
-void exynos_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type)
-{
-       LOGD("%s(%p, %d)", __func__, dev, msg_type);
-}
-
-void exynos_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type)
-{
-       LOGD("%s(%p, %d)", __func__, dev, msg_type);
-}
-
-int exynos_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type)
-{
-       LOGD("%s(%p, %d)", __func__, dev, msg_type);
-
-       return 0;
-}
-
-int exynos_camera_start_preview(struct camera_device *dev)
+int exynos_camera_preview_start(struct exynos_camera *exynos_camera)
 {
-       struct exynos_camera *exynos_camera;
        struct v4l2_streamparm streamparm;
        unsigned int fmt;
        int width, height, fps, frame_size;
@@ -462,17 +354,15 @@ int exynos_camera_start_preview(struct camera_device *dev)
        int rc;
        int i;
 
-       LOGD("%s(%p)", __func__, dev);
-
-       if (dev == NULL || dev->priv == NULL)
-               return -EINVAL;
-
-       exynos_camera = (struct exynos_camera *) dev->priv;
-
        if (exynos_camera->config == NULL || exynos_camera->config->presets == NULL ||
                exynos_camera->camera_id >= exynos_camera->config->presets_count)
                return -EINVAL;
 
+       if (exynos_camera->preview_enabled) {
+               LOGE("Preview was already started!");
+               return 0;
+       }
+
        // V4L2
 
        fmt = V4L2_PIX_FMT_NV21;
@@ -486,7 +376,7 @@ int exynos_camera_start_preview(struct camera_device *dev)
        width = 640;
        height = 480;
 
-       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, fmt);
+       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, fmt, V4L2_PIX_FMT_MODE_PREVIEW);
        if (rc < 0) {
                LOGE("%s: s fmt failed!", __func__);
                return -1;
@@ -539,7 +429,7 @@ int exynos_camera_start_preview(struct camera_device *dev)
                        exynos_camera->preview_memory->release(exynos_camera->preview_memory);
 
                exynos_camera->preview_memory =
-                       exynos_camera->callbacks.request_memory(fd, 
+                       exynos_camera->callbacks.request_memory(fd,
                                frame_size, exynos_camera->preview_buffers_count, 0);
                if (exynos_camera->preview_memory == NULL) {
                        LOGE("%s: memory request failed!", __func__);
@@ -587,13 +477,6 @@ int exynos_camera_start_preview(struct camera_device *dev)
                return -1;
        }
 
-       // Init FIMC1
-       rc = exynos_v4l2_open(exynos_camera, 1);
-       if (rc < 0) {
-               LOGE("Unable to open v4l2 device");
-               return -1;
-       }
-
        // Thread
 
        pthread_mutex_init(&exynos_camera->preview_mutex, NULL);
@@ -617,21 +500,18 @@ int exynos_camera_start_preview(struct camera_device *dev)
        return 0;
 }
 
-void exynos_camera_stop_preview(struct camera_device *dev)
+void exynos_camera_preview_stop(struct exynos_camera *exynos_camera)
 {
-       struct exynos_camera *exynos_camera;
        int rc;
        int i;
 
-       LOGD("%s(%p)", __func__, dev);
-
-       if (dev == NULL || dev->priv == NULL)
+       if (exynos_camera == NULL)
                return;
 
-       exynos_camera = (struct exynos_camera *) dev->priv;
-
-       if (!exynos_camera->preview_enabled)
+       if (!exynos_camera->preview_enabled) {
+               LOGE("Preview was already stopped!");
                return;
+       }
 
        exynos_camera->preview_enabled = 0;
 
@@ -661,72 +541,703 @@ void exynos_camera_stop_preview(struct camera_device *dev)
        pthread_mutex_unlock(&exynos_camera->preview_mutex);
 }
 
-int exynos_camera_preview_enabled(struct camera_device *dev)
+// Auto-focus
+
+void *exynos_camera_auto_focus_thread(void *data)
 {
        struct exynos_camera *exynos_camera;
+       int auto_focus_status = -1;
+       int auto_focus_result = 0;
+       int rc;
+       int i;
 
-       LOGD("%s(%p)", __func__, dev);
+       if (data == NULL)
+               return NULL;
 
-       if (dev == NULL || dev->priv == NULL)
-               return -EINVAL;
+       exynos_camera = (struct exynos_camera *) data;
 
-       exynos_camera = (struct exynos_camera *) dev->priv;
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->auto_focus_thread_running = 1;
 
-       return exynos_camera->preview_enabled;
-}
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_SET_AUTO_FOCUS, 1);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               auto_focus_result = 0;
+               goto thread_exit;
+       }
 
-int exynos_camera_store_meta_data_in_buffers(struct camera_device *dev,
-       int enable)
-{
-       LOGD("%s(%p, %d)", __func__, dev, enable);
+       while (exynos_camera->auto_focus_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->auto_focus_mutex);
 
-       return 0;
-}
+               rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_AUTO_FOCUS_RESULT, &auto_focus_status);
+               if (rc < 0) {
+                       LOGE("%s: g ctrl failed!", __func__);
+                       auto_focus_result = 0;
+                       pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                       goto thread_exit;
+               }
 
-int exynos_camera_start_recording(struct camera_device *dev)
-{
-       LOGD("%s(%p)", __func__, dev);
+               switch (auto_focus_status) {
+                       case CAMERA_AF_STATUS_IN_PROGRESS:
+                       case CAMERA_AF_STATUS_SUCCESS:
+                               usleep(500);
+                               break;
+                       case CAMERA_AF_STATUS_1ST_SUCCESS:
+                               auto_focus_result = 1;
+                               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                               goto thread_exit;
+                       case CAMERA_AF_STATUS_FAIL:
+                       default:
+                               auto_focus_result = 0;
+                               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+                               goto thread_exit;                               
+               }
 
-       return 0;
-}
+               pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+       }
 
-void exynos_camera_stop_recording(struct camera_device *dev)
-{
-       LOGD("%s(%p)", __func__, dev);
-}
+thread_exit:
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_FOCUS) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify))
+               exynos_camera->callbacks.notify(CAMERA_MSG_FOCUS,
+                       (int32_t) auto_focus_result, 0, exynos_camera->callbacks.user);
+               
+       exynos_camera->auto_focus_thread_running = 0;
+       exynos_camera->auto_focus_enabled = 0;
 
-int exynos_camera_recording_enabled(struct camera_device *dev)
-{
-       LOGD("%s(%p)", __func__, dev);
+       LOGE("%s: Exiting thread", __func__);
 
-       return 0;
+       return NULL;
 }
 
-void exynos_camera_release_recording_frame(struct camera_device *dev,
-       const void *opaque)
+int exynos_camera_auto_focus_start(struct exynos_camera *exynos_camera)
 {
-       LOGD("%s(%p, %p)", __func__, dev, opaque);
-}
+       pthread_attr_t thread_attr;
+       int rc;
 
-int exynos_camera_auto_focus(struct camera_device *dev)
-{
-       LOGD("%s(%p)", __func__, dev);
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // Thread
+
+       if (exynos_camera->auto_focus_thread_running) {
+               LOGE("Auto-focus thread is already running!");
+               return -1;
+       }
+
+       pthread_mutex_init(&exynos_camera->auto_focus_mutex, NULL);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->auto_focus_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->auto_focus_thread, &thread_attr,
+               exynos_camera_auto_focus_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
 
        return 0;
 }
 
-int exynos_camera_cancel_auto_focus(struct camera_device *dev)
+void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera)
 {
-       LOGD("%s(%p)", __func__, dev);
+       int rc;
+       int i;
 
-       return 0;
+       if (exynos_camera == NULL)
+               return;
+
+       pthread_mutex_lock(&exynos_camera->auto_focus_mutex);
+
+       // Disable auto-focus to make the thread end
+       exynos_camera->auto_focus_enabled = 0;
+
+       pthread_mutex_unlock(&exynos_camera->auto_focus_mutex);
+
+       // Wait for the thread to end
+       for (i=0 ; i < 10 ; i++) {
+               if (!exynos_camera->auto_focus_thread_running)
+                       break;
+
+               usleep(500);
+       }
+
+       pthread_mutex_destroy(&exynos_camera->auto_focus_mutex);
 }
 
-int exynos_camera_take_picture(struct camera_device *dev)
+// Picture
+
+int exynos_camera_picture(struct exynos_camera *exynos_camera)
 {
-       LOGD("%s(%p)", __func__, dev);
+       camera_memory_t *picture_main_memory;
+       camera_memory_t *picture_thumb_memory;
 
-       return 0;
+       int value;
+
+       int jpeg_main_size, jpeg_main_offset, jpeg_thumb_size, jpeg_thumb_offset;
+       int exif_tv, exif_flash, exif_iso, exif_bv;
+       int jpeg_postview_offset;
+
+       void *jpeg_main_addr, *jpeg_thumb_addr;
+
+       int index;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // V4L2
+
+       rc = exynos_v4l2_poll(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: poll failed!", __func__);
+               return -1;
+       } else if (rc == 0) {
+               LOGE("%s: poll timeout!", __func__);
+               // TODO: it's probably a good idea to restart everything
+               return -1;
+       }
+
+       rc = exynos_v4l2_streamoff_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamoff failed!", __func__);
+               return -1;
+       }
+
+       index = exynos_v4l2_dqbuf_cap(exynos_camera, 0);
+       if (index < 0) {
+               LOGE("%s: dqbuf failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_SIZE,
+               &jpeg_main_size);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_MAIN_OFFSET,
+               &jpeg_main_offset);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_SIZE,
+               &jpeg_thumb_size);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_THUMB_OFFSET,
+               &jpeg_thumb_offset);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAM_JPEG_POSTVIEW_OFFSET,
+               &jpeg_postview_offset);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               return -1;
+       }
+
+       jpeg_main_addr = (void *) ((int) exynos_camera->picture_memory->data + jpeg_main_offset);
+       jpeg_thumb_addr = (void *) ((int) exynos_camera->picture_memory->data + jpeg_thumb_offset);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_SHUTTER) && EXYNOS_CAMERA_CALLBACK_DEFINED(notify))
+               exynos_camera->callbacks.notify(CAMERA_MSG_SHUTTER, 0, 0,
+                       exynos_camera->callbacks.user);
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_thumb_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_thumb_size, 1, 0);
+                       if (picture_thumb_memory == NULL) {
+                               LOGE("%s: thumb memory request failed!", __func__);
+                               return -1;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       return -1;
+               }
+
+               memcpy(picture_thumb_memory->data, jpeg_thumb_addr, jpeg_thumb_size);
+
+               exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE,
+                       picture_thumb_memory, 0, NULL, exynos_camera->callbacks.user);
+
+               picture_thumb_memory->release(picture_thumb_memory);
+       }
+
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_main_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_main_size, 1, 0);
+                       if (picture_main_memory == NULL) {
+                               LOGE("%s: main memory request failed!", __func__);
+                               return -1;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       return -1;
+               }
+
+               memcpy(picture_main_memory->data, jpeg_main_addr, jpeg_main_size);
+
+               exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE,
+                       picture_main_memory, 0, NULL, exynos_camera->callbacks.user);
+
+               picture_main_memory->release(picture_main_memory);
+       }
+
+/*
+E/exynos_camera( 2647): main (0x0, 0x254686) thumb(0x3a0000, 0xb1d7) post(0x3afc00)
+offset = 3afc00
+size = 46b400
+diff = 768000 = 640 * 480 * 2.5
+
+*/
+       // Preview window
+/*
+       exynos_camera->preview_window->dequeue_buffer(exynos_camera->preview_window,
+               &buffer, &stride);
+       exynos_camera->gralloc->lock(exynos_camera->gralloc, *buffer, GRALLOC_USAGE_SW_WRITE_OFTEN,
+               0, 0, 640, 480, &addr);
+
+       if (addr == NULL) {
+               LOGE("Unable to get addr");
+               return -1;
+       }
+       offset = index*640*480*1.5;
+
+       void *frame = (void *) ((int) exynos_camera->preview_memory->data + offset);
+
+       memcpy(addr, frame, 640*480*1.5);
+
+       exynos_camera->gralloc->unlock(exynos_camera->gralloc, *buffer);
+
+       exynos_camera->preview_window->enqueue_buffer(exynos_camera->preview_window,
+               buffer);
+*/
+/*
+       rc = exynos_camera_preview_start(exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to start preview!", __func__);
+               return -1;
+       }
+
+       // Unlock preview lock (all should be set already)
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+*/
+       return 0;
+}
+
+void *exynos_camera_picture_thread(void *data)
+{
+       struct exynos_camera *exynos_camera;
+       int rc;
+       int i;
+
+       if (data == NULL)
+               return NULL;
+
+       exynos_camera = (struct exynos_camera *) data;
+
+       LOGE("%s: Starting thread", __func__);
+       exynos_camera->picture_thread_running = 1;
+
+       if (exynos_camera->picture_enabled == 1) {
+               pthread_mutex_lock(&exynos_camera->picture_mutex);
+
+               rc = exynos_camera_picture(exynos_camera);
+               if (rc < 0) {
+                       LOGE("%s: picture failed!", __func__);
+                       exynos_camera->picture_enabled = 0;
+               }
+
+               pthread_mutex_unlock(&exynos_camera->picture_mutex);
+       }
+
+       exynos_camera->picture_thread_running = 0;
+       exynos_camera->picture_enabled = 0;
+
+       LOGE("%s: Exiting thread", __func__);
+
+       return NULL;
+}
+
+int exynos_camera_picture_start(struct exynos_camera *exynos_camera)
+{
+       pthread_attr_t thread_attr;
+
+       int width, height, fmt;
+
+       int fd;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       // Stop preview thread
+       exynos_camera_preview_stop(exynos_camera);
+
+       // V4L2
+
+       fmt = V4L2_PIX_FMT_JPEG;
+
+       rc = exynos_v4l2_enum_fmt_cap(exynos_camera, 0, fmt);
+       if (rc < 0) {
+               LOGE("%s: enum fmt failed!", __func__);
+               return -1;
+       }
+
+       width = 3264;
+       height = 2448;
+
+       rc = exynos_v4l2_s_fmt_pix_cap(exynos_camera, 0, width, height, fmt, V4L2_PIX_FMT_MODE_CAPTURE);
+       if (rc < 0) {
+               LOGE("%s: s fmt failed!", __func__);
+               return -1;
+       }
+
+       // Only use 1 buffer
+       rc = exynos_v4l2_reqbufs_cap(exynos_camera, 0, 1);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_querybuf_cap(exynos_camera, 0, 0);
+       if (rc < 0) {
+               LOGE("%s: querybuf failed!", __func__);
+               return -1;
+       }
+
+       exynos_camera->picture_buffer_length = rc;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               fd = exynos_v4l2_find_fd(exynos_camera, 0);
+               if (fd < 0) {
+                       LOGE("%s: Unable to find v4l2 fd", __func__);
+                       return -1;
+               }
+
+               if (exynos_camera->picture_memory != NULL && exynos_camera->picture_memory->release != NULL)
+                       exynos_camera->picture_memory->release(exynos_camera->picture_memory);
+
+               exynos_camera->picture_memory =
+                       exynos_camera->callbacks.request_memory(fd,
+                               exynos_camera->picture_buffer_length, 1, 0);
+               if (exynos_camera->picture_memory == NULL) {
+                       LOGE("%s: memory request failed!", __func__);
+                       return -1;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_qbuf_cap(exynos_camera, 0, 0);
+       if (rc < 0) {
+               LOGE("%s: qbuf failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_streamon_cap(exynos_camera, 0);
+       if (rc < 0) {
+               LOGE("%s: streamon failed!", __func__);
+               return -1;
+       }
+
+       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_CAPTURE, 0);
+       if (rc < 0) {
+               LOGE("%s: s ctrl failed!", __func__);
+               return -1;
+       }
+
+       // Thread
+
+       if (exynos_camera->picture_thread_running) {
+               LOGE("Picture thread is already running!");
+               return -1;
+       }
+
+       pthread_mutex_init(&exynos_camera->picture_mutex, NULL);
+
+       pthread_attr_init(&thread_attr);
+       pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+
+       exynos_camera->picture_enabled = 1;
+
+       rc = pthread_create(&exynos_camera->picture_thread, &thread_attr,
+               exynos_camera_picture_thread, (void *) exynos_camera);
+       if (rc < 0) {
+               LOGE("%s: Unable to create thread", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * Exynos Camera OPS
+ */
+
+int exynos_camera_set_preview_window(struct camera_device *dev,
+       struct preview_stream_ops *w)
+{
+       struct exynos_camera *exynos_camera;
+       buffer_handle_t *buffer;
+       int stride;
+       void *addr = NULL;
+
+       int rc;
+
+       LOGD("%s(%p, %p)", __func__, dev, w);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       if (w == NULL)
+               return 0;
+
+       pthread_mutex_lock(&exynos_camera->preview_mutex);
+
+       exynos_camera->preview_window = w;
+
+       if (w->set_buffer_count == NULL || w->set_usage == NULL || w->set_buffers_geometry == NULL)
+               return -EINVAL;
+
+       if (exynos_camera->preview_buffers_count <= 0) {
+               LOGE("%s: Invalid preview buffers count", __func__);
+               goto error;
+       }
+
+       rc = w->set_buffer_count(w, exynos_camera->preview_buffers_count);
+       if (rc) {
+               LOGE("%s: Unable to set buffer count (%d)", __func__,
+                       exynos_camera->preview_buffers_count);
+               goto error;
+       }
+
+       rc = w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN);
+       if (rc) {
+               LOGE("%s: Unable to set usage", __func__);
+               goto error;
+       }
+
+       // TODO: Get this from params
+       rc = w->set_buffers_geometry(w, 640, 480, HAL_PIXEL_FORMAT_YCrCb_420_SP);
+       if (rc) {
+               LOGE("%s: Unable to set buffers geometry", __func__);
+               goto error;
+       }
+
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       // Unlock preview lock
+       pthread_mutex_unlock(&exynos_camera->preview_lock_mutex);
+
+       return 0;
+
+error:
+       pthread_mutex_unlock(&exynos_camera->preview_mutex);
+
+       return -1;
+}
+
+void exynos_camera_set_callbacks(struct camera_device *dev,
+       camera_notify_callback notify_cb,
+       camera_data_callback data_cb,
+       camera_data_timestamp_callback data_cb_timestamp,
+       camera_request_memory get_memory,
+       void *user)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %p)", __func__, dev, user);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->callbacks.notify = notify_cb;
+       exynos_camera->callbacks.data = data_cb;
+       exynos_camera->callbacks.data_timestamp = data_cb_timestamp;
+       exynos_camera->callbacks.request_memory = get_memory;
+       exynos_camera->callbacks.user = user;
+}
+
+void exynos_camera_enable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->messages_enabled |= msg_type;
+}
+
+void exynos_camera_disable_msg_type(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera->messages_enabled &= ~msg_type;
+}
+
+int exynos_camera_msg_type_enabled(struct camera_device *dev, int32_t msg_type)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p, %d)", __func__, dev, msg_type);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->messages_enabled & msg_type;
+}
+
+int exynos_camera_start_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_preview_start(exynos_camera);
+}
+
+void exynos_camera_stop_preview(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_preview_stop(exynos_camera);
+}
+
+int exynos_camera_preview_enabled(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera->preview_enabled;
+}
+
+int exynos_camera_store_meta_data_in_buffers(struct camera_device *dev,
+       int enable)
+{
+       LOGD("%s(%p, %d)", __func__, dev, enable);
+
+       return 0;
+}
+
+int exynos_camera_start_recording(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+void exynos_camera_stop_recording(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+}
+
+int exynos_camera_recording_enabled(struct camera_device *dev)
+{
+       LOGD("%s(%p)", __func__, dev);
+
+       return 0;
+}
+
+void exynos_camera_release_recording_frame(struct camera_device *dev,
+       const void *opaque)
+{
+       LOGD("%s(%p, %p)", __func__, dev, opaque);
+}
+
+int exynos_camera_auto_focus(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_auto_focus_start(exynos_camera);
+}
+
+int exynos_camera_cancel_auto_focus(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       exynos_camera_auto_focus_stop(exynos_camera);
+
+       return 0;
+}
+
+int exynos_camera_take_picture(struct camera_device *dev)
+{
+       struct exynos_camera *exynos_camera;
+
+       LOGD("%s(%p)", __func__, dev);
+
+       if (dev == NULL || dev->priv == NULL)
+               return -EINVAL;
+
+       exynos_camera = (struct exynos_camera *) dev->priv;
+
+       return exynos_camera_picture_start(exynos_camera);
 }
 
 int exynos_camera_cancel_picture(struct camera_device *dev)
index 21e3fa3..165cbec 100644 (file)
@@ -18,6 +18,7 @@
 #include <pthread.h>
 
 #include <linux/videodev2.h>
+#include <videodev2_samsung.h>
 
 #include <hardware/hardware.h>
 #include <hardware/camera.h>
 #define EXYNOS_CAMERA_MAX_PRESETS_COUNT                2
 #define EXYNOS_CAMERA_MAX_V4L2_NODES_COUNT     4
 
+#define EXYNOS_CAMERA_MSG_ENABLED(msg) \
+       (exynos_camera->messages_enabled & msg)
+#define EXYNOS_CAMERA_CALLBACK_DEFINED(cb) \
+       (exynos_camera->callbacks.cb != NULL)
+
 /*
  * Structures
  */
@@ -97,19 +103,38 @@ struct exynos_camera {
        struct exynos_param *params;
 
        struct exynos_camera_callbacks callbacks;
+       int messages_enabled;
 
        int camera_id;
 
        gralloc_module_t *gralloc;
 
+       // Preview
        pthread_t preview_thread;
        pthread_mutex_t preview_mutex;
        pthread_mutex_t preview_lock_mutex;
        int preview_thread_running;
+
        int preview_enabled;
        struct preview_stream_ops *preview_window;
        camera_memory_t *preview_memory;
        int preview_buffers_count;
+
+       // Auto-focus
+       pthread_t auto_focus_thread;
+       pthread_mutex_t auto_focus_mutex;
+       int auto_focus_thread_running;
+
+       int auto_focus_enabled;
+
+       // Picture
+       pthread_t picture_thread;
+       pthread_mutex_t picture_mutex;
+       int picture_thread_running;
+
+       int picture_enabled;
+       camera_memory_t *picture_memory;
+       int picture_buffer_length;
 };
 
 // This is because the linux header uses anonymous union
@@ -201,11 +226,11 @@ int exynos_v4l2_g_fmt_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_i
 int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        int *width, int *height, int *fmt);
 int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int type, int width, int height, int fmt);
+       int type, int width, int height, int fmt, int priv);
 int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int width, int height, int fmt);
+       int width, int height, int fmt, int priv);
 int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int width, int height, int fmt);
+       int width, int height, int fmt, int priv);
 int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        int left, int top, int width, int height);
 int exynos_v4l2_enum_fmt(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
@@ -220,6 +245,8 @@ int exynos_v4l2_s_input(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        int id);
 int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        struct v4l2_ext_control *control, int count);
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int *value);
 int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        int id, int value);
 int exynos_v4l2_s_parm(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
index 4733e43..cef63c5 100644 (file)
@@ -453,7 +453,7 @@ int exynos_v4l2_g_fmt_out(struct exynos_camera *exynos_camera, int exynos_v4l2_i
 }
 
 int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int type, int width, int height, int fmt)
+       int type, int width, int height, int fmt, int priv)
 {
        struct v4l2_format format;
        int rc;
@@ -467,6 +467,7 @@ int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_i
        format.fmt.pix.height = height;
        format.fmt.pix.pixelformat = fmt;
        format.fmt.pix.field = V4L2_FIELD_NONE;
+       format.fmt.pix.priv = priv;
 
        rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_S_FMT, &format);
        if (rc < 0) {
@@ -478,17 +479,17 @@ int exynos_v4l2_s_fmt_pix(struct exynos_camera *exynos_camera, int exynos_v4l2_i
 }
 
 int exynos_v4l2_s_fmt_pix_cap(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int width, int height, int fmt)
+       int width, int height, int fmt, int priv)
 {
        return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-               width, height, fmt);
+               width, height, fmt, priv);
 }
 
 int exynos_v4l2_s_fmt_pix_out(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
-       int width, int height, int fmt)
+       int width, int height, int fmt, int priv)
 {
        return exynos_v4l2_s_fmt_pix(exynos_camera, exynos_v4l2_id, V4L2_BUF_TYPE_VIDEO_OUTPUT,
-               width, height, fmt);
+               width, height, fmt, priv);
 }
 
 int exynos_v4l2_s_fmt_win(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
@@ -625,6 +626,29 @@ int exynos_v4l2_g_ext_ctrls(struct exynos_camera *exynos_camera, int exynos_v4l2
        return 0;
 }
 
+int exynos_v4l2_g_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
+       int id, int *value)
+{
+       struct v4l2_control control;
+       int rc;
+
+       if (exynos_camera == NULL)
+               return -EINVAL;
+
+       control.id = id;
+
+       rc = exynos_v4l2_ioctl(exynos_camera, exynos_v4l2_id, VIDIOC_G_CTRL, &control);
+       if (rc < 0) {
+               LOGE("%s: ioctl failed", __func__);
+               return -1;
+       }
+
+       if (value != NULL)
+               *value = control.value;
+
+       return 0;
+}
+
 int exynos_v4l2_s_ctrl(struct exynos_camera *exynos_camera, int exynos_v4l2_id,
        int id, int value)
 {