Skip to content

Commit

Permalink
Fix bug of not reloading the avs script in InputToOutputMediaType(), …
Browse files Browse the repository at this point in the history
…which desyncs the two avs cript instances
  • Loading branch information
CrendKing committed Apr 9, 2021
1 parent 9dc92ab commit 933813a
Show file tree
Hide file tree
Showing 12 changed files with 61 additions and 59 deletions.
9 changes: 3 additions & 6 deletions avisynth_filter/src/allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions avisynth_filter/src/avs_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
5 changes: 3 additions & 2 deletions avisynth_filter/src/avs_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class AvsHandler {
AvsHandler &_handler;
IScriptEnvironment *_env;
PClip _scriptClip = nullptr;
VideoInfo _scriptVideoInfo;
VideoInfo _scriptVideoInfo = {};
REFERENCE_TIME _scriptAvgFrameDuration = 0;
std::string _errorString;

Expand All @@ -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;}
};
Expand Down Expand Up @@ -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;
Expand Down
36 changes: 17 additions & 19 deletions avisynth_filter/src/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CMediaType *>(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()");
Expand All @@ -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());
}
}
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
});
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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<const CMediaType *>(inputType.get());
_mediaTypeReconnectionWatermark += 1;
break;
}
Expand Down
13 changes: 9 additions & 4 deletions avisynth_filter/src/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "format.h"
#include "frame_handler.h"
#include "remote_control.h"
#include "util.h"


namespace AvsFilter {
Expand All @@ -21,7 +22,7 @@ class CAviSynthFilter

public:
CAviSynthFilter(LPUNKNOWN pUnk, HRESULT *phr);
virtual ~CAviSynthFilter();
~CAviSynthFilter() override;

DECLARE_IUNKNOWN

Expand Down Expand Up @@ -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);
});
Expand Down
6 changes: 2 additions & 4 deletions avisynth_filter/src/format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -226,8 +225,7 @@ auto Format::CopyToOutput(const VideoFormat &videoFormat, const std::array<const
return;
}

const int dstUVHeight = height / videoFormat.pixelFormat->subsampleHeightRatio;
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;
Expand Down
18 changes: 7 additions & 11 deletions avisynth_filter/src/frame_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ auto FrameHandler::AddInputSample(IMediaSample *inSample) -> HRESULT {

HDRSideData hdrSideData;
{
const ATL::CComQIPtr<IMediaSideData> inSampleSideData(inSample);
if (inSampleSideData != nullptr) {
if (const ATL::CComQIPtr<IMediaSideData> inSampleSideData(inSample); inSampleSideData != nullptr) {
hdrSideData.ReadFrom(inSampleSideData);

if (const std::optional<const BYTE *> optHdr = hdrSideData.GetHDRData()) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -260,7 +260,7 @@ auto FrameHandler::PrepareForDelivery(PVideoFrame scriptFrame, ATL::CComPtr<IMed
AM_MEDIA_TYPE *pmtOut;
outSample->GetMediaType(&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<CMediaType *>(pmtOut));

Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -409,11 +408,8 @@ auto FrameHandler::ProcessOutputSamples() -> void {
const PVideoFrame scriptFrame = g_avs->GetMainScriptInstance().GetScriptClip()->GetFrame(_nextOutputFrameNb, g_avs->GetMainScriptInstance().GetEnv());

if (ATL::CComPtr<IMediaSample> outSample; PrepareForDelivery(scriptFrame, outSample, outputStartTime, outputStopTime)) {
{
const ATL::CComQIPtr<IMediaSideData> outSampleSideData(outSample);
if (outSampleSideData != nullptr) {
processSrcFrames[0]->hdrSideData.WriteTo(outSampleSideData);
}
if (const ATL::CComQIPtr<IMediaSideData> outSampleSideData(outSample); outSampleSideData != nullptr) {
processSrcFrames[0]->hdrSideData.WriteTo(outSampleSideData);
}

const std::unique_lock filterLock(_filter.m_csFilter);
Expand Down
2 changes: 1 addition & 1 deletion avisynth_filter/src/frame_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class FrameHandler {
int frameNb;
PVideoFrame avsFrame;
REFERENCE_TIME startTime;
UniqueMediaTypePtr mediaTypePtr;
SharedMediaTypePtr mediaTypePtr;
HDRSideData hdrSideData;
};

Expand Down
4 changes: 2 additions & 2 deletions avisynth_filter/src/input_pin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const CMediaType *>(pmt)) == S_OK) {
const std::unique_lock lock(*m_pLock);

ALLOCATOR_PROPERTIES props, actual;

CheckHr(m_pAllocator->Decommit());
Expand Down
3 changes: 1 addition & 2 deletions avisynth_filter/src/prop_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<WCHAR, STR_MAX_LENGTH> buffer;
GetDlgItemTextW(hwnd, IDC_EDIT_AVS_FILE, buffer.data(), static_cast<int>(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();
}
Expand Down
4 changes: 2 additions & 2 deletions avisynth_filter/src/registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ auto Registry::ReadString(const WCHAR *valueName) const -> std::wstring {
std::array<WCHAR, MAX_PATH> buffer;
DWORD bufferSize = static_cast<DWORD>(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);
}
}
Expand Down
10 changes: 4 additions & 6 deletions avisynth_filter/src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

namespace AvsFilter {

struct MediaTypeDeleter {
auto operator()(AM_MEDIA_TYPE *mediaType) const -> void {
DeleteMediaType(mediaType);
}
};
using UniqueMediaTypePtr = std::unique_ptr<AM_MEDIA_TYPE, MediaTypeDeleter>;
inline auto MediaTypeDeleter(AM_MEDIA_TYPE *mediaType) -> void {
DeleteMediaType(mediaType);
}
using SharedMediaTypePtr = std::shared_ptr<AM_MEDIA_TYPE>;

auto ConvertWideToUtf8(const std::wstring &wideString) -> std::string;
auto ConvertUtf8ToWide(const std::string &utf8String) -> std::wstring;
Expand Down

0 comments on commit 933813a

Please sign in to comment.