Added EXIF, some parts work, some don't, I'm frankly tired of trying so I'll probably...
authorPaul Kocialkowski <contact@paulk.fr>
Thu, 31 Jan 2013 20:59:32 +0000 (21:59 +0100)
committerPaul Kocialkowski <contact@paulk.fr>
Thu, 31 Jan 2013 20:59:32 +0000 (21:59 +0100)
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Android.mk
exynos_camera.c
exynos_camera.h
exynos_exif.c [new file with mode: 0644]
exynos_param.c

index b1a3248..13aa64e 100644 (file)
@@ -6,6 +6,7 @@ include $(CLEAR_VARS)
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_SRC_FILES:= \
        exynos_camera.c \
+       exynos_exif.c \
        exynos_param.c \
        exynos_v4l2.c
 
index ec20a23..8032f62 100644 (file)
@@ -49,6 +49,7 @@ struct exynos_camera_preset exynos_camera_presets_galaxys2[] = {
                .hflip = 0,
                .vflip = 0,
                .picture_format = V4L2_PIX_FMT_JPEG,
+               .focal_length = 400,
                .params = {
                        .preview_size_values = "640x480,720x480,800x480,800x450,352x288,320x240,176x144",
                        .preview_size = "640x480",
@@ -84,6 +85,7 @@ struct exynos_camera_preset exynos_camera_presets_galaxys2[] = {
                .hflip = 0,
                .vflip = 0,
                .picture_format = V4L2_PIX_FMT_YUYV,
+               .focal_length = 278,
                .params = {
                        .preview_size_values = "640x480,352x288,320x240,176x144",
                        .preview_size = "640x480",
@@ -270,6 +272,7 @@ int exynos_camera_params_init(struct exynos_camera *exynos_camera, int id)
        exynos_camera->camera_hflip = exynos_camera->config->presets[id].hflip;
        exynos_camera->camera_vflip = exynos_camera->config->presets[id].vflip;
        exynos_camera->camera_picture_format = exynos_camera->config->presets[id].picture_format;
+       exynos_camera->camera_focal_length = exynos_camera->config->presets[id].focal_length;
 
        // Preview
        exynos_param_string_set(exynos_camera, "preview-size-values",
@@ -360,6 +363,9 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera)
        int jpeg_thumbnail_quality;
        int jpeg_quality;
 
+       char *metering_string;
+       int metering;
+
        char *zoom_supported_string;
        int zoom, max_zoom;
 
@@ -479,6 +485,28 @@ int exynos_camera_params_apply(struct exynos_camera *exynos_camera)
 
        }
 
+       // Metering
+       metering_string = exynos_param_string_get(exynos_camera, "metering");
+       if (metering_string != NULL) {
+               if (strcmp(metering_string, "center") <= 0) {
+                       metering = METERING_CENTER;
+               } else if (strcmp(metering_string, "spot") <= 0) {
+                       metering = METERING_SPOT;
+               } else if (strcmp(metering_string, "matrix") <= 0) {
+                       metering = METERING_MATRIX;
+               } else {
+                       LOGE("%s: Unsupported metering: %s", __func__, metering_string);
+                       metering = METERING_MATRIX;
+               }
+
+               if (metering != exynos_camera->metering) {
+                       exynos_camera->metering = metering;
+                       rc = exynos_v4l2_s_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_METERING, metering);
+                       if (rc < 0)
+                               LOGE("%s: s ctrl failed!", __func__);
+               }
+       }
+
        // Focus
        
 
@@ -961,9 +989,12 @@ void exynos_camera_auto_focus_stop(struct exynos_camera *exynos_camera)
 
 int exynos_camera_picture(struct exynos_camera *exynos_camera)
 {
+       camera_memory_t *data_memory = NULL;
+       camera_memory_t *exif_data_memory = NULL;
        camera_memory_t *picture_data_memory = NULL;
        camera_memory_t *jpeg_thumbnail_data_memory = NULL;
 
+
        int camera_picture_format;
        int picture_width;
        int picture_height;
@@ -990,7 +1021,8 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera)
        void *jpeg_out_buffer;
        int jpeg_out_size;
 
-       int exif_tv, exif_flash, exif_iso, exif_bv;
+       exif_attribute_t exif_attributes;
+       int exif_size = 0;
 
        int index;
        int rc;
@@ -1070,261 +1102,287 @@ int exynos_camera_picture(struct exynos_camera *exynos_camera)
                jpeg_thumbnail_addr = (void *) ((int) exynos_camera->picture_memory->data + 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);
+       // Thumbnail
 
-       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) {
-               if (camera_picture_format == V4L2_PIX_FMT_JPEG && jpeg_thumbnail_addr != NULL && jpeg_thumbnail_size >= 0) {
-                       if (exynos_camera->callbacks.request_memory != NULL) {
-                               jpeg_thumbnail_data_memory =
-                                       exynos_camera->callbacks.request_memory(-1,
-                                               jpeg_thumbnail_size, 1, 0);
-                               if (jpeg_thumbnail_data_memory == NULL) {
-                                       LOGE("%s: thumb memory request failed!", __func__);
-                                       goto error;
-                               }
-                       } else {
-                               LOGE("%s: No memory request function!", __func__);
+       if (camera_picture_format == V4L2_PIX_FMT_JPEG && jpeg_thumbnail_addr != NULL && jpeg_thumbnail_size >= 0) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       jpeg_thumbnail_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_thumbnail_size, 1, 0);
+                       if (jpeg_thumbnail_data_memory == NULL) {
+                               LOGE("%s: thumb memory request failed!", __func__);
                                goto error;
                        }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       goto error;
+               }
 
-                       memcpy(jpeg_thumbnail_data_memory->data, jpeg_thumbnail_addr, jpeg_thumbnail_size);
+               memcpy(jpeg_thumbnail_data_memory->data, jpeg_thumbnail_addr, jpeg_thumbnail_size);
+       } else {
+               jpeg_fd = api_jpeg_encode_init();
+               if (jpeg_fd < 0) {
+                       LOGE("%s: Failed to init JPEG", __func__);
+                       goto error;
+               }
 
-                       exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE,
-                               jpeg_thumbnail_data_memory, 0, NULL, exynos_camera->callbacks.user);
+               switch (camera_picture_format) {
+                       case V4L2_PIX_FMT_RGB565:
+                               jpeg_in_format = RGB_565;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+                       case V4L2_PIX_FMT_NV12:
+                       case V4L2_PIX_FMT_NV21:
+                       case V4L2_PIX_FMT_NV12T:
+                       case V4L2_PIX_FMT_YUV420:
+                               jpeg_in_format = YUV_420;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 1.5);
+                               break;
+                       case V4L2_PIX_FMT_YUYV:
+                       case V4L2_PIX_FMT_UYVY:
+                       case V4L2_PIX_FMT_YUV422P:
+                       default:
+                               jpeg_in_format = YUV_422;
+                               jpeg_out_format = JPEG_422;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+               }
 
