diff --git a/avisynth_filter/src/frame_handler.cpp b/avisynth_filter/src/frame_handler.cpp index 46d939d..d0ce9ff 100644 --- a/avisynth_filter/src/frame_handler.cpp +++ b/avisynth_filter/src/frame_handler.cpp @@ -64,6 +64,32 @@ auto FrameHandler::AddInputSample(IMediaSample *inputSample) -> HRESULT { PVideoFrame frame = Format::CreateFrame(_filter._inputVideoFormat, sampleBuffer); + if (FrameServerCommon::GetInstance().IsFramePropsSupported()) { + AVSMap *frameProps = AVSF_AVS_API->getFramePropsRW(frame); + + AVSF_AVS_API->propSetFloat(frameProps, FRAME_PROP_NAME_ABS_TIME, inputSampleStartTime / static_cast(UNITS), PROPAPPENDMODE_REPLACE); + AVSF_AVS_API->propSetInt(frameProps, "_SARNum", _filter._inputVideoFormat.pixelAspectRatioNum, PROPAPPENDMODE_REPLACE); + AVSF_AVS_API->propSetInt(frameProps, "_SARDen", _filter._inputVideoFormat.pixelAspectRatioDen, PROPAPPENDMODE_REPLACE); + + if (const std::optional &optColorRange = _filter._inputVideoFormat.colorSpaceInfo.colorRange) { + AVSF_AVS_API->propSetInt(frameProps, "_ColorRange", *optColorRange, PROPAPPENDMODE_REPLACE); + } + AVSF_AVS_API->propSetInt(frameProps, "_Primaries", _filter._inputVideoFormat.colorSpaceInfo.primaries, PROPAPPENDMODE_REPLACE); + AVSF_AVS_API->propSetInt(frameProps, "_Matrix", _filter._inputVideoFormat.colorSpaceInfo.matrix, PROPAPPENDMODE_REPLACE); + AVSF_AVS_API->propSetInt(frameProps, "_Transfer", _filter._inputVideoFormat.colorSpaceInfo.transfer, PROPAPPENDMODE_REPLACE); + + const DWORD typeSpecificFlags = _filter.m_pInput->SampleProps()->dwTypeSpecificFlags; + int rfpFieldBased; + if (typeSpecificFlags & AM_VIDEO_FLAG_WEAVE) { + rfpFieldBased = 0; + } else if (typeSpecificFlags & AM_VIDEO_FLAG_FIELD1FIRST) { + rfpFieldBased = 2; + } else { + rfpFieldBased = 1; + } + AVSF_AVS_API->propSetInt(frameProps, FRAME_PROP_NAME_FIELD_BASED, rfpFieldBased, PROPAPPENDMODE_REPLACE); + } + std::unique_ptr hdrSideData = std::make_unique(); { if (const ATL::CComQIPtr inputSampleSideData(inputSample); inputSampleSideData != nullptr) { @@ -218,8 +244,35 @@ auto FrameHandler::PrepareOutputSample(ATL::CComPtr &outSample, RE } else { try { // some AviSynth internal filter (e.g. Subtitle) can't tolerate multi-thread access - const PVideoFrame scriptFrame = MainFrameServer::GetInstance().GetFrame(_nextOutputFrameNb); - Format::WriteSample(_filter._outputVideoFormat, scriptFrame, outputBuffer); + const PVideoFrame outputFrame = MainFrameServer::GetInstance().GetFrame(_nextOutputFrameNb); + + if (const ATL::CComQIPtr outSample2(outSample); outSample2 != nullptr) { + if (AM_SAMPLE2_PROPERTIES sampleProps; SUCCEEDED(outSample2->GetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&sampleProps)))) { + if (FrameServerCommon::GetInstance().IsFramePropsSupported()) { + const AVSMap *frameProps = AVSF_AVS_API->getFramePropsRO(outputFrame); + int propGetError; + + if (const int64_t rfpFieldBased = AVSF_AVS_API->propGetInt(frameProps, FRAME_PROP_NAME_FIELD_BASED, 0, &propGetError); + propGetError == GETPROPERROR_UNSET || rfpFieldBased == 0) { + sampleProps.dwTypeSpecificFlags = AM_VIDEO_FLAG_WEAVE; + } else if (rfpFieldBased == 2) { + sampleProps.dwTypeSpecificFlags = AM_VIDEO_FLAG_FIELD1FIRST; + } else { + sampleProps.dwTypeSpecificFlags = 0; + } + } else { + sampleProps.dwTypeSpecificFlags = AM_VIDEO_FLAG_WEAVE; + } + + if (sourceTypeSpecificFlags & AM_VIDEO_FLAG_REPEAT_FIELD) { + sampleProps.dwTypeSpecificFlags |= AM_VIDEO_FLAG_REPEAT_FIELD; + } + + outSample2->SetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&sampleProps)); + } + } + + Format::WriteSample(_filter._outputVideoFormat, outputFrame, outputBuffer); } catch (AvisynthError) { return false; } @@ -266,7 +319,7 @@ auto FrameHandler::WorkerProc() -> void { * Therefore instead of directly using the stop time from the current sample, we use the start time of the next sample. */ - std::array processSourceFrameIters; + std::array processSourceFrameIters; std::array outputFrameDurations; { @@ -316,20 +369,21 @@ auto FrameHandler::WorkerProc() -> void { } _nextOutputFrameStartTime = outputStopTime; + if (FrameServerCommon::GetInstance().IsFramePropsSupported()) { + AVSMap *frameProps = AVSF_AVS_API->getFramePropsRW(processSourceFrameIters[0]->second.frame); + REFERENCE_TIME frameDurationNum = processSourceFrameIters[1]->second.startTime - processSourceFrameIters[0]->second.startTime; + REFERENCE_TIME frameDurationDen = UNITS; + CoprimeIntegers(frameDurationNum, frameDurationDen); + AVSF_AVS_API->propSetInt(frameProps, FRAME_PROP_NAME_DURATION_NUM, frameDurationNum, PROPAPPENDMODE_REPLACE); + AVSF_AVS_API->propSetInt(frameProps, FRAME_PROP_NAME_DURATION_DEN, frameDurationDen, PROPAPPENDMODE_REPLACE); + } + Environment::GetInstance().Log(L"Processing output frame %6i for source frame %6i at %10lli ~ %10lli duration %10lli", _nextOutputFrameNb, processSourceFrameIters[0]->first, outputStartTime, outputStopTime, outputStopTime - outputStartTime); RefreshOutputFrameRates(_nextOutputFrameNb); if (ATL::CComPtr outSample; PrepareOutputSample(outSample, outputStartTime, outputStopTime, processSourceFrameIters[0]->second.typeSpecificFlags)) { - if (const ATL::CComQIPtr outSample2(outSample); outSample2 != nullptr) { - AM_SAMPLE2_PROPERTIES props; - if (SUCCEEDED(outSample2->GetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&props)))) { - props.dwTypeSpecificFlags = processSourceFrameIters[0]->second.typeSpecificFlags; - outSample2->SetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&props)); - } - } - if (const ATL::CComQIPtr sideData(outSample); sideData != nullptr) { processSourceFrameIters[0]->second.hdrSideData->WriteTo(sideData); } diff --git a/avisynth_filter/src/frameserver.cpp b/avisynth_filter/src/frameserver.cpp index e412d00..7e11ef8 100644 --- a/avisynth_filter/src/frameserver.cpp +++ b/avisynth_filter/src/frameserver.cpp @@ -25,8 +25,18 @@ FrameServerCommon::FrameServerCommon() { IScriptEnvironment *env = CreateEnv(); AVS_linkage = env->GetAVSLinkage(); + _versionString = env->Invoke("Eval", AVSValue("VersionString()")).AsString(); Environment::GetInstance().Log(L"AviSynth version: %S", GetVersionString().data()); + + try { + // AVS+ 3.6 is interface version 8 + env->CheckVersion(8); + _isFramePropsSupported = true; + Environment::GetInstance().Log(L"AviSynth supports frame properties"); + } catch (...) { + } + env->DeleteScriptEnvironment(); _sourceClip = new SourceClip(_sourceVideoInfo); diff --git a/avisynth_filter/src/frameserver.h b/avisynth_filter/src/frameserver.h index b13b73f..fb0c32a 100644 --- a/avisynth_filter/src/frameserver.h +++ b/avisynth_filter/src/frameserver.h @@ -24,12 +24,14 @@ class FrameServerCommon : public RefCountedSingleton { auto SetScriptPath(const std::filesystem::path &scriptPath) -> void; auto LinkFrameHandler(FrameHandler *frameHandler) const -> void; constexpr auto GetVersionString() const -> std::string_view { return _versionString == nullptr ? "unknown AviSynth version" : _versionString; } + constexpr auto IsFramePropsSupported() const -> bool { return _isFramePropsSupported; } constexpr auto GetScriptPath() const -> const std::filesystem::path & { return _scriptPath; } private: auto CreateEnv() const -> IScriptEnvironment *; const char *_versionString; + bool _isFramePropsSupported = false; std::filesystem::path _scriptPath = Environment::GetInstance().GetScriptPath(); VideoInfo _sourceVideoInfo = {}; PClip _sourceClip; diff --git a/filter_common/src/constants.h b/filter_common/src/constants.h index a5c1784..717079c 100644 --- a/filter_common/src/constants.h +++ b/filter_common/src/constants.h @@ -51,6 +51,17 @@ static constexpr const WCHAR *UNAVAILABLE_SOURCE_PATH = L"N/A"; */ static constexpr const int NUM_FRAMES_FOR_INFINITE_STREAM = 10810800; +/* + * AviSynth+ and VapourSynth frame property names + * The ones prefixed with "AVSF_" are specific private properties of this filter, both variants + */ +static constexpr const char *FRAME_PROP_NAME_ABS_TIME = "_AbsoluteTime"; +static constexpr const char *FRAME_PROP_NAME_DURATION_NUM = "_DurationNum"; +static constexpr const char *FRAME_PROP_NAME_DURATION_DEN = "_DurationDen"; +static constexpr const char *FRAME_PROP_NAME_FIELD_BASED = "_FieldBased"; +static constexpr const char *FRAME_PROP_NAME_SOURCE_FRAME_NB = "AVSF_SourceFrameNb"; +static constexpr const char *FRAME_PROP_NAME_TYPE_SPECIFIC_FLAGS = "AVSF_TypeSpecificFlags"; + static constexpr const WCHAR *REGISTRY_KEY_NAME_PREFIX = L"Software\\AviSynthFilter\\"; static constexpr const WCHAR *SETTING_NAME_SCRIPT_FILE = L"ScriptFile"; static constexpr const WCHAR *SETTING_NAME_LOG_FILE = L"LogFile"; diff --git a/filter_common/src/util.cpp b/filter_common/src/util.cpp index d836bc0..b6122ff 100644 --- a/filter_common/src/util.cpp +++ b/filter_common/src/util.cpp @@ -20,8 +20,8 @@ auto ConvertUtf8ToWide(std::string_view utf8String) -> std::wstring { return ret; } -auto DoubleToString(double d, int precision) -> std::wstring { - const std::wstring str = std::to_wstring(d); +auto DoubleToString(double num, int precision) -> std::wstring { + const std::wstring str = std::to_wstring(num); return str.substr(0, str.find(L'.') + 1 + precision); } @@ -44,4 +44,11 @@ auto ReplaceSubstr(std::string &str, std::string_view from, std::string_view to) return str; } +auto CoprimeIntegers(int64_t &a, int64_t &b) -> void { + if (const int64_t gcd = std::gcd(a, b); gcd > 1) { + a /= gcd; + b /= gcd; + } +} + } diff --git a/filter_common/src/util.h b/filter_common/src/util.h index 3eb144c..359d005 100644 --- a/filter_common/src/util.h +++ b/filter_common/src/util.h @@ -7,9 +7,10 @@ namespace SynthFilter { auto ConvertWideToUtf8(std::wstring_view wideString) -> std::string; auto ConvertUtf8ToWide(std::string_view utf8String) -> std::wstring; -auto DoubleToString(double d, int precision) -> std::wstring; +auto DoubleToString(double num, int precision) -> std::wstring; auto JoinStrings(const std::vector &input, std::wstring_view delimiter) -> std::wstring; auto ReplaceSubstr(std::string &str, std::string_view from, std::string_view to) -> std::string &; +auto CoprimeIntegers(int64_t &a, int64_t &b) -> void; /** * ceil(dividend / divisor), assuming both oprands are positive diff --git a/vapoursynth_filter/src/format.cpp b/vapoursynth_filter/src/format.cpp index 126f72b..4bffa69 100644 --- a/vapoursynth_filter/src/format.cpp +++ b/vapoursynth_filter/src/format.cpp @@ -40,7 +40,7 @@ auto Format::GetVideoFormat(const AM_MEDIA_TYPE &mediaType, const FrameServerBas const VIDEOINFOHEADER *vih = reinterpret_cast(mediaType.pbFormat); REFERENCE_TIME fpsNum = UNITS; REFERENCE_TIME fpsDen = vih->AvgTimePerFrame > 0 ? vih->AvgTimePerFrame : DEFAULT_AVG_TIME_PER_FRAME; - vs_normalizeRational(&fpsNum, &fpsDen); + CoprimeIntegers(fpsNum, fpsDen); VSCore *vsCore= vsscript_getCore(frameServerInstance->GetVsScript()); VideoFormat ret { @@ -73,7 +73,7 @@ auto Format::GetVideoFormat(const AM_MEDIA_TYPE &mediaType, const FrameServerBas */ ret.pixelAspectRatioNum = vih2->dwPictAspectRatioX * ret.videoInfo.height; ret.pixelAspectRatioDen = vih2->dwPictAspectRatioY * ret.videoInfo.width; - vs_normalizeRational(&ret.pixelAspectRatioNum, &ret.pixelAspectRatioDen); + CoprimeIntegers(ret.pixelAspectRatioNum, ret.pixelAspectRatioDen); } if ((vih2->dwControlFlags & AMCONTROL_USED) && (vih2->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)) { diff --git a/vapoursynth_filter/src/frame_handler.cpp b/vapoursynth_filter/src/frame_handler.cpp index fbb17a5..d93df83 100644 --- a/vapoursynth_filter/src/frame_handler.cpp +++ b/vapoursynth_filter/src/frame_handler.cpp @@ -62,11 +62,13 @@ auto FrameHandler::AddInputSample(IMediaSample *inputSample) -> HRESULT { } VSFrameRef *frame = Format::CreateFrame(_filter._inputVideoFormat, sampleBuffer); + VSMap *frameProps = AVSF_VPS_API->getFramePropsRW(frame); - AVSF_VPS_API->propSetFloat(frameProps, VS_PROP_NAME_ABS_TIME, inputSampleStartTime / static_cast(UNITS), paReplace); + + AVSF_VPS_API->propSetFloat(frameProps, FRAME_PROP_NAME_ABS_TIME, inputSampleStartTime / static_cast(UNITS), paReplace); AVSF_VPS_API->propSetInt(frameProps, "_SARNum", _filter._inputVideoFormat.pixelAspectRatioNum, paReplace); AVSF_VPS_API->propSetInt(frameProps, "_SARDen", _filter._inputVideoFormat.pixelAspectRatioDen, paReplace); - AVSF_VPS_API->propSetInt(frameProps, VS_PROP_NAME_SOURCE_FRAME_NB, _nextSourceFrameNb, paReplace); + AVSF_VPS_API->propSetInt(frameProps, FRAME_PROP_NAME_SOURCE_FRAME_NB, _nextSourceFrameNb, paReplace); if (const std::optional &optColorRange = _filter._inputVideoFormat.colorSpaceInfo.colorRange) { AVSF_VPS_API->propSetInt(frameProps, "_ColorRange", *optColorRange, paReplace); @@ -84,8 +86,8 @@ auto FrameHandler::AddInputSample(IMediaSample *inputSample) -> HRESULT { } else { rfpFieldBased = 1; } - AVSF_VPS_API->propSetInt(frameProps, VS_PROP_NAME_FIELD_BASED, rfpFieldBased, paReplace); - AVSF_VPS_API->propSetInt(frameProps, VS_PROP_NAME_TYPE_SPECIFIC_FLAGS, typeSpecificFlags, paReplace); + AVSF_VPS_API->propSetInt(frameProps, FRAME_PROP_NAME_FIELD_BASED, rfpFieldBased, paReplace); + AVSF_VPS_API->propSetInt(frameProps, FRAME_PROP_NAME_TYPE_SPECIFIC_FLAGS, typeSpecificFlags, paReplace); std::unique_ptr hdrSideData = std::make_unique(); { @@ -149,9 +151,9 @@ auto FrameHandler::AddInputSample(IMediaSample *inputSample) -> HRESULT { frameProps = AVSF_VPS_API->getFramePropsRW(processSourceFrameIters[0]->second.frame); REFERENCE_TIME frameDurationNum = processSourceFrameIters[1]->second.startTime - processSourceFrameIters[0]->second.startTime; REFERENCE_TIME frameDurationDen = UNITS; - vs_normalizeRational(&frameDurationNum, &frameDurationDen); - AVSF_VPS_API->propSetInt(frameProps, VS_PROP_NAME_DURATION_NUM, frameDurationNum, paReplace); - AVSF_VPS_API->propSetInt(frameProps, VS_PROP_NAME_DURATION_DEN, frameDurationDen, paReplace); + CoprimeIntegers(frameDurationNum, frameDurationDen); + AVSF_VPS_API->propSetInt(frameProps, FRAME_PROP_NAME_DURATION_NUM, frameDurationNum, paReplace); + AVSF_VPS_API->propSetInt(frameProps, FRAME_PROP_NAME_DURATION_DEN, frameDurationDen, paReplace); _newSourceFrameCv.notify_all(); const int maxRequestOutputFrameNb = static_cast(llMulDiv(processSourceFrameIters[0]->first, @@ -193,7 +195,7 @@ auto FrameHandler::GetSourceFrame(int frameNb) -> const VSFrameRef * { } const VSMap *frameProps = AVSF_VPS_API->getFramePropsRO(iter->second.frame); - return AVSF_VPS_API->propNumElements(frameProps, VS_PROP_NAME_DURATION_NUM) > 0 && AVSF_VPS_API->propNumElements(frameProps, VS_PROP_NAME_DURATION_DEN) > 0; + return AVSF_VPS_API->propNumElements(frameProps, FRAME_PROP_NAME_DURATION_NUM) > 0 && AVSF_VPS_API->propNumElements(frameProps, FRAME_PROP_NAME_DURATION_DEN) > 0; }); if (_isFlushing) { @@ -306,8 +308,8 @@ auto FrameHandler::ResetInput() -> void { auto FrameHandler::PrepareOutputSample(ATL::CComPtr &outSample, int outputFrameNb, const VSFrameRef *outputFrame, int sourceFrameNb) -> bool { const VSMap *frameProps = AVSF_VPS_API->getFramePropsRO(outputFrame); int propGetError; - const int64_t frameDurationNum = AVSF_VPS_API->propGetInt(frameProps, VS_PROP_NAME_DURATION_NUM, 0, &propGetError); - const int64_t frameDurationDen = AVSF_VPS_API->propGetInt(frameProps, VS_PROP_NAME_DURATION_DEN, 0, &propGetError); + const int64_t frameDurationNum = AVSF_VPS_API->propGetInt(frameProps, FRAME_PROP_NAME_DURATION_NUM, 0, &propGetError); + const int64_t frameDurationDen = AVSF_VPS_API->propGetInt(frameProps, FRAME_PROP_NAME_DURATION_DEN, 0, &propGetError); int64_t frameDuration; if (frameDurationNum > 0 && frameDurationDen > 0) { @@ -317,7 +319,7 @@ auto FrameHandler::PrepareOutputSample(ATL::CComPtr &outSample, in } if (_nextOutputFrameStartTime == 0) { - _nextOutputFrameStartTime = static_cast(AVSF_VPS_API->propGetFloat(frameProps, VS_PROP_NAME_ABS_TIME, 0, &propGetError) * UNITS); + _nextOutputFrameStartTime = static_cast(AVSF_VPS_API->propGetFloat(frameProps, FRAME_PROP_NAME_ABS_TIME, 0, &propGetError) * UNITS); } REFERENCE_TIME frameStartTime = _nextOutputFrameStartTime; @@ -364,22 +366,22 @@ auto FrameHandler::PrepareOutputSample(ATL::CComPtr &outSample, in } if (const ATL::CComQIPtr outSample2(outSample); outSample2 != nullptr) { - if (AM_SAMPLE2_PROPERTIES props; SUCCEEDED(outSample2->GetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&props)))) { - if (const int64_t rfpFieldBased = AVSF_VPS_API->propGetInt(frameProps, VS_PROP_NAME_FIELD_BASED, 0, &propGetError); + if (AM_SAMPLE2_PROPERTIES sampleProps; SUCCEEDED(outSample2->GetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&sampleProps)))) { + if (const int64_t rfpFieldBased = AVSF_VPS_API->propGetInt(frameProps, FRAME_PROP_NAME_FIELD_BASED, 0, &propGetError); propGetError == peUnset || rfpFieldBased == 0) { - props.dwTypeSpecificFlags = AM_VIDEO_FLAG_WEAVE; + sampleProps.dwTypeSpecificFlags = AM_VIDEO_FLAG_WEAVE; } else if (rfpFieldBased == 2) { - props.dwTypeSpecificFlags = AM_VIDEO_FLAG_FIELD1FIRST; + sampleProps.dwTypeSpecificFlags = AM_VIDEO_FLAG_FIELD1FIRST; } else { - props.dwTypeSpecificFlags = 0; + sampleProps.dwTypeSpecificFlags = 0; } - if (const int64_t sourceTypeSpecificFlags = AVSF_VPS_API->propGetInt(frameProps, VS_PROP_NAME_TYPE_SPECIFIC_FLAGS, 0, &propGetError); + if (const int64_t sourceTypeSpecificFlags = AVSF_VPS_API->propGetInt(frameProps, FRAME_PROP_NAME_TYPE_SPECIFIC_FLAGS, 0, &propGetError); sourceTypeSpecificFlags & AM_VIDEO_FLAG_REPEAT_FIELD) { - props.dwTypeSpecificFlags |= AM_VIDEO_FLAG_REPEAT_FIELD; + sampleProps.dwTypeSpecificFlags |= AM_VIDEO_FLAG_REPEAT_FIELD; } - outSample2->SetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&props)); + outSample2->SetProperties(SAMPLE2_TYPE_SPECIFIC_FLAGS_SIZE, reinterpret_cast(&sampleProps)); } } @@ -455,7 +457,7 @@ auto FrameHandler::WorkerProc() -> void { const VSMap *frameProps = AVSF_VPS_API->getFramePropsRO(iter->second); int propGetError; - const int sourceFrameNb = static_cast(AVSF_VPS_API->propGetInt(frameProps, VS_PROP_NAME_SOURCE_FRAME_NB, 0, &propGetError)); + const int sourceFrameNb = static_cast(AVSF_VPS_API->propGetInt(frameProps, FRAME_PROP_NAME_SOURCE_FRAME_NB, 0, &propGetError)); _lastUsedSourceFrameNb = sourceFrameNb; _addInputSampleCv.notify_all(); diff --git a/vapoursynth_filter/src/frame_handler.h b/vapoursynth_filter/src/frame_handler.h index 634c5ac..4a9b756 100644 --- a/vapoursynth_filter/src/frame_handler.h +++ b/vapoursynth_filter/src/frame_handler.h @@ -52,12 +52,6 @@ class FrameHandler { auto RefreshDeliveryFrameRates(int frameNb) -> void; static constexpr const int NUM_SRC_FRAMES_PER_PROCESSING = 2; - static constexpr const char *VS_PROP_NAME_ABS_TIME = "_AbsoluteTime"; - static constexpr const char *VS_PROP_NAME_DURATION_NUM = "_DurationNum"; - static constexpr const char *VS_PROP_NAME_DURATION_DEN = "_DurationDen"; - static constexpr const char *VS_PROP_NAME_FIELD_BASED = "_FieldBased"; - static constexpr const char *VS_PROP_NAME_SOURCE_FRAME_NB = "VPSF_SourceFrameNb"; - static constexpr const char *VS_PROP_NAME_TYPE_SPECIFIC_FLAGS = "VPSF_TypeSpecificFlags"; CSynthFilter &_filter;