FIX: [#37199] .ogg file is not recognized as a movie in File Browser
[blender.git] / source / blender / imbuf / intern / util.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  * util.c
27  *
28  */
29
30 /** \file blender/imbuf/intern/util.c
31  *  \ingroup imbuf
32  */
33
34
35 #ifdef _WIN32
36 #  include <io.h>
37 #  define open _open
38 #  define read _read
39 #  define close _close
40 #endif
41
42 #include <stdlib.h>
43
44 #include "BLI_utildefines.h"
45 #include "BLI_path_util.h"
46 #include "BLI_fileops.h"
47 #include "BLI_string.h"
48
49 #include "DNA_userdef_types.h"
50 #include "BKE_global.h"
51
52 #include "imbuf.h"
53 #include "IMB_imbuf_types.h"
54 #include "IMB_imbuf.h"
55 #include "IMB_filetype.h"
56
57 #include "IMB_anim.h"
58
59 #ifdef WITH_QUICKTIME
60 #include "quicktime_import.h"
61 #endif
62
63 #ifdef WITH_FFMPEG
64 #include <libavcodec/avcodec.h>
65 #include <libavformat/avformat.h>
66 #include <libavdevice/avdevice.h>
67 #include <libavutil/log.h>
68
69 #include "ffmpeg_compat.h"
70
71 #endif
72
73 #define UTIL_DEBUG 0
74
75 const char *imb_ext_image[] = {
76         ".png",
77         ".tga",
78         ".bmp",
79         ".jpg", ".jpeg",
80         ".sgi", ".rgb", ".rgba",
81 #ifdef WITH_TIFF
82         ".tif", ".tiff", ".tx",
83 #endif
84 #ifdef WITH_OPENJPEG
85         ".jp2",
86         ".j2c",
87 #endif
88 #ifdef WITH_HDR
89         ".hdr",
90 #endif
91 #ifdef WITH_DDS
92         ".dds",
93 #endif
94 #ifdef WITH_CINEON
95         ".dpx",
96         ".cin",
97 #endif
98 #ifdef WITH_OPENEXR
99         ".exr",
100 #endif
101 #ifdef WITH_OPENIMAGEIO
102         ".psd", ".pdd", ".psb",
103 #endif
104         NULL
105 };
106
107 const char *imb_ext_image_filepath_only[] = {
108 #ifdef WITH_OPENIMAGEIO
109         ".psd", ".pdd", ".psb",
110 #endif
111         NULL
112 };
113
114 const char *imb_ext_image_qt[] = {
115         ".gif",
116         ".psd",
117         ".pct", ".pict",
118         ".pntg",
119         ".qtif",
120         NULL
121 };
122
123 const char *imb_ext_movie_qt[] = {
124         ".avi",   
125         ".flc",   
126         ".dv",    
127         ".r3d",   
128         ".mov",   
129         ".movie", 
130         ".mv",
131         NULL
132 };
133
134 const char *imb_ext_movie[] = {
135         ".avi",
136         ".flc",
137         ".mov",
138         ".movie",
139         ".mp4",
140         ".m4v",
141         ".m2v",
142         ".m2t",
143         ".m2ts",
144         ".mts",
145         ".mv",
146         ".avs",
147         ".wmv",
148         ".ogv",
149         ".ogg",
150         ".r3d",
151         ".dv",
152         ".mpeg",
153         ".mpg",
154         ".mpg2",
155         ".vob",
156         ".mkv",
157         ".flv",
158         ".divx",
159         ".xvid",
160         ".mxf",
161         ".webm",
162         NULL
163 };
164
165 /* sort of wrong being here... */
166 const char *imb_ext_audio[] = {
167         ".wav",
168         ".ogg",
169         ".oga",
170         ".mp3",
171         ".mp2",
172         ".ac3",
173         ".aac",
174         ".flac",
175         ".wma",
176         ".eac3",
177         ".aif",
178         ".aiff",
179         ".m4a",
180         NULL
181 };
182
183 static int IMB_ispic_name(const char *name)
184 {
185         /* increased from 32 to 64 because of the bitmaps header size */
186 #define HEADER_SIZE 64
187
188         unsigned char buf[HEADER_SIZE];
189         ImFileType *type;
190         struct stat st;
191         int fp;
192
193         if (UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name);
194         
195         if (BLI_stat(name, &st) == -1)
196                 return FALSE;
197         if (((st.st_mode) & S_IFMT) != S_IFREG)
198                 return FALSE;
199
200         if ((fp = BLI_open(name, O_BINARY | O_RDONLY, 0)) < 0)
201                 return FALSE;
202
203         memset(buf, 0, sizeof(buf));
204         if (read(fp, buf, HEADER_SIZE) <= 0) {
205                 close(fp);
206                 return FALSE;
207         }
208
209         close(fp);
210
211         /* XXX move this exception */
212         if ((BIG_LONG(((int *)buf)[0]) & 0xfffffff0) == 0xffd8ffe0)
213                 return JPG;
214
215         for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
216                 if (type->is_a) {
217                         if (type->is_a(buf)) {
218                                 return type->filetype;
219                         }
220                 }
221                 else if (type->is_a_filepath) {
222                         if (type->is_a_filepath(name)) {
223                                 return type->filetype;
224                         }
225                 }
226         }
227
228         return FALSE;
229
230 #undef HEADER_SIZE
231 }
232
233 int IMB_ispic(const char *filename)
234 {
235         if (U.uiflag & USER_FILTERFILEEXTS) {
236                 if ((BLI_testextensie_array(filename, imb_ext_image)) ||
237                     (G.have_quicktime && BLI_testextensie_array(filename, imb_ext_image_qt)))
238                 {
239                         return IMB_ispic_name(filename);
240                 }
241                 else {
242                         return FALSE;
243                 }
244         }
245         else { /* no FILTERFILEEXTS */
246                 return IMB_ispic_name(filename);
247         }
248 }
249
250
251
252 static int isavi(const char *name)
253 {
254 #ifdef WITH_AVI
255         return AVI_is_avi(name);
256 #else
257         (void)name;
258         return FALSE;
259 #endif
260 }
261
262 #ifdef WITH_QUICKTIME
263 static int isqtime(const char *name)
264 {
265         return anim_is_quicktime(name);
266 }
267 #endif
268
269 #ifdef WITH_FFMPEG
270
271 #ifdef _MSC_VER
272 #define va_copy(dst, src) ((dst) = (src))
273 #endif
274
275 /* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */
276 #ifdef __GNUC__
277 #  pragma GCC diagnostic push
278 #  pragma GCC diagnostic ignored "-Wmissing-format-attribute"
279 #endif
280
281 static char ffmpeg_last_error[1024];
282
283 static void ffmpeg_log_callback(void *ptr, int level, const char *format, va_list arg)
284 {
285         if (ELEM(level, AV_LOG_FATAL, AV_LOG_ERROR)) {
286                 size_t n;
287                 va_list args_cpy;
288
289                 va_copy(args_cpy, arg);
290                 n = BLI_vsnprintf(ffmpeg_last_error, sizeof(ffmpeg_last_error), format, args_cpy);
291                 va_end(args_cpy);
292
293                 /* strip trailing \n */
294                 ffmpeg_last_error[n - 1] = '\0';
295         }
296
297         if (G.debug & G_DEBUG_FFMPEG) {
298                 /* call default logger to print all message to console */
299                 av_log_default_callback(ptr, level, format, arg);
300         }
301 }
302
303 #ifdef __GNUC__
304 #  pragma GCC diagnostic pop
305 #endif
306
307 void IMB_ffmpeg_init(void)
308 {
309         av_register_all();
310         avdevice_register_all();
311
312         ffmpeg_last_error[0] = '\0';
313
314         if (G.debug & G_DEBUG_FFMPEG)
315                 av_log_set_level(AV_LOG_DEBUG);
316
317         /* set own callback which could store last error to report to UI */
318         av_log_set_callback(ffmpeg_log_callback);
319 }
320
321 const char *IMB_ffmpeg_last_error(void)
322 {
323         return ffmpeg_last_error;
324 }
325
326 static int isffmpeg(const char *filename)
327 {
328         AVFormatContext *pFormatCtx = NULL;
329         unsigned int i;
330         int videoStream;
331         AVCodec *pCodec;
332         AVCodecContext *pCodecCtx;
333
334         if (BLI_testextensie(filename, ".swf") ||
335             BLI_testextensie(filename, ".jpg") ||
336             BLI_testextensie(filename, ".png") ||
337             BLI_testextensie(filename, ".dds") ||
338             BLI_testextensie(filename, ".tga") ||
339             BLI_testextensie(filename, ".bmp") ||
340             BLI_testextensie(filename, ".tif") ||
341             BLI_testextensie(filename, ".exr") ||
342             BLI_testextensie(filename, ".cin") ||
343             BLI_testextensie(filename, ".wav"))
344         {
345                 return 0;
346         }
347
348         if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
349                 if (UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_open_input_file failed\n");
350                 return 0;
351         }
352
353         if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
354                 if (UTIL_DEBUG) fprintf(stderr, "isffmpeg: avformat_find_stream_info failed\n");
355                 av_close_input_file(pFormatCtx);
356                 return 0;
357         }
358
359         if (UTIL_DEBUG) av_dump_format(pFormatCtx, 0, filename, 0);
360
361
362         /* Find the first video stream */
363         videoStream = -1;
364         for (i = 0; i < pFormatCtx->nb_streams; i++)
365                 if (pFormatCtx->streams[i] &&
366                     pFormatCtx->streams[i]->codec &&
367                     (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO))
368                 {
369                         videoStream = i;
370                         break;
371                 }
372
373         if (videoStream == -1) {
374                 av_close_input_file(pFormatCtx);
375                 return 0;
376         }
377
378         pCodecCtx = pFormatCtx->streams[videoStream]->codec;
379
380         /* Find the decoder for the video stream */
381         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
382         if (pCodec == NULL) {
383                 av_close_input_file(pFormatCtx);
384                 return 0;
385         }
386
387         if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
388                 av_close_input_file(pFormatCtx);
389                 return 0;
390         }
391
392         avcodec_close(pCodecCtx);
393         av_close_input_file(pFormatCtx);
394
395         return 1;
396 }
397 #endif
398
399 #ifdef WITH_REDCODE
400 static int isredcode(const char *filename)
401 {
402         struct redcode_handle *h = redcode_open(filename);
403         if (!h) {
404                 return 0;
405         }
406         redcode_close(h);
407         return 1;
408 }
409
410 #endif
411
412 int imb_get_anim_type(const char *name)
413 {
414         int type;
415         struct stat st;
416
417         if (UTIL_DEBUG) printf("in getanimtype: %s\n", name);
418
419 #ifndef _WIN32
420 #   ifdef WITH_QUICKTIME
421         if (isqtime(name)) return (ANIM_QTIME);
422 #   endif
423 #   ifdef WITH_FFMPEG
424         /* stat test below fails on large files > 4GB */
425         if (isffmpeg(name)) return (ANIM_FFMPEG);
426 #   endif
427         if (BLI_stat(name, &st) == -1) return(0);
428         if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
429
430         if (isavi(name)) return (ANIM_AVI);
431
432         if (ismovie(name)) return (ANIM_MOVIE);
433 #else
434         if (BLI_stat(name, &st) == -1) return(0);
435         if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
436
437         if (ismovie(name)) return (ANIM_MOVIE);
438 #   ifdef WITH_QUICKTIME
439         if (isqtime(name)) return (ANIM_QTIME);
440 #   endif
441 #   ifdef WITH_FFMPEG
442         if (isffmpeg(name)) return (ANIM_FFMPEG);
443 #   endif
444
445
446         if (isavi(name)) return (ANIM_AVI);
447 #endif
448 #ifdef WITH_REDCODE
449         if (isredcode(name)) return (ANIM_REDCODE);
450 #endif
451         type = IMB_ispic(name);
452         if (type) {
453                 return ANIM_SEQUENCE;
454         }
455
456         return ANIM_NONE;
457 }
458  
459 int IMB_isanim(const char *filename)
460 {
461         int type;
462         
463         if (U.uiflag & USER_FILTERFILEEXTS) {
464                 if (G.have_quicktime) {
465                         if (BLI_testextensie_array(filename, imb_ext_movie_qt)) {       
466                                 type = imb_get_anim_type(filename);
467                         }
468                         else {
469                                 return(FALSE);
470                         }
471                 }
472                 else { /* no quicktime */
473                         if (BLI_testextensie_array(filename, imb_ext_movie)) {
474                                 type = imb_get_anim_type(filename);
475                         }
476                         else {
477                                 return(FALSE);
478                         }
479                 }
480         }
481         else { /* no FILTERFILEEXTS */
482                 type = imb_get_anim_type(filename);
483         }
484         
485         return (type && type != ANIM_SEQUENCE);
486 }