]> git.sesse.net Git - x264/blob - input/avs.c
Add TFF/BFF detection to all demuxers
[x264] / input / avs.c
1 /*****************************************************************************
2  * avs.c: x264 avisynth input module
3  *****************************************************************************
4  * Copyright (C) 2009 x264 project
5  *
6  * Authors: Steven Walters <kemuri9@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 #include "muxers.h"
24 #include <windows.h>
25
26 /* the AVS interface currently uses __declspec to link function declarations to their definitions in the dll.
27    this has a side effect of preventing program execution if the avisynth dll is not found,
28    so define __declspec(dllimport) to nothing and work around this */
29 #undef __declspec
30 #define __declspec(i)
31 #undef EXTERN_C
32
33 #ifdef HAVE_AVISYNTH_C_H
34 #include <avisynth_c.h>
35 #else
36 #include "extras/avisynth_c.h"
37 #endif
38
39 /* AVS uses a versioned interface to control backwards compatibility */
40 /* YV12 support is required */
41 #define AVS_INTERFACE_YV12 2
42 /* when AVS supports other planar colorspaces, a workaround is required */
43 #define AVS_INTERFACE_OTHER_PLANAR 5
44
45 /* maximum size of the sequence of filters to try on non script files */
46 #define AVS_MAX_SEQUENCE 5
47
48 #define LOAD_AVS_FUNC(name, continue_on_fail) \
49 {\
50     h->func.name = (void*)GetProcAddress( h->library, #name );\
51     if( !continue_on_fail && !h->func.name )\
52         goto fail;\
53 }
54
55 typedef struct
56 {
57     AVS_Clip *clip;
58     AVS_ScriptEnvironment *env;
59     HMODULE library;
60     int num_frames;
61     /* declare function pointers for the utilized functions to be loaded without __declspec,
62        as the avisynth header does not compensate for this type of usage */
63     struct
64     {
65         const char *(__stdcall *avs_clip_get_error)( AVS_Clip *clip );
66         AVS_ScriptEnvironment *(__stdcall *avs_create_script_environment)( int version );
67         void (__stdcall *avs_delete_script_environment)( AVS_ScriptEnvironment *env );
68         AVS_VideoFrame *(__stdcall *avs_get_frame)( AVS_Clip *clip, int n );
69         int (__stdcall *avs_get_version)( AVS_Clip *clip );
70         const AVS_VideoInfo *(__stdcall *avs_get_video_info)( AVS_Clip *clip );
71         int (__stdcall *avs_function_exists)( AVS_ScriptEnvironment *env, const char *name );
72         AVS_Value (__stdcall *avs_invoke)( AVS_ScriptEnvironment *env, const char *name,
73             AVS_Value args, const char **arg_names );
74         void (__stdcall *avs_release_clip)( AVS_Clip *clip );
75         void (__stdcall *avs_release_value)( AVS_Value value );
76         void (__stdcall *avs_release_video_frame)( AVS_VideoFrame *frame );
77         AVS_Clip *(__stdcall *avs_take_clip)( AVS_Value, AVS_ScriptEnvironment *env );
78     } func;
79 } avs_hnd_t;
80
81 /* load the library and functions we require from it */
82 static int avs_load_library( avs_hnd_t *h )
83 {
84     h->library = LoadLibrary( "avisynth" );
85     if( !h->library )
86         return -1;
87     LOAD_AVS_FUNC( avs_clip_get_error, 0 );
88     LOAD_AVS_FUNC( avs_create_script_environment, 0 );
89     LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
90     LOAD_AVS_FUNC( avs_get_frame, 0 );
91     LOAD_AVS_FUNC( avs_get_version, 0 );
92     LOAD_AVS_FUNC( avs_get_video_info, 0 );
93     LOAD_AVS_FUNC( avs_function_exists, 0 );
94     LOAD_AVS_FUNC( avs_invoke, 0 );
95     LOAD_AVS_FUNC( avs_release_clip, 0 );
96     LOAD_AVS_FUNC( avs_release_value, 0 );
97     LOAD_AVS_FUNC( avs_release_video_frame, 0 );
98     LOAD_AVS_FUNC( avs_take_clip, 0 );
99     return 0;
100 fail:
101     FreeLibrary( h->library );
102     return -1;
103 }
104
105 /* generate a filter sequence to try based on the filename extension */
106 static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] )
107 {
108     int i = 0;
109     const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 };
110     if( !strcasecmp( filename_ext, "avi" ) )
111         filter[i++] = "AVISource";
112     if( !strcasecmp( filename_ext, "d2v" ) )
113         filter[i++] = "MPEG2Source";
114     if( !strcasecmp( filename_ext, "dga" ) )
115         filter[i++] = "AVCSource";
116     for( int j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
117         filter[i++] = all_purpose[j];
118 }
119
120 static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value res, AVS_Value release )
121 {
122     h->func.avs_release_clip( h->clip );
123     h->clip = h->func.avs_take_clip( res, h->env );
124     h->func.avs_release_value( release );
125     *vi = h->func.avs_get_video_info( h->clip );
126     return res;
127 }
128
129 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
130 {
131     FILE *fh = fopen( psz_filename, "r" );
132     if( !fh )
133         return -1;
134     else if( !x264_is_regular_file( fh ) )
135     {
136         fprintf( stderr, "avs [error]: AVS input is incompatible with non-regular file `%s'\n", psz_filename );
137         return -1;
138     }
139     fclose( fh );
140
141     avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
142     if( !h )
143         return -1;
144     if( avs_load_library( h ) )
145     {
146         fprintf( stderr, "avs [error]: failed to load avisynth\n" );
147         return -1;
148     }
149     h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
150     if( !h->env )
151     {
152         fprintf( stderr, "avs [error]: failed to initiate avisynth\n" );
153         return -1;
154     }
155     AVS_Value arg = avs_new_value_string( psz_filename );
156     AVS_Value res;
157     char *filename_ext = get_filename_extension( psz_filename );
158
159     if( !strcasecmp( filename_ext, "avs" ) )
160     {
161         res = h->func.avs_invoke( h->env, "Import", arg, NULL );
162         if( avs_is_error( res ) )
163         {
164             fprintf( stderr, "avs [error]: %s\n", avs_as_string( res ) );
165             return -1;
166         }
167         /* check if the user is using a multi-threaded script and apply distributor if necessary.
168            adapted from avisynth's vfw interface */
169         AVS_Value mt_test = h->func.avs_invoke( h->env, "GetMTMode", avs_new_value_bool( 0 ), NULL );
170         int mt_mode = avs_is_int( mt_test ) ? avs_as_int( mt_test ) : 0;
171         h->func.avs_release_value( mt_test );
172         if( mt_mode > 0 && mt_mode < 5 )
173         {
174             AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
175             h->func.avs_release_value( res );
176             res = temp;
177         }
178     }
179     else /* non script file */
180     {
181         /* cycle through known source filters to find one that works */
182         const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
183         avs_build_filter_sequence( filename_ext, filter );
184         int i;
185         for( i = 0; filter[i]; i++ )
186         {
187             fprintf( stderr, "avs [info]: trying %s... ", filter[i] );
188             if( !h->func.avs_function_exists( h->env, filter[i] ) )
189             {
190                 fprintf( stderr, "not found\n" );
191                 continue;
192             }
193             if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
194             {
195                 fprintf( stderr, "indexing... " );
196                 fflush( stderr );
197             }
198             res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
199             if( !avs_is_error( res ) )
200             {
201                 fprintf( stderr, "succeeded\n" );
202                 break;
203             }
204             fprintf( stderr, "failed\n" );
205         }
206         if( !filter[i] )
207         {
208             fprintf( stderr, "avs [error]: unable to find source filter to open `%s'\n", psz_filename );
209             return -1;
210         }
211     }
212     if( !avs_is_clip( res ) )
213     {
214         fprintf( stderr, "avs [error]: `%s' didn't return a video clip\n", psz_filename );
215         return -1;
216     }
217     h->clip = h->func.avs_take_clip( res, h->env );
218     int avs_version = h->func.avs_get_version( h->clip );
219     const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
220     if( !avs_has_video( vi ) )
221     {
222         fprintf( stderr, "avs [error]: `%s' has no video data\n", psz_filename );
223         return -1;
224     }
225     /* if the clip is made of fields instead of frames, call weave to make them frames */
226     if( avs_is_field_based( vi ) )
227     {
228         fprintf( stderr, "avs [warning]: detected fieldbased (separated) input, weaving to frames\n" );
229         AVS_Value tmp = h->func.avs_invoke( h->env, "Weave", res, NULL );
230         if( avs_is_error( tmp ) )
231         {
232             fprintf( stderr, "avs [error]: couldn't weave fields into frames\n" );
233             return -1;
234         }
235         res = update_clip( h, &vi, tmp, res );
236     }
237     if( vi->width&1 || vi->height&1 )
238     {
239         fprintf( stderr, "avs [error]: input clip width or height not divisible by 2 (%dx%d)\n",
240                  vi->width, vi->height );
241         return -1;
242     }
243     /* bff/tff flags in avisynth are not technically mutually exclusive, which can lead to both being set.
244      * avisynth's own functions enact mutual exclusion, but source filters are not guaranteed to do this. */
245     int tff = avs_is_tff( vi );
246     if( avs_is_bff( vi ) ^ tff )
247     {
248         info->interlaced = 1;
249         info->tff = !!tff;
250     }
251     /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
252        as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
253     if( !avs_is_yv12( vi ) || avs_version >= AVS_INTERFACE_OTHER_PLANAR )
254     {
255         fprintf( stderr, "avs %s\n", !avs_is_yv12( vi ) ? "[warning]: converting input clip to YV12"
256                : "[info]: avisynth 2.6+ detected, forcing conversion to YV12" );
257         const char *arg_name[2] = { NULL, "interlaced" };
258         AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) };
259         AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
260         if( avs_is_error( res2 ) )
261         {
262             fprintf( stderr, "avs [error]: couldn't convert input clip to YV12\n" );
263             return -1;
264         }
265         res = update_clip( h, &vi, res2, res );
266     }
267     h->func.avs_release_value( res );
268
269     info->width = vi->width;
270     info->height = vi->height;
271     info->fps_num = vi->fps_numerator;
272     info->fps_den = vi->fps_denominator;
273     h->num_frames = vi->num_frames;
274     info->csp = X264_CSP_YV12;
275     info->vfr = 0;
276
277     *p_handle = h;
278     return 0;
279 }
280
281 static int get_frame_total( hnd_t handle )
282 {
283     avs_hnd_t *h = handle;
284     return h->num_frames;
285 }
286
287 static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
288 {
289     pic->img.i_csp = i_csp;
290     pic->img.i_plane = 3;
291     pic->param = NULL;
292     pic->i_pic_struct = PIC_STRUCT_AUTO;
293     return 0;
294 }
295
296 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
297 {
298     static int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_V, AVS_PLANAR_U };
299     avs_hnd_t *h = handle;
300     if( i_frame >= h->num_frames )
301         return -1;
302     AVS_VideoFrame *frm = p_pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
303     const char *err = h->func.avs_clip_get_error( h->clip );
304     if( err )
305     {
306         fprintf( stderr, "avs [error]: %s occurred while reading frame %d\n", err, i_frame );
307         return -1;
308     }
309     for( int i = 0; i < 3; i++ )
310     {
311         /* explicitly cast away the const attribute to avoid a warning */
312         p_pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
313         p_pic->img.i_stride[i] = avs_get_pitch_p( frm, plane[i] );
314     }
315     return 0;
316 }
317
318 static int release_frame( x264_picture_t *pic, hnd_t handle )
319 {
320     avs_hnd_t *h = handle;
321     h->func.avs_release_video_frame( pic->opaque );
322     return 0;
323 }
324
325 static void picture_clean( x264_picture_t *pic )
326 {
327     memset( pic, 0, sizeof(x264_picture_t) );
328 }
329
330 static int close_file( hnd_t handle )
331 {
332     avs_hnd_t *h = handle;
333     h->func.avs_release_clip( h->clip );
334     if( h->func.avs_delete_script_environment )
335         h->func.avs_delete_script_environment( h->env );
336     FreeLibrary( h->library );
337     free( h );
338     return 0;
339 }
340
341 const cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };