]> git.sesse.net Git - x264/blobdiff - input/avs.c
Use a 16-bit buffer in hpel_filter regardless of bit depth
[x264] / input / avs.c
index b83f71598b18a21f18ff13f6797335872bd73c89..7cfdfd8dbdce0685001b32e6ea69fc6736cf3593 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
- * 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
@@ -59,28 +56,24 @@ typedef struct
     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 )
@@ -89,7 +82,6 @@ static int avs_load_library( avs_hnd_t *h )
     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 );
@@ -138,8 +130,8 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
     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;
@@ -192,7 +184,6 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
     }
     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 */
@@ -205,77 +196,100 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c
         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 )
@@ -289,4 +303,4 @@ 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 };