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 *****************************************************************************/
25 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "avs", __VA_ARGS__ )
27 /* the AVS interface currently uses __declspec to link function declarations to their definitions in the dll.
28 this has a side effect of preventing program execution if the avisynth dll is not found,
29 so define __declspec(dllimport) to nothing and work around this */
35 #include <avisynth_c.h>
37 #include "extras/avisynth_c.h"
40 /* AVS uses a versioned interface to control backwards compatibility */
41 /* YV12 support is required */
42 #define AVS_INTERFACE_YV12 2
43 /* when AVS supports other planar colorspaces, a workaround is required */
44 #define AVS_INTERFACE_OTHER_PLANAR 5
47 #include <libavutil/pixfmt.h>
50 /* maximum size of the sequence of filters to try on non script files */
51 #define AVS_MAX_SEQUENCE 5
53 #define LOAD_AVS_FUNC(name, continue_on_fail)\
55 h->func.name = (void*)GetProcAddress( h->library, #name );\
56 if( !continue_on_fail && !h->func.name )\
63 AVS_ScriptEnvironment *env;
66 /* declare function pointers for the utilized functions to be loaded without __declspec,
67 as the avisynth header does not compensate for this type of usage */
70 const char *(__stdcall *avs_clip_get_error)( AVS_Clip *clip );
71 AVS_ScriptEnvironment *(__stdcall *avs_create_script_environment)( int version );
72 void (__stdcall *avs_delete_script_environment)( AVS_ScriptEnvironment *env );
73 AVS_VideoFrame *(__stdcall *avs_get_frame)( AVS_Clip *clip, int n );
74 int (__stdcall *avs_get_version)( AVS_Clip *clip );
75 const AVS_VideoInfo *(__stdcall *avs_get_video_info)( AVS_Clip *clip );
76 int (__stdcall *avs_function_exists)( AVS_ScriptEnvironment *env, const char *name );
77 AVS_Value (__stdcall *avs_invoke)( AVS_ScriptEnvironment *env, const char *name,
78 AVS_Value args, const char **arg_names );
79 void (__stdcall *avs_release_clip)( AVS_Clip *clip );
80 void (__stdcall *avs_release_value)( AVS_Value value );
81 void (__stdcall *avs_release_video_frame)( AVS_VideoFrame *frame );
82 AVS_Clip *(__stdcall *avs_take_clip)( AVS_Value, AVS_ScriptEnvironment *env );
86 /* load the library and functions we require from it */
87 static int avs_load_library( avs_hnd_t *h )
89 h->library = LoadLibrary( "avisynth" );
92 LOAD_AVS_FUNC( avs_clip_get_error, 0 );
93 LOAD_AVS_FUNC( avs_create_script_environment, 0 );
94 LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
95 LOAD_AVS_FUNC( avs_get_frame, 0 );
96 LOAD_AVS_FUNC( avs_get_version, 0 );
97 LOAD_AVS_FUNC( avs_get_video_info, 0 );
98 LOAD_AVS_FUNC( avs_function_exists, 0 );
99 LOAD_AVS_FUNC( avs_invoke, 0 );
100 LOAD_AVS_FUNC( avs_release_clip, 0 );
101 LOAD_AVS_FUNC( avs_release_value, 0 );
102 LOAD_AVS_FUNC( avs_release_video_frame, 0 );
103 LOAD_AVS_FUNC( avs_take_clip, 0 );
106 FreeLibrary( h->library );
110 /* generate a filter sequence to try based on the filename extension */
111 static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] )
114 const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 };
115 if( !strcasecmp( filename_ext, "avi" ) )
116 filter[i++] = "AVISource";
117 if( !strcasecmp( filename_ext, "d2v" ) )
118 filter[i++] = "MPEG2Source";
119 if( !strcasecmp( filename_ext, "dga" ) )
120 filter[i++] = "AVCSource";
121 for( int j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
122 filter[i++] = all_purpose[j];
125 static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value res, AVS_Value release )
127 h->func.avs_release_clip( h->clip );
128 h->clip = h->func.avs_take_clip( res, h->env );
129 h->func.avs_release_value( release );
130 *vi = h->func.avs_get_video_info( h->clip );
134 static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
136 FILE *fh = fopen( psz_filename, "r" );
139 FAIL_IF_ERROR( !x264_is_regular_file( fh ), "AVS input is incompatible with non-regular file `%s'\n", psz_filename );
142 avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
145 FAIL_IF_ERROR( avs_load_library( h ), "failed to load avisynth\n" )
146 h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
147 FAIL_IF_ERROR( !h->env, "failed to initiate avisynth\n" )
148 AVS_Value arg = avs_new_value_string( psz_filename );
150 char *filename_ext = get_filename_extension( psz_filename );
152 if( !strcasecmp( filename_ext, "avs" ) )
154 res = h->func.avs_invoke( h->env, "Import", arg, NULL );
155 FAIL_IF_ERROR( avs_is_error( res ), "%s\n", avs_as_string( res ) )
156 /* check if the user is using a multi-threaded script and apply distributor if necessary.
157 adapted from avisynth's vfw interface */
158 AVS_Value mt_test = h->func.avs_invoke( h->env, "GetMTMode", avs_new_value_bool( 0 ), NULL );
159 int mt_mode = avs_is_int( mt_test ) ? avs_as_int( mt_test ) : 0;
160 h->func.avs_release_value( mt_test );
161 if( mt_mode > 0 && mt_mode < 5 )
163 AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
164 h->func.avs_release_value( res );
168 else /* non script file */
170 /* cycle through known source filters to find one that works */
171 const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
172 avs_build_filter_sequence( filename_ext, filter );
174 for( i = 0; filter[i]; i++ )
176 x264_cli_log( "avs", X264_LOG_INFO, "trying %s... ", filter[i] );
177 if( !h->func.avs_function_exists( h->env, filter[i] ) )
179 x264_cli_printf( X264_LOG_INFO, "not found\n" );
182 if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
184 x264_cli_printf( X264_LOG_INFO, "indexing... " );
187 res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
188 if( !avs_is_error( res ) )
190 x264_cli_printf( X264_LOG_INFO, "succeeded\n" );
193 x264_cli_printf( X264_LOG_INFO, "failed\n" );
195 FAIL_IF_ERROR( !filter[i], "unable to find source filter to open `%s'\n", psz_filename )
197 FAIL_IF_ERROR( !avs_is_clip( res ), "`%s' didn't return a video clip\n", psz_filename )
198 h->clip = h->func.avs_take_clip( res, h->env );
199 int avs_version = h->func.avs_get_version( h->clip );
200 const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
201 FAIL_IF_ERROR( !avs_has_video( vi ), "`%s' has no video data\n", psz_filename )
202 /* if the clip is made of fields instead of frames, call weave to make them frames */
203 if( avs_is_field_based( vi ) )
205 x264_cli_log( "avs", X264_LOG_WARNING, "detected fieldbased (separated) input, weaving to frames\n" );
206 AVS_Value tmp = h->func.avs_invoke( h->env, "Weave", res, NULL );
207 FAIL_IF_ERROR( avs_is_error( tmp ), "couldn't weave fields into frames\n" )
208 res = update_clip( h, &vi, tmp, res );
209 info->interlaced = 1;
210 info->tff = avs_is_tff( vi );
212 /* if swscale is available, convert CSPs with it rather than with avisynth. */
214 int convert_to_yv12 = 0;
216 int convert_to_yv12 = !avs_is_yv12( vi );
218 /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
219 as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
220 if( convert_to_yv12 || (avs_version >= AVS_INTERFACE_OTHER_PLANAR && avs_is_yv12( vi )) )
222 if( convert_to_yv12 )
223 x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to YV12" );
225 x264_cli_log( "avs", X264_LOG_INFO, "avisynth 2.6+ detected, forcing conversion to YV12" );
226 FAIL_IF_ERROR( vi->width&1 || vi->height&1, "input clip width or height not divisible by 2 (%dx%d)\n", vi->width, vi->height )
227 const char *arg_name[2] = { NULL, "interlaced" };
228 AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) };
229 AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
230 FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert input clip to YV12\n" )
231 res = update_clip( h, &vi, res2, res );
233 h->func.avs_release_value( res );
235 info->width = vi->width;
236 info->height = vi->height;
237 info->fps_num = vi->fps_numerator;
238 info->fps_den = vi->fps_denominator;
239 h->num_frames = info->num_frames = vi->num_frames;
240 info->thread_safe = 1;
242 if( avs_is_rgb32( vi ) )
243 info->csp = X264_CSP_BGRA | X264_CSP_VFLIP;
244 else if( avs_is_rgb24( vi ) )
245 info->csp = X264_CSP_BGR | X264_CSP_VFLIP;
246 else if( avs_is_yuy2( vi ) )
247 info->csp = PIX_FMT_YUYV422 | X264_CSP_OTHER;
249 info->csp = X264_CSP_I420;
251 info->csp = X264_CSP_I420;
259 static int picture_alloc( cli_pic_t *pic, int csp, int width, int height )
261 if( x264_cli_pic_alloc( pic, X264_CSP_NONE, width, height ) )
264 const x264_cli_csp_t *cli_csp = x264_cli_get_csp( csp );
265 pic->img.planes = cli_csp ? cli_csp->planes : 1;
269 static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame )
271 static const int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V };
272 avs_hnd_t *h = handle;
273 if( i_frame >= h->num_frames )
275 AVS_VideoFrame *frm = pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
276 const char *err = h->func.avs_clip_get_error( h->clip );
277 FAIL_IF_ERROR( err, "%s occurred while reading frame %d\n", err, i_frame )
278 for( int i = 0; i < pic->img.planes; i++ )
280 /* explicitly cast away the const attribute to avoid a warning */
281 pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
282 pic->img.stride[i] = avs_get_pitch_p( frm, plane[i] );
287 static int release_frame( cli_pic_t *pic, hnd_t handle )
289 avs_hnd_t *h = handle;
290 h->func.avs_release_video_frame( pic->opaque );
294 static void picture_clean( cli_pic_t *pic )
296 memset( pic, 0, sizeof(cli_pic_t) );
299 static int close_file( hnd_t handle )
301 avs_hnd_t *h = handle;
302 h->func.avs_release_clip( h->clip );
303 if( h->func.avs_delete_script_environment )
304 h->func.avs_delete_script_environment( h->env );
305 FreeLibrary( h->library );
310 const cli_input_t avs_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };