Add version of so files
[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 static 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_LOG_INFO("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_LOG_INFO("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_LOG_INFO("marker offset: %lu %p %p.", ret, (p+1), src);
123                                 return ret;
124                         }
125                 }
126         }
127         MMCAM_LOG_INFO("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_LOG_INFO("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_LOG_ERROR("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, (unsigned char *)(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_LOG_INFO("exif Null");
183                 return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
184         }
185
186         MMCAM_LOG_INFO("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_LOG_INFO("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_LOG_ERROR("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_LOG_ERROR("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_LOG_INFO("");
271
272         if (!info) {
273                 MMCAM_LOG_ERROR("NULL pointer");
274                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
275         }
276
277         x = malloc(sizeof(mm_exif_info_t));
278         if (!x) {
279                 MMCAM_LOG_ERROR("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_LOG_ERROR("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_LOG_ERROR("exif data new error");
296                 free(x);
297                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
298         }
299
300         exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL);
301         exif_data_set_data_type(ed, EXIF_DATA_TYPE_COMPRESSED);
302         exif_data_set_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION);
303
304         exif_data_fix(ed);
305
306         exif_data_save_data(ed, &eb, &ebs);
307         if (eb == NULL) {
308                 MMCAM_LOG_ERROR("exif_data_save_data error");
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_LOG_INFO("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_LOG_INFO( ""); */
329         if (info) {
330                 if (info->data)
331                         free(info->data);
332                 free(info);
333         }
334 }
335
336
337 int
338 mm_exif_add_thumbnail_info(mm_exif_info_t *info, void *thumbnail, int width, int height, int len)
339 {
340         ExifData *ed = NULL;
341         static ExifLong elong[10];
342
343         unsigned char *p_compressed = NULL;
344         int ret = MM_ERROR_NONE;
345         int cntl = 0;
346
347         MMCAM_LOG_INFO("Thumbnail size:%d, width:%d, height:%d", len, width, height);
348
349         if (len > JPEG_THUMBNAIL_MAX_SIZE) {
350                 MMCAM_LOG_ERROR("Thumbnail size[%d] over!!! Skip inserting thumbnail...", len);
351                 return MM_ERROR_NONE;
352         }
353
354         /* get ExifData from info*/
355         ed = mm_exif_get_exif_from_info(info);
356         if (ed == NULL) {
357                 MMCAM_LOG_ERROR("mm_exif_get_exif_from_info failed");
358                 return MM_ERROR_CAMCORDER_INTERNAL;
359         }
360
361         ed->data = thumbnail;
362         ed->size = len;
363
364         /* set thumbnail data */
365         p_compressed = (unsigned char *)malloc(sizeof(ExifShort));
366         if (p_compressed != NULL) {
367                 exif_set_short(p_compressed, exif_data_get_byte_order(ed), 6);
368                 ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_COMPRESSION, EXIF_FORMAT_SHORT, 1, (const char *)p_compressed);
369                 if (ret != MM_ERROR_NONE)
370                         goto exit;
371         } else {
372                 ret = MM_ERROR_CAMCORDER_LOW_MEMORY;
373                 goto exit;
374         }
375
376         /* set thumbnail size */
377         exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), width);
378         ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
379         if (ret != MM_ERROR_NONE)
380                 goto exit;
381
382         exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), height);
383         ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, EXIF_FORMAT_LONG, 1, (const char *)&elong[cntl++]);
384         if (ret != MM_ERROR_NONE)
385                 goto exit;
386
387         ret = mm_exif_set_exif_to_info(info, ed);
388         if (ret != MM_ERROR_NONE)
389                 goto exit;
390
391         ed->data = NULL;
392         ed->size = 0;
393         exif_data_unref(ed);
394
395 exit:
396         if (p_compressed != NULL)
397                 free(p_compressed);
398
399         return ret;
400 }
401
402
403 int
404 mm_exif_write_exif_jpeg_to_memory(void **mem, unsigned int *length, mm_exif_info_t *info,  unsigned char *jpeg, unsigned int jpeg_len)
405 {
406         unsigned short head[2] = {0,};
407         unsigned short head_len = 0;
408         unsigned char *eb = NULL;
409         unsigned int ebs;
410         int jpeg_offset = JPEG_DATA_OFFSET;
411         mm_exif_info_t *test_exif_info = NULL;
412
413         /*output*/
414         unsigned char *m = NULL;
415         int m_len = 0;
416
417         MMCAM_LOG_INFO("");
418
419         if (info == NULL || jpeg == NULL) {
420                 MMCAM_LOG_ERROR("MM_ERROR_CAMCORDER_INVALID_ARGUMENT info=%p, jpeg=%p", info, jpeg);
421                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
422         }
423
424         if (jpeg_len > JPEG_MAX_SIZE) {
425                 MMCAM_LOG_ERROR("jpeg_len is wrong jpeg_len=%d", jpeg_len);
426                 return MM_ERROR_CAMCORDER_DEVICE_WRONG_JPEG;
427         }
428
429         eb = info->data;
430         ebs = info->size;
431
432         /* check EXIF in JPEG */
433         if (mm_exif_load_exif_info(&test_exif_info, jpeg, jpeg_len) == MM_ERROR_NONE) {
434                 if (test_exif_info) {
435                         jpeg_offset = test_exif_info->size + JPEG_EXIF_OFFSET;
436                         if (test_exif_info->data) {
437                                 free(test_exif_info->data);
438                                 test_exif_info->data = NULL;
439                         }
440                         free(test_exif_info);
441                         test_exif_info = NULL;
442                 } else {
443                         MMCAM_LOG_ERROR("test_exif_info is NULL");
444                 }
445         } else {
446                 MMCAM_LOG_WARNING("no EXIF in JPEG");
447         }
448
449         /*length of output image*/
450         /*SOI + APP1 + length of APP1 + length of EXIF + IMAGE*/
451         m_len = EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs + (jpeg_len - jpeg_offset);
452         /*alloc output image*/
453         m = malloc(m_len);
454         if (!m) {
455                 MMCAM_LOG_ERROR("malloc() failed.");
456                 return MM_ERROR_CAMCORDER_LOW_MEMORY;
457         }
458
459         /*set SOI, APP1*/
460         _exif_set_uint16(0, &head[0], 0xffd8);
461         _exif_set_uint16(0, &head[1], 0xffe1);
462         /*set header length*/
463         _exif_set_uint16(0, &head_len, (unsigned short)(ebs + 2));
464         if (head[0] == 0 || head[1] == 0 || head_len == 0) {
465                 MMCAM_LOG_ERROR("setting error");
466                 free(m);
467                 return MM_ERROR_CAMCORDER_INVALID_ARGUMENT;
468         }
469
470         /* Complete JPEG+EXIF */
471         /*SOI marker*/
472         memcpy(m, &head[0], EXIF_MARKER_SOI_LENGTH);
473
474         /*APP1 marker*/
475         memcpy(m + EXIF_MARKER_SOI_LENGTH, &head[1], EXIF_MARKER_APP1_LENGTH);
476
477         /*length of APP1*/
478         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH, &head_len, EXIF_APP1_LENGTH);
479
480         /*EXIF*/
481         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH, eb, ebs);
482
483         /*IMAGE*/
484         memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs,
485                 jpeg + jpeg_offset, jpeg_len - jpeg_offset);
486
487         MMCAM_LOG_INFO("JPEG+EXIF Copy DONE(original:%d, offset:%d, copied:%d)",
488                 jpeg_len, jpeg_offset, jpeg_len - jpeg_offset);
489
490         /*set ouput param*/
491         *mem = m;
492         *length = m_len;
493
494         return MM_ERROR_NONE;
495 }
496
497
498 int mm_exif_load_exif_info(mm_exif_info_t **info, void *jpeg_data, int jpeg_length)
499 {
500         ExifLoader *loader = NULL;
501         const unsigned char *b = NULL;
502         unsigned int s = 0;
503         mm_exif_info_t *x = NULL;
504
505         /* TODO : get exif and re-set exif */
506
507         loader = exif_loader_new();
508         if (loader) {
509                 exif_loader_write(loader, jpeg_data, jpeg_length);
510                 exif_loader_get_buf(loader, &b, &s);
511                 if (s > 0) {
512                         x = malloc(sizeof(mm_exif_info_t));
513                         if (x) {
514                                 x->data = malloc(s);
515                                 if (x->data) {
516                                         memcpy((char*)x->data, b, s);
517                                         x->size = s;
518                                         *info = x;
519                                         MMCAM_LOG_WARNING("load EXIF : data %p, size %d", x->data, x->size);
520                                 } else {
521                                         MMCAM_LOG_ERROR("mm_exif_info_t malloc failed");
522                                         free(x);
523                                         exif_loader_unref(loader);
524
525                                         return MM_ERROR_CAMCORDER_LOW_MEMORY;
526                                 }
527                         } else {
528                                 MMCAM_LOG_ERROR("mm_exif_info_t malloc failed");
529                         }
530                 } else {
531                         MMCAM_LOG_ERROR("exif_loader_get_buf failed");
532                 }
533
534                 /* The loader is no longer needed--free it */
535                 exif_loader_unref(loader);
536                 loader = NULL;
537         } else {
538                 MMCAM_LOG_ERROR("exif_loader_new failed");
539         }
540
541         if (x)
542                 return MM_ERROR_NONE;
543         else
544                 return MM_ERROR_CAMCORDER_INTERNAL;
545 }