VSVideoSource::VSVideoSource(const char *SourceFile, int Track, FFMS_Index *Index, int AFPSNum, int AFPSDen, int Threads, int SeekMode, int /*RFFMode*/, int ResizeToWidth, int ResizeToHeight, const char *ResizerName, int Format, bool OutputAlpha, const VSAPI *vsapi, VSCore *core) : FPSNum(AFPSNum), FPSDen(AFPSDen), OutputAlpha(OutputAlpha) { VI[0] = {}; VI[1] = {}; char ErrorMsg[1024]; FFMS_ErrorInfo E; E.Buffer = ErrorMsg; E.BufferSize = sizeof(ErrorMsg); V = FFMS_CreateVideoSource(SourceFile, Track, Index, Threads, SeekMode, &E); if (!V) { throw std::runtime_error(std::string("Source: ") + E.Buffer); } try { InitOutputFormat(ResizeToWidth, ResizeToHeight, ResizerName, Format, vsapi, core); } catch (std::exception &) { FFMS_DestroyVideoSource(V); throw; } const FFMS_VideoProperties *VP = FFMS_GetVideoProperties(V); if (FPSNum > 0 && FPSDen > 0) { muldivRational(&FPSNum, &FPSDen, 1, 1); VI[0].fpsDen = FPSDen; VI[0].fpsNum = FPSNum; if (VP->NumFrames > 1) { VI[0].numFrames = static_cast<int>((VP->LastTime - VP->FirstTime) * (1 + 1. / (VP->NumFrames - 1)) * FPSNum / FPSDen + 0.5); if (VI[0].numFrames < 1) VI[0].numFrames = 1; } else { VI[0].numFrames = 1; } } else { VI[0].fpsDen = VP->FPSDenominator; VI[0].fpsNum = VP->FPSNumerator; VI[0].numFrames = VP->NumFrames; muldivRational(&VI[0].fpsNum, &VI[0].fpsDen, 1, 1); } if (OutputAlpha) { VI[1] = VI[0]; VI[1].format = vsapi->registerFormat(cmGray, VI[0].format->sampleType, VI[0].format->bitsPerSample, VI[0].format->subSamplingW, VI[0].format->subSamplingH, core); } SARNum = VP->SARNum; SARDen = VP->SARDen; }
static void propagate_sar(const VSAPI *vsapi, const VSMap *src_props, VSMap *dst_props, const zimg_image_format *src_format, const zimg_image_format *dst_format) { int64_t sar_num = 0; int64_t sar_den = 0; int err; if ((sar_num = vsapi->propGetInt(src_props, "_SARNum", 0, &err)), err) sar_num = 0; if ((sar_den = vsapi->propGetInt(src_props, "_SARDen", 0, &err)), err) sar_den = 0; if (sar_num <= 0 || sar_den <= 0) { vsapi->propDeleteKey(dst_props, "_SARNum"); vsapi->propDeleteKey(dst_props, "_SARDen"); } else { muldivRational(&sar_num, &sar_den, dst_format->width, src_format->width); muldivRational(&sar_num, &sar_den, src_format->height, dst_format->height); vsapi->propSetInt(dst_props, "_SARNum", sar_num, paReplace); vsapi->propSetInt(dst_props, "_SARDen", sar_den, paReplace); } }
const VSFrameRef *VS_CC VSVideoSource::GetFrame(int n, int activationReason, void **instanceData, void **, VSFrameContext *frameCtx, VSCore *core, const VSAPI *vsapi) { VSVideoSource *vs = static_cast<VSVideoSource *>(*instanceData); if (activationReason == arInitial) { char ErrorMsg[1024]; FFMS_ErrorInfo E; E.Buffer = ErrorMsg; E.BufferSize = sizeof(ErrorMsg); std::string buf = "Source: "; int OutputIndex = vs->OutputAlpha ? vsapi->getOutputIndex(frameCtx) : 0; VSFrameRef *Dst = vsapi->newVideoFrame(vs->VI[OutputIndex].format, vs->VI[OutputIndex].width, vs->VI[OutputIndex].height, nullptr, core); VSMap *Props = vsapi->getFramePropsRW(Dst); const FFMS_Frame *Frame; if (vs->FPSNum > 0 && vs->FPSDen > 0) { double currentTime = FFMS_GetVideoProperties(vs->V)->FirstTime + (double)(n * (int64_t)vs->FPSDen) / vs->FPSNum; Frame = FFMS_GetFrameByTime(vs->V, currentTime, &E); vsapi->propSetInt(Props, "_DurationNum", vs->FPSDen, paReplace); vsapi->propSetInt(Props, "_DurationDen", vs->FPSNum, paReplace); vsapi->propSetFloat(Props, "_AbsoluteTime", currentTime, paReplace); } else { Frame = FFMS_GetFrame(vs->V, n, &E); FFMS_Track *T = FFMS_GetTrackFromVideo(vs->V); const FFMS_TrackTimeBase *TB = FFMS_GetTimeBase(T); int64_t num; if (n + 1 < vs->VI[0].numFrames) num = FFMS_GetFrameInfo(T, n + 1)->PTS - FFMS_GetFrameInfo(T, n)->PTS; else if (n > 0) // simply use the second to last frame's duration for the last one, should be good enough num = FFMS_GetFrameInfo(T, n)->PTS - FFMS_GetFrameInfo(T, n - 1)->PTS; else // just make it one timebase if it's a single frame clip num = 1; int64_t DurNum = TB->Num * num; int64_t DurDen = TB->Den * 1000; muldivRational(&DurNum, &DurDen, 1, 1); vsapi->propSetInt(Props, "_DurationNum", DurNum, paReplace); vsapi->propSetInt(Props, "_DurationDen", DurDen, paReplace); vsapi->propSetFloat(Props, "_AbsoluteTime", ((static_cast<double>(TB->Num) / 1000) * FFMS_GetFrameInfo(T, n)->PTS) / TB->Den, paReplace); } if (Frame == nullptr) { buf += E.Buffer; vsapi->setFilterError(buf.c_str(), frameCtx); return nullptr; } // Set AR variables if (vs->SARNum > 0 && vs->SARDen > 0) { vsapi->propSetInt(Props, "_SARNum", vs->SARNum, paReplace); vsapi->propSetInt(Props, "_SARDen", vs->SARDen, paReplace); } vsapi->propSetInt(Props, "_Matrix", Frame->ColorSpace, paReplace); vsapi->propSetInt(Props, "_Primaries", Frame->ColorPrimaries, paReplace); vsapi->propSetInt(Props, "_Transfer", Frame->TransferCharateristics, paReplace); if (Frame->ChromaLocation > 0) vsapi->propSetInt(Props, "_ChromaLocation", Frame->ChromaLocation - 1, paReplace); if (Frame->ColorRange == FFMS_CR_MPEG) vsapi->propSetInt(Props, "_ColorRange", 1, paReplace); else if (Frame->ColorRange == FFMS_CR_JPEG) vsapi->propSetInt(Props, "_ColorRange", 0, paReplace); vsapi->propSetData(Props, "_PictType", &Frame->PictType, 1, paReplace); // Set field information int FieldBased = 0; if (Frame->InterlacedFrame) FieldBased = (Frame->TopFieldFirst ? 2 : 1); vsapi->propSetInt(Props, "_FieldBased", FieldBased, paReplace); if (OutputIndex == 0) OutputFrame(Frame, Dst, vsapi); else OutputAlphaFrame(Frame, vs->VI[0].format->numPlanes, Dst, vsapi); return Dst; } return nullptr; }