static void VS_CC spliceCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { SpliceData d; SpliceData *data; VSNodeRef *cref; int mismatch; int i; int err; int compat = 0; d.numclips = vsapi->propNumElements(in, "clips"); mismatch = !!vsapi->propGetInt(in, "mismatch", 0, &err); if (d.numclips == 1) { // passthrough for the special case with only one clip cref = vsapi->propGetNode(in, "clips", 0, 0); vsapi->propSetNode(out, "clip", cref, 0); vsapi->freeNode(cref); } else { d.node = malloc(sizeof(d.node[0]) * d.numclips); for (i = 0; i < d.numclips; i++) { d.node[i] = vsapi->propGetNode(in, "clips", i, 0); if (isCompatFormat(vsapi->getVideoInfo(d.node[i]))) compat = 1; } if (findCommonVi(d.node, d.numclips, &d.vi, 0, vsapi) && (!mismatch || compat) && !isSameFormat(&d.vi, vsapi->getVideoInfo(d.node[0]))) { for (i = 0; i < d.numclips; i++) vsapi->freeNode(d.node[i]); free(d.node); RETERROR("Splice: clip property mismatch"); } d.numframes = malloc(sizeof(d.numframes[0]) * d.numclips); d.vi.numFrames = 0; for (i = 0; i < d.numclips; i++) { d.numframes[i] = (vsapi->getVideoInfo(d.node[i]))->numFrames; d.vi.numFrames += d.numframes[i]; if (d.numframes[i] == 0 && i != d.numclips - 1) { for (i = 0; i < d.numclips; i++) vsapi->freeNode(d.node[i]); free(d.node); free(d.numframes); RETERROR("Splice: unknown length clips can only be last in a splice operation"); } } if (d.numframes[d.numclips - 1] == 0) d.vi.numFrames = 0; data = malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "Splice", spliceInit, spliceGetframe, spliceFree, fmParallel, nfNoCache, data, core); } }
static void VS_CC interleaveCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { InterleaveData d; InterleaveData *data; VSNodeRef *cref; int i; int err; int compat; int mismatch = !!vsapi->propGetInt(in, "mismatch", 0, &err); int extend = !!vsapi->propGetInt(in, "extend", 0, &err); d.numclips = vsapi->propNumElements(in, "clips"); if (d.numclips == 1) { // passthrough for the special case with only one clip cref = vsapi->propGetNode(in, "clips", 0, 0); vsapi->propSetNode(out, "clip", cref, 0); vsapi->freeNode(cref); } else { d.node = malloc(sizeof(d.node[0]) * d.numclips); compat = 0; for (i = 0; i < d.numclips; i++) { d.node[i] = vsapi->propGetNode(in, "clips", i, 0); if (isCompatFormat(vsapi->getVideoInfo(d.node[i]))) compat = 1; } if (findCommonVi(d.node, d.numclips, &d.vi, 1, vsapi) && (!mismatch || compat)) { for (i = 0; i < d.numclips; i++) vsapi->freeNode(d.node[i]); free(d.node); RETERROR("Interleave: clip property mismatch"); } if (extend) { d.vi.numFrames *= d.numclips; } else if (d.vi.numFrames) { // this is exactly how avisynth does it d.vi.numFrames = (vsapi->getVideoInfo(d.node[0])->numFrames - 1) * d.numclips + 1; for (i = 1; i < d.numclips; i++) d.vi.numFrames = VSMAX(d.vi.numFrames, (vsapi->getVideoInfo(d.node[i])->numFrames - 1) * d.numclips + i + 1); } d.vi.fpsNum *= d.numclips; data = malloc(sizeof(d)); *data = d; vsapi->createFilter(in, out, "Interleave", interleaveInit, interleaveGetframe, interleaveFree, fmParallel, nfNoCache, data, core); } }
static void VS_CC textCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { TextData d; TextData *data; int err; d.node = vsapi->propGetNode(in, "clip", 0, &err); if (err) { // Can only happen for CoreInfo. VSMap *args = vsapi->createMap(); VSPlugin *stdPlugin = vsapi->getPluginById("com.vapoursynth.std", core); VSMap *ret = vsapi->invoke(stdPlugin, "BlankClip", args); vsapi->freeMap(args); const char *error = vsapi->getError(ret); if (error) { std::string msg = "CoreInfo: No input clip was given and invoking BlankClip failed. The error message from BlankClip is:\n"; msg += error; vsapi->setError(out, msg.c_str()); vsapi->freeMap(ret); return; } d.node = vsapi->propGetNode(ret, "clip", 0, nullptr); vsapi->freeMap(ret); } d.vi = vsapi->getVideoInfo(d.node); if (isCompatFormat(d.vi)) { vsapi->setError(out, "Text: Compat formats not supported"); vsapi->freeNode(d.node); return; } if (d.vi->format && ((d.vi->format->sampleType == stInteger && d.vi->format->bitsPerSample > 16) || (d.vi->format->sampleType == stFloat && d.vi->format->bitsPerSample != 32))) { vsapi->setError(out, "Text: Only 8-16 bit integer and 32 bit float formats supported"); vsapi->freeNode(d.node); return; } d.alignment = int64ToIntS(vsapi->propGetInt(in, "alignment", 0, &err)); if (err) { d.alignment = 7; // top left } if (d.alignment < 1 || d.alignment > 9) { vsapi->setError(out, "Text: alignment must be between 1 and 9 (think numpad)"); vsapi->freeNode(d.node); return; } d.filter = reinterpret_cast<intptr_t>(userData); switch (d.filter) { case FILTER_TEXT: d.text = vsapi->propGetData(in, "text", 0, nullptr); d.instanceName = "Text"; break; case FILTER_CLIPINFO: d.instanceName = "ClipInfo"; break; case FILTER_COREINFO: { d.instanceName = "CoreInfo"; break; } case FILTER_FRAMENUM: d.instanceName = "FrameNum"; break; case FILTER_FRAMEPROPS: int numProps = vsapi->propNumElements(in, "props"); for (int i = 0; i < numProps; i++) { d.props.push_back(vsapi->propGetData(in, "props", i, nullptr)); } d.instanceName = "FrameProps"; break; } data = new TextData(d); vsapi->createFilter(in, out, d.instanceName.c_str(), textInit, textGetFrame, textFree, 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 textCreate(const VSMap *in, VSMap *out, void *userData, VSCore *core, const VSAPI *vsapi) { TextData d; TextData *data; int err; d.node = vsapi->propGetNode(in, "clip", 0, &err); if (err) { // Can only happen for CoreInfo. VSMap *args = vsapi->createMap(); VSPlugin *stdPlugin = vsapi->getPluginById("com.vapoursynth.std", core); VSMap *ret = vsapi->invoke(stdPlugin, "BlankClip", args); vsapi->freeMap(args); const char *error = vsapi->getError(ret); if (error) { std::string msg = "CoreInfo: No input clip was given and invoking BlankClip failed. The error message from BlankClip is:\n"; msg.append(error); vsapi->setError(out, msg.c_str()); vsapi->freeMap(ret); return; } d.node = vsapi->propGetNode(ret, "clip", 0, 0); vsapi->freeMap(ret); } d.vi = vsapi->getVideoInfo(d.node); if (isCompatFormat(d.vi)) { vsapi->setError(out, "Text: Compat formats not supported"); vsapi->freeNode(d.node); return; } if (d.vi->format && ((d.vi->format->sampleType == stInteger && d.vi->format->bitsPerSample > 16) || (d.vi->format->sampleType == stFloat && d.vi->format->bitsPerSample != 32))) { vsapi->setError(out, "Text: Only 8-16 bit integer and 32 bit float formats supported"); vsapi->freeNode(d.node); return; } d.alignment = int64ToIntS(vsapi->propGetInt(in, "alignment", 0, &err)); if (err) { d.alignment = 7; // top left } if (d.alignment < 1 || d.alignment > 9) { vsapi->setError(out, "Text: alignment must be between 1 and 9 (think numpad)"); vsapi->freeNode(d.node); return; } d.filter = (intptr_t)userData; switch (d.filter) { case FILTER_TEXT: d.text = vsapi->propGetData(in, "text", 0, 0); d.instanceName = "Text"; break; case FILTER_CLIPINFO: d.text.append("Clip info:\n"); if (d.vi->width) { d.text.append("Width: ").append(std::to_string(d.vi->width)).append(" px\n"); d.text.append("Height: ").append(std::to_string(d.vi->height)).append(" px\n"); } else { d.text.append("Width: may vary\n"); d.text.append("Height: may vary\n"); } if (d.vi->numFrames) { d.text.append("Length: ").append(std::to_string(d.vi->numFrames)).append(" frames\n"); } else { d.text.append("Length: unknown\n"); } if (d.vi->format) { const VSFormat *fi = d.vi->format; const char *family; switch (fi->colorFamily) { case cmGray: family = "Gray"; break; case cmRGB: family = "RGB"; break; case cmYUV: family = "YUV"; break; case cmYCoCg: family = "YCoCg"; break; case cmCompat: family = "Compat"; break; default: family = "impossible"; break; } const char *type; switch (fi->sampleType) { case stInteger: type = "integer"; break; case stFloat: type = "float"; break; default: type = "impossible"; break; } d.text.append("Format name: ").append(fi->name).append("\n"); d.text.append("Format id: ").append(std::to_string(fi->id)).append("\n"); d.text.append("Color family: ").append(family).append("\n"); d.text.append("Sample type: ").append(type).append("\n"); d.text.append("Bits per sample: ").append(std::to_string(fi->bitsPerSample)).append("\n"); d.text.append("Bytes per sample: ").append(std::to_string(fi->bytesPerSample)).append("\n"); d.text.append("Horizontal subsampling: ").append(std::to_string(fi->subSamplingW)).append("\n"); d.text.append("Vertical subsampling: ").append(std::to_string(fi->subSamplingH)).append("\n"); d.text.append("Number of planes: ").append(std::to_string(fi->numPlanes)).append("\n"); } else { d.text.append("Format: may vary").append("\n"); } d.text.append("FpsNum: ").append(std::to_string(d.vi->fpsNum)).append("\n"); d.text.append("FpsDen: ").append(std::to_string(d.vi->fpsDen)); d.instanceName = "ClipInfo"; break; case FILTER_COREINFO: { d.instanceName = "CoreInfo"; break; } case FILTER_FRAMENUM: d.instanceName = "FrameNum"; break; case FILTER_FRAMEPROPS: int numProps = vsapi->propNumElements(in, "props"); for (int i = 0; i < numProps; i++) { d.props.push_back(vsapi->propGetData(in, "props", i, 0)); } d.instanceName = "FrameProps"; break; } data = new TextData(); *data = d; vsapi->createFilter(in, out, d.instanceName.c_str(), textInit, textGetFrame, textFree, fmParallel, 0, data, core); }