/*
- * AviSynth/AvxSynth support
+ * AviSynth(+) support
* Copyright (c) 2012 AvxSynth Team
*
* This file is part of FFmpeg
/* Enable function pointer definitions for runtime loading. */
#define AVSC_NO_DECLSPEC
-/* Platform-specific directives for AviSynth vs AvxSynth. */
+/* Platform-specific directives. */
#ifdef _WIN32
#include "compat/w32dlfcn.h"
#undef EXTERN_C
- #include "compat/avisynth/avisynth_c.h"
#define AVISYNTH_LIB "avisynth"
- #define USING_AVISYNTH
#else
#include <dlfcn.h>
- #include "compat/avisynth/avxsynth_c.h"
- #define AVISYNTH_NAME "libavxsynth"
+ #define AVISYNTH_NAME "libavisynth"
#define AVISYNTH_LIB AVISYNTH_NAME SLIBSUF
#endif
+/* 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
+
+#include <avisynth/avisynth_c.h>
+
typedef struct AviSynthLibrary {
void *library;
#define AVSC_DECLARE_FUNC(name) name ## _func name
AVSC_DECLARE_FUNC(avs_get_version);
AVSC_DECLARE_FUNC(avs_get_video_info);
AVSC_DECLARE_FUNC(avs_invoke);
+ AVSC_DECLARE_FUNC(avs_is_color_space);
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);
-#ifdef USING_AVISYNTH
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_row_size_p);
AVSC_DECLARE_FUNC(avs_is_planar_rgb);
AVSC_DECLARE_FUNC(avs_is_planar_rgba);
-#endif
#undef AVSC_DECLARE_FUNC
} AviSynthLibrary;
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 };
-#ifdef USING_AVISYNTH
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 };
-#endif
/* A conflict between C++ global objects, atexit, and dynamic loading requires
* us to register our own atexit handler to prevent double freeing. */
return AVERROR_UNKNOWN;
#define LOAD_AVS_FUNC(name, continue_on_fail) \
- avs_library.name = dlsym(avs_library.library, #name); \
+ avs_library.name = (name ## _func) \
+ dlsym(avs_library.library, #name); \
if (!continue_on_fail && !avs_library.name) \
goto fail;
LOAD_AVS_FUNC(avs_get_version, 0);
LOAD_AVS_FUNC(avs_get_video_info, 0);
LOAD_AVS_FUNC(avs_invoke, 0);
+ LOAD_AVS_FUNC(avs_is_color_space, 1);
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);
-#ifdef USING_AVISYNTH
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_row_size_p, 1);
LOAD_AVS_FUNC(avs_is_planar_rgb, 1);
LOAD_AVS_FUNC(avs_is_planar_rgba, 1);
-#endif
#undef LOAD_AVS_FUNC
atexit(avisynth_atexit_handler);
st->nb_frames = avs->vi->num_frames;
avpriv_set_pts_info(st, 32, avs->vi->fps_denominator, avs->vi->fps_numerator);
+ av_log(s, AV_LOG_TRACE, "avs_is_field_based: %d\n", avs_is_field_based(avs->vi));
+ av_log(s, AV_LOG_TRACE, "avs_is_parity_known: %d\n", avs_is_parity_known(avs->vi));
+
+ /* The following typically only works when assumetff (-bff) and
+ * assumefieldbased is used in-script. Additional
+ * logic using GetParity() could deliver more accurate results
+ * but also decodes a frame which we want to avoid. */
+ st->codecpar->field_order = AV_FIELD_UNKNOWN;
+ if (avs_is_field_based(avs->vi)) {
+ 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;
+ }
+ }
+
switch (avs->vi->pixel_type) {
-#ifdef USING_AVISYNTH
/* 10~16-bit YUV pix_fmts (AviSynth+) */
case AVS_CS_YUV444P10:
st->codecpar->format = AV_PIX_FMT_YUV444P10;
st->codecpar->format = AV_PIX_FMT_YUVA420P10;
planar = 4;
break;
+ case AVS_CS_YUVA422P12:
+ st->codecpar->format = AV_PIX_FMT_YUVA422P12;
+ planar = 4;
+ break;
case AVS_CS_YUVA444P16:
st->codecpar->format = AV_PIX_FMT_YUVA444P16;
planar = 4;
st->codecpar->format = AV_PIX_FMT_GBRP16;
planar = 3;
break;
+ /* Single precision floating point Planar RGB (AviSynth+) */
+ case AVS_CS_RGBPS:
+ st->codecpar->format = AV_PIX_FMT_GBRPF32;
+ planar = 3;
+ break;
/* Planar RGB pix_fmts with Alpha (AviSynth+) */
case AVS_CS_RGBAP:
st->codecpar->format = AV_PIX_FMT_GBRAP;
st->codecpar->format = AV_PIX_FMT_GBRAP16;
planar = 5;
break;
- /* GRAY16 (AviSynth+) */
+ /* 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;
case AVS_CS_Y16:
st->codecpar->format = AV_PIX_FMT_GRAY16;
planar = 2;
break;
+ /* Single precision floating point gray (AviSynth+) */
+ case AVS_CS_Y32:
+ st->codecpar->format = AV_PIX_FMT_GRAYF32;
+ planar = 2;
+ break;
/* pix_fmts added in AviSynth 2.6 */
case AVS_CS_YV24:
st->codecpar->format = AV_PIX_FMT_YUV444P;
case AVS_CS_BGR64:
st->codecpar->format = AV_PIX_FMT_BGRA64;
break;
-#endif
- /* AviSynth 2.5 and AvxSynth pix_fmts */
+ /* AviSynth 2.5 pix_fmts */
case AVS_CS_BGR24:
st->codecpar->format = AV_PIX_FMT_BGR24;
break;
}
switch (planar) {
-#ifdef USING_AVISYNTH
case 5: // Planar RGB + Alpha
avs->n_planes = 4;
avs->planes = avs_planes_rgba;
avs->n_planes = 3;
avs->planes = avs_planes_rgb;
break;
-#endif
case 2: // Y8
avs->n_planes = 1;
avs->planes = avs_planes_grey;
st->codecpar->codec_id = AV_CODEC_ID_PCM_U8;
break;
case AVS_SAMPLE_INT16:
- st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE;
+ st->codecpar->codec_id = PCM(S16);
break;
case AVS_SAMPLE_INT24:
- st->codecpar->codec_id = AV_CODEC_ID_PCM_S24LE;
+ st->codecpar->codec_id = PCM(S24);
break;
case AVS_SAMPLE_INT32:
- st->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE;
+ st->codecpar->codec_id = PCM(S32);
break;
case AVS_SAMPLE_FLOAT:
- st->codecpar->codec_id = AV_CODEC_ID_PCM_F32LE;
+ st->codecpar->codec_id = PCM(F32);
break;
default:
av_log(s, AV_LOG_ERROR,
AviSynthContext *avs = s->priv_data;
AVS_Value arg, val;
int ret;
-#ifdef USING_AVISYNTH
+#ifdef _WIN32
char filename_ansi[MAX_PATH * 4];
wchar_t filename_wc[MAX_PATH * 4];
#endif
if (ret = avisynth_context_create(s))
return ret;
-#ifdef USING_AVISYNTH
+#ifdef _WIN32
/* Convert UTF-8 to ANSI code page */
- MultiByteToWideChar(CP_UTF8, 0, s->filename, -1, filename_wc, MAX_PATH * 4);
+ MultiByteToWideChar(CP_UTF8, 0, s->url, -1, filename_wc, MAX_PATH * 4);
WideCharToMultiByte(CP_THREAD_ACP, 0, filename_wc, -1, filename_ansi,
MAX_PATH * 4, NULL, NULL);
arg = avs_new_value_string(filename_ansi);
#else
- arg = avs_new_value_string(s->filename);
+ arg = avs_new_value_string(s->url);
#endif
val = avs_library.avs_invoke(avs->env, "Import", arg, 0);
if (avs_is_error(val)) {
avs->clip = avs_library.avs_take_clip(val, avs->env);
avs->vi = avs_library.avs_get_video_info(avs->clip);
-#ifdef USING_AVISYNTH
/* On Windows, FFmpeg supports AviSynth interface version 6 or higher.
* This includes AviSynth 2.6 RC1 or higher, and AviSynth+ r1718 or higher,
- * and excludes 2.5 and the 2.6 alphas. Since AvxSynth identifies itself
- * as interface version 3 like 2.5.8, this needs to be special-cased. */
+ * and excludes 2.5 and the 2.6 alphas. */
if (avs_library.avs_get_version(avs->clip) < 6) {
av_log(s, AV_LOG_ERROR,
ret = AVERROR_UNKNOWN;
goto fail;
}
-#endif
/* Release the AVS_Value as it will go out of scope. */
avs_library.avs_release_value(val);
AVS_VideoFrame *frame;
unsigned char *dst_p;
const unsigned char *src_p;
- int n, i, plane, rowsize, planeheight, pitch, bits;
+ int n, i, plane, rowsize, planeheight, pitch, bits, ret;
const char *error;
- int avsplus av_unused;
if (avs->curr_frame >= avs->vi->num_frames)
return AVERROR_EOF;
if (discard)
return 0;
-#ifdef USING_AVISYNTH
- /* Detect whether we're using AviSynth 2.6 or AviSynth+ by
- * looking for whether avs_is_planar_rgb exists. */
- if (GetProcAddress(avs_library.library, "avs_is_planar_rgb") == NULL)
- avsplus = 0;
- else
- avsplus = 1;
-
- /* avs_bits_per_pixel changed to AVSC_API with AviSynth 2.6, which
- * requires going through avs_library, while AvxSynth has it under
- * the older AVSC_INLINE type, so special-case this. */
-
bits = avs_library.avs_bits_per_pixel(avs->vi);
-#else
- bits = avs_bits_per_pixel(avs->vi);
-#endif
/* Without the cast to int64_t, calculation overflows at about 9k x 9k
* resolution. */
if (!pkt->size)
return AVERROR_UNKNOWN;
- if (av_new_packet(pkt, pkt->size) < 0)
- return AVERROR(ENOMEM);
+ if ((ret = av_new_packet(pkt, pkt->size)) < 0)
+ return ret;
pkt->pts = n;
pkt->dts = n;
dst_p = pkt->data;
for (i = 0; i < avs->n_planes; i++) {
plane = avs->planes[i];
-#ifdef USING_AVISYNTH
src_p = avs_library.avs_get_read_ptr_p(frame, plane);
pitch = avs_library.avs_get_pitch_p(frame, plane);
rowsize = avs_library.avs_get_row_size_p(frame, plane);
planeheight = avs_library.avs_get_height_p(frame, plane);
-#else
- src_p = avs_get_read_ptr_p(frame, plane);
- pitch = avs_get_pitch_p(frame, plane);
-
- rowsize = avs_get_row_size_p(frame, plane);
- planeheight = avs_get_height_p(frame, plane);
-#endif
/* Flip RGB video. */
- if (avs_is_rgb24(avs->vi) || avs_is_rgb(avs->vi)) {
+ if (avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR) ||
+ avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR48) ||
+ avs_library.avs_is_color_space(avs->vi, AVS_CS_BGR64)) {
src_p = src_p + (planeheight - 1) * pitch;
pitch = -pitch;
}
-#ifdef USING_AVISYNTH
- /* Flip Planar RGB video */
- if (avsplus && (avs_library.avs_is_planar_rgb(avs->vi) ||
- avs_library.avs_is_planar_rgba(avs->vi))) {
- src_p = src_p + (planeheight - 1) * pitch;
- pitch = -pitch;
- }
-#endif
-
avs_library.avs_bit_blt(avs->env, dst_p, rowsize, src_p, pitch,
rowsize, planeheight);
dst_p += rowsize * planeheight;
{
AviSynthContext *avs = s->priv_data;
AVRational fps, samplerate;
- int samples;
+ int samples, ret;
int64_t n;
const char *error;
if (!pkt->size)
return AVERROR_UNKNOWN;
- if (av_new_packet(pkt, pkt->size) < 0)
- return AVERROR(ENOMEM);
+ if ((ret = av_new_packet(pkt, pkt->size)) < 0)
+ return ret;
pkt->pts = n;
pkt->dts = n;
return 0;
}
-AVInputFormat ff_avisynth_demuxer = {
+const AVInputFormat ff_avisynth_demuxer = {
.name = "avisynth",
.long_name = NULL_IF_CONFIG_SMALL("AviSynth script"),
.priv_data_size = sizeof(AviSynthContext),