Add function to check media type for thumbnail-util
[platform/core/multimedia/libmedia-thumbnail.git] / src / media-thumbnail.c
1 /*
2  * libmedia-thumbnail
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hyunjun Ko <zzoon.ko@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <mm_file.h>
23 #include <mm_util_magick.h>
24 #include <media-util.h>
25 #include "media-thumbnail.h"
26 #include "media-thumbnail-debug.h"
27 #include <aul.h>
28
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
33
34 typedef enum {
35     MEDIA_THUMB_INVALID = 0,
36     MEDIA_THUMB_IMAGE,
37     MEDIA_THUMB_VIDEO,
38 } thumbnail_media_type_e;
39
40 static void __get_rotation_and_cdis(const char *path, mm_util_rotate_type_e *rot_type, int *cdis_value)
41 {
42         int err = MS_MEDIA_ERR_NONE;
43         MMHandleType tag = (MMHandleType) NULL;
44         char *p = NULL;
45         int size = 0;
46         int _cdis_value = 0;
47         mm_util_rotate_type_e _rot_type = MM_UTIL_ROTATE_0;
48
49         /* Get Content Tag attribute for orientation */
50         err = mm_file_create_tag_attrs(&tag, path);
51         if (err != FILEINFO_ERROR_NONE)
52                 return;
53
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;
62                 else
63                         _rot_type = MM_UTIL_ROTATE_0;
64
65                 thumb_dbg("There is tag rotate : %d", _rot_type);
66         }
67
68         err = mm_file_get_attrs(tag, MM_FILE_TAG_CDIS, &_cdis_value, NULL);
69         if (err != FILEINFO_ERROR_NONE)
70                 _cdis_value = 0;
71
72         *rot_type = _rot_type;
73         *cdis_value = _cdis_value;
74
75         mm_file_destroy_tag_attrs(tag);
76 }
77
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)
79 {
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;
86         void *_frame = NULL;
87
88         if (cdis_value == 1) {
89                 thumb_warn("This is CDIS vlaue 1");
90                 err = mm_file_create_content_attrs_safe(&content, path);
91         } else {
92                 err = mm_file_create_content_attrs(&content, path);
93         }
94         thumb_retvm_if(err != FILEINFO_ERROR_NONE, MS_MEDIA_ERR_INTERNAL, "mm_file_create_content_attrs fails : %d", err);
95
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 */
101                                 NULL);
102
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;
107         }
108
109         *video_track_num = _video_track_num;
110
111         if (_video_track_num == 0) {
112                 mm_file_destroy_content_attrs(content);
113                 return MS_MEDIA_ERR_NONE;
114         }
115
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;
120         }
121
122         *width = _width;
123         *height = _height;
124         *frame_size = _frame_size;
125         *frame = g_memdup2(_frame, _frame_size);
126
127         mm_file_destroy_content_attrs(content);
128
129         return MS_MEDIA_ERR_NONE;
130 }
131
132
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)
134 {
135         int err = MS_MEDIA_ERR_NONE;
136         int _cdis_value = 0;
137         mm_util_rotate_type_e _rot_type = MM_UTIL_ROTATE_0;
138
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);
141
142         if (rot_type)
143                 *rot_type = _rot_type;
144
145         return err;
146 }
147
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)
149 {
150         double ratio = 0.0;
151
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");
156
157         thumb_dbg("origin thumb w: %d h: %d", *thumb_width, *thumb_height);
158
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;
165         } else {
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;
170         }
171
172         thumb_dbg("proper thumb w: %d h: %d", *thumb_width, *thumb_height);
173 }
174
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)
176 {
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;
182
183         thumb_retvm_if(!thumb_path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid thumb_path");
184
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);
187
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);
190
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)
195                                 goto ERROR;
196
197                         err = mm_util_rotate_B_P(resize_img, rot_type, thumb_path);
198
199                 } else {
200                         err = mm_util_resize_B_P(img, thumb_w, thumb_h, thumb_path);
201                 }
202         } else {
203                 if (rot_type != MM_UTIL_ROTATE_0)
204                         err = mm_util_rotate_B_P(img, rot_type, thumb_path);
205                 else
206                         err = mm_util_resize_B_P(img, width, height, thumb_path);
207         }
208
209 ERROR:
210         mm_image_destroy_image(img);
211         mm_image_destroy_image(resize_img);
212
213         return (err == MM_UTIL_ERROR_NONE) ? MS_MEDIA_ERR_NONE : MS_MEDIA_ERR_INTERNAL;
214 }
215
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)
217 {
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;
222
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);
225
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);
228
229         if (width > thumb_w || height > thumb_h)
230                 err = mm_util_resize_B_B(img, thumb_w, thumb_h, dst_img);
231         else
232                 err = mm_image_clone_image(img, dst_img);
233         mm_image_destroy_image(img);
234
235         return (err == MM_UTIL_ERROR_NONE) ? MS_MEDIA_ERR_NONE : MS_MEDIA_ERR_INTERNAL;
236 }
237
238 static int __check_path_validity(const char *path)
239 {
240         thumb_retvm_if(!path, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
241
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;
246                 } else {
247                         thumb_err("Fail to open path: Invalid Path [%s]", path);
248                         return MS_MEDIA_ERR_INVALID_PARAMETER;
249                 }
250         }
251
252         return MS_MEDIA_ERR_NONE;
253 }
254
255 static int __check_thumb_path_validity(const char *path)
256 {
257         char *dir_name = NULL;
258         int ret = MS_MEDIA_ERR_NONE;
259
260         thumb_retvm_if(!THUMB_STRING_VALID(path), MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid path");
261
262         dir_name = g_path_get_dirname(path);
263
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;
268                 } else {
269                         thumb_err("Does not exists[%s]", dir_name);
270                         ret = MS_MEDIA_ERR_INVALID_PARAMETER;
271                 }
272         }
273
274         g_free(dir_name);
275
276         return ret;
277 }
278
279 static int __check_parameter_validity_for_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path)
280 {
281         int err = MS_MEDIA_ERR_NONE;
282
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);
285
286         /* Check path is accessible */
287         err = __check_path_validity(path);
288         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid path");
289
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");
293
294         return MS_MEDIA_ERR_NONE;
295 }
296
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)
298 {
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");
302
303         //Check path is accessible
304         return __check_path_validity(path);
305 }
306
307 int create_video_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path, bool auto_rotate)
308 {
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;
313         void *frame = NULL;
314         size_t frame_size = 0;
315         mm_util_rotate_type_e rot_type = MM_UTIL_ROTATE_NUM;
316
317         err = __check_parameter_validity_for_file(path, width, height, thumb_path);
318         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
319
320         //Get video info
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");
324
325         if (!auto_rotate)
326                 rot_type = MM_UTIL_ROTATE_0;
327
328         //Extract thumbnail
329         err = __get_video_thumb_to_file(video_width, video_height, frame, frame_size, rot_type, thumb_path, width, height);
330         g_free(frame);
331
332         return err;
333 }
334
335 int create_video_thumbnail_to_buffer(const char *path,
336                                                                 unsigned int width,
337                                                                 unsigned int height,
338                                                                 unsigned char **thumb_buffer,
339                                                                 size_t *thumb_size,
340                                                                 unsigned int *thumb_width,
341                                                                 unsigned int *thumb_height)
342 {
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;
347         void *frame = NULL;
348         size_t frame_size = 0;
349         mm_util_image_h img = NULL;
350
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");
353
354         //Get video info
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");
358
359         //Extract thumbnail
360         err = __get_video_thumb_to_buffer(video_w, video_h, frame, frame_size, width, height, &img);
361         g_free(frame);
362         if (err != MS_MEDIA_ERR_NONE)
363                 return err;
364
365         err = mm_image_get_image(img, thumb_width, thumb_height, NULL, thumb_buffer, thumb_size);
366         mm_image_destroy_image(img);
367
368         return err;
369 }
370
371 static int __adjust_thumb_ratio(const char *path, unsigned int *width, unsigned int *height)
372 {
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;
377
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");
381
382         __media_thumb_get_proper_thumb_size(image_w, image_h, width, height);
383
384         return MS_MEDIA_ERR_NONE;
385 }
386
387 int create_image_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path, bool auto_rotate)
388 {
389         int err = MS_MEDIA_ERR_NONE;
390         unsigned int thumb_w = width;
391         unsigned int thumb_h = height;
392
393         err = __check_parameter_validity_for_file(path, width, height, thumb_path);
394         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "Invalid parameter");
395
396         err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
397         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
398
399         if (auto_rotate)
400                 err = mm_util_resize_and_rotate_P_P(path, thumb_w, thumb_h, thumb_path);
401         else
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);
404
405         return MS_MEDIA_ERR_NONE;
406 }
407
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)
409 {
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;
414
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");
417
418         err = __adjust_thumb_ratio(path, &thumb_w, &thumb_h);
419         thumb_retvm_if(err != MS_MEDIA_ERR_NONE, err, "__adjust_thumb_ratio failed");
420
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);
423
424         err = mm_image_get_image(img, thumb_width, thumb_height, NULL, thumb_buffer, thumb_size);
425
426         mm_image_destroy_image(img);
427
428         return err;
429 }
430
431 static int __get_media_type(const char *path, thumbnail_media_type_e *media_type)
432 {
433         int ret = MS_MEDIA_ERR_NONE;
434         char mime[MIME_MAX_LEN] = {0,};
435
436         ret = __check_path_validity(path);
437         thumb_retv_if(ret != MS_MEDIA_ERR_NONE, ret);
438
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");
441
442         thumb_dbg("mime type : %s", mime);
443
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;
448         }
449
450         if (strstr(mime, "video") != NULL) {
451                 *media_type = MEDIA_THUMB_VIDEO;
452                 return MS_MEDIA_ERR_NONE;
453         }
454
455         if (strcmp(mime, MIME_TYPE_ASF) == 0) {
456                 *media_type = MEDIA_THUMB_VIDEO;
457                 return MS_MEDIA_ERR_NONE;
458         }
459
460         return MS_MEDIA_ERR_THUMB_UNSUPPORTED;
461 }
462
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)
464 {
465         int ret = MS_MEDIA_ERR_NONE;
466         thumbnail_media_type_e type = MEDIA_THUMB_INVALID;
467
468         ret = __get_media_type(path, &type);
469         thumb_retvm_if(ret != MS_MEDIA_ERR_NONE, ret, "__get_media_type failed");
470
471         if (type == MEDIA_THUMB_IMAGE)
472                 return create_image_thumbnail_to_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
473         else
474                 return create_video_thumbnail_to_buffer(path, width, height, thumb_buffer, thumb_size, thumb_width, thumb_height);
475 }
476
477 int create_thumbnail_to_file(const char *path, unsigned int width, unsigned int height, const char *thumb_path)
478 {
479         int ret = MS_MEDIA_ERR_NONE;
480         thumbnail_media_type_e type = MEDIA_THUMB_INVALID;
481
482         ret = __get_media_type(path, &type);
483         thumb_retvm_if(ret != MS_MEDIA_ERR_NONE, ret, "__get_media_type failed");
484
485         if (type == MEDIA_THUMB_IMAGE)
486                 return create_image_thumbnail_to_file(path, width, height, thumb_path, false);
487
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;
491         }
492
493         return create_video_thumbnail_to_file(path, width, height, thumb_path, false);
494 }