1 /*****************************************************************************
2 * avs.c: x264 avisynth input module
3 *****************************************************************************
4 * Copyright (C) 2009 x264 project
6 * Authors: Steven Walters <kemuri9@gmail.com>
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.
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.
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 *****************************************************************************/
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 */
33 #ifdef HAVE_AVISYNTH_C_H
34 #include <avisynth_c.h>
36 #include "extras/avisynth_c.h"
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
45 /* maximum size of the sequence of filters to try on non script files */
46 #define AVS_MAX_SEQUENCE 5
48 #define LOAD_AVS_FUNC(name, continue_on_fail) \
50 h->func.name = (void*)GetProcAddress( h->library, #name );\
51 if( !continue_on_fail && !h->func.name )\
58 AVS_ScriptEnvironment *env;
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 */
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 );
81 /* load the library and functions we require from it */
82 static int avs_load_library( avs_hnd_t *h )
84 h->library = LoadLibrary( "avisynth" );
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 );
101 FreeLibrary( h->library );
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] )
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];
120 static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value res, AVS_Value release )
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 );
129 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
131 FILE *fh = fopen( psz_filename, "r" );
134 else if( !x264_is_regular_file( fh ) )
136 fprintf( stderr, "avs [error]: AVS input is incompatible with non-regular file `%s'\n", psz_filename );
141 avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
144 if( avs_load_library( h ) )
146 fprintf( stderr, "avs [error]: failed to load avisynth\n" );
149 h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
152 fprintf( stderr, "avs [error]: failed to initiate avisynth\n" );
155 AVS_Value arg = avs_new_value_string( psz_filename );
157 char *filename_ext = get_filename_extension( psz_filename );
159 if( !strcasecmp( filename_ext, "avs" ) )
161 res = h->func.avs_invoke( h->env, "Import", arg, NULL );
162 if( avs_is_error( res ) )
164 fprintf( stderr, "avs [error]: %s\n", avs_as_string( res ) );
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 )
174 AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
175 h->func.avs_release_value( res );
179 else /* non script file */
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 );
185 for( i = 0; filter[i]; i++ )
187 fprintf( stderr, "avs [info]: trying %s... ", filter[i] );
188 if( !h->func.avs_function_exists( h->env, filter[i] ) )
190 fprintf( stderr, "not found\n" );
193 if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
195 fprintf( stderr, "indexing... " );
198 res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
199 if( !avs_is_error( res ) )
201 fprintf( stderr, "succeeded\n" );
204 fprintf( stderr, "failed\n" );
208 fprintf( stderr, "avs [error]: unable to find source filter to open `%s'\n", psz_filename );
212 if( !avs_is_clip( res ) )
214 fprintf( stderr, "avs [error]: `%s' didn't return a video clip\n", psz_filename );
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 ) )
222 fprintf( stderr, "avs [error]: `%s' has no video data\n", psz_filename );
225 /* if the clip is made of fields instead of frames, call weave to make them frames */
226 if( avs_is_field_based( vi ) )
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 ) )
232 fprintf( stderr, "avs [error]: couldn't weave fields into frames\n" );
235 res = update_clip( h, &vi, tmp, res );
237 if( vi->width&1 || vi->height&1 )
239 fprintf( stderr, "avs [error]: input clip width or height not divisible by 2 (%dx%d)\n",
240 vi->width, vi->height );
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 )
248 info->interlaced = 1;
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 )
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 ) )
262 fprintf( stderr, "avs [error]: couldn't convert input clip to YV12\n" );
265 res = update_clip( h, &vi, res2, res );
267 h->func.avs_release_value( res );
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;
281 static int get_frame_total( hnd_t handle )
283 avs_hnd_t *h = handle;
284 return h->num_frames;
287 static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
289 pic->img.i_csp = i_csp;
290 pic->img.i_plane = 3;
292 pic->i_pic_struct = PIC_STRUCT_AUTO;
296 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
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 )
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 );
306 fprintf( stderr, "avs [error]: %s occurred while reading frame %d\n", err, i_frame );
309 for( int i = 0; i < 3; i++ )
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] );
318 static int release_frame( x264_picture_t *pic, hnd_t handle )
320 avs_hnd_t *h = handle;
321 h->func.avs_release_video_frame( pic->opaque );
325 static void picture_clean( x264_picture_t *pic )
327 memset( pic, 0, sizeof(x264_picture_t) );
330 static int close_file( hnd_t handle )
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 );
341 const cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };