Skip to content

Commit

Permalink
Rename interface function names to Pascal Case like most other AviSyn…
Browse files Browse the repository at this point in the history
…th plugins do.

Support dynamic video window dimension change (rcSource, rcTarget).
  • Loading branch information
CrendKing committed May 2, 2020
1 parent 2970826 commit 02cef87
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 38 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A DirectShow filter that loads an AviSynth script and feed the frames to the video player.

This filter exports an "avsfilter_source()" function to the AviSynth script, which serves as a source plugin. This filter feeds the video samples from DirectShow upstream to the script. Then it sends the processed frame data to the downstream.
This filter exports an "AvsFilterSource()" function to the AviSynth script, which serves as a source plugin. This filter feeds the video samples from DirectShow upstream to the script. Then it sends the processed frame data to the downstream.

If you used ffdshow's AviSynth plugin, you may find this filter similar in many ways. On top of that, this filter is actively adding new features. Support most common input formats such as NV12, YUY2 and P010 etc.

Expand All @@ -23,13 +23,13 @@ Run uninstall.bat to unregister the filter and clean up user data.

The filter exports the following functions to the AviSynth script.

#### `avsfilter_source()`
#### `AvsFilterSource()`

The source function which returns a `clip` object. Similar to other source functions like `AviSource()`.

This function takes no argument.

#### `avsfilter_disconnect()`
#### `AvsFilterDisconnect()`

This function serves as a heuristic to disconnect the AviSynth Filter from DirectShow filter graph. Put at the end of the script file.

Expand All @@ -44,14 +44,14 @@ This function takes no argument.
Add a line of text to videos with less than 20 FPS. Otherwise disconnect the filter.

```
avsfilter_source()
AvsFilterSource()
fps = Round(FrameRate())
if (fps < 20) {
Subtitle("This video has low FPS")
Prefetch(4)
} else {
avsfilter_disconnect()
AvsFilterDisconnect()
}
```

Expand Down
6 changes: 3 additions & 3 deletions avisynth_filter/src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ DEFINE_GUID(CLSID_AviSynthFilter,

// {90C56868-7D47-4AA2-A42D-06406A6DB35F}
DEFINE_GUID(CLSID_AvsPropSettings,
0x90c56868, 0x7d47, 0x4aa2, 0xa4, 0x2d, 0x6, 0x40, 0x6a, 0x6d, 0xb3, 0x5f);
0x90c56868, 0x7d47, 0x4aa2, 0xa4, 0x2d, 0x06, 0x40, 0x6a, 0x6d, 0xb3, 0x5f);

// {E58206EF-C9F2-4F8C-BF0B-975C28552700}
DEFINE_GUID(CLSID_AvsPropStatus,
0xe58206ef, 0xc9f2, 0x4f8c, 0xbf, 0xb, 0x97, 0x5c, 0x28, 0x55, 0x27, 0x0);
0xe58206ef, 0xc9f2, 0x4f8c, 0xbf, 0x0b, 0x97, 0x5c, 0x28, 0x55, 0x27, 0x00);

// {871B4CAB-7E31-4E2C-8A9B-ED9AD64702DF}
DEFINE_GUID(IID_IAvsFilterSettings,
0x871b4cab, 0x7e31, 0x4e2c, 0x8a, 0x9b, 0xed, 0x9a, 0xd6, 0x47, 0x2, 0xdf);
0x871b4cab, 0x7e31, 0x4e2c, 0x8a, 0x9b, 0xed, 0x9a, 0xd6, 0x47, 0x02, 0xdf);

