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( j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
117 filter[i++] = all_purpose[j];
120 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
122 FILE *fh = fopen( psz_filename, "r" );
125 else if( !x264_is_regular_file( fh ) )
127 fprintf( stderr, "avs [error]: AVS input is incompatible with non-regular file `%s'\n", psz_filename );
132 avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
135 if( avs_load_library( h ) )
137 fprintf( stderr, "avs [error]: failed to load avisynth\n" );
140 h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
143 fprintf( stderr, "avs [error]: failed to initiate avisynth\n" );
146 AVS_Value arg = avs_new_value_string( psz_filename );
148 char *filename_ext = get_filename_extension( psz_filename );
150 if( !strcasecmp( filename_ext, "avs" ) )
152 res = h->func.avs_invoke( h->env, "Import", arg, NULL );
153 if( avs_is_error( res ) )
155 fprintf( stderr, "avs [error]: %s\n", avs_as_string( res ) );
158 /* check if the user is using a multi-threaded script and apply distributor if necessary.
159 adapted from avisynth's vfw interface */
160 AVS_Value mt_test = h->func.avs_invoke( h->env, "GetMTMode", avs_new_value_bool( 0 ), NULL );
161 int mt_mode = avs_is_int( mt_test ) ? avs_as_int( mt_test ) : 0;
162 h->func.avs_release_value( mt_test );
163 if( mt_mode > 0 && mt_mode < 5 )
165 AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
166 h->func.avs_release_value( res );
170 else /* non script file */
172 /* cycle through known source filters to find one that works */
173 const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
174 avs_build_filter_sequence( filename_ext, filter );
176 for( i = 0; filter[i]; i++ )
178 fprintf( stderr, "avs [info]: trying %s... ", filter[i] );
179 if( !h->func.avs_function_exists( h->env, filter[i] ) )
181 fprintf( stderr, "not found\n" );
184 if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
186 fprintf( stderr, "indexing... " );
189 res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
190 if( !avs_is_error( res ) )
192 fprintf( stderr, "succeeded\n" );
195 fprintf( stderr, "failed\n" );
199 fprintf( stderr, "avs [error]: unable to find source filter to open `%s'\n", psz_filename );
203 if( !avs_is_clip( res ) )
205 fprintf( stderr, "avs [error]: `%s' didn't return a video clip\n", psz_filename );
208 h->clip = h->func.avs_take_clip( res, h->env );
209 int avs_version = h->func.avs_get_version( h->clip );
210 const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
211 if( !avs_has_video( vi ) )
213 fprintf( stderr, "avs [error]: `%s' has no video data\n", psz_filename );
216 if( vi->width&1 || vi->height&1 )
218 fprintf( stderr, "avs [error]: input clip width or height not divisible by 2 (%dx%d)\n",
219 vi->width, vi->height );
222 /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
223 as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
224 if( !avs_is_yv12( vi ) || avs_version >= AVS_INTERFACE_OTHER_PLANAR )
226 h->func.avs_release_clip( h->clip );
227 fprintf( stderr, "avs %s\n", !avs_is_yv12( vi ) ? "[warning]: converting input clip to YV12"
228 : "[info]: avisynth 2.6+ detected, forcing conversion to YV12" );
229 const char *arg_name[2] = { NULL, "interlaced" };
230 AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) };
231 AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
232 if( avs_is_error( res2 ) )
234 fprintf( stderr, "avs [error]: couldn't convert input clip to YV12\n" );
237 h->clip = h->func.avs_take_clip( res2, h->env );
238 h->func.avs_release_value( res2 );
239 vi = h->func.avs_get_video_info( h->clip );
241 h->func.avs_release_value( res );
243 info->width = vi->width;
244 info->height = vi->height;
245 info->fps_num = vi->fps_numerator;
246 info->fps_den = vi->fps_denominator;
247 h->num_frames = vi->num_frames;
248 info->csp = X264_CSP_YV12;
255 static int get_frame_total( hnd_t handle )
257 avs_hnd_t *h = handle;
258 return h->num_frames;
261 static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
263 pic->img.i_csp = i_csp;
264 pic->img.i_plane = 3;
269 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
271 static int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_V, AVS_PLANAR_U };
272 avs_hnd_t *h = handle;
273 if( i_frame >= h->num_frames )
275 AVS_VideoFrame *frm =
276 p_pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
278 const char *err = h->func.avs_clip_get_error( h->clip );
281 fprintf( stderr, "avs [error]: %s occurred while reading frame %d\n", err, i_frame );
284 for( i = 0; i < 3; i++ )
286 /* explicitly cast away the const attribute to avoid a warning */
287 p_pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
288 p_pic->img.i_stride[i] = avs_get_pitch_p( frm, plane[i] );
293 static int release_frame( x264_picture_t *pic, hnd_t handle )
295 avs_hnd_t *h = handle;
296 h->func.avs_release_video_frame( pic->opaque );
300 static void picture_clean( x264_picture_t *pic )
302 memset( pic, 0, sizeof(x264_picture_t) );
305 static int close_file( hnd_t handle )
307 avs_hnd_t *h = handle;
308 h->func.avs_release_clip( h->clip );
309 if( h->func.avs_delete_script_environment )
310 h->func.avs_delete_script_environment( h->env );
311 FreeLibrary( h->library );
316 const cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };