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