2009-11-27 07:37:18 +01:00
|
|
|
/*****************************************************************************
|
2010-09-17 13:03:27 +02:00
|
|
|
* avs.c: avisynth input
|
2009-11-27 07:37:18 +01:00
|
|
|
*****************************************************************************
|
2020-02-29 20:02:01 +01:00
|
|
|
* Copyright (C) 2009-2020 x264 project
|
2009-11-27 07:37:18 +01:00
|
|
|
*
|
|
|
|
* Authors: Steven Walters <kemuri9@gmail.com>
|
2016-08-18 18:00:48 +02:00
|
|
|
* Anton Mitrofanov <BugMaster@narod.ru>
|
2009-11-27 07:37:18 +01:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* 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.
|
2010-09-17 13:03:27 +02:00
|
|
|
*
|
|
|
|
* This program is also available under a commercial proprietary license.
|
|
|
|
* For more information, contact us at licensing@x264.com.
|
2009-11-27 07:37:18 +01:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2010-06-26 22:28:49 +02:00
|
|
|
#include "input.h"
|
Unify 8-bit and 10-bit CLI and libraries
Add 'i_bitdepth' to x264_param_t with the corresponding '--output-depth' CLI
option to set the bit depth at runtime.
Drop the 'x264_bit_depth' global variable. Rather than hardcoding it to an
incorrect value, it's preferable to induce a linking failure. If applications
relies on this symbol this will make it more obvious where the problem is.
Add Makefile rules that compiles modules with different bit depths. Assembly
on x86 is prefixed with the 'private_prefix' define, while all other archs
modify their function prefix internally.
Templatize the main C library, x86/x86_64 assembly, ARM assembly, AARCH64
assembly, PowerPC assembly, and MIPS assembly.
The depth and cache CLI filters heavily depend on bit depth size, so they
need to be duplicated for each value. This means having to rename these
filters, and adjust the callers to use the right version.
Unfortunately the threaded input CLI module inherits a common.h dependency
(input/frame -> common/threadpool -> common/frame -> common/common) which
is extremely complicated to address in a sensible way. Instead duplicate
the module and select the appropriate one at run time.
Each bitdepth needs different checkasm compilation rules, so split the main
checkasm target into two executables.
2017-01-06 15:23:38 +01:00
|
|
|
|
2013-02-13 03:55:43 +01:00
|
|
|
#if USE_AVXSYNTH
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#if SYS_MACOSX
|
2014-11-21 23:47:20 +01:00
|
|
|
#define avs_open() dlopen( "libavxsynth.dylib", RTLD_NOW )
|
2013-02-13 03:55:43 +01:00
|
|
|
#else
|
2014-11-21 23:47:20 +01:00
|
|
|
#define avs_open() dlopen( "libavxsynth.so", RTLD_NOW )
|
2013-02-13 03:55:43 +01:00
|
|
|
#endif
|
|
|
|
#define avs_close dlclose
|
|
|
|
#define avs_address dlsym
|
|
|
|
#else
|
2014-11-21 23:47:20 +01:00
|
|
|
#define avs_open() LoadLibraryW( L"avisynth" )
|
2013-02-13 03:55:43 +01:00
|
|
|
#define avs_close FreeLibrary
|
|
|
|
#define avs_address GetProcAddress
|
|
|
|
#endif
|
2009-11-27 07:37:18 +01:00
|
|
|
|
2010-07-17 23:43:37 +02:00
|
|
|
#define AVSC_NO_DECLSPEC
|
2009-11-27 07:37:18 +01:00
|
|
|
#undef EXTERN_C
|
2013-02-13 03:55:43 +01:00
|
|
|
#if USE_AVXSYNTH
|
|
|
|
#include "extras/avxsynth_c.h"
|
|
|
|
#else
|
2009-11-27 07:37:18 +01:00
|
|
|
#include "extras/avisynth_c.h"
|
2013-02-13 03:55:43 +01:00
|
|
|
#endif
|
2010-07-17 23:43:37 +02:00
|
|
|
#define AVSC_DECLARE_FUNC(name) name##_func name
|
2009-11-27 07:37:18 +01:00
|
|
|
|
Unify 8-bit and 10-bit CLI and libraries
Add 'i_bitdepth' to x264_param_t with the corresponding '--output-depth' CLI
option to set the bit depth at runtime.
Drop the 'x264_bit_depth' global variable. Rather than hardcoding it to an
incorrect value, it's preferable to induce a linking failure. If applications
relies on this symbol this will make it more obvious where the problem is.
Add Makefile rules that compiles modules with different bit depths. Assembly
on x86 is prefixed with the 'private_prefix' define, while all other archs
modify their function prefix internally.
Templatize the main C library, x86/x86_64 assembly, ARM assembly, AARCH64
assembly, PowerPC assembly, and MIPS assembly.
The depth and cache CLI filters heavily depend on bit depth size, so they
need to be duplicated for each value. This means having to rename these
filters, and adjust the callers to use the right version.
Unfortunately the threaded input CLI module inherits a common.h dependency
(input/frame -> common/threadpool -> common/frame -> common/common) which
is extremely complicated to address in a sensible way. Instead duplicate
the module and select the appropriate one at run time.
Each bitdepth needs different checkasm compilation rules, so split the main
checkasm target into two executables.
2017-01-06 15:23:38 +01:00
|
|
|
#define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "avs", __VA_ARGS__ )
|
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
/* AVS uses a versioned interface to control backwards compatibility */
|
2010-07-17 23:43:37 +02:00
|
|
|
/* YV12 support is required, which was added in 2.5 */
|
|
|
|
#define AVS_INTERFACE_25 2
|
2009-11-27 07:37:18 +01:00
|
|
|
|
2010-07-05 23:37:47 +02:00
|
|
|
#if HAVE_SWSCALE
|
|
|
|
#include <libavutil/pixfmt.h>
|
|
|
|
#endif
|
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
/* maximum size of the sequence of filters to try on non script files */
|
|
|
|
#define AVS_MAX_SEQUENCE 5
|
|
|
|
|
2010-05-06 19:03:31 +02:00
|
|
|
#define LOAD_AVS_FUNC(name, continue_on_fail)\
|
2009-11-27 07:37:18 +01:00
|
|
|
{\
|
2013-02-13 03:55:43 +01:00
|
|
|
h->func.name = (void*)avs_address( h->library, #name );\
|
2009-11-27 07:37:18 +01:00
|
|
|
if( !continue_on_fail && !h->func.name )\
|
|
|
|
goto fail;\
|
|
|
|
}
|
|
|
|
|
2016-08-18 18:00:48 +02:00
|
|
|
#define LOAD_AVS_FUNC_ALIAS(name, alias, continue_on_fail)\
|
|
|
|
{\
|
|
|
|
if( !h->func.name )\
|
|
|
|
h->func.name = (void*)avs_address( h->library, alias );\
|
|
|
|
if( !continue_on_fail && !h->func.name )\
|
|
|
|
goto fail;\
|
|
|
|
}
|
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
AVS_Clip *clip;
|
|
|
|
AVS_ScriptEnvironment *env;
|
2014-11-21 23:47:20 +01:00
|
|
|
void *library;
|
2009-12-08 20:36:25 +01:00
|
|
|
int num_frames;
|
2009-11-27 07:37:18 +01:00
|
|
|
struct
|
|
|
|
{
|
2010-07-17 23:43:37 +02:00
|
|
|
AVSC_DECLARE_FUNC( avs_clip_get_error );
|
|
|
|
AVSC_DECLARE_FUNC( avs_create_script_environment );
|
|
|
|
AVSC_DECLARE_FUNC( avs_delete_script_environment );
|
2010-10-14 03:53:50 +02:00
|
|
|
AVSC_DECLARE_FUNC( avs_get_error );
|
2010-07-17 23:43:37 +02:00
|
|
|
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 );
|
2016-08-18 18:00:48 +02:00
|
|
|
#if !USE_AVXSYNTH
|
|
|
|
// AviSynth+ extension
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_rgb48 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_rgb64 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv444p16 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv422p16 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv420p16 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_y16 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv444ps );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv422ps );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuv420ps );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_y32 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_444 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_422 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_420 );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_y );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_yuva );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_planar_rgb );
|
|
|
|
AVSC_DECLARE_FUNC( avs_is_planar_rgba );
|
|
|
|
AVSC_DECLARE_FUNC( avs_num_components );
|
|
|
|
AVSC_DECLARE_FUNC( avs_component_size );
|
|
|
|
AVSC_DECLARE_FUNC( avs_bits_per_component );
|
|
|
|
#endif
|
2009-11-27 07:37:18 +01:00
|
|
|
} func;
|
|
|
|
} avs_hnd_t;
|
|
|
|
|
|
|
|
/* load the library and functions we require from it */
|
2017-01-27 11:58:33 +01:00
|
|
|
static int custom_avs_load_library( avs_hnd_t *h )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2014-11-21 23:47:20 +01:00
|
|
|
h->library = avs_open();
|
2009-11-27 07:37:18 +01:00
|
|
|
if( !h->library )
|
|
|
|
return -1;
|
|
|
|
LOAD_AVS_FUNC( avs_clip_get_error, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_create_script_environment, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
|
2010-10-14 03:53:50 +02:00
|
|
|
LOAD_AVS_FUNC( avs_get_error, 1 );
|
2009-11-27 07:37:18 +01:00
|
|
|
LOAD_AVS_FUNC( avs_get_frame, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_get_video_info, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_function_exists, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_invoke, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_release_clip, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_release_value, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_release_video_frame, 0 );
|
|
|
|
LOAD_AVS_FUNC( avs_take_clip, 0 );
|
2016-08-18 18:00:48 +02:00
|
|
|
#if !USE_AVXSYNTH
|
|
|
|
// AviSynth+ extension
|
|
|
|
LOAD_AVS_FUNC( avs_is_rgb48, 1 );
|
|
|
|
LOAD_AVS_FUNC_ALIAS( avs_is_rgb48, "_avs_is_rgb48@4", 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_rgb64, 1 );
|
|
|
|
LOAD_AVS_FUNC_ALIAS( avs_is_rgb64, "_avs_is_rgb64@4", 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv444p16, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv422p16, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv420p16, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_y16, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv444ps, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv422ps, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuv420ps, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_y32, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_444, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_422, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_420, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_y, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_yuva, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_planar_rgb, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_is_planar_rgba, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_num_components, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_component_size, 1 );
|
|
|
|
LOAD_AVS_FUNC( avs_bits_per_component, 1 );
|
|
|
|
#endif
|
2009-11-27 07:37:18 +01:00
|
|
|
return 0;
|
|
|
|
fail:
|
2013-02-13 03:55:43 +01:00
|
|
|
avs_close( h->library );
|
2016-08-18 18:00:48 +02:00
|
|
|
h->library = NULL;
|
2009-11-27 07:37:18 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-08-18 18:00:48 +02:00
|
|
|
/* AvxSynth doesn't have yv24, yv16, yv411, or y8, so disable them. */
|
|
|
|
#if USE_AVXSYNTH
|
|
|
|
#define avs_is_yv24( vi ) (0)
|
|
|
|
#define avs_is_yv16( vi ) (0)
|
|
|
|
#define avs_is_yv411( vi ) (0)
|
|
|
|
#define avs_is_y8( vi ) (0)
|
|
|
|
/* AvxSynth doesn't support AviSynth+ pixel types. */
|
|
|
|
#define AVS_IS_AVISYNTHPLUS (0)
|
|
|
|
#define AVS_IS_420( vi ) (0)
|
|
|
|
#define AVS_IS_422( vi ) (0)
|
|
|
|
#define AVS_IS_444( vi ) (0)
|
|
|
|
#define AVS_IS_RGB48( vi ) (0)
|
|
|
|
#define AVS_IS_RGB64( vi ) (0)
|
|
|
|
#define AVS_IS_YUV420P16( vi ) (0)
|
|
|
|
#define AVS_IS_YUV422P16( vi ) (0)
|
|
|
|
#define AVS_IS_YUV444P16( vi ) (0)
|
2018-01-06 02:34:39 +01:00
|
|
|
#define AVS_IS_Y( vi ) (0)
|
|
|
|
#define AVS_IS_Y16( vi ) (0)
|
2016-08-18 18:00:48 +02:00
|
|
|
#else
|
|
|
|
#define AVS_IS_AVISYNTHPLUS (h->func.avs_is_420 && h->func.avs_is_422 && h->func.avs_is_444)
|
|
|
|
#define AVS_IS_420( vi ) (h->func.avs_is_420 ? h->func.avs_is_420( vi ) : avs_is_yv12( vi ))
|
|
|
|
#define AVS_IS_422( vi ) (h->func.avs_is_422 ? h->func.avs_is_422( vi ) : avs_is_yv16( vi ))
|
|
|
|
#define AVS_IS_444( vi ) (h->func.avs_is_444 ? h->func.avs_is_444( vi ) : avs_is_yv24( vi ))
|
|
|
|
#define AVS_IS_RGB48( vi ) (h->func.avs_is_rgb48 && h->func.avs_is_rgb48( vi ))
|
|
|
|
#define AVS_IS_RGB64( vi ) (h->func.avs_is_rgb64 && h->func.avs_is_rgb64( vi ))
|
|
|
|
#define AVS_IS_YUV420P16( vi ) (h->func.avs_is_yuv420p16 && h->func.avs_is_yuv420p16( vi ))
|
|
|
|
#define AVS_IS_YUV422P16( vi ) (h->func.avs_is_yuv422p16 && h->func.avs_is_yuv422p16( vi ))
|
|
|
|
#define AVS_IS_YUV444P16( vi ) (h->func.avs_is_yuv444p16 && h->func.avs_is_yuv444p16( vi ))
|
2018-01-06 02:34:39 +01:00
|
|
|
#define AVS_IS_Y( vi ) (h->func.avs_is_y ? h->func.avs_is_y( vi ) : avs_is_y8( vi ))
|
|
|
|
#define AVS_IS_Y16( vi ) (h->func.avs_is_y16 && h->func.avs_is_y16( vi ))
|
2016-08-18 18:00:48 +02:00
|
|
|
#endif
|
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
/* generate a filter sequence to try based on the filename extension */
|
|
|
|
static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] )
|
|
|
|
{
|
2010-03-31 10:44:07 +02:00
|
|
|
int i = 0;
|
2013-02-13 03:55:43 +01:00
|
|
|
#if USE_AVXSYNTH
|
|
|
|
const char *all_purpose[] = { "FFVideoSource", 0 };
|
|
|
|
#else
|
2009-11-27 07:37:18 +01:00
|
|
|
const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 };
|
|
|
|
if( !strcasecmp( filename_ext, "avi" ) )
|
|
|
|
filter[i++] = "AVISource";
|
|
|
|
if( !strcasecmp( filename_ext, "d2v" ) )
|
|
|
|
filter[i++] = "MPEG2Source";
|
|
|
|
if( !strcasecmp( filename_ext, "dga" ) )
|
|
|
|
filter[i++] = "AVCSource";
|
2013-02-13 03:55:43 +01:00
|
|
|
#endif
|
2010-03-31 10:44:07 +02:00
|
|
|
for( int j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
|
2009-11-27 07:37:18 +01:00
|
|
|
filter[i++] = all_purpose[j];
|
|
|
|
}
|
|
|
|
|
2010-04-07 04:08:21 +02:00
|
|
|
static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value res, AVS_Value release )
|
|
|
|
{
|
|
|
|
h->func.avs_release_clip( h->clip );
|
|
|
|
h->clip = h->func.avs_take_clip( res, h->env );
|
|
|
|
h->func.avs_release_value( release );
|
|
|
|
*vi = h->func.avs_get_video_info( h->clip );
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2011-06-22 12:32:53 +02:00
|
|
|
static float get_avs_version( avs_hnd_t *h )
|
|
|
|
{
|
2013-02-13 03:55:43 +01:00
|
|
|
/* AvxSynth has its version defined starting at 4.0, even though it's based on
|
|
|
|
AviSynth 2.5.8. This is troublesome for get_avs_version and working around
|
|
|
|
the new colorspaces in 2.6. So if AvxSynth is detected, explicitly define
|
|
|
|
the version as 2.58. */
|
|
|
|
#if USE_AVXSYNTH
|
|
|
|
return 2.58f;
|
|
|
|
#else
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( !h->func.avs_function_exists( h->env, "VersionNumber" ), "VersionNumber does not exist\n" );
|
2011-06-22 12:32:53 +02:00
|
|
|
AVS_Value ver = h->func.avs_invoke( h->env, "VersionNumber", avs_new_value_array( NULL, 0 ), NULL );
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( avs_is_error( ver ), "unable to determine avisynth version: %s\n", avs_as_error( ver ) );
|
2011-06-22 12:32:53 +02:00
|
|
|
FAIL_IF_ERROR( !avs_is_float( ver ), "VersionNumber did not return a float value\n" );
|
|
|
|
float ret = avs_as_float( ver );
|
|
|
|
h->func.avs_release_value( ver );
|
|
|
|
return ret;
|
2013-02-13 03:55:43 +01:00
|
|
|
#endif
|
2011-06-22 12:32:53 +02:00
|
|
|
}
|
|
|
|
|
2020-09-12 19:23:57 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
static int utf16_to_ansi( const wchar_t *utf16, char *ansi )
|
|
|
|
{
|
|
|
|
BOOL invalid;
|
|
|
|
return WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, utf16, -1, ansi, MAX_PATH, NULL, &invalid ) && !invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int utf8_to_ansi( const char *filename, char *ansi_filename )
|
|
|
|
{
|
|
|
|
wchar_t filename_utf16[MAX_PATH];
|
|
|
|
if( utf8_to_utf16( filename, filename_utf16 ) )
|
|
|
|
{
|
|
|
|
/* Check if the filename already is valid ANSI. */
|
|
|
|
if( utf16_to_ansi( filename_utf16, ansi_filename ) )
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Check for a legacy 8.3 short filename. */
|
|
|
|
int short_length = GetShortPathNameW( filename_utf16, filename_utf16, MAX_PATH );
|
|
|
|
if( short_length > 0 && short_length < MAX_PATH )
|
|
|
|
if( utf16_to_ansi( filename_utf16, ansi_filename ) )
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
LAVF/FFMS input support, native VFR timestamp handling
libx264 now takes three new API parameters.
b_vfr_input tells x264 whether or not the input is VFR, and is 1 by default.
i_timebase_num and i_timebase_den pass the timebase to x264.
x264_picture_t now returns the DTS of each frame: the calling app need not calculate it anymore.
Add libavformat and FFMS2 input support: requires libav* and ffms2 libraries respectively.
FFMS2 is _STRONGLY_ preferred over libavformat: we encourage all distributions to compile with FFMS2 support if at all possible.
FFMS2 can be found at http://code.google.com/p/ffmpegsource/.
--index, a new x264cli option, allows the user to store (or load) an FFMS2 index file for future use, to avoid re-indexing in the future.
Overhaul the muxers to pass through timestamps instead of assuming CFR.
Also overhaul muxers to correctly use b_annexb and b_repeat_headers to simplify the code.
Remove VFW input support, since it's now pretty much redundant with native AVS support and LAVF support.
Finally, overhaul a large part of the x264cli internals.
--force-cfr, a new x264cli option, allows the user to force the old method of timestamp handling. May be useful in case of a source with broken timestamps.
Avisynth, YUV, and Y4M input are all still CFR. LAVF or FFMS2 must be used for VFR support.
Do note that this patch does *not* add VFR ratecontrol yet.
Support for telecined input is also somewhat dubious at the moment.
Large parts of this patch by Mike Gurlitz <mike.gurlitz@gmail.com>, Steven Walters <kemuri9@gmail.com>, and Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>.
2009-12-28 16:42:17 +01:00
|
|
|
static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2013-08-11 19:50:42 +02:00
|
|
|
FILE *fh = x264_fopen( psz_filename, "r" );
|
2009-11-27 07:37:18 +01:00
|
|
|
if( !fh )
|
|
|
|
return -1;
|
2015-06-24 01:23:35 +02:00
|
|
|
int b_regular = x264_is_regular_file( fh );
|
2009-11-27 07:37:18 +01:00
|
|
|
fclose( fh );
|
2015-06-24 01:23:35 +02:00
|
|
|
FAIL_IF_ERROR( !b_regular, "AVS input is incompatible with non-regular file `%s'\n", psz_filename );
|
2009-11-27 07:37:18 +01:00
|
|
|
|
2016-08-18 18:00:48 +02:00
|
|
|
avs_hnd_t *h = calloc( 1, sizeof(avs_hnd_t) );
|
2009-11-27 07:37:18 +01:00
|
|
|
if( !h )
|
|
|
|
return -1;
|
2017-01-27 11:58:33 +01:00
|
|
|
FAIL_IF_ERROR( custom_avs_load_library( h ), "failed to load avisynth\n" );
|
2010-07-17 23:43:37 +02:00
|
|
|
h->env = h->func.avs_create_script_environment( AVS_INTERFACE_25 );
|
2010-10-14 03:53:50 +02:00
|
|
|
if( h->func.avs_get_error )
|
|
|
|
{
|
|
|
|
const char *error = h->func.avs_get_error( h->env );
|
|
|
|
FAIL_IF_ERROR( error, "%s\n", error );
|
|
|
|
}
|
2011-06-22 12:32:53 +02:00
|
|
|
float avs_version = get_avs_version( h );
|
|
|
|
if( avs_version <= 0 )
|
|
|
|
return -1;
|
|
|
|
x264_cli_log( "avs", X264_LOG_DEBUG, "using avisynth version %.2f\n", avs_version );
|
2013-08-11 19:50:42 +02:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
/* Avisynth doesn't support Unicode filenames. */
|
|
|
|
char ansi_filename[MAX_PATH];
|
2020-09-12 19:23:57 +02:00
|
|
|
FAIL_IF_ERROR( !utf8_to_ansi( psz_filename, ansi_filename ), "invalid ansi filename\n" );
|
2013-08-11 19:50:42 +02:00
|
|
|
AVS_Value arg = avs_new_value_string( ansi_filename );
|
|
|
|
#else
|
2009-11-27 07:37:18 +01:00
|
|
|
AVS_Value arg = avs_new_value_string( psz_filename );
|
2013-08-11 19:50:42 +02:00
|
|
|
#endif
|
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
AVS_Value res;
|
|
|
|
char *filename_ext = get_filename_extension( psz_filename );
|
|
|
|
|
|
|
|
if( !strcasecmp( filename_ext, "avs" ) )
|
|
|
|
{
|
|
|
|
res = h->func.avs_invoke( h->env, "Import", arg, NULL );
|
2018-01-06 02:34:39 +01:00
|
|
|
FAIL_IF_ERROR( avs_is_error( res ), "%s\n", avs_as_error( res ) );
|
2009-12-11 04:48:51 +01:00
|
|
|
/* check if the user is using a multi-threaded script and apply distributor if necessary.
|
|
|
|
adapted from avisynth's vfw interface */
|
|
|
|
AVS_Value mt_test = h->func.avs_invoke( h->env, "GetMTMode", avs_new_value_bool( 0 ), NULL );
|
|
|
|
int mt_mode = avs_is_int( mt_test ) ? avs_as_int( mt_test ) : 0;
|
|
|
|
h->func.avs_release_value( mt_test );
|
|
|
|
if( mt_mode > 0 && mt_mode < 5 )
|
|
|
|
{
|
|
|
|
AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
|
|
|
|
h->func.avs_release_value( res );
|
|
|
|
res = temp;
|
|
|
|
}
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
|
|
|
else /* non script file */
|
|
|
|
{
|
|
|
|
/* cycle through known source filters to find one that works */
|
|
|
|
const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
|
|
|
|
avs_build_filter_sequence( filename_ext, filter );
|
|
|
|
int i;
|
|
|
|
for( i = 0; filter[i]; i++ )
|
|
|
|
{
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_log( "avs", X264_LOG_INFO, "trying %s... ", filter[i] );
|
2009-11-27 07:37:18 +01:00
|
|
|
if( !h->func.avs_function_exists( h->env, filter[i] ) )
|
|
|
|
{
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_printf( X264_LOG_INFO, "not found\n" );
|
2009-11-27 07:37:18 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
|
|
|
|
{
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_printf( X264_LOG_INFO, "indexing... " );
|
2009-11-27 07:37:18 +01:00
|
|
|
fflush( stderr );
|
|
|
|
}
|
|
|
|
res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
|
|
|
|
if( !avs_is_error( res ) )
|
|
|
|
{
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_printf( X264_LOG_INFO, "succeeded\n" );
|
2009-11-27 07:37:18 +01:00
|
|
|
break;
|
|
|
|
}
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_printf( X264_LOG_INFO, "failed\n" );
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( !filter[i], "unable to find source filter to open `%s'\n", psz_filename );
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( !avs_is_clip( res ), "`%s' didn't return a video clip\n", psz_filename );
|
2009-11-27 07:37:18 +01:00
|
|
|
h->clip = h->func.avs_take_clip( res, h->env );
|
|
|
|
const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( !avs_has_video( vi ), "`%s' has no video data\n", psz_filename );
|
2010-04-07 04:08:21 +02:00
|
|
|
/* if the clip is made of fields instead of frames, call weave to make them frames */
|
|
|
|
if( avs_is_field_based( vi ) )
|
|
|
|
{
|
2010-06-26 22:28:49 +02:00
|
|
|
x264_cli_log( "avs", X264_LOG_WARNING, "detected fieldbased (separated) input, weaving to frames\n" );
|
2010-04-07 04:08:21 +02:00
|
|
|
AVS_Value tmp = h->func.avs_invoke( h->env, "Weave", res, NULL );
|
2018-01-06 02:34:39 +01:00
|
|
|
FAIL_IF_ERROR( avs_is_error( tmp ), "couldn't weave fields into frames: %s\n", avs_as_error( tmp ) );
|
2010-04-07 04:08:21 +02:00
|
|
|
res = update_clip( h, &vi, tmp, res );
|
2010-04-13 14:44:37 +02:00
|
|
|
info->interlaced = 1;
|
|
|
|
info->tff = avs_is_tff( vi );
|
2010-04-07 04:08:21 +02:00
|
|
|
}
|
2010-07-17 23:43:37 +02:00
|
|
|
#if !HAVE_SWSCALE
|
2011-06-22 12:32:53 +02:00
|
|
|
/* if swscale is not available, convert the CSP if necessary */
|
2018-01-06 02:34:39 +01:00
|
|
|
FAIL_IF_ERROR( avs_version < 2.6f && (opt->output_csp == X264_CSP_I400 || opt->output_csp == X264_CSP_I422 || opt->output_csp == X264_CSP_I444),
|
|
|
|
"avisynth >= 2.6 is required for i400/i422/i444 output\n" );
|
|
|
|
if( (opt->output_csp == X264_CSP_I400 && !AVS_IS_Y( vi )) ||
|
|
|
|
(opt->output_csp == X264_CSP_I420 && !AVS_IS_420( vi )) ||
|
2016-08-18 18:00:48 +02:00
|
|
|
(opt->output_csp == X264_CSP_I422 && !AVS_IS_422( vi )) ||
|
|
|
|
(opt->output_csp == X264_CSP_I444 && !AVS_IS_444( vi )) ||
|
|
|
|
(opt->output_csp == X264_CSP_RGB && !avs_is_rgb( vi )) )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2016-08-18 18:00:48 +02:00
|
|
|
const char *csp;
|
|
|
|
if( AVS_IS_AVISYNTHPLUS )
|
|
|
|
{
|
2018-01-06 02:34:39 +01:00
|
|
|
csp = opt->output_csp == X264_CSP_I400 ? "Y" :
|
|
|
|
opt->output_csp == X264_CSP_I420 ? "YUV420" :
|
2016-08-18 18:00:48 +02:00
|
|
|
opt->output_csp == X264_CSP_I422 ? "YUV422" :
|
|
|
|
opt->output_csp == X264_CSP_I444 ? "YUV444" :
|
|
|
|
"RGB";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-06 02:34:39 +01:00
|
|
|
csp = opt->output_csp == X264_CSP_I400 ? "Y8" :
|
|
|
|
opt->output_csp == X264_CSP_I420 ? "YV12" :
|
2016-08-18 18:00:48 +02:00
|
|
|
opt->output_csp == X264_CSP_I422 ? "YV16" :
|
|
|
|
opt->output_csp == X264_CSP_I444 ? "YV24" :
|
|
|
|
"RGB";
|
|
|
|
}
|
2011-06-22 12:32:53 +02:00
|
|
|
x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to %s\n", csp );
|
2018-01-06 02:34:39 +01:00
|
|
|
if( opt->output_csp != X264_CSP_I400 )
|
|
|
|
{
|
|
|
|
FAIL_IF_ERROR( opt->output_csp < X264_CSP_I444 && (vi->width&1),
|
|
|
|
"input clip width not divisible by 2 (%dx%d)\n", vi->width, vi->height );
|
|
|
|
FAIL_IF_ERROR( opt->output_csp == X264_CSP_I420 && info->interlaced && (vi->height&3),
|
|
|
|
"input clip height not divisible by 4 (%dx%d)\n", vi->width, vi->height );
|
|
|
|
FAIL_IF_ERROR( (opt->output_csp == X264_CSP_I420 || info->interlaced) && (vi->height&1),
|
|
|
|
"input clip height not divisible by 2 (%dx%d)\n", vi->width, vi->height );
|
|
|
|
}
|
2016-08-18 18:00:48 +02:00
|
|
|
char conv_func[16];
|
2015-07-29 19:30:41 +02:00
|
|
|
snprintf( conv_func, sizeof(conv_func), "ConvertTo%s", csp );
|
2018-01-06 02:34:39 +01:00
|
|
|
AVS_Value arg_arr[3];
|
|
|
|
const char *arg_name[3];
|
|
|
|
int arg_count = 1;
|
|
|
|
arg_arr[0] = res;
|
|
|
|
arg_name[0] = NULL;
|
|
|
|
if( opt->output_csp != X264_CSP_I400 )
|
|
|
|
{
|
|
|
|
arg_arr[arg_count] = avs_new_value_bool( info->interlaced );
|
|
|
|
arg_name[arg_count] = "interlaced";
|
|
|
|
arg_count++;
|
|
|
|
}
|
2011-11-06 18:48:30 +01:00
|
|
|
/* if doing a rgb <-> yuv conversion then range is handled via 'matrix'. though it's only supported in 2.56+ */
|
2018-01-06 02:34:39 +01:00
|
|
|
char matrix[7];
|
2011-11-06 18:48:30 +01:00
|
|
|
if( avs_version >= 2.56f && ((opt->output_csp == X264_CSP_RGB && avs_is_yuv( vi )) || (opt->output_csp != X264_CSP_RGB && avs_is_rgb( vi ))) )
|
|
|
|
{
|
|
|
|
// if converting from yuv, then we specify the matrix for the input, otherwise use the output's.
|
|
|
|
int use_pc_matrix = avs_is_yuv( vi ) ? opt->input_range == RANGE_PC : opt->output_range == RANGE_PC;
|
2015-07-29 19:30:41 +02:00
|
|
|
snprintf( matrix, sizeof(matrix), "%s601", use_pc_matrix ? "PC." : "Rec" ); /* FIXME: use correct coefficients */
|
2018-01-06 02:34:39 +01:00
|
|
|
arg_arr[arg_count] = avs_new_value_string( matrix );
|
|
|
|
arg_name[arg_count] = "matrix";
|
2011-11-06 18:48:30 +01:00
|
|
|
arg_count++;
|
|
|
|
// notification that the input range has changed to the desired one
|
|
|
|
opt->input_range = opt->output_range;
|
|
|
|
}
|
|
|
|
AVS_Value res2 = h->func.avs_invoke( h->env, conv_func, avs_new_value_array( arg_arr, arg_count ), arg_name );
|
2018-01-06 02:34:39 +01:00
|
|
|
FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert input clip to %s: %s\n", csp, avs_as_error( res2 ) );
|
2010-04-07 04:08:21 +02:00
|
|
|
res = update_clip( h, &vi, res2, res );
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
2011-11-06 18:48:30 +01:00
|
|
|
/* if swscale is not available, change the range if necessary. This only applies to YUV-based CSPs however */
|
|
|
|
if( avs_is_yuv( vi ) && opt->output_range != RANGE_AUTO && ((opt->input_range == RANGE_PC) != opt->output_range) )
|
|
|
|
{
|
|
|
|
const char *levels = opt->output_range ? "TV->PC" : "PC->TV";
|
|
|
|
x264_cli_log( "avs", X264_LOG_WARNING, "performing %s conversion\n", levels );
|
2014-05-31 16:31:16 +02:00
|
|
|
AVS_Value arg_arr[2];
|
|
|
|
arg_arr[0] = res;
|
|
|
|
arg_arr[1] = avs_new_value_string( levels );
|
2011-11-06 18:48:30 +01:00
|
|
|
const char *arg_name[] = { NULL, "levels" };
|
|
|
|
AVS_Value res2 = h->func.avs_invoke( h->env, "ColorYUV", avs_new_value_array( arg_arr, 2 ), arg_name );
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert range: %s\n", avs_as_error( res2 ) );
|
2011-11-06 18:48:30 +01:00
|
|
|
res = update_clip( h, &vi, res2, res );
|
|
|
|
// notification that the input range has changed to the desired one
|
|
|
|
opt->input_range = opt->output_range;
|
|
|
|
}
|
2010-07-17 23:43:37 +02:00
|
|
|
#endif
|
2013-02-13 03:55:43 +01:00
|
|
|
|
2009-11-27 07:37:18 +01:00
|
|
|
h->func.avs_release_value( res );
|
|
|
|
|
2010-07-05 23:37:47 +02:00
|
|
|
info->width = vi->width;
|
|
|
|
info->height = vi->height;
|
LAVF/FFMS input support, native VFR timestamp handling
libx264 now takes three new API parameters.
b_vfr_input tells x264 whether or not the input is VFR, and is 1 by default.
i_timebase_num and i_timebase_den pass the timebase to x264.
x264_picture_t now returns the DTS of each frame: the calling app need not calculate it anymore.
Add libavformat and FFMS2 input support: requires libav* and ffms2 libraries respectively.
FFMS2 is _STRONGLY_ preferred over libavformat: we encourage all distributions to compile with FFMS2 support if at all possible.
FFMS2 can be found at http://code.google.com/p/ffmpegsource/.
--index, a new x264cli option, allows the user to store (or load) an FFMS2 index file for future use, to avoid re-indexing in the future.
Overhaul the muxers to pass through timestamps instead of assuming CFR.
Also overhaul muxers to correctly use b_annexb and b_repeat_headers to simplify the code.
Remove VFW input support, since it's now pretty much redundant with native AVS support and LAVF support.
Finally, overhaul a large part of the x264cli internals.
--force-cfr, a new x264cli option, allows the user to force the old method of timestamp handling. May be useful in case of a source with broken timestamps.
Avisynth, YUV, and Y4M input are all still CFR. LAVF or FFMS2 must be used for VFR support.
Do note that this patch does *not* add VFR ratecontrol yet.
Support for telecined input is also somewhat dubious at the moment.
Large parts of this patch by Mike Gurlitz <mike.gurlitz@gmail.com>, Steven Walters <kemuri9@gmail.com>, and Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>.
2009-12-28 16:42:17 +01:00
|
|
|
info->fps_num = vi->fps_numerator;
|
|
|
|
info->fps_den = vi->fps_denominator;
|
2010-07-05 23:37:47 +02:00
|
|
|
h->num_frames = info->num_frames = vi->num_frames;
|
|
|
|
info->thread_safe = 1;
|
2016-08-18 18:00:48 +02:00
|
|
|
if( AVS_IS_RGB64( vi ) )
|
|
|
|
info->csp = X264_CSP_BGRA | X264_CSP_VFLIP | X264_CSP_HIGH_DEPTH;
|
|
|
|
else if( avs_is_rgb32( vi ) )
|
2010-07-05 23:37:47 +02:00
|
|
|
info->csp = X264_CSP_BGRA | X264_CSP_VFLIP;
|
2016-08-18 18:00:48 +02:00
|
|
|
else if( AVS_IS_RGB48( vi ) )
|
|
|
|
info->csp = X264_CSP_BGR | X264_CSP_VFLIP | X264_CSP_HIGH_DEPTH;
|
2010-07-05 23:37:47 +02:00
|
|
|
else if( avs_is_rgb24( vi ) )
|
|
|
|
info->csp = X264_CSP_BGR | X264_CSP_VFLIP;
|
2016-08-18 18:00:48 +02:00
|
|
|
else if( AVS_IS_YUV444P16( vi ) )
|
|
|
|
info->csp = X264_CSP_I444 | X264_CSP_HIGH_DEPTH;
|
2010-07-17 23:43:37 +02:00
|
|
|
else if( avs_is_yv24( vi ) )
|
|
|
|
info->csp = X264_CSP_I444;
|
2016-08-18 18:00:48 +02:00
|
|
|
else if( AVS_IS_YUV422P16( vi ) )
|
|
|
|
info->csp = X264_CSP_I422 | X264_CSP_HIGH_DEPTH;
|
2011-08-26 15:57:04 +02:00
|
|
|
else if( avs_is_yv16( vi ) )
|
|
|
|
info->csp = X264_CSP_I422;
|
2016-08-18 18:00:48 +02:00
|
|
|
else if( AVS_IS_YUV420P16( vi ) )
|
|
|
|
info->csp = X264_CSP_I420 | X264_CSP_HIGH_DEPTH;
|
2011-06-23 03:46:14 +02:00
|
|
|
else if( avs_is_yv12( vi ) )
|
|
|
|
info->csp = X264_CSP_I420;
|
2018-01-06 02:34:39 +01:00
|
|
|
else if( AVS_IS_Y16( vi ) )
|
|
|
|
info->csp = X264_CSP_I400 | X264_CSP_HIGH_DEPTH;
|
|
|
|
else if( avs_is_y8( vi ) )
|
|
|
|
info->csp = X264_CSP_I400;
|
2011-06-23 03:46:14 +02:00
|
|
|
else if( avs_is_yuy2( vi ) )
|
2018-01-06 02:34:39 +01:00
|
|
|
info->csp = X264_CSP_YUYV;
|
|
|
|
#if HAVE_SWSCALE
|
2010-07-17 23:43:37 +02:00
|
|
|
else if( avs_is_yv411( vi ) )
|
2013-10-08 21:20:40 +02:00
|
|
|
info->csp = AV_PIX_FMT_YUV411P | X264_CSP_OTHER;
|
2011-06-23 03:46:14 +02:00
|
|
|
#endif
|
2010-07-17 23:43:37 +02:00
|
|
|
else
|
2016-08-18 18:00:48 +02:00
|
|
|
{
|
|
|
|
AVS_Value pixel_type = h->func.avs_invoke( h->env, "PixelType", res, NULL );
|
|
|
|
const char *pixel_type_name = avs_is_string( pixel_type ) ? avs_as_string( pixel_type ) : "unknown";
|
|
|
|
FAIL_IF_ERROR( 1, "not supported pixel type: %s\n", pixel_type_name );
|
|
|
|
}
|
LAVF/FFMS input support, native VFR timestamp handling
libx264 now takes three new API parameters.
b_vfr_input tells x264 whether or not the input is VFR, and is 1 by default.
i_timebase_num and i_timebase_den pass the timebase to x264.
x264_picture_t now returns the DTS of each frame: the calling app need not calculate it anymore.
Add libavformat and FFMS2 input support: requires libav* and ffms2 libraries respectively.
FFMS2 is _STRONGLY_ preferred over libavformat: we encourage all distributions to compile with FFMS2 support if at all possible.
FFMS2 can be found at http://code.google.com/p/ffmpegsource/.
--index, a new x264cli option, allows the user to store (or load) an FFMS2 index file for future use, to avoid re-indexing in the future.
Overhaul the muxers to pass through timestamps instead of assuming CFR.
Also overhaul muxers to correctly use b_annexb and b_repeat_headers to simplify the code.
Remove VFW input support, since it's now pretty much redundant with native AVS support and LAVF support.
Finally, overhaul a large part of the x264cli internals.
--force-cfr, a new x264cli option, allows the user to force the old method of timestamp handling. May be useful in case of a source with broken timestamps.
Avisynth, YUV, and Y4M input are all still CFR. LAVF or FFMS2 must be used for VFR support.
Do note that this patch does *not* add VFR ratecontrol yet.
Support for telecined input is also somewhat dubious at the moment.
Large parts of this patch by Mike Gurlitz <mike.gurlitz@gmail.com>, Steven Walters <kemuri9@gmail.com>, and Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>.
2009-12-28 16:42:17 +01:00
|
|
|
info->vfr = 0;
|
2009-11-27 07:37:18 +01:00
|
|
|
|
|
|
|
*p_handle = h;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-26 19:54:20 +01:00
|
|
|
static int picture_alloc( cli_pic_t *pic, hnd_t handle, int csp, int width, int height )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2010-07-05 23:37:47 +02:00
|
|
|
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 );
|
2010-07-17 23:43:37 +02:00
|
|
|
if( cli_csp )
|
|
|
|
pic->img.planes = cli_csp->planes;
|
|
|
|
#if HAVE_SWSCALE
|
2013-10-08 21:20:40 +02:00
|
|
|
else if( csp == (AV_PIX_FMT_YUV411P | X264_CSP_OTHER) )
|
2010-07-17 23:43:37 +02:00
|
|
|
pic->img.planes = 3;
|
|
|
|
else
|
|
|
|
pic->img.planes = 1; //y8 and yuy2 are one plane
|
|
|
|
#endif
|
2009-11-27 07:37:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-05 23:37:47 +02:00
|
|
|
static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2010-07-05 23:37:47 +02:00
|
|
|
static const int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V };
|
2009-11-27 07:37:18 +01:00
|
|
|
avs_hnd_t *h = handle;
|
2009-12-08 20:36:25 +01:00
|
|
|
if( i_frame >= h->num_frames )
|
|
|
|
return -1;
|
2010-07-05 23:37:47 +02:00
|
|
|
AVS_VideoFrame *frm = pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
|
2009-11-27 07:37:18 +01:00
|
|
|
const char *err = h->func.avs_clip_get_error( h->clip );
|
2016-08-18 21:14:22 +02:00
|
|
|
FAIL_IF_ERROR( err, "%s occurred while reading frame %d\n", err, i_frame );
|
2010-07-05 23:37:47 +02:00
|
|
|
for( int i = 0; i < pic->img.planes; i++ )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
|
|
|
/* explicitly cast away the const attribute to avoid a warning */
|
2010-07-05 23:37:47 +02:00
|
|
|
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] );
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-05 23:37:47 +02:00
|
|
|
static int release_frame( cli_pic_t *pic, hnd_t handle )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
|
|
|
avs_hnd_t *h = handle;
|
|
|
|
h->func.avs_release_video_frame( pic->opaque );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-26 19:54:20 +01:00
|
|
|
static void picture_clean( cli_pic_t *pic, hnd_t handle )
|
2009-11-27 07:37:18 +01:00
|
|
|
{
|
2010-07-05 23:37:47 +02:00
|
|
|
memset( pic, 0, sizeof(cli_pic_t) );
|
2009-11-27 07:37:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int close_file( hnd_t handle )
|
|
|
|
{
|
|
|
|
avs_hnd_t *h = handle;
|
2016-08-18 18:00:48 +02:00
|
|
|
if( h->func.avs_release_clip && h->clip )
|
|
|
|
h->func.avs_release_clip( h->clip );
|
|
|
|
if( h->func.avs_delete_script_environment && h->env )
|
2009-11-27 07:37:18 +01:00
|
|
|
h->func.avs_delete_script_environment( h->env );
|
2016-08-18 18:00:48 +02:00
|
|
|
if( h->library )
|
|
|
|
avs_close( h->library );
|
2009-11-27 07:37:18 +01:00
|
|
|
free( h );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-05 23:37:47 +02:00
|
|
|
const cli_input_t avs_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };
|