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