// This function is responsible for validating arguments and creating a new filter static void VS_CC invertCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { InvertData d; InvertData *data; VSNodeRef *cref; int err; // Get a clip reference from the input arguments. This must be freed later. d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = vsapi->getVideoInfo(d.node); // In this first version we only want to handle 8bit integer formats. Note that // vi->format can be 0 if the input clip can change format midstream. if (!isConstantFormat(d.vi) || d.vi->format->sampleType != stInteger || d.vi->format->bitsPerSample != 8) { vsapi->setError(out, "Invert: only constant format 8bit integer input supported"); vsapi->freeNode(d.node); return; } // If a property read fails for some reason (index out of bounds/wrong type) // then err will have flags set to indicate why and 0 will be returned. This // can be very useful to know when having optional arguments. Since we have // strict checking because of what we wrote in the argument string the only reason // this could fail is when the value wasn't set by the user. // And when it's not set we want it to default to enabled. d.enabled = !!vsapi->propGetInt(in, "enable", 0, &err); if (err) d.enabled = 1; // Let's pretend the only allowed values are 1 or 0... if (d.enabled < 0 || d.enabled > 1) { vsapi->setError(out, "Invert: enabled must be 0 or 1"); vsapi->freeNode(d.node); return; } // I usually keep the filter data struct on the stack and don't allocate it // until all the input validation is done. data = malloc(sizeof(d)); *data = d; // Create a new filter and returns a reference to it. Always pass on the in and out // arguments or unexpected things may happen. The name should be something that's // easy to connect to the filter, like its function name. // The three function pointers handle initialization, frame processing and filter destruction. // The filtermode is very important to get right as it controls how threading of the filter // is handled. In general you should only use fmParallel whenever possible. This is if you // need to modify no shared data at all when the filter is running. // For more complicated filters fmParallelRequests is usually easier to achieve as an // be prefetched in parallel but the actual processing is serialized. // The others can be considered special cases where fmSerial is useful to source filters and // fmUnordered is useful when a filter's state may change even when deciding which frames to // prefetch (such as a cache filter). // If you filter is really fast (such as a filter that only resorts frames) you should set the // nfNoCache flag to make the caching work smoother. vsapi->createFilter(in, out, "Invert", invertInit, invertGetFrame, invertFree, fmParallel, 0, data, core); return; }
static int get_video_track ( lsmash_handler_t *h ) { vpy_handler_t *hp = (vpy_handler_t *)h->video_private; if( !isConstantFormat( hp->vi ) || hp->vi->numFrames <= 0 ) return -1; hp->av_frame = av_frame_alloc(); return hp->av_frame ? 0 : -1; }
static void VS_CC minsrpCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { MinSRPData d; MinSRPData *data = nullptr; d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = vsapi->getVideoInfo(d.node); const int m = vsapi->propNumElements(in, "mode"); const int n = vsapi->propNumElements(in, "str"); if (m > d.vi->format->numPlanes) { vsapi->setError(out, "MinSRP: number of modes specified must be equal to or fewer than the number of input planes"); vsapi->freeNode(d.node); return; } if (n > d.vi->format->numPlanes) { vsapi->setError(out, "MinSRP: number of the specified elements in str array must be equal to or fewer than the number of input planes"); vsapi->freeNode(d.node); return; } for (int i = 0; i < 3; ++i) { if (m == -1) d.mode[0] = d.mode[1] = d.mode[2] = 3; else if (i < m) { d.mode[i] = int64ToIntS(vsapi->propGetInt(in, "mode", i, nullptr)); if (d.mode[i] < 0 || d.mode[i] > 3) { vsapi->setError(out, "MinSRP: invalid mode specified, only modes 0-3 supported"); vsapi->freeNode(d.node); return; } } else d.mode[i] = d.mode[i - 1]; if (n == -1) d.str[0] = d.str[1] = d.str[2] = 1.; else if (i < n) d.str[i] = vsapi->propGetFloat(in, "str", i, nullptr); else d.str[i] = d.str[i - 1]; if (d.vi->format->subSamplingH || d.vi->format->subSamplingW) { vsapi->setError(out, "MinSRP: 4:4:4 or gray input required!"); vsapi->freeNode(d.node); return; } } if (!isConstantFormat(d.vi)) { vsapi->setError(out, "MinSRP: only input with constant format supported"); vsapi->freeNode(d.node); return; } data = new MinSRPData; *data = d; vsapi->createFilter(in, out, "MinSRP", minsrpInit, minsrpGetFrame, minsrpFree, fmParallel, 0, data, core); }
void VS_CC SCSelectCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { SCSelectData d = { 0 }; d.input = vsapi->propGetNode(in, "input", 0, 0); d.vi = vsapi->getVideoInfo(d.input); if (!isConstantFormat(d.vi)) { vsapi->freeNode(d.input); vsapi->setError(out, "SCSelect: Only constant format input supported"); return; } if (d.vi->format->id != pfYUV420P8 && d.vi->format->id != pfYUV422P8) { vsapi->freeNode(d.input); vsapi->setError(out, "SCSelect: Only planar YV12 and YUY2 colorspaces are supported"); return; } d.sceneBegin = vsapi->propGetNode(in, "sceneBegin", 0, 0); d.sceneEnd = vsapi->propGetNode(in, "sceneEnd", 0, 0); d.globalMotion = vsapi->propGetNode(in, "globalMotion", 0, 0); if (!isSameFormat(d.vi, vsapi->getVideoInfo(d.sceneBegin)) || !isSameFormat(d.vi, vsapi->getVideoInfo(d.sceneEnd)) || !isSameFormat(d.vi, vsapi->getVideoInfo(d.globalMotion))) { vsapi->freeNode(d.input); vsapi->freeNode(d.sceneBegin); vsapi->freeNode(d.sceneEnd); vsapi->freeNode(d.globalMotion); vsapi->setError(out, "SCSelect: Clips are not of equal type"); return; } int32_t err; double dFactor = vsapi->propGetFloat(in, "dfactor", 0, &err); if (err) { dFactor = 4.0; } d.hblocks = d.vi->width / (2 * 16); d.incpitch = d.hblocks * (-2 * 16); SCSelectData *data = (SCSelectData *)malloc(sizeof(d)); if (!data) { vsapi->setError(out, "Could not allocate SCSelectData"); return; } *data = d; vsapi->createFilter(in, out, "SCSelect", SCSelectInit, SCSelectGetFrame, SCSelectFree, fmParallel, 0, data, core); };
static void VS_CC infiltInit(VSMap *in, VSMap *out, void **instanceData, VSNode *node, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = *instanceData; struct vf_priv_s *p = vf->priv; // Note: this is called from createFilter, so no need for locking. VSVideoInfo fmt = { .format = p->vsapi->getFormatPreset(mp_to_vs(p->fmt_in.imgfmt), p->vscore), .width = p->fmt_in.w, .height = p->fmt_in.h, }; if (!fmt.format) { p->vsapi->setError(out, "Unsupported input format.\n"); return; } p->vsapi->setVideoInfo(&fmt, 1, node); p->in_node_active = true; } static const VSFrameRef *VS_CC infiltGetFrame(int frameno, int activationReason, void **instanceData, void **frameData, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = *instanceData; struct vf_priv_s *p = vf->priv; VSFrameRef *ret = NULL; pthread_mutex_lock(&p->lock); while (1) { if (p->shutdown) break; if (frameno < p->in_frameno) { p->vsapi->setFilterError("Requesting a frame too far in the past. " "Try increasing the maxbuffer suboption", frameCtx); break; } if (frameno >= p->in_frameno + MP_TALLOC_ELEMS(p->buffered)) { // Too far in the future. Remove frames, so that the main thread can // queue new frames. if (p->num_buffered) { drain_oldest_buffered_frame(p); pthread_cond_broadcast(&p->wakeup); continue; } } if (frameno < p->in_frameno + p->num_buffered) { struct mp_image *img = p->buffered[frameno - p->in_frameno]; const VSFormat *vsfmt = vsapi->getFormatPreset(mp_to_vs(img->imgfmt), core); ret = vsapi->newVideoFrame(vsfmt, img->w, img->h, NULL, core); if (!ret) { p->vsapi->setFilterError("Could not allocate VS frame", frameCtx); break; } struct mp_image vsframe = map_vs_frame(p, ret, true); mp_image_copy(&vsframe, img); VSMap *map = p->vsapi->getFramePropsRW(ret); if (map) { int res = 1e6; int dur = img->pts * res + 0.5; p->vsapi->propSetInt(map, "_DurationNum", dur, 0); p->vsapi->propSetInt(map, "_DurationDen", res, 0); copy_mp_to_vs_frame_props(p, map, img); } break; } pthread_cond_wait(&p->wakeup, &p->lock); } pthread_mutex_unlock(&p->lock); return ret; } static void VS_CC infiltFree(void *instanceData, VSCore *core, const VSAPI *vsapi) { struct vf_instance *vf = instanceData; struct vf_priv_s *p = vf->priv; pthread_mutex_lock(&p->lock); p->in_node_active = false; pthread_cond_broadcast(&p->wakeup); pthread_mutex_unlock(&p->lock); } static void destroy_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; // Wait until our frame callback returns. pthread_mutex_lock(&p->lock); p->shutdown = true; pthread_cond_broadcast(&p->wakeup); while (p->getting_frame) pthread_cond_wait(&p->wakeup, &p->lock); pthread_mutex_unlock(&p->lock); if (p->in_node) p->vsapi->freeNode(p->in_node); if (p->out_node) p->vsapi->freeNode(p->out_node); p->in_node = p->out_node = NULL; if (p->se) vsscript_freeScript(p->se); p->se = NULL; p->vsapi = NULL; p->vscore = NULL; assert(!p->in_node_active); p->shutdown = false; talloc_free(p->got_frame); p->got_frame = NULL; // Kill queued frames too for (int n = 0; n < p->num_buffered; n++) talloc_free(p->buffered[n]); p->num_buffered = 0; talloc_free(p->next_image); p->next_image = NULL; p->prev_pts = MP_NOPTS_VALUE; p->out_frameno = p->in_frameno = 0; } static int reinit_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; VSMap *vars = NULL, *in = NULL, *out = NULL; int res = -1; destroy_vs(vf); // First load an empty script to get a VSScript, so that we get the vsapi // and vscore. if (vsscript_evaluateScript(&p->se, "", NULL, 0)) goto error; p->vsapi = vsscript_getVSApi(); p->vscore = vsscript_getCore(p->se); if (!p->vsapi || !p->vscore) goto error; in = p->vsapi->createMap(); out = p->vsapi->createMap(); vars = p->vsapi->createMap(); if (!in || !out || !vars) goto error; p->vsapi->createFilter(in, out, "Input", infiltInit, infiltGetFrame, infiltFree, fmSerial, 0, vf, p->vscore); int vserr; p->in_node = p->vsapi->propGetNode(out, "clip", 0, &vserr); if (!p->in_node) goto error; if (p->vsapi->propSetNode(vars, "video_in", p->in_node, 0)) goto error; vsscript_setVariable(p->se, vars); if (vsscript_evaluateFile(&p->se, p->cfg_file, 0)) { MP_FATAL(vf, "Script evaluation failed:\n%s\n", vsscript_getError(p->se)); goto error; } p->out_node = vsscript_getOutput(p->se, 0); if (!p->out_node) goto error; const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); if (!isConstantFormat(vi)) { MP_FATAL(vf, "Video format is required to be constant.\n"); goto error; } res = 0; error: if (p->vsapi) { p->vsapi->freeMap(in); p->vsapi->freeMap(out); p->vsapi->freeMap(vars); } if (res < 0) destroy_vs(vf); return res; } static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int fmt) { struct vf_priv_s *p = vf->priv; p->fmt_in = (struct mp_image_params){ .imgfmt = fmt, .w = width, .h = height, }; if (reinit_vs(vf) < 0) return 0; const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); fmt = mp_from_vs(vi->format->id); if (!fmt) { MP_FATAL(vf, "Unsupported output format.\n"); destroy_vs(vf); return 0; } vf_rescale_dsize(&d_width, &d_height, width, height, vi->width, vi->height); return vf_next_config(vf, vi->width, vi->height, d_width, d_height, flags, fmt); } static int query_format(struct vf_instance *vf, unsigned int fmt) { return mp_to_vs(fmt) != pfNone ? VFCAP_CSP_SUPPORTED : 0; } static int control(vf_instance_t *vf, int request, void *data) { switch (request) { case VFCTRL_SEEK_RESET: if (reinit_vs(vf) < 0) return CONTROL_ERROR; return CONTROL_OK; } return CONTROL_UNKNOWN; } static void uninit(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; destroy_vs(vf); vsscript_finalize(); pthread_cond_destroy(&p->wakeup); pthread_mutex_destroy(&p->lock); } static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; if (!vsscript_init()) { MP_FATAL(vf, "Could not initialize VapourSynth scripting.\n"); return 0; } if (!p->cfg_file || !p->cfg_file[0]) { MP_FATAL(vf, "'file' parameter must be set.\n"); return 0; } pthread_mutex_init(&p->lock, NULL); pthread_cond_init(&p->wakeup, NULL); vf->reconfig = NULL; vf->config = config; vf->filter_ext = filter_ext; vf->filter = NULL; vf->query_format = query_format; vf->control = control; vf->uninit = uninit; p->buffered = talloc_array(vf, struct mp_image *, p->cfg_maxbuffer); return 1; } #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_STRING("file", cfg_file, 0), OPT_INTRANGE("maxbuffer", cfg_maxbuffer, 0, 1, 9999, OPTDEF_INT(5)), {0} }; const vf_info_t vf_info_vapoursynth = { .description = "vapoursynth bridge", .name = "vapoursynth", .open = vf_open, .priv_size = sizeof(struct vf_priv_s), .options = vf_opts_fields, };
static void VS_CC mvsuperCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { MVSuperData d; MVSuperData *data; int err; d.nHPad = int64ToIntS(vsapi->propGetInt(in, "hpad", 0, &err)); if (err) d.nHPad = 8; d.nVPad = int64ToIntS(vsapi->propGetInt(in, "vpad", 0, &err)); if (err) d.nVPad = 8; d.nPel = int64ToIntS(vsapi->propGetInt(in, "pel", 0, &err)); if (err) d.nPel = 2; d.nLevels = int64ToIntS(vsapi->propGetInt(in, "levels", 0, &err)); d.chroma = !!vsapi->propGetInt(in, "chroma", 0, &err); if (err) d.chroma = 1; d.sharp = int64ToIntS(vsapi->propGetInt(in, "sharp", 0, &err)); if (err) d.sharp = 2; d.rfilter = int64ToIntS(vsapi->propGetInt(in, "rfilter", 0, &err)); if (err) d.rfilter = 2; if ((d.nPel != 1) && (d.nPel != 2) && (d.nPel != 4)) { vsapi->setError(out, "Super: pel must be 1, 2, or 4."); return; } if (d.sharp < 0 || d.sharp > 2) { vsapi->setError(out, "Super: sharp must be between 0 and 2 (inclusive)."); return; } if (d.rfilter < 0 || d.rfilter > 4) { vsapi->setError(out, "Super: rfilter must be between 0 and 4 (inclusive)."); return; } d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = *vsapi->getVideoInfo(d.node); d.nWidth = d.vi.width; d.nHeight = d.vi.height; if (!isConstantFormat(&d.vi) || d.vi.format->bitsPerSample < 32 || d.vi.format->sampleType != stFloat) { vsapi->setError(out, "Super: input clip must be single precision fp, with constant dimensions."); vsapi->freeNode(d.node); return; } if (d.vi.format->colorFamily == cmGray) d.chroma = 0; if (d.vi.format->colorFamily == cmRGB) d.chroma = 1; d.nModeYUV = d.chroma ? YUVPLANES : YPLANE; d.xRatioUV = 1 << d.vi.format->subSamplingW; d.yRatioUV = 1 << d.vi.format->subSamplingH; int32_t nLevelsMax = 0; while (PlaneHeightLuma(d.vi.height, nLevelsMax, d.yRatioUV, d.nVPad) >= d.yRatioUV * 2 && PlaneWidthLuma(d.vi.width, nLevelsMax, d.xRatioUV, d.nHPad) >= d.xRatioUV * 2) { ++nLevelsMax; } if (d.nLevels <= 0 || d.nLevels > nLevelsMax) d.nLevels = nLevelsMax; d.pelclip = vsapi->propGetNode(in, "pelclip", 0, &err); const VSVideoInfo *pelvi = d.pelclip ? vsapi->getVideoInfo(d.pelclip) : nullptr; if (d.pelclip && (!isConstantFormat(pelvi) || pelvi->format != d.vi.format)) { vsapi->setError(out, "Super: pelclip must have the same format as the input clip, and it must have constant dimensions."); vsapi->freeNode(d.node); vsapi->freeNode(d.pelclip); return; } d.usePelClip = false; if (d.pelclip && (d.nPel >= 2)) { if ((pelvi->width == d.vi.width * d.nPel) && (pelvi->height == d.vi.height * d.nPel)) { d.usePelClip = true; d.isPelClipPadded = false; } else if ((pelvi->width == (d.vi.width + d.nHPad * 2) * d.nPel) && (pelvi->height == (d.vi.height + d.nVPad * 2) * d.nPel)) { d.usePelClip = true; d.isPelClipPadded = true; } else { vsapi->setError(out, "Super: pelclip's dimensions must be multiples of the input clip's dimensions."); vsapi->freeNode(d.pelclip); vsapi->freeNode(d.node); return; } } d.nSuperWidth = d.nWidth + 2 * d.nHPad; d.nSuperHeight = PlaneSuperOffset(false, d.nHeight, d.nLevels, d.nPel, d.nVPad, d.nSuperWidth, d.yRatioUV) / d.nSuperWidth; if (d.yRatioUV == 2 && d.nSuperHeight & 1) ++d.nSuperHeight; if (d.xRatioUV == 2 && d.nSuperWidth & 1) ++d.nSuperWidth; d.vi.width = d.nSuperWidth; d.vi.height = d.nSuperHeight; data = new MVSuperData; *data = d; vsapi->createFilter(in, out, "Super", mvsuperInit, mvsuperGetFrame, mvsuperFree, fmParallel, 0, data, core); }
static void VS_CC resizeCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { ResizeData d; ResizeData *data; int id; int dstwidth; int dstheight; int pf; int err; d.context = 0; d.dstrange = 0; d.lsrcformat = 0; d.lsrch = 0; d.lsrcw = 0; d.node = 0; d.flags = (intptr_t)userData; d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = *vsapi->getVideoInfo(d.node); dstwidth = int64ToIntS(vsapi->propGetInt(in, "width", 0, &err)); if (err) dstwidth = d.vi.width; dstheight = int64ToIntS(vsapi->propGetInt(in, "height", 0, &err)); if (err) dstheight = d.vi.height; id = int64ToIntS(vsapi->propGetInt(in, "format", 0, &err)); if (err && d.vi.format) id = d.vi.format->id; if (dstwidth > 0) d.vi.width = dstwidth; if (dstheight > 0) d.vi.height = dstheight; pf = formatIdToPixelFormat(id); if (pf == PIX_FMT_NONE) { vsapi->freeNode(d.node); RETERROR("Resize: unsupported output format"); } d.vi.format = vsapi->getFormatPreset(id, core); if ((d.vi.width % (1 << d.vi.format->subSamplingW)) || (d.vi.height % (1 << d.vi.format->subSamplingH))) { vsapi->freeNode(d.node); RETERROR("Resize: mod requirements of the target colorspace not fulfilled"); } if (!isConstantFormat(&d.vi)) { vsapi->freeNode(d.node); RETERROR("Resize: output format not constant, set width, height and format"); } data = malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "Resize", resizeInit, resizeGetframe, resizeFree, fmParallelRequests, 0, data, core); }
static int reinit_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; VSMap *vars = NULL, *in = NULL, *out = NULL; int res = -1; destroy_vs(vf); MP_DBG(vf, "initializing...\n"); p->initializing = true; if (p->drv->load_core(vf) < 0 || !p->vsapi || !p->vscore) { MP_FATAL(vf, "Could not get vapoursynth API handle.\n"); goto error; } in = p->vsapi->createMap(); out = p->vsapi->createMap(); vars = p->vsapi->createMap(); if (!in || !out || !vars) goto error; p->vsapi->createFilter(in, out, "Input", infiltInit, infiltGetFrame, infiltFree, fmSerial, 0, vf, p->vscore); int vserr; p->in_node = p->vsapi->propGetNode(out, "clip", 0, &vserr); if (!p->in_node) { MP_FATAL(vf, "Could not get our own input node.\n"); goto error; } if (p->vsapi->propSetNode(vars, "video_in", p->in_node, 0)) goto error; int d_w, d_h; mp_image_params_get_dsize(&p->fmt_in, &d_w, &d_h); p->vsapi->propSetInt(vars, "video_in_dw", d_w, 0); p->vsapi->propSetInt(vars, "video_in_dh", d_h, 0); p->vsapi->propSetFloat(vars, "container_fps", vf->chain->container_fps, 0); p->vsapi->propSetFloat(vars, "display_fps", vf->chain->display_fps, 0); if (p->drv->load(vf, vars) < 0) goto error; if (!p->out_node) { MP_FATAL(vf, "Could not get script output node.\n"); goto error; } const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); if (!isConstantFormat(vi)) { MP_FATAL(vf, "Video format is required to be constant.\n"); goto error; } pthread_mutex_lock(&p->lock); p->initializing = false; pthread_mutex_unlock(&p->lock); MP_DBG(vf, "initialized.\n"); res = 0; error: if (p->vsapi) { p->vsapi->freeMap(in); p->vsapi->freeMap(out); p->vsapi->freeMap(vars); } if (res < 0) destroy_vs(vf); return res; }
static void VS_CC vs_depth_create(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { vs_depth_data *data = 0; zimg_depth_params params; zimg_filter *filter = 0; zimg_filter *filter_uv = 0; char fail_str[1024]; int err; VSNodeRef *node = 0; const VSVideoInfo *node_vi; const VSFormat *node_fmt; VSVideoInfo vi; const char *dither_str; int sample_type; int depth; node = vsapi->propGetNode(in, "clip", 0, 0); node_vi = vsapi->getVideoInfo(node); node_fmt = node_vi->format; if (!isConstantFormat(node_vi)) { strcpy(fail_str, "clip must have a defined format"); goto fail; } sample_type = (int)propGetIntDefault(vsapi, in, "sample", 0, node_fmt->sampleType); depth = (int)propGetIntDefault(vsapi, in, "depth", 0, node_fmt->bitsPerSample); if (sample_type != stInteger && sample_type != stFloat) { strcpy(fail_str, "invalid sample type: must be stInteger or stFloat"); goto fail; } if (sample_type == stFloat && depth != 16 && depth != 32) { strcpy(fail_str, "invalid depth: must be 16 or 32 for stFloat"); goto fail; } if (sample_type == stInteger && (depth <= 0 || depth > 16)) { strcpy(fail_str, "invalid depth: must be between 1-16 for stInteger"); goto fail; } vi = *node_vi; vi.format = vsapi->registerFormat(node_fmt->colorFamily, sample_type, depth < 8 ? 8 : depth, node_fmt->subSamplingW, node_fmt->subSamplingH, core); if (!vi.format) { strcpy(fail_str, "unable to register output VSFormat"); goto fail; } zimg2_depth_params_default(¶ms, ZIMG_API_VERSION); params.width = node_vi->width; params.height = node_vi->height; dither_str = vsapi->propGetData(in, "dither", 0, &err); if (!err) params.dither_type = translate_dither(dither_str); params.chroma = 0; params.pixel_in = translate_pixel(node_fmt); params.depth_in = node_fmt->bitsPerSample; params.range_in = (int)propGetIntDefault(vsapi, in, "range_in", 0, node_fmt->colorFamily == cmRGB ? ZIMG_RANGE_FULL : ZIMG_RANGE_LIMITED); params.pixel_out = translate_pixel(vi.format); params.depth_out = depth; params.range_out = (int)propGetIntDefault(vsapi, in, "range_out", 0, params.range_in); if (!(filter = zimg2_depth_create(¶ms))) { zimg_get_last_error(fail_str, sizeof(fail_str)); goto fail; } if (node_fmt->colorFamily == cmYUV || node_fmt->colorFamily == cmYCoCg) { params.width = params.width >> node_fmt->subSamplingW; params.height = params.height >> node_fmt->subSamplingH; params.chroma = 1; if (!(filter_uv = zimg2_depth_create(¶ms))) { zimg_get_last_error(fail_str, sizeof(fail_str)); goto fail; } }
int wmain(int argc, wchar_t **argv) { #else int main(int argc, char **argv) { #endif if (argc < 3) { fprintf(stderr, "VSPipe usage:\n"); fprintf(stderr, "Show script info: vspipe script.vpy - -info\n"); fprintf(stderr, "Write to stdout: vspipe script.vpy - [options]\n"); fprintf(stderr, "Write to file: vspipe script.vpy <outFile> [options]\n"); fprintf(stderr, "Available options:\n"); fprintf(stderr, "Select output index: -index N\n"); fprintf(stderr, "Set number of concurrent frame requests: -requests N\n"); fprintf(stderr, "Add YUV4MPEG headers: -y4m\n"); fprintf(stderr, "Show video info: -info (overrides other options)\n"); return 1; } QFile scriptFile(nativeToQString(argv[1])); if (!scriptFile.open(QIODevice::ReadOnly)) { fprintf(stderr, "Failed to to open script file for reading\n"); return 1; } if (scriptFile.size() > 1024*1024*16) { fprintf(stderr, "Script files bigger than 16MB not allowed\n"); return 1; } QByteArray scriptData = scriptFile.readAll(); scriptFile.close(); if (scriptData.isEmpty()) { fprintf(stderr, "Failed to read script file or file is empty\n"); return 1; } QString outputFilename = nativeToQString(argv[2]); if (outputFilename == "-") { outFile = stdout; } else { #ifdef VS_TARGET_OS_WINDOWS outFile = _wfopen(outputFilename.toStdWString().c_str(), L"wb"); #else outFile = fopen(outputFilename.toLocal8Bit(), "wb"); #endif if (!outFile) { fprintf(stderr, "Failed to open output for writing\n"); return 1; } } for (int arg = 3; arg < argc; arg++) { QString argString = nativeToQString(argv[arg]); if (argString == "-y4m") { y4m = true; } else if (argString == "-info") { showInfo = true; } else if (argString == "-index") { bool ok = false; if (argc <= arg + 1) { fprintf(stderr, "No index number specified"); return 1; } QString numString = nativeToQString(argv[arg+1]); outputIndex = numString.toInt(&ok); if (!ok) { fprintf(stderr, "Couldn't convert %s to an integer", numString.toUtf8().constData()); return 1; } arg++; } else if (argString == "-requests") { bool ok = false; if (argc <= arg + 1) { fprintf(stderr, "No request number specified"); return 1; } QString numString = nativeToQString(argv[arg+1]); requests = numString.toInt(&ok); if (!ok) { fprintf(stderr, "Couldn't convert %s to an integer", numString.toUtf8().constData()); return 1; } arg++; } else { fprintf(stderr, "Unknown argument: %s\n", argString.toUtf8().constData()); return 1; } } if (!vseval_init()) { fprintf(stderr, "Failed to initialize VapourSynth environment\n"); return 1; } vsapi = vseval_getVSApi(); if (!vsapi) { fprintf(stderr, "Failed to get VapourSynth API pointer\n"); vseval_finalize(); return 1; } if (vseval_evaluateScript(&se, scriptData.constData(), nativeToQString(argv[1]).toUtf8())) { fprintf(stderr, "Script evaluation failed:\n%s", vseval_getError(se)); vseval_freeScript(se); vseval_finalize(); return 1; } node = vseval_getOutput(se, outputIndex); if (!node) { fprintf(stderr, "Failed to retrieve output node. Invalid index specified?\n"); vseval_freeScript(se); vseval_finalize(); return 1; } bool error = false; const VSVideoInfo *vi = vsapi->getVideoInfo(node); if (showInfo) { fprintf(outFile, "Width: %d\n", vi->width); fprintf(outFile, "Height: %d\n", vi->height); fprintf(outFile, "Frames: %d\n", vi->numFrames); fprintf(outFile, "FPS: %" PRId64 "/%" PRId64 "\n", vi->fpsNum, vi->fpsDen); if (vi->format) { fprintf(outFile, "Format Name: %s\n", vi->format->name); fprintf(outFile, "Color Family: %s\n", colorFamilyToString(vi->format->colorFamily)); fprintf(outFile, "Bits: %d\n", vi->format->bitsPerSample); fprintf(outFile, "SubSampling W: %d\n", vi->format->subSamplingW); fprintf(outFile, "SubSampling H: %d\n", vi->format->subSamplingH); } else { fprintf(outFile, "Format Name: Variable\n"); } } else { if (!isConstantFormat(vi) || vi->numFrames == 0) { fprintf(stderr, "Cannot output clips with varying dimensions or unknown length\n"); vsapi->freeNode(node); vseval_freeScript(se); vseval_finalize(); return 1; } error = outputNode(); } fflush(outFile); vsapi->freeNode(node); vseval_freeScript(se); vseval_finalize(); return error; }
static void VS_CC mvflowblurCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { (void)userData; MVFlowBlurData d; MVFlowBlurData *data; int err; d.blur = (float)vsapi->propGetFloat(in, "blur", 0, &err); if (err) d.blur = 50.0f; d.prec = int64ToIntS(vsapi->propGetInt(in, "prec", 0, &err)); if (err) d.prec = 1; d.thscd1 = int64ToIntS(vsapi->propGetInt(in, "thscd1", 0, &err)); if (err) d.thscd1 = MV_DEFAULT_SCD1; d.thscd2 = int64ToIntS(vsapi->propGetInt(in, "thscd2", 0, &err)); if (err) d.thscd2 = MV_DEFAULT_SCD2; d.opt = !!vsapi->propGetInt(in, "opt", 0, &err); if (err) d.opt = 1; if (d.blur < 0.0f || d.blur > 200.0f) { vsapi->setError(out, "FlowBlur: blur must be between 0 and 200 % (inclusive)."); return; } if (d.prec < 1) { vsapi->setError(out, "FlowBlur: prec must be at least 1."); return; } d.blur256 = (int)(d.blur * 256.0f / 200.0f); d.super = vsapi->propGetNode(in, "super", 0, NULL); #define ERROR_SIZE 1024 char errorMsg[ERROR_SIZE] = "FlowBlur: failed to retrieve first frame from super clip. Error message: "; size_t errorLen = strlen(errorMsg); const VSFrameRef *evil = vsapi->getFrame(0, d.super, errorMsg + errorLen, ERROR_SIZE - errorLen); #undef ERROR_SIZE if (!evil) { vsapi->setError(out, errorMsg); vsapi->freeNode(d.super); return; } const VSMap *props = vsapi->getFramePropsRO(evil); int evil_err[3]; int nHeightS = int64ToIntS(vsapi->propGetInt(props, "Super_height", 0, &evil_err[0])); d.nSuperHPad = int64ToIntS(vsapi->propGetInt(props, "Super_hpad", 0, &evil_err[1])); int nSuperPel = int64ToIntS(vsapi->propGetInt(props, "Super_pel", 0, &evil_err[2])); vsapi->freeFrame(evil); for (int i = 0; i < 2; i++) if (evil_err[i]) { vsapi->setError(out, "FlowBlur: required properties not found in first frame of super clip. Maybe clip didn't come from mv.Super? Was the first frame trimmed away?"); vsapi->freeNode(d.super); return; } d.mvbw = vsapi->propGetNode(in, "mvbw", 0, NULL); d.mvfw = vsapi->propGetNode(in, "mvfw", 0, NULL); #define ERROR_SIZE 512 char error[ERROR_SIZE + 1] = { 0 }; const char *filter_name = "FlowBlur"; adataFromVectorClip(&d.mvbw_data, d.mvbw, filter_name, "mvbw", vsapi, error, ERROR_SIZE); adataFromVectorClip(&d.mvfw_data, d.mvfw, filter_name, "mvfw", vsapi, error, ERROR_SIZE); scaleThSCD(&d.thscd1, &d.thscd2, &d.mvbw_data, filter_name, error, ERROR_SIZE); adataCheckSimilarity(&d.mvbw_data, &d.mvfw_data, filter_name, "mvbw", "mvfw", error, ERROR_SIZE); #undef ERROR_SIZE if (error[0]) { vsapi->setError(out, error); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); return; } if (d.mvbw_data.nDeltaFrame <= 0 || d.mvfw_data.nDeltaFrame <= 0) { vsapi->setError(out, "FlowBlur: cannot use motion vectors with absolute frame references."); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); return; } // XXX Alternatively, use both clips' delta as offsets in GetFrame. if (d.mvfw_data.nDeltaFrame != d.mvbw_data.nDeltaFrame) { vsapi->setError(out, "FlowBlur: mvbw and mvfw must be generated with the same delta."); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); return; } // Make sure the motion vector clips are correct. if (!d.mvbw_data.isBackward || d.mvfw_data.isBackward) { if (!d.mvbw_data.isBackward) vsapi->setError(out, "FlowBlur: mvbw must be generated with isb=True."); else vsapi->setError(out, "FlowBlur: mvfw must be generated with isb=False."); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); return; } if (d.mvbw_data.nPel == 1) d.finest = vsapi->cloneNodeRef(d.super); // v2.0.9.1 else { VSPlugin *mvtoolsPlugin = vsapi->getPluginById("com.nodame.mvtools", core); VSPlugin *stdPlugin = vsapi->getPluginById("com.vapoursynth.std", core); VSMap *args = vsapi->createMap(); vsapi->propSetNode(args, "super", d.super, paReplace); vsapi->propSetInt(args, "opt", d.opt, paReplace); VSMap *ret = vsapi->invoke(mvtoolsPlugin, "Finest", args); if (vsapi->getError(ret)) { #define ERROR_SIZE 512 char error_msg[ERROR_SIZE + 1] = { 0 }; snprintf(error_msg, ERROR_SIZE, "FlowBlur: %s", vsapi->getError(ret)); #undef ERROR_SIZE vsapi->setError(out, error_msg); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeMap(args); vsapi->freeMap(ret); return; } d.finest = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); vsapi->clearMap(args); vsapi->propSetNode(args, "clip", d.finest, paReplace); vsapi->freeNode(d.finest); ret = vsapi->invoke(stdPlugin, "Cache", args); vsapi->freeMap(args); if (vsapi->getError(ret)) { #define ERROR_SIZE 512 char error_msg[ERROR_SIZE + 1] = { 0 }; snprintf(error_msg, ERROR_SIZE, "FlowBlur: %s", vsapi->getError(ret)); #undef ERROR_SIZE vsapi->setError(out, error_msg); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeMap(ret); return; } d.finest = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); } d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = vsapi->getVideoInfo(d.node); const VSVideoInfo *supervi = vsapi->getVideoInfo(d.super); int nSuperWidth = supervi->width; if (d.mvbw_data.nHeight != nHeightS || d.mvbw_data.nWidth != nSuperWidth - d.nSuperHPad * 2 || d.mvbw_data.nPel != nSuperPel) { vsapi->setError(out, "FlowBlur: wrong source or super clip frame size."); vsapi->freeNode(d.finest); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); return; } if (!isConstantFormat(d.vi) || d.vi->format->bitsPerSample > 16 || d.vi->format->sampleType != stInteger || d.vi->format->subSamplingW > 1 || d.vi->format->subSamplingH > 1 || (d.vi->format->colorFamily != cmYUV && d.vi->format->colorFamily != cmGray)) { vsapi->setError(out, "FlowBlur: input clip must be GRAY, 420, 422, 440, or 444, up to 16 bits, with constant dimensions."); vsapi->freeNode(d.super); vsapi->freeNode(d.finest); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); return; } d.nHeightUV = d.mvbw_data.nHeight / d.mvbw_data.yRatioUV; d.nWidthUV = d.mvbw_data.nWidth / d.mvbw_data.xRatioUV; d.nHPaddingUV = d.mvbw_data.nHPadding / d.mvbw_data.xRatioUV; //d.nVPaddingUV = d.mvbw_data.nHPadding / d.mvbw_data.yRatioUV; // original looks wrong d.nVPaddingUV = d.mvbw_data.nVPadding / d.mvbw_data.yRatioUV; d.VPitchY = d.mvbw_data.nWidth; d.VPitchUV = d.nWidthUV; simpleInit(&d.upsizer, d.mvbw_data.nWidth, d.mvbw_data.nHeight, d.mvbw_data.nBlkX, d.mvbw_data.nBlkY, d.opt); if (d.vi->format->colorFamily != cmGray) simpleInit(&d.upsizerUV, d.nWidthUV, d.nHeightUV, d.mvbw_data.nBlkX, d.mvbw_data.nBlkY, d.opt); data = (MVFlowBlurData *)malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "FlowBlur", mvflowblurInit, mvflowblurGetFrame, mvflowblurFree, fmParallel, 0, data, core); }
static void VS_CC mvmaskCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { (void)userData; MVMaskData d; MVMaskData *data; int err; d.ml = (float)vsapi->propGetFloat(in, "ml", 0, &err); if (err) d.ml = 100.0f; d.fGamma = (float)vsapi->propGetFloat(in, "gamma", 0, &err); if (err) d.fGamma = 1.0f; d.kind = int64ToIntS(vsapi->propGetInt(in, "kind", 0, &err)); double time = vsapi->propGetFloat(in, "time", 0, &err); if (err) time = 100.0; d.nSceneChangeValue = int64ToIntS(vsapi->propGetInt(in, "ysc", 0, &err)); d.thscd1 = vsapi->propGetInt(in, "thscd1", 0, &err); if (err) d.thscd1 = MV_DEFAULT_SCD1; d.thscd2 = int64ToIntS(vsapi->propGetInt(in, "thscd2", 0, &err)); if (err) d.thscd2 = MV_DEFAULT_SCD2; d.opt = !!vsapi->propGetInt(in, "opt", 0, &err); if (err) d.opt = 1; if (d.fGamma < 0.0f) { vsapi->setError(out, "Mask: gamma must not be negative."); return; } if (d.kind < 0 || d.kind > 5) { vsapi->setError(out, "Mask: kind must 0, 1, 2, 3, 4, or 5."); return; } if (time < 0.0 || time > 100.0) { vsapi->setError(out, "Mask: time must be between 0.0 and 100.0 (inclusive)."); return; } if (d.nSceneChangeValue < 0 || d.nSceneChangeValue > 255) { vsapi->setError(out, "Mask: ysc must be between 0 and 255 (inclusive)."); return; } d.vectors = vsapi->propGetNode(in, "vectors", 0, NULL); #define ERROR_SIZE 512 char error[ERROR_SIZE + 1] = { 0 }; const char *filter_name = "Mask"; adataFromVectorClip(&d.vectors_data, d.vectors, filter_name, "vectors", vsapi, error, ERROR_SIZE); scaleThSCD(&d.thscd1, &d.thscd2, &d.vectors_data, filter_name, error, ERROR_SIZE); #undef ERROR_SIZE if (error[0]) { vsapi->setError(out, error); vsapi->freeNode(d.vectors); return; } d.fMaskNormFactor = 1.0f / d.ml; // Fizick d.fMaskNormFactor2 = d.fMaskNormFactor * d.fMaskNormFactor; d.fHalfGamma = d.fGamma * 0.5f; d.nWidthB = d.vectors_data.nBlkX * (d.vectors_data.nBlkSizeX - d.vectors_data.nOverlapX) + d.vectors_data.nOverlapX; d.nHeightB = d.vectors_data.nBlkY * (d.vectors_data.nBlkSizeY - d.vectors_data.nOverlapY) + d.vectors_data.nOverlapY; d.nHeightUV = d.vectors_data.nHeight / d.vectors_data.yRatioUV; d.nWidthUV = d.vectors_data.nWidth / d.vectors_data.xRatioUV; d.nHeightBUV = d.nHeightB / d.vectors_data.yRatioUV; d.nWidthBUV = d.nWidthB / d.vectors_data.xRatioUV; d.node = vsapi->propGetNode(in, "clip", 0, NULL); d.vi = *vsapi->getVideoInfo(d.node); if (!isConstantFormat(&d.vi) || d.vi.format->bitsPerSample > 8 || d.vi.format->subSamplingW > 1 || d.vi.format->subSamplingH > 1 || (d.vi.format->colorFamily != cmYUV && d.vi.format->colorFamily != cmGray)) { vsapi->setError(out, "Mask: input clip must be GRAY8, YUV420P8, YUV422P8, YUV440P8, or YUV444P8, with constant dimensions."); vsapi->freeNode(d.node); vsapi->freeNode(d.vectors); return; } if (d.vi.format->colorFamily == cmGray) d.vi.format = vsapi->getFormatPreset(pfYUV444P8, core); simpleInit(&d.upsizer, d.nWidthB, d.nHeightB, d.vectors_data.nBlkX, d.vectors_data.nBlkY, d.opt); simpleInit(&d.upsizerUV, d.nWidthBUV, d.nHeightBUV, d.vectors_data.nBlkX, d.vectors_data.nBlkY, d.opt); d.time256 = (int)(time * 256 / 100); data = (MVMaskData *)malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "Mask", mvmaskInit, mvmaskGetFrame, mvmaskFree, fmParallel, 0, data, core); }
static void VS_CC lut2Create(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { std::unique_ptr<Lut2Data> d(new Lut2Data(vsapi)); d->node[0] = vsapi->propGetNode(in, "clipa", 0, 0); d->node[1] = vsapi->propGetNode(in, "clipb", 0, 0); d->vi[0] = vsapi->getVideoInfo(d->node[0]); d->vi[1] = vsapi->getVideoInfo(d->node[1]); if (!isConstantFormat(d->vi[0]) || !isConstantFormat(d->vi[1])) RETERROR("Lut2: only clips with constant format and dimensions supported"); if (isCompatFormat(d->vi[0]) || isCompatFormat(d->vi[1])) RETERROR("Lut2: compat formats are not supported"); if (d->vi[0]->format->sampleType != stInteger || d->vi[1]->format->sampleType != stInteger || (d->vi[0]->format->bitsPerSample + d->vi[1]->format->bitsPerSample) > 20 || d->vi[0]->format->subSamplingH != d->vi[1]->format->subSamplingH || d->vi[0]->format->subSamplingW != d->vi[1]->format->subSamplingW || d->vi[0]->width != d->vi[1]->width || d->vi[0]->height != d->vi[1]->height) RETERROR("Lut2: only clips with integer samples, same dimensions, same subsampling and up to a total of 20 indexing bits supported"); int n = d->vi[0]->format->numPlanes; int num_planes = vsapi->propNumElements(in, "planes"); for (int i = 0; i < 3; i++) d->process[i] = (num_planes <= 0); for (int i = 0; i < num_planes; i++) { int o = int64ToIntS(vsapi->propGetInt(in, "planes", i, 0)); if (o < 0 || o >= n) RETERROR("Lut2: plane index out of range"); if (d->process[o]) RETERROR("Lut2: plane specified twice"); d->process[o] = true; } int err; VSFuncRef *func = vsapi->propGetFunc(in, "function", 0, &err); int lut_elem = vsapi->propNumElements(in, "lut"); int lutf_elem = vsapi->propNumElements(in, "lutf"); bool floatout = !!vsapi->propGetInt(in, "floatout", 0, &err); int num_set = (lut_elem >= 0) + (lutf_elem >= 0) + !!func; if (!num_set) { vsapi->freeFunc(func); RETERROR("Lut2: none of lut, lutf and function are set"); } if (num_set > 1) { vsapi->freeFunc(func); RETERROR("Lut2: more than one of lut, lutf and function are set"); } if (lut_elem >= 0 && floatout) { vsapi->freeFunc(func); RETERROR("Lut2: lut set but float output specified"); } if (lutf_elem >= 0 && !floatout) { vsapi->freeFunc(func); RETERROR("Lut2: lutf set but float output not specified"); } n = 1 << (d->vi[0]->format->bitsPerSample + d->vi[1]->format->bitsPerSample); int lut_length = std::max(lut_elem, lutf_elem); if (lut_length >= 0 && lut_length != n) { vsapi->freeFunc(func); RETERROR(("Lut2: bad lut length. Expected " + std::to_string(n) + " elements, got " + std::to_string(lut_length) + " instead").c_str()); } int bitsout = int64ToIntS(vsapi->propGetInt(in, "bits", 0, &err)); if (err) bitsout = floatout ? sizeof(float) * 8 : d->vi[0]->format->bitsPerSample; if ((floatout && bitsout != 32) || (!floatout && (bitsout < 8 || bitsout > 16))) { vsapi->freeFunc(func); RETERROR("Lut2: only 8-16 bit integer and 32 bit float output supported"); } d->vi_out = *d->vi[0]; d->vi_out.format = vsapi->registerFormat(d->vi[0]->format->colorFamily, floatout ? stFloat : stInteger, bitsout, d->vi[0]->format->subSamplingW, d->vi[0]->format->subSamplingH, core); if (d->vi[0]->format->bytesPerSample == 1) { if (d->vi[1]->format->bytesPerSample == 1) { if (d->vi_out.format->bytesPerSample == 1 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint8_t, uint8_t, uint8_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bytesPerSample == 2 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint8_t, uint8_t, uint16_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bitsPerSample == 32 && d->vi_out.format->sampleType == stFloat) lut2CreateHelper<uint8_t, uint8_t, float>(in, out, func, d, core, vsapi); } else if (d->vi[1]->format->bytesPerSample == 2) { if (d->vi_out.format->bytesPerSample == 1 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint8_t, uint16_t, uint8_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bytesPerSample == 2 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint8_t, uint16_t, uint16_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bitsPerSample == 32 && d->vi_out.format->sampleType == stFloat) lut2CreateHelper<uint8_t, uint16_t, float>(in, out, func, d, core, vsapi); } } else if (d->vi[0]->format->bytesPerSample == 2) { if (d->vi[1]->format->bytesPerSample == 1) { if (d->vi_out.format->bytesPerSample == 1 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint16_t, uint8_t, uint8_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bytesPerSample == 2 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint16_t, uint8_t, uint16_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bitsPerSample == 32 && d->vi_out.format->sampleType == stFloat) lut2CreateHelper<uint16_t, uint8_t, float>(in, out, func, d, core, vsapi); } else if (d->vi[1]->format->bytesPerSample == 2) { if (d->vi_out.format->bytesPerSample == 1 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint16_t, uint16_t, uint8_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bytesPerSample == 2 && d->vi_out.format->sampleType == stInteger) lut2CreateHelper<uint16_t, uint16_t, uint16_t>(in, out, func, d, core, vsapi); else if (d->vi_out.format->bitsPerSample == 32 && d->vi_out.format->sampleType == stFloat) lut2CreateHelper<uint16_t, uint16_t, float>(in, out, func, d, core, vsapi); } } }
static void VS_CC mvsuperCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { (void)userData; MVSuperData d; MVSuperData *data; int err; d.nHPad = int64ToIntS(vsapi->propGetInt(in, "hpad", 0, &err)); if (err) d.nHPad = 8; d.nVPad = int64ToIntS(vsapi->propGetInt(in, "vpad", 0, &err)); if (err) d.nVPad = 8; d.nPel = int64ToIntS(vsapi->propGetInt(in, "pel", 0, &err)); if (err) d.nPel = 2; d.nLevels = int64ToIntS(vsapi->propGetInt(in, "levels", 0, &err)); d.chroma = !!vsapi->propGetInt(in, "chroma", 0, &err); if (err) d.chroma = 1; d.sharp = int64ToIntS(vsapi->propGetInt(in, "sharp", 0, &err)); // pel2 interpolation type if (err) d.sharp = SharpWiener; d.rfilter = int64ToIntS(vsapi->propGetInt(in, "rfilter", 0, &err)); if (err) d.rfilter = RfilterBilinear; d.opt = !!vsapi->propGetInt(in, "opt", 0, &err); if (err) d.opt = 1; if ((d.nPel != 1) && (d.nPel != 2) && (d.nPel != 4)) { vsapi->setError(out, "Super: pel must be 1, 2, or 4."); return; } if (d.sharp < SharpBilinear || d.sharp > SharpWiener) { vsapi->setError(out, "Super: sharp must be between 0 and 2 (inclusive)."); return; } if (d.rfilter < RfilterSimple || d.rfilter > RfilterCubic) { vsapi->setError(out, "Super: rfilter must be between 0 and 4 (inclusive)."); return; } d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = *vsapi->getVideoInfo(d.node); d.nWidth = d.vi.width; d.nHeight = d.vi.height; if (!isConstantFormat(&d.vi) || d.vi.format->bitsPerSample > 16 || d.vi.format->sampleType != stInteger || d.vi.format->subSamplingW > 1 || d.vi.format->subSamplingH > 1 || (d.vi.format->colorFamily != cmYUV && d.vi.format->colorFamily != cmGray)) { vsapi->setError(out, "Super: input clip must be GRAY, 420, 422, 440, or 444, up to 16 bits, with constant dimensions."); vsapi->freeNode(d.node); return; } if (d.vi.format->colorFamily == cmGray) d.chroma = 0; d.nModeYUV = d.chroma ? YUVPLANES : YPLANE; d.xRatioUV = 1 << d.vi.format->subSamplingW; d.yRatioUV = 1 << d.vi.format->subSamplingH; int nLevelsMax = 0; while (PlaneHeightLuma(d.vi.height, nLevelsMax, d.yRatioUV, d.nVPad) >= d.yRatioUV * 2 && PlaneWidthLuma(d.vi.width, nLevelsMax, d.xRatioUV, d.nHPad) >= d.xRatioUV * 2) // at last two pixels width and height of chroma { nLevelsMax++; } if (d.nLevels <= 0 || d.nLevels > nLevelsMax) d.nLevels = nLevelsMax; d.pelclip = vsapi->propGetNode(in, "pelclip", 0, &err); const VSVideoInfo *pelvi = d.pelclip ? vsapi->getVideoInfo(d.pelclip) : NULL; if (d.pelclip && (!isConstantFormat(pelvi) || pelvi->format != d.vi.format)) { vsapi->setError(out, "Super: pelclip must have the same format as the input clip, and it must have constant dimensions."); vsapi->freeNode(d.node); vsapi->freeNode(d.pelclip); return; } d.usePelClip = 0; if (d.pelclip && (d.nPel >= 2)) { if ((pelvi->width == d.vi.width * d.nPel) && (pelvi->height == d.vi.height * d.nPel)) { d.usePelClip = 1; d.isPelClipPadded = 0; } else if ((pelvi->width == (d.vi.width + d.nHPad * 2) * d.nPel) && (pelvi->height == (d.vi.height + d.nVPad * 2) * d.nPel)) { d.usePelClip = 1; d.isPelClipPadded = 1; } else { vsapi->setError(out, "Super: pelclip's dimensions must be multiples of the input clip's dimensions."); vsapi->freeNode(d.pelclip); vsapi->freeNode(d.node); return; } } d.nSuperWidth = d.nWidth + 2 * d.nHPad; d.nSuperHeight = PlaneSuperOffset(0, d.nHeight, d.nLevels, d.nPel, d.nVPad, d.nSuperWidth, d.yRatioUV) / d.nSuperWidth; if (d.yRatioUV == 2 && d.nSuperHeight & 1) d.nSuperHeight++; // even if (d.xRatioUV == 2 && d.nSuperWidth & 1) d.nSuperWidth++; d.vi.width = d.nSuperWidth; d.vi.height = d.nSuperHeight; data = (MVSuperData *)malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "Super", mvsuperInit, mvsuperGetFrame, mvsuperFree, fmParallel, 0, data, core); }
int main(int argc, char **argv) { const VSAPI *vsapi = NULL; VSScript *se = NULL; FILE *outFile = NULL; if (argc != 3) { fprintf(stderr, "Usage: vsscript_example <infile> <outfile>\n"); return 1; } // Open the output file for writing outFile = fopen(argv[2], "wb"); if (!outFile) { fprintf(stderr, "Failed to open output for writing\n"); return 1; } // Initialize VSScript, vsscript_finalize() needs to be called the same number of times as vsscript_init() if (!vsscript_init()) { // VapourSynth probably isn't properly installed at all fprintf(stderr, "Failed to initialize VapourSynth environment\n"); return 1; } // Get a pointer to the normal api struct, exists so you don't have to link with the VapourSynth core library // Failure only happens on very rare API version mismatches vsapi = vsscript_getVSApi(); assert(vsapi); // This line does the actual script evaluation. If se = NULL it will create a new environment if (vsscript_evaluateFile(&se, argv[1], 0)) { fprintf(stderr, "Script evaluation failed:\n%s", vsscript_getError(se)); vsscript_freeScript(se); vsscript_finalize(); return 1; } // Get the clip set as output. It is valid until the out index is re-set/cleared/the script is freed VSNodeRef *node = vsscript_getOutput(se, 0); if (!node) { fprintf(stderr, "Failed to retrieve output node\n"); vsscript_freeScript(se); vsscript_finalize(); return 1; } // Reject hard to handle formats const VSVideoInfo *vi = vsapi->getVideoInfo(node); if (!isConstantFormat(vi) || !vi->numFrames) { fprintf(stderr, "Cannot output clips with varying dimensions or unknown length\n"); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return 1; } // Output all frames char errMsg[1024]; int error = 0; for (int n = 0; n < vi->numFrames; n++) { const VSFrameRef *frame = vsapi->getFrame(n, node, errMsg, sizeof(errMsg)); if (!frame) { // Check if an error happened when getting the frame error = 1; break; } // Loop over every row of every plane write to the file for (int p = 0; p < vi->format->numPlanes; p++) { int stride = vsapi->getStride(frame, p); const uint8_t *readPtr = vsapi->getReadPtr(frame, p); int rowSize = vsapi->getFrameWidth(frame, p) * vi->format->bytesPerSample; int height = vsapi->getFrameHeight(frame, p); for (int y = 0; y < height; y++) { // You should probably handle any fwrite errors here as well fwrite(readPtr, rowSize, 1, outFile); readPtr += stride; } } vsapi->freeFrame(frame); } // Cleanup fclose(outFile); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); if (error) { fprintf(stderr, "%s", errMsg); return 1; } return 0; }
int VBM3D_Data_Base::arguments_process(const VSMap *in, VSMap *out) { int error; int m; // input - clip node = vsapi->propGetNode(in, "input", 0, nullptr); vi = vsapi->getVideoInfo(node); if (!isConstantFormat(vi)) { setError(out, "Invalid input clip, only constant format input supported"); return 1; } if ((vi->format->sampleType == stInteger && vi->format->bitsPerSample > 16) || (vi->format->sampleType == stFloat && vi->format->bitsPerSample != 32)) { setError(out, "Invalid input clip, only 8-16 bit integer or 32 bit float formats supported"); return 1; } // ref - clip rnode = vsapi->propGetNode(in, "ref", 0, &error); if (error) { rdef = false; rnode = node; rvi = vi; } else { rdef = true; rvi = vsapi->getVideoInfo(rnode); if (!isConstantFormat(rvi)) { setError(out, "Invalid clip \"ref\", only constant format input supported"); return 1; } if (rvi->format != vi->format) { setError(out, "input clip and clip \"ref\" must be of the same format"); return 1; } if (rvi->width != vi->width || rvi->height != vi->height) { setError(out, "input clip and clip \"ref\" must be of the same width and height"); return 1; } if (rvi->numFrames != vi->numFrames) { setError(out, "input clip and clip \"ref\" must have the same number of frames"); return 1; } } // profile - data auto profile = vsapi->propGetData(in, "profile", 0, &error); if (error) { para.profile = para_default.profile; } else { para.profile = profile; } if (para.profile != "fast" && para.profile != "lc" && para.profile != "np" && para.profile != "high" && para.profile != "vn") { setError(out, "Unrecognized \"profile\" specified, should be \"fast\", \"lc\", \"np\", \"high\" or \"vn\""); return 1; } get_default_para(para.profile); // sigma - float[] m = vsapi->propNumElements(in, "sigma"); if (m > 0) { int i; if (m > 3) m = 3; for (i = 0; i < m; ++i) { para.sigma[i] = vsapi->propGetFloat(in, "sigma", i, nullptr); if (para.sigma[i] < 0) { setError(out, "Invalid \"sigma\" assigned, must be a non-negative floating point number"); return 1; } } for (; i < 3; ++i) { para.sigma[i] = para.sigma[i - 1]; } } else { para.sigma = para_default.sigma; } // radius - int para.radius = int64ToIntS(vsapi->propGetInt(in, "radius", 0, &error)); if (error) { para.radius = para_default.radius; } else if (para.radius < 1 || para.radius > 16) { setError(out, "Invalid \"radius\" assigned, must be an integer in [1, 16]"); return 1; } // block_size - int para.BlockSize = int64ToIntS(vsapi->propGetInt(in, "block_size", 0, &error)); if (error) { para.BlockSize = para_default.BlockSize; } else if (para.BlockSize < 1 || para.BlockSize > 64) { setError(out, "Invalid \"block_size\" assigned, must be an integer in [1, 64]"); return 1; } else if (para.BlockSize > vi->width || para.BlockSize > vi->height) { setError(out, "Invalid \"block_size\" assigned, must not exceed width or height of the frame"); return 1; } // block_step - int para.BlockStep = int64ToIntS(vsapi->propGetInt(in, "block_step", 0, &error)); if (error) { para.BlockStep = para_default.BlockStep; } else if (para.BlockStep < 1 || para.BlockStep > para.BlockSize) { setError(out, "Invalid \"block_step\" assigned, must be an integer in [1, block_size]"); return 1; } // group_size - int para.GroupSize = int64ToIntS(vsapi->propGetInt(in, "group_size", 0, &error)); if (error) { para.GroupSize = para_default.GroupSize; } else if (para.GroupSize < 1 || para.GroupSize > 256) { setError(out, "Invalid \"group_size\" assigned, must be an integer in [1, 256]"); return 1; } // bm_range - int para.BMrange = int64ToIntS(vsapi->propGetInt(in, "bm_range", 0, &error)); if (error) { para.BMrange = para_default.BMrange; } else if (para.BMrange < 1) { setError(out, "Invalid \"bm_range\" assigned, must be a positive integer"); return 1; } // bm_step - int para.BMstep = int64ToIntS(vsapi->propGetInt(in, "bm_step", 0, &error)); if (error) { para.BMstep = para_default.BMstep; } else if (para.BMstep < 1 || para.BMstep > para.BMrange) { setError(out, "Invalid \"bm_step\" assigned, must be an integer in [1, bm_range]"); return 1; } // ps_num - int para.PSnum = int64ToIntS(vsapi->propGetInt(in, "ps_num", 0, &error)); if (error) { para.PSnum = para_default.PSnum; } else if (para.PSnum < 1 || para.PSnum > para.GroupSize) { setError(out, "Invalid \"ps_num\" assigned, must be an integer in [1, group_size]"); return 1; } // ps_range - int para.PSrange = int64ToIntS(vsapi->propGetInt(in, "ps_range", 0, &error)); if (error) { para.PSrange = para_default.PSrange; } else if (para.PSrange < 1) { setError(out, "Invalid \"ps_range\" assigned, must be a positive integer"); return 1; } // ps_step - int para.PSstep = int64ToIntS(vsapi->propGetInt(in, "ps_step", 0, &error)); if (error) { para.PSstep = para_default.PSstep; } else if (para.PSstep < 1 || para.PSstep > para.PSrange) { setError(out, "Invalid \"ps_step\" assigned, must be an integer in [1, ps_range]"); return 1; } // th_mse - float para.thMSE = vsapi->propGetFloat(in, "th_mse", 0, &error); if (error) { para.thMSE_Default(); } else if (para.thMSE <= 0) { setError(out, "Invalid \"th_mse\" assigned, must be a positive floating point number"); return 1; } // matrix - int matrix = static_cast<ColorMatrix>(vsapi->propGetInt(in, "matrix", 0, &error)); if (vi->format->colorFamily == cmRGB) { matrix = ColorMatrix::OPP; } else if (vi->format->colorFamily == cmYCoCg) { matrix = ColorMatrix::YCgCo; } else if (error || matrix == ColorMatrix::Unspecified) { matrix = ColorMatrix_Default(vi->width, vi->height); } else if (matrix != ColorMatrix::GBR && matrix != ColorMatrix::bt709 && matrix != ColorMatrix::fcc && matrix != ColorMatrix::bt470bg && matrix != ColorMatrix::smpte170m && matrix != ColorMatrix::smpte240m && matrix != ColorMatrix::YCgCo && matrix != ColorMatrix::bt2020nc && matrix != ColorMatrix::bt2020c && matrix != ColorMatrix::OPP) { setError(out, "Unsupported \"matrix\" specified"); return 1; } // process for (int i = 0; i < VSMaxPlaneCount; i++) { if (vi->format->colorFamily != cmRGB && para.sigma[i] == 0) { process[i] = 0; } } if (process[1] || process[2]) { if (vi->format->subSamplingH || vi->format->subSamplingW) { setError(out, "input clip: sub-sampled format is not supported when chroma is processed, convert it to YUV444 or RGB first. " "For the best quality, RGB colorspace is recommended as input."); return 1; } if (rvi->format->subSamplingH || rvi->format->subSamplingW) { setError(out, "clip \"ref\": sub-sampled format is not supported when chroma is processed, convert it to YUV444 or RGB first. " "For the best quality, RGB colorspace is recommended as input."); return 1; } } return 0; }
static void VS_CC vs_colorspace_create(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { vs_colorspace_data *data = 0; zimg_colorspace_params params; zimg_filter *filter = 0; char fail_str[1024]; VSNodeRef *node = 0; const VSVideoInfo *node_vi; const VSFormat *node_fmt; VSVideoInfo vi; node = vsapi->propGetNode(in, "clip", 0, 0); node_vi = vsapi->getVideoInfo(node); node_fmt = node_vi->format; if (!isConstantFormat(node_vi)) { strcpy(fail_str, "clip must have a defined format"); goto fail; } if (node_fmt->numPlanes < 3 || node_fmt->subSamplingW || node_fmt->subSamplingH) { strcpy(fail_str, "colorspace conversion can only be performed on 4:4:4 clips"); goto fail; } zimg2_colorspace_params_default(¶ms, ZIMG_API_VERSION); params.width = node_vi->width; params.height = node_vi->height; params.matrix_in = (int)vsapi->propGetInt(in, "matrix_in", 0, 0); params.transfer_in = (int)vsapi->propGetInt(in, "transfer_in", 0, 0); params.primaries_in = (int)vsapi->propGetInt(in, "primaries_in", 0, 0); params.matrix_out = (int)propGetIntDefault(vsapi, in, "matrix_out", 0, params.matrix_in); params.transfer_out = (int)propGetIntDefault(vsapi, in, "transfer_out", 0, params.transfer_in); params.primaries_out = (int)propGetIntDefault(vsapi, in, "primaries_out", 0, params.primaries_in); params.pixel_type = translate_pixel(node_fmt); params.depth = node_fmt->bitsPerSample; params.range_in = (int)!!propGetIntDefault(vsapi, in, "fullrange_in", 0, params.matrix_in == ZIMG_MATRIX_RGB ? ZIMG_RANGE_FULL : ZIMG_RANGE_LIMITED); params.range_out = (int)!!propGetIntDefault(vsapi, in, "fullrange_out", 0, params.matrix_out == ZIMG_MATRIX_RGB ? ZIMG_RANGE_FULL : ZIMG_RANGE_LIMITED); vi = *node_vi; vi.format = vsapi->registerFormat(params.matrix_out == ZIMG_MATRIX_RGB ? cmRGB : cmYUV, node_fmt->sampleType, node_fmt->bitsPerSample, node_fmt->subSamplingW, node_fmt->subSamplingH, core); if (!(filter = zimg2_colorspace_create(¶ms))) { zimg_get_last_error(fail_str, sizeof(fail_str)); goto fail; } if (!(data = malloc(sizeof(*data)))) { strcpy(fail_str, "error allocating vs_colorspace_data"); goto fail; } data->filter = filter; data->node = node; data->vi = vi; data->matrix_out = params.matrix_out; data->transfer_out = params.transfer_out; data->primaries_out = params.primaries_out; vsapi->createFilter(in, out, "colorspace", vs_colorspace_init, vs_colorspace_get_frame, vs_colorspace_free, fmParallel, 0, data, core); return; fail: vsapi->setError(out, fail_str); vsapi->freeNode(node); zimg2_filter_free(filter); free(data); }
static void VS_CC exprCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { JitExprData d; JitExprData *data; int err; try { for (int i = 0; i < 3; i++) d.node[i] = vsapi->propGetNode(in, "clips", i, &err); const VSVideoInfo *vi[3]; for (int i = 0; i < 3; i++) if (d.node[i]) vi[i] = vsapi->getVideoInfo(d.node[i]); else vi[i] = NULL; for (int i = 0; i < 3; i++) { if (vi[i]) { if (!isConstantFormat(vi[i])) throw std::runtime_error("Only constant format input allowed"); if (vi[0]->format->numPlanes != vi[i]->format->numPlanes || vi[0]->format->subSamplingW != vi[i]->format->subSamplingW || vi[0]->format->subSamplingH != vi[i]->format->subSamplingH || vi[0]->width != vi[i]->width || vi[0]->height != vi[i]->height) throw std::runtime_error("All inputs must have the same number of planes and the same dimensions, subsampling included"); if ((vi[i]->format->bitsPerSample > 16 && vi[i]->format->sampleType == stInteger) || vi[i]->format->bitsPerSample != 32 && vi[i]->format->sampleType == stFloat) throw std::runtime_error("Input clips must be 8-16 bit integer or 32 bit float format"); } } d.vi = *vi[0]; int format = int64ToIntS(vsapi->propGetInt(in, "format", 0, &err)); if (!err) { const VSFormat *f = vsapi->getFormatPreset(format, core); if (f) { if (d.vi.format->colorFamily == cmCompat) throw std::runtime_error("No compat formats allowed"); if (d.vi.format->numPlanes != f->numPlanes) throw std::runtime_error("The number of planes in the inputs and output must match"); d.vi.format = vsapi->registerFormat(d.vi.format->colorFamily, f->sampleType, f->bitsPerSample, d.vi.format->subSamplingW, d.vi.format->subSamplingH, core); } } int nexpr = vsapi->propNumElements(in, "expr"); if (nexpr > d.vi.format->numPlanes) throw std::runtime_error("More expressions given than there are planes"); std::string expr[3]; for (int i = 0; i < nexpr; i++) expr[i] = vsapi->propGetData(in, "expr", i, 0); if (nexpr == 1) { expr[1] = expr[0]; expr[2] = expr[0]; } else if (nexpr == 2) { expr[2] = expr[1]; } for (int i = 0; i < 3; i++) { if (!expr[i].empty()) { d.plane[i] = poProcess; } else { if (d.vi.format->bitsPerSample == vi[0]->format->bitsPerSample && d.vi.format->sampleType == vi[0]->format->sampleType) d.plane[i] = poCopy; else d.plane[i] = poUndefined; } } const SOperation sop[3] = { getLoadOp(vi[0]), getLoadOp(vi[1]), getLoadOp(vi[2]) }; int maxStackSize = 0; for (int i = 0; i < d.vi.format->numPlanes; i++) maxStackSize = std::max(parseExpression(expr[i], d.ops[i], sop, getStoreOp(&d.vi)), maxStackSize); #ifdef VS_TARGET_CPU_X86 d.stack = vs_aligned_malloc<void>(maxStackSize * 32, 32); #else d.stack.resize(maxStackSize); #endif } catch (std::runtime_error &e) { for (int i = 0; i < 3; i++) vsapi->freeNode(d.node[i]); std::string s = "Expr: "; s += e.what(); vsapi->setError(out, s.c_str()); return; } data = new JitExprData(); *data = d; vsapi->createFilter(in, out, "Expr", exprInit, exprGetFrame, exprFree, fmParallelRequests, 0, data, core); }
static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) { vs_hnd_t *h = new vs_hnd_t; if( !h ) return -1; FILE *fh = x264_fopen(psz_filename, "rb"); if (!fh) return -1; int b_regular = x264_is_regular_file(fh); fclose(fh); FAIL_IF_ERROR(!b_regular, "VS input is incompatible with non-regular file `%s'\n", psz_filename); FAIL_IF_ERROR(!vsscript_init(), "Failed to initialize VapourSynth environment\n"); h->vsapi = vsscript_getVSApi(); if (!h->vsapi) { fprintf(stderr, "Failed to get VapourSynth API pointer\n"); vsscript_finalize(); return -1; } // Should always succeed if (vsscript_createScript(&h->se)) { fprintf(stderr, "Script environment initialization failed:\n%s\n", vsscript_getError(h->se)); vsscript_freeScript(h->se); vsscript_finalize(); return -1; } std::string strfilename = psz_filename; nstring scriptFilename = s2ws(strfilename); if (vsscript_evaluateFile(&h->se, nstringToUtf8(scriptFilename).c_str(), efSetWorkingDir)) { fprintf(stderr, "Script evaluation failed:\n%s\n", vsscript_getError(h->se)); vsscript_freeScript(h->se); vsscript_finalize(); return -1; } h->node = vsscript_getOutput(h->se, 0);//outputIndex if (!h->node) { fprintf(stderr, "Failed to retrieve output node. Invalid index specified?\n"); vsscript_freeScript(h->se); vsscript_finalize(); return -1; } const VSCoreInfo *vsInfo = h->vsapi->getCoreInfo(vsscript_getCore(h->se)); h->sea = new semaphore(vsInfo->numThreads); const VSVideoInfo *vi = h->vsapi->getVideoInfo(h->node); if (vi->format->colorFamily != cmYUV) { fprintf(stderr, "Can only read YUV format clips"); h->vsapi->freeNode(h->node); vsscript_freeScript(h->se); vsscript_finalize(); return -1; } if (!isConstantFormat(vi)) { fprintf(stderr, "Cannot output clips with varying dimensions\n"); h->vsapi->freeNode(h->node); vsscript_freeScript(h->se); vsscript_finalize(); return -1; } info->width = vi->width; info->height = vi->height; info->fps_num = vi->fpsNum; info->fps_den = vi->fpsDen; info->thread_safe = 1; info->num_frames = vi->numFrames; if (vi->format->subSamplingW == 1 && vi->format->subSamplingH == 1) info->csp = X264_CSP_I420; else if (vi->format->subSamplingW == 1 && vi->format->subSamplingH == 0) info->csp = X264_CSP_I422; else if (vi->format->subSamplingW == 0 && vi->format->subSamplingH == 0) info->csp = X264_CSP_I444; h->bit_depth = vi->format->bitsPerSample; if (h->bit_depth > 8) { info->csp |= X264_CSP_HIGH_DEPTH; } *p_handle = (void*)h; return 0; }
static int reinit_vs(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; VSMap *vars = NULL, *in = NULL, *out = NULL; int res = -1; destroy_vs(vf); MP_DBG(vf, "initializing...\n"); // First load an empty script to get a VSScript, so that we get the vsapi // and vscore. if (vsscript_evaluateScript(&p->se, "", NULL, 0)) goto error; p->vsapi = vsscript_getVSApi(); p->vscore = vsscript_getCore(p->se); if (!p->vsapi || !p->vscore) goto error; in = p->vsapi->createMap(); out = p->vsapi->createMap(); vars = p->vsapi->createMap(); if (!in || !out || !vars) goto error; p->vsapi->createFilter(in, out, "Input", infiltInit, infiltGetFrame, infiltFree, fmSerial, 0, vf, p->vscore); int vserr; p->in_node = p->vsapi->propGetNode(out, "clip", 0, &vserr); if (!p->in_node) goto error; if (p->vsapi->propSetNode(vars, "video_in", p->in_node, 0)) goto error; vsscript_setVariable(p->se, vars); if (vsscript_evaluateFile(&p->se, p->cfg_file, 0)) { MP_FATAL(vf, "Script evaluation failed:\n%s\n", vsscript_getError(p->se)); goto error; } p->out_node = vsscript_getOutput(p->se, 0); if (!p->out_node) goto error; const VSVideoInfo *vi = p->vsapi->getVideoInfo(p->out_node); if (!isConstantFormat(vi)) { MP_FATAL(vf, "Video format is required to be constant.\n"); goto error; } MP_DBG(vf, "initialized.\n"); res = 0; error: if (p->vsapi) { p->vsapi->freeMap(in); p->vsapi->freeMap(out); p->vsapi->freeMap(vars); } if (res < 0) destroy_vs(vf); return res; }
static void VS_CC vszimg_create(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { struct vszimg_data *data = NULL; const VSVideoInfo *node_vi; const VSFormat *node_fmt; int format_id; char err_msg[64]; #define FAIL_BAD_VALUE(name) \ do { \ sprintf(err_msg, "%s: bad value", (name)); \ goto fail; \ } while (0) #define TRY_GET_ENUM(name, out, flag, table) \ do { \ int enum_tmp; \ if (tryGetEnum(vsapi, in, (name), &enum_tmp, &(flag), (table), ARRAY_SIZE((table)))) \ FAIL_BAD_VALUE(name); \ if ((flag)) \ (out) = enum_tmp; \ } while (0) #define TRY_GET_ENUM_STR(name, out, table) \ do { \ int enum_tmp; \ vszimg_bool flag; \ if (tryGetEnumStr(vsapi, in, (name), &enum_tmp, &flag, (table), ARRAY_SIZE((table)))) \ FAIL_BAD_VALUE(name); \ if ((flag)) \ (out) = enum_tmp; \ } while (0) if (!(data = malloc(sizeof(*data)))) { sprintf(err_msg, "error allocating vszimg_data"); goto fail; } _vszimg_default_init(data); if (vszimg_mutex_init(&data->graph_mutex)) { sprintf(err_msg, "error initializing mutex"); goto fail; } data->graph_mutex_initialized = VSZIMG_TRUE; data->node = vsapi->propGetNode(in, "clip", 0, NULL); node_vi = vsapi->getVideoInfo(data->node); node_fmt = node_vi->format; data->vi = *node_vi; zimg_graph_builder_params_default(&data->params, ZIMG_API_VERSION); if (propGetUintDef(vsapi, in, "width", &data->vi.width, node_vi->width)) FAIL_BAD_VALUE("width"); if (propGetUintDef(vsapi, in, "height", &data->vi.height, node_vi->height)) FAIL_BAD_VALUE("height"); if (propGetSintDef(vsapi, in, "format", &format_id, pfNone)) FAIL_BAD_VALUE("format"); data->vi.format = (format_id == pfNone) ? node_fmt : vsapi->getFormatPreset(format_id, core); TRY_GET_ENUM("matrix", data->matrix, data->have_matrix, g_matrix_table); TRY_GET_ENUM("transfer", data->transfer, data->have_transfer, g_transfer_table); TRY_GET_ENUM("primaries", data->primaries, data->have_primaries, g_primaries_table); TRY_GET_ENUM("range", data->range, data->have_range, g_range_table); TRY_GET_ENUM("chromaloc", data->chromaloc, data->have_chromaloc, g_chromaloc_table); TRY_GET_ENUM("matrix_in", data->matrix_in, data->have_matrix_in, g_matrix_table); TRY_GET_ENUM("transfer_in", data->transfer_in, data->have_transfer_in, g_transfer_table); TRY_GET_ENUM("primaries_in", data->primaries_in, data->have_primaries_in, g_primaries_table); TRY_GET_ENUM("range_in", data->range_in, data->have_range_in, g_range_table); TRY_GET_ENUM("chromaloc_in", data->chromaloc_in, data->have_chromaloc_in, g_chromaloc_table); TRY_GET_ENUM_STR("resample_filter", data->params.resample_filter, g_resample_filter_table); data->params.filter_param_a = propGetFloatDef(vsapi, in, "filter_param_a", data->params.filter_param_a); data->params.filter_param_b = propGetFloatDef(vsapi, in, "filter_param_b", data->params.filter_param_b); TRY_GET_ENUM_STR("resample_filter_uv", data->params.resample_filter_uv, g_resample_filter_table); data->params.filter_param_a_uv = propGetFloatDef(vsapi, in, "filter_param_a_uv", data->params.filter_param_a_uv); data->params.filter_param_b_uv = propGetFloatDef(vsapi, in, "filter_param_b_uv", data->params.filter_param_b_uv); TRY_GET_ENUM_STR("dither_type", data->params.dither_type, g_dither_type_table); TRY_GET_ENUM_STR("cpu_type", data->params.cpu_type, g_cpu_type_table); #undef FAIL_BAD_VALUE #undef TRY_GET_ENUM #undef TRY_GET_ENUM_STR /* Basic compatibility check. */ if (isConstantFormat(node_vi) && isConstantFormat(&data->vi)) { zimg_image_format src_format; zimg_image_format dst_format; zimg_image_format_default(&src_format, ZIMG_API_VERSION); zimg_image_format_default(&dst_format, ZIMG_API_VERSION); src_format.width = node_vi->width; src_format.height = node_vi->height; dst_format.width = data->vi.width; dst_format.height = data->vi.height; if (translate_vsformat(node_vi->format, &src_format, err_msg)) goto fail; if (translate_vsformat(data->vi.format, &dst_format, err_msg)) goto fail; } vsapi->createFilter(in, out, "format", vszimg_init, vszimg_get_frame, vszimg_free, fmParallel, 0, data, core); return; fail: vsapi->setError(out, err_msg); _vszimg_destroy(data, vsapi); free(data); }
static void VS_CC mvflowfpsCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { MVFlowFPSData d; MVFlowFPSData *data; int err; d.num = vsapi->propGetInt(in, "num", 0, &err); if (err) d.num = 25; d.den = vsapi->propGetInt(in, "den", 0, &err); if (err) d.den = 1; d.maskmode = int64ToIntS(vsapi->propGetInt(in, "mask", 0, &err)); if (err) d.maskmode = 2; d.ml = vsapi->propGetFloat(in, "ml", 0, &err); if (err) d.ml = 100.0; d.blend = !!vsapi->propGetInt(in, "blend", 0, &err); if (err) d.blend = 1; d.thscd1 = int64ToIntS(vsapi->propGetInt(in, "thscd1", 0, &err)); if (err) d.thscd1 = MV_DEFAULT_SCD1; d.thscd2 = int64ToIntS(vsapi->propGetInt(in, "thscd2", 0, &err)); if (err) d.thscd2 = MV_DEFAULT_SCD2; d.isse = !!vsapi->propGetInt(in, "isse", 0, &err); if (err) d.isse = 1; if (d.maskmode < 0 || d.maskmode > 2) { vsapi->setError(out, "FlowFPS: mask must be 0, 1, or 2."); return; } if (d.ml <= 0.0) { vsapi->setError(out, "FlowFPS: ml must be greater than 0."); return; } d.super = vsapi->propGetNode(in, "super", 0, NULL); char errorMsg[1024]; const VSFrameRef *evil = vsapi->getFrame(0, d.super, errorMsg, 1024); if (!evil) { vsapi->setError(out, std::string("FlowFPS: failed to retrieve first frame from super clip. Error message: ").append(errorMsg).c_str()); vsapi->freeNode(d.super); return; } const VSMap *props = vsapi->getFramePropsRO(evil); int evil_err[2]; int nHeightS = int64ToIntS(vsapi->propGetInt(props, "Super_height", 0, &evil_err[0])); d.nSuperHPad = int64ToIntS(vsapi->propGetInt(props, "Super_hpad", 0, &evil_err[1])); vsapi->freeFrame(evil); for (int i = 0; i < 2; i++) if (evil_err[i]) { vsapi->setError(out, "FlowFPS: required properties not found in first frame of super clip. Maybe clip didn't come from mv.Super? Was the first frame trimmed away?"); vsapi->freeNode(d.super); return; } d.mvbw = vsapi->propGetNode(in, "mvbw", 0, NULL); d.mvfw = vsapi->propGetNode(in, "mvfw", 0, NULL); // XXX F**k all this trying. try { d.mvClipB = new MVClipDicks(d.mvbw, d.thscd1, d.thscd2, vsapi); } catch (MVException &e) { vsapi->setError(out, std::string("FlowFPS: ").append(e.what()).c_str()); vsapi->freeNode(d.super); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.mvfw); return; } try { d.mvClipF = new MVClipDicks(d.mvfw, d.thscd1, d.thscd2, vsapi); } catch (MVException &e) { vsapi->setError(out, std::string("FlowFPS: ").append(e.what()).c_str()); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); delete d.mvClipB; return; } // XXX Alternatively, use both clips' delta as offsets in GetFrame. if (d.mvClipF->GetDeltaFrame() != d.mvClipB->GetDeltaFrame()) { vsapi->setError(out, "FlowFPS: mvbw and mvfw must be generated with the same delta."); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); delete d.mvClipB; delete d.mvClipF; return; } // Make sure the motion vector clips are correct. if (!d.mvClipB->IsBackward() || d.mvClipF->IsBackward()) { if (!d.mvClipB->IsBackward()) vsapi->setError(out, "FlowFPS: mvbw must be generated with isb=True."); else vsapi->setError(out, "FlowFPS: mvfw must be generated with isb=False."); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); delete d.mvClipB; delete d.mvClipF; return; } try { d.bleh = new MVFilter(d.mvfw, "FlowFPS", vsapi); } catch (MVException &e) { vsapi->setError(out, std::string("FlowFPS: ").append(e.what()).c_str()); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); delete d.mvClipB; delete d.mvClipF; return; } try { // So it checks the similarity of mvfw and mvfw? ????? // Copied straight from 2.5.11.3... d.bleh->CheckSimilarity(d.mvClipF, "mvfw"); d.bleh->CheckSimilarity(d.mvClipB, "mvbw"); } catch (MVException &e) { vsapi->setError(out, std::string("FlowFPS: ").append(e.what()).c_str()); delete d.bleh; delete d.mvClipB; delete d.mvClipF; vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); return; } if (d.bleh->nPel == 1) d.finest = vsapi->cloneNodeRef(d.super); // v2.0.9.1 else { VSPlugin *mvtoolsPlugin = vsapi->getPluginById("com.nodame.mvtools", core); VSPlugin *stdPlugin = vsapi->getPluginById("com.vapoursynth.std", core); VSMap *args = vsapi->createMap(); vsapi->propSetNode(args, "super", d.super, paReplace); vsapi->propSetInt(args, "isse", d.isse, paReplace); VSMap *ret = vsapi->invoke(mvtoolsPlugin, "Finest", args); if (vsapi->getError(ret)) { vsapi->setError(out, std::string("FlowFPS: ").append(vsapi->getError(ret)).c_str()); delete d.bleh; delete d.mvClipB; delete d.mvClipF; vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeMap(args); vsapi->freeMap(ret); return; } d.finest = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); vsapi->clearMap(args); vsapi->propSetNode(args, "clip", d.finest, paReplace); vsapi->freeNode(d.finest); ret = vsapi->invoke(stdPlugin, "Cache", args); vsapi->freeMap(args); if (vsapi->getError(ret)) { // prefix the error messages vsapi->setError(out, std::string("FlowFPS: ").append(vsapi->getError(ret)).c_str()); delete d.bleh; delete d.mvClipB; delete d.mvClipF; vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeMap(ret); return; } d.finest = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); } d.node = vsapi->propGetNode(in, "clip", 0, 0); d.vi = *vsapi->getVideoInfo(d.node); if (d.vi.fpsNum == 0 || d.vi.fpsDen == 0) { vsapi->setError(out, "FlowFPS: The input clip must have a frame rate. Invoke AssumeFPS if necessary."); vsapi->freeNode(d.finest); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); delete d.bleh; delete d.mvClipB; delete d.mvClipF; return; } int64_t numeratorOld = d.vi.fpsNum; int64_t denominatorOld = d.vi.fpsDen; int64_t numerator, denominator; if (d.num != 0 && d.den != 0) { numerator = d.num; denominator = d.den; } else { numerator = numeratorOld * 2; // double fps by default denominator = denominatorOld; } // safe for big numbers since v2.1 d.fa = denominator * numeratorOld; d.fb = numerator * denominatorOld; int64_t fgcd = gcd(d.fa, d.fb); // general common divisor d.fa /= fgcd; d.fb /= fgcd; setFPS(&d.vi, numerator, denominator); if (d.vi.numFrames) d.vi.numFrames = (int)(1 + (d.vi.numFrames - 1) * d.fb / d.fa); if (d.bleh->nWidth != d.vi.width || d.bleh->nHeight != d.vi.height) { vsapi->setError(out, "FlowFPS: inconsistent source and vector frame size."); vsapi->freeNode(d.finest); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); delete d.bleh; delete d.mvClipB; delete d.mvClipF; return; } const VSVideoInfo *supervi = vsapi->getVideoInfo(d.super); int nSuperWidth = supervi->width; if (d.bleh->nHeight != nHeightS || d.bleh->nWidth != nSuperWidth - d.nSuperHPad * 2) { vsapi->setError(out, "FlowFPS: wrong source or super clip frame size."); vsapi->freeNode(d.finest); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); delete d.bleh; delete d.mvClipB; delete d.mvClipF; return; } if (!((d.bleh->nWidth + d.bleh->nHPadding*2) == supervi->width && (d.bleh->nHeight + d.bleh->nVPadding*2) <= supervi->height)) { vsapi->setError(out, "FlowFPS: inconsistent clips frame size! Incomprehensible error messages are the best, right?"); vsapi->freeNode(d.finest); vsapi->freeNode(d.super); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); delete d.bleh; delete d.mvClipB; delete d.mvClipF; return; } if (!isConstantFormat(&d.vi) || d.vi.format->bitsPerSample > 16 || d.vi.format->sampleType != stInteger || d.vi.format->subSamplingW > 1 || d.vi.format->subSamplingH > 1 || (d.vi.format->colorFamily != cmYUV && d.vi.format->colorFamily != cmGray)) { vsapi->setError(out, "FlowFPS: input clip must be GRAY, 420, 422, 440, or 444, up to 16 bits, with constant dimensions."); vsapi->freeNode(d.super); vsapi->freeNode(d.finest); vsapi->freeNode(d.mvfw); vsapi->freeNode(d.mvbw); vsapi->freeNode(d.node); delete d.bleh; delete d.mvClipB; delete d.mvClipF; return; } if (d.vi.format->bitsPerSample > 8) d.isse = 0; d.nBlkXP = (d.bleh->nBlkX * (d.bleh->nBlkSizeX - d.bleh->nOverlapX) + d.bleh->nOverlapX < d.bleh->nWidth) ? d.bleh->nBlkX + 1 : d.bleh->nBlkX; d.nBlkYP = (d.bleh->nBlkY * (d.bleh->nBlkSizeY - d.bleh->nOverlapY) + d.bleh->nOverlapY < d.bleh->nHeight) ? d.bleh->nBlkY + 1 : d.bleh->nBlkY; d.nWidthP = d.nBlkXP * (d.bleh->nBlkSizeX - d.bleh->nOverlapX) + d.bleh->nOverlapX; d.nHeightP = d.nBlkYP * (d.bleh->nBlkSizeY - d.bleh->nOverlapY) + d.bleh->nOverlapY; d.nWidthPUV = d.nWidthP / d.bleh->xRatioUV; d.nHeightPUV = d.nHeightP / d.bleh->yRatioUV; d.nHeightUV = d.bleh->nHeight / d.bleh->yRatioUV; d.nWidthUV = d.bleh->nWidth / d.bleh->xRatioUV; d.nHPaddingUV = d.bleh->nHPadding / d.bleh->xRatioUV; d.nVPaddingUV = d.bleh->nVPadding / d.bleh->yRatioUV; d.VPitchY = (d.nWidthP + 15) & (~15); d.VPitchUV = (d.nWidthPUV + 15) & (~15); d.VXFullYB = new uint8_t [d.nHeightP * d.VPitchY]; d.VYFullYB = new uint8_t [d.nHeightP * d.VPitchY]; d.VXFullYF = new uint8_t [d.nHeightP * d.VPitchY]; d.VYFullYF = new uint8_t [d.nHeightP * d.VPitchY]; d.VXSmallYB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallYB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VXSmallYF = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallYF = new uint8_t [d.nBlkXP * d.nBlkYP]; if (d.maskmode == 2) { d.VXFullYBB = new uint8_t [d.nHeightP * d.VPitchY]; d.VYFullYBB = new uint8_t [d.nHeightP * d.VPitchY]; d.VXFullYFF = new uint8_t [d.nHeightP * d.VPitchY]; d.VYFullYFF = new uint8_t [d.nHeightP * d.VPitchY]; d.VXSmallYBB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallYBB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VXSmallYFF = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallYFF = new uint8_t [d.nBlkXP * d.nBlkYP]; } d.MaskSmallB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.MaskFullYB = new uint8_t [d.nHeightP * d.VPitchY]; d.MaskSmallF = new uint8_t [d.nBlkXP * d.nBlkYP]; d.MaskFullYF = new uint8_t [d.nHeightP * d.VPitchY]; d.upsizer = new SimpleResize(d.nWidthP, d.nHeightP, d.nBlkXP, d.nBlkYP); if (d.vi.format->colorFamily != cmGray) { d.VXFullUVB = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VYFullUVB = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VXFullUVF = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VYFullUVF = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VXSmallUVB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallUVB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VXSmallUVF = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallUVF = new uint8_t [d.nBlkXP * d.nBlkYP]; if (d.maskmode == 2) { d.VXFullUVBB = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VYFullUVBB = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VXFullUVFF = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VYFullUVFF = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.VXSmallUVBB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallUVBB = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VXSmallUVFF = new uint8_t [d.nBlkXP * d.nBlkYP]; d.VYSmallUVFF = new uint8_t [d.nBlkXP * d.nBlkYP]; } d.MaskFullUVB = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.MaskFullUVF = new uint8_t [d.nHeightPUV * d.VPitchUV]; d.upsizerUV = new SimpleResize(d.nWidthPUV, d.nHeightPUV, d.nBlkXP, d.nBlkYP); } d.LUTVB = new int[256]; d.LUTVF = new int[256]; d.nleftLast = -1000; d.nrightLast = -1000; data = (MVFlowFPSData *)malloc(sizeof(d)); *data = d; // Can't use fmParallel because of nleftLast/nrightLast. vsapi->createFilter(in, out, "FlowFPS", mvflowfpsInit, mvflowfpsGetFrame, mvflowfpsFree, fmParallelRequests, 0, data, core); // AssumeFPS sets the _DurationNum and _DurationDen properties. VSNodeRef *node = vsapi->propGetNode(out, "clip", 0, NULL); VSMap *args = vsapi->createMap(); vsapi->propSetNode(args, "clip", node, paReplace); vsapi->freeNode(node); vsapi->propSetInt(args, "fpsnum", d.vi.fpsNum, paReplace); vsapi->propSetInt(args, "fpsden", d.vi.fpsDen, paReplace); VSPlugin *stdPlugin = vsapi->getPluginById("com.vapoursynth.std", core); VSMap *ret = vsapi->invoke(stdPlugin, "AssumeFPS", args); const char *error = vsapi->getError(ret); if (error) { vsapi->setError(out, std::string("FlowFPS: Failed to invoke AssumeFPS. Error message: ").append(error).c_str()); vsapi->freeMap(args); vsapi->freeMap(ret); return; } node = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); vsapi->clearMap(args); vsapi->propSetNode(args, "clip", node, paReplace); vsapi->freeNode(node); ret = vsapi->invoke(stdPlugin, "Cache", args); vsapi->freeMap(args); error = vsapi->getError(ret); if (error) { vsapi->setError(out, std::string("FlowFPS: Failed to invoke Cache. Error message: ").append(error).c_str()); vsapi->freeMap(ret); return; } node = vsapi->propGetNode(ret, "clip", 0, NULL); vsapi->freeMap(ret); vsapi->propSetNode(out, "clip", node, paReplace); vsapi->freeNode(node); }
int wmain(int argc, wchar_t **argv) { if (_setmode(_fileno(stdout), _O_BINARY) == -1) fprintf(stderr, "Failed to set stdout to binary mode\n"); SetConsoleCtrlHandler(HandlerRoutine, TRUE); #else int main(int argc, char **argv) { #endif if (argc == 2) { if (nstring(argv[1]) == NSTRING("-version")) { if (!vsscript_init()) { fprintf(stderr, "Failed to initialize VapourSynth environment\n"); return 1; } vsapi = vsscript_getVSApi(); if (!vsapi) { fprintf(stderr, "Failed to get VapourSynth API pointer\n"); vsscript_finalize(); return 1; } VSCore *core = vsapi->createCore(0); if (!core) { fprintf(stderr, "Failed to create core\n"); vsscript_finalize(); return 1; } const VSCoreInfo *info = vsapi->getCoreInfo(core); printf("%s", info->versionString); vsapi->freeCore(core); return 0; } } if (argc < 3) { fprintf(stderr, "VSPipe usage:\n"); fprintf(stderr, "Show version info: vspipe -version\n"); fprintf(stderr, "Show script info: vspipe script.vpy - -info\n"); fprintf(stderr, "Write to stdout: vspipe script.vpy - [options]\n"); fprintf(stderr, "Write to file: vspipe script.vpy <outFile> [options]\n"); fprintf(stderr, "Available options:\n"); fprintf(stderr, "Select output index: -index N\n"); fprintf(stderr, "Set number of concurrent frame requests: -requests N\n"); fprintf(stderr, "Add YUV4MPEG headers: -y4m\n"); fprintf(stderr, "Print progress to stderr: -progress\n"); fprintf(stderr, "Show video info: -info (overrides other options)\n"); return 1; } nstring outputFilename = argv[2]; if (outputFilename == NSTRING("-")) { outFile = stdout; } else { #ifdef VS_TARGET_OS_WINDOWS outFile = _wfopen(outputFilename.c_str(), L"wb"); #else outFile = fopen(outputFilename.c_str(), "wb"); #endif if (!outFile) { fprintf(stderr, "Failed to open output for writing\n"); return 1; } } for (int arg = 3; arg < argc; arg++) { nstring argString = argv[arg]; if (argString == NSTRING("-y4m")) { y4m = true; } else if (argString == NSTRING("-info")) { showInfo = true; } else if (argString == NSTRING("-index")) { bool ok = false; if (argc <= arg + 1) { fprintf(stderr, "No index number specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], outputIndex)) { fprintf(stderr, "Couldn't convert %s to an integer\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } arg++; } else if (argString == NSTRING("-requests")) { bool ok = false; if (argc <= arg + 1) { fprintf(stderr, "No request number specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], requests)) { fprintf(stderr, "Couldn't convert %s to an integer\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } arg++; } else if (argString == NSTRING("-progress")) { printFrameNumber = true; } else { fprintf(stderr, "Unknown argument: %s\n", nstringToUtf8(argString).c_str()); return 1; } } if (!vsscript_init()) { fprintf(stderr, "Failed to initialize VapourSynth environment\n"); return 1; } vsapi = vsscript_getVSApi(); if (!vsapi) { fprintf(stderr, "Failed to get VapourSynth API pointer\n"); vsscript_finalize(); return 1; } std::chrono::time_point<std::chrono::high_resolution_clock> start(std::chrono::high_resolution_clock::now()); if (vsscript_evaluateFile(&se, nstringToUtf8(argv[1]).c_str(), efSetWorkingDir)) { fprintf(stderr, "Script evaluation failed:\n%s\n", vsscript_getError(se)); vsscript_freeScript(se); vsscript_finalize(); return 1; } node = vsscript_getOutput(se, outputIndex); if (!node) { fprintf(stderr, "Failed to retrieve output node. Invalid index specified?\n"); vsscript_freeScript(se); vsscript_finalize(); return 1; } bool error = false; const VSVideoInfo *vi = vsapi->getVideoInfo(node); if (showInfo) { fprintf(outFile, "Width: %d\n", vi->width); fprintf(outFile, "Height: %d\n", vi->height); fprintf(outFile, "Frames: %d\n", vi->numFrames); fprintf(outFile, "FPS: %" PRId64 "/%" PRId64 "\n", vi->fpsNum, vi->fpsDen); if (vi->format) { fprintf(outFile, "Format Name: %s\n", vi->format->name); fprintf(outFile, "Color Family: %s\n", colorFamilyToString(vi->format->colorFamily)); fprintf(outFile, "Bits: %d\n", vi->format->bitsPerSample); fprintf(outFile, "SubSampling W: %d\n", vi->format->subSamplingW); fprintf(outFile, "SubSampling H: %d\n", vi->format->subSamplingH); } else { fprintf(outFile, "Format Name: Variable\n"); } } else { if (!isConstantFormat(vi) || vi->numFrames == 0) { fprintf(stderr, "Cannot output clips with varying dimensions or unknown length\n"); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return 1; } lastFpsReportTime = std::chrono::high_resolution_clock::now(); error = outputNode(); } fflush(outFile); std::chrono::time_point<std::chrono::high_resolution_clock> end(std::chrono::high_resolution_clock::now()); std::chrono::duration<double> elapsedSeconds = end - start; fprintf(stderr, "Output %d frames in %.2f seconds (%.2f fps)\n", outputFrames, elapsedSeconds.count(), outputFrames / elapsedSeconds.count()); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return error; }
int wmain(int argc, wchar_t **argv) { if (_setmode(_fileno(stdout), _O_BINARY) == -1) fprintf(stderr, "Failed to set stdout to binary mode\n"); SetConsoleCtrlHandler(HandlerRoutine, TRUE); #else int main(int argc, char **argv) { #endif nstring outputFilename, scriptFilename; bool showHelp = false; std::map<std::string, std::string> scriptArgs; int startFrame = 0; for (int arg = 1; arg < argc; arg++) { nstring argString = argv[arg]; if (argString == NSTRING("-v") || argString == NSTRING("--version")) { showVersion = true; } else if (argString == NSTRING("-y") || argString == NSTRING("--y4m")) { y4m = true; } else if (argString == NSTRING("-p") || argString == NSTRING("--progress")) { printFrameNumber = true; } else if (argString == NSTRING("-i") || argString == NSTRING("--info")) { showInfo = true; } else if (argString == NSTRING("-h") || argString == NSTRING("--help")) { showHelp = true; } else if (argString == NSTRING("-s") || argString == NSTRING("--start")) { if (argc <= arg + 1) { fprintf(stderr, "No start frame specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], startFrame)) { fprintf(stderr, "Couldn't convert %s to an integer (start)\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } if (startFrame < 0) { fprintf(stderr, "Negative start frame specified\n"); return 1; } completedFrames = startFrame; outputFrames = startFrame; requestedFrames = startFrame; lastFpsReportFrame = startFrame; arg++; } else if (argString == NSTRING("-e") || argString == NSTRING("--end")) { if (argc <= arg + 1) { fprintf(stderr, "No end frame specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], totalFrames)) { fprintf(stderr, "Couldn't convert %s to an integer (end)\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } if (totalFrames < 0) { fprintf(stderr, "Negative end frame specified\n"); return 1; } totalFrames++; arg++; } else if (argString == NSTRING("-o") || argString == NSTRING("--outputindex")) { if (argc <= arg + 1) { fprintf(stderr, "No output index specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], outputIndex)) { fprintf(stderr, "Couldn't convert %s to an integer (index)\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } arg++; } else if (argString == NSTRING("-r") || argString == NSTRING("--requests")) { if (argc <= arg + 1) { fprintf(stderr, "Number of requests not specified\n"); return 1; } if (!nstringToInt(argv[arg + 1], requests)) { fprintf(stderr, "Couldn't convert %s to an integer (requests)\n", nstringToUtf8(argv[arg + 1]).c_str()); return 1; } arg++; } else if (argString == NSTRING("-a") || argString == NSTRING("--arg")) { if (argc <= arg + 1) { fprintf(stderr, "No argument specified\n"); return 1; } std::string aLine = nstringToUtf8(argv[arg + 1]).c_str(); size_t equalsPos = aLine.find("="); if (equalsPos == std::string::npos) { fprintf(stderr, "No value specified for argument: %s\n", aLine.c_str()); return 1; } scriptArgs[aLine.substr(0, equalsPos)] = aLine.substr(equalsPos + 1); arg++; } else if (scriptFilename.empty() && !argString.empty() && argString.substr(0, 1) != NSTRING("-")) { scriptFilename = argString; } else if (outputFilename.empty() && !argString.empty() && (argString == NSTRING("-") || (argString.substr(0, 1) != NSTRING("-")))) { outputFilename = argString; } else { fprintf(stderr, "Unknown argument: %s\n", nstringToUtf8(argString).c_str()); return 1; } } if (showVersion && argc > 2) { fprintf(stderr, "Cannot combine version information with other options\n"); return 1; } else if (showVersion) { return printVersion() ? 0 : 1; } else if (showHelp || argc <= 1) { printHelp(); return 1; } else if (scriptFilename.empty()) { fprintf(stderr, "No script file specified\n"); return 1; } else if (outputFilename.empty()) { fprintf(stderr, "No output file specified\n"); return 1; } if (outputFilename == NSTRING("-")) { outFile = stdout; } else { #ifdef VS_TARGET_OS_WINDOWS outFile = _wfopen(outputFilename.c_str(), L"wb"); #else outFile = fopen(outputFilename.c_str(), "wb"); #endif if (!outFile) { fprintf(stderr, "Failed to open output for writing\n"); return 1; } } if (!vsscript_init()) { fprintf(stderr, "Failed to initialize VapourSynth environment\n"); return 1; } vsapi = vsscript_getVSApi(); if (!vsapi) { fprintf(stderr, "Failed to get VapourSynth API pointer\n"); vsscript_finalize(); return 1; } // Should always succeed if (vsscript_createScript(&se)) { fprintf(stderr, "Script environment initialization failed:\n%s\n", vsscript_getError(se)); vsscript_freeScript(se); vsscript_finalize(); return 1; } { VSMap *foldedArgs = vsapi->createMap(); for (const auto &iter : scriptArgs) vsapi->propSetData(foldedArgs, iter.first.c_str(), iter.second.c_str(), static_cast<int>(iter.second.size()), paAppend); vsscript_setVariable(se, foldedArgs); vsapi->freeMap(foldedArgs); } start = std::chrono::high_resolution_clock::now(); if (vsscript_evaluateFile(&se, nstringToUtf8(scriptFilename).c_str(), efSetWorkingDir)) { fprintf(stderr, "Script evaluation failed:\n%s\n", vsscript_getError(se)); vsscript_freeScript(se); vsscript_finalize(); return 1; } node = vsscript_getOutput(se, outputIndex); if (!node) { fprintf(stderr, "Failed to retrieve output node. Invalid index specified?\n"); vsscript_freeScript(se); vsscript_finalize(); return 1; } bool error = false; const VSVideoInfo *vi = vsapi->getVideoInfo(node); if (showInfo) { if (vi->width && vi->height) { fprintf(outFile, "Width: %d\n", vi->width); fprintf(outFile, "Height: %d\n", vi->height); } else { fprintf(outFile, "Width: Variable\n"); fprintf(outFile, "Height: Variable\n"); } if (vi->numFrames) fprintf(outFile, "Frames: %d\n", vi->numFrames); else fprintf(outFile, "Frames: Unknown\n"); if (vi->fpsNum && vi->fpsDen) fprintf(outFile, "FPS: %" PRId64 "/%" PRId64 " (%.3f fps)\n", vi->fpsNum, vi->fpsDen, vi->fpsNum/(double)vi->fpsDen); else fprintf(outFile, "FPS: Variable\n"); if (vi->format) { fprintf(outFile, "Format Name: %s\n", vi->format->name); fprintf(outFile, "Color Family: %s\n", colorFamilyToString(vi->format->colorFamily)); fprintf(outFile, "Bits: %d\n", vi->format->bitsPerSample); fprintf(outFile, "SubSampling W: %d\n", vi->format->subSamplingW); fprintf(outFile, "SubSampling H: %d\n", vi->format->subSamplingH); } else { fprintf(outFile, "Format Name: Variable\n"); } } else { const VSVideoInfo *vi = vsapi->getVideoInfo(node); if (totalFrames == -1) totalFrames = vi->numFrames; if ((vi->numFrames && vi->numFrames < totalFrames) || completedFrames >= totalFrames) { fprintf(stderr, "Invalid range of frames to output specified:\nfirst: %d\nlast: %d\nclip length: %d\nframes to output: %d\n", completedFrames, totalFrames, vi->numFrames, totalFrames - completedFrames); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return 1; } if (!isConstantFormat(vi) || !totalFrames) { fprintf(stderr, "Cannot output clips with varying dimensions or unknown length\n"); vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return 1; } lastFpsReportTime = std::chrono::high_resolution_clock::now();; error = outputNode(); } fflush(outFile); if (!showInfo) { int totalFrames = outputFrames - startFrame; std::chrono::duration<double> elapsedSeconds = std::chrono::high_resolution_clock::now() - start; fprintf(stderr, "Output %d frames in %.2f seconds (%.2f fps)\n", totalFrames, elapsedSeconds.count(), totalFrames / elapsedSeconds.count()); } vsapi->freeNode(node); vsscript_freeScript(se); vsscript_finalize(); return error ? 1 : 0; }