-                       jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory);
-               } else {
-                       jpeg_fd = api_jpeg_encode_init();
-                       if (jpeg_fd < 0) {
-                               LOGE("%s: Failed to init JPEG", __func__);
-                               goto error;
-                       }
+               memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
 
-                       switch (camera_picture_format) {
-                               case V4L2_PIX_FMT_RGB565:
-                                       jpeg_in_format = RGB_565;
-                                       jpeg_out_format = JPEG_420;
-                                       jpeg_in_size = (picture_width * picture_height * 2);
-                                       break;
-                               case V4L2_PIX_FMT_NV12:
-                               case V4L2_PIX_FMT_NV21:
-                               case V4L2_PIX_FMT_NV12T:
-                               case V4L2_PIX_FMT_YUV420:
-                                       jpeg_in_format = YUV_420;
-                                       jpeg_out_format = JPEG_420;
-                                       jpeg_in_size = (picture_width * picture_height * 1.5);
-                                       break;
-                               case V4L2_PIX_FMT_YUYV:
-                               case V4L2_PIX_FMT_UYVY:
-                               case V4L2_PIX_FMT_YUV422P:
-                               default:
-                                       jpeg_in_format = YUV_422;
-                                       jpeg_out_format = JPEG_422;
-                                       jpeg_in_size = (picture_width * picture_height * 2);
-                                       break;
-                       }
+               jpeg_enc_params.width = jpeg_thumbnail_width;
+               jpeg_enc_params.height = jpeg_thumbnail_height;
+               jpeg_enc_params.in_fmt = jpeg_in_format;
+               jpeg_enc_params.out_fmt = jpeg_out_format;
 
-                       memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
+               if (jpeg_thumbnail_quality >= 90)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_1;
+               else if (jpeg_thumbnail_quality >= 80)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_2;
+               else if (jpeg_thumbnail_quality >= 70)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_3;
+               else
+                       jpeg_enc_params.quality = QUALITY_LEVEL_4;
 
-                       jpeg_enc_params.width = jpeg_thumbnail_width;
-                       jpeg_enc_params.height = jpeg_thumbnail_height;
-                       jpeg_enc_params.in_fmt = jpeg_in_format;
-                       jpeg_enc_params.out_fmt = jpeg_out_format;
+               api_jpeg_set_encode_param(&jpeg_enc_params);
 
-                       if (jpeg_thumbnail_quality >= 90)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_1;
-                       else if (jpeg_thumbnail_quality >= 80)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_2;
-                       else if (jpeg_thumbnail_quality >= 70)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_3;
-                       else
-                               jpeg_enc_params.quality = QUALITY_LEVEL_4;
+               jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
+               if (jpeg_in_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG in buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       api_jpeg_set_encode_param(&jpeg_enc_params);
+               jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
+               if (jpeg_out_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG out buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
-                       if (jpeg_in_buffer == NULL) {
-                               LOGE("%s: Failed to get JPEG in buffer", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+               memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
 
-                       jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
-                       if (jpeg_out_buffer == NULL) {
-                               LOGE("%s: Failed to get JPEG out buffer", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+               jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
+               if (jpeg_result != JPEG_ENCODE_OK) {
+                       LOGE("%s: Failed to encode JPEG", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
+               jpeg_out_size = jpeg_enc_params.size;
+               if (jpeg_out_size <= 0) {
+                       LOGE("%s: Failed to get JPEG out size", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
-                       if (jpeg_result != JPEG_ENCODE_OK) {
-                               LOGE("%s: Failed to encode JPEG", __func__);
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       jpeg_thumbnail_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_out_size, 1, 0);
+                       if (jpeg_thumbnail_data_memory == NULL) {
+                               LOGE("%s: thumbnail memory request failed!", __func__);
                                api_jpeg_encode_deinit(jpeg_fd);
                                goto error;
                        }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_out_size = jpeg_enc_params.size;
-                       if (jpeg_out_size <= 0) {
-                               LOGE("%s: Failed to get JPEG out size", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+               memcpy(jpeg_thumbnail_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+               jpeg_thumbnail_size = jpeg_out_size;
 
-                       if (exynos_camera->callbacks.request_memory != NULL) {
-                               jpeg_thumbnail_data_memory =
-                                       exynos_camera->callbacks.request_memory(-1,
-                                               jpeg_out_size, 1, 0);
-                               if (jpeg_thumbnail_data_memory == NULL) {
-                                       LOGE("%s: thumbnail memory request failed!", __func__);
-                                       api_jpeg_encode_deinit(jpeg_fd);
-                                       goto error;
-                               }
-                       } else {
-                               LOGE("%s: No memory request function!", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+               api_jpeg_encode_deinit(jpeg_fd);
+       }
 
-                       memcpy(jpeg_thumbnail_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+       // Picture
 
-                       api_jpeg_encode_deinit(jpeg_fd);
+       if (camera_picture_format == V4L2_PIX_FMT_JPEG && picture_addr != NULL && picture_size >= 0) {
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       picture_size, 1, 0);
+                       if (picture_data_memory == NULL) {
+                               LOGE("%s: picture memory request failed!", __func__);
+                               goto error;
+                       }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       goto error;
+               }
 
-                       exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE,
-                               jpeg_thumbnail_data_memory, 0, NULL, exynos_camera->callbacks.user);
+               memcpy(picture_data_memory->data, picture_addr, picture_size);
+       } else {
+               jpeg_fd = api_jpeg_encode_init();
+               if (jpeg_fd < 0) {
+                       LOGE("%s: Failed to init JPEG", __func__);
+                       goto error;
+               }
 
-                       jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory);
+               switch (camera_picture_format) {
+                       case V4L2_PIX_FMT_RGB565:
+                               jpeg_in_format = RGB_565;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
+                       case V4L2_PIX_FMT_NV12:
+                       case V4L2_PIX_FMT_NV21:
+                       case V4L2_PIX_FMT_NV12T:
+                       case V4L2_PIX_FMT_YUV420:
+                               jpeg_in_format = YUV_420;
+                               jpeg_out_format = JPEG_420;
+                               jpeg_in_size = (picture_width * picture_height * 1.5);
+                               break;
+                       case V4L2_PIX_FMT_YUYV:
+                       case V4L2_PIX_FMT_UYVY:
+                       case V4L2_PIX_FMT_YUV422P:
+                       default:
+                               jpeg_in_format = YUV_422;
+                               jpeg_out_format = JPEG_422;
+                               jpeg_in_size = (picture_width * picture_height * 2);
+                               break;
                }
-       }
 
-       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data)) {
-               if (camera_picture_format == V4L2_PIX_FMT_JPEG && picture_addr != NULL && picture_size >= 0) {
-                       if (exynos_camera->callbacks.request_memory != NULL) {
-                               picture_data_memory =
-                                       exynos_camera->callbacks.request_memory(-1,
-                                               picture_size, 1, 0);
-                               if (picture_data_memory == NULL) {
-                                       LOGE("%s: picture memory request failed!", __func__);
-                                       goto error;
-                               }
-                       } else {
-                               LOGE("%s: No memory request function!", __func__);
-                               goto error;
-                       }
+               memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
 
-                       memcpy(picture_data_memory->data, picture_addr, picture_size);
+               jpeg_enc_params.width = picture_width;
+               jpeg_enc_params.height = picture_height;
+               jpeg_enc_params.in_fmt = jpeg_in_format;
+               jpeg_enc_params.out_fmt = jpeg_out_format;
 
-                       exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE,
-                               picture_data_memory, 0, NULL, exynos_camera->callbacks.user);
+               if (jpeg_quality >= 90)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_1;
+               else if (jpeg_quality >= 80)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_2;
+               else if (jpeg_quality >= 70)
+                       jpeg_enc_params.quality = QUALITY_LEVEL_3;
+               else
+                       jpeg_enc_params.quality = QUALITY_LEVEL_4;
 
-                       picture_data_memory->release(picture_data_memory);
-               } else {
-                       jpeg_fd = api_jpeg_encode_init();
-                       if (jpeg_fd < 0) {
-                               LOGE("%s: Failed to init JPEG", __func__);
-                               goto error;
-                       }
+               api_jpeg_set_encode_param(&jpeg_enc_params);
 
-                       switch (camera_picture_format) {
-                               case V4L2_PIX_FMT_RGB565:
-                                       jpeg_in_format = RGB_565;
-                                       jpeg_out_format = JPEG_420;
-                                       jpeg_in_size = (picture_width * picture_height * 2);
-                                       break;
-                               case V4L2_PIX_FMT_NV12:
-                               case V4L2_PIX_FMT_NV21:
-                               case V4L2_PIX_FMT_NV12T:
-                               case V4L2_PIX_FMT_YUV420:
-                                       jpeg_in_format = YUV_420;
-                                       jpeg_out_format = JPEG_420;
-                                       jpeg_in_size = (picture_width * picture_height * 1.5);
-                                       break;
-                               case V4L2_PIX_FMT_YUYV:
-                               case V4L2_PIX_FMT_UYVY:
-                               case V4L2_PIX_FMT_YUV422P:
-                               default:
-                                       jpeg_in_format = YUV_422;
-                                       jpeg_out_format = JPEG_422;
-                                       jpeg_in_size = (picture_width * picture_height * 2);
-                                       break;
-                       }
+               jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
+               if (jpeg_in_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG in buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       memset(&jpeg_enc_params, 0, sizeof(jpeg_enc_params));
+               jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
+               if (jpeg_out_buffer == NULL) {
+                       LOGE("%s: Failed to get JPEG out buffer", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_enc_params.width = picture_width;
-                       jpeg_enc_params.height = picture_height;
-                       jpeg_enc_params.in_fmt = jpeg_in_format;
-                       jpeg_enc_params.out_fmt = jpeg_out_format;
+               memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
 
-                       if (jpeg_quality >= 90)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_1;
-                       else if (jpeg_quality >= 80)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_2;
-                       else if (jpeg_quality >= 70)
-                               jpeg_enc_params.quality = QUALITY_LEVEL_3;
-                       else
-                               jpeg_enc_params.quality = QUALITY_LEVEL_4;
+               jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
+               if (jpeg_result != JPEG_ENCODE_OK) {
+                       LOGE("%s: Failed to encode JPEG", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       api_jpeg_set_encode_param(&jpeg_enc_params);
+               jpeg_out_size = jpeg_enc_params.size;
+               if (jpeg_out_size <= 0) {
+                       LOGE("%s: Failed to get JPEG out size", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_in_buffer = api_jpeg_get_encode_in_buf(jpeg_fd, jpeg_in_size);
-                       if (jpeg_in_buffer == NULL) {
-                               LOGE("%s: Failed to get JPEG in buffer", __func__);
+               if (exynos_camera->callbacks.request_memory != NULL) {
+                       picture_data_memory =
+                               exynos_camera->callbacks.request_memory(-1,
+                                       jpeg_out_size, 1, 0);
+                       if (picture_data_memory == NULL) {
+                               LOGE("%s: picture memory request failed!", __func__);
                                api_jpeg_encode_deinit(jpeg_fd);
                                goto error;
                        }
+               } else {
+                       LOGE("%s: No memory request function!", __func__);
+                       api_jpeg_encode_deinit(jpeg_fd);
+                       goto error;
+               }
 
-                       jpeg_out_buffer = api_jpeg_get_encode_out_buf(jpeg_fd);
-                       if (jpeg_out_buffer == NULL) {
-                               LOGE("%s: Failed to get JPEG out buffer", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+               memcpy(picture_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+               picture_size = jpeg_out_size;
 
-                       memcpy(jpeg_in_buffer, exynos_camera->picture_memory->data, jpeg_in_size);
+               api_jpeg_encode_deinit(jpeg_fd);
+       }
 
-                       jpeg_result = api_jpeg_encode_exe(jpeg_fd, &jpeg_enc_params);
-                       if (jpeg_result != JPEG_ENCODE_OK) {
-                               LOGE("%s: Failed to encode JPEG", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+       // EXIF
 
-                       jpeg_out_size = jpeg_enc_params.size;
-                       if (jpeg_out_size <= 0) {
-                               LOGE("%s: Failed to get JPEG out size", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+       memset(&exif_attributes, 0, sizeof(exif_attributes));
+       exynos_exif_attributes_create_static(exynos_camera, &exif_attributes);
+       exynos_exif_attributes_create_params(exynos_camera, &exif_attributes);
 
-                       if (exynos_camera->callbacks.request_memory != NULL) {
-                               picture_data_memory =
-                                       exynos_camera->callbacks.request_memory(-1,
-                                               jpeg_out_size, 1, 0);
-                               if (picture_data_memory == NULL) {
-                                       LOGE("%s: picture memory request failed!", __func__);
-                                       api_jpeg_encode_deinit(jpeg_fd);
-                                       goto error;
-                               }
-                       } else {
-                               LOGE("%s: No memory request function!", __func__);
-                               api_jpeg_encode_deinit(jpeg_fd);
-                               goto error;
-                       }
+       rc = exynos_exif_create(exynos_camera, &exif_attributes,
+               picture_data_memory, picture_size,
+               jpeg_thumbnail_data_memory, jpeg_thumbnail_size,
+               &exif_data_memory);
+if (rc == -EINVAL) {
+LOGE("OMG ITS EINVALL (%p %p %p %d %d)", picture_data_memory, jpeg_thumbnail_data_memory, &exif_data_memory, picture_size, jpeg_thumbnail_size);
+}
+       if (rc < 0) {
+               LOGE("%s: EXIF create failed!", __func__);
+               goto error;
+       }
+
+/*
+exif_data_memory
+*/
+       // Callbacks
 
-                       memcpy(picture_data_memory->data, jpeg_out_buffer, jpeg_out_size);
+       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);
 
-                       api_jpeg_encode_deinit(jpeg_fd);
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_RAW_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) &&
+               jpeg_thumbnail_data_memory != NULL)
+               exynos_camera->callbacks.data(CAMERA_MSG_RAW_IMAGE,
+                       jpeg_thumbnail_data_memory, 0, NULL, exynos_camera->callbacks.user);
 
-                       exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE,
-                               picture_data_memory, 0, NULL, exynos_camera->callbacks.user);
+       if (EXYNOS_CAMERA_MSG_ENABLED(CAMERA_MSG_COMPRESSED_IMAGE) && EXYNOS_CAMERA_CALLBACK_DEFINED(data) &&
+               exif_data_memory != NULL)
+               exynos_camera->callbacks.data(CAMERA_MSG_COMPRESSED_IMAGE,
+                       exif_data_memory, 0, NULL, exynos_camera->callbacks.user);
 
-                       picture_data_memory->release(picture_data_memory);
-               }
-       }
+       // Release memory
+
+       if (jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_data_memory->release != NULL)
+               jpeg_thumbnail_data_memory->release(jpeg_thumbnail_data_memory);
+
+       if (picture_data_memory != NULL && picture_data_memory->release != NULL)
+               picture_data_memory->release(picture_data_memory);
+
+       if (exif_data_memory != NULL && exif_data_memory->release != NULL)
+               exif_data_memory->release(exif_data_memory);
 
        return 0;
 
index a1fbce1..bc348cc 100644 (file)
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
 #include <pthread.h>
 
 #include <linux/videodev2.h>
 #include <videodev2_samsung.h>
 
+#include <Exif.h>
+
 #include <hardware/hardware.h>
 #include <hardware/camera.h>
 
@@ -101,6 +106,7 @@ struct exynos_camera_preset {
        int vflip;
 
        int picture_format;
+       int focal_length;
 
        struct exynos_camera_params params;
 };
@@ -169,6 +175,7 @@ struct exynos_camera {
        int camera_hflip;
        int camera_vflip;
        int camera_picture_format;
+       int camera_focal_length;
 
        // Params
        int preview_width;
@@ -184,6 +191,7 @@ struct exynos_camera {
        int jpeg_thumbnail_quality;
        int jpeg_quality;
        int zoom;
+       int metering;
        int focus_object_x;
        int focus_object_y;
 };
@@ -201,6 +209,21 @@ struct exynos_v4l2_ext_control {
 } __attribute__ ((packed));
 
 /*
+ * EXIF
+ */
+
+int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes);
+int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes);
+
+int exynos_exif_create(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes,
+       camera_memory_t *picture_data_memory, int picture_size,
+       camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size,
+       camera_memory_t **exif_data_memory_p);
+
+/*
  * Param
  */
 
diff --git a/exynos_exif.c b/exynos_exif.c
new file mode 100644 (file)
index 0000000..2a16c4b
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * Copyright (C) 2013 Paul Kocialkowski
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include <Exif.h>
+
+#define LOG_TAG "exynos_camera"
+#include <utils/Log.h>
+#include <cutils/properties.h>
+
+#include "exynos_camera.h"
+
+int exynos_exif_attributes_create_static(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       unsigned char gps_version[] = { 0x02, 0x02, 0x00, 0x00 };
+       char property[PROPERTY_VALUE_MAX];
+       uint32_t av;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       // Device
+       property_get("ro.product.brand", property, EXIF_DEF_MAKER);
+       strncpy((char *) exif_attributes->maker, property,
+               sizeof(exif_attributes->maker) - 1);
+       exif_attributes->maker[sizeof(exif_attributes->maker) - 1] = '\0';
+
+       property_get("ro.product.model", property, EXIF_DEF_MODEL);
+       strncpy((char *) exif_attributes->model, property,
+               sizeof(exif_attributes->model) - 1);
+       exif_attributes->model[sizeof(exif_attributes->model) - 1] = '\0';
+
+       property_get("ro.build.id", property, EXIF_DEF_SOFTWARE);
+       strncpy((char *) exif_attributes->software, property,
+               sizeof(exif_attributes->software) - 1);
+       exif_attributes->software[sizeof(exif_attributes->software) - 1] = '\0';
+
+       exif_attributes->ycbcr_positioning = EXIF_DEF_YCBCR_POSITIONING;
+
+       exif_attributes->fnumber.num = EXIF_DEF_FNUMBER_NUM;
+       exif_attributes->fnumber.den = EXIF_DEF_FNUMBER_DEN;
+
+       exif_attributes->exposure_program = EXIF_DEF_EXPOSURE_PROGRAM;
+
+       memcpy(exif_attributes->exif_version, EXIF_DEF_EXIF_VERSION,
+               sizeof(exif_attributes->exif_version));
+
+       av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num /
+               exif_attributes->fnumber.den);
+       exif_attributes->aperture.num = av * EXIF_DEF_APEX_DEN;
+       exif_attributes->aperture.den = EXIF_DEF_APEX_DEN;
+       exif_attributes->max_aperture.num = av * EXIF_DEF_APEX_DEN;
+       exif_attributes->max_aperture.den = EXIF_DEF_APEX_DEN;
+
+       strcpy((char *) exif_attributes->user_comment, EXIF_DEF_USERCOMMENTS);
+       exif_attributes->color_space = EXIF_DEF_COLOR_SPACE;
+       exif_attributes->exposure_mode = EXIF_DEF_EXPOSURE_MODE;
+
+       // GPS version
+       memcpy(exif_attributes->gps_version_id, gps_version, sizeof(gps_version));
+
+       exif_attributes->compression_scheme = EXIF_DEF_COMPRESSION;
+       exif_attributes->x_resolution.num = EXIF_DEF_RESOLUTION_NUM;
+       exif_attributes->x_resolution.den = EXIF_DEF_RESOLUTION_DEN;
+       exif_attributes->y_resolution.num = EXIF_DEF_RESOLUTION_NUM;
+       exif_attributes->y_resolution.den = EXIF_DEF_RESOLUTION_DEN;
+       exif_attributes->resolution_unit = EXIF_DEF_RESOLUTION_UNIT;
+
+       return 0;
+}
+
+int exynos_exif_attributes_create_gps(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       float gps_latitude_float, gps_longitude_float, gps_altitude_float;
+       int gps_timestamp_int;
+       char *gps_processing_method_string;
+       long gps_latitude, gps_longitude;
+       long gps_altitude, gps_timestamp;
+       double gps_latitude_abs, gps_longitude_abs, gps_altitude_abs;
+
+       struct tm time_info;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       gps_latitude_float = exynos_param_float_get(exynos_camera, "gps-latitude");
+       gps_longitude_float = exynos_param_float_get(exynos_camera, "gps-longitude");
+       gps_altitude_float = exynos_param_float_get(exynos_camera, "gps-altitude");
+       if (gps_altitude_float == -1)
+               gps_altitude_float = (float) exynos_param_int_get(exynos_camera, "gps-altitude");
+       gps_timestamp_int = exynos_param_int_get(exynos_camera, "gps-timestamp");
+       gps_processing_method_string = exynos_param_string_get(exynos_camera, "gps-processing-method");
+
+       if (gps_latitude_float == -1 || gps_longitude_float == -1 ||
+               gps_altitude_float == -1 || gps_timestamp_int <= 0 ||
+               gps_processing_method_string == NULL) {
+               exif_attributes->enableGps = false;
+               return 0;
+       }
+
+       gps_latitude = (long) (gps_latitude_float * 10000) / 1;
+       gps_longitude = (long) (gps_longitude_float * 10000) / 1;
+       gps_altitude = (long) (gps_altitude_float * 100) / 1;
+       gps_timestamp = (long) gps_timestamp_int;
+
+       if (gps_latitude == 0 || gps_longitude == 0) {
+               exif_attributes->enableGps = false;
+               return 0;
+       }
+
+       if (gps_latitude > 0)
+               strcpy((char *) exif_attributes->gps_latitude_ref, "N");
+       else
+               strcpy((char *) exif_attributes->gps_latitude_ref, "S");
+
+       if (gps_longitude > 0)
+               strcpy((char *) exif_attributes->gps_longitude_ref, "E");
+       else
+               strcpy((char *) exif_attributes->gps_longitude_ref, "W");
+
+       if (gps_altitude > 0)
+               exif_attributes->gps_altitude_ref = 0;
+       else
+               exif_attributes->gps_altitude_ref = 1;
+
+
+       gps_latitude_abs = fabs(gps_latitude / 10000.0);
+       gps_longitude_abs = fabs(gps_longitude / 10000.0);
+       gps_altitude_abs = fabs(gps_altitude / 100.0);
+
+       exif_attributes->gps_latitude[0].num = (uint32_t) gps_latitude_abs;
+       exif_attributes->gps_latitude[0].den = 1;
+       exif_attributes->gps_latitude[1].num = 0;
+       exif_attributes->gps_latitude[1].den = 1;
+       exif_attributes->gps_latitude[2].num = 0;
+       exif_attributes->gps_latitude[2].den = 1;
+
+       exif_attributes->gps_longitude[0].num = (uint32_t) gps_longitude_abs;
+       exif_attributes->gps_longitude[0].den = 1;
+       exif_attributes->gps_longitude[1].num = 0;
+       exif_attributes->gps_longitude[1].den = 1;
+       exif_attributes->gps_longitude[2].num = 0;
+       exif_attributes->gps_longitude[2].den = 1;
+
+       exif_attributes->gps_altitude.num = (uint32_t) gps_altitude_abs;
+       exif_attributes->gps_altitude.den = 1;
+
+       gmtime_r(&gps_timestamp, &time_info);
+
+       exif_attributes->gps_timestamp[0].num = time_info.tm_hour;
+       exif_attributes->gps_timestamp[0].den = 1;
+       exif_attributes->gps_timestamp[1].num = time_info.tm_min;
+       exif_attributes->gps_timestamp[1].den = 1;
+       exif_attributes->gps_timestamp[2].num = time_info.tm_sec;
+       exif_attributes->gps_timestamp[2].den = 1;
+       snprintf((char *) exif_attributes->gps_datestamp, sizeof(exif_attributes->gps_datestamp),
+               "%04d:%02d:%02d", time_info.tm_year + 1900, time_info.tm_mon + 1, time_info.tm_mday);
+
+       exif_attributes->enableGps = true;
+
+       return 0;
+}
+
+int exynos_exif_attributes_create_params(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes)
+{
+       uint32_t av, tv, bv, sv, ev;
+       time_t time_data;
+       struct tm *time_info;
+       int rotation;
+       int shutter_speed;
+       int exposure_time;
+       int iso_speed;
+       int exposure;
+
+       int rc;
+
+       if (exynos_camera == NULL || exif_attributes == NULL)
+               return -EINVAL;
+
+       // Picture size
+       exif_attributes->width = exynos_camera->picture_width;
+       exif_attributes->height = exynos_camera->picture_height;
+
+       // Thumbnail
+       exif_attributes->widthThumb = exynos_camera->jpeg_thumbnail_width;
+       exif_attributes->heightThumb = exynos_camera->jpeg_thumbnail_height;
+       exif_attributes->enableThumb = true;
+
+       // Orientation
+       rotation = exynos_param_int_get(exynos_camera, "rotation");
+       switch (rotation) {
+               case 90:
+                       exif_attributes->orientation = EXIF_ORIENTATION_90;
+                       break;
+               case 180:
+                       exif_attributes->orientation = EXIF_ORIENTATION_180;
+                       break;
+               case 270:
+                       exif_attributes->orientation = EXIF_ORIENTATION_270;
+                       break;
+               case 0:
+               default:
+                       exif_attributes->orientation = EXIF_ORIENTATION_UP;
+                       break;
+       }
+
+       // Time
+       time(&time_data);
+       time_info = localtime(&time_data);
+       strftime((char *) exif_attributes->date_time, sizeof(exif_attributes->date_time),
+               "%Y:%m:%d %H:%M:%S", time_info);
+
+       exif_attributes->focal_length.num = exynos_camera->camera_focal_length;
+       exif_attributes->focal_length.den = EXIF_DEF_FOCAL_LEN_DEN;
+
+       shutter_speed = 100;
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_TV,
+               &shutter_speed);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->shutter_speed.num = 1;
+       exif_attributes->shutter_speed.den = shutter_speed;
+
+       exposure_time = shutter_speed;
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EXPTIME,
+               &exposure_time);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->exposure_time.num = 1;
+       exif_attributes->exposure_time.den = exposure_time;
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_ISO,
+               &iso_speed);
+       if (rc < 0)
+               LOGE("%s: g ctrl failed!", __func__);
+
+       exif_attributes->iso_speed_rating = iso_speed;
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_BV,
+               (int *) &bv);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               goto bv_static;
+       }
+
+       rc = exynos_v4l2_g_ctrl(exynos_camera, 0, V4L2_CID_CAMERA_EXIF_EBV,
+               (int *) &ev);
+       if (rc < 0) {
+               LOGE("%s: g ctrl failed!", __func__);
+               goto bv_static;
+       }
+
+       goto bv_ioctl;
+
+bv_static:
+       exposure = exynos_param_int_get(exynos_camera, "exposure-compensation");
+       if (exposure < 0)
+               exposure = IS_EXPOSURE_DEFAULT;
+
+       av = APEX_FNUM_TO_APERTURE((double) exif_attributes->fnumber.num /
+               exif_attributes->fnumber.den);
+       tv = APEX_EXPOSURE_TO_SHUTTER((double) exif_attributes->exposure_time.num /
+               exif_attributes->exposure_time.den);
+       sv = APEX_ISO_TO_FILMSENSITIVITY(iso_speed);
+       bv = av + tv - sv;
+       ev = exposure - IS_EXPOSURE_DEFAULT;
+
+bv_ioctl:
+       exif_attributes->brightness.num = bv * EXIF_DEF_APEX_DEN;
+       exif_attributes->brightness.den = EXIF_DEF_APEX_DEN;
+
+       /* TODO
+    if (m_params->scene_mode == SCENE_MODE_BEACH_SNOW) {
+       mExifInfo.exposure_bias.num = EXIF_DEF_APEX_DEN;
+       mExifInfo.exposure_bias.den = EXIF_DEF_APEX_DEN;
+    } else {
+       mExifInfo.exposure_bias.num = ev*EXIF_DEF_APEX_DEN;
+       mExifInfo.exposure_bias.den = EXIF_DEF_APEX_DEN;
+    }
+       */
+
+       switch (exynos_camera->metering) {
+               case METERING_CENTER:
+                       exif_attributes->metering_mode = EXIF_METERING_CENTER;
+                       break;
+               case METERING_MATRIX:
+                       exif_attributes->metering_mode = EXIF_METERING_AVERAGE;
+                       break;
+               case METERING_SPOT:
+                       exif_attributes->metering_mode = EXIF_METERING_SPOT;
+                       break;
+               default:
+                       exif_attributes->metering_mode = EXIF_METERING_AVERAGE;
+                       break;
+       }
+
+       /* TODO
+    int flash = m_params->flash_mode;
+    //int flash = fimc_v4l2_g_ctrl(m_cam_fd, V4L2_CID_CAMERA_GET_FLASH_ONOFF);
+    if (flash < 0)
+       mExifInfo.flash = EXIF_DEF_FLASH;
+    else
+       mExifInfo.flash = flash;
+
+    //3 White Balance
+    if (m_params->white_balance == WHITE_BALANCE_AUTO || m_params->white_balance == IS_AWB_AUTO)
+       mExifInfo.white_balance = EXIF_WB_AUTO;
+    else
+       mExifInfo.white_balance = EXIF_WB_MANUAL;
+    //3 Scene Capture Type
+    switch (m_params->scene_mode) {
+    case SCENE_MODE_PORTRAIT:
+       mExifInfo.scene_capture_type = EXIF_SCENE_PORTRAIT;
+       break;
+    case SCENE_MODE_LANDSCAPE:
+       mExifInfo.scene_capture_type = EXIF_SCENE_LANDSCAPE;
+       break;
+    case SCENE_MODE_NIGHTSHOT:
+       mExifInfo.scene_capture_type = EXIF_SCENE_NIGHT;
+       break;
+    default:
+       mExifInfo.scene_capture_type = EXIF_SCENE_STANDARD;
+       break;
+    }
+       */
+
+       rc = exynos_exif_attributes_create_gps(exynos_camera, exif_attributes);
+       if (rc < 0) {
+               LOGE("%s: Failed to create GPS attributes", __func__);
+               return -1;
+       }
+
+       return 0;
+}
+
+int exynos_exif_write_data(void *exif_data, unsigned short tag,
+       unsigned short type, unsigned int count, int *offset, void *start, 
+       void *data, int length)
+{
+       unsigned char *pointer;
+       int size;
+
+       if (exif_data == NULL || data == NULL || length <= 0)
+               return -EINVAL;
+
+       pointer = (unsigned char *) exif_data;
+
+       memcpy(pointer, &tag, sizeof(tag));
+       pointer += sizeof(tag);
+
+       memcpy(pointer, &type, sizeof(type));
+       pointer += sizeof(type);
+
+       memcpy(pointer, &count, sizeof(count));
+       pointer += sizeof(count);
+
+       if (offset != NULL && start != NULL) {
+               memcpy(pointer, offset, sizeof(*offset));
+               pointer += sizeof(*offset);
+
+               memcpy((void *) ((int) start + *offset), data, count * length);
+               *offset += count * length;              
+       } else {
+               memcpy(pointer, data, count * length);
+               pointer += count * length;
+       }
+
+       size = (int) pointer - (int) exif_data;
+       return size;
+}
+
+// fix respective count/length
+
+int exynos_exif_create(struct exynos_camera *exynos_camera,
+       exif_attribute_t *exif_attributes,
+       camera_memory_t *picture_data_memory, int picture_size,
+       camera_memory_t *jpeg_thumbnail_data_memory, int jpeg_thumbnail_size,
+       camera_memory_t **exif_data_memory_p)
+{
+       // Markers
+       unsigned char exif_app1_marker[] = { 0xff, 0xe1 };
+       unsigned char exif_app1_size[] = { 0x00, 0x00 };
+       unsigned char exif_marker[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
+       unsigned char tiff_marker[] = { 0x49, 0x49, 0x2A, 0x00, 0x08, 0x00, 0x00, 0x00 };
+
+       unsigned char user_comment_code[] = { 0x00, 0x00, 0x00, 0x49, 0x49, 0x43, 0x53, 0x41 };
+       unsigned char exif_ascii_prefix[] = { 0x41, 0x53, 0x43, 0x49, 0x49, 0x0, 0x0, 0x0 };
+
+       camera_memory_t *exif_data_memory;
+       void *exif_data;
+       int exif_data_size;
+       int exif_size;
+
+       void *exif_ifd_data_start, *exif_ifd_start, *exif_ifd_gps, *exif_ifd_thumb;
+
+       void *exif_thumb_data;
+       unsigned int exif_thumb_size;
+
+       unsigned char *pointer;
+       unsigned int offset;
+       void *data;
+       int count;
+
+       unsigned int value;
+
+       if (exynos_camera == NULL || exif_attributes == NULL ||
+               picture_data_memory == NULL || picture_size <= 0 ||
+               jpeg_thumbnail_data_memory == NULL || jpeg_thumbnail_size <= 0 ||
+               exif_data_memory_p == NULL)
+               return -EINVAL;
+
+       exif_data_size = EXIF_FILE_SIZE + picture_size + jpeg_thumbnail_size;
+
+       if (exynos_camera->callbacks.request_memory != NULL) {
+               exif_data_memory = exynos_camera->callbacks.request_memory(-1,
+                       exif_data_size, 1, 0);
+               if (exif_data_memory == NULL) {
+                       LOGE("%s: exif memory request failed!", __func__);
+                       goto error;
+               }
+       } else {
+               LOGE("%s: No memory request function!", __func__);
+               goto error;
+       }
+
+       *exif_data_memory_p = exif_data_memory;
+
+       exif_data = exif_data_memory->data;
+       pointer = (unsigned char *) exif_data;
+
+       memset(exif_data, 0, exif_data_size);
+
+       // Copy the first two bytes of the JPEG picture
+       memcpy(pointer, picture_data_memory->data, 2);
+       pointer += 2;
+
+       exif_ifd_data_start = (void *) pointer;
+
+       // Skip 4 bytes for APP1 marker
+       pointer += 4;
+
+       // Copy EXIF marker
+       memcpy(pointer, exif_marker, sizeof(exif_marker));
+       pointer += sizeof(exif_marker);
+
+       // Copy TIFF marker
+       memcpy(pointer, tiff_marker, sizeof(tiff_marker));
+       exif_ifd_start = (void *) pointer;
+       pointer += sizeof(tiff_marker);
+
+       if (exif_attributes->enableGps)
+               value = NUM_0TH_IFD_TIFF;
+       else
+               value = NUM_0TH_IFD_TIFF - 1;
+
+       memcpy(pointer, &value, NUM_SIZE);
+       pointer += NUM_SIZE;
+
+       offset = 8 + NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE;
+
+       // Write EXIF data
+       count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MAKE,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->maker) + 1,
+               &offset, exif_ifd_start, &exif_attributes->maker, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MODEL,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->model) + 1,
+               &offset, exif_ifd_start, &exif_attributes->model, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SOFTWARE,
+               EXIF_TYPE_ASCII, strlen((char *) exif_attributes->software) + 1,
+               &offset, exif_ifd_start, &exif_attributes->software, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_YCBCR_POSITIONING,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->ycbcr_positioning, sizeof(exif_attributes->ycbcr_positioning));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_IFD_POINTER,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+       pointer += count;
+
+       if (exif_attributes->enableGps) {
+               exif_ifd_gps = (void *) pointer;
+               pointer += IFD_SIZE;
+       }
+
+       exif_ifd_thumb = (void *) pointer;
+       pointer += OFFSET_SIZE;
+
+       pointer = (unsigned char *) exif_ifd_start;
+       pointer += offset;
+
+       value = NUM_0TH_IFD_EXIF;
+       memcpy(pointer, &value, NUM_SIZE);
+       pointer += NUM_SIZE;
+
+       offset += NUM_SIZE + NUM_0TH_IFD_EXIF * IFD_SIZE + OFFSET_SIZE;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_TIME,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_time, sizeof(exif_attributes->exposure_time));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FNUMBER,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->fnumber, sizeof(exif_attributes->fnumber));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_PROGRAM,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->exposure_program, sizeof(exif_attributes->exposure_program));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_ISO_SPEED_RATING,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->iso_speed_rating, sizeof(exif_attributes->iso_speed_rating));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXIF_VERSION,
+               EXIF_TYPE_UNDEFINED, 1, NULL, NULL, &exif_attributes->exif_version, sizeof(exif_attributes->exif_version));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_ORG,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_DATE_TIME_DIGITIZE,
+               EXIF_TYPE_ASCII, 20, &offset, exif_ifd_start, &exif_attributes->date_time, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SHUTTER_SPEED,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->shutter_speed, sizeof(exif_attributes->shutter_speed));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_APERTURE,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->aperture, sizeof(exif_attributes->shutter_speed));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_BRIGHTNESS,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->brightness, sizeof(exif_attributes->brightness));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_BIAS,
+               EXIF_TYPE_SRATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->exposure_bias, sizeof(exif_attributes->exposure_bias));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_MAX_APERTURE,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->max_aperture, sizeof(exif_attributes->max_aperture));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_METERING_MODE,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->metering_mode, sizeof(exif_attributes->metering_mode));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FLASH,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->flash, sizeof(exif_attributes->flash));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_FOCAL_LENGTH,
+               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->focal_length, sizeof(exif_attributes->focal_length));
+       pointer += count;
+
+       value = strlen((char *) exif_attributes->user_comment) + 1;
+       memmove(exif_attributes->user_comment + sizeof(user_comment_code), exif_attributes->user_comment, value);
+       memcpy(exif_attributes->user_comment, user_comment_code, sizeof(user_comment_code));
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_USER_COMMENT,
+               EXIF_TYPE_UNDEFINED, value + sizeof(user_comment_code), &offset, exif_ifd_start, &exif_attributes->user_comment, sizeof(char));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_COLOR_SPACE,
+               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->color_space, sizeof(exif_attributes->color_space));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_X_DIMENSION,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->width, sizeof(exif_attributes->width));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_PIXEL_Y_DIMENSION,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->height, sizeof(exif_attributes->height));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_EXPOSURE_MODE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->exposure_mode, sizeof(exif_attributes->exposure_mode));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_WHITE_BALANCE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->white_balance, sizeof(exif_attributes->white_balance));
+       pointer += count;
+
+       count = exynos_exif_write_data(pointer, EXIF_TAG_SCENCE_CAPTURE_TYPE,
+               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->scene_capture_type, sizeof(exif_attributes->scene_capture_type));
+       pointer += count;
+
+       value = 0;
+       memcpy(pointer, &value, OFFSET_SIZE);
+       pointer += OFFSET_SIZE;
+
+       // GPS
+       if (exif_attributes->enableGps) {
+               pointer = (unsigned char *) exif_ifd_gps;
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_IFD_POINTER,
+                       EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+
+               pointer = exif_ifd_start + offset;
+
+               if (exif_attributes->gps_processing_method[0] == 0)
+                       value = NUM_0TH_IFD_GPS - 1;
+               else
+                       value = NUM_0TH_IFD_GPS;
+
+               memcpy(pointer, &value, NUM_SIZE);
+               pointer += NUM_SIZE;
+
+               offset += NUM_SIZE + value * IFD_SIZE + OFFSET_SIZE;
+               
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_VERSION_ID,
+                       EXIF_TYPE_LONG, 4, NULL, NULL, &exif_attributes->gps_version_id, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE_REF,
+                       EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_latitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LATITUDE,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_latitude, sizeof(exif_attributes->gps_latitude[0]));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE_REF,
+                       EXIF_TYPE_ASCII, 2, NULL, NULL, &exif_attributes->gps_longitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_LONGITUDE,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_longitude, sizeof(exif_attributes->gps_longitude[0]));
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE_REF,
+                       EXIF_TYPE_BYTE, 1, NULL, NULL, &exif_attributes->gps_altitude_ref, 1);
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_ALTITUDE,
+                       EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->gps_altitude, sizeof(exif_attributes->gps_altitude));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_TIMESTAMP,
+                       EXIF_TYPE_RATIONAL, 3, &offset, exif_ifd_start, &exif_attributes->gps_timestamp, sizeof(exif_attributes->gps_timestamp[0]));
+               pointer += count;
+
+               value = strlen((char *) exif_attributes->gps_processing_method);
+               if (value > 0) {
+                       value = value > 100 ? 100 : value;
+
+                       data = calloc(1, value + sizeof(exif_ascii_prefix));
+                       memcpy(data, &exif_ascii_prefix, sizeof(exif_ascii_prefix));
+                       memcpy((void *) ((int) data + (int) sizeof(exif_ascii_prefix)), exif_attributes->gps_processing_method, value);
+
+                       count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_PROCESSING_METHOD,
+                               EXIF_TYPE_UNDEFINED, value + sizeof(exif_ascii_prefix), &offset, exif_ifd_start, data, 1);
+                       pointer += count;
+
+                       free(data);
+               }
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_GPS_DATESTAMP,
+                               EXIF_TYPE_ASCII, 11, &offset, exif_ifd_start, &exif_attributes->gps_datestamp, 1);
+               pointer += count;
+
+               value = 0;
+               memcpy(pointer, &value, OFFSET_SIZE);
+               pointer += OFFSET_SIZE;
+       }
+
+       if (exif_attributes->enableThumb && jpeg_thumbnail_data_memory != NULL && jpeg_thumbnail_size > 0) {
+               exif_thumb_size = (unsigned int) jpeg_thumbnail_size;
+               exif_thumb_data = (void *) jpeg_thumbnail_data_memory->data;
+
+               value = offset;
+               memcpy(exif_ifd_thumb, &value, OFFSET_SIZE);
+
+               pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset);
+
+               value = NUM_1TH_IFD_TIFF;
+               memcpy(pointer, &value, NUM_SIZE);
+               pointer += NUM_SIZE;
+
+               offset += NUM_SIZE + NUM_1TH_IFD_TIFF * IFD_SIZE + OFFSET_SIZE;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_WIDTH,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->widthThumb, sizeof(exif_attributes->widthThumb));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_IMAGE_HEIGHT,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->heightThumb, sizeof(exif_attributes->heightThumb));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_COMPRESSION_SCHEME,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_attributes->compression_scheme, sizeof(exif_attributes->compression_scheme));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_ORIENTATION,
+                               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->orientation, sizeof(exif_attributes->orientation));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_X_RESOLUTION,
+                               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->x_resolution, sizeof(exif_attributes->x_resolution));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_Y_RESOLUTION,
+                               EXIF_TYPE_RATIONAL, 1, &offset, exif_ifd_start, &exif_attributes->y_resolution, sizeof(exif_attributes->y_resolution));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_RESOLUTION_UNIT,
+                               EXIF_TYPE_SHORT, 1, NULL, NULL, &exif_attributes->resolution_unit, sizeof(exif_attributes->resolution_unit));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &offset, sizeof(offset));
+               pointer += count;
+
+               count = exynos_exif_write_data(pointer, EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LEN,
+                               EXIF_TYPE_LONG, 1, NULL, NULL, &exif_thumb_size, sizeof(exif_thumb_size));
+               pointer += count;
+
+               value = 0;
+               memcpy(pointer, &value, OFFSET_SIZE);
+
+               pointer = (unsigned char *) ((int) exif_ifd_start + (int) offset);
+
+               memcpy(pointer, exif_thumb_data, exif_thumb_size);
+               offset += exif_thumb_size;
+       } else {
+               value = 0;
+               memcpy(exif_ifd_thumb, &value, OFFSET_SIZE);
+               
+       }
+
+       pointer = (unsigned char *) exif_ifd_data_start;
+
+       memcpy(pointer, exif_app1_marker, sizeof(exif_app1_marker));
+       pointer += sizeof(exif_app1_marker);
+
+       exif_size = offset + 10;
+       value = exif_size - 2;
+       exif_app1_size[0] = (value >> 8) & 0xff;
+       exif_app1_size[1] = value & 0xff;
+
+       memcpy(pointer, exif_app1_size, sizeof(exif_app1_size));
+
+       // Add the picture after the EXIF data
+       memcpy((void *) ((int) exif_data + exif_size), picture_data_memory->data, picture_size);
+
+       return 0;
+
+error:
+       if (exif_data_memory != NULL && exif_data_memory->release != NULL)
+               exif_data_memory->release(exif_data_memory);
+
+       *exif_data_memory_p = NULL;
+
+       return -1;
+}
index 91da359..17b0450 100644 (file)
@@ -172,7 +172,6 @@ int exynos_param_data_set(struct exynos_camera *exynos_camera, char *key,
        if (exynos_camera == NULL || key == NULL)
                return -EINVAL;
 
-
        if (strchr(key, '=') || strchr(key, ';'))
                return -EINVAL;
 
@@ -469,7 +468,7 @@ int exynos_params_string_set(struct exynos_camera *exynos_camera, char *string)
                if (isdigit(k[0]) || k[0] == '-') {
                        type = EXYNOS_PARAM_INT;
 
-                       for (i=0 ; k[i] != '\0' ; i++) {
+                       for (i=1 ; k[i] != '\0' ; i++) {
                                if (k[i] == '.') {
                                        type = EXYNOS_PARAM_FLOAT;
                                } else if (!isdigit(k[i])) {