From patchwork Fri Apr 27 19:37:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wm4 X-Patchwork-Id: 8672 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:155:0:0:0:0:0 with SMTP id c82-v6csp1003956jad; Fri, 27 Apr 2018 12:43:50 -0700 (PDT) X-Google-Smtp-Source: AB8JxZo2UYyapx/5clduhd59es2cLQpSqbhfKTGwH33+gXuY+IgXWPZzslTBntndbX38zxp4atDZ X-Received: by 2002:adf:b352:: with SMTP id k18-v6mr2636083wrd.95.1524858230055; Fri, 27 Apr 2018 12:43:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524858230; cv=none; d=google.com; s=arc-20160816; b=IjoiD6jdpmap4G/BkiPyWO6oqjcwgHEyUAYqs/injwX+eEKWo4k4wcPqK2os8n82Lm WE22R6fTZFGDwV2ImHJCNDqX94q9S9ifSNAZIj8wtc71/utaJ7NneQNRTfMf+LseQG+Z Rg7FAdSoCPHiofaCvvAlXEX1MULiyET+mzOEZhxLcYbYBhmulm2Hb8V5owr3/DGO5x/w eQGvOcWwr79nBc6vJTDYVi93aYEZ9tQjNCv/C1UARK2ZQE74LZP0JvGqKvK6LzJ1n0Qt XtqlVFJACOYabGRzmBi4OvNmIRsDuyNrQeKYaKmgM9A04MCYuXkQT81HGIyCpKgK/3DV 6slw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:message-id:date:to:from:dkim-signature :delivered-to:arc-authentication-results; bh=3lmJDTmj3om8FCC+RsE69OVGT77Qex2ml5ytjvlLaOw=; b=UVk7cTriE2BjoCjMg8bQhxTHXpLFtkuy3adCnqwVdqW43JZyr+sykkvNtslnR56B+w ZxOPb7k6pr+QPR8RTb0AbwF11Z0EuMPdfKyjaeXuHzPh0AA0dpP6wZ0pfc6/StkeGhLE WjuicHUODuzI3otMp8ZvBRquQpiL2rWTT0AEt5DE5RlMSRHak9XK9hYj+9ABo/VIx6Yx qAkeAn5/qACE5TpSIXHpckOrWd/SPggbJ1QxC/NV3RyLPYn5v32KMwwU0PwA71WFeTCc ZjN5ImMUx2MqDiqbDodCy20txpDNmxykCXDBxUO7ns5YZSVCnCxAegUHRqu2rNGcV0ZS bRtQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@googlemail.com header.s=20161025 header.b=LPq1X0Qx; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id r78-v6si1678802wrb.332.2018.04.27.12.43.48; Fri, 27 Apr 2018 12:43:50 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@googlemail.com header.s=20161025 header.b=LPq1X0Qx; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=googlemail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 494C468A609; Fri, 27 Apr 2018 22:43:16 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr0-f195.google.com (mail-wr0-f195.google.com [209.85.128.195]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0446D68A583 for ; Fri, 27 Apr 2018 22:43:10 +0300 (EEST) Received: by mail-wr0-f195.google.com with SMTP id u18-v6so2776882wrg.3 for ; Fri, 27 Apr 2018 12:43:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=XarzlUp/fTaAxnGKWFTpRWqK5z3cLG2DMY+HpVxPvvQ=; b=LPq1X0QxjfAmccQOdwxfme5ja7NXlFk3nIpDevIofAoMrJf8SXSroI/0utdoJHjcxT dguioO3hAmqoTHcgCJwALhaWDOt1n2bxCN4mre1j3sMW2jQftIgCs5Z0FjiXg3rgg+8J M/uYehaOe6o6ubbCW63wU5LubSRgqwtGUymnZogA3Sin9EDu5Fdsgs60cYZfHlTqRQel /wI8ulSOlQGCb0JdnCJe0SAe7wF115JtzCe4RiKUQH+aFt2i7gx+61uDfHWQWEcJQ3F9 SLxxYKfmUUgKc2hzofjLjnwuxo1sKSyECl+rGOH5iSWf8UcK40IvcmUU4Mf9/XoqWfIb O2SA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=XarzlUp/fTaAxnGKWFTpRWqK5z3cLG2DMY+HpVxPvvQ=; b=mTN6kcJS64d3COingv3Y9gxR0MiMoomMzNunWySkxOOfMFEtxvXIPve5w/lTdv5M2M x4Mnb9/FCxFUt7HlpBEzvXh5MpvmtPoK/Bmv0UklNjMkHAVDj50mg7MtINpNgPfJI6MY hImdfDzGKW2KBPz57QYwc1TXC0cAHdpU6f8VujRbGwx348lqV8GEh3RreIdPEzlSFt1p U51mODpiz6uTZ6cEJE4o1AAyjPwT8PU8aMJ/K7lF62KwX+JjhjEp/vroCiqAJUzrrT+1 Xn6NKRBhu7xUAECGKrZ6wJ2XsfHhay5NNlgkReL/cXbi80brZUsAIO+mNIAzJb+8zYsD +Yzw== X-Gm-Message-State: ALQs6tAJqwGdvO25LxGb5jnrz6iCHfszKVNhm/zBwVVF7FjPL7DkHmmo C01wgOxjM9BNC0oA9uPoTj7vgw== X-Received: by 2002:adf:af65:: with SMTP id z92-v6mr2728040wrc.250.1524857828704; Fri, 27 Apr 2018 12:37:08 -0700 (PDT) Received: from debian.speedport.ip (p2003006CCD400535589914C4CEE55446.dip0.t-ipconnect.de. [2003:6c:cd40:535:5899:14c4:cee5:5446]) by smtp.googlemail.com with ESMTPSA id v5sm1681081wmh.19.2018.04.27.12.37.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 27 Apr 2018 12:37:07 -0700 (PDT) From: wm4 X-Google-Original-From: wm4 X-Mailer: git-send-email 2.16.1 Subject: [FFmpeg-devel] [PATCH] avformat: add vapoursynth wrapper X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: wm4 MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: wm4 This can "demux" .vpy files. Some minor code copied from other LGPL parts of FFmpeg. Possibly support VS compat pixel formats. TODO: - check whether VS can change format midstream - test vfr mode, return proper timestamps when using it - drop "lib" prefix? --- configure | 4 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/libvapoursynth.c | 379 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 385 insertions(+) create mode 100644 libavformat/libvapoursynth.c diff --git a/configure b/configure index 9fa1665496..17e46c5daa 100755 --- a/configure +++ b/configure @@ -265,6 +265,7 @@ External library support: if openssl or gnutls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] + --enable-libvapoursynth enable VapourSynth demuxer [no] --enable-libvidstab enable video stabilization using vid.stab [no] --enable-libvmaf enable vmaf filter via libvmaf [no] --enable-libvo-amrwbenc enable AMR-WB encoding via libvo-amrwbenc [no] @@ -1712,6 +1713,7 @@ EXTERNAL_LIBRARY_LIST=" libtheora libtwolame libv4l2 + libvapoursynth libvorbis libvpx libwavpack @@ -3068,6 +3070,7 @@ libspeex_encoder_deps="libspeex" libspeex_encoder_select="audio_frame_queue" libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" +libvapoursynth_demuxer_deps="libvapoursynth" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" libvorbis_decoder_deps="libvorbis" libvorbis_encoder_deps="libvorbis libvorbisenc" @@ -6041,6 +6044,7 @@ enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl +enabled libvapoursynth && require_pkg_config libvapoursynth "vapoursynth >= 42" VapourSynth.h getVapourSynthAPI && require_pkg_config libvapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init || die "ERROR: vapoursynth or vsscript not found"; enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 0.6.2" libvmaf.h compute_vmaf enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc diff --git a/libavformat/Makefile b/libavformat/Makefile index 3eeca5091d..731b7ac714 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -570,6 +570,7 @@ OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o +OBJS-$(CONFIG_LIBVAPOURSYNTH_DEMUXER) += libvapoursynth.o # protocols I/O OBJS-$(CONFIG_ASYNC_PROTOCOL) += async.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d582778b3b..67f6c4339c 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -482,6 +482,7 @@ extern AVOutputFormat ff_chromaprint_muxer; extern AVInputFormat ff_libgme_demuxer; extern AVInputFormat ff_libmodplug_demuxer; extern AVInputFormat ff_libopenmpt_demuxer; +extern AVInputFormat ff_libvapoursynth_demuxer; #include "libavformat/muxer_list.c" #include "libavformat/demuxer_list.c" diff --git a/libavformat/libvapoursynth.c b/libavformat/libvapoursynth.c new file mode 100644 index 0000000000..95699e81d2 --- /dev/null +++ b/libavformat/libvapoursynth.c @@ -0,0 +1,379 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file +* VapourSynth demuxer +* +* Synthesizes vapour (?) +*/ + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/eval.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avformat.h" +#include "internal.h" + +typedef struct VSContext { + const AVClass *class; + + const VSAPI *vsapi; + VSCore *vscore; + VSScript *vss; + + VSNodeRef *outnode; + int is_cfr; + int current_frame; + + int c_order[4]; + + /* options */ + int64_t max_size; +} VSContext; + +#define OFFSET(x) offsetof(VSContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + {"max_size", "set max file size supported (in bytes)", OFFSET(max_size), AV_OPT_TYPE_INT64, {.i64 = 1 * 1024 * 1024}, 0, SIZE_MAX - 1, A|D}, + {NULL} +}; + +static int read_close_vs(AVFormatContext *s) +{ + VSContext *vs = s->priv_data; + + if (vs->outnode) + vs->vsapi->freeNode(vs->outnode); + + vsscript_freeScript(vs->vss); + vs->vss = NULL; + vs->vsapi = NULL; + vs->vscore = NULL; + vs->outnode = NULL; + + vsscript_finalize(); + + return 0; +} + +static int is_native_endian(enum AVPixelFormat pixfmt) +{ + enum AVPixelFormat other = av_pix_fmt_swap_endianness(pixfmt); + const AVPixFmtDescriptor *pd; + if (other == AV_PIX_FMT_NONE || other == pixfmt) + return 1; // not affected by byte order + pd = av_pix_fmt_desc_get(pixfmt); + return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); +} + +static enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) +{ + static const int yuv_order[4] = {0, 1, 2, 0}; + static const int rgb_order[4] = {1, 2, 0, 0}; + const AVPixFmtDescriptor *pd; + + for (pd = av_pix_fmt_desc_next(NULL); pd; pd = av_pix_fmt_desc_next(pd)) { + int is_rgb, is_yuv, i, *order; + enum AVPixelFormat pixfmt; + + pixfmt = av_pix_fmt_desc_get_id(pd); + + if (pd->flags & (AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM)) + continue; + + if (pd->log2_chroma_w != vsf->subSamplingW || + pd->log2_chroma_h != vsf->subSamplingH) + continue; + + is_rgb = vsf->colorFamily == cmRGB; + if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) + continue; + + is_yuv = vsf->colorFamily == cmYUV || + vsf->colorFamily == cmYCoCg || + vsf->colorFamily == cmGray; + if (!is_rgb && !is_yuv) + continue; + + if (vsf->sampleType != ((pd->flags & AV_PIX_FMT_FLAG_FLOAT) ? stFloat : stInteger)) + continue; + + if (av_pix_fmt_count_planes(pixfmt) != vsf->numPlanes) + continue; + + if (strncmp(pd->name, "xyz", 3) == 0) + continue; + + if (!is_native_endian(pixfmt)) + continue; + + order = is_yuv ? yuv_order : rgb_order; + + for (i = 0; i < pd->nb_components; i++) { + const AVComponentDescriptor *c = &pd->comp[i]; + if (order[c->plane] != i || + c->offset != 0 || c->shift != 0 || + c->step != vsf->bytesPerSample || + c->depth != vsf->bitsPerSample) + goto cont; + } + + // Use it. + memcpy(c_order, order, sizeof(int[4])); + return pixfmt; + + cont: ; + } + + return AV_PIX_FMT_NONE; +} + +static int read_header_vs(AVFormatContext *s) +{ + AVStream *st; + AVIOContext *pb = s->pb; + VSContext *vs = s->priv_data; + int64_t sz = avio_size(pb); + char *buf = NULL; + char dummy; + const VSVideoInfo *info; + int err; + + vsscript_init(); + + if (sz < 0 || sz > vs->max_size) { + if (sz < 0) + av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); + sz = vs->max_size; + } + + buf = av_malloc(sz + 1); + if (!buf) { + err = AVERROR(ENOMEM); + goto done; + } + sz = avio_read(pb, buf, sz); + + if (sz < 0) { + av_log(s, AV_LOG_ERROR, "Could not read script.\n"); + err = sz; + goto done; + } + + // Data left means our buffer (the max_size option) is too small + if (avio_read(pb, &dummy, 1) == 1) { + av_log(s, AV_LOG_ERROR, "File size is larger than max_size option " + "value %"PRIi64", consider increasing the max_size option\n", + vs->max_size); + err = AVERROR_BUFFER_TOO_SMALL; + goto done; + } + + if (vsscript_createScript(&vs->vss)) { + av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + buf[sz] = '\0'; + if (vsscript_evaluateScript(&vs->vss, buf, s->url, 0)) { + const char *msg = vsscript_getError(vs->vss); + av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); + err = AVERROR_EXTERNAL; + goto done; + } + + vs->vsapi = vsscript_getVSApi(); + vs->vscore = vsscript_getCore(vs->vss); + + vs->outnode = vsscript_getOutput(vs->vss, 0); + if (!vs->outnode) { + av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + st = avformat_new_stream(s, NULL); + if (!st) { + err = AVERROR(ENOMEM); + goto done; + } + + info = vs->vsapi->getVideoInfo(vs->outnode); + + if (info->fpsDen) { + vs->is_cfr = 1; + avpriv_set_pts_info(st, 64, info->fpsDen, info->fpsNum); + st->duration = info->numFrames; + } else { + // VFR. Just set "something". + avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE); + s->ctx_flags |= AVFMTCTX_UNSEEKABLE; + } + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; + st->codecpar->width = info->width; + st->codecpar->height = info->height; + st->codecpar->format = match_pixfmt(info->format, vs->c_order); + + if (st->codecpar->format == AV_PIX_FMT_NONE) { + av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name); + err = AVERROR_EXTERNAL; + goto done; + } + av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name, + av_get_pix_fmt_name(st->codecpar->format)); + + if (info->format->colorFamily == cmYCoCg) + st->codecpar->color_space = AVCOL_SPC_YCGCO; + +done: + av_free(buf); + if (err < 0) + read_close_vs(s); + return err; +} + +static void free_frame(void *opaque, uint8_t *data) +{ + AVFrame *frame = (AVFrame *)data; + + av_frame_free(&frame); +} + +static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) +{ + VSContext *vs = s->priv_data; + AVStream *st = s->streams[0]; + AVFrame *frame = NULL; + char vserr[80]; + const VSFrameRef *vsframe = NULL; + const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode); + int err = 0; + const uint8_t *src_data[4]; + int src_linesizes[4]; + int i; + + if (vs->current_frame >= info->numFrames) + return AVERROR_EOF; + + vsframe = vs->vsapi->getFrame(vs->current_frame, vs->outnode, vserr, sizeof(vserr)); + if (!vsframe) { + av_log(s, AV_LOG_ERROR, "Error getting frame: %s\n", vserr); + err = AVERROR_EXTERNAL; + goto end; + } + + frame = av_frame_alloc(); + if (!frame) { + err = AVERROR(ENOMEM); + goto end; + } + + frame->format = st->codecpar->format; + frame->width = st->codecpar->width; + frame->height = st->codecpar->height; + frame->colorspace = st->codecpar->color_space; + + av_assert0(vs->vsapi->getFrameWidth(vsframe, 0) == frame->width); + av_assert0(vs->vsapi->getFrameHeight(vsframe, 0) == frame->height); + + err = av_frame_get_buffer(frame, 0); + if (err < 0) + goto end; + + for (i = 0; i < info->format->numPlanes; i++) { + int p = vs->c_order[i]; + src_data[i] = vs->vsapi->getReadPtr(vsframe, p); + src_linesizes[i] = vs->vsapi->getStride(vsframe, p); + } + + av_image_copy(frame->data, frame->linesize, src_data, src_linesizes, + frame->format, frame->width, frame->height); + + pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame), + free_frame, NULL, 0); + if (!pkt->buf) { + err = AVERROR(ENOMEM); + goto end; + } + + frame = NULL; // pkt owns it now + + pkt->data = pkt->buf->data; + pkt->size = pkt->buf->size; + pkt->flags |= AV_PKT_FLAG_TRUSTED; + + if (vs->is_cfr) + pkt->pts = vs->current_frame; + + vs->current_frame++; + +end: + if (err < 0) + av_packet_unref(pkt); + av_frame_free(&frame); + vs->vsapi->freeFrame(vsframe); + return err; +} + +static int read_seek_vs(AVFormatContext *s, int stream_idx, int64_t ts, int flags) +{ + VSContext *vs = s->priv_data; + + if (!vs->is_cfr) + return AVERROR(ENOSYS); + + vs->current_frame = FFMIN(FFMAX(0, ts), s->streams[0]->duration); + return 0; +} + +static int probe_vs(AVProbeData *p) +{ + // Explicitly do not support this. VS scripts are written in Python, and + // can run arbitrary code on the user's system. + return 0; +} + +static const AVClass class_vs = { + .class_name = "VapourSynth demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_libvapoursynth_demuxer = { + .name = "libvapoursynth", + .long_name = NULL_IF_CONFIG_SMALL("VapourSynth demuxer"), + .priv_data_size = sizeof(VSContext), + .read_probe = probe_vs, + .read_header = read_header_vs, + .read_packet = read_packet_vs, + .read_close = read_close_vs, + .read_seek = read_seek_vs, + .priv_class = &class_vs, +};