/* * libmedia-thumbnail * * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: Hyunjun Ko * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "media-thumb-debug.h" #include "media-thumb-util.h" #include "media-thumb-internal.h" #include "media-thumb-ipc.h" #include "AGifFrameInfo.h" #include "IfegDecodeAGIF.h" #include "img-codec.h" #include "img-codec-agif.h" #include "img-codec-common.h" #include "img-codec-osal.h" #include "img-codec-parser.h" #include #include #include #include #include #include #include #include #include #include #include #define MEDIA_THUMB_ROUND_UP_8(num) (((num)+7)&~7) int _media_thumb_rgb_to_argb(const unsigned char *src_data, const int src_size, unsigned char **dst_data, unsigned int *buf_size, int width, int height) { int err = MS_MEDIA_ERR_NONE; int i = 0, j; if (mm_util_get_image_size(MM_UTIL_IMG_FMT_BGRA8888, width, height, buf_size) < 0) { thumb_err("mm_util_get_image_size failed"); return MS_MEDIA_ERR_INTERNAL; } thumb_dbg("mm_util_get_image_size : %d", *buf_size); *dst_data = (unsigned char *)malloc(*buf_size); if (*dst_data == NULL) { thumb_err("Failed to allocate memory"); return MS_MEDIA_ERR_OUT_OF_MEMORY; } for (j = 0; ((j < src_size) && (i < *buf_size)); j += 3) { (*dst_data)[i++] = (src_data[j + 2]); (*dst_data)[i++] = (src_data[j + 1]); (*dst_data)[i++] = (src_data[j]); (*dst_data)[i++] = 0x0; } thumb_dbg("_media_thumb_rgb_to_argb success"); return err; } int _media_thumb_resize_with_evas(const void *image, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { Ecore_Evas *resize_img_ee; if (image == NULL) { thumb_err("Invalid parameter"); return MS_MEDIA_ERR_INVALID_PARAMETER; } resize_img_ee = ecore_evas_buffer_new(thumb_width, thumb_height); if (!resize_img_ee) { thumb_err("ecore_evas_buffer_new failed"); return MS_MEDIA_ERR_INTERNAL; } Evas *resize_img_e = ecore_evas_get(resize_img_ee); if (!resize_img_e) { thumb_err("ecore_evas_get failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *source_img = evas_object_image_add(resize_img_e); if (!source_img) { thumb_err("evas_object_image_add failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } evas_object_image_size_set(source_img, thumb_info->origin_width, thumb_info->origin_height); evas_object_image_colorspace_set(source_img, EVAS_COLORSPACE_ARGB8888); evas_object_image_fill_set(source_img, 0, 0, thumb_info->origin_width, thumb_info->origin_height); evas_object_image_filled_set(source_img, EINA_TRUE); evas_object_image_data_set(source_img, (int *)image); evas_object_image_data_update_add(source_img, 0, 0, thumb_info->origin_width, thumb_info->origin_height); if (thumb_info->origin_width * thumb_info->origin_height > THUMB_MAX_ALLOWED_MEM_FOR_THUMB) { thumb_warn("This is too large image. so this's scale is going to be down"); evas_object_image_load_scale_down_set(source_img, 10); } ecore_evas_resize(resize_img_ee, thumb_width, thumb_height); evas_object_image_load_size_set(source_img, thumb_width, thumb_height); evas_object_image_fill_set(source_img, 0, 0, thumb_width, thumb_height); evas_object_image_filled_set(source_img, EINA_TRUE); evas_object_resize(source_img, thumb_width, thumb_height); evas_object_show(source_img); /* Set alpha from original */ thumb_info->alpha = evas_object_image_alpha_get(source_img); if (thumb_info->alpha) ecore_evas_alpha_set(resize_img_ee, EINA_TRUE); /* Create target buffer and copy origin resized img to it */ Ecore_Evas *target_ee = ecore_evas_buffer_new(thumb_width, thumb_height); if (!target_ee) { thumb_err("ecore_evas_buffer_new failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } Evas *target_evas = ecore_evas_get(target_ee); if (!target_evas) { thumb_err("ecore_evas_get failed"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *ret_image = evas_object_image_add(target_evas); evas_object_image_size_set(ret_image, thumb_width, thumb_height); evas_object_image_fill_set(ret_image, 0, 0, thumb_width, thumb_height); evas_object_image_filled_set(ret_image, EINA_TRUE); evas_object_image_data_set(ret_image, (int *)ecore_evas_buffer_pixels_get(resize_img_ee)); evas_object_image_data_update_add(ret_image, 0, 0, thumb_width, thumb_height); unsigned int buf_size = 0; if (mm_util_get_image_size(MM_UTIL_IMG_FMT_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) { thumb_err("mm_util_get_image_size failed"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_INTERNAL; } thumb_info->size = buf_size; thumb_info->width = thumb_width; thumb_info->height = thumb_height; thumb_info->data = malloc(buf_size); if (thumb_info->data == NULL) { thumb_err("Failed to allocate memory"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_OUT_OF_MEMORY; } void *image_data = evas_object_image_data_get(ret_image, EINA_TRUE); if (image_data != NULL) { memcpy(thumb_info->data, image_data, buf_size); } else { thumb_err("image_data is NULL. evas_object_image_data_get failed"); } ecore_evas_free(target_ee); ecore_evas_free(resize_img_ee); thumb_dbg("_media_thumb_resize_with_evas success"); return MS_MEDIA_ERR_NONE; } int _media_thumb_rotate_argb(unsigned char *source, const unsigned int size, int format, int *ori_width, int *ori_height) { int dpp = 0; /* data per pixel */ int x = 0, y = 0; int i = 0; int width = 0, height = 0; unsigned char *temp_buf = NULL; if (format == MM_UTIL_JPEG_FMT_BGRA8888) { dpp = 4; } else if (format == MM_UTIL_JPEG_FMT_RGB888) { dpp = 3; } else { thumb_err("Invalid parameter"); return MS_MEDIA_ERR_INVALID_PARAMETER; } temp_buf = malloc(size); if (temp_buf == NULL) { thumb_err("Failed to allocate memory"); return MS_MEDIA_ERR_OUT_OF_MEMORY; } /* initialize */ memset(temp_buf, 0x00, size); width = *ori_width; height = *ori_height; /* rotate image to 90 degree clockwise */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { for (i = 0; i < dpp; i++) { temp_buf[(x * height + (height - y - 1)) * dpp + i] = source[(y * width + x) * dpp + i]; } } } /* copy image from temp buffer to original buffer */ memcpy(source, temp_buf, size); SAFE_FREE(temp_buf); /* swap width & height due to rotate 90 degree */ *ori_width = height; *ori_height = width; return MS_MEDIA_ERR_NONE; } int _media_thumb_rotate_thumb(unsigned char *data, int size, int *width, int *height, int orientation, int format) { int err = MS_MEDIA_ERR_NONE; int i = 0, count = 0; if (orientation == MM_UTIL_ROTATE_90) { count = 1; } else if (orientation == MM_UTIL_ROTATE_180) { count = 2; } else if (orientation == MM_UTIL_ROTATE_270) { count = 3; } for (i = 0; i < count; i++) { err = _media_thumb_rotate_argb(data, size, format, width, height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("Failed to rotate video thumbnail %d", err); return err; } // thumb_dbg("[%d rotate] width:%d, height:%d", (i + 1) * 90, thumb_info->width, thumb_info->height); } thumb_dbg("_media_thumb_rotate_thumb success"); return MS_MEDIA_ERR_NONE; } int _media_thumb_get_proper_thumb_size(int orig_w, int orig_h, int *thumb_w, int *thumb_h) { BOOL portrait = FALSE; double ratio; if (orig_w < orig_h) { portrait = TRUE; } /* Set smaller length to default size */ if (portrait) { if (orig_w < *thumb_w) *thumb_w = orig_w; ratio = (double)orig_h / (double)orig_w; *thumb_h = *thumb_w * ratio; } else { if (orig_h < *thumb_h) *thumb_h = orig_h; ratio = (double)orig_w / (double)orig_h; *thumb_w = *thumb_h * ratio; } /** CAUTION :: The width of RGB888 raw data has to be rounded by 8 **/ *thumb_w = MEDIA_THUMB_ROUND_UP_8(*thumb_w); thumb_dbg("proper thumb w: %d h: %d", *thumb_w, *thumb_h); return MS_MEDIA_ERR_NONE; } int _media_thumb_get_exif_info(ExifData *ed, int *value, int ifdtype, long tagtype) { ExifEntry *entry; ExifIfd ifd; ExifTag tag; if (ed == NULL) { return MS_MEDIA_ERR_INVALID_PARAMETER; } ifd = ifdtype; tag = tagtype; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { if (tag == EXIF_TAG_ORIENTATION || tag == EXIF_TAG_PIXEL_X_DIMENSION || tag == EXIF_TAG_PIXEL_Y_DIMENSION) { if (value == NULL) { thumb_err("value is NULL"); return MS_MEDIA_ERR_INVALID_PARAMETER; } ExifByteOrder mByteOrder = exif_data_get_byte_order(ed); short exif_value = exif_get_short(entry->data, mByteOrder); *value = (int)exif_value; } } return MS_MEDIA_ERR_NONE; } static int __media_thumb_safe_atoi(char *buffer, int *si) { char *end = NULL; errno = 0; thumb_retvm_if(buffer == NULL || si == NULL, MS_MEDIA_ERR_INTERNAL, "invalid parameter"); const long sl = strtol(buffer, &end, 10); thumb_retvm_if(end == buffer, MS_MEDIA_ERR_INTERNAL, "not a decimal number"); thumb_retvm_if('\0' != *end, MS_MEDIA_ERR_INTERNAL, "extra characters at end of input: %s", end); thumb_retvm_if((LONG_MIN == sl || LONG_MAX == sl) && (ERANGE == errno), MS_MEDIA_ERR_INTERNAL, "out of range of type long"); thumb_retvm_if(sl > INT_MAX, MS_MEDIA_ERR_INTERNAL, "greater than INT_MAX"); thumb_retvm_if(sl < INT_MIN, MS_MEDIA_ERR_INTERNAL, "less than INT_MIN"); *si = (int)sl; return MS_MEDIA_ERR_NONE; } static int _media_thumb_get_data_from_exif(ExifData *ed, void **thumb_data, int *thumb_size, int *thumb_width, int *thumb_height, int *origin_width, int *origin_height) { ExifEntry *entry; ExifIfd ifd; ExifTag tag; ExifByteOrder byte_order = exif_data_get_byte_order(ed); ifd = EXIF_IFD_1; tag = EXIF_TAG_COMPRESSION; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { /* Get the contents of the tag in human-readable form */ ExifShort value = exif_get_short(entry->data, byte_order); //thumb_dbg("%s: %d", exif_tag_get_name_in_ifd(tag,ifd), value); if (value == 6) { thumb_dbg("There's jpeg thumb in this image"); } else { thumb_dbg("There's NO jpeg thumb in this image"); return MS_MEDIA_ERR_INVALID_PARAMETER; } } else { thumb_dbg("entry is NULL"); return MS_MEDIA_ERR_INVALID_PARAMETER; } /* copy the real thumbnail data from exif data */ if (ed->data && ed->size) { /* NOTICE : ExifData->size type is unsigned int, But Internal IPC, and CAPI use int */ if (ed->size > INT_MAX) { thumb_err("EXIF thumbnail size is over INT_MAX"); return MS_MEDIA_ERR_THUMB_TOO_BIG; } *thumb_data = (char *)malloc(ed->size); if (*thumb_data == NULL) { thumb_dbg("malloc failed!"); return MS_MEDIA_ERR_INVALID_PARAMETER; } memcpy(*thumb_data, (void *)ed->data, ed->size); *thumb_size = ed->size; } else { thumb_dbg("data is NULL"); return MS_MEDIA_ERR_INVALID_PARAMETER; } /* Get width and height of thumbnail */ tag = EXIF_TAG_IMAGE_WIDTH; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { /* Get the contents of the tag in human-readable form */ char width[10] = {0,}; exif_entry_get_value(entry, width, 10); __media_thumb_safe_atoi(width, thumb_width); } else { thumb_warn("EXIF_TAG_IMAGE_WIDTH does not exist"); *thumb_width = 0; } tag = EXIF_TAG_IMAGE_LENGTH; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { /* Get the contents of the tag in human-readable form */ char height[10] = {0, }; exif_entry_get_value(entry, height, 10); __media_thumb_safe_atoi(height, thumb_height); } else { thumb_warn("EXIF_TAG_IMAGE_LENGTH does not exist"); *thumb_height = 0; } thumb_dbg("thumb width : height [%d:%d]", *thumb_width, *thumb_height); /* Get width and height of original image from exif */ ifd = EXIF_IFD_EXIF; tag = EXIF_TAG_PIXEL_X_DIMENSION; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { char width[10] = {0,}; exif_entry_get_value(entry, width, 10); __media_thumb_safe_atoi(width, origin_width); } else { thumb_warn("EXIF_TAG_PIXEL_X_DIMENSION does not exist"); *origin_width = 0; } tag = EXIF_TAG_PIXEL_Y_DIMENSION; entry = exif_content_get_entry(ed->ifd[ifd], tag); if (entry) { char height[10] = {0, }; exif_entry_get_value(entry, height, 10); __media_thumb_safe_atoi(height, origin_height); } else { thumb_warn("EXIF_TAG_PIXEL_Y_DIMENSION does not exist"); *origin_height = 0; } return MS_MEDIA_ERR_NONE; } int _media_thumb_get_thumb_from_exif(ExifData *ed, const char *file_full_path, const char *thumb_path, int orientation, int required_width, int required_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; int size = 0; int thumb_width = 0; int thumb_height = 0; int origin_width = 0; int origin_height = 0; void *thumb = NULL; bool is_rotated = (orientation == ROT_90 || orientation == ROT_180 || orientation == ROT_270) ? TRUE : FALSE; mm_util_jpeg_yuv_data decoded = {0,}; if (ed == NULL) { return MS_MEDIA_ERR_INVALID_PARAMETER; } err = _media_thumb_get_data_from_exif(ed, &thumb, &size, &thumb_width, &thumb_height, &origin_width, &origin_height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("There is no exif data"); return err; } thumb_dbg("thumb width : height [%d:%d]", thumb_width, thumb_height); thumb_dbg("origin width : height [%d:%d]", origin_width, origin_height); thumb_info->origin_height = origin_height; thumb_info->origin_width = origin_width; if (thumb_width < required_width) { thumb_err("Thumb data in exif is too small"); SAFE_FREE(thumb); return MS_MEDIA_ERR_INVALID_PARAMETER; } if (is_rotated) { err = mm_util_decode_from_jpeg_memory(&decoded, thumb, (unsigned int)size, MM_UTIL_JPEG_FMT_RGB888); SAFE_FREE(thumb); if (err != MS_MEDIA_ERR_NONE) { thumb_err("mm_util_decode_from_jpeg_turbo_memory failed : %d", err); return err; } thumb_width = decoded.width; thumb_height = decoded.height; int rot_type = MM_UTIL_ROTATE_0; if (orientation == ROT_90) { rot_type = MM_UTIL_ROTATE_90; } else if (orientation == ROT_180) { rot_type = MM_UTIL_ROTATE_180; } else if (orientation == ROT_270) { rot_type = MM_UTIL_ROTATE_270; } err = _media_thumb_rotate_thumb(decoded.data, decoded.size, &(decoded.width), &(decoded.height), rot_type, MM_UTIL_JPEG_FMT_RGB888); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_rotate_thumb falied: %d", err); SAFE_FREE(thumb_info->data); return err; } //thumb_dbg("Width : %d, Height : %d", decoded.width, decoded.height); thumb_info->data = decoded.data; thumb_info->size = decoded.size; thumb_info->width = decoded.width; thumb_info->height = decoded.height; } else { /*in this case, just write raw data in file */ thumb_dbg_slog("Thumb is :%s", thumb_path); int nwrite; int fd = open(thumb_path, O_RDWR | O_CREAT | O_EXCL | O_SYNC, 0644); if (fd < 0) { if (errno == EEXIST) { thumb_err("thumb alread exist!"); } else { thumb_err("open failed"); SAFE_FREE(thumb); return MS_MEDIA_ERR_INVALID_PARAMETER; } } else { nwrite = write(fd, thumb, size); if (nwrite < 0) { thumb_err("write failed"); close(fd); SAFE_FREE(thumb); return MS_MEDIA_ERR_INVALID_PARAMETER; } close(fd); } SAFE_FREE(thumb); thumb_info->data = NULL; thumb_info->size = size; thumb_info->width = thumb_width; thumb_info->height = thumb_height; thumb_info->is_saved = TRUE; } return err; } int _media_thumb_get_wh_with_evas(const char *origin_path, int *width, int *height) { /* using evas to get w/h */ Ecore_Evas *ee = ecore_evas_buffer_new(0, 0); if (!ee) { thumb_err("ecore_evas_buffer_new fails"); return MS_MEDIA_ERR_INTERNAL; } Evas *evas = ecore_evas_get(ee); if (!evas) { thumb_err("ecore_evas_get fails"); ecore_evas_free(ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *image_object = evas_object_image_add(evas); if (!image_object) { thumb_err("evas_object_image_add fails"); ecore_evas_free(ee); return MS_MEDIA_ERR_INTERNAL; } evas_object_image_file_set(image_object, origin_path, NULL); evas_object_image_size_get(image_object, width, height); thumb_dbg("Width:%d, Height:%d", *width, *height); ecore_evas_free(ee); return MS_MEDIA_ERR_NONE; } int _media_thumb_decode_with_evas(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info, int need_scale, int orientation) { Ecore_Evas *resize_img_ee; resize_img_ee = ecore_evas_buffer_new(thumb_width, thumb_height); if (!resize_img_ee) { thumb_err("ecore_evas_buffer_new failed"); return MS_MEDIA_ERR_INTERNAL; } Evas *resize_img_e = ecore_evas_get(resize_img_ee); if (!resize_img_e) { thumb_err("ecore_evas_get failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *source_img = evas_object_image_add(resize_img_e); if (!source_img) { thumb_err("evas_object_image_add failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } evas_object_image_file_set(source_img, origin_path, NULL); /* Get w/h of original image */ int width = 0; int height = 0; evas_object_image_size_get(source_img, &width, &height); thumb_info->origin_width = width; thumb_info->origin_height = height; //thumb_dbg("origin width:%d, origin height:%d", width, height); /* This case for only JPEG format.. JPEG can be partially processed.. */ if ((need_scale == 1) && (width * height > THUMB_MAX_ALLOWED_MEM_FOR_THUMB)) { thumb_warn("This is too large image. so this's scale is going to be down"); evas_object_image_load_scale_down_set(source_img, 10); } if (orientation != TRANSPOSE) evas_object_image_load_orientation_set(source_img, 1); int rotated_orig_w = 0; int rotated_orig_h = 0; if (orientation == ROT_90 || orientation == ROT_270) { rotated_orig_w = height; rotated_orig_h = width; } else { rotated_orig_w = width; rotated_orig_h = height; } //thumb_dbg("rotated - origin width:%d, origin height:%d", rotated_orig_w, rotated_orig_h); int err = MS_MEDIA_ERR_NONE; err = _media_thumb_get_proper_thumb_size(rotated_orig_w, rotated_orig_h, &thumb_width, &thumb_height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_get_proper_thumb_size failed: %d", err); ecore_evas_free(resize_img_ee); return err; } ecore_evas_resize(resize_img_ee, thumb_width, thumb_height); evas_object_image_load_size_set(source_img, thumb_width, thumb_height); evas_object_image_fill_set(source_img, 0, 0, thumb_width, thumb_height); evas_object_image_filled_set(source_img, 1); evas_object_resize(source_img, thumb_width, thumb_height); evas_object_show(source_img); /* Set alpha from original */ thumb_info->alpha = evas_object_image_alpha_get(source_img); if (thumb_info->alpha) ecore_evas_alpha_set(resize_img_ee, EINA_TRUE); /* Create target buffer and copy origin resized img to it */ Ecore_Evas *target_ee = ecore_evas_buffer_new(thumb_width, thumb_height); if (!target_ee) { thumb_err("ecore_evas_buffer_new failed"); ecore_evas_free(resize_img_ee); return MS_MEDIA_ERR_INTERNAL; } Evas *target_evas = ecore_evas_get(target_ee); if (!target_evas) { thumb_err("ecore_evas_get failed"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *ret_image = evas_object_image_add(target_evas); evas_object_image_size_set(ret_image, thumb_width, thumb_height); evas_object_image_fill_set(ret_image, 0, 0, thumb_width, thumb_height); evas_object_image_filled_set(ret_image, EINA_TRUE); evas_object_image_data_set(ret_image, (int *)ecore_evas_buffer_pixels_get(resize_img_ee)); evas_object_image_data_update_add(ret_image, 0, 0, thumb_width, thumb_height); unsigned int buf_size = 0; if (mm_util_get_image_size(MM_UTIL_IMG_FMT_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) { thumb_err("mm_util_get_image_size failed"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_INTERNAL; } //thumb_dbg("mm_util_get_image_size : %d", buf_size); thumb_info->size = buf_size; thumb_info->width = thumb_width; thumb_info->height = thumb_height; thumb_info->data = malloc(buf_size); if (thumb_info->data == NULL) { thumb_err("Failed to allocate memory"); ecore_evas_free(resize_img_ee); ecore_evas_free(target_ee); return MS_MEDIA_ERR_OUT_OF_MEMORY; } void *image_data = evas_object_image_data_get(ret_image, 1); if (image_data != NULL) { memcpy(thumb_info->data, image_data, buf_size); } else { thumb_err("image_data is NULL. evas_object_image_data_get failed"); } ecore_evas_free(target_ee); ecore_evas_free(resize_img_ee); return err; } int _media_thumb_convert_data(media_thumb_info *thumb_info, int thumb_width, int thumb_height) { int err = MS_MEDIA_ERR_NONE; unsigned int buf_size = 0; unsigned char *src_data = thumb_info->data; unsigned char *dst_data = NULL; int i = 0, j; if (mm_util_get_image_size(MM_UTIL_IMG_FMT_BGRA8888, thumb_width, thumb_height, &buf_size) < 0) { thumb_err("mm_util_get_image_size failed"); return MS_MEDIA_ERR_INTERNAL; } thumb_dbg("mm_util_get_image_size : %d", buf_size); dst_data = (unsigned char *)malloc(buf_size); if (dst_data == NULL) { thumb_err("Failed to allocate memory"); return MS_MEDIA_ERR_OUT_OF_MEMORY; } for (j = 0; j < thumb_width * 3 * thumb_height; j += 3) { dst_data[i++] = (src_data[j + 2]); dst_data[i++] = (src_data[j + 1]); dst_data[i++] = (src_data[j]); dst_data[i++] = 0x0; } SAFE_FREE(thumb_info->data); thumb_info->data = dst_data; thumb_info->size = buf_size; thumb_dbg("_media_thumb_convert_data success"); return err; } int _media_thumb_agif(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; unsigned int *thumb = NULL; unsigned char *dst_image = NULL; unsigned int dst_size = 0; unsigned int thumb_size = 0; thumb = ImgGetFirstFrameAGIFAtSize(origin_path, thumb_info->origin_width, thumb_info->origin_height); if (!thumb) { thumb_err("Frame data is NULL!!"); return MS_MEDIA_ERR_INTERNAL; } err = mm_util_get_image_size(MM_UTIL_IMG_FMT_RGB888, thumb_info->origin_width, thumb_info->origin_height, &thumb_size); if (err != MS_MEDIA_ERR_NONE) { thumb_err("mm_util_get_image_size failed: %d", err); SAFE_FREE(thumb); return err; } err = _media_thumb_get_proper_thumb_size(thumb_info->origin_width, thumb_info->origin_height, &thumb_width, &thumb_height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_get_proper_thumb_size failed: %d", err); SAFE_FREE(thumb); return err; } err = _media_thumb_rgb_to_argb((unsigned char *) thumb, thumb_size, &dst_image, &dst_size, thumb_info->origin_width, thumb_info->origin_height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_convert_data falied: %d", err); SAFE_FREE(thumb); return err; } err = _media_thumb_resize_with_evas(dst_image, thumb_width, thumb_height, thumb_info); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_resize_data failed: %d", err); SAFE_FREE(thumb_info->data); SAFE_FREE(thumb); return err; } SAFE_FREE(thumb); return err; } int _media_thumb_general(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; err = _media_thumb_decode_with_evas(origin_path, thumb_width, thumb_height, thumb_info, 1, NORMAL); if (err != MS_MEDIA_ERR_NONE) { thumb_err("decode_with_evas failed : %d", err); return err; } return err; } int _media_thumb_jpeg(const char *origin_path, const char *thumb_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; int thumb_done = 0; int orientation = NORMAL; ExifData *ed = NULL; if (!thumb_info->is_raw) { /* Load an ExifData object from an EXIF file */ ed = exif_data_new_from_file(origin_path); if (ed) { /* First, Get orientation from exif */ err = _media_thumb_get_exif_info(ed, &orientation, EXIF_IFD_0, EXIF_TAG_ORIENTATION); if (err != MS_MEDIA_ERR_NONE) { thumb_warn("_media_thumb_get_exif_info failed"); } /* Second, Get thumb from exif */ err = _media_thumb_get_thumb_from_exif(ed, origin_path, thumb_path, orientation, thumb_width, thumb_height, thumb_info); if (err != MS_MEDIA_ERR_NONE) { thumb_dbg("_media_thumb_get_thumb_from_exif failed"); } else { thumb_done = 1; thumb_dbg("_media_thumb_get_thumb_from_exif succeed"); /* The case that original image's size is not in exif header. Use evas to get w/h */ if (thumb_info->origin_width == 0 || thumb_info->origin_height == 0) { thumb_warn("original image's size is not in exif header. Use evas to get w/h"); err = _media_thumb_get_wh_with_evas(origin_path, &(thumb_info->origin_width), &(thumb_info->origin_height)); if (err != MS_MEDIA_ERR_NONE) { thumb_err("Couldn't get w/h using evas : %s", origin_path); } else { thumb_dbg("origin w : %d, origin h : %d", thumb_info->origin_width, thumb_info->origin_height); } } if (thumb_info->is_saved == FALSE) { err = _media_thumb_convert_data(thumb_info, thumb_info->width, thumb_info->height); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_convert_data failed : %d", err); exif_data_unref(ed); return err; } } } exif_data_unref(ed); } } else { ed = exif_data_new_from_file(origin_path); if (ed) { err = _media_thumb_get_exif_info(ed, &orientation, EXIF_IFD_0, EXIF_TAG_ORIENTATION); if (err != MS_MEDIA_ERR_NONE) { thumb_warn("_media_thumb_get_exif_info failed"); } exif_data_unref(ed); } } if (!thumb_done) { err = _media_thumb_decode_with_evas(origin_path, thumb_width, thumb_height, thumb_info, 1, orientation); if (err != MS_MEDIA_ERR_NONE) { thumb_err("decode_with_evas failed : %d", err); return err; } } return err; } int _media_thumb_image(const char *origin_path, const char *thumb_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; ImgCodecType image_type = 0; unsigned int origin_w = 0; unsigned int origin_h = 0; err = ImgGetImageInfoForThumb(origin_path, &image_type, &origin_w, &origin_h); if (err != MS_MEDIA_ERR_NONE) { thumb_warn("Getting image info is failed err: %d", err); } thumb_info->origin_width = origin_w; thumb_info->origin_height = origin_h; if ((image_type != IMG_CODEC_JPEG) && (origin_w * origin_h > THUMB_MAX_ALLOWED_MEM_FOR_THUMB)) { thumb_warn("This original image is too big"); return MS_MEDIA_ERR_THUMB_TOO_BIG; } if (image_type == IMG_CODEC_AGIF) { err = _media_thumb_agif(origin_path, thumb_width, thumb_height, thumb_info); } else if (image_type == IMG_CODEC_JPEG) { err = _media_thumb_jpeg(origin_path, thumb_path, thumb_width, thumb_height, thumb_info); } else if (image_type == IMG_CODEC_PNG || image_type == IMG_CODEC_GIF || image_type == IMG_CODEC_BMP || image_type == IMG_CODEC_WBMP) { err = _media_thumb_general(origin_path, thumb_width, thumb_height, thumb_info); } else { thumb_warn("Unsupported image type"); return MS_MEDIA_ERR_THUMB_UNSUPPORTED; } return err; } int _media_thumb_video(const char *origin_path, int thumb_width, int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; MMHandleType content = (MMHandleType) NULL; void *frame = NULL; int video_track_num = 0; char *err_msg = NULL; int is_drm = 0; int size = 0; int width = 0; int height = 0; bool drm_type = FALSE; is_drm = drm_type; /* Get Content Tag attribute for orientatin */ MMHandleType tag = (MMHandleType) NULL; char *p = NULL; int cdis_value = 0; err = mm_file_create_tag_attrs(&tag, origin_path); mm_util_img_rotate_type rot_type = MM_UTIL_ROTATE_0; if (err == FILEINFO_ERROR_NONE) { err = mm_file_get_attrs(tag, &err_msg, MM_FILE_TAG_ROTATE, &p, &size, NULL); if (err == FILEINFO_ERROR_NONE && size >= 0) { if (p == NULL) { rot_type = MM_UTIL_ROTATE_0; } else { if (strncmp(p, "90", size) == 0) { rot_type = MM_UTIL_ROTATE_90; } else if (strncmp(p, "180", size) == 0) { rot_type = MM_UTIL_ROTATE_180; } else if (strncmp(p, "270", size) == 0) { rot_type = MM_UTIL_ROTATE_270; } else { rot_type = MM_UTIL_ROTATE_0; } } thumb_dbg("There is tag rotate : %d", rot_type); } else { thumb_dbg("There is NOT tag rotate"); rot_type = MM_UTIL_ROTATE_0; SAFE_FREE(err_msg); } err = mm_file_get_attrs(tag, &err_msg, MM_FILE_TAG_CDIS, &cdis_value, NULL); if (err != FILEINFO_ERROR_NONE) { cdis_value = 0; SAFE_FREE(err_msg); } } else { rot_type = MM_UTIL_ROTATE_0; cdis_value = 0; } err = mm_file_destroy_tag_attrs(tag); if (err != FILEINFO_ERROR_NONE) { thumb_err("fail to free tag attr - err(%x)", err); } if (cdis_value == 1) { thumb_warn("This is CDIS vlaue 1"); err = mm_file_create_content_attrs_safe(&content, origin_path); } else { err = mm_file_create_content_attrs(&content, origin_path); } if (err != FILEINFO_ERROR_NONE) { thumb_err("mm_file_create_content_attrs fails : %d", err); return MS_MEDIA_ERR_INTERNAL; } err = mm_file_get_attrs(content, &err_msg, MM_FILE_CONTENT_VIDEO_TRACK_COUNT, &video_track_num, NULL); if (err != FILEINFO_ERROR_NONE) { thumb_err("mm_file_get_attrs fails : %s", err_msg); SAFE_FREE(err_msg); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } /* MMF api handle both normal and DRM video */ if (video_track_num > 0 || is_drm) { err = mm_file_get_attrs(content, &err_msg, MM_FILE_CONTENT_VIDEO_WIDTH, &width, MM_FILE_CONTENT_VIDEO_HEIGHT, &height, MM_FILE_CONTENT_VIDEO_THUMBNAIL, &frame, /* raw image is RGB888 format */ &size, NULL); if (err != FILEINFO_ERROR_NONE) { thumb_err("mm_file_get_attrs fails : %s", err_msg); SAFE_FREE(err_msg); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } thumb_dbg("video width: %d", width); thumb_dbg("video height: %d", height); thumb_dbg("thumbnail size: %d", size); thumb_dbg("frame: %p", frame); thumb_dbg("orientation: %d", rot_type); if (frame == NULL || width == 0 || height == 0) { thumb_err("Failed to get frame data"); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } thumb_info->origin_width = width; thumb_info->origin_height = height; err = _media_thumb_get_proper_thumb_size(width, height, &thumb_width, &thumb_height); unsigned int new_size = 0; unsigned char *new_frame = NULL; err = _media_thumb_rgb_to_argb(frame, size, &new_frame, &new_size, width, height); if ((err != MS_MEDIA_ERR_NONE) || (new_frame == NULL)) { thumb_err("_media_thumb_convert_video falied: %d", err); mm_file_destroy_content_attrs(content); SAFE_FREE(new_frame); return err; } mm_file_destroy_content_attrs(content); thumb_dbg("original size - width:%d, height:%d", width, height); thumb_dbg("proper thumb size - width:%d, height:%d", thumb_width, thumb_height); if (width > thumb_width || height > thumb_height) { err = _media_thumb_resize_with_evas(new_frame, thumb_width, thumb_height, thumb_info); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_resize_video_with_evas falied: %d", err); SAFE_FREE(new_frame); return err; } } else { thumb_info->size = new_size; thumb_info->width = width; thumb_info->height = height; thumb_info->data = malloc(new_size); if (thumb_info->data == NULL) { thumb_err("memory allcation failed"); SAFE_FREE(new_frame); return MS_MEDIA_ERR_OUT_OF_MEMORY; } memcpy(thumb_info->data, new_frame, new_size); } SAFE_FREE(new_frame); if (rot_type == MM_UTIL_ROTATE_90 || rot_type == MM_UTIL_ROTATE_180 || rot_type == MM_UTIL_ROTATE_270) { err = _media_thumb_rotate_thumb(thumb_info->data, thumb_info->size, &(thumb_info->width), &(thumb_info->height), rot_type, MM_UTIL_JPEG_FMT_BGRA8888); if (err != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_rotate_thumb falied: %d", err); SAFE_FREE(thumb_info->data); return err; } } } else { thumb_dbg("no contents information"); frame = NULL; mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } return err; } int _media_thumb_get_hash_name(const char *file_full_path, char *thumb_hash_path, size_t max_thumb_path, uid_t uid) { char *hash_name = NULL; /*char *thumb_dir = NULL;*/ char file_ext[255] = { 0 }; char *get_path = NULL; int ret_len = 0; ms_user_storage_type_t store_type = -1; int ret = MS_MEDIA_ERR_NONE; if (file_full_path == NULL || thumb_hash_path == NULL || max_thumb_path <= 0) { thumb_err("file_full_path==NULL || thumb_hash_path == NULL || max_thumb_path <= 0"); return MS_MEDIA_ERR_INVALID_PARAMETER; } _media_thumb_get_file_ext(file_full_path, file_ext, sizeof(file_ext)); ret = ms_user_get_storage_type(uid, file_full_path, &store_type); if((ret != MS_MEDIA_ERR_NONE) || ((store_type != MS_USER_STORAGE_INTERNAL) && (store_type != MS_USER_STORAGE_EXTERNAL))) { thumb_err_slog("origin path(%s) is invalid. err : [%d] store_type [%d]", file_full_path, ret, store_type); return MS_MEDIA_ERR_INVALID_PARAMETER; } hash_name = _media_thumb_generate_hash_name(file_full_path); if (hash_name == NULL) { thumb_err("_media_thumb_generate_hash_name fail"); return MS_MEDIA_ERR_INTERNAL; } if (store_type == MS_USER_STORAGE_EXTERNAL) { ret = ms_user_get_mmc_thumb_store_path(uid, &get_path); if (get_path != NULL) ret_len = snprintf(thumb_hash_path, max_thumb_path - 1, "%s/.%s-%s.jpg", get_path, file_ext, hash_name); } else { ret = ms_user_get_default_thumb_store_path(uid, &get_path); if (get_path != NULL) ret_len = snprintf(thumb_hash_path, max_thumb_path - 1, "%s/.%s-%s.jpg", get_path, file_ext, hash_name); } SAFE_FREE(get_path); if ((ret_len < 0) || (ret_len > (int)max_thumb_path)) { thumb_err("invalid hash path ret_len[%d]", ret_len); return MS_MEDIA_ERR_INTERNAL; } //thumb_dbg("thumb hash : %s", thumb_hash_path); return MS_MEDIA_ERR_NONE; } int _media_thumb_save_to_file_with_evas(unsigned char *data, int w, int h, int alpha, char *thumb_path) { Ecore_Evas *ee = ecore_evas_buffer_new(w, h); if (ee == NULL) { thumb_err("ecore_evas_buffer_new failed"); return MS_MEDIA_ERR_INTERNAL; } Evas *evas = ecore_evas_get(ee); if (evas == NULL) { thumb_err("ecore_evas_get failed"); ecore_evas_free(ee); return MS_MEDIA_ERR_INTERNAL; } Evas_Object *img = NULL; img = evas_object_image_add(evas); if (img == NULL) { thumb_err("evas_object_image_add failed"); ecore_evas_free(ee); return MS_MEDIA_ERR_INTERNAL; } evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888); evas_object_image_size_set(img, w, h); evas_object_image_fill_set(img, 0, 0, w, h); if (alpha) evas_object_image_alpha_set(img, 1); evas_object_image_data_set(img, data); evas_object_image_data_update_add(img, 0, 0, w, h); if (evas_object_image_save(img, thumb_path, NULL, "quality=90 compress=1")) { thumb_dbg("evas_object_image_save success"); ecore_evas_free(ee); return MS_MEDIA_ERR_NONE; } else { thumb_err("evas_object_image_save failed"); ecore_evas_free(ee); return MS_MEDIA_ERR_INTERNAL; } }