4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hyunjun Ko <zzoon.ko@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include "media-thumb-debug.h"
23 #include "media-thumb-util.h"
24 #include "media-thumb-internal.h"
25 #include "media-thumb-ipc.h"
27 #include "AGifFrameInfo.h"
28 #include "IfegDecodeAGIF.h"
29 #include "img-codec.h"
30 #include "img-codec-agif.h"
31 #include "img-codec-common.h"
32 #include "img-codec-osal.h"
33 #include "img-codec-parser.h"
35 #include <sys/types.h>
40 #include <image_util.h>
42 #include <Ecore_Evas.h>
43 #include <libexif/exif-data.h>
45 #define MEDIA_THUMB_ROUND_UP_8(num) (((num)+7)&~7)
47 static int __media_thumb_get_buffer_size(image_util_colorspace_e format, unsigned int width, unsigned int height, unsigned int *imgsize)
49 int err = IMAGE_UTIL_ERROR_NONE;
51 err = image_util_calculate_buffer_size(width, height, format, imgsize);
52 if (err != IMAGE_UTIL_ERROR_NONE) {
53 thumb_err("image_util_calculate_buffer_size failed");
54 return MS_MEDIA_ERR_INTERNAL;
57 return MS_MEDIA_ERR_NONE;
60 int _media_thumb_rgb_to_argb(const unsigned char *src_data, const int src_size,
61 unsigned char **dst_data,
62 unsigned int *buf_size,
66 int err = MS_MEDIA_ERR_NONE;
69 if (__media_thumb_get_buffer_size(IMAGE_UTIL_COLORSPACE_BGRA8888, width, height, buf_size) < 0) {
70 thumb_err("__media_thumb_get_buffer_size failed");
71 return MS_MEDIA_ERR_INTERNAL;
74 thumb_dbg("__media_thumb_get_buffer_size : %d", *buf_size);
76 *dst_data = (unsigned char *)malloc(*buf_size);
77 if (*dst_data == NULL) {
78 thumb_err("Failed to allocate memory");
79 return MS_MEDIA_ERR_OUT_OF_MEMORY;
82 for (j = 0; ((j < src_size) && (i < *buf_size)); j += 3) {
83 (*dst_data)[i++] = (src_data[j + 2]);
84 (*dst_data)[i++] = (src_data[j + 1]);
85 (*dst_data)[i++] = (src_data[j]);
86 (*dst_data)[i++] = 0x0;
89 thumb_dbg("_media_thumb_rgb_to_argb success");
94 int _media_thumb_resize_with_evas(const void *image, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
96 Ecore_Evas *resize_img_ee;
99 thumb_err("Invalid parameter");
100 return MS_MEDIA_ERR_INVALID_PARAMETER;
102 resize_img_ee = ecore_evas_buffer_new(thumb_width, thumb_height);
103 if (!resize_img_ee) {
104 thumb_err("ecore_evas_buffer_new failed");
105 return MS_MEDIA_ERR_INTERNAL;
108 Evas *resize_img_e = ecore_evas_get(resize_img_ee);
110 thumb_err("ecore_evas_get failed");
111 ecore_evas_free(resize_img_ee);
112 return MS_MEDIA_ERR_INTERNAL;
115 Evas_Object *source_img = evas_object_image_add(resize_img_e);
117 thumb_err("evas_object_image_add failed");
118 ecore_evas_free(resize_img_ee);
119 return MS_MEDIA_ERR_INTERNAL;
122 evas_object_image_size_set(source_img, thumb_info->origin_width, thumb_info->origin_height);
123 evas_object_image_colorspace_set(source_img, EVAS_COLORSPACE_ARGB8888);
124 evas_object_image_fill_set(source_img, 0, 0, thumb_info->origin_width, thumb_info->origin_height);
125 evas_object_image_filled_set(source_img, EINA_TRUE);
127 evas_object_image_data_set(source_img, (int *)image);
128 evas_object_image_data_update_add(source_img, 0, 0, thumb_info->origin_width, thumb_info->origin_height);
130 if (thumb_info->origin_width * thumb_info->origin_height > THUMB_MAX_ALLOWED_MEM_FOR_THUMB) {
131 thumb_warn("This is too large image. so this's scale is going to be down");
132 evas_object_image_load_scale_down_set(source_img, 10);
135 ecore_evas_resize(resize_img_ee, thumb_width, thumb_height);
137 evas_object_image_load_size_set(source_img, thumb_width, thumb_height);
138 evas_object_image_fill_set(source_img, 0, 0, thumb_width, thumb_height);
139 evas_object_image_filled_set(source_img, EINA_TRUE);
141 evas_object_resize(source_img, thumb_width, thumb_height);
142 evas_object_show(source_img);
144 /* Set alpha from original */
145 thumb_info->alpha = evas_object_image_alpha_get(source_img);
146 if (thumb_info->alpha)
147 ecore_evas_alpha_set(resize_img_ee, EINA_TRUE);
149 /* Create target buffer and copy origin resized img to it */
150 Ecore_Evas *target_ee = ecore_evas_buffer_new(thumb_width, thumb_height);
152 thumb_err("ecore_evas_buffer_new failed");
153 ecore_evas_free(resize_img_ee);
154 return MS_MEDIA_ERR_INTERNAL;
157 Evas *target_evas = ecore_evas_get(target_ee);
159 thumb_err("ecore_evas_get failed");
160 ecore_evas_free(resize_img_ee);
161 ecore_evas_free(target_ee);
162 return MS_MEDIA_ERR_INTERNAL;
165 Evas_Object *ret_image = evas_object_image_add(target_evas);
166 evas_object_image_size_set(ret_image, thumb_width, thumb_height);
167 evas_object_image_fill_set(ret_image, 0, 0, thumb_width, thumb_height);
168 evas_object_image_filled_set(ret_image, EINA_TRUE);
170 evas_object_image_data_set(ret_image, (int *)ecore_evas_buffer_pixels_get(resize_img_ee));
171 evas_object_image_data_update_add(ret_image, 0, 0, thumb_width, thumb_height);
173 unsigned int buf_size = 0;
174 if (__media_thumb_get_buffer_size(IMAGE_UTIL_COLORSPACE_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) {
175 thumb_err("__media_thumb_get_buffer_size failed");
177 ecore_evas_free(resize_img_ee);
178 ecore_evas_free(target_ee);
180 return MS_MEDIA_ERR_INTERNAL;
183 thumb_info->size = buf_size;
184 thumb_info->width = thumb_width;
185 thumb_info->height = thumb_height;
186 thumb_info->data = malloc(buf_size);
187 if (thumb_info->data == NULL) {
188 thumb_err("Failed to allocate memory");
189 ecore_evas_free(resize_img_ee);
190 ecore_evas_free(target_ee);
192 return MS_MEDIA_ERR_OUT_OF_MEMORY;
195 void *image_data = evas_object_image_data_get(ret_image, EINA_TRUE);
196 if (image_data != NULL) {
197 memcpy(thumb_info->data, image_data, buf_size);
199 thumb_err("image_data is NULL. evas_object_image_data_get failed");
202 ecore_evas_free(target_ee);
203 ecore_evas_free(resize_img_ee);
205 thumb_dbg("_media_thumb_resize_with_evas success");
207 return MS_MEDIA_ERR_NONE;
210 int _media_thumb_rotate_argb(unsigned char *source, const unsigned int size, int format, int *ori_width, int *ori_height)
212 int dpp = 0; /* data per pixel */
215 int width = 0, height = 0;
216 unsigned char *temp_buf = NULL;
218 if (format == IMAGE_UTIL_COLORSPACE_BGRA8888) {
220 } else if (format == IMAGE_UTIL_COLORSPACE_RGB888) {
223 thumb_err("Invalid parameter");
224 return MS_MEDIA_ERR_INVALID_PARAMETER;
227 temp_buf = malloc(size);
228 if (temp_buf == NULL) {
229 thumb_err("Failed to allocate memory");
230 return MS_MEDIA_ERR_OUT_OF_MEMORY;
233 memset(temp_buf, 0x00, size);
235 height = *ori_height;
237 /* rotate image to 90 degree clockwise */
238 for (y = 0; y < height; y++) {
239 for (x = 0; x < width; x++) {
240 for (i = 0; i < dpp; i++) {
241 temp_buf[(x * height + (height - y - 1)) * dpp + i] = source[(y * width + x) * dpp + i];
246 /* copy image from temp buffer to original buffer */
247 memcpy(source, temp_buf, size);
250 /* swap width & height due to rotate 90 degree */
254 return MS_MEDIA_ERR_NONE;
257 int _media_thumb_rotate_thumb(unsigned char *data, int size, int *width, int *height, int orientation, int format)
259 int err = MS_MEDIA_ERR_NONE;
260 int i = 0, count = 0;
262 if (orientation == IMAGE_UTIL_ROTATION_90) {
264 } else if (orientation == IMAGE_UTIL_ROTATION_180) {
266 } else if (orientation == IMAGE_UTIL_ROTATION_270) {
270 for (i = 0; i < count; i++) {
271 err = _media_thumb_rotate_argb(data, size, format, width, height);
272 if (err != MS_MEDIA_ERR_NONE) {
273 thumb_err("Failed to rotate video thumbnail %d", err);
276 // thumb_dbg("[%d rotate] width:%d, height:%d", (i + 1) * 90, thumb_info->width, thumb_info->height);
279 thumb_dbg("_media_thumb_rotate_thumb success");
280 return MS_MEDIA_ERR_NONE;
283 int _media_thumb_get_proper_thumb_size(int orig_w, int orig_h, int *thumb_w, int *thumb_h)
285 BOOL portrait = FALSE;
288 if (orig_w < orig_h) {
292 /* Set smaller length to default size */
294 if (orig_w < *thumb_w)
296 ratio = (double)orig_h / (double)orig_w;
297 *thumb_h = *thumb_w * ratio;
299 if (orig_h < *thumb_h)
301 ratio = (double)orig_w / (double)orig_h;
302 *thumb_w = *thumb_h * ratio;
305 /** CAUTION :: The width of RGB888 raw data has to be rounded by 8 **/
306 *thumb_w = MEDIA_THUMB_ROUND_UP_8(*thumb_w);
308 thumb_dbg("proper thumb w: %d h: %d", *thumb_w, *thumb_h);
310 return MS_MEDIA_ERR_NONE;
313 int _media_thumb_get_exif_info(ExifData *ed, int *value, int ifdtype, long tagtype)
320 return MS_MEDIA_ERR_INVALID_PARAMETER;
326 entry = exif_content_get_entry(ed->ifd[ifd], tag);
328 if (tag == EXIF_TAG_ORIENTATION ||
329 tag == EXIF_TAG_PIXEL_X_DIMENSION ||
330 tag == EXIF_TAG_PIXEL_Y_DIMENSION) {
333 thumb_err("value is NULL");
334 return MS_MEDIA_ERR_INVALID_PARAMETER;
337 ExifByteOrder mByteOrder = exif_data_get_byte_order(ed);
338 short exif_value = exif_get_short(entry->data, mByteOrder);
339 *value = (int)exif_value;
343 return MS_MEDIA_ERR_NONE;
346 static int __media_thumb_safe_atoi(char *buffer, int *si)
350 thumb_retvm_if(buffer == NULL || si == NULL, MS_MEDIA_ERR_INTERNAL, "invalid parameter");
352 const long sl = strtol(buffer, &end, 10);
354 thumb_retvm_if(end == buffer, MS_MEDIA_ERR_INTERNAL, "not a decimal number");
355 thumb_retvm_if('\0' != *end, MS_MEDIA_ERR_INTERNAL, "extra characters at end of input: %s", end);
356 thumb_retvm_if((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno), MS_MEDIA_ERR_INTERNAL, "out of range of type long");
357 thumb_retvm_if(sl > INT_MAX, MS_MEDIA_ERR_INTERNAL, "greater than INT_MAX");
358 thumb_retvm_if(sl < INT_MIN, MS_MEDIA_ERR_INTERNAL, "less than INT_MIN");
362 return MS_MEDIA_ERR_NONE;
365 static int _media_thumb_get_data_from_exif(ExifData *ed,
377 ExifByteOrder byte_order = exif_data_get_byte_order(ed);
380 tag = EXIF_TAG_COMPRESSION;
382 entry = exif_content_get_entry(ed->ifd[ifd], tag);
385 /* Get the contents of the tag in human-readable form */
386 ExifShort value = exif_get_short(entry->data, byte_order);
387 //thumb_dbg("%s: %d", exif_tag_get_name_in_ifd(tag,ifd), value);
390 thumb_dbg("There's jpeg thumb in this image");
392 thumb_dbg("There's NO jpeg thumb in this image");
393 return MS_MEDIA_ERR_INVALID_PARAMETER;
396 thumb_dbg("entry is NULL");
397 return MS_MEDIA_ERR_INVALID_PARAMETER;
400 /* copy the real thumbnail data from exif data */
401 if (ed->data && ed->size) {
402 /* NOTICE : ExifData->size type is unsigned int, But Internal IPC, and CAPI use int */
403 if (ed->size > INT_MAX) {
404 thumb_err("EXIF thumbnail size is over INT_MAX");
405 return MS_MEDIA_ERR_THUMB_TOO_BIG;
408 *thumb_data = (char *)malloc(ed->size);
410 if (*thumb_data == NULL) {
411 thumb_dbg("malloc failed!");
412 return MS_MEDIA_ERR_INVALID_PARAMETER;
415 memcpy(*thumb_data, (void *)ed->data, ed->size);
416 *thumb_size = ed->size;
418 thumb_dbg("data is NULL");
419 return MS_MEDIA_ERR_INVALID_PARAMETER;
422 /* Get width and height of thumbnail */
423 tag = EXIF_TAG_IMAGE_WIDTH;
424 entry = exif_content_get_entry(ed->ifd[ifd], tag);
427 /* Get the contents of the tag in human-readable form */
428 char width[10] = {0,};
429 exif_entry_get_value(entry, width, 10);
430 __media_thumb_safe_atoi(width, thumb_width);
432 thumb_warn("EXIF_TAG_IMAGE_WIDTH does not exist");
436 tag = EXIF_TAG_IMAGE_LENGTH;
437 entry = exif_content_get_entry(ed->ifd[ifd], tag);
439 /* Get the contents of the tag in human-readable form */
440 char height[10] = {0, };
441 exif_entry_get_value(entry, height, 10);
442 __media_thumb_safe_atoi(height, thumb_height);
444 thumb_warn("EXIF_TAG_IMAGE_LENGTH does not exist");
448 thumb_dbg("thumb width : height [%d:%d]", *thumb_width, *thumb_height);
450 /* Get width and height of original image from exif */
452 tag = EXIF_TAG_PIXEL_X_DIMENSION;
453 entry = exif_content_get_entry(ed->ifd[ifd], tag);
456 char width[10] = {0,};
457 exif_entry_get_value(entry, width, 10);
458 __media_thumb_safe_atoi(width, origin_width);
460 thumb_warn("EXIF_TAG_PIXEL_X_DIMENSION does not exist");
464 tag = EXIF_TAG_PIXEL_Y_DIMENSION;
465 entry = exif_content_get_entry(ed->ifd[ifd], tag);
468 char height[10] = {0, };
469 exif_entry_get_value(entry, height, 10);
470 __media_thumb_safe_atoi(height, origin_height);
472 thumb_warn("EXIF_TAG_PIXEL_Y_DIMENSION does not exist");
476 return MS_MEDIA_ERR_NONE;
479 static int __media_thumb_decode_jpeg(unsigned char *src, unsigned long long size, image_util_colorspace_e colorspace, unsigned char **dst, unsigned long *width, unsigned long *height, unsigned long long *dst_size)
481 int err = IMAGE_UTIL_ERROR_NONE;
482 image_util_decode_h decoder = NULL;
484 err = image_util_decode_create(&decoder);
485 if (err != IMAGE_UTIL_ERROR_NONE) {
486 thumb_err("image_util_decode_create failed! (%d)", err);
487 return MS_MEDIA_ERR_INTERNAL;
490 err = image_util_decode_set_input_buffer(decoder, src, size);
491 if (err != IMAGE_UTIL_ERROR_NONE) {
492 thumb_err("image_util_decode_set_input_buffer failed! (%d)", err);
493 image_util_decode_destroy(decoder);
494 return MS_MEDIA_ERR_INTERNAL;
497 err = image_util_decode_set_colorspace(decoder, colorspace);
498 if (err != IMAGE_UTIL_ERROR_NONE) {
499 thumb_err("image_util_decode_set_colorspace failed! (%d)", err);
500 image_util_decode_destroy(decoder);
501 return MS_MEDIA_ERR_INTERNAL;
504 err = image_util_decode_set_output_buffer(decoder, dst);
505 if (err != IMAGE_UTIL_ERROR_NONE) {
506 thumb_err("image_util_decode_set_output_buffer failed! (%d)", err);
507 image_util_decode_destroy(decoder);
508 return MS_MEDIA_ERR_INTERNAL;
511 err = image_util_decode_run(decoder, width, height, dst_size);
512 if (err != IMAGE_UTIL_ERROR_NONE) {
513 thumb_err("image_util_decode_run failed! (%d)", err);
514 image_util_decode_destroy(decoder);
515 return MS_MEDIA_ERR_INTERNAL;
518 err = image_util_decode_destroy(decoder);
519 if (err != IMAGE_UTIL_ERROR_NONE) {
520 thumb_err("image_util_decode_destroy failed! (%d)", err);
521 return MS_MEDIA_ERR_INTERNAL;
524 return MS_MEDIA_ERR_NONE;
528 int _media_thumb_get_thumb_from_exif(ExifData *ed,
529 const char *file_full_path,
530 const char *thumb_path,
534 media_thumb_info *thumb_info)
536 int err = MS_MEDIA_ERR_NONE;
539 int thumb_height = 0;
540 unsigned long long thumb_size = 0;
541 unsigned char *raw_image = NULL;
542 int origin_width = 0;
543 int origin_height = 0;
545 bool is_rotated = (orientation == ROT_90 || orientation == ROT_180 || orientation == ROT_270) ? TRUE : FALSE;
548 return MS_MEDIA_ERR_INVALID_PARAMETER;
551 err = _media_thumb_get_data_from_exif(ed,
559 if (err != MS_MEDIA_ERR_NONE) {
560 thumb_err("There is no exif data");
564 thumb_dbg("thumb width : height [%d:%d]", thumb_width, thumb_height);
565 thumb_dbg("origin width : height [%d:%d]", origin_width, origin_height);
566 thumb_info->origin_height = origin_height;
567 thumb_info->origin_width = origin_width;
569 if (thumb_width < required_width) {
570 thumb_err("Thumb data in exif is too small");
572 return MS_MEDIA_ERR_INVALID_PARAMETER;
576 err = __media_thumb_decode_jpeg(thumb, size, IMAGE_UTIL_COLORSPACE_RGB888, &raw_image, (unsigned long *)&thumb_width, (unsigned long *)&thumb_height, &thumb_size);
578 if (err != MS_MEDIA_ERR_NONE) {
579 thumb_err("__media_thumb_decode_jpeg failed : %d", err);
583 int rot_type = IMAGE_UTIL_ROTATION_NONE;
584 if (orientation == ROT_90) {
585 rot_type = IMAGE_UTIL_ROTATION_90;
586 } else if (orientation == ROT_180) {
587 rot_type = IMAGE_UTIL_ROTATION_180;
588 } else if (orientation == ROT_270) {
589 rot_type = IMAGE_UTIL_ROTATION_270;
591 err = _media_thumb_rotate_thumb(raw_image, thumb_size, &thumb_width, &thumb_height, rot_type, IMAGE_UTIL_COLORSPACE_RGB888);
592 if (err != MS_MEDIA_ERR_NONE) {
593 thumb_err("_media_thumb_rotate_thumb falied: %d", err);
594 SAFE_FREE(thumb_info->data);
595 SAFE_FREE(raw_image);
599 thumb_info->data = raw_image;
600 thumb_info->size = thumb_size;
601 thumb_info->width = thumb_width;
602 thumb_info->height = thumb_height;
604 /*in this case, just write raw data in file */
605 thumb_dbg_slog("Thumb is :%s", thumb_path);
608 int fd = open(thumb_path, O_RDWR | O_CREAT | O_EXCL | O_SYNC, 0644);
610 if (errno == EEXIST) {
611 thumb_err("thumb alread exist!");
613 thumb_err("open failed");
615 return MS_MEDIA_ERR_INVALID_PARAMETER;
618 nwrite = write(fd, thumb, size);
620 thumb_err("write failed");
624 return MS_MEDIA_ERR_INVALID_PARAMETER;
630 thumb_info->data = NULL;
631 thumb_info->size = size;
632 thumb_info->width = thumb_width;
633 thumb_info->height = thumb_height;
634 thumb_info->is_saved = TRUE;
640 int _media_thumb_get_wh_with_evas(const char *origin_path, int *width, int *height)
642 /* using evas to get w/h */
643 Ecore_Evas *ee = ecore_evas_buffer_new(0, 0);
645 thumb_err("ecore_evas_buffer_new fails");
646 return MS_MEDIA_ERR_INTERNAL;
649 Evas *evas = ecore_evas_get(ee);
651 thumb_err("ecore_evas_get fails");
653 return MS_MEDIA_ERR_INTERNAL;
656 Evas_Object *image_object = evas_object_image_add(evas);
658 thumb_err("evas_object_image_add fails");
660 return MS_MEDIA_ERR_INTERNAL;
663 evas_object_image_file_set(image_object, origin_path, NULL);
664 evas_object_image_size_get(image_object, width, height);
666 thumb_dbg("Width:%d, Height:%d", *width, *height);
670 return MS_MEDIA_ERR_NONE;
673 int _media_thumb_decode_with_evas(const char *origin_path,
674 int thumb_width, int thumb_height,
675 media_thumb_info *thumb_info, int need_scale, int orientation)
677 Ecore_Evas *resize_img_ee;
679 resize_img_ee = ecore_evas_buffer_new(thumb_width, thumb_height);
680 if (!resize_img_ee) {
681 thumb_err("ecore_evas_buffer_new failed");
682 return MS_MEDIA_ERR_INTERNAL;
685 Evas *resize_img_e = ecore_evas_get(resize_img_ee);
687 thumb_err("ecore_evas_get failed");
688 ecore_evas_free(resize_img_ee);
689 return MS_MEDIA_ERR_INTERNAL;
692 Evas_Object *source_img = evas_object_image_add(resize_img_e);
694 thumb_err("evas_object_image_add failed");
695 ecore_evas_free(resize_img_ee);
696 return MS_MEDIA_ERR_INTERNAL;
699 evas_object_image_file_set(source_img, origin_path, NULL);
701 /* Get w/h of original image */
705 evas_object_image_size_get(source_img, &width, &height);
706 thumb_info->origin_width = width;
707 thumb_info->origin_height = height;
708 //thumb_dbg("origin width:%d, origin height:%d", width, height);
710 /* This case for only JPEG format.. JPEG can be partially processed.. */
711 if ((need_scale == 1) && (width * height > THUMB_MAX_ALLOWED_MEM_FOR_THUMB)) {
712 thumb_warn("This is too large image. so this's scale is going to be down");
713 evas_object_image_load_scale_down_set(source_img, 10);
716 if (orientation != TRANSPOSE)
717 evas_object_image_load_orientation_set(source_img, 1);
719 int rotated_orig_w = 0;
720 int rotated_orig_h = 0;
722 if (orientation == ROT_90 || orientation == ROT_270) {
723 rotated_orig_w = height;
724 rotated_orig_h = width;
726 rotated_orig_w = width;
727 rotated_orig_h = height;
729 //thumb_dbg("rotated - origin width:%d, origin height:%d", rotated_orig_w, rotated_orig_h);
731 int err = MS_MEDIA_ERR_NONE;
733 err = _media_thumb_get_proper_thumb_size(rotated_orig_w, rotated_orig_h, &thumb_width, &thumb_height);
734 if (err != MS_MEDIA_ERR_NONE) {
735 thumb_err("_media_thumb_get_proper_thumb_size failed: %d", err);
736 ecore_evas_free(resize_img_ee);
740 ecore_evas_resize(resize_img_ee, thumb_width, thumb_height);
742 evas_object_image_load_size_set(source_img, thumb_width, thumb_height);
743 evas_object_image_fill_set(source_img, 0, 0, thumb_width, thumb_height);
744 evas_object_image_filled_set(source_img, 1);
746 evas_object_resize(source_img, thumb_width, thumb_height);
747 evas_object_show(source_img);
749 /* Set alpha from original */
750 thumb_info->alpha = evas_object_image_alpha_get(source_img);
751 if (thumb_info->alpha) ecore_evas_alpha_set(resize_img_ee, EINA_TRUE);
753 /* Create target buffer and copy origin resized img to it */
754 Ecore_Evas *target_ee = ecore_evas_buffer_new(thumb_width, thumb_height);
756 thumb_err("ecore_evas_buffer_new failed");
757 ecore_evas_free(resize_img_ee);
758 return MS_MEDIA_ERR_INTERNAL;
761 Evas *target_evas = ecore_evas_get(target_ee);
763 thumb_err("ecore_evas_get failed");
764 ecore_evas_free(resize_img_ee);
765 ecore_evas_free(target_ee);
766 return MS_MEDIA_ERR_INTERNAL;
769 Evas_Object *ret_image = evas_object_image_add(target_evas);
770 evas_object_image_size_set(ret_image, thumb_width, thumb_height);
771 evas_object_image_fill_set(ret_image, 0, 0, thumb_width, thumb_height);
772 evas_object_image_filled_set(ret_image, EINA_TRUE);
774 evas_object_image_data_set(ret_image, (int *)ecore_evas_buffer_pixels_get(resize_img_ee));
775 evas_object_image_data_update_add(ret_image, 0, 0, thumb_width, thumb_height);
777 unsigned int buf_size = 0;
778 if (__media_thumb_get_buffer_size(IMAGE_UTIL_COLORSPACE_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) {
779 thumb_err("__media_thumb_get_buffer_size failed");
781 ecore_evas_free(resize_img_ee);
782 ecore_evas_free(target_ee);
784 return MS_MEDIA_ERR_INTERNAL;
786 //thumb_dbg("__media_thumb_get_buffer_size : %d", buf_size);
788 thumb_info->size = buf_size;
789 thumb_info->width = thumb_width;
790 thumb_info->height = thumb_height;
791 thumb_info->data = malloc(buf_size);
792 if (thumb_info->data == NULL) {
793 thumb_err("Failed to allocate memory");
794 ecore_evas_free(resize_img_ee);
795 ecore_evas_free(target_ee);
797 return MS_MEDIA_ERR_OUT_OF_MEMORY;
800 void *image_data = evas_object_image_data_get(ret_image, 1);
801 if (image_data != NULL) {
802 memcpy(thumb_info->data, image_data, buf_size);
804 thumb_err("image_data is NULL. evas_object_image_data_get failed");
807 ecore_evas_free(target_ee);
808 ecore_evas_free(resize_img_ee);
813 int _media_thumb_convert_data(media_thumb_info *thumb_info, int thumb_width, int thumb_height)
815 int err = MS_MEDIA_ERR_NONE;
816 unsigned int buf_size = 0;
817 unsigned char *src_data = thumb_info->data;
818 unsigned char *dst_data = NULL;
821 if (__media_thumb_get_buffer_size(IMAGE_UTIL_COLORSPACE_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) {
822 thumb_err("__media_thumb_get_buffer_size failed");
823 return MS_MEDIA_ERR_INTERNAL;
826 thumb_dbg("__media_thumb_get_buffer_size : %d", buf_size);
828 dst_data = (unsigned char *)malloc(buf_size);
829 if (dst_data == NULL) {
830 thumb_err("Failed to allocate memory");
831 return MS_MEDIA_ERR_OUT_OF_MEMORY;
834 for (j = 0; j < thumb_width * 3 * thumb_height; j += 3) {
835 dst_data[i++] = (src_data[j + 2]);
836 dst_data[i++] = (src_data[j + 1]);
837 dst_data[i++] = (src_data[j]);
841 SAFE_FREE(thumb_info->data);
842 thumb_info->data = dst_data;
843 thumb_info->size = buf_size;
845 thumb_dbg("_media_thumb_convert_data success");
850 int _media_thumb_agif(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
852 int err = MS_MEDIA_ERR_NONE;
853 unsigned int *thumb = NULL;
854 unsigned char *dst_image = NULL;
855 unsigned int dst_size = 0;
856 unsigned int thumb_size = 0;
858 thumb = ImgGetFirstFrameAGIFAtSize(origin_path, thumb_info->origin_width, thumb_info->origin_height);
860 thumb_err("Frame data is NULL!!");
861 return MS_MEDIA_ERR_INTERNAL;
864 err = __media_thumb_get_buffer_size(IMAGE_UTIL_COLORSPACE_RGB888, thumb_info->origin_width, thumb_info->origin_height, &thumb_size);
865 if (err != MS_MEDIA_ERR_NONE) {
866 thumb_err("__media_thumb_get_buffer_size failed: %d", err);
871 err = _media_thumb_get_proper_thumb_size(thumb_info->origin_width, thumb_info->origin_height, &thumb_width, &thumb_height);
872 if (err != MS_MEDIA_ERR_NONE) {
873 thumb_err("_media_thumb_get_proper_thumb_size failed: %d", err);
878 err = _media_thumb_rgb_to_argb((unsigned char *) thumb, thumb_size, &dst_image, &dst_size, thumb_info->origin_width, thumb_info->origin_height);
879 if (err != MS_MEDIA_ERR_NONE) {
880 thumb_err("_media_thumb_convert_data falied: %d", err);
885 err = _media_thumb_resize_with_evas(dst_image, thumb_width, thumb_height, thumb_info);
886 if (err != MS_MEDIA_ERR_NONE) {
887 thumb_err("_media_thumb_resize_data failed: %d", err);
888 SAFE_FREE(thumb_info->data);
898 int _media_thumb_general(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
900 int err = MS_MEDIA_ERR_NONE;
902 err = _media_thumb_decode_with_evas(origin_path, thumb_width, thumb_height, thumb_info, 1, NORMAL);
903 if (err != MS_MEDIA_ERR_NONE) {
904 thumb_err("decode_with_evas failed : %d", err);
911 int _media_thumb_jpeg(const char *origin_path, const char *thumb_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
913 int err = MS_MEDIA_ERR_NONE;
915 int orientation = NORMAL;
918 if (!thumb_info->is_raw) {
919 /* Load an ExifData object from an EXIF file */
920 ed = exif_data_new_from_file(origin_path);
923 /* First, Get orientation from exif */
924 err = _media_thumb_get_exif_info(ed, &orientation, EXIF_IFD_0, EXIF_TAG_ORIENTATION);
925 if (err != MS_MEDIA_ERR_NONE) {
926 thumb_warn("_media_thumb_get_exif_info failed");
929 /* Second, Get thumb from exif */
930 err = _media_thumb_get_thumb_from_exif(ed, origin_path, thumb_path, orientation, thumb_width, thumb_height, thumb_info);
931 if (err != MS_MEDIA_ERR_NONE) {
932 thumb_dbg("_media_thumb_get_thumb_from_exif failed");
935 thumb_dbg("_media_thumb_get_thumb_from_exif succeed");
937 /* The case that original image's size is not in exif header. Use evas to get w/h */
938 if (thumb_info->origin_width == 0 || thumb_info->origin_height == 0) {
939 thumb_warn("original image's size is not in exif header. Use evas to get w/h");
940 err = _media_thumb_get_wh_with_evas(origin_path, &(thumb_info->origin_width), &(thumb_info->origin_height));
941 if (err != MS_MEDIA_ERR_NONE) {
942 thumb_err("Couldn't get w/h using evas : %s", origin_path);
944 thumb_dbg("origin w : %d, origin h : %d", thumb_info->origin_width, thumb_info->origin_height);
948 if (thumb_info->is_saved == FALSE) {
949 err = _media_thumb_convert_data(thumb_info, thumb_info->width, thumb_info->height);
950 if (err != MS_MEDIA_ERR_NONE) {
951 thumb_err("_media_thumb_convert_data failed : %d", err);
961 ed = exif_data_new_from_file(origin_path);
963 err = _media_thumb_get_exif_info(ed, &orientation, EXIF_IFD_0, EXIF_TAG_ORIENTATION);
964 if (err != MS_MEDIA_ERR_NONE) {
965 thumb_warn("_media_thumb_get_exif_info failed");
972 err = _media_thumb_decode_with_evas(origin_path, thumb_width, thumb_height, thumb_info, 1, orientation);
973 if (err != MS_MEDIA_ERR_NONE) {
974 thumb_err("decode_with_evas failed : %d", err);
982 int _media_thumb_image(const char *origin_path, const char *thumb_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
984 int err = MS_MEDIA_ERR_NONE;
985 ImgCodecType image_type = 0;
986 unsigned int origin_w = 0;
987 unsigned int origin_h = 0;
989 err = ImgGetImageInfoForThumb(origin_path, &image_type, &origin_w, &origin_h);
990 if (err != MS_MEDIA_ERR_NONE) {
991 thumb_warn("Getting image info is failed err: %d", err);
994 thumb_info->origin_width = origin_w;
995 thumb_info->origin_height = origin_h;
997 if ((image_type != IMG_CODEC_JPEG) && (origin_w * origin_h > THUMB_MAX_ALLOWED_MEM_FOR_THUMB)) {
998 thumb_warn("This original image is too big");
999 return MS_MEDIA_ERR_THUMB_TOO_BIG;
1002 if (image_type == IMG_CODEC_AGIF) {
1003 err = _media_thumb_agif(origin_path, thumb_width, thumb_height, thumb_info);
1004 } else if (image_type == IMG_CODEC_JPEG) {
1005 err = _media_thumb_jpeg(origin_path, thumb_path, thumb_width, thumb_height, thumb_info);
1006 } else if (image_type == IMG_CODEC_PNG || image_type == IMG_CODEC_GIF || image_type == IMG_CODEC_BMP || image_type == IMG_CODEC_WBMP) {
1007 err = _media_thumb_general(origin_path, thumb_width, thumb_height, thumb_info);
1009 thumb_warn("Unsupported image type");
1010 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
1016 int _media_thumb_video(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info)
1018 int err = MS_MEDIA_ERR_NONE;
1020 MMHandleType content = (MMHandleType) NULL;
1022 int video_track_num = 0;
1023 char *err_msg = NULL;
1028 bool drm_type = FALSE;
1032 /* Get Content Tag attribute for orientatin */
1033 MMHandleType tag = (MMHandleType) NULL;
1036 err = mm_file_create_tag_attrs(&tag, origin_path);
1037 image_util_rotation_e rot_type = IMAGE_UTIL_ROTATION_NONE;
1039 if (err == FILEINFO_ERROR_NONE) {
1040 err = mm_file_get_attrs(tag, &err_msg, MM_FILE_TAG_ROTATE, &p, &size, NULL);
1041 if (err == FILEINFO_ERROR_NONE && size >= 0) {
1043 rot_type = IMAGE_UTIL_ROTATION_NONE;
1045 if (strncmp(p, "90", size) == 0) {
1046 rot_type = IMAGE_UTIL_ROTATION_90;
1047 } else if (strncmp(p, "180", size) == 0) {
1048 rot_type = IMAGE_UTIL_ROTATION_180;
1049 } else if (strncmp(p, "270", size) == 0) {
1050 rot_type = IMAGE_UTIL_ROTATION_270;
1052 rot_type = IMAGE_UTIL_ROTATION_NONE;
1055 thumb_dbg("There is tag rotate : %d", rot_type);
1057 thumb_dbg("There is NOT tag rotate");
1058 rot_type = IMAGE_UTIL_ROTATION_NONE;
1062 err = mm_file_get_attrs(tag, &err_msg, MM_FILE_TAG_CDIS, &cdis_value, NULL);
1063 if (err != FILEINFO_ERROR_NONE) {
1069 rot_type = IMAGE_UTIL_ROTATION_NONE;
1073 err = mm_file_destroy_tag_attrs(tag);
1074 if (err != FILEINFO_ERROR_NONE) {
1075 thumb_err("fail to free tag attr - err(%x)", err);
1078 if (cdis_value == 1) {
1079 thumb_warn("This is CDIS vlaue 1");
1080 err = mm_file_create_content_attrs_safe(&content, origin_path);
1082 err = mm_file_create_content_attrs(&content, origin_path);
1085 if (err != FILEINFO_ERROR_NONE) {
1086 thumb_err("mm_file_create_content_attrs fails : %d", err);
1087 return MS_MEDIA_ERR_INTERNAL;
1090 err = mm_file_get_attrs(content, &err_msg, MM_FILE_CONTENT_VIDEO_TRACK_COUNT, &video_track_num, NULL);
1091 if (err != FILEINFO_ERROR_NONE) {
1092 thumb_err("mm_file_get_attrs fails : %s", err_msg);
1094 mm_file_destroy_content_attrs(content);
1095 return MS_MEDIA_ERR_INTERNAL;
1098 /* MMF api handle both normal and DRM video */
1099 if (video_track_num > 0 || is_drm) {
1100 err = mm_file_get_attrs(content, &err_msg,
1101 MM_FILE_CONTENT_VIDEO_WIDTH,
1103 MM_FILE_CONTENT_VIDEO_HEIGHT,
1105 MM_FILE_CONTENT_VIDEO_THUMBNAIL, &frame, /* raw image is RGB888 format */
1108 if (err != FILEINFO_ERROR_NONE) {
1109 thumb_err("mm_file_get_attrs fails : %s", err_msg);
1111 mm_file_destroy_content_attrs(content);
1112 return MS_MEDIA_ERR_INTERNAL;
1115 thumb_dbg("video width: %d", width);
1116 thumb_dbg("video height: %d", height);
1117 thumb_dbg("thumbnail size: %d", size);
1118 thumb_dbg("frame: %p", frame);
1119 thumb_dbg("orientation: %d", rot_type);
1121 if (frame == NULL || width == 0 || height == 0) {
1122 thumb_err("Failed to get frame data");
1123 mm_file_destroy_content_attrs(content);
1124 return MS_MEDIA_ERR_INTERNAL;
1127 thumb_info->origin_width = width;
1128 thumb_info->origin_height = height;
1130 err = _media_thumb_get_proper_thumb_size(width, height, &thumb_width, &thumb_height);
1132 unsigned int new_size = 0;
1133 unsigned char *new_frame = NULL;
1134 err = _media_thumb_rgb_to_argb(frame, size, &new_frame, &new_size, width, height);
1135 if ((err != MS_MEDIA_ERR_NONE) || (new_frame == NULL)) {
1136 thumb_err("_media_thumb_convert_video falied: %d", err);
1137 mm_file_destroy_content_attrs(content);
1138 SAFE_FREE(new_frame);
1141 mm_file_destroy_content_attrs(content);
1142 thumb_dbg("original size - width:%d, height:%d", width, height);
1143 thumb_dbg("proper thumb size - width:%d, height:%d", thumb_width, thumb_height);
1144 if (width > thumb_width || height > thumb_height) {
1145 err = _media_thumb_resize_with_evas(new_frame, thumb_width, thumb_height, thumb_info);
1146 if (err != MS_MEDIA_ERR_NONE) {
1147 thumb_err("_media_thumb_resize_video_with_evas falied: %d", err);
1148 SAFE_FREE(new_frame);
1152 thumb_info->size = new_size;
1153 thumb_info->width = width;
1154 thumb_info->height = height;
1155 thumb_info->data = malloc(new_size);
1156 if (thumb_info->data == NULL) {
1157 thumb_err("memory allcation failed");
1158 SAFE_FREE(new_frame);
1159 return MS_MEDIA_ERR_OUT_OF_MEMORY;
1161 memcpy(thumb_info->data, new_frame, new_size);
1163 SAFE_FREE(new_frame);
1165 if (rot_type == IMAGE_UTIL_ROTATION_90 || rot_type == IMAGE_UTIL_ROTATION_180 || rot_type == IMAGE_UTIL_ROTATION_270) {
1166 err = _media_thumb_rotate_thumb(thumb_info->data, thumb_info->size, &(thumb_info->width), &(thumb_info->height), rot_type, IMAGE_UTIL_COLORSPACE_BGRA8888);
1167 if (err != MS_MEDIA_ERR_NONE) {
1168 thumb_err("_media_thumb_rotate_thumb falied: %d", err);
1169 SAFE_FREE(thumb_info->data);
1174 thumb_dbg("no contents information");
1176 mm_file_destroy_content_attrs(content);
1178 return MS_MEDIA_ERR_INTERNAL;
1184 int _media_thumb_get_hash_name(const char *file_full_path, char *thumb_hash_path, size_t max_thumb_path, uid_t uid)
1186 char *hash_name = NULL;
1187 /*char *thumb_dir = NULL;*/
1188 char file_ext[255] = { 0 };
1189 char *get_path = NULL;
1191 ms_user_storage_type_e storage_type = -1;
1192 int ret = MS_MEDIA_ERR_NONE;
1194 if (file_full_path == NULL || thumb_hash_path == NULL || max_thumb_path <= 0) {
1195 thumb_err("file_full_path==NULL || thumb_hash_path == NULL || max_thumb_path <= 0");
1196 return MS_MEDIA_ERR_INVALID_PARAMETER;
1199 _media_thumb_get_file_ext(file_full_path, file_ext, sizeof(file_ext));
1201 ret = ms_user_get_storage_type(uid, file_full_path, &storage_type);
1202 if ((ret != MS_MEDIA_ERR_NONE) || ((storage_type != MS_USER_STORAGE_INTERNAL) && (storage_type != MS_USER_STORAGE_EXTERNAL))) {
1203 thumb_err_slog("origin path(%s) is invalid. err : [%d] storage_type [%d]", file_full_path, ret, storage_type);
1204 return MS_MEDIA_ERR_INVALID_PARAMETER;
1207 hash_name = _media_thumb_generate_hash_name(file_full_path);
1208 if (hash_name == NULL) {
1209 thumb_err("_media_thumb_generate_hash_name fail");
1210 return MS_MEDIA_ERR_INTERNAL;
1213 ret = ms_user_get_thumb_store_path(uid, storage_type, &get_path);
1214 if (get_path != NULL)
1215 ret_len = snprintf(thumb_hash_path, max_thumb_path - 1, "%s/.%s-%s.jpg", get_path, file_ext, hash_name);
1217 SAFE_FREE(get_path);
1219 if ((ret_len < 0) || (ret_len > (int)max_thumb_path)) {
1220 thumb_err("invalid hash path ret_len[%d]", ret_len);
1221 return MS_MEDIA_ERR_INTERNAL;
1223 //thumb_dbg("thumb hash : %s", thumb_hash_path);
1225 return MS_MEDIA_ERR_NONE;
1229 int _media_thumb_save_to_file_with_evas(unsigned char *data, int w, int h, int alpha, char *thumb_path)
1231 Ecore_Evas *ee = ecore_evas_buffer_new(w, h);
1233 thumb_err("ecore_evas_buffer_new failed");
1234 return MS_MEDIA_ERR_INTERNAL;
1237 Evas *evas = ecore_evas_get(ee);
1239 thumb_err("ecore_evas_get failed");
1240 ecore_evas_free(ee);
1241 return MS_MEDIA_ERR_INTERNAL;
1244 Evas_Object *img = NULL;
1245 img = evas_object_image_add(evas);
1248 thumb_err("evas_object_image_add failed");
1249 ecore_evas_free(ee);
1250 return MS_MEDIA_ERR_INTERNAL;
1253 evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888);
1254 evas_object_image_size_set(img, w, h);
1255 evas_object_image_fill_set(img, 0, 0, w, h);
1257 if (alpha) evas_object_image_alpha_set(img, 1);
1259 evas_object_image_data_set(img, data);
1260 evas_object_image_data_update_add(img, 0, 0, w, h);
1262 if (evas_object_image_save(img, thumb_path, NULL, "quality=90 compress=1")) {
1263 thumb_dbg("evas_object_image_save success");
1264 ecore_evas_free(ee);
1266 return MS_MEDIA_ERR_NONE;
1268 thumb_err("evas_object_image_save failed");
1269 ecore_evas_free(ee);
1270 return MS_MEDIA_ERR_INTERNAL;