/*****************************************************************************
- * avs.c: x264 avisynth input module
+ * avs.c: avisynth input
*****************************************************************************
- * Copyright (C) 2009 x264 project
+ * Copyright (C) 2009-2010 x264 project
*
* Authors: Steven Walters <kemuri9@gmail.com>
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
+ *
+ * This program is also available under a commercial proprietary license.
+ * For more information, contact us at licensing@x264.com.
*****************************************************************************/
#include "input.h"
#include <windows.h>
#define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "avs", __VA_ARGS__ )
-/* the AVS interface currently uses __declspec to link function declarations to their definitions in the dll.
- this has a side effect of preventing program execution if the avisynth dll is not found,
- so define __declspec(dllimport) to nothing and work around this */
-#undef __declspec
-#define __declspec(i)
+#define AVSC_NO_DECLSPEC
#undef EXTERN_C
-
-#if HAVE_AVISYNTH_C_H
-#include <avisynth_c.h>
-#else
#include "extras/avisynth_c.h"
-#endif
+#define AVSC_DECLARE_FUNC(name) name##_func name
/* AVS uses a versioned interface to control backwards compatibility */
-/* YV12 support is required */
-#define AVS_INTERFACE_YV12 2
-/* when AVS supports other planar colorspaces, a workaround is required */
-#define AVS_INTERFACE_OTHER_PLANAR 5
+/* YV12 support is required, which was added in 2.5 */
+#define AVS_INTERFACE_25 2
+
+#if HAVE_SWSCALE
+#include <libavutil/pixfmt.h>
+#endif
/* maximum size of the sequence of filters to try on non script files */
#define AVS_MAX_SEQUENCE 5
AVS_ScriptEnvironment *env;
HMODULE library;
int num_frames;
- /* declare function pointers for the utilized functions to be loaded without __declspec,
- as the avisynth header does not compensate for this type of usage */
struct
{
- const char *(__stdcall *avs_clip_get_error)( AVS_Clip *clip );
- AVS_ScriptEnvironment *(__stdcall *avs_create_script_environment)( int version );
- void (__stdcall *avs_delete_script_environment)( AVS_ScriptEnvironment *env );
- AVS_VideoFrame *(__stdcall *avs_get_frame)( AVS_Clip *clip, int n );
- int (__stdcall *avs_get_version)( AVS_Clip *clip );
- const AVS_VideoInfo *(__stdcall *avs_get_video_info)( AVS_Clip *clip );
- int (__stdcall *avs_function_exists)( AVS_ScriptEnvironment *env, const char *name );
- AVS_Value (__stdcall *avs_invoke)( AVS_ScriptEnvironment *env, const char *name,
- AVS_Value args, const char **arg_names );
- void (__stdcall *avs_release_clip)( AVS_Clip *clip );
- void (__stdcall *avs_release_value)( AVS_Value value );
- void (__stdcall *avs_release_video_frame)( AVS_VideoFrame *frame );
- AVS_Clip *(__stdcall *avs_take_clip)( AVS_Value, AVS_ScriptEnvironment *env );
+ AVSC_DECLARE_FUNC( avs_clip_get_error );
+ AVSC_DECLARE_FUNC( avs_create_script_environment );
+ AVSC_DECLARE_FUNC( avs_delete_script_environment );
+ AVSC_DECLARE_FUNC( avs_get_frame );
+ AVSC_DECLARE_FUNC( avs_get_video_info );
+ AVSC_DECLARE_FUNC( avs_function_exists );
+ AVSC_DECLARE_FUNC( avs_invoke );
+ AVSC_DECLARE_FUNC( avs_release_clip );
+ AVSC_DECLARE_FUNC( avs_release_value );
+ AVSC_DECLARE_FUNC( avs_release_video_frame );
+ AVSC_DECLARE_FUNC( avs_take_clip );
} func;
} avs_hnd_t;
/* load the library and functions we require from it */
-static int avs_load_library( avs_hnd_t *h )
+static int x264_avs_load_library( avs_hnd_t *h )
{
h->library = LoadLibrary( "avisynth" );
if( !h->library )
LOAD_AVS_FUNC( avs_create_script_environment, 0 );
LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
LOAD_AVS_FUNC( avs_get_frame, 0 );
- LOAD_AVS_FUNC( avs_get_version, 0 );
LOAD_AVS_FUNC( avs_get_video_info, 0 );
LOAD_AVS_FUNC( avs_function_exists, 0 );
LOAD_AVS_FUNC( avs_invoke, 0 );
avs_hnd_t *h = malloc( sizeof(avs_hnd_t) );
if( !h )
return -1;
- FAIL_IF_ERROR( avs_load_library( h ), "failed to load avisynth\n" )
- h->env = h->func.avs_create_script_environment( AVS_INTERFACE_YV12 );
+ FAIL_IF_ERROR( x264_avs_load_library( h ), "failed to load avisynth\n" )
+ h->env = h->func.avs_create_script_environment( AVS_INTERFACE_25 );
FAIL_IF_ERROR( !h->env, "failed to initiate avisynth\n" )
AVS_Value arg = avs_new_value_string( psz_filename );
AVS_Value res;
}
FAIL_IF_ERROR( !avs_is_clip( res ), "`%s' didn't return a video clip\n", psz_filename )
h->clip = h->func.avs_take_clip( res, h->env );
- int avs_version = h->func.avs_get_version( h->clip );
const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
FAIL_IF_ERROR( !avs_has_video( vi ), "`%s' has no video data\n", psz_filename )
/* if the clip is made of fields instead of frames, call weave to make them frames */
info->interlaced = 1;
info->tff = avs_is_tff( vi );
}
- 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 )
- /* always call ConvertToYV12 to convert non YV12 planar colorspaces to YV12 when user's AVS supports them,
- as all planar colorspaces are flagged as YV12. If it is already YV12 in this case, the call does nothing */
- if( !avs_is_yv12( vi ) || avs_version >= AVS_INTERFACE_OTHER_PLANAR )
+#if !HAVE_SWSCALE
+ /* if swscale is not available, convert CSPs to yv12 */
+ if( !avs_is_yv12( vi ) )
{
- if( !avs_is_yv12( vi ) )
- x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to YV12" );
- else
- x264_cli_log( "avs", X264_LOG_INFO, "avisynth 2.6+ detected, forcing conversion to YV12" );
+ x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to YV12\n" );
+ 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 )
const char *arg_name[2] = { NULL, "interlaced" };
AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) };
AVS_Value res2 = h->func.avs_invoke( h->env, "ConvertToYV12", avs_new_value_array( arg_arr, 2 ), arg_name );
FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert input clip to YV12\n" )
res = update_clip( h, &vi, res2, res );
}
+#endif
h->func.avs_release_value( res );
- info->width = vi->width;
- info->height = vi->height;
+ info->width = vi->width;
+ info->height = vi->height;
info->fps_num = vi->fps_numerator;
info->fps_den = vi->fps_denominator;
- h->num_frames = vi->num_frames;
- info->csp = X264_CSP_YV12;
+ h->num_frames = info->num_frames = vi->num_frames;
+ info->thread_safe = 1;
+#if HAVE_SWSCALE
+ if( avs_is_rgb32( vi ) )
+ info->csp = X264_CSP_BGRA | X264_CSP_VFLIP;
+ else if( avs_is_rgb24( vi ) )
+ info->csp = X264_CSP_BGR | X264_CSP_VFLIP;
+ else if( avs_is_yuy2( vi ) )
+ info->csp = PIX_FMT_YUYV422 | X264_CSP_OTHER;
+ else if( avs_is_yv24( vi ) )
+ info->csp = X264_CSP_I444;
+ else if( avs_is_yv16( vi ) )
+ info->csp = X264_CSP_I422;
+ else if( avs_is_yv12( vi ) )
+ info->csp = X264_CSP_I420;
+ else if( avs_is_yv411( vi ) )
+ info->csp = PIX_FMT_YUV411P | X264_CSP_OTHER;
+ else if( avs_is_y8( vi ) )
+ info->csp = PIX_FMT_GRAY8 | X264_CSP_OTHER;
+ else
+ info->csp = X264_CSP_NONE;
+#else
+ info->csp = X264_CSP_I420;
+#endif
info->vfr = 0;
*p_handle = h;
return 0;
}
-static int get_frame_total( hnd_t handle )
+static int picture_alloc( cli_pic_t *pic, int csp, int width, int height )
{
- avs_hnd_t *h = handle;
- return h->num_frames;
-}
-
-static int picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_height )
-{
- x264_picture_init( pic );
- pic->img.i_csp = i_csp;
- pic->img.i_plane = 3;
+ if( x264_cli_pic_alloc( pic, X264_CSP_NONE, width, height ) )
+ return -1;
+ pic->img.csp = csp;
+ const x264_cli_csp_t *cli_csp = x264_cli_get_csp( csp );
+ if( cli_csp )
+ pic->img.planes = cli_csp->planes;
+#if HAVE_SWSCALE
+ else if( csp == (PIX_FMT_YUV411P | X264_CSP_OTHER) )
+ pic->img.planes = 3;
+ else
+ pic->img.planes = 1; //y8 and yuy2 are one plane
+#endif
return 0;
}
-static int read_frame( x264_picture_t *p_pic, hnd_t handle, int i_frame )
+static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame )
{
- static int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_V, AVS_PLANAR_U };
+ static const int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V };
avs_hnd_t *h = handle;
if( i_frame >= h->num_frames )
return -1;
- AVS_VideoFrame *frm = p_pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
+ AVS_VideoFrame *frm = pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
const char *err = h->func.avs_clip_get_error( h->clip );
FAIL_IF_ERROR( err, "%s occurred while reading frame %d\n", err, i_frame )
- for( int i = 0; i < 3; i++ )
+ for( int i = 0; i < pic->img.planes; i++ )
{
/* explicitly cast away the const attribute to avoid a warning */
- p_pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
- p_pic->img.i_stride[i] = avs_get_pitch_p( frm, plane[i] );
+ pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
+ pic->img.stride[i] = avs_get_pitch_p( frm, plane[i] );
}
return 0;
}
-static int release_frame( x264_picture_t *pic, hnd_t handle )
+static int release_frame( cli_pic_t *pic, hnd_t handle )
{
avs_hnd_t *h = handle;
h->func.avs_release_video_frame( pic->opaque );
return 0;
}
-static void picture_clean( x264_picture_t *pic )
+static void picture_clean( cli_pic_t *pic )
{
- memset( pic, 0, sizeof(x264_picture_t) );
+ memset( pic, 0, sizeof(cli_pic_t) );
}
static int close_file( hnd_t handle )
return 0;
}
-const cli_input_t avs_input = { open_file, get_frame_total, picture_alloc, read_frame, release_frame, picture_clean, close_file };
+const cli_input_t avs_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };