Change flag for some attributes
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_exifinfo.c
1 /*
2  * libmm-camcorder
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jeongmo Yang <jm80.yang@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include "mm_camcorder_exifinfo.h"
23 #include "mm_camcorder_exifdef.h"
24 #include "mm_camcorder_internal.h"
25
26 #include <libexif/exif-loader.h>
27 #include <libexif/exif-utils.h>
28 #include <libexif/exif-data.h>
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <mm_error.h>
34
35 #define MM_EXIFINFO_USE_BINARY_EXIFDATA         1
36 #define JPEG_MAX_SIZE                           20000000
37 #define JPEG_THUMBNAIL_MAX_SIZE                 (128*1024)
38 #define JPEG_DATA_OFFSET                        2
39 #define JPEG_EXIF_OFFSET                        4
40 #define EXIF_MARKER_SOI_LENGTH                  2
41 #define EXIF_MARKER_APP1_LENGTH                 2
42 #define EXIF_APP1_LENGTH                        2
43
44
45 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
46 /**
47  * Exif Binary Data.
48  */
49 #include <string.h>
50 #define _EXIF_BIN_SIZE_         ((unsigned int)174)
51 unsigned char g_exif_bin[_EXIF_BIN_SIZE_] = {
52         0x45 , 0x78 , 0x69 , 0x66 , 0x00 , 0x00 , 0x49 , 0x49 , 0x2a , 0x00 , 0x08 , 0x00 , 0x00 , 0x00 , 0x05 , 0x00 ,
53         0x1a , 0x01 , 0x05 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x4a , 0x00 , 0x00 , 0x00 , 0x1b , 0x01 , 0x05 , 0x00 ,
54         0x01 , 0x00 , 0x00 , 0x00 , 0x52 , 0x00 , 0x00 , 0x00 , 0x28 , 0x01 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 ,
55         0x02 , 0x00 , 0x00 , 0x00 , 0x13 , 0x02 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 ,
56         0x69 , 0x87 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x5a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
57         0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 ,
58         0x06 , 0x00 , 0x00 , 0x90 , 0x07 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 , 0x30 , 0x32 , 0x31 , 0x30 , 0x01 , 0x91 ,
59         0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xa0 , 0x07 , 0x00 , 0x04 , 0x00 ,
60         0x00 , 0x00 , 0x30 , 0x31 , 0x30 , 0x30 , 0x01 , 0xa0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
61         0x00 , 0x00 , 0x02 , 0xa0 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0xa0 ,
62         0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
63 };
64 #endif
65
66 /**
67  * Structure for exif entry.
68  */
69 typedef struct  _mm_exif_entry_t {
70         ExifTag                 tag;                    /**< exif tag*/
71         ExifFormat              format;                 /**< exif format*/
72         unsigned long   components;             /**< number of components*/
73         unsigned char   *data;                  /**< data*/
74         unsigned int    size;                   /**< size of data*/
75 } mm_exif_entry_type;
76
77
78 /**
79  * local functions.
80  */
81 static void
82 _exif_set_uint16(int is_motorola, void * out, unsigned short in)
83 {
84         if (is_motorola) {
85                 ((unsigned char *)out)[0] = in & 0x00ff;
86                 ((unsigned char *)out)[1] = in >> 8;
87         } else {
88                 ((unsigned char *)out)[0] = in >> 8;
89                 ((unsigned char *)out)[1] = in & 0x00ff;
90         }
91 }
92
93
94 #ifdef _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET
95 static unsigned long
96 _exif_get_jpeg_marker_offset(void *jpeg, int jpeg_size, unsigned short marker)
97 {
98         unsigned char *p = NULL;
99         unsigned char *src = jpeg;
100         int src_sz = jpeg_size;
101         unsigned char m[2];
102         unsigned long ret;
103         int i;
104
105         m[0] = marker >> 8;
106         m[1] = marker & 0x00FF;
107
108         _mmcam_dbg_log("marker: 0x%02X 0x%02X", m[0], m[1]);
109
110         if (*src == 0xff && *(src + 1) == 0xd8) {
111                 p = src + 2; /* SOI(start of image) */
112         } else {
113                 _mmcam_dbg_log("invalid JPEG file.");
114                 return 0UL;
115         }
116
117         for (i = 0; i < src_sz - (1 + 2); i++, p++) {
118                 if (*p == 0xff) {
119                         /*marker is 0xFFxx*/
120                         if (*(p + 1) == m[1]) {
121                                 ret = p - src;
122                                 _mmcam_dbg_log("marker offset: %lu %p %p.", ret, (p+1), src);
123                                 return ret;
124                         }
125                 }
126         }
127         _mmcam_dbg_log("Marker not found.");
128         return 0UL;
129 }
130 #endif /* _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET */
131
132
133 ExifData*
134 mm_exif_get_exif_data_from_data(mm_exif_info_t *info)
135 {
136         ExifData *ed = NULL;
137
138         ed = exif_data_new_from_data(info->data, info->size);
139         if (ed == NULL)
140                 _mmcam_dbg_log("Null exif data. (ed:%p)", ed);
141
142         return ed;
143 }
144
145
146 ExifData*
147 mm_exif_get_exif_from_info(mm_exif_info_t *info)
148 {
149         ExifData *ed = NULL;
150         ExifLoader *loader = NULL;
151
152         unsigned char size[2];
153         unsigned int i;
154
155         if (!info) {
156                 _mmcam_dbg_err("NULL exif info");
157                 return NULL;
158         }
159
160         /*get ExifData from info*/
161         loader = exif_loader_new();
162
163         size[0] = (unsigned char) (info->size);
164         size[1] = (unsigned char) (info->size >> 8);
165         exif_loader_write(loader, size, 2);
166
167         for (i = 0; i < info->size && exif_loader_write(loader, info->data + i, 1); i++);
168
169         ed = exif_loader_get_data(loader);
170         exif_loader_unref(loader);
171         return ed;
172 }
173
174
175 int
176 mm_exif_set_exif_to_info(mm_exif_info_t *info, ExifData *exif)
177 {
178         unsigned char *eb = NULL;
179         unsigned int ebs;
180
181         if (!exif) {
182                 _mmcam_dbg_log("exif Null");
183                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
184         }
185
186         _mmcam_dbg_log("exif(ifd :%p)", exif->ifd);
187
188         if (info->data) {
189                 free(info->data);
190                 info->data = NULL;
191                 info->size = 0;
192         }
193
194         exif_data_save_data(exif, &eb, &ebs);
195         if (eb == NULL) {
196                 _mmcam_dbg_log("MM_ERROR_CAMCORDER_LOW_MEMORY");
197                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
198         }
199         info->data = eb;
200         info->size = ebs;
201         return MM_ERROR_NONE;
202 }
203
204
205 int
206 mm_exif_set_add_entry(ExifData *exif, ExifIfd ifd, ExifTag tag, ExifFormat format, unsigned long components, const char* data)
207 {
208         ExifData *ed = (ExifData *)exif;
209         ExifEntry *e = NULL;
210
211         if (exif == NULL || format <= 0 || components <= 0 || data == NULL) {
212                 _mmcam_dbg_err("invalid argument exif=%p format=%d, components=%lu data=%p!",
213                                            exif, format, components, data);
214                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
215         }
216
217         /*remove same tag in EXIF*/
218         exif_content_remove_entry(ed->ifd[ifd], exif_content_get_entry(ed->ifd[ifd], tag));
219
220         /*create new tag*/
221         e = exif_entry_new();
222         if (e == NULL) {
223                 _mmcam_dbg_err("entry create error!");
224                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
225         }
226
227         exif_entry_initialize(e, tag);
228
229         e->tag = tag;
230         e->format = format;
231         e->components = components;
232
233         if (e->size == 0) {
234                 e->data = NULL;
235                 e->data = malloc(exif_format_get_size(format) * e->components);
236                 if (!e->data) {
237                         exif_entry_unref(e);
238                         return MM_ERROR_CAMCORDER_LOW_MEMORY;
239                 }
240
241                 if (format == EXIF_FORMAT_ASCII)
242                         memset(e->data, '\0', exif_format_get_size(format) * e->components);
243         }
244
245         e->size = exif_format_get_size(format) * e->components;
246         memcpy(e->data, data, e->size);
247         exif_content_add_entry(ed->ifd[ifd], e);
248         exif_entry_unref(e);
249
250         return MM_ERROR_NONE;
251 }
252
253
254
255
256 /**
257  * global functions.
258  */
259
260
261 int
262 mm_exif_create_exif_info(mm_exif_info_t **info)
263 {
264         mm_exif_info_t *x = NULL;
265 #if (MM_EXIFINFO_USE_BINARY_EXIFDATA == 0)
266         ExifData *ed = NULL;
267         unsigned char *eb = NULL;
268         unsigned int ebs;
269 #endif
270         _mmcam_dbg_log("");
271
272         if (!info) {
273                 _mmcam_dbg_err("NULL pointer");
274                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
275         }
276
277         x = malloc(sizeof(mm_exif_info_t));
278         if (!x) {
279                 _mmcam_dbg_err("malloc error");
280                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
281         }
282 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
283         x->data = NULL;
284         x->data = malloc(_EXIF_BIN_SIZE_);
285         if (!x->data) {
286                 _mmcam_dbg_err("malloc error");
287                 free(x);
288                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
289         }
290         memcpy(x->data, g_exif_bin, _EXIF_BIN_SIZE_);
291         x->size = _EXIF_BIN_SIZE_;
292 #else
293         ed = exif_data_new();
294         if (!ed) {
295                 _mmcam_dbg_err("exif data new error");
296                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
297         }
298
299         exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL);
300         exif_data_set_data_type(ed, EXIF_DATA_TYPE_COMPRESSED);
301         exif_data_set_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
302
303         exif_data_fix(ed);
304
305         exif_data_save_data(ed, &eb, &ebs);
306         if (eb == NULL) {
307                 _mmcam_dbg_err("exif_data_save_data error");
308                 free(x->data);
309                 free(x);
310                 exif_data_unref(ed);
311                 return MM_ERROR_CAMCORDER_INTERNAL;
312         }
313         exif_data_unref(ed);
314
315         x->data = eb;
316         x->size = ebs;
317 #endif
318         *info = x;
319
320         _mmcam_dbg_log("Data:%p Size:%d", x->data, x->size);
321
322         return MM_ERROR_NONE;
323 }
324
325 void
326 mm_exif_destory_exif_info(mm_exif_info_t *info)
327 {
328         /* _mmcam_dbg_log( ""); */
329
330 #if MM_EXIFINFO_USE_BINARY_EXIFDATA
331         if (info) {
332                 if (info->data)
333                         free(info->data);
334                 free(info);
335         }
336 #else
337         if (info) {
338                 if (info->data)
339                         exif_mem_free(info->data);
340                 free(info);
341         }
342 #endif
343 }
344
345
346 int
347 mm_exif_add_thumbnail_info(mm_exif_info_t *info, void *thumbnail, int width, int height, int len)
348 {
349         ExifData *ed = NULL;
350         static ExifLong elong[10];
351
352         unsigned char *p_compressed = NULL;
353         int ret = MM_ERROR_NONE;
354         int cntl = 0;
355
356         _mmcam_dbg_log("Thumbnail size:%d, width:%d, height:%d", len, width, height);
357
358         if (len > JPEG_THUMBNAIL_MAX_SIZE) {
359                 _mmcam_dbg_err("Thumbnail size[%d] over!!! Skip inserting thumbnail...", len);
360                 return MM_ERROR_NONE;
361         }
362
363         /* get ExifData from info*/
364         ed = mm_exif_get_exif_from_info(info);
365         if (ed == NULL) {
366                 _mmcam_dbg_err("mm_exif_get_exif_from_info failed");
367                 return MM_ERROR_CAMCORDER_INTERNAL;
368         }
369
370         ed->data = thumbnail;
371         ed->size = len;
372
373         /* set thumbnail data */
374         p_compressed = (unsigned char *)malloc(sizeof(ExifShort));
375         if (p_compressed != NULL) {
376                 exif_set_short(p_compressed, exif_data_get_byte_order(ed), 6);
377                 ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_COMPRESSION, EXIF_FORMAT_SHORT, 1, (const char *)p_compressed);
378                 if (ret != MM_ERROR_NONE)
379                         goto exit;
380         } else {
381                 ret = MM_ERROR_CAMCORDER_LOW_MEMORY;
382                 goto exit;
383         }
384
385         /* set thumbnail size */
386         exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), width);
387         ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
388         if (ret != MM_ERROR_NONE)
389                 goto exit;
390
391         exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), height);
392         ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
393         if (ret != MM_ERROR_NONE)
394                 goto exit;
395
396         ret = mm_exif_set_exif_to_info(info, ed);
397         if (ret != MM_ERROR_NONE)
398                 goto exit;
399
400         ed->data = NULL;
401         ed->size = 0;
402         exif_data_unref(ed);
403
404 exit:
405         if (p_compressed != NULL)
406                 free(p_compressed);
407
408         return ret;
409 }
410
411
412 int
413 mm_exif_write_exif_jpeg_to_memory(void **mem, unsigned int *length, mm_exif_info_t *info,  unsigned char *jpeg, unsigned int jpeg_len)
414 {
415         unsigned short head[2] = {0,};
416         unsigned short head_len = 0;
417         unsigned char *eb = NULL;
418         unsigned int ebs;
419         int jpeg_offset = JPEG_DATA_OFFSET;
420         mm_exif_info_t *test_exif_info = NULL;
421
422         /*output*/
423         unsigned char *m = NULL;
424         int m_len = 0;
425
426         _mmcam_dbg_log("");
427
428         if (info == NULL || jpeg == NULL) {
429                 _mmcam_dbg_err("MM_ERROR_CAMCORDER_INVALID_ARGUMENT info=%p, jpeg=%p", info, jpeg);
430                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
431         }
432
433         if (jpeg_len > JPEG_MAX_SIZE) {
434                 _mmcam_dbg_err("jpeg_len is worng jpeg_len=%d", jpeg_len);
435                 return MM_ERROR_CAMCORDER_DEVICE_WRONG_JPEG;
436         }
437
438         eb = info->data;
439         ebs = info->size;
440
441         /* check EXIF in JPEG */
442         if (mm_exif_load_exif_info(&test_exif_info, jpeg, jpeg_len) == MM_ERROR_NONE) {
443                 if (test_exif_info) {
444                         jpeg_offset = test_exif_info->size + JPEG_EXIF_OFFSET;
445                         if (test_exif_info->data) {
446                                 free(test_exif_info->data);
447                                 test_exif_info->data = NULL;
448                         }
449                         free(test_exif_info);
450                         test_exif_info = NULL;
451                 } else {
452                         _mmcam_dbg_err("test_exif_info is NULL");
453                 }
454         } else {
455                 _mmcam_dbg_warn("no EXIF in JPEG");
456         }
457
458         /*length of output image*/
459         /*SOI + APP1 + length of APP1 + length of EXIF + IMAGE*/
460         m_len = EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs + (jpeg_len - jpeg_offset);
461         /*alloc output image*/
462         m = malloc(m_len);
463         if (!m) {
464                 _mmcam_dbg_err("malloc() failed.");
465                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
466         }
467
468         /*set SOI, APP1*/
469         _exif_set_uint16(0, &head[0], 0xffd8);
470         _exif_set_uint16(0, &head[1], 0xffe1);
471         /*set header length*/
472         _exif_set_uint16(0, &head_len, (unsigned short)(ebs + 2));
473         if (head[0] == 0 || head[1] == 0 || head_len == 0) {
474                 _mmcam_dbg_err("setting error");
475                 free(m);
476                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
477         }
478
479         /* Complete JPEG+EXIF */
480         /*SOI marker*/
481         memcpy(m, &head[0], EXIF_MARKER_SOI_LENGTH);
482
483         /*APP1 marker*/
484         memcpy(m + EXIF_MARKER_SOI_LENGTH, &head[1], EXIF_MARKER_APP1_LENGTH);
485
486         /*length of APP1*/
487         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH, &head_len, EXIF_APP1_LENGTH);
488
489         /*EXIF*/
490         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH, eb, ebs);
491
492         /*IMAGE*/
493         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs,
494                 jpeg + jpeg_offset, jpeg_len - jpeg_offset);
495
496         _mmcam_dbg_log("JPEG+EXIF Copy DONE(original:%d, offset:%d, copied:%d)",
497                 jpeg_len, jpeg_offset, jpeg_len - jpeg_offset);
498
499         /*set ouput param*/
500         *mem = m;
501         *length = m_len;
502
503         return MM_ERROR_NONE;
504 }
505
506
507 int mm_exif_load_exif_info(mm_exif_info_t **info, void *jpeg_data, int jpeg_length)
508 {
509         ExifLoader *loader = NULL;
510         const unsigned char *b = NULL;
511         unsigned int s = 0;
512         mm_exif_info_t *x = NULL;
513
514         /* TODO : get exif and re-set exif */
515
516         loader = exif_loader_new();
517         if (loader) {
518                 exif_loader_write(loader, jpeg_data, jpeg_length);
519                 exif_loader_get_buf(loader, &b, &s);
520                 if (s > 0) {
521                         x = malloc(sizeof(mm_exif_info_t));
522                         if (x) {
523                                 x->data = malloc(s);
524                                 if (x->data) {
525                                         memcpy((char*)x->data, b, s);
526                                         x->size = s;
527                                         *info = x;
528                                         _mmcam_dbg_warn("load EXIF : data %p, size %d", x->data, x->size);
529                                 } else {
530                                         _mmcam_dbg_err("mm_exif_info_t malloc failed");
531                                         free(x);
532                                         exif_loader_unref(loader);
533
534                                         return MM_ERROR_CAMCORDER_LOW_MEMORY;
535                                 }
536                         } else {
537                                 _mmcam_dbg_err("mm_exif_info_t malloc failed");
538                         }
539                 } else {
540                         _mmcam_dbg_err("exif_loader_get_buf failed");
541                 }
542
543                 /* The loader is no longer needed--free it */
544                 exif_loader_unref(loader);
545                 loader = NULL;
546         } else {
547                 _mmcam_dbg_err("exif_loader_new failed");
548         }
549
550         if (x)
551                 return MM_ERROR_NONE;
552         else
553                 return MM_ERROR_CAMCORDER_INTERNAL;
554 }