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.
23 #include <mm_util_magick.h>
24 #include <media-util.h>
25 #include "media-thumbnail.h"
26 #include "media-thumbnail-debug.h"
29 #define MAX_THUMB_SIZE 2000
30 #define MIME_TYPE_TIFF "image/tiff"
31 #define MIME_TYPE_ASF "application/vnd.ms-asf"
32 #define MIME_MAX_LEN 255
35 MEDIA_THUMB_INVALID = 0,
38 } thumbnail_media_type_e;
40 static void __get_rotation_and_cdis(const char *path, mm_util_rotate_type_e *rot_type, int *cdis_value)
42 int err = MS_MEDIA_ERR_NONE;
43 MMHandleType tag = (MMHandleType) NULL;
47 mm_util_rotate_type_e _rot_type = MM_UTIL_ROTATE_0;
49 /* Get Content Tag attribute for orientation */
50 err = mm_file_create_tag_attrs(&tag, path);
51 if (err != FILEINFO_ERROR_NONE)
54 err = mm_file_get_attrs(tag, MM_FILE_TAG_ROTATE, &p, &size, NULL);
55 if (err == FILEINFO_ERROR_NONE && size >= 0 && p) {
56 if (strncmp(p, "90", size) == 0)
57 _rot_type = MM_UTIL_ROTATE_90;
58 else if (strncmp(p, "180", size) == 0)
59 _rot_type = MM_UTIL_ROTATE_180;
60 else if (strncmp(p, "270", size) == 0)
61 _rot_type = MM_UTIL_ROTATE_270;
63 _rot_type = MM_UTIL_ROTATE_0;
65 thumb_dbg("There is tag rotate : %d", _rot_type);
68 err = mm_file_get_attrs(tag, MM_FILE_TAG_CDIS, &_cdis_value, NULL);
69 if (err != FILEINFO_ERROR_NONE)
72 *rot_type = _rot_type;
73 *cdis_value = _cdis_value;
75 mm_file_destroy_tag_attrs(tag);
78 static int __get_video_meta(int cdis_value, const char *path, int *video_track_num, unsigned int *width, unsigned int *height, void **frame, size_t *frame_size)
80 int err = MS_MEDIA_ERR_NONE;
81 MMHandleType content = (MMHandleType) NULL;
82 int _video_track_num = 0;
83 unsigned int _width = 0;
84 unsigned int _height = 0;
85 size_t _frame_size = 0;
88 if (cdis_value == 1) {
89 thumb_warn("This is CDIS vlaue 1");
90 err = mm_file_create_content_attrs_safe(&content, path);
92 err = mm_file_create_content_attrs(&content, path);
94 thumb_retvm_if(err != FILEINFO_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_file_create_content_attrs fails : %d", err);
96 err = mm_file_get_attrs(content,
97 MM_FILE_CONTENT_VIDEO_TRACK_COUNT, &_video_track_num,
98 MM_FILE_CONTENT_VIDEO_WIDTH, &_width,
99 MM_FILE_CONTENT_VIDEO_HEIGHT, &_height,
100 MM_FILE_CONTENT_VIDEO_THUMBNAIL, &_frame, &_frame_size, /* raw image is RGB888 format */
103 if (err != FILEINFO_ERROR_NONE) {
104 thumb_err("mm_file_get_attrs fails : %d", err);
105 mm_file_destroy_content_attrs(content);
106 return MS_MEDIA_ERR_INTERNAL;
109 *video_track_num = _video_track_num;
111 if (_video_track_num == 0) {
112 mm_file_destroy_content_attrs(content);
113 return MS_MEDIA_ERR_NONE;
116 if (!_frame || !_width || !_height) {
117 thumb_err("wrong video info W[%d] H[%d] Size[%zu] Frame[%p]", _width, _height, _frame_size, _frame);
118 mm_file_destroy_content_attrs(content);
119 return MS_MEDIA_ERR_INTERNAL;
124 *frame_size = _frame_size;
125 *frame = g_memdup2(_frame, _frame_size);
127 mm_file_destroy_content_attrs(content);
129 return MS_MEDIA_ERR_NONE;
133 static int __get_video_info(const char *path, int *video_track_num, unsigned int *width, unsigned int *height, void **frame, size_t *frame_size, mm_util_rotate_type_e *rot_type)
135 int err = MS_MEDIA_ERR_NONE;
137 mm_util_rotate_type_e _rot_type = MM_UTIL_ROTATE_0;
139 __get_rotation_and_cdis(path, &_rot_type, &_cdis_value);
140 err = __get_video_meta(_cdis_value, path, video_track_num, width, height, frame, frame_size);
143 *rot_type = _rot_type;
148 static void __media_thumb_get_proper_thumb_size(unsigned int origin_width, unsigned int origin_height, unsigned int *thumb_width, unsigned int *thumb_height)
152 thumb_retm_if(origin_width == 0, "Invalid origin_width");
153 thumb_retm_if(origin_height == 0, "Invalid origin_height");
154 thumb_retm_if(!thumb_width, "Invalid thumb_width");
155 thumb_retm_if(!thumb_height, "Invalid thumb_height");
157 thumb_dbg("origin thumb w: %d h: %d", *thumb_width, *thumb_height);
159 /* Set smaller length to default size */
160 if (origin_width < origin_height) {
161 if (origin_width < *thumb_width)
162 *thumb_width = origin_width;
163 ratio = (double)origin_height / (double)origin_width;
164 *thumb_height = *thumb_width * ratio;
166 if (origin_height < *thumb_height)
167 *thumb_height = origin_height;
168 ratio = (double)origin_width / (double)origin_height;
169 *thumb_width = *thumb_height * ratio;
172 thumb_dbg("proper thumb w: %d h: %d", *thumb_width, *thumb_height);
175 static int __get_video_thumb_to_file(unsigned int width, unsigned int height, void *frame, size_t frame_size, mm_util_rotate_type_e rot_type, const char *thumb_path, unsigned int thumb_width, unsigned int thumb_height)
177 int err = MS_MEDIA_ERR_NONE;
178 mm_util_image_h img = NULL;
179 mm_util_image_h resize_img = NULL;
180 unsigned int thumb_w = thumb_width;
181 unsigned int thumb_h = thumb_height;
183 thumb_retvm_if(!thumb_path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid thumb_path");
185 __media_thumb_get_proper_thumb_size(width, height, &thumb_w, &thumb_h);
186 thumb_retv_if(thumb_w == 0 || thumb_h == 0, MS_MEDIA_ERR_INTERNAL);
188 err = mm_image_create_image(width, height, MM_UTIL_COLOR_RGB24, (unsigned char *)frame, frame_size, &img);
189 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to mm_image_create_image [%d]", err);
191 if (width > thumb_w || height > thumb_h) {
192 if (rot_type != MM_UTIL_ROTATE_0) {
193 err = mm_util_resize_B_B(img, thumb_w, thumb_h, &resize_img);
194 if (err != MM_UTIL_ERROR_NONE)
197 err = mm_util_rotate_B_P(resize_img, rot_type, thumb_path);
200 err = mm_util_resize_B_P(img, thumb_w, thumb_h, thumb_path);
203 if (rot_type != MM_UTIL_ROTATE_0)
204 err = mm_util_rotate_B_P(img, rot_type, thumb_path);
206 err = mm_util_resize_B_P(img, width, height, thumb_path);
210 mm_image_destroy_image(img);
211 mm_image_destroy_image(resize_img);
213 return (err == MM_UTIL_ERROR_NONE) ? MS_MEDIA_ERR_NONE : MS_MEDIA_ERR_INTERNAL;
216 static int __get_video_thumb_to_buffer(unsigned int width, unsigned int height, void *frame, size_t frame_size, unsigned int thumb_width, unsigned int thumb_height, mm_util_image_h *dst_img)
218 int err = MS_MEDIA_ERR_NONE;
219 mm_util_image_h img = NULL;
220 unsigned int thumb_w = thumb_width;
221 unsigned int thumb_h = thumb_height;
223 __media_thumb_get_proper_thumb_size(width, height, &thumb_w, &thumb_h);
224 thumb_retv_if(thumb_w == 0 || thumb_h == 0, MS_MEDIA_ERR_INTERNAL);
226 err = mm_image_create_image(width, height, MM_UTIL_COLOR_RGB24, (unsigned char *)frame, frame_size, &img);
227 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to mm_image_create_image [%d]", err);
229 if (width > thumb_w || height > thumb_h)
230 err = mm_util_resize_B_B(img, thumb_w, thumb_h, dst_img);
232 err = mm_image_clone_image(img, dst_img);
233 mm_image_destroy_image(img);
235 return (err == MM_UTIL_ERROR_NONE) ? MS_MEDIA_ERR_NONE : MS_MEDIA_ERR_INTERNAL;
238 static int __check_path_validity(const char *path)
240 thumb_retvm_if(!path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
242 if (access(path, R_OK) < 0) {
243 if (errno == EACCES || errno == EPERM) {
244 thumb_err("Fail to open path: Permission Denied [%s]", path);
245 return MS_MEDIA_ERR_PERMISSION_DENIED;
247 thumb_err("Fail to open path: Invalid Path [%s]", path);
248 return MS_MEDIA_ERR_INVALID_PARAMETER;
252 return MS_MEDIA_ERR_NONE;
255 static int __check_thumb_path_validity(const char *path)
257 char *dir_name = NULL;
258 int ret = MS_MEDIA_ERR_NONE;
260 thumb_retvm_if(!THUMB_STRING_VALID(path), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
262 dir_name = g_path_get_dirname(path);
264 if (access(dir_name, W_OK) != 0) {
265 if (errno == EACCES || errno == EPERM) {
266 thumb_err("No permission to write[%s]", dir_name);
267 ret = MS_MEDIA_ERR_PERMISSION_DENIED;
269 thumb_err("Does not exists[%s]", dir_name);
270 ret = MS_MEDIA_ERR_INVALID_PARAMETER;
279 static int __check_parameter_validity_for_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path)
281 int err = MS_MEDIA_ERR_NONE;
283 thumb_retvm_if((width > MAX_THUMB_SIZE || width == 0), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid width[%d]", width);
284 thumb_retvm_if((height > MAX_THUMB_SIZE || height == 0), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid height[%d]", height);
286 /* Check path is accessible */
287 err = __check_path_validity(path);
288 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid path");
290 /* Check thumbnail path is writable */
291 err = __check_thumb_path_validity(thumb_path);
292 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid thumb_path");
294 return MS_MEDIA_ERR_NONE;
297 static int __check_parameter_validity_for_buffer(const char *path, unsigned int width, unsigned int height, unsigned char **thumb_buffer, size_t *thumb_size, unsigned int *thumb_width, unsigned int *thumb_height)
299 thumb_retvm_if((width > MAX_THUMB_SIZE || width == 0), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid width[%d]", width);
300 thumb_retvm_if((height > MAX_THUMB_SIZE || height == 0), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid height[%d]", height);
301 thumb_retvm_if(!thumb_buffer || !thumb_size || !thumb_width || !thumb_height, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid out param");
303 //Check path is accessible
304 return __check_path_validity(path);
307 int create_video_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path, bool auto_rotate)
309 int err = MS_MEDIA_ERR_NONE;
310 int video_track_num = 0;
311 unsigned int video_width = 0;
312 unsigned int video_height = 0;
314 size_t frame_size = 0;
315 mm_util_rotate_type_e rot_type = MM_UTIL_ROTATE_NUM;
317 err = __check_parameter_validity_for_file(path, width, height, thumb_path);
318 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
321 err = __get_video_info(path, &video_track_num, &video_width, &video_height, &frame, &frame_size, &rot_type);
322 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to __get_video_info [%d]", err);
323 thumb_retvm_if(video_track_num == 0, MM_UTIL_ERROR_NONE, "No video track");
326 rot_type = MM_UTIL_ROTATE_0;
329 err = __get_video_thumb_to_file(video_width, video_height, frame, frame_size, rot_type, thumb_path, width, height);
335 int create_video_thumbnail_to_buffer(const char *path,
338 unsigned char **thumb_buffer,
340 unsigned int *thumb_width,
341 unsigned int *thumb_height)
343 int err = MS_MEDIA_ERR_NONE;
344 int video_track_num = 0;
345 unsigned int video_w = 0;
346 unsigned int video_h = 0;
348 size_t frame_size = 0;
349 mm_util_image_h img = NULL;
351 err = __check_parameter_validity_for_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
352 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
355 err = __get_video_info(path, &video_track_num, &video_w, &video_h, &frame, &frame_size, NULL);
356 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, err, "fail to __get_video_info [%d]", err);
357 thumb_retvm_if(video_track_num == 0, MM_UTIL_ERROR_NONE, "No video track");
360 err = __get_video_thumb_to_buffer(video_w, video_h, frame, frame_size, width, height, &img);
362 if (err != MS_MEDIA_ERR_NONE)
365 err = mm_image_get_image(img, thumb_width, thumb_height, NULL, thumb_buffer, thumb_size);
366 mm_image_destroy_image(img);
371 static int __adjust_thumb_ratio(const char *path, unsigned int *width, unsigned int *height)
373 int err = MS_MEDIA_ERR_NONE;
374 unsigned int image_w = 0;
375 unsigned int image_h = 0;
376 mm_util_img_codec_type image_type = 0;
378 err = mm_util_extract_image_info(path, &image_type, &image_w, &image_h);
379 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_extract_image_info: %d", err);
380 thumb_retvm_if(image_type == IMG_CODEC_UNKNOWN_TYPE, MS_MEDIA_ERR_THUMB_UNSUPPORTED, "Unsupported image codec");
382 __media_thumb_get_proper_thumb_size(image_w, image_h, width, height);
384 return MS_MEDIA_ERR_NONE;
387 int create_image_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path, bool auto_rotate)
389 int err = MS_MEDIA_ERR_NONE;
390 unsigned int thumb_w = width;
391 unsigned int thumb_h = height;
393 err = __check_parameter_validity_for_file(path, width, height, thumb_path);
394 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
396 err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
397 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
400 err = mm_util_resize_and_rotate_P_P(path, thumb_w, thumb_h, thumb_path);
402 err = mm_util_resize_P_P(path, thumb_w, thumb_h, thumb_path);
403 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_P_P failed : %d", err);
405 return MS_MEDIA_ERR_NONE;
408 int create_image_thumbnail_to_buffer(const char *path, unsigned int width, unsigned int height, unsigned char **thumb_buffer, size_t *thumb_size, unsigned int *thumb_width, unsigned int *thumb_height)
410 int err = MS_MEDIA_ERR_NONE;
411 unsigned int thumb_w = width;
412 unsigned int thumb_h = height;
413 mm_util_image_h img = NULL;
415 err = __check_parameter_validity_for_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
416 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
418 err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
419 thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
421 err = mm_util_resize_P_B(path, thumb_w, thumb_h, MM_UTIL_COLOR_BGRA, &img);
422 thumb_retvm_if(err != MM_UTIL_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_util_resize_P_B failed : %d", err);
424 err = mm_image_get_image(img, thumb_width, thumb_height, NULL, thumb_buffer, thumb_size);
426 mm_image_destroy_image(img);
431 static int __get_media_type(const char *path, thumbnail_media_type_e *media_type)
433 int ret = MS_MEDIA_ERR_NONE;
434 char mime[MIME_MAX_LEN] = {0,};
436 ret = __check_path_validity(path);
437 thumb_retv_if(ret != MS_MEDIA_ERR_NONE, ret);
439 ret = aul_get_mime_from_file(path, mime, MIME_MAX_LEN);
440 thumb_retvm_if(ret < 0, MS_MEDIA_ERR_INTERNAL, "aul_get_mime_from_file failed");
442 thumb_dbg("mime type : %s", mime);
444 if (strstr(mime, "image") != NULL) {
445 thumb_retvm_if(!strcmp(mime, MIME_TYPE_TIFF), MS_MEDIA_ERR_THUMB_UNSUPPORTED, "Unsupported type");
446 *media_type = MEDIA_THUMB_IMAGE;
447 return MS_MEDIA_ERR_NONE;
450 if (strstr(mime, "video") != NULL) {
451 *media_type = MEDIA_THUMB_VIDEO;
452 return MS_MEDIA_ERR_NONE;
455 if (strcmp(mime, MIME_TYPE_ASF) == 0) {
456 *media_type = MEDIA_THUMB_VIDEO;
457 return MS_MEDIA_ERR_NONE;
460 return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
463 int create_thumbnail_to_buffer(const char *path, unsigned int width, unsigned int height, unsigned char **thumb_buffer, size_t *thumb_size, unsigned int *thumb_width, unsigned int *thumb_height)
465 int ret = MS_MEDIA_ERR_NONE;
466 thumbnail_media_type_e type = MEDIA_THUMB_INVALID;
468 ret = __get_media_type(path, &type);
469 thumb_retvm_if(ret != MS_MEDIA_ERR_NONE, ret, "__get_media_type failed");
471 if (type == MEDIA_THUMB_IMAGE)
472 return create_image_thumbnail_to_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
474 return create_video_thumbnail_to_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
477 int create_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path)
479 int ret = MS_MEDIA_ERR_NONE;
480 thumbnail_media_type_e type = MEDIA_THUMB_INVALID;
482 ret = __get_media_type(path, &type);
483 thumb_retvm_if(ret != MS_MEDIA_ERR_NONE, ret, "__get_media_type failed");
485 if (type == MEDIA_THUMB_IMAGE)
486 return create_image_thumbnail_to_file(path, width, height, thumb_path, false);
488 if (!g_regex_match_simple("[^/]\\.jpe?g$", thumb_path, G_REGEX_CASELESS, 0)) {
489 thumb_err("Unsupported path or extensions [%s]", thumb_path);
490 return MS_MEDIA_ERR_INVALID_PARAMETER;
493 return create_video_thumbnail_to_file(path, width, height, thumb_path, false);