Add API function to fix x264_picture_t initialization
[x264/x264-sandbox.git] / 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         info->interlaced = 1;
237         info->tff = avs_is_tff( vi );
238     }
239     if( vi->width&1 || vi->height&1 )
240     {
241         fprintf( stderr, "avs [error]: input clip width or height not divisible by 2 (%dx%d)\n",
242                  vi->width, vi->height );
243         return -1;
244     }
245     /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
246        as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
247     if( !avs_is_yv12( vi ) || avs_version >= AVS_INTERFACE_OTHER_PLANAR )
248     {
249         fprintf( stderr, "avs %s\n", !avs_is_yv12( vi ) ? "[warning]: converting input clip to YV12"
250                : "[info]: avisynth 2.6+ detected, forcing conversion to YV12" );
251         const char *arg_name[2] = { NULL, "interlaced" };
252         AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) };
253         AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
254         if( avs_is_error( res2 ) )
255         {
256             fprintf( stderr, "avs [error]: couldn't convert input clip to YV12\n" );
257             return -1;
258         }
259         res = update_clip( h, &vi, res2, res );
260     }
261     h->func.avs_release_value( res );
262
263     info->width = vi->width;
264     info->height = vi->height;
265     info->fps_num = vi->fps_numerator;
266     info->fps_den = vi->fps_denominator;
267     h->num_frames = vi->num_frames;
268     info->csp = X264_CSP_YV12;
269     info->vfr = 0;
270
271     *p_handle = h;
272     return 0;
273 }
274
275 static int get_frame_total( hnd_t handle )
276 {
277     avs_hnd_t *h = handle;
278     return h->num_frames;
279 }
280
281 static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
282 {
283     x264_picture_init( pic );
284     pic->img.i_csp = i_csp;
285     pic->img.i_plane = 3;
286     return 0;
287 }
288
289 static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
290 {
291     static int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_V, AVS_PLANAR_U };
292     avs_hnd_t *h = handle;
293     if( i_frame >= h->num_frames )
294         return -1;
295     AVS_VideoFrame *frm = p_pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
296     const char *err = h->func.avs_clip_get_error( h->clip );
297     if( err )
298     {
299         fprintf( stderr, "avs [error]: %s occurred while reading frame %d\n", err, i_frame );
300         return -1;
301     }
302     for( int i = 0; i < 3; i++ )
303     {
304         /* explicitly cast away the const attribute to avoid a warning */
305         p_pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
306         p_pic->img.i_stride[i] = avs_get_pitch_p( frm, plane[i] );
307     }
308     return 0;
309 }
310
311 static int release_frame( x264_picture_t *pic, hnd_t handle )
312 {
313     avs_hnd_t *h = handle;
314     h->func.avs_release_video_frame( pic->opaque );
315     return 0;
316 }
317
318 static void picture_clean( x264_picture_t *pic )
319 {
320     memset( pic, 0, sizeof(x264_picture_t) );
321 }
322
323 static int close_file( hnd_t handle )
324 {
325     avs_hnd_t *h = handle;
326     h->func.avs_release_clip( h->clip );
327     if( h->func.avs_delete_script_environment )
328         h->func.avs_delete_script_environment( h->env );
329     FreeLibrary( h->library );
330     free( h );
331     return 0;
332 }
333
334 const cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };