From 933813af6b1d3b9580bfd6df8ca759c840423ac8 Mon Sep 17 00:00:00 2001 From: Crend King <975235+CrendKing@users.noreply.github.com> Date: Fri, 9 Apr 2021 05:37:45 -0700 Subject: [PATCH] Fix bug of not reloading the avs script in InputToOutputMediaType(), which desyncs the two avs cript instances --- avisynth_filter/src/allocator.cpp | 9 +++---- avisynth_filter/src/avs_handler.cpp | 10 ++++++++ avisynth_filter/src/avs_handler.h | 5 ++-- avisynth_filter/src/filter.cpp | 36 +++++++++++++-------------- avisynth_filter/src/filter.h | 13 +++++++--- avisynth_filter/src/format.cpp | 6 ++--- avisynth_filter/src/frame_handler.cpp | 18 ++++++-------- avisynth_filter/src/frame_handler.h | 2 +- avisynth_filter/src/input_pin.cpp | 4 +-- avisynth_filter/src/prop_settings.cpp | 3 +-- avisynth_filter/src/registry.cpp | 4 +-- avisynth_filter/src/util.h | 10 +++----- 12 files changed, 61 insertions(+), 59 deletions(-) diff --git a/avisynth_filter/src/allocator.cpp b/avisynth_filter/src/allocator.cpp index 3a1a3aa..fa31cea 100644 --- a/avisynth_filter/src/allocator.cpp +++ b/avisynth_filter/src/allocator.cpp @@ -42,8 +42,7 @@ auto CAviSynthFilterAllocator::Alloc() -> HRESULT { } if (m_lAlignment > 1) { - const LONG lRemainder = lAlignedSize % m_lAlignment; - if (lRemainder != 0) { + if (const LONG lRemainder = lAlignedSize % m_lAlignment; lRemainder != 0) { const LONG lNewSize = lAlignedSize + m_lAlignment - lRemainder; if (lNewSize < lAlignedSize) { return E_OUTOFMEMORY; @@ -68,12 +67,10 @@ auto CAviSynthFilterAllocator::Alloc() -> HRESULT { return E_OUTOFMEMORY; } - LPBYTE pNext = m_pBuffer; - CMediaSample *pSample; - ASSERT(m_lAllocated == 0); - for (; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { + LPBYTE pNext = m_pBuffer; + for (CMediaSample *pSample; m_lAllocated < m_lCount; m_lAllocated++, pNext += lAlignedSize) { pSample = new CAviSynthFilterMediaSample( NAME("AviSynthFilter memory media sample"), this, diff --git a/avisynth_filter/src/avs_handler.cpp b/avisynth_filter/src/avs_handler.cpp index 542121c..c14a663 100644 --- a/avisynth_filter/src/avs_handler.cpp +++ b/avisynth_filter/src/avs_handler.cpp @@ -140,6 +140,16 @@ AvsHandler::CheckingScriptInstance::CheckingScriptInstance(AvsHandler &handler) : ScriptInstance(handler) { } +auto AvsHandler::CheckingScriptInstance::ReloadScript(const AM_MEDIA_TYPE &mediaType, bool ignoreDisconnect) -> bool { + if (__super::ReloadScript(mediaType, ignoreDisconnect)) { + StopScript(); + + return true; + } + + return false; +} + /** * Create media type based on a template while changing its subtype. Also change fields in format if necessary. * diff --git a/avisynth_filter/src/avs_handler.h b/avisynth_filter/src/avs_handler.h index a0522e0..fc692f1 100644 --- a/avisynth_filter/src/avs_handler.h +++ b/avisynth_filter/src/avs_handler.h @@ -27,7 +27,7 @@ class AvsHandler { AvsHandler &_handler; IScriptEnvironment *_env; PClip _scriptClip = nullptr; - VideoInfo _scriptVideoInfo; + VideoInfo _scriptVideoInfo = {}; REFERENCE_TIME _scriptAvgFrameDuration = 0; std::string _errorString; @@ -52,6 +52,7 @@ class AvsHandler { public: explicit CheckingScriptInstance(AvsHandler &handler); + auto ReloadScript(const AM_MEDIA_TYPE &mediaType, bool ignoreDisconnect) -> bool; auto GenerateMediaType(const Format::PixelFormat &pixelFormat, const AM_MEDIA_TYPE *templateMediaType) const -> CMediaType; constexpr auto GetScriptPixelType() const -> int { return _scriptVideoInfo.pixel_type;} }; @@ -81,7 +82,7 @@ class AvsHandler { const char *_versionString; std::filesystem::path _scriptPath = g_env.GetAvsPath(); - VideoInfo _sourceVideoInfo; + VideoInfo _sourceVideoInfo = {}; PClip _sourceClip = new SourceClip(_sourceVideoInfo); PVideoFrame _sourceDrainFrame = nullptr; REFERENCE_TIME _sourceAvgFrameDuration = 0; diff --git a/avisynth_filter/src/filter.cpp b/avisynth_filter/src/filter.cpp index cd1de80..4d28bdc 100644 --- a/avisynth_filter/src/filter.cpp +++ b/avisynth_filter/src/filter.cpp @@ -78,10 +78,10 @@ auto CAviSynthFilter::CheckConnect(PIN_DIRECTION direction, IPin *pPin) -> HRESU while (true) { hr = enumTypes->Next(1, &nextType, nullptr); if (hr == S_OK) { - const UniqueMediaTypePtr nextTypePtr(nextType); + const SharedMediaTypePtr nextTypePtr(nextType, MediaTypeDeleter); if (const Format::PixelFormat *optInputPixelFormat = GetInputPixelFormat(nextType); - optInputPixelFormat && std::ranges::find(_compatibleMediaTypes, *static_cast(nextType), &MediaTypePair::input) == _compatibleMediaTypes.cend()) { + optInputPixelFormat && std::ranges::find(_compatibleMediaTypes, optInputPixelFormat, &MediaTypePair::inputFormat) == _compatibleMediaTypes.cend()) { // invoke AviSynth script with each supported input pixel format, and observe the output avs type if (!g_avs->GetCheckingScriptInstance().ReloadScript(*nextType, _remoteControl.has_value())) { g_env.Log(L"Disconnect due to AvsFilterDisconnect()"); @@ -91,7 +91,8 @@ auto CAviSynthFilter::CheckConnect(PIN_DIRECTION direction, IPin *pPin) -> HRESU // all media types that share the same avs type are acceptable for output pin connection for (const Format::PixelFormat &avsPixelFormat : Format::LookupAvsType(g_avs->GetCheckingScriptInstance().GetScriptPixelType())) { - _compatibleMediaTypes.emplace_back(*nextType, g_avs->GetCheckingScriptInstance().GenerateMediaType(avsPixelFormat, nextType)); + const CMediaType outputType = g_avs->GetCheckingScriptInstance().GenerateMediaType(avsPixelFormat, nextType); + _compatibleMediaTypes.emplace_back(nextTypePtr, optInputPixelFormat, outputType, MediaTypeToPixelFormat(&outputType)); g_env.Log(L"Add compatible formats: input %s output %s", optInputPixelFormat->name.c_str(), avsPixelFormat.name.c_str()); } } @@ -109,8 +110,7 @@ auto CAviSynthFilter::CheckConnect(PIN_DIRECTION direction, IPin *pPin) -> HRESU auto CAviSynthFilter::CheckInputType(const CMediaType *mtIn) -> HRESULT { if (const Format::PixelFormat *optInputPixelFormat = MediaTypeToPixelFormat(mtIn); optInputPixelFormat && std::ranges::any_of(_compatibleMediaTypes, - [optInputPixelFormat](const Format::PixelFormat *optCompatibleFormatName) -> bool { return optInputPixelFormat == optCompatibleFormatName; }, - [](const MediaTypePair &pair) -> const Format::PixelFormat * { return MediaTypeToPixelFormat(&pair.input); })) { + [optInputPixelFormat](const MediaTypePair &pair) -> bool { return optInputPixelFormat == pair.inputFormat; })) { return S_OK; } @@ -130,7 +130,7 @@ auto CAviSynthFilter::GetMediaType(int iPosition, CMediaType *pMediaType) -> HRE return VFW_S_NO_MORE_ITEMS; } - *pMediaType = _compatibleMediaTypes[iPosition].output; + *pMediaType = _compatibleMediaTypes[iPosition].outputType; g_env.Log(L"GetMediaType() offer media type %d with %s", iPosition, MediaTypeToPixelFormat(pMediaType)->name.c_str()); return S_OK; @@ -141,8 +141,6 @@ auto CAviSynthFilter::CheckTransform(const CMediaType *mtIn, const CMediaType *m bool isOutputTypeOk = mtOut == &m_pOutput->CurrentMediaType(); if (!isInputTypeOk) { - g_avs->GetCheckingScriptInstance().ReloadScript(*mtIn, true); - isInputTypeOk = std::ranges::any_of(InputToOutputMediaType(mtIn), [this](const CMediaType &newOutputType) -> bool { return m_pOutput->GetConnected()->QueryAccept(&newOutputType) == S_OK; }); @@ -151,15 +149,15 @@ auto CAviSynthFilter::CheckTransform(const CMediaType *mtIn, const CMediaType *m } if (!isOutputTypeOk) { - if (const Format::PixelFormat *optOutputPixelFormat = MediaTypeToPixelFormat(mtOut)) { + const Format::PixelFormat *optInputPixelFormat = MediaTypeToPixelFormat(mtIn); + const Format::PixelFormat *optOutputPixelFormat = MediaTypeToPixelFormat(mtOut); + if (optInputPixelFormat && optOutputPixelFormat) { const auto &iter = std::ranges::find_if(_compatibleMediaTypes, - [&optOutputPixelFormat](const Format::PixelFormat *optCompatiblePixelFormat) -> bool { - return optOutputPixelFormat == optCompatiblePixelFormat; - }, - [](const MediaTypePair &pair) -> const Format::PixelFormat * { return MediaTypeToPixelFormat(&pair.output); }); + [optInputPixelFormat, optOutputPixelFormat](const MediaTypePair &pair) -> bool { + return optInputPixelFormat == pair.inputFormat && optOutputPixelFormat == pair.outputFormat; + }); isOutputTypeOk = iter != _compatibleMediaTypes.cend(); - g_env.Log(L"CheckTransform() for output type: result: %i output %s offered input: %s compatible input: %s", - isOutputTypeOk, optOutputPixelFormat->name.c_str(), MediaTypeToPixelFormat(mtIn)->name.c_str(), MediaTypeToPixelFormat(&iter->input)->name.c_str()); + g_env.Log(L"CheckTransform() for %s -> %s, result: %i", optInputPixelFormat->name.c_str(), optOutputPixelFormat->name.c_str(), isOutputTypeOk); } } @@ -224,16 +222,16 @@ auto CAviSynthFilter::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin int mediaTypeReconnectionIndex = 0; const CMediaType *reconnectInputMediaType = nullptr; - for (const auto &[compatibleInput, compatibleOutput] : _compatibleMediaTypes) { - if (optConnectionOutputPixelFormat == MediaTypeToPixelFormat(&compatibleOutput)) { - if (optConnectionInputPixelFormat == MediaTypeToPixelFormat(&compatibleInput)) { + for (const auto &[inputType, compatibleInput, outputType, compatibleOutput] : _compatibleMediaTypes) { + if (optConnectionOutputPixelFormat == compatibleInput) { + if (optConnectionInputPixelFormat == compatibleOutput) { g_env.Log(L"Connected with types: in %s out %s", optConnectionInputPixelFormat->name.c_str(), optConnectionOutputPixelFormat->name.c_str()); isMediaTypesCompatible = true; break; } if (mediaTypeReconnectionIndex >= _mediaTypeReconnectionWatermark) { - reconnectInputMediaType = &compatibleInput; + reconnectInputMediaType = reinterpret_cast(inputType.get()); _mediaTypeReconnectionWatermark += 1; break; } diff --git a/avisynth_filter/src/filter.h b/avisynth_filter/src/filter.h index adf3215..25fb53e 100644 --- a/avisynth_filter/src/filter.h +++ b/avisynth_filter/src/filter.h @@ -8,6 +8,7 @@ #include "format.h" #include "frame_handler.h" #include "remote_control.h" +#include "util.h" namespace AvsFilter { @@ -21,7 +22,7 @@ class CAviSynthFilter public: CAviSynthFilter(LPUNKNOWN pUnk, HRESULT *phr); - virtual ~CAviSynthFilter(); + ~CAviSynthFilter() override; DECLARE_IUNKNOWN @@ -52,11 +53,15 @@ class CAviSynthFilter private: struct MediaTypePair { - CMediaType input; - CMediaType output; + const SharedMediaTypePtr &inputType; + const Format::PixelFormat *inputFormat; + + CMediaType outputType; + const Format::PixelFormat *outputFormat; }; - static constexpr auto InputToOutputMediaType(const AM_MEDIA_TYPE *mtIn) { + static auto InputToOutputMediaType(const AM_MEDIA_TYPE *mtIn) { + g_avs->GetCheckingScriptInstance().ReloadScript(*mtIn, true); return Format::LookupAvsType(g_avs->GetCheckingScriptInstance().GetScriptPixelType()) | std::views::transform([mtIn](const Format::PixelFormat &pixelFormat) -> CMediaType { return g_avs->GetCheckingScriptInstance().GenerateMediaType(pixelFormat, mtIn); }); diff --git a/avisynth_filter/src/format.cpp b/avisynth_filter/src/format.cpp index bb916d7..c1d8ceb 100644 --- a/avisynth_filter/src/format.cpp +++ b/avisynth_filter/src/format.cpp @@ -159,8 +159,7 @@ auto Format::CopyFromInput(const VideoFormat &videoFormat, const BYTE *srcBuffer return; } - const int srcUVHeight = height / videoFormat.pixelFormat->subsampleHeightRatio; - if (videoFormat.pixelFormat->areUVPlanesInterleaved) { + if (const int srcUVHeight = height / videoFormat.pixelFormat->subsampleHeightRatio; videoFormat.pixelFormat->areUVPlanesInterleaved) { const BYTE *srcUVStart = srcBuffer + srcMainPlaneSize; const int srcUVStride = srcMainPlaneStride * 2 / videoFormat.pixelFormat->subsampleWidthRatio; const int srcUVRowSize = rowSize * 2 / videoFormat.pixelFormat->subsampleWidthRatio; @@ -226,8 +225,7 @@ auto Format::CopyToOutput(const VideoFormat &videoFormat, const std::arraysubsampleHeightRatio; - if (videoFormat.pixelFormat->areUVPlanesInterleaved) { + if (const int dstUVHeight = height / videoFormat.pixelFormat->subsampleHeightRatio; videoFormat.pixelFormat->areUVPlanesInterleaved) { BYTE *dstUVStart = dstBuffer + dstMainPlaneSize; const int dstUVStride = dstMainPlaneStride * 2 / videoFormat.pixelFormat->subsampleWidthRatio; const int dstUVRowSize = rowSize * 2 / videoFormat.pixelFormat->subsampleWidthRatio; diff --git a/avisynth_filter/src/frame_handler.cpp b/avisynth_filter/src/frame_handler.cpp index 1e31675..80811dc 100644 --- a/avisynth_filter/src/frame_handler.cpp +++ b/avisynth_filter/src/frame_handler.cpp @@ -85,8 +85,7 @@ auto FrameHandler::AddInputSample(IMediaSample *inSample) -> HRESULT { HDRSideData hdrSideData; { - const ATL::CComQIPtr inSampleSideData(inSample); - if (inSampleSideData != nullptr) { + if (const ATL::CComQIPtr inSampleSideData(inSample); inSampleSideData != nullptr) { hdrSideData.ReadFrom(inSampleSideData); if (const std::optional optHdr = hdrSideData.GetHDRData()) { @@ -106,7 +105,7 @@ auto FrameHandler::AddInputSample(IMediaSample *inSample) -> HRESULT { _sourceFrames.emplace(std::piecewise_construct, std::forward_as_tuple(_nextSourceFrameNb), - std::forward_as_tuple(_nextSourceFrameNb, avsFrame, inSampleStartTime, UniqueMediaTypePtr(pmtIn), hdrSideData)); + std::forward_as_tuple(_nextSourceFrameNb, avsFrame, inSampleStartTime, SharedMediaTypePtr(pmtIn, MediaTypeDeleter), hdrSideData)); g_env.Log(L"Stored source frame: %6i at %10lli ~ %10lli duration(literal) %10lli nextSourceFrameNb %6i", _nextSourceFrameNb, inSampleStartTime, inSampleStopTime, inSampleStopTime - inSampleStartTime, _nextSourceFrameNb); @@ -241,6 +240,7 @@ auto FrameHandler::ResetInputProperties() -> void { } auto FrameHandler::ResetOutputProperties() -> void { + // to ensure these non-atomic properties are only modified by their sole consumer the worker thread ASSERT(!_outputThread.joinable() || std::this_thread::get_id() == _outputThread.get_id()); _nextProcessSrcFrameNb = 0; @@ -260,7 +260,7 @@ auto FrameHandler::PrepareForDelivery(PVideoFrame scriptFrame, ATL::CComPtrGetMediaType(&pmtOut); - if (const UniqueMediaTypePtr pmtOutPtr(pmtOut); pmtOut != nullptr && pmtOut->pbFormat != nullptr) { + if (const SharedMediaTypePtr pmtOutPtr(pmtOut, MediaTypeDeleter); pmtOut != nullptr && pmtOut->pbFormat != nullptr) { _filter.StopStreaming(); _filter.m_pOutput->SetMediaType(static_cast(pmtOut)); @@ -366,8 +366,7 @@ auto FrameHandler::ProcessOutputSamples() -> void { ResetOutputProperties(); _filter._reloadAvsSource = false; - const HRESULT hr = _filter.UpdateOutputFormat(_filter.m_pInput->CurrentMediaType()); - if (FAILED(hr)) { + if (const HRESULT hr = _filter.UpdateOutputFormat(_filter.m_pInput->CurrentMediaType()); FAILED(hr)) { _filter.AbortPlayback(hr); } @@ -409,11 +408,8 @@ auto FrameHandler::ProcessOutputSamples() -> void { const PVideoFrame scriptFrame = g_avs->GetMainScriptInstance().GetScriptClip()->GetFrame(_nextOutputFrameNb, g_avs->GetMainScriptInstance().GetEnv()); if (ATL::CComPtr outSample; PrepareForDelivery(scriptFrame, outSample, outputStartTime, outputStopTime)) { - { - const ATL::CComQIPtr outSampleSideData(outSample); - if (outSampleSideData != nullptr) { - processSrcFrames[0]->hdrSideData.WriteTo(outSampleSideData); - } + if (const ATL::CComQIPtr outSampleSideData(outSample); outSampleSideData != nullptr) { + processSrcFrames[0]->hdrSideData.WriteTo(outSampleSideData); } const std::unique_lock filterLock(_filter.m_csFilter); diff --git a/avisynth_filter/src/frame_handler.h b/avisynth_filter/src/frame_handler.h index 1ab156d..1863ada 100644 --- a/avisynth_filter/src/frame_handler.h +++ b/avisynth_filter/src/frame_handler.h @@ -57,7 +57,7 @@ class FrameHandler { int frameNb; PVideoFrame avsFrame; REFERENCE_TIME startTime; - UniqueMediaTypePtr mediaTypePtr; + SharedMediaTypePtr mediaTypePtr; HDRSideData hdrSideData; }; diff --git a/avisynth_filter/src/input_pin.cpp b/avisynth_filter/src/input_pin.cpp index 5d989da..ffa9ebc 100644 --- a/avisynth_filter/src/input_pin.cpp +++ b/avisynth_filter/src/input_pin.cpp @@ -24,12 +24,12 @@ auto STDMETHODCALLTYPE CAviSynthFilterInputPin::ReceiveConnection(IPin *pConnect const HRESULT receiveConnectionHr = __super::ReceiveConnection(pConnector, pmt); - const std::unique_lock lock(*m_pLock); - if (receiveConnectionHr == VFW_E_ALREADY_CONNECTED) { ASSERT(m_pAllocator != nullptr); if (CheckMediaType(static_cast(pmt)) == S_OK) { + const std::unique_lock lock(*m_pLock); + ALLOCATOR_PROPERTIES props, actual; CheckHr(m_pAllocator->Decommit()); diff --git a/avisynth_filter/src/prop_settings.cpp b/avisynth_filter/src/prop_settings.cpp index 1e6f463..23013a0 100644 --- a/avisynth_filter/src/prop_settings.cpp +++ b/avisynth_filter/src/prop_settings.cpp @@ -83,9 +83,8 @@ auto CAvsFilterPropSettings::OnReceiveMessage(HWND hwnd, UINT uMsg, WPARAM wPara if (const WORD eventTarget = LOWORD(wParam); eventTarget == IDC_EDIT_AVS_FILE) { std::array buffer; GetDlgItemTextW(hwnd, IDC_EDIT_AVS_FILE, buffer.data(), static_cast(buffer.size())); - const std::wstring newValue = std::wstring(buffer.data(), buffer.size()).c_str(); - if (newValue != _configAvsPath) { + if (const std::wstring newValue = std::wstring(buffer.data(), buffer.size()).c_str(); newValue != _configAvsPath) { _configAvsPath = newValue; SetDirty(); } diff --git a/avisynth_filter/src/registry.cpp b/avisynth_filter/src/registry.cpp index 72cdc91..17d95da 100644 --- a/avisynth_filter/src/registry.cpp +++ b/avisynth_filter/src/registry.cpp @@ -24,8 +24,8 @@ auto Registry::ReadString(const WCHAR *valueName) const -> std::wstring { std::array buffer; DWORD bufferSize = static_cast(buffer.size()); - const LSTATUS registryStatus = RegGetValueW(_registryKey, nullptr, valueName, RRF_RT_REG_SZ, nullptr, buffer.data(), &bufferSize); - if (registryStatus == ERROR_SUCCESS) { + if (const LSTATUS registryStatus = RegGetValueW(_registryKey, nullptr, valueName, RRF_RT_REG_SZ, nullptr, buffer.data(), &bufferSize); + registryStatus == ERROR_SUCCESS) { ret.assign(buffer.data(), bufferSize / sizeof(WCHAR) - 1); } } diff --git a/avisynth_filter/src/util.h b/avisynth_filter/src/util.h index 145d4be..2a7a810 100644 --- a/avisynth_filter/src/util.h +++ b/avisynth_filter/src/util.h @@ -7,12 +7,10 @@ namespace AvsFilter { -struct MediaTypeDeleter { - auto operator()(AM_MEDIA_TYPE *mediaType) const -> void { - DeleteMediaType(mediaType); - } -}; -using UniqueMediaTypePtr = std::unique_ptr; +inline auto MediaTypeDeleter(AM_MEDIA_TYPE *mediaType) -> void { + DeleteMediaType(mediaType); +} +using SharedMediaTypePtr = std::shared_ptr; auto ConvertWideToUtf8(const std::wstring &wideString) -> std::string; auto ConvertUtf8ToWide(const std::string &utf8String) -> std::wstring;