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