avs.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*****************************************************************************
  2. * avs.c: avisynth input
  3. *****************************************************************************
  4. * Copyright (C) 2009-2018 x264 project
  5. *
  6. * Authors: Steven Walters <kemuri9@gmail.com>
  7. * Anton Mitrofanov <BugMaster@narod.ru>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
  22. *
  23. * This program is also available under a commercial proprietary license.
  24. * For more information, contact us at licensing@x264.com.
  25. *****************************************************************************/
  26. #include "input.h"
  27. #if USE_AVXSYNTH
  28. #include <dlfcn.h>
  29. #if SYS_MACOSX
  30. #define avs_open() dlopen( "libavxsynth.dylib", RTLD_NOW )
  31. #else
  32. #define avs_open() dlopen( "libavxsynth.so", RTLD_NOW )
  33. #endif
  34. #define avs_close dlclose
  35. #define avs_address dlsym
  36. #else
  37. #define avs_open() LoadLibraryW( L"avisynth" )
  38. #define avs_close FreeLibrary
  39. #define avs_address GetProcAddress
  40. #endif
  41. #define AVSC_NO_DECLSPEC
  42. #undef EXTERN_C
  43. #if USE_AVXSYNTH
  44. #include "extras/avxsynth_c.h"
  45. #else
  46. #include "extras/avisynth_c.h"
  47. #endif
  48. #define AVSC_DECLARE_FUNC(name) name##_func name
  49. #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "avs", __VA_ARGS__ )
  50. /* AVS uses a versioned interface to control backwards compatibility */
  51. /* YV12 support is required, which was added in 2.5 */
  52. #define AVS_INTERFACE_25 2
  53. #if HAVE_SWSCALE
  54. #include <libavutil/pixfmt.h>
  55. #endif
  56. /* maximum size of the sequence of filters to try on non script files */
  57. #define AVS_MAX_SEQUENCE 5
  58. #define LOAD_AVS_FUNC(name, continue_on_fail)\
  59. {\
  60. h->func.name = (void*)avs_address( h->library, #name );\
  61. if( !continue_on_fail && !h->func.name )\
  62. goto fail;\
  63. }
  64. #define LOAD_AVS_FUNC_ALIAS(name, alias, continue_on_fail)\
  65. {\
  66. if( !h->func.name )\
  67. h->func.name = (void*)avs_address( h->library, alias );\
  68. if( !continue_on_fail && !h->func.name )\
  69. goto fail;\
  70. }
  71. typedef struct
  72. {
  73. AVS_Clip *clip;
  74. AVS_ScriptEnvironment *env;
  75. void *library;
  76. int num_frames;
  77. struct
  78. {
  79. AVSC_DECLARE_FUNC( avs_clip_get_error );
  80. AVSC_DECLARE_FUNC( avs_create_script_environment );
  81. AVSC_DECLARE_FUNC( avs_delete_script_environment );
  82. AVSC_DECLARE_FUNC( avs_get_error );
  83. AVSC_DECLARE_FUNC( avs_get_frame );
  84. AVSC_DECLARE_FUNC( avs_get_video_info );
  85. AVSC_DECLARE_FUNC( avs_function_exists );
  86. AVSC_DECLARE_FUNC( avs_invoke );
  87. AVSC_DECLARE_FUNC( avs_release_clip );
  88. AVSC_DECLARE_FUNC( avs_release_value );
  89. AVSC_DECLARE_FUNC( avs_release_video_frame );
  90. AVSC_DECLARE_FUNC( avs_take_clip );
  91. #if !USE_AVXSYNTH
  92. // AviSynth+ extension
  93. AVSC_DECLARE_FUNC( avs_is_rgb48 );
  94. AVSC_DECLARE_FUNC( avs_is_rgb64 );
  95. AVSC_DECLARE_FUNC( avs_is_yuv444p16 );
  96. AVSC_DECLARE_FUNC( avs_is_yuv422p16 );
  97. AVSC_DECLARE_FUNC( avs_is_yuv420p16 );
  98. AVSC_DECLARE_FUNC( avs_is_y16 );
  99. AVSC_DECLARE_FUNC( avs_is_yuv444ps );
  100. AVSC_DECLARE_FUNC( avs_is_yuv422ps );
  101. AVSC_DECLARE_FUNC( avs_is_yuv420ps );
  102. AVSC_DECLARE_FUNC( avs_is_y32 );
  103. AVSC_DECLARE_FUNC( avs_is_444 );
  104. AVSC_DECLARE_FUNC( avs_is_422 );
  105. AVSC_DECLARE_FUNC( avs_is_420 );
  106. AVSC_DECLARE_FUNC( avs_is_y );
  107. AVSC_DECLARE_FUNC( avs_is_yuva );
  108. AVSC_DECLARE_FUNC( avs_is_planar_rgb );
  109. AVSC_DECLARE_FUNC( avs_is_planar_rgba );
  110. AVSC_DECLARE_FUNC( avs_num_components );
  111. AVSC_DECLARE_FUNC( avs_component_size );
  112. AVSC_DECLARE_FUNC( avs_bits_per_component );
  113. #endif
  114. } func;
  115. } avs_hnd_t;
  116. /* load the library and functions we require from it */
  117. static int custom_avs_load_library( avs_hnd_t *h )
  118. {
  119. h->library = avs_open();
  120. if( !h->library )
  121. return -1;
  122. LOAD_AVS_FUNC( avs_clip_get_error, 0 );
  123. LOAD_AVS_FUNC( avs_create_script_environment, 0 );
  124. LOAD_AVS_FUNC( avs_delete_script_environment, 1 );
  125. LOAD_AVS_FUNC( avs_get_error, 1 );
  126. LOAD_AVS_FUNC( avs_get_frame, 0 );
  127. LOAD_AVS_FUNC( avs_get_video_info, 0 );
  128. LOAD_AVS_FUNC( avs_function_exists, 0 );
  129. LOAD_AVS_FUNC( avs_invoke, 0 );
  130. LOAD_AVS_FUNC( avs_release_clip, 0 );
  131. LOAD_AVS_FUNC( avs_release_value, 0 );
  132. LOAD_AVS_FUNC( avs_release_video_frame, 0 );
  133. LOAD_AVS_FUNC( avs_take_clip, 0 );
  134. #if !USE_AVXSYNTH
  135. // AviSynth+ extension
  136. LOAD_AVS_FUNC( avs_is_rgb48, 1 );
  137. LOAD_AVS_FUNC_ALIAS( avs_is_rgb48, "_avs_is_rgb48@4", 1 );
  138. LOAD_AVS_FUNC( avs_is_rgb64, 1 );
  139. LOAD_AVS_FUNC_ALIAS( avs_is_rgb64, "_avs_is_rgb64@4", 1 );
  140. LOAD_AVS_FUNC( avs_is_yuv444p16, 1 );
  141. LOAD_AVS_FUNC( avs_is_yuv422p16, 1 );
  142. LOAD_AVS_FUNC( avs_is_yuv420p16, 1 );
  143. LOAD_AVS_FUNC( avs_is_y16, 1 );
  144. LOAD_AVS_FUNC( avs_is_yuv444ps, 1 );
  145. LOAD_AVS_FUNC( avs_is_yuv422ps, 1 );
  146. LOAD_AVS_FUNC( avs_is_yuv420ps, 1 );
  147. LOAD_AVS_FUNC( avs_is_y32, 1 );
  148. LOAD_AVS_FUNC( avs_is_444, 1 );
  149. LOAD_AVS_FUNC( avs_is_422, 1 );
  150. LOAD_AVS_FUNC( avs_is_420, 1 );
  151. LOAD_AVS_FUNC( avs_is_y, 1 );
  152. LOAD_AVS_FUNC( avs_is_yuva, 1 );
  153. LOAD_AVS_FUNC( avs_is_planar_rgb, 1 );
  154. LOAD_AVS_FUNC( avs_is_planar_rgba, 1 );
  155. LOAD_AVS_FUNC( avs_num_components, 1 );
  156. LOAD_AVS_FUNC( avs_component_size, 1 );
  157. LOAD_AVS_FUNC( avs_bits_per_component, 1 );
  158. #endif
  159. return 0;
  160. fail:
  161. avs_close( h->library );
  162. h->library = NULL;
  163. return -1;
  164. }
  165. /* AvxSynth doesn't have yv24, yv16, yv411, or y8, so disable them. */
  166. #if USE_AVXSYNTH
  167. #define avs_is_yv24( vi ) (0)
  168. #define avs_is_yv16( vi ) (0)
  169. #define avs_is_yv411( vi ) (0)
  170. #define avs_is_y8( vi ) (0)
  171. /* AvxSynth doesn't support AviSynth+ pixel types. */
  172. #define AVS_IS_AVISYNTHPLUS (0)
  173. #define AVS_IS_420( vi ) (0)
  174. #define AVS_IS_422( vi ) (0)
  175. #define AVS_IS_444( vi ) (0)
  176. #define AVS_IS_RGB48( vi ) (0)
  177. #define AVS_IS_RGB64( vi ) (0)
  178. #define AVS_IS_YUV420P16( vi ) (0)
  179. #define AVS_IS_YUV422P16( vi ) (0)
  180. #define AVS_IS_YUV444P16( vi ) (0)
  181. #define AVS_IS_Y( vi ) (0)
  182. #define AVS_IS_Y16( vi ) (0)
  183. #else
  184. #define AVS_IS_AVISYNTHPLUS (h->func.avs_is_420 && h->func.avs_is_422 && h->func.avs_is_444)
  185. #define AVS_IS_420( vi ) (h->func.avs_is_420 ? h->func.avs_is_420( vi ) : avs_is_yv12( vi ))
  186. #define AVS_IS_422( vi ) (h->func.avs_is_422 ? h->func.avs_is_422( vi ) : avs_is_yv16( vi ))
  187. #define AVS_IS_444( vi ) (h->func.avs_is_444 ? h->func.avs_is_444( vi ) : avs_is_yv24( vi ))
  188. #define AVS_IS_RGB48( vi ) (h->func.avs_is_rgb48 && h->func.avs_is_rgb48( vi ))
  189. #define AVS_IS_RGB64( vi ) (h->func.avs_is_rgb64 && h->func.avs_is_rgb64( vi ))
  190. #define AVS_IS_YUV420P16( vi ) (h->func.avs_is_yuv420p16 && h->func.avs_is_yuv420p16( vi ))
  191. #define AVS_IS_YUV422P16( vi ) (h->func.avs_is_yuv422p16 && h->func.avs_is_yuv422p16( vi ))
  192. #define AVS_IS_YUV444P16( vi ) (h->func.avs_is_yuv444p16 && h->func.avs_is_yuv444p16( vi ))
  193. #define AVS_IS_Y( vi ) (h->func.avs_is_y ? h->func.avs_is_y( vi ) : avs_is_y8( vi ))
  194. #define AVS_IS_Y16( vi ) (h->func.avs_is_y16 && h->func.avs_is_y16( vi ))
  195. #endif
  196. /* generate a filter sequence to try based on the filename extension */
  197. static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] )
  198. {
  199. int i = 0;
  200. #if USE_AVXSYNTH
  201. const char *all_purpose[] = { "FFVideoSource", 0 };
  202. #else
  203. const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 };
  204. if( !strcasecmp( filename_ext, "avi" ) )
  205. filter[i++] = "AVISource";
  206. if( !strcasecmp( filename_ext, "d2v" ) )
  207. filter[i++] = "MPEG2Source";
  208. if( !strcasecmp( filename_ext, "dga" ) )
  209. filter[i++] = "AVCSource";
  210. #endif
  211. for( int j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ )
  212. filter[i++] = all_purpose[j];
  213. }
  214. static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value res, AVS_Value release )
  215. {
  216. h->func.avs_release_clip( h->clip );
  217. h->clip = h->func.avs_take_clip( res, h->env );
  218. h->func.avs_release_value( release );
  219. *vi = h->func.avs_get_video_info( h->clip );
  220. return res;
  221. }
  222. static float get_avs_version( avs_hnd_t *h )
  223. {
  224. /* AvxSynth has its version defined starting at 4.0, even though it's based on
  225. AviSynth 2.5.8. This is troublesome for get_avs_version and working around
  226. the new colorspaces in 2.6. So if AvxSynth is detected, explicitly define
  227. the version as 2.58. */
  228. #if USE_AVXSYNTH
  229. return 2.58f;
  230. #else
  231. FAIL_IF_ERROR( !h->func.avs_function_exists( h->env, "VersionNumber" ), "VersionNumber does not exist\n" );
  232. AVS_Value ver = h->func.avs_invoke( h->env, "VersionNumber", avs_new_value_array( NULL, 0 ), NULL );
  233. FAIL_IF_ERROR( avs_is_error( ver ), "unable to determine avisynth version: %s\n", avs_as_error( ver ) );
  234. FAIL_IF_ERROR( !avs_is_float( ver ), "VersionNumber did not return a float value\n" );
  235. float ret = avs_as_float( ver );
  236. h->func.avs_release_value( ver );
  237. return ret;
  238. #endif
  239. }
  240. static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt )
  241. {
  242. FILE *fh = x264_fopen( psz_filename, "r" );
  243. if( !fh )
  244. return -1;
  245. int b_regular = x264_is_regular_file( fh );
  246. fclose( fh );
  247. FAIL_IF_ERROR( !b_regular, "AVS input is incompatible with non-regular file `%s'\n", psz_filename );
  248. avs_hnd_t *h = calloc( 1, sizeof(avs_hnd_t) );
  249. if( !h )
  250. return -1;
  251. FAIL_IF_ERROR( custom_avs_load_library( h ), "failed to load avisynth\n" );
  252. h->env = h->func.avs_create_script_environment( AVS_INTERFACE_25 );
  253. if( h->func.avs_get_error )
  254. {
  255. const char *error = h->func.avs_get_error( h->env );
  256. FAIL_IF_ERROR( error, "%s\n", error );
  257. }
  258. float avs_version = get_avs_version( h );
  259. if( avs_version <= 0 )
  260. return -1;
  261. x264_cli_log( "avs", X264_LOG_DEBUG, "using avisynth version %.2f\n", avs_version );
  262. #ifdef _WIN32
  263. /* Avisynth doesn't support Unicode filenames. */
  264. char ansi_filename[MAX_PATH];
  265. FAIL_IF_ERROR( !x264_ansi_filename( psz_filename, ansi_filename, MAX_PATH, 0 ), "invalid ansi filename\n" );
  266. AVS_Value arg = avs_new_value_string( ansi_filename );
  267. #else
  268. AVS_Value arg = avs_new_value_string( psz_filename );
  269. #endif
  270. AVS_Value res;
  271. char *filename_ext = get_filename_extension( psz_filename );
  272. if( !strcasecmp( filename_ext, "avs" ) )
  273. {
  274. res = h->func.avs_invoke( h->env, "Import", arg, NULL );
  275. FAIL_IF_ERROR( avs_is_error( res ), "%s\n", avs_as_error( res ) );
  276. /* check if the user is using a multi-threaded script and apply distributor if necessary.
  277. adapted from avisynth's vfw interface */
  278. AVS_Value mt_test = h->func.avs_invoke( h->env, "GetMTMode", avs_new_value_bool( 0 ), NULL );
  279. int mt_mode = avs_is_int( mt_test ) ? avs_as_int( mt_test ) : 0;
  280. h->func.avs_release_value( mt_test );
  281. if( mt_mode > 0 && mt_mode < 5 )
  282. {
  283. AVS_Value temp = h->func.avs_invoke( h->env, "Distributor", res, NULL );
  284. h->func.avs_release_value( res );
  285. res = temp;
  286. }
  287. }
  288. else /* non script file */
  289. {
  290. /* cycle through known source filters to find one that works */
  291. const char *filter[AVS_MAX_SEQUENCE+1] = { 0 };
  292. avs_build_filter_sequence( filename_ext, filter );
  293. int i;
  294. for( i = 0; filter[i]; i++ )
  295. {
  296. x264_cli_log( "avs", X264_LOG_INFO, "trying %s... ", filter[i] );
  297. if( !h->func.avs_function_exists( h->env, filter[i] ) )
  298. {
  299. x264_cli_printf( X264_LOG_INFO, "not found\n" );
  300. continue;
  301. }
  302. if( !strncasecmp( filter[i], "FFmpegSource", 12 ) )
  303. {
  304. x264_cli_printf( X264_LOG_INFO, "indexing... " );
  305. fflush( stderr );
  306. }
  307. res = h->func.avs_invoke( h->env, filter[i], arg, NULL );
  308. if( !avs_is_error( res ) )
  309. {
  310. x264_cli_printf( X264_LOG_INFO, "succeeded\n" );
  311. break;
  312. }
  313. x264_cli_printf( X264_LOG_INFO, "failed\n" );
  314. }
  315. FAIL_IF_ERROR( !filter[i], "unable to find source filter to open `%s'\n", psz_filename );
  316. }
  317. FAIL_IF_ERROR( !avs_is_clip( res ), "`%s' didn't return a video clip\n", psz_filename );
  318. h->clip = h->func.avs_take_clip( res, h->env );
  319. const AVS_VideoInfo *vi = h->func.avs_get_video_info( h->clip );
  320. FAIL_IF_ERROR( !avs_has_video( vi ), "`%s' has no video data\n", psz_filename );
  321. /* if the clip is made of fields instead of frames, call weave to make them frames */
  322. if( avs_is_field_based( vi ) )
  323. {
  324. x264_cli_log( "avs", X264_LOG_WARNING, "detected fieldbased (separated) input, weaving to frames\n" );
  325. AVS_Value tmp = h->func.avs_invoke( h->env, "Weave", res, NULL );
  326. FAIL_IF_ERROR( avs_is_error( tmp ), "couldn't weave fields into frames: %s\n", avs_as_error( tmp ) );
  327. res = update_clip( h, &vi, tmp, res );
  328. info->interlaced = 1;
  329. info->tff = avs_is_tff( vi );
  330. }
  331. #if !HAVE_SWSCALE
  332. /* if swscale is not available, convert the CSP if necessary */
  333. 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),
  334. "avisynth >= 2.6 is required for i400/i422/i444 output\n" );
  335. if( (opt->output_csp == X264_CSP_I400 && !AVS_IS_Y( vi )) ||
  336. (opt->output_csp == X264_CSP_I420 && !AVS_IS_420( vi )) ||
  337. (opt->output_csp == X264_CSP_I422 && !AVS_IS_422( vi )) ||
  338. (opt->output_csp == X264_CSP_I444 && !AVS_IS_444( vi )) ||
  339. (opt->output_csp == X264_CSP_RGB && !avs_is_rgb( vi )) )
  340. {
  341. const char *csp;
  342. if( AVS_IS_AVISYNTHPLUS )
  343. {
  344. csp = opt->output_csp == X264_CSP_I400 ? "Y" :
  345. opt->output_csp == X264_CSP_I420 ? "YUV420" :
  346. opt->output_csp == X264_CSP_I422 ? "YUV422" :
  347. opt->output_csp == X264_CSP_I444 ? "YUV444" :
  348. "RGB";
  349. }
  350. else
  351. {
  352. csp = opt->output_csp == X264_CSP_I400 ? "Y8" :
  353. opt->output_csp == X264_CSP_I420 ? "YV12" :
  354. opt->output_csp == X264_CSP_I422 ? "YV16" :
  355. opt->output_csp == X264_CSP_I444 ? "YV24" :
  356. "RGB";
  357. }
  358. x264_cli_log( "avs", X264_LOG_WARNING, "converting input clip to %s\n", csp );
  359. if( opt->output_csp != X264_CSP_I400 )
  360. {
  361. FAIL_IF_ERROR( opt->output_csp < X264_CSP_I444 && (vi->width&1),
  362. "input clip width not divisible by 2 (%dx%d)\n", vi->width, vi->height );
  363. FAIL_IF_ERROR( opt->output_csp == X264_CSP_I420 && info->interlaced && (vi->height&3),
  364. "input clip height not divisible by 4 (%dx%d)\n", vi->width, vi->height );
  365. FAIL_IF_ERROR( (opt->output_csp == X264_CSP_I420 || info->interlaced) && (vi->height&1),
  366. "input clip height not divisible by 2 (%dx%d)\n", vi->width, vi->height );
  367. }
  368. char conv_func[16];
  369. snprintf( conv_func, sizeof(conv_func), "ConvertTo%s", csp );
  370. AVS_Value arg_arr[3];
  371. const char *arg_name[3];
  372. int arg_count = 1;
  373. arg_arr[0] = res;
  374. arg_name[0] = NULL;
  375. if( opt->output_csp != X264_CSP_I400 )
  376. {
  377. arg_arr[arg_count] = avs_new_value_bool( info->interlaced );
  378. arg_name[arg_count] = "interlaced";
  379. arg_count++;
  380. }
  381. /* if doing a rgb <-> yuv conversion then range is handled via 'matrix'. though it's only supported in 2.56+ */
  382. char matrix[7];
  383. 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 ))) )
  384. {
  385. // if converting from yuv, then we specify the matrix for the input, otherwise use the output's.
  386. int use_pc_matrix = avs_is_yuv( vi ) ? opt->input_range == RANGE_PC : opt->output_range == RANGE_PC;
  387. snprintf( matrix, sizeof(matrix), "%s601", use_pc_matrix ? "PC." : "Rec" ); /* FIXME: use correct coefficients */
  388. arg_arr[arg_count] = avs_new_value_string( matrix );
  389. arg_name[arg_count] = "matrix";
  390. arg_count++;
  391. // notification that the input range has changed to the desired one
  392. opt->input_range = opt->output_range;
  393. }
  394. AVS_Value res2 = h->func.avs_invoke( h->env, conv_func, avs_new_value_array( arg_arr, arg_count ), arg_name );
  395. FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert input clip to %s: %s\n", csp, avs_as_error( res2 ) );
  396. res = update_clip( h, &vi, res2, res );
  397. }
  398. /* if swscale is not available, change the range if necessary. This only applies to YUV-based CSPs however */
  399. if( avs_is_yuv( vi ) && opt->output_range != RANGE_AUTO && ((opt->input_range == RANGE_PC) != opt->output_range) )
  400. {
  401. const char *levels = opt->output_range ? "TV->PC" : "PC->TV";
  402. x264_cli_log( "avs", X264_LOG_WARNING, "performing %s conversion\n", levels );
  403. AVS_Value arg_arr[2];
  404. arg_arr[0] = res;
  405. arg_arr[1] = avs_new_value_string( levels );
  406. const char *arg_name[] = { NULL, "levels" };
  407. AVS_Value res2 = h->func.avs_invoke( h->env, "ColorYUV", avs_new_value_array( arg_arr, 2 ), arg_name );
  408. FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert range: %s\n", avs_as_error( res2 ) );
  409. res = update_clip( h, &vi, res2, res );
  410. // notification that the input range has changed to the desired one
  411. opt->input_range = opt->output_range;
  412. }
  413. #endif
  414. h->func.avs_release_value( res );
  415. info->width = vi->width;
  416. info->height = vi->height;
  417. info->fps_num = vi->fps_numerator;
  418. info->fps_den = vi->fps_denominator;
  419. h->num_frames = info->num_frames = vi->num_frames;
  420. info->thread_safe = 1;
  421. if( AVS_IS_RGB64( vi ) )
  422. info->csp = X264_CSP_BGRA | X264_CSP_VFLIP | X264_CSP_HIGH_DEPTH;
  423. else if( avs_is_rgb32( vi ) )
  424. info->csp = X264_CSP_BGRA | X264_CSP_VFLIP;
  425. else if( AVS_IS_RGB48( vi ) )
  426. info->csp = X264_CSP_BGR | X264_CSP_VFLIP | X264_CSP_HIGH_DEPTH;
  427. else if( avs_is_rgb24( vi ) )
  428. info->csp = X264_CSP_BGR | X264_CSP_VFLIP;
  429. else if( AVS_IS_YUV444P16( vi ) )
  430. info->csp = X264_CSP_I444 | X264_CSP_HIGH_DEPTH;
  431. else if( avs_is_yv24( vi ) )
  432. info->csp = X264_CSP_I444;
  433. else if( AVS_IS_YUV422P16( vi ) )
  434. info->csp = X264_CSP_I422 | X264_CSP_HIGH_DEPTH;
  435. else if( avs_is_yv16( vi ) )
  436. info->csp = X264_CSP_I422;
  437. else if( AVS_IS_YUV420P16( vi ) )
  438. info->csp = X264_CSP_I420 | X264_CSP_HIGH_DEPTH;
  439. else if( avs_is_yv12( vi ) )
  440. info->csp = X264_CSP_I420;
  441. else if( AVS_IS_Y16( vi ) )
  442. info->csp = X264_CSP_I400 | X264_CSP_HIGH_DEPTH;
  443. else if( avs_is_y8( vi ) )
  444. info->csp = X264_CSP_I400;
  445. else if( avs_is_yuy2( vi ) )
  446. info->csp = X264_CSP_YUYV;
  447. #if HAVE_SWSCALE
  448. else if( avs_is_yv411( vi ) )
  449. info->csp = AV_PIX_FMT_YUV411P | X264_CSP_OTHER;
  450. #endif
  451. else
  452. {
  453. AVS_Value pixel_type = h->func.avs_invoke( h->env, "PixelType", res, NULL );
  454. const char *pixel_type_name = avs_is_string( pixel_type ) ? avs_as_string( pixel_type ) : "unknown";
  455. FAIL_IF_ERROR( 1, "not supported pixel type: %s\n", pixel_type_name );
  456. }
  457. info->vfr = 0;
  458. *p_handle = h;
  459. return 0;
  460. }
  461. static int picture_alloc( cli_pic_t *pic, hnd_t handle, int csp, int width, int height )
  462. {
  463. if( x264_cli_pic_alloc( pic, X264_CSP_NONE, width, height ) )
  464. return -1;
  465. pic->img.csp = csp;
  466. const x264_cli_csp_t *cli_csp = x264_cli_get_csp( csp );
  467. if( cli_csp )
  468. pic->img.planes = cli_csp->planes;
  469. #if HAVE_SWSCALE
  470. else if( csp == (AV_PIX_FMT_YUV411P | X264_CSP_OTHER) )
  471. pic->img.planes = 3;
  472. else
  473. pic->img.planes = 1; //y8 and yuy2 are one plane
  474. #endif
  475. return 0;
  476. }
  477. static int read_frame( cli_pic_t *pic, hnd_t handle, int i_frame )
  478. {
  479. static const int plane[3] = { AVS_PLANAR_Y, AVS_PLANAR_U, AVS_PLANAR_V };
  480. avs_hnd_t *h = handle;
  481. if( i_frame >= h->num_frames )
  482. return -1;
  483. AVS_VideoFrame *frm = pic->opaque = h->func.avs_get_frame( h->clip, i_frame );
  484. const char *err = h->func.avs_clip_get_error( h->clip );
  485. FAIL_IF_ERROR( err, "%s occurred while reading frame %d\n", err, i_frame );
  486. for( int i = 0; i < pic->img.planes; i++ )
  487. {
  488. /* explicitly cast away the const attribute to avoid a warning */
  489. pic->img.plane[i] = (uint8_t*)avs_get_read_ptr_p( frm, plane[i] );
  490. pic->img.stride[i] = avs_get_pitch_p( frm, plane[i] );
  491. }
  492. return 0;
  493. }
  494. static int release_frame( cli_pic_t *pic, hnd_t handle )
  495. {
  496. avs_hnd_t *h = handle;
  497. h->func.avs_release_video_frame( pic->opaque );
  498. return 0;
  499. }
  500. static void picture_clean( cli_pic_t *pic, hnd_t handle )
  501. {
  502. memset( pic, 0, sizeof(cli_pic_t) );
  503. }
  504. static int close_file( hnd_t handle )
  505. {
  506. avs_hnd_t *h = handle;
  507. if( h->func.avs_release_clip && h->clip )
  508. h->func.avs_release_clip( h->clip );
  509. if( h->func.avs_delete_script_environment && h->env )
  510. h->func.avs_delete_script_environment( h->env );
  511. if( h->library )
  512. avs_close( h->library );
  513. free( h );
  514. return 0;
  515. }
  516. const cli_input_t avs_input = { open_file, picture_alloc, read_frame, release_frame, picture_clean, close_file };