// {2A5B2CEC-D874-4ED8-B8D9-4043333037E4}
DEFINE_GUID(IID_IAvsFilterStatus,
Expand Down
72 changes: 47 additions & 25 deletions avisynth_filter/src/filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define CheckHr(expr) { hr = (expr); if (FAILED(hr)) { return hr; } }

auto __cdecl CreateAvsFilterSource(AVSValue args, void *user_data, IScriptEnvironment *env) -> AVSValue {
return reinterpret_cast<SourceClip *>(user_data);
return static_cast<SourceClip *>(user_data);
}

auto __cdecl CreateAvsFilterDisconnect(AVSValue args, void *user_data, IScriptEnvironment *env) -> AVSValue {
Expand Down Expand Up @@ -65,7 +65,7 @@ auto CAviSynthFilter::CheckConnect(PIN_DIRECTION direction, IPin *pPin) -> HRESU
if (inputDefinition != INVALID_DEFINITION && !IsInputUniqueByAvsType(inputDefinition)) {
// invoke AviSynth script with each supported input definition, and observe the output avs type
if (!ReloadAviSynth(nextType, true)) {
Log("Disconnect due to avsfilter_disconnect()");
Log("Disconnect due to AvsFilterDisconnect()");
return VFW_E_CANNOT_CONNECT;
}

Expand Down Expand Up @@ -222,30 +222,47 @@ auto CAviSynthFilter::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin
return CVideoTransformFilter::CompleteConnect(direction, pReceivePin);
}

auto CAviSynthFilter::StartStreaming() -> HRESULT {
const Format::VideoFormat newInputType = Format::GetVideoFormat(m_pInput->CurrentMediaType());
const Format::VideoFormat newOutputType = Format::GetVideoFormat(m_pOutput->CurrentMediaType());
auto CAviSynthFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) -> HRESULT {
HRESULT hr;

Log("new input type: definition %i, width %5i, height %5i, codec %#10x",
newInputType.definition, newInputType.bmi.biWidth, newInputType.bmi.biHeight, newInputType.bmi.biCompression);
Log("new output type: definition %i, width %5i, height %5i, codec %#10x",
newOutputType.definition, newOutputType.bmi.biWidth, newOutputType.bmi.biHeight, newOutputType.bmi.biCompression);
AM_MEDIA_TYPE *pmtIn;
if (pIn->GetMediaType(&pmtIn) == S_OK) {
DeleteMediaType(pmtIn);

if (_inputFormat != newInputType) {
_inputFormat = newInputType;
_reloadAvsFile = true;
}
const Format::VideoFormat newInputType = Format::GetVideoFormat(m_pInput->CurrentMediaType());

Log("new input type: definition %i, width %5i, height %5i, codec %#10x",
newInputType.definition, newInputType.bmi.biWidth, newInputType.bmi.biHeight, newInputType.bmi.biCompression);

if (_outputFormat != newOutputType) {
_outputFormat = newOutputType;
_reloadAvsFile = true;
if (_inputFormat != newInputType) {
_inputFormat = newInputType;
_reloadAvsFile = true;
}
}

return CVideoTransformFilter::StartStreaming();
}
bool sendOutputFormat = false;
AM_MEDIA_TYPE *pmtOut;
if (pOut->GetMediaType(&pmtOut) == S_OK) {
DeleteMediaType(pmtOut);
sendOutputFormat = true;

auto CAviSynthFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) -> HRESULT {
HRESULT hr;
const Format::VideoFormat newOutputType = Format::GetVideoFormat(m_pOutput->CurrentMediaType());

Log("new output type: definition %i, width %5i, height %5i, codec %#10x",
newOutputType.definition, newOutputType.bmi.biWidth, newOutputType.bmi.biHeight, newOutputType.bmi.biCompression);

if (_outputFormat != newOutputType) {
_outputFormat = newOutputType;
_reloadAvsFile = true;
}
}

if (memcmp(&_outputFormat.vih->rcSource, &_inputFormat.vih->rcSource, sizeof(RECT)) != 0 ||
memcmp(&_outputFormat.vih->rcTarget, &_inputFormat.vih->rcTarget, sizeof(RECT)) != 0) {
memcpy(&_outputFormat.vih->rcSource, &_inputFormat.vih->rcSource, sizeof(RECT));
memcpy(&_outputFormat.vih->rcTarget, &_inputFormat.vih->rcTarget, sizeof(RECT));
sendOutputFormat = true;
}

CRefTime streamTime;
CheckHr(StreamTime(streamTime));
Expand Down Expand Up @@ -287,6 +304,11 @@ auto CAviSynthFilter::Transform(IMediaSample *pIn, IMediaSample *pOut) -> HRESUL
IMediaSample *outSample = nullptr;
CheckHr(InitializeOutputSample(nullptr, &outSample));

if (sendOutputFormat) {
CheckHr(outSample->SetMediaType(&m_pOutput->CurrentMediaType()));
sendOutputFormat = false;
}

// even if missing sample times from upstream, we always set times for output samples in case downstream needs them
REFERENCE_TIME outStartTime = _deliveryFrameNb * _timePerFrame;
REFERENCE_TIME outStopTime = outStartTime + _timePerFrame;
Expand Down Expand Up @@ -512,16 +534,16 @@ auto CAviSynthFilter::ReloadAviSynth() -> void {

/**
* Create new AviSynth script clip with specified media type.
* If allowDisconnect == true, return false early if no avs script or avsfilter_disconnect() is returned from script
* If allowDisconnect == true, return false early if no avs script or AvsFilterDisconnect() is returned from script
*/
auto CAviSynthFilter::ReloadAviSynth(const AM_MEDIA_TYPE *mediaType, bool allowDisconnect) -> bool {
DeleteAviSynth();

_avsSourceVideoInfo = Format::GetVideoFormat(*mediaType).videoInfo;

_avsEnv = CreateScriptEnvironment2();
_avsEnv->AddFunction("avsfilter_source", "", CreateAvsFilterSource, new SourceClip(_avsSourceVideoInfo, _frameHandler));
_avsEnv->AddFunction("avsfilter_disconnect", "", CreateAvsFilterDisconnect, nullptr);
_avsEnv->AddFunction("AvsFilterSource", "", CreateAvsFilterSource, new SourceClip(_avsSourceVideoInfo, _frameHandler));
_avsEnv->AddFunction("AvsFilterDisconnect", "", CreateAvsFilterDisconnect, nullptr);

AVSValue invokeResult;
std::string errorScript;
Expand All @@ -538,7 +560,7 @@ auto CAviSynthFilter::ReloadAviSynth(const AM_MEDIA_TYPE *mediaType, bool allowD
return false;
}

AVSValue evalArgs[] = { AVSValue("return avsfilter_source()")
AVSValue evalArgs[] = { AVSValue("return AvsFilterSource()")
, AVSValue(EVAL_FILENAME) };
invokeResult = _avsEnv->Invoke("Eval", AVSValue(evalArgs, 2), nullptr);
}
Expand All @@ -553,7 +575,7 @@ auto CAviSynthFilter::ReloadAviSynth(const AM_MEDIA_TYPE *mediaType, bool allowD
}

if (!errorScript.empty()) {
errorScript.insert(0, "return avsfilter_source().Subtitle(\"");
errorScript.insert(0, "return AvsFilterSource().Subtitle(\"");
errorScript.append("\")");
AVSValue evalArgs[] = { AVSValue(errorScript.c_str())
, AVSValue(EVAL_FILENAME) };
Expand Down
1 change: 0 additions & 1 deletion avisynth_filter/src/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ class CAviSynthFilter
auto CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) -> HRESULT override;
auto DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProperties) -> HRESULT override;
auto CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) -> HRESULT override;
auto StartStreaming() -> HRESULT override;
auto Transform(IMediaSample *pIn, IMediaSample *pOut) -> HRESULT override;
auto BeginFlush() -> HRESULT override;

Expand Down
7 changes: 4 additions & 3 deletions avisynth_filter/src/format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ auto Format::VideoFormat::operator!=(const VideoFormat &other) const -> bool {
return definition != other.definition
|| memcmp(&videoInfo, &other.videoInfo, sizeof(videoInfo)) != 0
|| bmi.biSize != other.bmi.biSize
|| memcmp(&bmi, &other.bmi, bmi.biSize) != 0;
|| memcmp(&bmi, &other.bmi, bmi.biSize) != 0
|| memcmp(vih, other.vih, sizeof(VIDEOINFOHEADER)) != 0;
}

auto Format::LookupMediaSubtype(const CLSID &mediaSubtype) -> int {
Expand Down Expand Up @@ -72,8 +73,8 @@ auto Format::GetBitmapInfo(AM_MEDIA_TYPE &mediaType) -> BITMAPINFOHEADER * {
auto Format::GetVideoFormat(const AM_MEDIA_TYPE &mediaType) -> VideoFormat {
VideoFormat info;

const VIDEOINFOHEADER *vih = reinterpret_cast<VIDEOINFOHEADER *>(mediaType.pbFormat);
const REFERENCE_TIME frameTime = vih->AvgTimePerFrame > 0 ? vih->AvgTimePerFrame : DEFAULT_AVG_TIME_PER_FRAME;
info.vih = reinterpret_cast<VIDEOINFOHEADER *>(mediaType.pbFormat);
const REFERENCE_TIME frameTime = info.vih->AvgTimePerFrame > 0 ? info.vih->AvgTimePerFrame : DEFAULT_AVG_TIME_PER_FRAME;

info.definition = LookupMediaSubtype(mediaType.subtype);
info.bmi = *GetBitmapInfo(const_cast<AM_MEDIA_TYPE &>(mediaType));
Expand Down
1 change: 1 addition & 0 deletions avisynth_filter/src/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Format {
int definition;
VideoInfo videoInfo;
BITMAPINFOHEADER bmi;
VIDEOINFOHEADER *vih;

auto operator!=(const VideoFormat &other) const -> bool;
};
Expand Down
2 changes: 1 addition & 1 deletion avisynth_filter/src/pch.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include <codeanalysis\warnings.h>
#include <codeanalysis/warnings.h>
#pragma warning(push, 0)
#pragma warning(disable: ALL_CODE_ANALYSIS_WARNINGS 26812))

Expand Down

0 comments on commit 02cef87

Please sign in to comment.