PVideoFrame AvisynthVideoSource::GetFrame(int n, IScriptEnvironment *Env) { n = FFMIN(FFMAX(n,0), VI.num_frames - 1); char ErrorMsg[1024]; FFMS_ErrorInfo E; E.Buffer = ErrorMsg; E.BufferSize = sizeof(ErrorMsg); PVideoFrame Dst = Env->NewVideoFrame(VI); if (RFFMode > 0) { const FFMS_Frame *Frame = FFMS_GetFrame(V, FFMIN(FieldList[n].Top, FieldList[n].Bottom), &E); if (Frame == NULL) Env->ThrowError("FFVideoSource: %s", E.Buffer); if (FieldList[n].Top == FieldList[n].Bottom) { OutputFrame(Frame, Dst, Env); } else { int FirstField = FFMIN(FieldList[n].Top, FieldList[n].Bottom) == FieldList[n].Bottom; OutputField(Frame, Dst, FirstField, Env); Frame = FFMS_GetFrame(V, FFMAX(FieldList[n].Top, FieldList[n].Bottom), &E); if (Frame == NULL) Env->ThrowError("FFVideoSource: %s", E.Buffer); OutputField(Frame, Dst, !FirstField, Env); } } else { const FFMS_Frame *Frame; if (FPSNum > 0 && FPSDen > 0) { Frame = FFMS_GetFrameByTime(V, FFMS_GetVideoProperties(V)->FirstTime + (double)(n * (int64_t)FPSDen) / FPSNum, &E); } else { Frame = FFMS_GetFrame(V, n, &E); FFMS_Track *T = FFMS_GetTrackFromVideo(V); const FFMS_TrackTimeBase *TB = FFMS_GetTimeBase(T); Env->SetVar(Env->Sprintf("%s%s", this->VarPrefix, "FFVFR_TIME"), static_cast<int>(FFMS_GetFrameInfo(T, n)->PTS * static_cast<double>(TB->Num) / TB->Den)); } if (Frame == NULL) Env->ThrowError("FFVideoSource: %s", E.Buffer); Env->SetVar(Env->Sprintf("%s%s", this->VarPrefix, "FFPICT_TYPE"), static_cast<int>(Frame->PictType)); OutputFrame(Frame, Dst, Env); } return Dst; }
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; }