/* * 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 "media-thumb-db.h" #include #include #include #include #include static void __media_thumb_get_proper_thumb_size(unsigned int origin_width, unsigned int origin_height, unsigned int *thumb_width, unsigned int *thumb_height) { bool portrait = false; double ratio = 0.0; thumb_retm_if(origin_width == 0, "Invalid origin_width"); thumb_retm_if(origin_height == 0, "Invalid origin_height"); thumb_retm_if(!thumb_width, "Invalid thumb_width"); thumb_retm_if(!thumb_height, "Invalid thumb_height"); if (origin_width < origin_height) portrait = true; /* Set smaller length to default size */ if (portrait) { if (origin_width < *thumb_width) *thumb_width = origin_width; ratio = (double)origin_height / (double)origin_width; *thumb_height = *thumb_width * ratio; } else { if (origin_height < *thumb_height) *thumb_height = origin_height; ratio = (double)origin_width / (double)origin_height; *thumb_width = *thumb_height * ratio; } thumb_dbg("proper thumb w: %d h: %d", *thumb_width, *thumb_height); return; } int _media_thumb_general(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; mm_util_image_h img = NULL; unsigned char *buf = NULL; unsigned int width = 0; unsigned int height = 0; size_t size = 0; mm_util_color_format_e format = MM_UTIL_COLOR_NUM; if (thumb_path != NULL) { err = mm_util_resize_P_P(origin_path, thumb_width, thumb_height, thumb_path); } else { err = mm_util_resize_P_B(origin_path, thumb_width, thumb_height, MM_UTIL_COLOR_BGRA, &img); if (err != MM_UTIL_ERROR_NONE) { thumb_err("mm_util_resize_P_B failed : %d", err); return MS_MEDIA_ERR_INTERNAL; } mm_image_get_image(img, &width, &height, &format, &buf, &size); thumb_info->data = buf; thumb_info->size = size; thumb_info->width = width; thumb_info->height = height; mm_image_destroy_image(img); } return err; } int _media_thumb_image(const char *origin_path, char *thumb_path, unsigned int thumb_width, unsigned int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; mm_util_img_codec_type image_type = 0; unsigned int origin_w = 0; unsigned int origin_h = 0; err = mm_util_extract_image_info(origin_path, &image_type, &origin_w, &origin_h); if (err != MS_MEDIA_ERR_NONE) { thumb_warn("Getting image info is failed err: %d", err); return MS_MEDIA_ERR_INTERNAL; } 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; } __media_thumb_get_proper_thumb_size(origin_w, origin_h, &thumb_width, &thumb_height); if (image_type != IMG_CODEC_UNKNOWN_TYPE) { err = _media_thumb_general(origin_path, thumb_path, thumb_width, thumb_height, thumb_info); } else { thumb_warn("Unsupported image type"); err = MS_MEDIA_ERR_THUMB_UNSUPPORTED; } return err; } static void __get_rotation_and_cdis(const char *origin_path, mm_util_magick_rotate_type *rot_type, int *cdis_value) { int err = MS_MEDIA_ERR_NONE; MMHandleType tag = (MMHandleType) NULL; char *p = NULL; int size = 0; int _cdis_value = 0; mm_util_magick_rotate_type _rot_type = MM_UTIL_ROTATE_NUM; /* Get Content Tag attribute for orientation */ err = mm_file_create_tag_attrs(&tag, origin_path); if (err != FILEINFO_ERROR_NONE) { *rot_type = MM_UTIL_ROTATE_0; *cdis_value = 0; return; } err = mm_file_get_attrs(tag, 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; } err = mm_file_get_attrs(tag, MM_FILE_TAG_CDIS, &_cdis_value, NULL); if (err != FILEINFO_ERROR_NONE) _cdis_value = 0; *rot_type = _rot_type; *cdis_value = _cdis_value; err = mm_file_destroy_tag_attrs(tag); if (err != FILEINFO_ERROR_NONE) { thumb_err("fail to free tag attr - err(%x)", err); } return; } static int __get_video_info(int cdis_value, const char *origin_path, int *video_track_num, unsigned int *width, unsigned int *height, void **frame, size_t *size) { int err = MS_MEDIA_ERR_NONE; MMHandleType content = (MMHandleType) NULL; int _video_track_num = 0; int _width = 0; int _height = 0; size_t _size = 0; void *_frame = NULL; 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, MM_FILE_CONTENT_VIDEO_TRACK_COUNT, &_video_track_num, NULL); if (err != FILEINFO_ERROR_NONE) { thumb_err("mm_file_get_attrs fails : %d", err); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } *video_track_num = _video_track_num; if (_video_track_num == 0) { mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_NONE; } err = mm_file_get_attrs(content, 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 : %d", err); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } thumb_dbg("W[%d] H[%d] Size[%zu] Frame[%p]", _width, _height, _size, _frame); if (!_frame || !_width || !_height) { mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_INTERNAL; } *width = _width; *height = _height; *size = _size; *frame = calloc(1, _size); memcpy(*frame, _frame, _size); mm_file_destroy_content_attrs(content); return MS_MEDIA_ERR_NONE; } static int __get_video_thumb(int width, int height, void *frame, size_t size, mm_util_magick_rotate_type rot_type, const char *thumb_path, unsigned int thumb_width, unsigned int thumb_height, mm_util_image_h *dst_img) { int err = MS_MEDIA_ERR_NONE; mm_util_image_h img = NULL; mm_util_image_h resize_img = NULL; __media_thumb_get_proper_thumb_size(width, height, &thumb_width, &thumb_height); if (thumb_width <= 0 || thumb_height <= 0) { thumb_err("Failed to get thumb size"); return MS_MEDIA_ERR_INTERNAL; } thumb_dbg("Origin:W[%d] H[%d] Proper:W[%d] H[%d]", width, height, thumb_width, thumb_height); err = mm_image_create_image(width, height, MM_UTIL_COLOR_RGB24, (unsigned char *)frame, size, &img); thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to mm_image_create_image [%d]", err); if (width > thumb_width || height > thumb_height) { if (rot_type != MM_UTIL_ROTATE_0) { if (STRING_VALID(thumb_path)) { err = mm_util_resize_B_B(img, thumb_width, thumb_height, &resize_img); if (err != MM_UTIL_ERROR_NONE) goto ERROR; err = mm_util_rotate_B_P(resize_img, rot_type, thumb_path); } else { err = mm_util_resize_B_B(img, thumb_width, thumb_height, &resize_img); if (err != MM_UTIL_ERROR_NONE) goto ERROR; err = mm_util_rotate_B_B(resize_img, rot_type, dst_img); } } else { if (STRING_VALID(thumb_path)) err = mm_util_resize_B_P(img, thumb_width, thumb_height, thumb_path); else err = mm_util_resize_B_B(img, thumb_width, thumb_height, dst_img); } } else { if (rot_type != MM_UTIL_ROTATE_0) { if (STRING_VALID(thumb_path)) { err = mm_util_rotate_B_P(img, rot_type, thumb_path); } else { err = mm_util_rotate_B_B(img, rot_type, dst_img); } } else { if (STRING_VALID(thumb_path)) { err = mm_util_resize_B_P(img, width, height, thumb_path); } else { err = mm_image_clone_image(img, dst_img); } } } ERROR: mm_image_destroy_image(img); mm_image_destroy_image(resize_img); if (err != MS_MEDIA_ERR_NONE) return MS_MEDIA_ERR_INTERNAL; return MS_MEDIA_ERR_NONE; } int _media_thumb_video(const char *origin_path, const char *thumb_path, unsigned int thumb_width, unsigned int thumb_height, media_thumb_info *thumb_info) { int err = MS_MEDIA_ERR_NONE; int cdis_value = 0; void *frame = NULL; int video_track_num = 0; unsigned int width = 0; unsigned int height = 0; mm_util_image_h dst_img = NULL; unsigned char *buf = NULL; size_t size = 0; mm_util_color_format_e format = MM_UTIL_COLOR_NUM; mm_util_magick_rotate_type rot_type = MM_UTIL_ROTATE_NUM; __get_rotation_and_cdis(origin_path, &rot_type, &cdis_value); err = __get_video_info(cdis_value, origin_path, &video_track_num, &width, &height, &frame, &size); thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to __get_video_info [%d]", err); thumb_retvm_if(video_track_num == 0, MM_UTIL_ERROR_NONE, "No video track"); if (STRING_VALID(thumb_path)) { err = __get_video_thumb(width, height, frame, size, rot_type, thumb_path, thumb_width, thumb_height, NULL); } else if (thumb_info) { err = __get_video_thumb(width, height, frame, size, rot_type, NULL, thumb_width, thumb_height, &dst_img); if (err == MS_MEDIA_ERR_NONE) { err = mm_image_get_image(dst_img, &width, &height, &format, &buf, &size); thumb_info->data = buf; thumb_info->size = size; thumb_info->width = width; thumb_info->height = height; } mm_image_destroy_image(dst_img); } else { thumb_err("Invalid parameter"); err = MS_MEDIA_ERR_INVALID_PARAMETER; } SAFE_FREE(frame); 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 file_ext[255] = { 0 }; char *get_path = NULL; char *storage_id = NULL; int ret_len = 0; ms_user_storage_type_e storage_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, &storage_type); if ((ret != MS_MEDIA_ERR_NONE) || ((storage_type != MS_USER_STORAGE_INTERNAL) && (storage_type != MS_USER_STORAGE_EXTERNAL))) { thumb_err_slog("origin path(%s) is invalid. err : [%d] storage_type [%d]", file_full_path, ret, storage_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; } ret = _media_thumb_get_storage_id_from_db(file_full_path, &storage_id, uid); if (ret != MS_MEDIA_ERR_NONE) { thumb_err("_media_thumb_get_storage_id_from_db fail"); return MS_MEDIA_ERR_INTERNAL; } ret = ms_user_get_root_thumb_store_path(uid, &get_path); SAFE_FREE(storage_id); if (get_path != NULL) ret_len = snprintf(thumb_hash_path, max_thumb_path - 1, "%s/.%s-%s.png", 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; } return MS_MEDIA_ERR_NONE; }