1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci/**
20cabdff1aSopenharmony_ci* @file
21cabdff1aSopenharmony_ci* VapourSynth demuxer
22cabdff1aSopenharmony_ci*
23cabdff1aSopenharmony_ci* Synthesizes vapour (?)
24cabdff1aSopenharmony_ci*/
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include <limits.h>
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#include <VapourSynth.h>
29cabdff1aSopenharmony_ci#include <VSScript.h>
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
32cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
33cabdff1aSopenharmony_ci#include "libavutil/eval.h"
34cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
35cabdff1aSopenharmony_ci#include "libavutil/opt.h"
36cabdff1aSopenharmony_ci#include "libavutil/pixdesc.h"
37cabdff1aSopenharmony_ci#include "avformat.h"
38cabdff1aSopenharmony_ci#include "internal.h"
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistruct VSState {
41cabdff1aSopenharmony_ci    VSScript *vss;
42cabdff1aSopenharmony_ci};
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_citypedef struct VSContext {
45cabdff1aSopenharmony_ci    const AVClass *class;
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    AVBufferRef *vss_state;
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_ci    const VSAPI *vsapi;
50cabdff1aSopenharmony_ci    VSCore *vscore;
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_ci    VSNodeRef *outnode;
53cabdff1aSopenharmony_ci    int is_cfr;
54cabdff1aSopenharmony_ci    int current_frame;
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci    int c_order[4];
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    /* options */
59cabdff1aSopenharmony_ci    int64_t max_script_size;
60cabdff1aSopenharmony_ci} VSContext;
61cabdff1aSopenharmony_ci
62cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(VSContext, x)
63cabdff1aSopenharmony_ci#define A AV_OPT_FLAG_AUDIO_PARAM
64cabdff1aSopenharmony_ci#define D AV_OPT_FLAG_DECODING_PARAM
65cabdff1aSopenharmony_cistatic const AVOption options[] = {
66cabdff1aSopenharmony_ci    {"max_script_size",    "set max file size supported (in bytes)", OFFSET(max_script_size),    AV_OPT_TYPE_INT64, {.i64 = 1 * 1024 * 1024}, 0,    SIZE_MAX - 1, A|D},
67cabdff1aSopenharmony_ci    {NULL}
68cabdff1aSopenharmony_ci};
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_cistatic void free_vss_state(void *opaque, uint8_t *data)
71cabdff1aSopenharmony_ci{
72cabdff1aSopenharmony_ci    struct VSState *vss = opaque;
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_ci    if (vss->vss) {
75cabdff1aSopenharmony_ci        vsscript_freeScript(vss->vss);
76cabdff1aSopenharmony_ci        vsscript_finalize();
77cabdff1aSopenharmony_ci    }
78cabdff1aSopenharmony_ci}
79cabdff1aSopenharmony_ci
80cabdff1aSopenharmony_cistatic av_cold int read_close_vs(AVFormatContext *s)
81cabdff1aSopenharmony_ci{
82cabdff1aSopenharmony_ci    VSContext *vs = s->priv_data;
83cabdff1aSopenharmony_ci
84cabdff1aSopenharmony_ci    if (vs->outnode)
85cabdff1aSopenharmony_ci        vs->vsapi->freeNode(vs->outnode);
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_ci    av_buffer_unref(&vs->vss_state);
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci    vs->vsapi = NULL;
90cabdff1aSopenharmony_ci    vs->vscore = NULL;
91cabdff1aSopenharmony_ci    vs->outnode = NULL;
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_ci    return 0;
94cabdff1aSopenharmony_ci}
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_cistatic av_cold int is_native_endian(enum AVPixelFormat pixfmt)
97cabdff1aSopenharmony_ci{
98cabdff1aSopenharmony_ci    enum AVPixelFormat other = av_pix_fmt_swap_endianness(pixfmt);
99cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *pd;
100cabdff1aSopenharmony_ci    if (other == AV_PIX_FMT_NONE || other == pixfmt)
101cabdff1aSopenharmony_ci        return 1; // not affected by byte order
102cabdff1aSopenharmony_ci    pd = av_pix_fmt_desc_get(pixfmt);
103cabdff1aSopenharmony_ci    return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE));
104cabdff1aSopenharmony_ci}
105cabdff1aSopenharmony_ci
106cabdff1aSopenharmony_cistatic av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4])
107cabdff1aSopenharmony_ci{
108cabdff1aSopenharmony_ci    static const int yuv_order[4] = {0, 1, 2, 0};
109cabdff1aSopenharmony_ci    static const int rgb_order[4] = {1, 2, 0, 0};
110cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *pd;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci    for (pd = av_pix_fmt_desc_next(NULL); pd; pd = av_pix_fmt_desc_next(pd)) {
113cabdff1aSopenharmony_ci        int is_rgb, is_yuv, i;
114cabdff1aSopenharmony_ci        const int *order;
115cabdff1aSopenharmony_ci        enum AVPixelFormat pixfmt;
116cabdff1aSopenharmony_ci
117cabdff1aSopenharmony_ci        pixfmt = av_pix_fmt_desc_get_id(pd);
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci        if (pd->flags & (AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_ALPHA |
120cabdff1aSopenharmony_ci                         AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM))
121cabdff1aSopenharmony_ci            continue;
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci        if (pd->log2_chroma_w != vsf->subSamplingW ||
124cabdff1aSopenharmony_ci            pd->log2_chroma_h != vsf->subSamplingH)
125cabdff1aSopenharmony_ci            continue;
126cabdff1aSopenharmony_ci
127cabdff1aSopenharmony_ci        is_rgb = vsf->colorFamily == cmRGB;
128cabdff1aSopenharmony_ci        if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB))
129cabdff1aSopenharmony_ci            continue;
130cabdff1aSopenharmony_ci
131cabdff1aSopenharmony_ci        is_yuv = vsf->colorFamily == cmYUV ||
132cabdff1aSopenharmony_ci                 vsf->colorFamily == cmYCoCg ||
133cabdff1aSopenharmony_ci                 vsf->colorFamily == cmGray;
134cabdff1aSopenharmony_ci        if (!is_rgb && !is_yuv)
135cabdff1aSopenharmony_ci            continue;
136cabdff1aSopenharmony_ci
137cabdff1aSopenharmony_ci        if (vsf->sampleType != ((pd->flags & AV_PIX_FMT_FLAG_FLOAT) ? stFloat : stInteger))
138cabdff1aSopenharmony_ci            continue;
139cabdff1aSopenharmony_ci
140cabdff1aSopenharmony_ci        if (av_pix_fmt_count_planes(pixfmt) != vsf->numPlanes)
141cabdff1aSopenharmony_ci            continue;
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_ci        if (strncmp(pd->name, "xyz", 3) == 0)
144cabdff1aSopenharmony_ci            continue;
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci        if (!is_native_endian(pixfmt))
147cabdff1aSopenharmony_ci            continue;
148cabdff1aSopenharmony_ci
149cabdff1aSopenharmony_ci        order = is_yuv ? yuv_order : rgb_order;
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_ci        for (i = 0; i < pd->nb_components; i++) {
152cabdff1aSopenharmony_ci            const AVComponentDescriptor *c = &pd->comp[i];
153cabdff1aSopenharmony_ci            if (order[c->plane] != i ||
154cabdff1aSopenharmony_ci                c->offset != 0 || c->shift != 0 ||
155cabdff1aSopenharmony_ci                c->step != vsf->bytesPerSample ||
156cabdff1aSopenharmony_ci                c->depth != vsf->bitsPerSample)
157cabdff1aSopenharmony_ci                goto cont;
158cabdff1aSopenharmony_ci        }
159cabdff1aSopenharmony_ci
160cabdff1aSopenharmony_ci        // Use it.
161cabdff1aSopenharmony_ci        memcpy(c_order, order, sizeof(int[4]));
162cabdff1aSopenharmony_ci        return pixfmt;
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    cont: ;
165cabdff1aSopenharmony_ci    }
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    return AV_PIX_FMT_NONE;
168cabdff1aSopenharmony_ci}
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_cistatic av_cold int read_header_vs(AVFormatContext *s)
171cabdff1aSopenharmony_ci{
172cabdff1aSopenharmony_ci    AVStream *st;
173cabdff1aSopenharmony_ci    AVIOContext *pb = s->pb;
174cabdff1aSopenharmony_ci    VSContext *vs = s->priv_data;
175cabdff1aSopenharmony_ci    int64_t sz = avio_size(pb);
176cabdff1aSopenharmony_ci    char *buf = NULL;
177cabdff1aSopenharmony_ci    char dummy;
178cabdff1aSopenharmony_ci    const VSVideoInfo *info;
179cabdff1aSopenharmony_ci    struct VSState *vss_state;
180cabdff1aSopenharmony_ci    int err = 0;
181cabdff1aSopenharmony_ci
182cabdff1aSopenharmony_ci    vss_state = av_mallocz(sizeof(*vss_state));
183cabdff1aSopenharmony_ci    if (!vss_state) {
184cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
185cabdff1aSopenharmony_ci        goto done;
186cabdff1aSopenharmony_ci    }
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_ci    vs->vss_state = av_buffer_create(NULL, 0, free_vss_state, vss_state, 0);
189cabdff1aSopenharmony_ci    if (!vs->vss_state) {
190cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
191cabdff1aSopenharmony_ci        av_free(vss_state);
192cabdff1aSopenharmony_ci        goto done;
193cabdff1aSopenharmony_ci    }
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_ci    if (!vsscript_init()) {
196cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n");
197cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
198cabdff1aSopenharmony_ci        goto done;
199cabdff1aSopenharmony_ci    }
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_ci    if (vsscript_createScript(&vss_state->vss)) {
202cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n");
203cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
204cabdff1aSopenharmony_ci        vsscript_finalize();
205cabdff1aSopenharmony_ci        goto done;
206cabdff1aSopenharmony_ci    }
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_ci    if (sz < 0 || sz > vs->max_script_size) {
209cabdff1aSopenharmony_ci        if (sz < 0)
210cabdff1aSopenharmony_ci            av_log(s, AV_LOG_WARNING, "Could not determine file size\n");
211cabdff1aSopenharmony_ci        sz = vs->max_script_size;
212cabdff1aSopenharmony_ci    }
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ci    buf = av_malloc(sz + 1);
215cabdff1aSopenharmony_ci    if (!buf) {
216cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
217cabdff1aSopenharmony_ci        goto done;
218cabdff1aSopenharmony_ci    }
219cabdff1aSopenharmony_ci    sz = avio_read(pb, buf, sz);
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    if (sz < 0) {
222cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Could not read script.\n");
223cabdff1aSopenharmony_ci        err = sz;
224cabdff1aSopenharmony_ci        goto done;
225cabdff1aSopenharmony_ci    }
226cabdff1aSopenharmony_ci
227cabdff1aSopenharmony_ci    // Data left means our buffer (the max_script_size option) is too small
228cabdff1aSopenharmony_ci    if (avio_read(pb, &dummy, 1) == 1) {
229cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "File size is larger than max_script_size option "
230cabdff1aSopenharmony_ci               "value %"PRIi64", consider increasing the max_script_size option\n",
231cabdff1aSopenharmony_ci               vs->max_script_size);
232cabdff1aSopenharmony_ci        err = AVERROR_BUFFER_TOO_SMALL;
233cabdff1aSopenharmony_ci        goto done;
234cabdff1aSopenharmony_ci    }
235cabdff1aSopenharmony_ci
236cabdff1aSopenharmony_ci    buf[sz] = '\0';
237cabdff1aSopenharmony_ci    if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) {
238cabdff1aSopenharmony_ci        const char *msg = vsscript_getError(vss_state->vss);
239cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)");
240cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
241cabdff1aSopenharmony_ci        goto done;
242cabdff1aSopenharmony_ci    }
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci    vs->vsapi = vsscript_getVSApi();
245cabdff1aSopenharmony_ci    vs->vscore = vsscript_getCore(vss_state->vss);
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci    vs->outnode = vsscript_getOutput(vss_state->vss, 0);
248cabdff1aSopenharmony_ci    if (!vs->outnode) {
249cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Could not get script output node.\n");
250cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
251cabdff1aSopenharmony_ci        goto done;
252cabdff1aSopenharmony_ci    }
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    st = avformat_new_stream(s, NULL);
255cabdff1aSopenharmony_ci    if (!st) {
256cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
257cabdff1aSopenharmony_ci        goto done;
258cabdff1aSopenharmony_ci    }
259cabdff1aSopenharmony_ci
260cabdff1aSopenharmony_ci    info = vs->vsapi->getVideoInfo(vs->outnode);
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci    if (!info->format || !info->width || !info->height) {
263cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n");
264cabdff1aSopenharmony_ci        err = AVERROR_PATCHWELCOME;
265cabdff1aSopenharmony_ci        goto done;
266cabdff1aSopenharmony_ci    }
267cabdff1aSopenharmony_ci
268cabdff1aSopenharmony_ci    if (info->fpsDen) {
269cabdff1aSopenharmony_ci        vs->is_cfr = 1;
270cabdff1aSopenharmony_ci        avpriv_set_pts_info(st, 64, info->fpsDen, info->fpsNum);
271cabdff1aSopenharmony_ci        st->duration = info->numFrames;
272cabdff1aSopenharmony_ci    } else {
273cabdff1aSopenharmony_ci        // VFR. Just set "something".
274cabdff1aSopenharmony_ci        avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE);
275cabdff1aSopenharmony_ci        s->ctx_flags |= AVFMTCTX_UNSEEKABLE;
276cabdff1aSopenharmony_ci    }
277cabdff1aSopenharmony_ci
278cabdff1aSopenharmony_ci    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
279cabdff1aSopenharmony_ci    st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME;
280cabdff1aSopenharmony_ci    st->codecpar->width = info->width;
281cabdff1aSopenharmony_ci    st->codecpar->height = info->height;
282cabdff1aSopenharmony_ci    st->codecpar->format = match_pixfmt(info->format, vs->c_order);
283cabdff1aSopenharmony_ci
284cabdff1aSopenharmony_ci    if (st->codecpar->format == AV_PIX_FMT_NONE) {
285cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name);
286cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
287cabdff1aSopenharmony_ci        goto done;
288cabdff1aSopenharmony_ci    }
289cabdff1aSopenharmony_ci    av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name,
290cabdff1aSopenharmony_ci           av_get_pix_fmt_name(st->codecpar->format));
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    if (info->format->colorFamily == cmYCoCg)
293cabdff1aSopenharmony_ci        st->codecpar->color_space = AVCOL_SPC_YCGCO;
294cabdff1aSopenharmony_ci
295cabdff1aSopenharmony_cidone:
296cabdff1aSopenharmony_ci    av_free(buf);
297cabdff1aSopenharmony_ci    return err;
298cabdff1aSopenharmony_ci}
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_cistatic void free_frame(void *opaque, uint8_t *data)
301cabdff1aSopenharmony_ci{
302cabdff1aSopenharmony_ci    AVFrame *frame = (AVFrame *)data;
303cabdff1aSopenharmony_ci
304cabdff1aSopenharmony_ci    av_frame_free(&frame);
305cabdff1aSopenharmony_ci}
306cabdff1aSopenharmony_ci
307cabdff1aSopenharmony_cistatic int get_vs_prop_int(AVFormatContext *s, const VSMap *map, const char *name, int def)
308cabdff1aSopenharmony_ci{
309cabdff1aSopenharmony_ci    VSContext *vs = s->priv_data;
310cabdff1aSopenharmony_ci    int64_t res;
311cabdff1aSopenharmony_ci    int err = 1;
312cabdff1aSopenharmony_ci
313cabdff1aSopenharmony_ci    res = vs->vsapi->propGetInt(map, name, 0, &err);
314cabdff1aSopenharmony_ci    return err || res < INT_MIN || res > INT_MAX ? def : res;
315cabdff1aSopenharmony_ci}
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_cistruct vsframe_ref_data {
318cabdff1aSopenharmony_ci    const VSAPI *vsapi;
319cabdff1aSopenharmony_ci    const VSFrameRef *frame;
320cabdff1aSopenharmony_ci    AVBufferRef *vss_state;
321cabdff1aSopenharmony_ci};
322cabdff1aSopenharmony_ci
323cabdff1aSopenharmony_cistatic void free_vsframe_ref(void *opaque, uint8_t *data)
324cabdff1aSopenharmony_ci{
325cabdff1aSopenharmony_ci    struct vsframe_ref_data *d = opaque;
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci    if (d->frame)
328cabdff1aSopenharmony_ci        d->vsapi->freeFrame(d->frame);
329cabdff1aSopenharmony_ci
330cabdff1aSopenharmony_ci    av_buffer_unref(&d->vss_state);
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci    av_free(d);
333cabdff1aSopenharmony_ci}
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_cistatic int read_packet_vs(AVFormatContext *s, AVPacket *pkt)
336cabdff1aSopenharmony_ci{
337cabdff1aSopenharmony_ci    VSContext *vs = s->priv_data;
338cabdff1aSopenharmony_ci    AVStream *st = s->streams[0];
339cabdff1aSopenharmony_ci    AVFrame *frame = NULL;
340cabdff1aSopenharmony_ci    char vserr[80];
341cabdff1aSopenharmony_ci    const VSFrameRef *vsframe;
342cabdff1aSopenharmony_ci    const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode);
343cabdff1aSopenharmony_ci    const VSMap *props;
344cabdff1aSopenharmony_ci    const AVPixFmtDescriptor *desc;
345cabdff1aSopenharmony_ci    AVBufferRef *vsframe_ref = NULL;
346cabdff1aSopenharmony_ci    struct vsframe_ref_data *ref_data;
347cabdff1aSopenharmony_ci    int err = 0;
348cabdff1aSopenharmony_ci    int i;
349cabdff1aSopenharmony_ci
350cabdff1aSopenharmony_ci    if (vs->current_frame >= info->numFrames)
351cabdff1aSopenharmony_ci        return AVERROR_EOF;
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci    ref_data = av_mallocz(sizeof(*ref_data));
354cabdff1aSopenharmony_ci    if (!ref_data) {
355cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
356cabdff1aSopenharmony_ci        goto end;
357cabdff1aSopenharmony_ci    }
358cabdff1aSopenharmony_ci
359cabdff1aSopenharmony_ci    // (the READONLY flag is important because the ref is reused for plane data)
360cabdff1aSopenharmony_ci    vsframe_ref = av_buffer_create(NULL, 0, free_vsframe_ref, ref_data, AV_BUFFER_FLAG_READONLY);
361cabdff1aSopenharmony_ci    if (!vsframe_ref) {
362cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
363cabdff1aSopenharmony_ci        av_free(ref_data);
364cabdff1aSopenharmony_ci        goto end;
365cabdff1aSopenharmony_ci    }
366cabdff1aSopenharmony_ci
367cabdff1aSopenharmony_ci    vsframe = vs->vsapi->getFrame(vs->current_frame, vs->outnode, vserr, sizeof(vserr));
368cabdff1aSopenharmony_ci    if (!vsframe) {
369cabdff1aSopenharmony_ci        av_log(s, AV_LOG_ERROR, "Error getting frame: %s\n", vserr);
370cabdff1aSopenharmony_ci        err = AVERROR_EXTERNAL;
371cabdff1aSopenharmony_ci        goto end;
372cabdff1aSopenharmony_ci    }
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_ci    ref_data->vsapi = vs->vsapi;
375cabdff1aSopenharmony_ci    ref_data->frame = vsframe;
376cabdff1aSopenharmony_ci
377cabdff1aSopenharmony_ci    ref_data->vss_state = av_buffer_ref(vs->vss_state);
378cabdff1aSopenharmony_ci    if (!ref_data->vss_state) {
379cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
380cabdff1aSopenharmony_ci        goto end;
381cabdff1aSopenharmony_ci    }
382cabdff1aSopenharmony_ci
383cabdff1aSopenharmony_ci    props = vs->vsapi->getFramePropsRO(vsframe);
384cabdff1aSopenharmony_ci
385cabdff1aSopenharmony_ci    frame = av_frame_alloc();
386cabdff1aSopenharmony_ci    if (!frame) {
387cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
388cabdff1aSopenharmony_ci        goto end;
389cabdff1aSopenharmony_ci    }
390cabdff1aSopenharmony_ci
391cabdff1aSopenharmony_ci    frame->format       = st->codecpar->format;
392cabdff1aSopenharmony_ci    frame->width        = st->codecpar->width;
393cabdff1aSopenharmony_ci    frame->height       = st->codecpar->height;
394cabdff1aSopenharmony_ci    frame->colorspace   = st->codecpar->color_space;
395cabdff1aSopenharmony_ci
396cabdff1aSopenharmony_ci    // Values according to ISO/IEC 14496-10.
397cabdff1aSopenharmony_ci    frame->colorspace       = get_vs_prop_int(s, props, "_Matrix",      frame->colorspace);
398cabdff1aSopenharmony_ci    frame->color_primaries  = get_vs_prop_int(s, props, "_Primaries",   frame->color_primaries);
399cabdff1aSopenharmony_ci    frame->color_trc        = get_vs_prop_int(s, props, "_Transfer",    frame->color_trc);
400cabdff1aSopenharmony_ci
401cabdff1aSopenharmony_ci    if (get_vs_prop_int(s, props, "_ColorRange", 1) == 0)
402cabdff1aSopenharmony_ci        frame->color_range = AVCOL_RANGE_JPEG;
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci    frame->sample_aspect_ratio.num = get_vs_prop_int(s, props, "_SARNum", 0);
405cabdff1aSopenharmony_ci    frame->sample_aspect_ratio.den = get_vs_prop_int(s, props, "_SARDen", 1);
406cabdff1aSopenharmony_ci
407cabdff1aSopenharmony_ci    av_assert0(vs->vsapi->getFrameWidth(vsframe, 0) == frame->width);
408cabdff1aSopenharmony_ci    av_assert0(vs->vsapi->getFrameHeight(vsframe, 0) == frame->height);
409cabdff1aSopenharmony_ci
410cabdff1aSopenharmony_ci    desc = av_pix_fmt_desc_get(frame->format);
411cabdff1aSopenharmony_ci
412cabdff1aSopenharmony_ci    for (i = 0; i < info->format->numPlanes; i++) {
413cabdff1aSopenharmony_ci        int p = vs->c_order[i];
414cabdff1aSopenharmony_ci        ptrdiff_t plane_h = frame->height;
415cabdff1aSopenharmony_ci
416cabdff1aSopenharmony_ci        frame->data[i] = (void *)vs->vsapi->getReadPtr(vsframe, p);
417cabdff1aSopenharmony_ci        frame->linesize[i] = vs->vsapi->getStride(vsframe, p);
418cabdff1aSopenharmony_ci
419cabdff1aSopenharmony_ci        frame->buf[i] = av_buffer_ref(vsframe_ref);
420cabdff1aSopenharmony_ci        if (!frame->buf[i]) {
421cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
422cabdff1aSopenharmony_ci            goto end;
423cabdff1aSopenharmony_ci        }
424cabdff1aSopenharmony_ci
425cabdff1aSopenharmony_ci        // Each plane needs an AVBufferRef that indicates the correct plane
426cabdff1aSopenharmony_ci        // memory range. VapourSynth doesn't even give us the memory range,
427cabdff1aSopenharmony_ci        // so make up a bad guess to make FFmpeg happy (even if almost nothing
428cabdff1aSopenharmony_ci        // checks the memory range).
429cabdff1aSopenharmony_ci        if (i == 1 || i == 2)
430cabdff1aSopenharmony_ci            plane_h = AV_CEIL_RSHIFT(plane_h, desc->log2_chroma_h);
431cabdff1aSopenharmony_ci        frame->buf[i]->data = frame->data[i];
432cabdff1aSopenharmony_ci        frame->buf[i]->size = frame->linesize[i] * plane_h;
433cabdff1aSopenharmony_ci    }
434cabdff1aSopenharmony_ci
435cabdff1aSopenharmony_ci    pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame),
436cabdff1aSopenharmony_ci                                free_frame, NULL, 0);
437cabdff1aSopenharmony_ci    if (!pkt->buf) {
438cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
439cabdff1aSopenharmony_ci        goto end;
440cabdff1aSopenharmony_ci    }
441cabdff1aSopenharmony_ci
442cabdff1aSopenharmony_ci    frame = NULL; // pkt owns it now
443cabdff1aSopenharmony_ci
444cabdff1aSopenharmony_ci    pkt->data   = pkt->buf->data;
445cabdff1aSopenharmony_ci    pkt->size   = pkt->buf->size;
446cabdff1aSopenharmony_ci    pkt->flags |= AV_PKT_FLAG_TRUSTED;
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci    if (vs->is_cfr)
449cabdff1aSopenharmony_ci        pkt->pts = vs->current_frame;
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci    vs->current_frame++;
452cabdff1aSopenharmony_ci
453cabdff1aSopenharmony_ciend:
454cabdff1aSopenharmony_ci    av_frame_free(&frame);
455cabdff1aSopenharmony_ci    av_buffer_unref(&vsframe_ref);
456cabdff1aSopenharmony_ci    return err;
457cabdff1aSopenharmony_ci}
458cabdff1aSopenharmony_ci
459cabdff1aSopenharmony_cistatic int read_seek_vs(AVFormatContext *s, int stream_idx, int64_t ts, int flags)
460cabdff1aSopenharmony_ci{
461cabdff1aSopenharmony_ci    VSContext *vs = s->priv_data;
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci    if (!vs->is_cfr)
464cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
465cabdff1aSopenharmony_ci
466cabdff1aSopenharmony_ci    vs->current_frame = FFMIN(FFMAX(0, ts), s->streams[0]->duration);
467cabdff1aSopenharmony_ci    return 0;
468cabdff1aSopenharmony_ci}
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_cistatic av_cold int probe_vs(const AVProbeData *p)
471cabdff1aSopenharmony_ci{
472cabdff1aSopenharmony_ci    // Explicitly do not support this. VS scripts are written in Python, and
473cabdff1aSopenharmony_ci    // can run arbitrary code on the user's system.
474cabdff1aSopenharmony_ci    return 0;
475cabdff1aSopenharmony_ci}
476cabdff1aSopenharmony_ci
477cabdff1aSopenharmony_cistatic const AVClass class_vs = {
478cabdff1aSopenharmony_ci    .class_name = "VapourSynth demuxer",
479cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
480cabdff1aSopenharmony_ci    .option     = options,
481cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
482cabdff1aSopenharmony_ci};
483cabdff1aSopenharmony_ci
484cabdff1aSopenharmony_ciconst AVInputFormat ff_vapoursynth_demuxer = {
485cabdff1aSopenharmony_ci    .name           = "vapoursynth",
486cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("VapourSynth demuxer"),
487cabdff1aSopenharmony_ci    .priv_data_size = sizeof(VSContext),
488cabdff1aSopenharmony_ci    .flags_internal = FF_FMT_INIT_CLEANUP,
489cabdff1aSopenharmony_ci    .read_probe     = probe_vs,
490cabdff1aSopenharmony_ci    .read_header    = read_header_vs,
491cabdff1aSopenharmony_ci    .read_packet    = read_packet_vs,
492cabdff1aSopenharmony_ci    .read_close     = read_close_vs,
493cabdff1aSopenharmony_ci    .read_seek      = read_seek_vs,
494cabdff1aSopenharmony_ci    .priv_class     = &class_vs,
495cabdff1aSopenharmony_ci};
496