2006-08-29 08:15:38 +00:00
/*
2020-03-12 19:38:00 -04:00
* AviSynth(+) support
2016-04-27 13:45:23 -04:00
* Copyright (c) 2012 AvxSynth Team
2006-10-07 15:30:46 +00:00
*
2013-02-26 18:02:20 -05:00
* This file is part of FFmpeg
2006-10-07 15:30:46 +00:00
*
* FFmpeg is free software; you can redistribute it and/or
2006-08-29 08:15:38 +00:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
2006-10-07 15:30:46 +00:00
* version 2.1 of the License, or (at your option) any later version.
2006-08-29 08:15:38 +00:00
*
2006-10-07 15:30:46 +00:00
* FFmpeg is distributed in the hope that it will be useful,
2006-08-29 08:15:38 +00:00
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
2006-10-07 15:30:46 +00:00
* License along with FFmpeg; if not, write to the Free Software
2006-08-29 08:15:38 +00:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
2016-10-26 22:54:18 -04:00
#include "libavutil/attributes.h"
2013-09-04 20:03:14 +02:00
#include "libavutil/internal.h"
2024-03-25 01:30:37 +01:00
#include "libavutil/mem.h"
2022-08-30 18:34:57 -04:00
#include "libavutil/opt.h"
2024-05-17 14:53:33 +02:00
#include "libavutil/thread.h"
2016-10-26 22:54:18 -04:00
2006-08-29 08:15:38 +00:00
#include "avformat.h"
2024-02-10 15:50:43 +01:00
#include "demux.h"
2011-11-29 19:28:15 +01:00
#include "internal.h"
2015-03-17 13:32:06 +01:00
#include "config.h"
2006-08-29 08:15:38 +00:00
2013-10-28 16:52:44 -04:00
/* Enable function pointer definitions for runtime loading. */
2013-02-26 18:02:20 -05:00
#define AVSC_NO_DECLSPEC
2006-08-29 08:15:38 +00:00
2020-03-12 19:38:00 -04:00
/* Platform-specific directives. */
2013-02-26 18:02:20 -05:00
#ifdef _WIN32
2016-10-31 14:30:43 +11:00
#include "compat/w32dlfcn.h"
2022-06-20 13:30:00 +03:00
#include "libavutil/wchar_filename.h"
2013-02-26 18:02:20 -05:00
#undef EXTERN_C
#define AVISYNTH_LIB "avisynth"
#else
#include <dlfcn.h>
2020-03-12 19:38:00 -04:00
#define AVISYNTH_NAME "libavisynth"
2015-03-17 13:32:06 +01:00
#define AVISYNTH_LIB AVISYNTH_NAME SLIBSUF
2012-06-26 13:10:01 +02:00
#endif
2006-08-29 08:15:38 +00:00
2021-01-03 17:58:36 -05:00
/* Endianness guards for audio */
#if HAVE_BIGENDIAN
#define PCM(format) (AV_CODEC_ID_PCM_ ## format ## BE)
#else
#define PCM(format) (AV_CODEC_ID_PCM_ ## format ## LE)
#endif
2020-03-12 19:38:00 -04:00
#include <avisynth/avisynth_c.h>
2013-10-28 16:52:47 -04:00
typedef struct AviSynthLibrary {
2013-02-26 18:02:20 -05:00
void * library ;
2013-10-28 16:52:45 -04:00
#define AVSC_DECLARE_FUNC(name) name ## _func name
2013-08-06 20:57:16 -04:00
AVSC_DECLARE_FUNC ( avs_bit_blt );
AVSC_DECLARE_FUNC ( avs_clip_get_error );
2022-06-20 13:30:00 +03:00
AVSC_DECLARE_FUNC ( avs_check_version );
2013-02-26 18:02:20 -05:00
AVSC_DECLARE_FUNC ( avs_create_script_environment );
AVSC_DECLARE_FUNC ( avs_delete_script_environment );
AVSC_DECLARE_FUNC ( avs_get_audio );
2023-06-11 20:21:41 -04:00
AVSC_DECLARE_FUNC ( avs_get_channel_mask );
2013-08-06 20:57:16 -04:00
AVSC_DECLARE_FUNC ( avs_get_error );
2013-02-26 18:02:20 -05:00
AVSC_DECLARE_FUNC ( avs_get_frame );
2013-08-06 20:57:17 -04:00
AVSC_DECLARE_FUNC ( avs_get_version );
2013-08-06 20:57:16 -04:00
AVSC_DECLARE_FUNC ( avs_get_video_info );
AVSC_DECLARE_FUNC ( avs_invoke );
2020-04-07 19:47:43 -04:00
AVSC_DECLARE_FUNC ( avs_is_color_space );
2013-08-06 20:57:16 -04:00
AVSC_DECLARE_FUNC ( avs_release_clip );
AVSC_DECLARE_FUNC ( avs_release_value );
2013-02-26 18:02:20 -05:00
AVSC_DECLARE_FUNC ( avs_release_video_frame );
2013-08-06 20:57:16 -04:00
AVSC_DECLARE_FUNC ( avs_take_clip );
2015-03-12 22:52:29 -04:00
AVSC_DECLARE_FUNC ( avs_bits_per_pixel );
AVSC_DECLARE_FUNC ( avs_get_height_p );
AVSC_DECLARE_FUNC ( avs_get_pitch_p );
AVSC_DECLARE_FUNC ( avs_get_read_ptr_p );
AVSC_DECLARE_FUNC ( avs_get_row_size_p );
2016-08-16 18:45:21 -04:00
AVSC_DECLARE_FUNC ( avs_is_planar_rgb );
AVSC_DECLARE_FUNC ( avs_is_planar_rgba );
2021-09-23 01:35:08 -04:00
AVSC_DECLARE_FUNC ( avs_get_frame_props_ro );
AVSC_DECLARE_FUNC ( avs_prop_get_int );
2022-02-26 19:25:40 -05:00
AVSC_DECLARE_FUNC ( avs_prop_get_type );
2021-09-23 01:35:08 -04:00
AVSC_DECLARE_FUNC ( avs_get_env_property );
2013-02-26 18:02:20 -05:00
#undef AVSC_DECLARE_FUNC
} AviSynthLibrary ;
2011-09-10 05:23:17 +02:00
2022-08-30 18:34:57 -04:00
typedef enum AviSynthFlags {
AVISYNTH_FRAMEPROP_FIELD_ORDER = ( 1 << 0 ),
AVISYNTH_FRAMEPROP_RANGE = ( 1 << 1 ),
AVISYNTH_FRAMEPROP_PRIMARIES = ( 1 << 2 ),
AVISYNTH_FRAMEPROP_TRANSFER = ( 1 << 3 ),
AVISYNTH_FRAMEPROP_MATRIX = ( 1 << 4 ),
AVISYNTH_FRAMEPROP_CHROMA_LOCATION = ( 1 << 5 ),
AVISYNTH_FRAMEPROP_SAR = ( 1 << 6 ),
} AviSynthFlags ;
2013-10-28 16:52:47 -04:00
typedef struct AviSynthContext {
2022-08-30 18:34:57 -04:00
const AVClass * class ;
2013-02-26 18:02:20 -05:00
AVS_ScriptEnvironment * env ;
AVS_Clip * clip ;
const AVS_VideoInfo * vi ;
2006-08-29 08:15:38 +00:00
2013-10-28 16:52:44 -04:00
/* avisynth_read_packet_video() iterates over this. */
2013-02-26 18:02:20 -05:00
int n_planes ;
const int * planes ;
2006-08-29 08:15:38 +00:00
2013-02-26 18:02:20 -05:00
int curr_stream ;
int curr_frame ;
int64_t curr_sample ;
2006-08-29 08:15:38 +00:00
2013-02-26 18:02:20 -05:00
int error ;
2006-08-29 08:15:38 +00:00
2022-08-30 18:34:57 -04:00
uint32_t flags ;
2024-07-28 13:46:22 -04:00
struct AviSynthLibrary avs_library ;
2013-10-28 16:52:47 -04:00
} AviSynthContext ;
2013-02-26 18:02:20 -05:00
2024-07-28 13:46:22 -04:00
static av_cold int avisynth_load_library ( AviSynthContext * avs )
2013-10-28 16:52:45 -04:00
{
2024-07-28 13:46:22 -04:00
avs -> avs_library . library = dlopen ( AVISYNTH_LIB , RTLD_NOW | RTLD_LOCAL );
if ( ! avs -> avs_library . library )
2013-02-26 18:02:20 -05:00
return AVERROR_UNKNOWN ;
2013-12-01 06:03:35 -05:00
#define LOAD_AVS_FUNC(name, continue_on_fail) \
2024-07-28 13:46:22 -04:00
avs->avs_library.name = (name ## _func) \
dlsym(avs->avs_library.library, #name); \
if (!continue_on_fail && !avs->avs_library.name) \
2013-10-28 16:52:45 -04:00
goto fail;
2013-08-06 20:57:16 -04:00
LOAD_AVS_FUNC ( avs_bit_blt , 0 );
LOAD_AVS_FUNC ( avs_clip_get_error , 0 );
2022-06-20 13:30:00 +03:00
LOAD_AVS_FUNC ( avs_check_version , 0 );
2013-02-26 18:02:20 -05:00
LOAD_AVS_FUNC ( avs_create_script_environment , 0 );
LOAD_AVS_FUNC ( avs_delete_script_environment , 0 );
LOAD_AVS_FUNC ( avs_get_audio , 0 );
2023-06-11 20:21:41 -04:00
LOAD_AVS_FUNC ( avs_get_channel_mask , 1 );
2013-08-06 20:57:16 -04:00
LOAD_AVS_FUNC ( avs_get_error , 1 ); // New to AviSynth 2.6
2013-02-26 18:02:20 -05:00
LOAD_AVS_FUNC ( avs_get_frame , 0 );
2013-08-06 20:57:17 -04:00
LOAD_AVS_FUNC ( avs_get_version , 0 );
2013-08-06 20:57:16 -04:00
LOAD_AVS_FUNC ( avs_get_video_info , 0 );
LOAD_AVS_FUNC ( avs_invoke , 0 );
2020-04-07 19:47:43 -04:00
LOAD_AVS_FUNC ( avs_is_color_space , 1 );
2013-08-06 20:57:16 -04:00
LOAD_AVS_FUNC ( avs_release_clip , 0 );
LOAD_AVS_FUNC ( avs_release_value , 0 );
2013-02-26 18:02:20 -05:00
LOAD_AVS_FUNC ( avs_release_video_frame , 0 );
2013-08-06 20:57:16 -04:00
LOAD_AVS_FUNC ( avs_take_clip , 0 );
2015-04-02 15:38:53 -04:00
LOAD_AVS_FUNC ( avs_bits_per_pixel , 1 );
LOAD_AVS_FUNC ( avs_get_height_p , 1 );
LOAD_AVS_FUNC ( avs_get_pitch_p , 1 );
LOAD_AVS_FUNC ( avs_get_read_ptr_p , 1 );
LOAD_AVS_FUNC ( avs_get_row_size_p , 1 );
2016-08-16 18:45:21 -04:00
LOAD_AVS_FUNC ( avs_is_planar_rgb , 1 );
LOAD_AVS_FUNC ( avs_is_planar_rgba , 1 );
2021-09-23 01:35:08 -04:00
LOAD_AVS_FUNC ( avs_get_frame_props_ro , 1 );
LOAD_AVS_FUNC ( avs_prop_get_int , 1 );
2022-02-26 19:25:40 -05:00
LOAD_AVS_FUNC ( avs_prop_get_type , 1 );
2021-09-23 01:35:08 -04:00
LOAD_AVS_FUNC ( avs_get_env_property , 1 );
2013-02-26 18:02:20 -05:00
#undef LOAD_AVS_FUNC
return 0 ;
fail :
2024-07-28 13:46:22 -04:00
dlclose ( avs -> avs_library . library );
2013-02-26 18:02:20 -05:00
return AVERROR_UNKNOWN ;
}
2013-10-28 16:52:44 -04:00
/* Note that avisynth_context_create and avisynth_context_destroy
* do not allocate or free the actual context! That is taken care of
* by libavformat. */
2013-10-28 16:52:45 -04:00
static av_cold int avisynth_context_create ( AVFormatContext * s )
{
2013-10-28 16:52:48 -04:00
AviSynthContext * avs = s -> priv_data ;
2013-02-26 18:02:20 -05:00
int ret ;
2024-07-28 13:46:22 -04:00
if ( ! avs -> avs_library . library )
if ( ret = avisynth_load_library ( avs ))
2013-02-26 18:02:20 -05:00
return ret ;
2024-07-28 13:46:22 -04:00
avs -> env = avs -> avs_library . avs_create_script_environment ( 3 );
if ( avs -> avs_library . avs_get_error ) {
const char * error = avs -> avs_library . avs_get_error ( avs -> env );
2013-03-26 19:36:18 -07:00
if ( error ) {
av_log ( s , AV_LOG_ERROR , "%s \n " , error );
return AVERROR_UNKNOWN ;
}
}
2013-02-26 18:02:20 -05:00
return 0 ;
2006-08-29 08:15:38 +00:00
}
2013-10-28 16:52:45 -04:00
static av_cold void avisynth_context_destroy ( AviSynthContext * avs )
{
2013-02-26 18:02:20 -05:00
if ( avs -> clip ) {
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_release_clip ( avs -> clip );
2013-02-26 18:02:20 -05:00
avs -> clip = NULL ;
}
if ( avs -> env ) {
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_delete_script_environment ( avs -> env );
2013-02-26 18:02:20 -05:00
avs -> env = NULL ;
}
2006-08-29 08:15:38 +00:00
}
2013-10-28 16:52:44 -04:00
/* Create AVStream from audio and video data. */
2013-10-28 16:52:45 -04:00
static int avisynth_create_stream_video ( AVFormatContext * s , AVStream * st )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
2021-09-23 01:35:08 -04:00
const AVS_Map * avsmap ;
AVS_VideoFrame * frame ;
2022-02-19 16:06:21 -05:00
int error ;
2016-08-16 18:45:21 -04:00
int planar = 0 ; // 0: packed, 1: YUV, 2: Y8, 3: Planar RGB, 4: YUVA, 5: Planar RGBA
2022-08-28 14:08:55 -04:00
int sar_num = 1 ;
int sar_den = 1 ;
2013-02-26 18:02:20 -05:00
2024-07-28 14:49:40 -04:00
static const int avs_planes_packed [ 1 ] = { 0 };
static const int avs_planes_grey [ 1 ] = { AVS_PLANAR_Y };
static const int avs_planes_yuv [ 3 ] = { AVS_PLANAR_Y , AVS_PLANAR_U ,
AVS_PLANAR_V };
static const int avs_planes_rgb [ 3 ] = { AVS_PLANAR_G , AVS_PLANAR_B ,
AVS_PLANAR_R };
static const int avs_planes_yuva [ 4 ] = { AVS_PLANAR_Y , AVS_PLANAR_U ,
AVS_PLANAR_V , AVS_PLANAR_A };
static const int avs_planes_rgba [ 4 ] = { AVS_PLANAR_G , AVS_PLANAR_B ,
AVS_PLANAR_R , AVS_PLANAR_A };
2014-06-18 20:42:52 +02:00
st -> codecpar -> codec_type = AVMEDIA_TYPE_VIDEO ;
st -> codecpar -> codec_id = AV_CODEC_ID_RAWVIDEO ;
st -> codecpar -> width = avs -> vi -> width ;
st -> codecpar -> height = avs -> vi -> height ;
2013-02-26 18:02:20 -05:00
2013-10-28 16:52:45 -04:00
st -> avg_frame_rate = ( AVRational ) { avs -> vi -> fps_numerator ,
avs -> vi -> fps_denominator };
st -> start_time = 0 ;
st -> duration = avs -> vi -> num_frames ;
st -> nb_frames = avs -> vi -> num_frames ;
2015-08-10 22:09:52 +02:00
avpriv_set_pts_info ( st , 32 , avs -> vi -> fps_denominator , avs -> vi -> fps_numerator );
2013-02-26 18:02:20 -05:00
2021-01-21 18:59:45 +01:00
2013-02-26 18:02:20 -05:00
switch ( avs -> vi -> pixel_type ) {
2016-10-26 22:54:18 -04:00
/* 10~16-bit YUV pix_fmts (AviSynth+) */
2016-08-16 18:45:21 -04:00
case AVS_CS_YUV444P10 :
st -> codecpar -> format = AV_PIX_FMT_YUV444P10 ;
planar = 1 ;
break ;
case AVS_CS_YUV422P10 :
st -> codecpar -> format = AV_PIX_FMT_YUV422P10 ;
planar = 1 ;
break ;
case AVS_CS_YUV420P10 :
st -> codecpar -> format = AV_PIX_FMT_YUV420P10 ;
planar = 1 ;
break ;
case AVS_CS_YUV444P12 :
st -> codecpar -> format = AV_PIX_FMT_YUV444P12 ;
planar = 1 ;
break ;
case AVS_CS_YUV422P12 :
st -> codecpar -> format = AV_PIX_FMT_YUV422P12 ;
planar = 1 ;
break ;
case AVS_CS_YUV420P12 :
st -> codecpar -> format = AV_PIX_FMT_YUV420P12 ;
planar = 1 ;
break ;
case AVS_CS_YUV444P14 :
st -> codecpar -> format = AV_PIX_FMT_YUV444P14 ;
planar = 1 ;
break ;
case AVS_CS_YUV422P14 :
st -> codecpar -> format = AV_PIX_FMT_YUV422P14 ;
planar = 1 ;
break ;
case AVS_CS_YUV420P14 :
st -> codecpar -> format = AV_PIX_FMT_YUV420P14 ;
planar = 1 ;
break ;
case AVS_CS_YUV444P16 :
st -> codecpar -> format = AV_PIX_FMT_YUV444P16 ;
planar = 1 ;
break ;
case AVS_CS_YUV422P16 :
st -> codecpar -> format = AV_PIX_FMT_YUV422P16 ;
planar = 1 ;
break ;
case AVS_CS_YUV420P16 :
st -> codecpar -> format = AV_PIX_FMT_YUV420P16 ;
planar = 1 ;
break ;
2016-10-26 22:54:18 -04:00
/* 8~16-bit YUV pix_fmts with Alpha (AviSynth+) */
2016-08-16 18:45:21 -04:00
case AVS_CS_YUVA444 :
st -> codecpar -> format = AV_PIX_FMT_YUVA444P ;
planar = 4 ;
break ;
case AVS_CS_YUVA422 :
st -> codecpar -> format = AV_PIX_FMT_YUVA422P ;
planar = 4 ;
break ;
case AVS_CS_YUVA420 :
st -> codecpar -> format = AV_PIX_FMT_YUVA420P ;
planar = 4 ;
break ;
case AVS_CS_YUVA444P10 :
st -> codecpar -> format = AV_PIX_FMT_YUVA444P10 ;
planar = 4 ;
break ;
case AVS_CS_YUVA422P10 :
st -> codecpar -> format = AV_PIX_FMT_YUVA422P10 ;
planar = 4 ;
break ;
case AVS_CS_YUVA420P10 :
st -> codecpar -> format = AV_PIX_FMT_YUVA420P10 ;
planar = 4 ;
break ;
2019-03-24 16:25:37 -04:00
case AVS_CS_YUVA422P12 :
st -> codecpar -> format = AV_PIX_FMT_YUVA422P12 ;
planar = 4 ;
break ;
2016-08-16 18:45:21 -04:00
case AVS_CS_YUVA444P16 :
st -> codecpar -> format = AV_PIX_FMT_YUVA444P16 ;
planar = 4 ;
break ;
case AVS_CS_YUVA422P16 :
st -> codecpar -> format = AV_PIX_FMT_YUVA422P16 ;
planar = 4 ;
break ;
case AVS_CS_YUVA420P16 :
st -> codecpar -> format = AV_PIX_FMT_YUVA420P16 ;
planar = 4 ;
break ;
2016-10-26 22:54:18 -04:00
/* Planar RGB pix_fmts (AviSynth+) */
2016-08-16 18:45:21 -04:00
case AVS_CS_RGBP :
st -> codecpar -> format = AV_PIX_FMT_GBRP ;
planar = 3 ;
break ;
case AVS_CS_RGBP10 :
st -> codecpar -> format = AV_PIX_FMT_GBRP10 ;
planar = 3 ;
break ;
case AVS_CS_RGBP12 :
st -> codecpar -> format = AV_PIX_FMT_GBRP12 ;
planar = 3 ;
break ;
case AVS_CS_RGBP14 :
st -> codecpar -> format = AV_PIX_FMT_GBRP14 ;
planar = 3 ;
break ;
case AVS_CS_RGBP16 :
st -> codecpar -> format = AV_PIX_FMT_GBRP16 ;
planar = 3 ;
break ;
2019-03-24 16:25:37 -04:00
/* Single precision floating point Planar RGB (AviSynth+) */
case AVS_CS_RGBPS :
st -> codecpar -> format = AV_PIX_FMT_GBRPF32 ;
planar = 3 ;
break ;
2016-10-26 22:54:18 -04:00
/* Planar RGB pix_fmts with Alpha (AviSynth+) */
2016-08-16 18:45:21 -04:00
case AVS_CS_RGBAP :
st -> codecpar -> format = AV_PIX_FMT_GBRAP ;
planar = 5 ;
break ;
case AVS_CS_RGBAP10 :
st -> codecpar -> format = AV_PIX_FMT_GBRAP10 ;
planar = 5 ;
break ;
case AVS_CS_RGBAP12 :
st -> codecpar -> format = AV_PIX_FMT_GBRAP12 ;
planar = 5 ;
break ;
case AVS_CS_RGBAP16 :
st -> codecpar -> format = AV_PIX_FMT_GBRAP16 ;
planar = 5 ;
break ;
2019-03-24 16:25:37 -04:00
/* Single precision floating point Planar RGB with Alpha (AviSynth+) */
case AVS_CS_RGBAPS :
st -> codecpar -> format = AV_PIX_FMT_GBRAPF32 ;
planar = 5 ;
break ;
/* 10~16-bit gray pix_fmts (AviSynth+) */
case AVS_CS_Y10 :
st -> codecpar -> format = AV_PIX_FMT_GRAY10 ;
planar = 2 ;
break ;
case AVS_CS_Y12 :
st -> codecpar -> format = AV_PIX_FMT_GRAY12 ;
planar = 2 ;
break ;
case AVS_CS_Y14 :
st -> codecpar -> format = AV_PIX_FMT_GRAY14 ;
planar = 2 ;
break ;
2016-08-16 18:45:21 -04:00
case AVS_CS_Y16 :
st -> codecpar -> format = AV_PIX_FMT_GRAY16 ;
planar = 2 ;
break ;
2019-03-24 16:25:37 -04:00
/* Single precision floating point gray (AviSynth+) */
case AVS_CS_Y32 :
st -> codecpar -> format = AV_PIX_FMT_GRAYF32 ;
planar = 2 ;
break ;
2016-10-26 22:54:18 -04:00
/* pix_fmts added in AviSynth 2.6 */
2013-02-26 18:02:20 -05:00
case AVS_CS_YV24 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUV444P ;
planar = 1 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_YV16 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUV422P ;
planar = 1 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_YV411 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUV411P ;
planar = 1 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_Y8 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_GRAY8 ;
planar = 2 ;
2013-02-26 18:02:20 -05:00
break ;
2016-10-26 22:54:18 -04:00
/* 16-bit packed RGB pix_fmts (AviSynth+) */
2016-08-16 18:45:21 -04:00
case AVS_CS_BGR48 :
st -> codecpar -> format = AV_PIX_FMT_BGR48 ;
break ;
case AVS_CS_BGR64 :
st -> codecpar -> format = AV_PIX_FMT_BGRA64 ;
break ;
2020-03-12 19:38:00 -04:00
/* AviSynth 2.5 pix_fmts */
2013-02-26 18:02:20 -05:00
case AVS_CS_BGR24 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_BGR24 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_BGR32 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_RGB32 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_YUY2 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUYV422 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_YV12 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUV420P ;
planar = 1 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_CS_I420 : // Is this even used anywhere?
2014-06-18 20:42:52 +02:00
st -> codecpar -> format = AV_PIX_FMT_YUV420P ;
planar = 1 ;
2013-02-26 18:02:20 -05:00
break ;
default :
2013-10-28 16:52:45 -04:00
av_log ( s , AV_LOG_ERROR ,
"unknown AviSynth colorspace %d \n " , avs -> vi -> pixel_type );
2013-02-26 18:02:20 -05:00
avs -> error = 1 ;
return AVERROR_UNKNOWN ;
2006-08-29 08:15:38 +00:00
}
2013-02-26 18:02:20 -05:00
switch ( planar ) {
2016-08-16 18:45:21 -04:00
case 5 : // Planar RGB + Alpha
avs -> n_planes = 4 ;
avs -> planes = avs_planes_rgba ;
break ;
case 4 : // YUV + Alpha
avs -> n_planes = 4 ;
avs -> planes = avs_planes_yuva ;
break ;
case 3 : // Planar RGB
avs -> n_planes = 3 ;
avs -> planes = avs_planes_rgb ;
break ;
2013-02-26 18:02:20 -05:00
case 2 : // Y8
avs -> n_planes = 1 ;
2013-10-28 16:52:45 -04:00
avs -> planes = avs_planes_grey ;
2013-02-26 18:02:20 -05:00
break ;
case 1 : // YUV
avs -> n_planes = 3 ;
2013-10-28 16:52:45 -04:00
avs -> planes = avs_planes_yuv ;
2013-02-26 18:02:20 -05:00
break ;
default :
avs -> n_planes = 1 ;
2013-10-28 16:52:45 -04:00
avs -> planes = avs_planes_packed ;
2013-02-26 18:02:20 -05:00
}
2021-09-23 01:35:08 -04:00
/* Read AviSynth+'s frame properties to set additional info.
*
* Due to a bug preventing the C interface from accessing frame
2022-02-16 19:37:18 -05:00
* properties in earlier versions of interface version 8, and
* previous attempts at being clever resulting in pre-8 versions
* of AviSynth+ segfaulting, only enable this if we detect
* version 9 at the minimum. Technically, 8.1 works, but the time
* distance between 8.1 and 9 is very small, so just restrict it to 9. */
2021-09-23 01:35:08 -04:00
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_get_version ( avs -> clip ) >= 9 ) {
2021-09-23 01:35:08 -04:00
2024-07-28 13:46:22 -04:00
frame = avs -> avs_library . avs_get_frame ( avs -> clip , 0 );
avsmap = avs -> avs_library . avs_get_frame_props_ro ( avs -> env , frame );
2021-09-23 01:35:08 -04:00
/* Field order */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_FIELD_ORDER ) {
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_prop_get_type ( avs -> env , avsmap , "_FieldBased" ) == AVS_PROPTYPE_UNSET ) {
2022-02-26 19:25:40 -05:00
st -> codecpar -> field_order = AV_FIELD_UNKNOWN ;
2022-08-30 20:11:20 -04:00
} else {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_FieldBased" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 0 :
st -> codecpar -> field_order = AV_FIELD_PROGRESSIVE ;
break ;
case 1 :
st -> codecpar -> field_order = AV_FIELD_BB ;
break ;
case 2 :
st -> codecpar -> field_order = AV_FIELD_TT ;
break ;
default :
st -> codecpar -> field_order = AV_FIELD_UNKNOWN ;
}
2022-02-26 19:25:40 -05:00
}
2021-09-23 01:35:08 -04:00
}
/* Color Range */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_RANGE ) {
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_prop_get_type ( avs -> env , avsmap , "_ColorRange" ) == AVS_PROPTYPE_UNSET ) {
2022-02-26 19:25:40 -05:00
st -> codecpar -> color_range = AVCOL_RANGE_UNSPECIFIED ;
2022-08-30 20:11:20 -04:00
} else {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_ColorRange" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 0 :
st -> codecpar -> color_range = AVCOL_RANGE_JPEG ;
break ;
case 1 :
st -> codecpar -> color_range = AVCOL_RANGE_MPEG ;
break ;
default :
st -> codecpar -> color_range = AVCOL_RANGE_UNSPECIFIED ;
}
2022-02-26 19:25:40 -05:00
}
2021-09-23 01:35:08 -04:00
}
/* Color Primaries */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_PRIMARIES ) {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_Primaries" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 1 :
st -> codecpar -> color_primaries = AVCOL_PRI_BT709 ;
break ;
case 2 :
st -> codecpar -> color_primaries = AVCOL_PRI_UNSPECIFIED ;
break ;
case 4 :
st -> codecpar -> color_primaries = AVCOL_PRI_BT470M ;
break ;
case 5 :
st -> codecpar -> color_primaries = AVCOL_PRI_BT470BG ;
break ;
case 6 :
st -> codecpar -> color_primaries = AVCOL_PRI_SMPTE170M ;
break ;
case 7 :
st -> codecpar -> color_primaries = AVCOL_PRI_SMPTE240M ;
break ;
case 8 :
st -> codecpar -> color_primaries = AVCOL_PRI_FILM ;
break ;
case 9 :
st -> codecpar -> color_primaries = AVCOL_PRI_BT2020 ;
break ;
case 10 :
st -> codecpar -> color_primaries = AVCOL_PRI_SMPTE428 ;
break ;
case 11 :
st -> codecpar -> color_primaries = AVCOL_PRI_SMPTE431 ;
break ;
case 12 :
st -> codecpar -> color_primaries = AVCOL_PRI_SMPTE432 ;
break ;
case 22 :
st -> codecpar -> color_primaries = AVCOL_PRI_EBU3213 ;
break ;
default :
st -> codecpar -> color_primaries = AVCOL_PRI_UNSPECIFIED ;
}
2022-08-30 18:34:57 -04:00
}
2021-09-23 01:35:08 -04:00
/* Color Transfer Characteristics */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_TRANSFER ) {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_Transfer" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 1 :
st -> codecpar -> color_trc = AVCOL_TRC_BT709 ;
break ;
case 2 :
st -> codecpar -> color_trc = AVCOL_TRC_UNSPECIFIED ;
break ;
case 4 :
st -> codecpar -> color_trc = AVCOL_TRC_GAMMA22 ;
break ;
case 5 :
st -> codecpar -> color_trc = AVCOL_TRC_GAMMA28 ;
break ;
case 6 :
st -> codecpar -> color_trc = AVCOL_TRC_SMPTE170M ;
break ;
case 7 :
st -> codecpar -> color_trc = AVCOL_TRC_SMPTE240M ;
break ;
case 8 :
st -> codecpar -> color_trc = AVCOL_TRC_LINEAR ;
break ;
case 9 :
st -> codecpar -> color_trc = AVCOL_TRC_LOG ;
break ;
case 10 :
st -> codecpar -> color_trc = AVCOL_TRC_LOG_SQRT ;
break ;
case 11 :
st -> codecpar -> color_trc = AVCOL_TRC_IEC61966_2_4 ;
break ;
case 12 :
st -> codecpar -> color_trc = AVCOL_TRC_BT1361_ECG ;
break ;
case 13 :
st -> codecpar -> color_trc = AVCOL_TRC_IEC61966_2_1 ;
break ;
case 14 :
st -> codecpar -> color_trc = AVCOL_TRC_BT2020_10 ;
break ;
case 15 :
st -> codecpar -> color_trc = AVCOL_TRC_BT2020_12 ;
break ;
case 16 :
st -> codecpar -> color_trc = AVCOL_TRC_SMPTE2084 ;
break ;
case 17 :
st -> codecpar -> color_trc = AVCOL_TRC_SMPTE428 ;
break ;
case 18 :
st -> codecpar -> color_trc = AVCOL_TRC_ARIB_STD_B67 ;
break ;
default :
st -> codecpar -> color_trc = AVCOL_TRC_UNSPECIFIED ;
}
2022-08-30 18:34:57 -04:00
}
2021-09-23 01:35:08 -04:00
/* Matrix coefficients */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_MATRIX ) {
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_prop_get_type ( avs -> env , avsmap , "_Matrix" ) == AVS_PROPTYPE_UNSET ) {
2022-02-26 19:25:40 -05:00
st -> codecpar -> color_space = AVCOL_SPC_UNSPECIFIED ;
2022-08-30 20:11:20 -04:00
} else {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_Matrix" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 0 :
st -> codecpar -> color_space = AVCOL_SPC_RGB ;
break ;
case 1 :
st -> codecpar -> color_space = AVCOL_SPC_BT709 ;
break ;
case 2 :
st -> codecpar -> color_space = AVCOL_SPC_UNSPECIFIED ;
break ;
case 4 :
st -> codecpar -> color_space = AVCOL_SPC_FCC ;
break ;
case 5 :
st -> codecpar -> color_space = AVCOL_SPC_BT470BG ;
break ;
case 6 :
st -> codecpar -> color_space = AVCOL_SPC_SMPTE170M ;
break ;
case 7 :
st -> codecpar -> color_space = AVCOL_SPC_SMPTE240M ;
break ;
case 8 :
st -> codecpar -> color_space = AVCOL_SPC_YCGCO ;
break ;
case 9 :
st -> codecpar -> color_space = AVCOL_SPC_BT2020_NCL ;
break ;
case 10 :
st -> codecpar -> color_space = AVCOL_SPC_BT2020_CL ;
break ;
case 11 :
st -> codecpar -> color_space = AVCOL_SPC_SMPTE2085 ;
break ;
case 12 :
st -> codecpar -> color_space = AVCOL_SPC_CHROMA_DERIVED_NCL ;
break ;
case 13 :
st -> codecpar -> color_space = AVCOL_SPC_CHROMA_DERIVED_CL ;
break ;
case 14 :
st -> codecpar -> color_space = AVCOL_SPC_ICTCP ;
break ;
default :
st -> codecpar -> color_space = AVCOL_SPC_UNSPECIFIED ;
}
2022-02-26 19:25:40 -05:00
}
2021-09-23 01:35:08 -04:00
}
/* Chroma Location */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_CHROMA_LOCATION ) {
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_prop_get_type ( avs -> env , avsmap , "_ChromaLocation" ) == AVS_PROPTYPE_UNSET ) {
2022-02-26 19:25:40 -05:00
st -> codecpar -> chroma_location = AVCHROMA_LOC_UNSPECIFIED ;
2022-08-30 20:11:20 -04:00
} else {
2024-07-28 13:46:22 -04:00
switch ( avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_ChromaLocation" , 0 , & error )) {
2022-08-30 20:11:20 -04:00
case 0 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_LEFT ;
break ;
case 1 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_CENTER ;
break ;
case 2 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_TOPLEFT ;
break ;
case 3 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_TOP ;
break ;
case 4 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_BOTTOMLEFT ;
break ;
case 5 :
st -> codecpar -> chroma_location = AVCHROMA_LOC_BOTTOM ;
break ;
default :
st -> codecpar -> chroma_location = AVCHROMA_LOC_UNSPECIFIED ;
}
2022-02-26 19:25:40 -05:00
}
2021-09-23 01:35:08 -04:00
}
2022-08-28 14:08:55 -04:00
/* Sample aspect ratio */
2022-08-30 18:34:57 -04:00
if ( avs -> flags & AVISYNTH_FRAMEPROP_SAR ) {
2024-07-28 13:46:22 -04:00
sar_num = avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_SARNum" , 0 , & error );
sar_den = avs -> avs_library . avs_prop_get_int ( avs -> env , avsmap , "_SARDen" , 0 , & error );
2022-08-30 20:11:20 -04:00
st -> sample_aspect_ratio = ( AVRational ){ sar_num , sar_den };
2022-08-30 18:34:57 -04:00
}
2022-08-28 14:08:55 -04:00
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_release_video_frame ( frame );
2021-09-23 01:35:08 -04:00
} else {
st -> codecpar -> field_order = AV_FIELD_UNKNOWN ;
/* AviSynth works with frame-based video, detecting field order can
* only work when avs_is_field_based returns 'false'. */
av_log ( s , AV_LOG_TRACE , "avs_is_field_based: %d \n " , avs_is_field_based ( avs -> vi ));
if ( avs_is_field_based ( avs -> vi ) == 0 ) {
if ( avs_is_tff ( avs -> vi )) {
st -> codecpar -> field_order = AV_FIELD_TT ;
}
else if ( avs_is_bff ( avs -> vi )) {
st -> codecpar -> field_order = AV_FIELD_BB ;
}
}
}
2013-02-26 18:02:20 -05:00
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_create_stream_audio ( AVFormatContext * s , AVStream * st )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
2022-08-07 21:25:32 -04:00
st -> codecpar -> codec_type = AVMEDIA_TYPE_AUDIO ;
st -> codecpar -> sample_rate = avs -> vi -> audio_samples_per_second ;
st -> codecpar -> ch_layout . nb_channels = avs -> vi -> nchannels ;
st -> duration = avs -> vi -> num_audio_samples ;
2015-08-10 22:09:52 +02:00
avpriv_set_pts_info ( st , 64 , 1 , avs -> vi -> audio_samples_per_second );
2013-02-26 18:02:20 -05:00
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_get_version ( avs -> clip ) >= 10 )
2023-06-11 20:21:41 -04:00
av_channel_layout_from_mask ( & st -> codecpar -> ch_layout ,
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_get_channel_mask ( avs -> vi ));
2023-06-11 20:21:41 -04:00
2013-02-26 18:02:20 -05:00
switch ( avs -> vi -> sample_type ) {
case AVS_SAMPLE_INT8 :
2014-06-18 20:42:52 +02:00
st -> codecpar -> codec_id = AV_CODEC_ID_PCM_U8 ;
2013-02-26 18:02:20 -05:00
break ;
case AVS_SAMPLE_INT16 :
2021-01-03 17:58:36 -05:00
st -> codecpar -> codec_id = PCM ( S16 );
2013-02-26 18:02:20 -05:00
break ;
case AVS_SAMPLE_INT24 :
2021-01-03 17:58:36 -05:00
st -> codecpar -> codec_id = PCM ( S24 );
2013-02-26 18:02:20 -05:00
break ;
case AVS_SAMPLE_INT32 :
2021-01-03 17:58:36 -05:00
st -> codecpar -> codec_id = PCM ( S32 );
2013-02-26 18:02:20 -05:00
break ;
case AVS_SAMPLE_FLOAT :
2021-01-03 17:58:36 -05:00
st -> codecpar -> codec_id = PCM ( F32 );
2013-02-26 18:02:20 -05:00
break ;
default :
2013-10-28 16:52:45 -04:00
av_log ( s , AV_LOG_ERROR ,
"unknown AviSynth sample type %d \n " , avs -> vi -> sample_type );
2013-02-26 18:02:20 -05:00
avs -> error = 1 ;
return AVERROR_UNKNOWN ;
}
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_create_stream ( AVFormatContext * s )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
AVStream * st ;
int ret ;
int id = 0 ;
if ( avs_has_video ( avs -> vi )) {
st = avformat_new_stream ( s , NULL );
if ( ! st )
return AVERROR_UNKNOWN ;
st -> id = id ++ ;
if ( ret = avisynth_create_stream_video ( s , st ))
return ret ;
}
if ( avs_has_audio ( avs -> vi )) {
st = avformat_new_stream ( s , NULL );
if ( ! st )
return AVERROR_UNKNOWN ;
st -> id = id ++ ;
if ( ret = avisynth_create_stream_audio ( s , st ))
return ret ;
}
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_open_file ( AVFormatContext * s )
{
2013-10-28 16:52:48 -04:00
AviSynthContext * avs = s -> priv_data ;
2022-06-20 13:30:00 +03:00
AVS_Value val ;
2013-02-26 18:02:20 -05:00
int ret ;
if ( ret = avisynth_context_create ( s ))
return ret ;
2024-07-28 13:46:22 -04:00
if ( ! avs -> avs_library . avs_check_version ( avs -> env , 7 )) {
2022-06-20 13:30:00 +03:00
AVS_Value args [] = {
avs_new_value_string ( s -> url ),
avs_new_value_bool ( 1 ) // filename is in UTF-8
};
2024-07-28 13:46:22 -04:00
val = avs -> avs_library . avs_invoke ( avs -> env , "Import" ,
avs_new_value_array ( args , 2 ), 0 );
2022-06-20 13:30:00 +03:00
} else {
AVS_Value arg ;
2020-03-12 19:38:00 -04:00
#ifdef _WIN32
2022-06-20 13:30:00 +03:00
char * filename_ansi ;
/* Convert UTF-8 to ANSI code page */
if ( utf8toansi ( s -> url , & filename_ansi )) {
ret = AVERROR_UNKNOWN ;
goto fail ;
}
arg = avs_new_value_string ( filename_ansi );
2013-06-21 22:57:03 +09:00
#else
2022-06-20 13:30:00 +03:00
arg = avs_new_value_string ( s -> url );
2013-06-21 22:57:03 +09:00
#endif
2024-07-28 13:46:22 -04:00
val = avs -> avs_library . avs_invoke ( avs -> env , "Import" , arg , 0 );
2022-06-20 13:30:00 +03:00
#ifdef _WIN32
av_free ( filename_ansi );
#endif
}
2013-02-26 18:02:20 -05:00
if ( avs_is_error ( val )) {
av_log ( s , AV_LOG_ERROR , "%s \n " , avs_as_error ( val ));
ret = AVERROR_UNKNOWN ;
goto fail ;
}
if ( ! avs_is_clip ( val )) {
2013-10-29 19:42:00 +01:00
av_log ( s , AV_LOG_ERROR , "AviSynth script did not return a clip \n " );
2013-02-26 18:02:20 -05:00
ret = AVERROR_UNKNOWN ;
goto fail ;
}
2024-07-28 13:46:22 -04:00
avs -> clip = avs -> avs_library . avs_take_clip ( val , avs -> env );
avs -> vi = avs -> avs_library . avs_get_video_info ( avs -> clip );
2013-02-26 18:02:20 -05:00
2015-04-02 15:38:54 -04:00
/* On Windows, FFmpeg supports AviSynth interface version 6 or higher.
* This includes AviSynth 2.6 RC1 or higher, and AviSynth+ r1718 or higher,
2020-03-12 19:38:00 -04:00
* and excludes 2.5 and the 2.6 alphas. */
2015-03-24 15:23:30 -04:00
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_get_version ( avs -> clip ) < 6 ) {
2015-03-24 15:23:30 -04:00
av_log ( s , AV_LOG_ERROR ,
2015-04-02 15:38:54 -04:00
"AviSynth version is too old. Please upgrade to either AviSynth 2.6 >= RC1 or AviSynth+ >= r1718. \n " );
2015-03-24 15:23:30 -04:00
ret = AVERROR_UNKNOWN ;
goto fail ;
}
2013-10-28 16:52:44 -04:00
/* Release the AVS_Value as it will go out of scope. */
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_release_value ( val );
2013-02-26 18:02:20 -05:00
if ( ret = avisynth_create_stream ( s ))
goto fail ;
return 0 ;
fail :
avisynth_context_destroy ( avs );
return ret ;
}
2013-10-28 16:52:45 -04:00
static void avisynth_next_stream ( AVFormatContext * s , AVStream ** st ,
AVPacket * pkt , int * discard )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
2014-01-09 18:33:39 +01:00
avs -> curr_stream ++ ;
2013-02-26 18:02:20 -05:00
avs -> curr_stream %= s -> nb_streams ;
2014-01-09 18:33:39 +01:00
* st = s -> streams [ avs -> curr_stream ];
2013-02-26 18:02:20 -05:00
if (( * st ) -> discard == AVDISCARD_ALL )
* discard = 1 ;
else
* discard = 0 ;
return ;
}
2013-10-28 16:52:44 -04:00
/* Copy AviSynth clip data into an AVPacket. */
2013-10-28 16:52:45 -04:00
static int avisynth_read_packet_video ( AVFormatContext * s , AVPacket * pkt ,
int discard )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
AVS_VideoFrame * frame ;
2013-04-09 15:38:27 -07:00
unsigned char * dst_p ;
const unsigned char * src_p ;
2019-12-10 22:59:53 +01:00
int n , i , plane , rowsize , planeheight , pitch , bits , ret ;
2013-04-09 15:38:27 -07:00
const char * error ;
2013-02-26 18:02:20 -05:00
if ( avs -> curr_frame >= avs -> vi -> num_frames )
return AVERROR_EOF ;
2013-10-28 16:52:44 -04:00
/* This must happen even if the stream is discarded to prevent desync. */
2013-04-09 15:36:58 -07:00
n = avs -> curr_frame ++ ;
2013-02-26 18:02:20 -05:00
if ( discard )
return 0 ;
2024-07-28 13:46:22 -04:00
bits = avs -> avs_library . avs_bits_per_pixel ( avs -> vi );
2013-02-26 18:02:20 -05:00
2013-10-28 16:52:44 -04:00
/* Without the cast to int64_t, calculation overflows at about 9k x 9k
* resolution. */
2013-10-28 16:52:45 -04:00
pkt -> size = ((( int64_t ) avs -> vi -> width *
( int64_t ) avs -> vi -> height ) * bits ) / 8 ;
2013-02-26 18:02:20 -05:00
if ( ! pkt -> size )
return AVERROR_UNKNOWN ;
2014-01-08 00:37:56 -05:00
2019-12-10 22:59:53 +01:00
if (( ret = av_new_packet ( pkt , pkt -> size )) < 0 )
return ret ;
2013-02-26 18:02:20 -05:00
2014-01-09 18:33:39 +01:00
pkt -> pts = n ;
pkt -> dts = n ;
pkt -> duration = 1 ;
pkt -> stream_index = avs -> curr_stream ;
2014-01-08 00:37:57 -05:00
2024-07-28 13:46:22 -04:00
frame = avs -> avs_library . avs_get_frame ( avs -> clip , n );
error = avs -> avs_library . avs_clip_get_error ( avs -> clip );
2013-02-26 18:02:20 -05:00
if ( error ) {
av_log ( s , AV_LOG_ERROR , "%s \n " , error );
avs -> error = 1 ;
2014-01-08 00:37:56 -05:00
av_packet_unref ( pkt );
2013-02-26 18:02:20 -05:00
return AVERROR_UNKNOWN ;
}
dst_p = pkt -> data ;
for ( i = 0 ; i < avs -> n_planes ; i ++ ) {
plane = avs -> planes [ i ];
2024-07-28 13:46:22 -04:00
src_p = avs -> avs_library . avs_get_read_ptr_p ( frame , plane );
pitch = avs -> avs_library . avs_get_pitch_p ( frame , plane );
2015-03-12 22:52:29 -04:00
2024-07-28 13:46:22 -04:00
rowsize = avs -> avs_library . avs_get_row_size_p ( frame , plane );
planeheight = avs -> avs_library . avs_get_height_p ( frame , plane );
2013-02-26 18:02:20 -05:00
2013-10-28 16:52:44 -04:00
/* Flip RGB video. */
2024-07-28 13:46:22 -04:00
if ( avs -> avs_library . avs_is_color_space ( avs -> vi , AVS_CS_BGR ) ||
avs -> avs_library . avs_is_color_space ( avs -> vi , AVS_CS_BGR48 ) ||
avs -> avs_library . avs_is_color_space ( avs -> vi , AVS_CS_BGR64 )) {
2016-08-30 20:26:08 -04:00
src_p = src_p + ( planeheight - 1 ) * pitch ;
2016-08-16 18:45:21 -04:00
pitch = - pitch ;
2016-08-30 20:26:08 -04:00
}
2016-08-16 18:45:21 -04:00
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_bit_blt ( avs -> env , dst_p , rowsize , src_p , pitch ,
rowsize , planeheight );
2013-02-26 18:02:20 -05:00
dst_p += rowsize * planeheight ;
}
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_release_video_frame ( frame );
2013-02-26 18:02:20 -05:00
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_read_packet_audio ( AVFormatContext * s , AVPacket * pkt ,
int discard )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
AVRational fps , samplerate ;
2019-12-10 22:59:53 +01:00
int samples , ret ;
2013-04-09 15:36:58 -07:00
int64_t n ;
2013-04-09 15:38:27 -07:00
const char * error ;
2013-02-26 18:02:20 -05:00
if ( avs -> curr_sample >= avs -> vi -> num_audio_samples )
return AVERROR_EOF ;
2013-10-28 16:52:45 -04:00
fps . num = avs -> vi -> fps_numerator ;
fps . den = avs -> vi -> fps_denominator ;
2013-02-26 18:02:20 -05:00
samplerate . num = avs -> vi -> audio_samples_per_second ;
samplerate . den = 1 ;
if ( avs_has_video ( avs -> vi )) {
if ( avs -> curr_frame < avs -> vi -> num_frames )
2013-10-28 16:52:45 -04:00
samples = av_rescale_q ( avs -> curr_frame , samplerate , fps ) -
avs -> curr_sample ;
2013-02-26 18:02:20 -05:00
else
samples = av_rescale_q ( 1 , samplerate , fps );
} else {
samples = 1000 ;
}
2013-10-28 16:52:44 -04:00
/* After seeking, audio may catch up with video. */
2013-02-26 18:02:20 -05:00
if ( samples <= 0 ) {
pkt -> size = 0 ;
pkt -> data = NULL ;
return 0 ;
}
if ( avs -> curr_sample + samples > avs -> vi -> num_audio_samples )
samples = avs -> vi -> num_audio_samples - avs -> curr_sample ;
2013-10-28 16:52:44 -04:00
/* This must happen even if the stream is discarded to prevent desync. */
2013-10-28 16:52:45 -04:00
n = avs -> curr_sample ;
2013-02-26 18:02:20 -05:00
avs -> curr_sample += samples ;
if ( discard )
return 0 ;
2013-10-28 16:52:45 -04:00
pkt -> size = avs_bytes_per_channel_sample ( avs -> vi ) *
samples * avs -> vi -> nchannels ;
2013-02-26 18:02:20 -05:00
if ( ! pkt -> size )
return AVERROR_UNKNOWN ;
2014-01-08 00:37:56 -05:00
2019-12-10 22:59:53 +01:00
if (( ret = av_new_packet ( pkt , pkt -> size )) < 0 )
return ret ;
2013-02-26 18:02:20 -05:00
2014-01-09 18:33:39 +01:00
pkt -> pts = n ;
pkt -> dts = n ;
pkt -> duration = samples ;
pkt -> stream_index = avs -> curr_stream ;
2014-01-08 00:37:57 -05:00
2024-07-28 13:46:22 -04:00
avs -> avs_library . avs_get_audio ( avs -> clip , pkt -> data , n , samples );
error = avs -> avs_library . avs_clip_get_error ( avs -> clip );
2013-02-26 18:02:20 -05:00
if ( error ) {
av_log ( s , AV_LOG_ERROR , "%s \n " , error );
avs -> error = 1 ;
2014-01-08 00:37:56 -05:00
av_packet_unref ( pkt );
2013-02-26 18:02:20 -05:00
return AVERROR_UNKNOWN ;
}
return 0 ;
}
2013-10-28 16:52:45 -04:00
static av_cold int avisynth_read_header ( AVFormatContext * s )
{
2013-02-26 18:02:20 -05:00
int ret ;
2024-07-28 13:46:22 -04:00
if ( ret = avisynth_open_file ( s ))
2013-02-26 18:02:20 -05:00
return ret ;
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
AVStream * st ;
int discard = 0 ;
int ret ;
if ( avs -> error )
return AVERROR_UNKNOWN ;
2013-10-28 16:52:44 -04:00
/* If either stream reaches EOF, try to read the other one before
* giving up. */
2013-02-26 18:02:20 -05:00
avisynth_next_stream ( s , & st , pkt , & discard );
2014-06-18 20:42:52 +02:00
if ( st -> codecpar -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2013-02-26 18:02:20 -05:00
ret = avisynth_read_packet_video ( s , pkt , discard );
if ( ret == AVERROR_EOF && avs_has_audio ( avs -> vi )) {
avisynth_next_stream ( s , & st , pkt , & discard );
return avisynth_read_packet_audio ( s , pkt , discard );
}
} else {
ret = avisynth_read_packet_audio ( s , pkt , discard );
if ( ret == AVERROR_EOF && avs_has_video ( avs -> vi )) {
avisynth_next_stream ( s , & st , pkt , & discard );
return avisynth_read_packet_video ( s , pkt , discard );
}
}
2013-10-28 16:52:53 -04:00
return ret ;
2013-02-26 18:02:20 -05:00
}
2013-10-28 16:52:45 -04:00
static av_cold int avisynth_read_close ( AVFormatContext * s )
{
2024-07-28 13:46:22 -04:00
AviSynthContext * avs = s -> priv_data ;
if ( avs -> avs_library . library ) {
avisynth_context_destroy ( s -> priv_data );
dlclose ( avs -> avs_library . library );
}
2013-02-26 18:02:20 -05:00
return 0 ;
}
2013-10-28 16:52:45 -04:00
static int avisynth_read_seek ( AVFormatContext * s , int stream_index ,
int64_t timestamp , int flags )
{
2013-02-26 18:02:20 -05:00
AviSynthContext * avs = s -> priv_data ;
AVStream * st ;
AVRational fps , samplerate ;
if ( avs -> error )
return AVERROR_UNKNOWN ;
2013-10-28 16:52:45 -04:00
fps = ( AVRational ) { avs -> vi -> fps_numerator ,
avs -> vi -> fps_denominator };
samplerate = ( AVRational ) { avs -> vi -> audio_samples_per_second , 1 };
2013-02-26 18:02:20 -05:00
st = s -> streams [ stream_index ];
2014-06-18 20:42:52 +02:00
if ( st -> codecpar -> codec_type == AVMEDIA_TYPE_VIDEO ) {
2013-10-28 16:52:44 -04:00
/* AviSynth frame counts are signed int. */
2013-10-28 16:52:45 -04:00
if (( timestamp >= avs -> vi -> num_frames ) ||
( timestamp > INT_MAX ) ||
( timestamp < 0 ))
2013-02-26 18:02:20 -05:00
return AVERROR_EOF ;
avs -> curr_frame = timestamp ;
if ( avs_has_audio ( avs -> vi ))
avs -> curr_sample = av_rescale_q ( timestamp , samplerate , fps );
} else {
if (( timestamp >= avs -> vi -> num_audio_samples ) || ( timestamp < 0 ))
return AVERROR_EOF ;
2013-10-28 16:52:44 -04:00
/* Force frame granularity for seeking. */
2013-02-26 18:02:20 -05:00
if ( avs_has_video ( avs -> vi )) {
2013-10-28 16:52:45 -04:00
avs -> curr_frame = av_rescale_q ( timestamp , fps , samplerate );
2013-02-26 18:02:20 -05:00
avs -> curr_sample = av_rescale_q ( avs -> curr_frame , samplerate , fps );
} else {
avs -> curr_sample = timestamp ;
}
}
return 0 ;
2006-08-29 08:15:38 +00:00
}
2022-08-30 18:34:57 -04:00
#define AVISYNTH_FRAMEPROP_DEFAULT AVISYNTH_FRAMEPROP_FIELD_ORDER | AVISYNTH_FRAMEPROP_RANGE | \
AVISYNTH_FRAMEPROP_PRIMARIES | AVISYNTH_FRAMEPROP_TRANSFER | \
AVISYNTH_FRAMEPROP_MATRIX | AVISYNTH_FRAMEPROP_CHROMA_LOCATION
#define OFFSET(x) offsetof(AviSynthContext, x)
static const AVOption avisynth_options [] = {
2024-02-11 15:41:05 +01:00
{ "avisynth_flags" , "set flags related to reading frame properties from script (AviSynth+ v3.7.1 or higher)" , OFFSET ( flags ), AV_OPT_TYPE_FLAGS , {. i64 = AVISYNTH_FRAMEPROP_DEFAULT }, 0 , INT_MAX , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "field_order" , "read field order" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_FIELD_ORDER }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "range" , "read color range" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_RANGE }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "primaries" , "read color primaries" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_PRIMARIES }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "transfer" , "read color transfer characteristics" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_TRANSFER }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "matrix" , "read matrix coefficients" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_MATRIX }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "chroma_location" , "read chroma location" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_CHROMA_LOCATION }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
{ "sar" , "read sample aspect ratio" , 0 , AV_OPT_TYPE_CONST , {. i64 = AVISYNTH_FRAMEPROP_SAR }, 0 , 1 , AV_OPT_FLAG_DECODING_PARAM , . unit = "flags" },
2022-08-30 18:34:57 -04:00
{ NULL },
};
static const AVClass avisynth_demuxer_class = {
. class_name = "AviSynth demuxer" ,
2024-01-19 13:33:28 +01:00
. item_name = av_default_item_name ,
2022-08-30 18:34:57 -04:00
. option = avisynth_options ,
. version = LIBAVUTIL_VERSION_INT ,
};
2024-02-10 15:50:43 +01:00
const FFInputFormat ff_avisynth_demuxer = {
. p . name = "avisynth" ,
. p . long_name = NULL_IF_CONFIG_SMALL ( "AviSynth script" ),
. p . extensions = "avs" ,
. p . priv_class = & avisynth_demuxer_class ,
2013-02-26 18:02:20 -05:00
. priv_data_size = sizeof ( AviSynthContext ),
2011-07-16 22:18:12 +02:00
. read_header = avisynth_read_header ,
. read_packet = avisynth_read_packet ,
. read_close = avisynth_read_close ,
. read_seek = avisynth_read_seek ,
2006-08-29 08:15:38 +00:00
};