From 21e167cc6a0d66d0d57bb5b751bdff536e7f271c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Michaj=C5=82ow?= Date: Sat, 11 May 2024 16:30:11 +0200 Subject: [PATCH] vf_vapoursynth: pass image properties from input This might not always be correct depending on filtering done in VS. But unless VS send us all the metadata we have to get it from somewhere. Fixes dynamic frame metadata, which was copied from fmt_in, initialized only upon reinitialization. Fixes crashes caused by the use of stale pointers. Fixes: #13956 --- video/filter/vf_vapoursynth.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/video/filter/vf_vapoursynth.c b/video/filter/vf_vapoursynth.c index a32772f86e..597ef5cbf2 100644 --- a/video/filter/vf_vapoursynth.c +++ b/video/filter/vf_vapoursynth.c @@ -209,6 +209,10 @@ static void copy_mp_to_vs_frame_props_map(struct priv *p, VSMap *map, if (img->fields & MP_IMGFIELD_INTERLACED) field = img->fields & MP_IMGFIELD_TOP_FIRST ? 2 : 1; p->vsapi->propSetInt(map, "_FieldBased", field, 0); + + // Don't increase the reference count. It is not intended to be read externally, + // and we know it will be alive when we retrieve it. + p->vsapi->propSetData(map, "_MP_IMAGE", (const char *)img, sizeof(*img), 0); } static int set_vs_frame_props(struct priv *p, VSFrameRef *frame, @@ -231,11 +235,13 @@ static VSFrameRef *alloc_vs_frame(struct priv *p, struct mp_image_params *fmt) } static struct mp_image map_vs_frame(struct priv *p, const VSFrameRef *ref, - bool w) + bool w, struct mp_image *ref_image) { const VSFormat *fmt = p->vsapi->getFrameFormat(ref); struct mp_image img = {0}; + if (ref_image) + img = *ref_image; mp_image_setfmt(&img, mp_from_vs(fmt->id)); mp_image_set_size(&img, p->vsapi->getFrameWidth(ref, 0), p->vsapi->getFrameHeight(ref, 0)); @@ -270,13 +276,19 @@ static void VS_CC vs_frame_done(void *userData, const VSFrameRef *f, int n, struct mp_image *res = NULL; if (f) { - struct mp_image img = map_vs_frame(p, f, false); - struct mp_image dummy = {.params = p->fmt_in}; - if (p->fmt_in.w != img.w || p->fmt_in.h != img.h) - dummy.params.crop = (struct mp_rect){0, 0, img.w, img.h}; - mp_image_copy_attributes(&img, &dummy); - img.pkt_duration = -1; const VSMap *map = p->vsapi->getFramePropsRO(f); + if (!map) + MP_ERR(p, "Failed to get frame properties!"); + struct mp_image *mpi = NULL; + if (map) { + mpi = (void *)p->vsapi->propGetData(map, "_MP_IMAGE", 0, NULL); + if (!mpi) + MP_ERR(p, "Failed to get mp_image attributes!"); + } + struct mp_image img = map_vs_frame(p, f, false, mpi); + img.pkt_duration = -1; + if (mpi && (mpi->params.w != img.w || mpi->params.h != img.h)) + img.params.crop = (struct mp_rect){0, 0, img.w, img.h}; if (map) { int err1, err2; int num = p->vsapi->propGetInt(map, "_DurationNum", 0, &err1); @@ -491,7 +503,7 @@ static const VSFrameRef *VS_CC infiltGetFrame(int frameno, int activationReason, p->vsapi->setFilterError("Could not allocate VS frame", frameCtx); break; } - struct mp_image vsframe = map_vs_frame(p, ret, true); + struct mp_image vsframe = map_vs_frame(p, ret, true, NULL); mp_image_clear(&vsframe, 0, 0, p->fmt_in.w, p->fmt_in.h); struct mp_image dummy = {0}; mp_image_set_params(&dummy, &p->fmt_in); @@ -539,7 +551,7 @@ static const VSFrameRef *VS_CC infiltGetFrame(int frameno, int activationReason, } mp_mutex_unlock(&p->lock); - struct mp_image vsframe = map_vs_frame(p, ret, true); + struct mp_image vsframe = map_vs_frame(p, ret, true, NULL); mp_image_copy(&vsframe, img); int res = 1e6; int dur = img->pkt_duration * res + 0.5;