4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jeongmo Yang <jm80.yang@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include "mm_camcorder_exifinfo.h"
23 #include "mm_camcorder_exifdef.h"
24 #include "mm_camcorder_internal.h"
26 #include <libexif/exif-loader.h>
27 #include <libexif/exif-utils.h>
28 #include <libexif/exif-data.h>
36 #define MM_EXIFINFO_USE_BINARY_EXIFDATA 1
37 #define JPEG_MAX_SIZE 20000000
38 #define JPEG_THUMBNAIL_MAX_SIZE (128*1024)
39 #define JPEG_DATA_OFFSET 2
40 #define JPEG_EXIF_OFFSET 4
41 #define EXIF_MARKER_SOI_LENGTH 2
42 #define EXIF_MARKER_APP1_LENGTH 2
43 #define EXIF_APP1_LENGTH 2
46 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
51 #define _EXIF_BIN_SIZE_ ((unsigned int)174)
52 unsigned char g_exif_bin [_EXIF_BIN_SIZE_] = {
53 0x45 , 0x78 , 0x69 , 0x66 , 0x00 , 0x00 , 0x49 , 0x49 , 0x2a , 0x00 , 0x08 , 0x00 , 0x00 , 0x00 , 0x05 , 0x00
54 , 0x1a , 0x01 , 0x05 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x4a , 0x00 , 0x00 , 0x00 , 0x1b , 0x01 , 0x05 , 0x00
55 , 0x01 , 0x00 , 0x00 , 0x00 , 0x52 , 0x00 , 0x00 , 0x00 , 0x28 , 0x01 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00
56 , 0x02 , 0x00 , 0x00 , 0x00 , 0x13 , 0x02 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00
57 , 0x69 , 0x87 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x5a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
58 , 0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00
59 , 0x06 , 0x00 , 0x00 , 0x90 , 0x07 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 , 0x30 , 0x32 , 0x31 , 0x30 , 0x01 , 0x91
60 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xa0 , 0x07 , 0x00 , 0x04 , 0x00
61 , 0x00 , 0x00 , 0x30 , 0x31 , 0x30 , 0x30 , 0x01 , 0xa0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
62 , 0x00 , 0x00 , 0x02 , 0xa0 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0xa0
63 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
68 * Structure for exif entry.
70 typedef struct _mm_exif_entry_t
72 ExifTag tag; /**< exif tag*/
73 ExifFormat format; /**< exif format*/
74 unsigned long components; /**< number of components*/
75 unsigned char *data; /**< data*/
76 unsigned int size; /**< size of data*/
84 _exif_set_uint16 (int is_motorola, void * out, unsigned short in)
87 ((unsigned char *)out)[0] = in & 0x00ff;
88 ((unsigned char *)out)[1] = in >> 8;
90 ((unsigned char *)out)[0] = in >> 8;
91 ((unsigned char *)out)[1] = in & 0x00ff;
96 #ifdef _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET
98 _exif_get_jpeg_marker_offset (void *jpeg, int jpeg_size, unsigned short marker)
100 unsigned char *p = NULL;
101 unsigned char *src = jpeg;
102 int src_sz = jpeg_size;
108 m[1] = marker & 0x00FF;
110 _mmcam_dbg_log("marker: 0x%02X 0x%02X", m[0], m[1]);
112 if (*src == 0xff && *(src + 1) == 0xd8)
114 p = src + 2; /* SOI(start of image) */
118 _mmcam_dbg_log("invalid JPEG file.");
122 for (i = 0; i < src_sz - (1 + 2); i++, p++)
127 if (*(p + 1) == m[1])
130 _mmcam_dbg_log("marker offset: %lu %p %p.",ret, (p+1), src);
135 _mmcam_dbg_log("Marker not found.");
138 #endif /* _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET */
142 mm_exif_get_exif_data_from_data (mm_exif_info_t *info)
146 ed = exif_data_new_from_data(info->data, info->size);
149 _mmcam_dbg_log("Null exif data. (ed:%p)", ed);
157 mm_exif_get_exif_from_info (mm_exif_info_t *info)
160 ExifLoader *loader = NULL;
162 unsigned char size[2];
165 /*get ExifData from info*/
166 loader = exif_loader_new ();
168 size[0] = (unsigned char) (info->size);
169 size[1] = (unsigned char) (info->size >> 8);
170 exif_loader_write (loader, size, 2);
172 for (i = 0; i < info->size && exif_loader_write (loader, info->data + i, 1); i++);
174 ed = exif_loader_get_data (loader);
175 exif_loader_unref (loader);
181 mm_exif_set_exif_to_info (mm_exif_info_t *info, ExifData *exif)
183 unsigned char *eb = NULL;
188 _mmcam_dbg_log("exif Null");
189 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
192 _mmcam_dbg_log("exif(ifd :%p)", exif->ifd);
201 exif_data_save_data (exif, &eb, &ebs);
204 _mmcam_dbg_log("MM_ERROR_CAMCORDER_LOW_MEMORY");
205 return MM_ERROR_CAMCORDER_LOW_MEMORY;
209 return MM_ERROR_NONE;
214 mm_exif_set_add_entry (ExifData *exif, ExifIfd ifd, ExifTag tag,ExifFormat format,unsigned long components, const char* data)
216 ExifData *ed = (ExifData *)exif;
219 if (exif == NULL || format <= 0 || components <= 0 || data == NULL) {
220 _mmcam_dbg_err("invalid argument exif=%p format=%d, components=%lu data=%p!",
221 exif,format,components,data);
222 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
225 /*remove same tag in EXIF*/
226 exif_content_remove_entry(ed->ifd[ifd], exif_content_get_entry(ed->ifd[ifd], tag));
229 e = exif_entry_new();
231 _mmcam_dbg_err("entry create error!");
232 return MM_ERROR_CAMCORDER_LOW_MEMORY;
235 exif_entry_initialize(e, tag);
239 e->components = components;
243 e->data = malloc(exif_format_get_size(format) * e->components);
246 return MM_ERROR_CAMCORDER_LOW_MEMORY;
249 if (format == EXIF_FORMAT_ASCII) {
250 memset(e->data, '\0', exif_format_get_size(format) * e->components);
254 e->size = exif_format_get_size(format) * e->components;
255 memcpy(e->data,data,e->size);
256 exif_content_add_entry(ed->ifd[ifd], e);
259 return MM_ERROR_NONE;
271 mm_exif_create_exif_info (mm_exif_info_t **info)
273 mm_exif_info_t *x = NULL;
274 #if (MM_EXIFINFO_USE_BINARY_EXIFDATA == 0)
276 unsigned char *eb = NULL;
282 _mmcam_dbg_err("NULL pointer");
283 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
286 x = malloc(sizeof(mm_exif_info_t));
288 _mmcam_dbg_err("malloc error");
289 return MM_ERROR_CAMCORDER_LOW_MEMORY;
291 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
293 x->data = malloc(_EXIF_BIN_SIZE_);
295 _mmcam_dbg_err("malloc error");
297 return MM_ERROR_CAMCORDER_LOW_MEMORY;
299 memcpy(x->data, g_exif_bin, _EXIF_BIN_SIZE_);
300 x->size = _EXIF_BIN_SIZE_;
302 ed = exif_data_new();
304 _mmcam_dbg_err("exif data new error");
305 return MM_ERROR_CAMCORDER_LOW_MEMORY;
308 exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL);
309 exif_data_set_data_type(ed, EXIF_DATA_TYPE_COMPRESSED);
310 exif_data_set_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
314 exif_data_save_data(ed, &eb, &ebs);
316 _mmcam_dbg_err("exif_data_save_data error");
320 return MM_ERROR_CAMCORDER_INTERNAL;
329 _mmcam_dbg_log("Data:%p Size:%d", x->data, x->size);
331 return MM_ERROR_NONE;
335 mm_exif_destory_exif_info (mm_exif_info_t *info)
337 //_mmcam_dbg_log( "");
339 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
348 exif_mem_free (info->data);
356 mm_exif_add_thumbnail_info (mm_exif_info_t *info, void *thumbnail, int width, int height, int len)
359 static ExifLong elong[10];
361 unsigned char *p_compressed = NULL;
362 int ret = MM_ERROR_NONE;
365 _mmcam_dbg_log("Thumbnail size:%d, width:%d, height:%d", len, width, height);
367 if( len > JPEG_THUMBNAIL_MAX_SIZE )
369 _mmcam_dbg_err("Thumbnail size[%d] over!!! Skip inserting thumbnail...", len);
370 return MM_ERROR_NONE;
373 /* get ExifData from info*/
374 ed = mm_exif_get_exif_from_info(info);
376 _mmcam_dbg_err("mm_exif_get_exif_from_info failed");
377 return MM_ERROR_CAMCORDER_INTERNAL;
380 ed->data = thumbnail;
383 /* set thumbnail data */
384 p_compressed = (unsigned char *)malloc(sizeof(ExifShort));
385 if (p_compressed != NULL) {
386 exif_set_short(p_compressed, exif_data_get_byte_order(ed), 6);
387 ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_COMPRESSION, EXIF_FORMAT_SHORT, 1, (const char *)p_compressed);
388 if (ret != MM_ERROR_NONE) {
392 ret = MM_ERROR_CAMCORDER_LOW_MEMORY;
396 /* set thumbnail size */
397 exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), width);
398 ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
399 if (ret != MM_ERROR_NONE) {
402 exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), height);
403 ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
404 if (ret != MM_ERROR_NONE) {
408 ret = mm_exif_set_exif_to_info (info, ed);
409 if (ret != MM_ERROR_NONE) {
415 exif_data_unref (ed);
418 if(p_compressed != NULL)
425 mm_exif_write_exif_jpeg_to_file (char *filename, mm_exif_info_t *info, void *jpeg, int jpeg_len)
428 unsigned short head[2] = {0,};
429 unsigned short head_len = 0;
430 unsigned char *eb = NULL;
439 fp = fopen (filename, "wb");
441 _mmcam_dbg_err( "fopen() failed [%s].", filename);
442 return MM_ERROR_IMAGE_FILEOPEN;
446 _exif_set_uint16 (0, &head[0], 0xffd8);
447 _exif_set_uint16 (0, &head[1], 0xffe1);
448 /*set header length*/
449 _exif_set_uint16 (0, &head_len, (unsigned short)(ebs + 2));
451 if(head[0]==0 || head[1]==0 || head_len==0)
453 _mmcam_dbg_err("setting error");
458 fwrite (&head[0], 1, EXIF_MARKER_SOI_LENGTH, fp); /*SOI marker*/
459 fwrite (&head[1], 1, EXIF_MARKER_APP1_LENGTH, fp); /*APP1 marker*/
460 fwrite (&head_len, 1, EXIF_APP1_LENGTH, fp); /*length of APP1*/
461 fwrite (eb, 1, ebs, fp); /*EXIF*/
462 fwrite (jpeg + JPEG_DATA_OFFSET, 1, jpeg_len - JPEG_DATA_OFFSET, fp); /*IMAGE*/
466 return MM_ERROR_NONE;
470 mm_exif_write_exif_jpeg_to_memory (void **mem, unsigned int *length, mm_exif_info_t *info, void *jpeg, unsigned int jpeg_len)
472 unsigned short head[2] = {0,};
473 unsigned short head_len = 0;
474 unsigned char *eb = NULL;
476 int jpeg_offset = JPEG_DATA_OFFSET;
477 mm_exif_info_t *test_exif_info = NULL;
480 unsigned char *m = NULL;
485 if(info==NULL || jpeg==NULL)
487 _mmcam_dbg_err( "MM_ERROR_CAMCORDER_INVALID_ARGUMENT info=%p, jpeg=%p",info,jpeg);
488 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
491 if(jpeg_len>JPEG_MAX_SIZE)
493 _mmcam_dbg_err( "jpeg_len is worng jpeg_len=%d",jpeg_len);
494 return MM_ERROR_CAMCORDER_DEVICE_WRONG_JPEG;
500 /* check EXIF in JPEG */
501 if (mm_exif_load_exif_info(&test_exif_info, jpeg, jpeg_len) == MM_ERROR_NONE) {
502 if (test_exif_info) {
503 jpeg_offset = test_exif_info->size + JPEG_EXIF_OFFSET;
504 if (test_exif_info->data) {
505 free(test_exif_info->data);
506 test_exif_info->data = NULL;
508 free(test_exif_info);
509 test_exif_info = NULL;
511 _mmcam_dbg_err("test_exif_info is NULL");
514 _mmcam_dbg_warn("no EXIF in JPEG");
517 /*length of output image*/
518 /*SOI + APP1 + length of APP1 + length of EXIF + IMAGE*/
519 m_len = EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs + (jpeg_len - jpeg_offset);
520 /*alloc output image*/
523 _mmcam_dbg_err( "malloc() failed.");
524 return MM_ERROR_CAMCORDER_LOW_MEMORY;
528 _exif_set_uint16 (0, &head[0], 0xffd8);
529 _exif_set_uint16 (0, &head[1], 0xffe1);
530 /*set header length*/
531 _exif_set_uint16 (0, &head_len, (unsigned short)(ebs + 2));
532 if (head[0] == 0 || head[1] == 0 || head_len == 0) {
533 _mmcam_dbg_err("setting error");
535 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
538 /* Complete JPEG+EXIF */
540 memcpy(m, &head[0], EXIF_MARKER_SOI_LENGTH);
542 memcpy(m + EXIF_MARKER_SOI_LENGTH,
543 &head[1], EXIF_MARKER_APP1_LENGTH);
545 memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH,
546 &head_len, EXIF_APP1_LENGTH);
548 memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH,
551 memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs,
552 jpeg + jpeg_offset, jpeg_len - jpeg_offset);
554 _mmcam_dbg_log("JPEG+EXIF Copy DONE(original:%d, offset:%d, copied:%d)",
555 jpeg_len, jpeg_offset, jpeg_len - jpeg_offset);
561 return MM_ERROR_NONE;
565 int mm_exif_load_exif_info(mm_exif_info_t **info, void *jpeg_data, int jpeg_length)
567 ExifLoader *loader = NULL;
568 const unsigned char *b = NULL;
570 mm_exif_info_t *x = NULL;
571 // TODO : get exif and re-set exif
572 loader = exif_loader_new();
574 exif_loader_write (loader, jpeg_data, jpeg_length);
575 exif_loader_get_buf (loader, &b, &s);
577 x = malloc(sizeof(mm_exif_info_t));
581 memcpy((char*)x->data, b, s);
584 _mmcam_dbg_warn("load EXIF : data %p, size %d", x->data, x->size);
586 _mmcam_dbg_err("mm_exif_info_t malloc failed");
588 exif_loader_unref(loader);
589 return MM_ERROR_CAMCORDER_LOW_MEMORY;
592 _mmcam_dbg_err("mm_exif_info_t malloc failed");
595 _mmcam_dbg_err("exif_loader_get_buf failed");
598 /* The loader is no longer needed--free it */
599 exif_loader_unref(loader);
602 _mmcam_dbg_err("exif_loader_new failed");
606 return MM_ERROR_NONE;
608 return MM_ERROR_CAMCORDER_INTERNAL;