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;
60 /* declare function pointers for the utilized functions to be loaded without __declspec,
61 as the avisynth header does not compensate for this type of usage */
64 const char *(__stdcall *avs_clip_get_error)( AVS_Clip *clip );
65 AVS_ScriptEnvironment *(__stdcall *avs_create_script_environment)( int version );
66 void (__stdcall *avs_delete_script_environment)( AVS_ScriptEnvironment *env );
67 AVS_VideoFrame *(__stdcall *avs_get_frame)( AVS_Clip *clip, int n );
68 int (__stdcall *avs_get_version)( AVS_Clip *clip );
69 const AVS_VideoInfo *(__stdcall *avs_get_video_info)( AVS_Clip *clip );
70 int (__stdcall *avs_function_exists)( AVS_ScriptEnvironment *env, const char *name );
71 AVS_Value (__stdcall *avs_invoke)( AVS_ScriptEnvironment *env, const char *name,
72 AVS_Value args, const char **arg_names );
73 void (__stdcall *avs_release_clip)( AVS_Clip *clip );
74 void (__stdcall *avs_release_value)( AVS_Value value );
75 void (__stdcall *avs_release_video_frame)( AVS_VideoFrame *frame );
76 AVS_Clip *(__stdcall *avs_take_clip)( AVS_Value, AVS_ScriptEnvironment *env );
80 /* load the library and functions we require from it */
81 static int avs_load_library( avs_hnd_t *h )
83 h->library = LoadLibrary( "avisynth" );
86 LOAD_AVS_FUNC( avs_clip_get_error, 0 );
87 LOAD_AVS_FUNC( avs_create_script_environment, 0 );
88 LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
89 LOAD_AVS_FUNC( avs_get_frame, 0 );
90 LOAD_AVS_FUNC( avs_get_version, 0 );
91 LOAD_AVS_FUNC( avs_get_video_info, 0 );
92 LOAD_AVS_FUNC( avs_function_exists, 0 );
93 LOAD_AVS_FUNC( avs_invoke, 0 );
94 LOAD_AVS_FUNC( avs_release_clip, 0 );
95 LOAD_AVS_FUNC( avs_release_value, 0 );
96 LOAD_AVS_FUNC( avs_release_video_frame, 0 );
97 LOAD_AVS_FUNC( avs_take_clip, 0 );
100 FreeLibrary( h->library );
104 /* generate a filter sequence to try based on the filename extension */
105 static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] )
108 const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 };
109 if( !strcasecmp( filename_ext, "avi" ) )
110 filter[i++] = "AVISource";
111 if( !strcasecmp( filename_ext, "d2v" ) )
112 filter[i++] = "MPEG2Source";
113 if( !strcasecmp( filename_ext, "dga" ) )
114 filter[i++] = "AVCSource";
115 for( j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
116 filter[i++] = all_purpose[j];
119 static int open_file( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param )
121 FILE *fh = fopen( psz_filename, "r" );
124 else if( !x264_is_regular_file( fh ) )
126 fprintf( stderr, "avs [error]: AVS input is incompatible with non-regular file `%s'\n", psz_filename );
131 avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
134 if( avs_load_library( h ) )
136 fprintf( stderr, "avs [error]: failed to load avisynth\n" );
139 h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
142 fprintf( stderr, "avs [error]: failed to initiate avisynth\n" );
145 AVS_Value arg = avs_new_value_string( psz_filename );
147 char *filename_ext = get_filename_extension( psz_filename );
149 if( !strcasecmp( filename_ext, "avs" ) )
151 res = h->func.avs_invoke( h->env, "Import", arg, NULL );
152 if( avs_is_error( res ) )
154 fprintf( stderr, "avs [error]: %s\n", avs_as_string( res ) );
158 else /* non script file */
160 /* cycle through known source filters to find one that works */
161 const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
162 avs_build_filter_sequence( filename_ext, filter );
164 for( i = 0; filter[i]; i++ )
166 fprintf( stderr, "avs [info]: Trying %s... ", filter[i] );
167 if( !h->func.avs_function_exists( h->env, filter[i] ) )
169 fprintf( stderr, "not found\n" );
172 if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
174 fprintf( stderr, "Indexing... " );
177 res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
178 if( !avs_is_error( res ) )
180 fprintf( stderr, "succeeded\n" );
183 fprintf( stderr, "failed\n" );
187 fprintf( stderr, "avs [error]: unable to find source filter to open `%s'\n", psz_filename );
191 if( !avs_is_clip( res ) )
193 fprintf( stderr, "avs [error]: `%s' didn't return a video clip\n", psz_filename );
196 h->clip = h->func.avs_take_clip( res, h->env );
197 int avs_version = h->func.avs_get_version( h->clip );
198 const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
199 if( !avs_has_video( vi ) )
201 fprintf( stderr, "avs [error]: `%s' has no video data\n", psz_filename );
204 if( vi->width&1 || vi->height&1 )
206 fprintf( stderr, "avs [error]: input clip width or height not divisible by 2 (%dx%d)\n",
207 vi->width, vi->height );
210 /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
211 as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
212 if( !avs_is_yv12( vi ) || avs_version >= AVS_INTERFACE_OTHER_PLANAR )
214 h->func.avs_release_clip( h->clip );
215 fprintf( stderr, "avs [warning]: converting input clip to YV12\n" );
216 const char *arg_name[2] = { NULL, "interlaced" };
217 AVS_Value arg_arr[2] = { res, avs_new_value_bool( p_param->b_interlaced ) };
218 AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
219 if( avs_is_error( res2 ) )
221 fprintf( stderr, "avs [error]: Couldn't convert input clip to YV12\n" );
224 h->clip = h->func.avs_take_clip( res2, h->env );
225 h->func.avs_release_value( res2 );
226 vi = h->func.avs_get_video_info( h->clip );
228 h->func.avs_release_value( res );
230 p_param->i_width = vi->width;
231 p_param->i_height = vi->height;
232 p_param->i_fps_num = vi->fps_numerator;
233 p_param->i_fps_den = vi->fps_denominator;
234 p_param->i_csp = X264_CSP_YV12;
236 fprintf( stderr, "avs [info]: %dx%d @ %.2f fps (%d frames)\n",
237 p_param->i_width, p_param->i_height,
238 (double)p_param->i_fps_num / p_param->i_fps_den,
245 static int get_frame_total( hnd_t handle )
247 avs_hnd_t *h = handle;
248 const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
249 return vi->num_frames;
252 static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
254 pic->img.i_csp = i_csp;
255 pic->img.i_plane = 3;
260 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
262 static int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_V, AVS_PLANAR_U };
263 avs_hnd_t *h = handle;
264 AVS_VideoFrame *frm =
265 p_pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
267 const char *err = h->func.avs_clip_get_error( h->clip );
270 fprintf( stderr, "avs [error]: %s occurred while reading frame %d\n", err, i_frame );
273 for( i = 0; i < 3; i++ )
275 /* explicitly cast away the const attribute to avoid a warning */
276 p_pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
277 p_pic->img.i_stride[i] = avs_get_pitch_p( frm, plane[i] );
282 static int release_frame( x264_picture_t *pic, hnd_t handle )
284 avs_hnd_t *h = handle;
285 h->func.avs_release_video_frame( pic->opaque );
289 static void picture_clean( x264_picture_t *pic )
291 memset( pic, 0, sizeof(x264_picture_t) );
294 static int close_file( hnd_t handle )
296 avs_hnd_t *h = handle;
297 h->func.avs_release_clip( h->clip );
298 if( h->func.avs_delete_script_environment )
299 h->func.avs_delete_script_environment( h->env );
300 FreeLibrary( h->library );
305 cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };