Remove the DirectShow VideoProvider. Fixes #930.

Originally committed to SVN as r3195.
This commit is contained in:
Karl Blomster 2009-07-23 00:12:22 +00:00
parent 5e902e2ef1
commit 352df194aa
8 changed files with 0 additions and 1392 deletions

View File

@ -1,594 +0,0 @@
/*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: VideoSink.cpp,v 1.8 2007/01/17 23:40:51 mike Exp $
*
*/
#include "config.h"
#ifdef WITH_DIRECTSHOW
#include <windows.h>
#ifdef __WXDEBUG__
#undef __WXDEBUG__
#endif
typedef TCHAR* PTCHAR;
#include <streams.h>
#include <dvdmedia.h>
#include "VideoSink.h"
#include "initguid.h"
class CVideoSink;
// CLSID for videosink: {F13D3732-96BD-4108-AFEB-E85F68FF64DC}
//DEFINE_GUID(CLSID_AegiVideoSink, 0xf13d3732, 0x96bd, 0x4108, 0xaf, 0xeb, 0xe8, 0x5f, 0x68, 0xff, 0x64, 0xdc);
// {E9C80780-4C07-4b36-87D4-5241CD0C6FE2}
DEFINE_GUID(CLSID_AegiVideoSink, 0xe9c80780, 0x4c07, 0x4b36, 0x87, 0xd4, 0x52, 0x41, 0xcd, 0xc, 0x6f, 0xe2);
static int GetBPP(const BITMAPINFOHEADER& h) {
switch (h.biCompression) {
case MAKEFOURCC('Y','U','Y','2'): return 16;
case MAKEFOURCC('Y','V','1','2'): return 12;
case 0: return h.biBitCount;
}
return 0;
}
[uuid("2EE04A02-4AF5-43f8-B05B-5DEB66473419")]
interface IVSAllocator : public IUnknown {
STDMETHOD(SetNextMT)(const AM_MEDIA_TYPE *pMT) = 0;
};
class CVSAllocator : public CMemAllocator, public IVSAllocator {
CMediaType *m_nextmt;
public:
CVSAllocator(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr) : CMemAllocator(pName, pUnk, phr), m_nextmt(NULL) { }
~CVSAllocator() {
delete m_nextmt;
}
STDMETHOD(SetNextMT)(const AM_MEDIA_TYPE *pMT) {
CMediaType *newMT = new CMediaType(*pMT);
newMT = (CMediaType *)InterlockedExchangePointer((void **)&m_nextmt, newMT);
if (newMT != NULL)
delete pMT;
return S_OK;
}
STDMETHOD(GetBuffer)(IMediaSample **ppS, REFERENCE_TIME *pStart, REFERENCE_TIME *pStop, DWORD dwFlags) {
CMediaType *pMT = (CMediaType *)InterlockedExchangePointer((void **)&m_nextmt, NULL);
if (pMT != NULL) {
BITMAPINFOHEADER *bmh = NULL;
if (pMT->formattype == FORMAT_VideoInfo)
bmh = &((VIDEOINFOHEADER *)pMT->pbFormat)->bmiHeader;
else if (pMT->formattype == FORMAT_VideoInfo2)
bmh = &((VIDEOINFOHEADER2 *)pMT->pbFormat)->bmiHeader;
if (bmh != NULL) {
ALLOCATOR_PROPERTIES ap, act;
Decommit();
GetProperties(&ap);
long newsize = (bmh->biWidth * abs(bmh->biHeight) * GetBPP(*bmh)) >> 3;
if (ap.cbBuffer < newsize)
ap.cbBuffer = newsize;
SetProperties(&ap, &act);
Commit();
}
}
HRESULT hr = CMemAllocator::GetBuffer(ppS, pStart, pStop, dwFlags);
if (SUCCEEDED(hr) && pMT != NULL)
(*ppS)->SetMediaType(pMT);
if (pMT != NULL)
delete pMT;
return hr;
}
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
if (riid == __uuidof(IVSAllocator))
return GetInterface((IVSAllocator *)this, ppv);
return CMemAllocator::NonDelegatingQueryInterface(riid, ppv);
}
};
class CVideoSinkPin : public CRenderedInputPin {
bool m_changedmt;
unsigned m_types;
CVideoSink *m_sink;
HRESULT CheckMediaType(const CMediaType *pMT) {
if (pMT->majortype != MEDIATYPE_Video ||
(pMT->formattype != FORMAT_VideoInfo && pMT->formattype != FORMAT_VideoInfo2))
return VFW_E_TYPE_NOT_ACCEPTED;
if (pMT->subtype == MEDIASUBTYPE_RGB24 && m_types & IVS_RGB24)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_RGB32 && m_types & IVS_RGB32)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_YUY2 && m_types & IVS_YUY2)
return S_OK;
if (pMT->subtype == MEDIASUBTYPE_YV12 && m_types & IVS_YV12)
return S_OK;
return VFW_E_TYPE_NOT_ACCEPTED;
}
STDMETHOD(Receive)(IMediaSample *pS);
STDMETHOD(EndOfStream)();
STDMETHOD(BeginFlush)();
public:
CVideoSinkPin(CVideoSink *sink, HRESULT *phr);
STDMETHOD(GetAllocator)(IMemAllocator **ppAllocator) {
CAutoLock cObjectLock(m_pLock);
if (m_pAllocator == NULL) {
HRESULT hr = S_OK;
m_pAllocator = new CVSAllocator(NAME("CVSAllocator"), NULL, &hr);
if (FAILED(hr)) {
delete m_pAllocator;
m_pAllocator = NULL;
return hr;
}
m_pAllocator->AddRef();
}
ASSERT(m_pAllocator != NULL);
*ppAllocator = m_pAllocator;
m_pAllocator->AddRef();
return NOERROR;
}
STDMETHOD(NotifyAllocator)(IMemAllocator *pAlloc, BOOL bReadOnly) {
CAutoLock cObjectLock(m_pLock);
CComQIPtr<IVSAllocator> pVSA(pAlloc);
if (!pVSA)
return E_NOINTERFACE;
if (m_changedmt) {
m_changedmt = false;
pVSA->SetNextMT(&m_mt);
}
return CRenderedInputPin::NotifyAllocator(pAlloc, bReadOnly);
}
HRESULT SetMediaType(const CMediaType *pMT) {
HRESULT hr = CRenderedInputPin::SetMediaType(pMT);
if (FAILED(hr))
return hr;
unsigned type, width, height, bpp, arx, ary;
int stride;
if (FAILED(hr = GetFrameFormat(&type, &width, &height, &stride, &bpp, &arx, &ary, NULL)))
return hr;
if ((stride & 15) != 0) { // extend
CMediaType newMT(m_mt);
if (newMT.formattype == FORMAT_VideoInfo) {
VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)newMT.pbFormat;
vh->bmiHeader.biWidth = ((abs(stride) + 15) & ~15) / bpp;
vh->rcTarget.left = vh->rcTarget.top = 0;
vh->rcTarget.right = width;
vh->rcTarget.bottom = height;
vh->rcSource = vh->rcTarget;
} else if (newMT.formattype == FORMAT_VideoInfo2) {
VIDEOINFOHEADER2 *vh = (VIDEOINFOHEADER2 *)newMT.pbFormat;
vh->bmiHeader.biWidth = ((abs(stride) + 15) & ~15) / bpp;
vh->rcTarget.left = vh->rcTarget.top = 0;
vh->rcTarget.right = width;
vh->rcTarget.bottom = height;
vh->rcSource = vh->rcTarget;
} else
return E_FAIL;
hr = m_Connected->QueryAccept(&newMT);
if (SUCCEEDED(hr)) {
hr = CRenderedInputPin::SetMediaType(&newMT);
if (FAILED(hr))
return hr;
CComQIPtr<IVSAllocator> pVSA(m_pAllocator);
if (pVSA)
pVSA->SetNextMT(&newMT);
else
m_changedmt = true;
}
}
return S_OK;
}
BOOL AtEOF() { return m_bAtEndOfStream; }
REFERENCE_TIME SegStartTime() { return m_tStart; }
unsigned GetTypes() { return m_types; }
void SetTypes(unsigned t) { m_types = t; }
HRESULT GetFrameFormat(unsigned *type, unsigned *width, unsigned *height, int *stride,
unsigned *pbpp, unsigned *arx, unsigned *ary, __int64 *def_duration)
{
if (!IsConnected())
return VFW_E_NOT_CONNECTED;
unsigned bpp;
if (m_mt.subtype == MEDIASUBTYPE_RGB24)
*type = IVS_RGB24, bpp = 3;
else if (m_mt.subtype == MEDIASUBTYPE_RGB32)
*type = IVS_RGB32, bpp = 4;
else if (m_mt.subtype == MEDIASUBTYPE_YUY2)
*type = IVS_YUY2, bpp = 2;
else if (m_mt.subtype == MEDIASUBTYPE_YV12)
*type = IVS_YV12, bpp = 1;
else
return VFW_E_INVALID_MEDIA_TYPE;
if (pbpp)
*pbpp = bpp;
BITMAPINFOHEADER *bmh;
RECT rct;
if (m_mt.formattype == FORMAT_VideoInfo && m_mt.FormatLength() >= sizeof(VIDEOINFOHEADER)) {
VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)m_mt.Format();
bmh = &vh->bmiHeader;
rct = vh->rcTarget;
if (arx)
*arx = 1;
if (*ary)
*ary = 1;
if (def_duration)
*def_duration = vh->AvgTimePerFrame;
} else if (m_mt.formattype == FORMAT_VideoInfo2 && m_mt.FormatLength() >= sizeof(VIDEOINFOHEADER2)) {
VIDEOINFOHEADER2 *vh = (VIDEOINFOHEADER2 *)m_mt.Format();
bmh = &vh->bmiHeader;
rct = vh->rcTarget;
if (arx)
*arx = vh->dwPictAspectRatioX;
if (ary)
*ary = vh->dwPictAspectRatioY;
if (def_duration)
*def_duration = vh->AvgTimePerFrame;
} else
return VFW_E_INVALID_MEDIA_TYPE;
if (stride)
*stride = (bmh->biHeight > 0 && bmh->biCompression == 0 ? -1 : 1) * (int)bmh->biWidth * (int)bpp;
if (rct.right != 0)
*width = rct.right - rct.left;
else
*width = bmh->biWidth;
if (rct.bottom != 0)
*height = rct.bottom - rct.top;
else
*height = abs(bmh->biHeight);
return S_OK;
}
DECLARE_IUNKNOWN;
};
class CVideoSink :
public CBaseFilter,
public IVideoSink,
public IVideoSink2,
public IAMFilterMiscFlags
{
CVideoSinkPin *m_pin;
CRendererPosPassThru *m_rpp;
CCritSec m_lock;
int GetPinCount() { return 1; }
CBasePin *GetPin(int n) { return n == 0 ? m_pin : NULL; }
CComPtr<IMediaSample> m_sample;
HANDLE m_hEvent1, m_hEvent2, m_hNotify;
CComPtr<IVideoSinkNotify> m_notify;
public:
CVideoSink(IUnknown *pUnk, HRESULT *phr) :
CBaseFilter(_T("CVideoSink"), pUnk, &m_lock, CLSID_AegiVideoSink),
m_pin(NULL),
m_rpp(NULL)
{
m_pin = new CVideoSinkPin(this, phr);
if (FAILED(*phr))
return;
m_rpp = new CRendererPosPassThru(NAME("CVideoSink PosPassThru"), CBaseFilter::GetOwner(), phr, m_pin);
if (FAILED(*phr))
return;
m_hEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hNotify = NULL;
}
~CVideoSink() {
m_sample = NULL;
delete m_rpp;
delete m_pin;
CloseHandle(m_hEvent1);
CloseHandle(m_hEvent2);
}
CCritSec *pStateLock() { return m_pLock; }
// called when lock is held
HRESULT Receive(IMediaSample *pS) {
if (pS == NULL)
m_rpp->EOS();
else
m_rpp->RegisterMediaTime(pS);
// notify callback
CComPtr<IVideoSinkNotify> notify = m_notify;
HANDLE hNotify = m_hNotify;
if (notify || hNotify) {
// save our sample
m_sample = pS;
// notify receiver
SetEvent(m_hEvent1);
}
pStateLock()->Unlock();
if (notify || hNotify) {
if (notify)
notify->FrameReady();
if (hNotify)
SetEvent(hNotify);
// wait until the thing is processed
WaitForSingleObject(m_hEvent2, INFINITE);
}
if (pS == NULL)
NotifyEvent(EC_COMPLETE, 0, (LONG_PTR)static_cast<IBaseFilter*>(this));
return S_OK;
}
HRESULT BeginFlush() {
CAutoLock lock(pStateLock());
ResetEvent(m_hEvent1);
m_sample = NULL;
SetEvent(m_hEvent2);
return S_OK;
}
STDMETHOD(Stop)() {
BeginFlush();
return CBaseFilter::Stop();
}
// IVideoSink
STDMETHOD(SetAllowedTypes)(unsigned types) {
CAutoLock lock(pStateLock());
m_pin->SetTypes(types);
return S_OK;
}
STDMETHOD(GetAllowedTypes)(unsigned *types) {
CheckPointer(types, E_POINTER);
CAutoLock lock(pStateLock());
*types = m_pin->GetTypes();
return S_OK;
}
STDMETHOD(NotifyFrame)(IVideoSinkNotify *notify) {
CAutoLock lock(pStateLock());
m_notify = notify;
return S_OK;
}
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary) {
CheckPointer(type, E_POINTER);
CheckPointer(width, E_POINTER);
CheckPointer(height, E_POINTER);
CAutoLock lock(pStateLock());
return m_pin->GetFrameFormat(type, width, height, NULL, NULL, arx, ary, NULL);
}
STDMETHOD(ReadFrame)(ReadFrameFunc f, void *arg) {
{
CAutoLock lock(pStateLock());
if (m_pin->AtEOF()) {
if (WaitForSingleObject(m_hEvent1, 0) == WAIT_OBJECT_0)
SetEvent(m_hEvent2);
return S_FALSE;
}
}
WaitForSingleObject(m_hEvent1, INFINITE);
HRESULT hr = S_OK;
{
CAutoLock lock(pStateLock());
CComPtr<IMediaSample> pS(m_sample);
m_sample = NULL;
if (!pS)
hr = S_FALSE;
else {
REFERENCE_TIME rtS, rtE;
if (SUCCEEDED(pS->GetTime(&rtS, &rtE)))
rtS += m_pin->SegStartTime();
else
rtS = -1;
if (f) {
unsigned type, srcW, srcH, arx, ary, srcBPP;
int srcS;
BYTE *srcP;
if (FAILED(m_pin->GetFrameFormat(&type, &srcW, &srcH, &srcS, &srcBPP, &arx, &ary, NULL)) ||
FAILED(pS->GetPointer(&srcP)))
hr = E_FAIL;
else {
if (srcS < 0)
srcP += abs(srcS) * (srcH - 1);
f(rtS, type, srcBPP, srcP, srcW, srcH, srcS, arx, ary, arg);
}
}
}
}
SetEvent(m_hEvent2);
return hr;
}
// IVideoSink2
STDMETHOD(NotifyFrame)(HANDLE hEvent) {
m_hNotify = hEvent;
return S_OK;
}
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary, __int64 *def_duration) {
CheckPointer(type, E_POINTER);
CheckPointer(width, E_POINTER);
CheckPointer(height, E_POINTER);
CAutoLock lock(pStateLock());
return m_pin->GetFrameFormat(type, width, height, NULL, NULL, arx, ary, def_duration);
}
// IAMFilterMiscFlags
STDMETHOD_(ULONG, GetMiscFlags)() { return AM_FILTER_MISC_FLAGS_IS_RENDERER; }
// COM
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv) {
CAutoLock lock(pStateLock());
if (riid == __uuidof(IVideoSink))
return GetInterface((IVideoSink *)this, ppv);
if (riid == __uuidof(IVideoSink2))
return GetInterface((IVideoSink2 *)this, ppv);
if (riid == __uuidof(IAMFilterMiscFlags))
return GetInterface((IAMFilterMiscFlags *)this, ppv);
if (riid == IID_IMediaSeeking || riid == IID_IMediaPosition)
return m_rpp->NonDelegatingQueryInterface(riid, ppv);
return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
}
};
CVideoSinkPin::CVideoSinkPin(CVideoSink *sink, HRESULT *phr) :
CRenderedInputPin(_T("CVideoSinkPin"), sink, sink->pStateLock(), phr, L"Input"),
m_types(IVS_RGB32),
m_sink(sink),
m_changedmt(false)
{
}
HRESULT CVideoSinkPin::Receive(IMediaSample *pS) {
m_pLock->Lock();
if (m_bFlushing) {
m_pLock->Unlock();
return S_FALSE;
}
CMediaType MT;
AM_MEDIA_TYPE *pMT;
if (SUCCEEDED(pS->GetMediaType(&pMT)) && pMT != NULL) {
MT.Set(*pMT); DeleteMediaType(pMT);
HRESULT hr = CheckMediaType(&MT);
if (FAILED(hr)) {
m_pLock->Unlock();
return hr;
}
SetMediaType(&MT);
}
if (pS->IsPreroll() == S_OK) {
m_pLock->Unlock();
return S_OK;
}
return m_sink->Receive(pS);
}
HRESULT CVideoSinkPin::EndOfStream() {
HRESULT hr1, hr2;
m_pLock->Lock();
hr1 = CRenderedInputPin::EndOfStream();
if (m_bFlushing) {
m_pLock->Unlock();
return hr1;
}
hr2 = m_sink->Receive(NULL);
if (FAILED(hr1))
return hr1;
return hr2;
}
HRESULT CVideoSinkPin::BeginFlush() {
HRESULT hr = CRenderedInputPin::BeginFlush();
m_sink->BeginFlush();
return hr;
}
//CUnknown * WINAPI CreateVideoSink(IUnknown *pUnk, HRESULT *phr) {
// CVideoSink *vs = new CVideoSink(pUnk, phr);
// if (vs == NULL)
// *phr = E_OUTOFMEMORY;
// else if (FAILED(*phr)) {
// delete vs;
// vs = NULL;
// }
// return vs;
//}
HRESULT CreateVideoSink(IBaseFilter **pVS) {
HRESULT hr = S_OK;
CVideoSink *vs = new CVideoSink(NULL,&hr);
if (vs == NULL) hr = E_OUTOFMEMORY;
else if (FAILED(hr)) {
delete vs;
vs = NULL;
}
vs->AddRef();
*pVS = vs;
return hr;
}
#endif // WITH_DIRECTSHOW

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2004-2006 Mike Matsnev. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice immediately at the beginning of the file, without modification,
* this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Absolutely no warranty of function or purpose is made by the author
* Mike Matsnev.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: VideoSink.h,v 1.5 2007/01/17 23:40:51 mike Exp $
*
*/
#ifndef VIDEOSINK_H
#define VIDEOSINK_H
// callback, invoked when a new frame is ready
[uuid("8D9F1DA8-10DB-42fe-8CAC-94A02497B3DD")]
interface IVideoSinkNotify : public IUnknown {
// this may be called on a worker thread!
STDMETHOD(FrameReady)() = 0;
};
// supported bitmap types
#define IVS_RGB24 1
#define IVS_RGB32 2
#define IVS_YUY2 4
#define IVS_YV12 8
typedef void (*ReadFrameFunc)(__int64 timestamp, unsigned format, unsigned bpp,
const unsigned char *frame, unsigned width, unsigned height, int stride,
unsigned arx, unsigned ary,
void *arg);
[uuid("6B9EFC3E-3841-42ca-ABE5-0F963C638249")]
interface IVideoSink : public IUnknown {
STDMETHOD(SetAllowedTypes)(unsigned types) = 0;
STDMETHOD(GetAllowedTypes)(unsigned *types) = 0;
STDMETHOD(NotifyFrame)(IVideoSinkNotify *notify) = 0;
// failure return means format is not negotiated yet
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary) = 0;
// S_FALSE return means end of file was reached
STDMETHOD(ReadFrame)(ReadFrameFunc f, void *arg) = 0;
};
[uuid("80CADA0E-DFA5-4fcc-99DD-52F7C1B0E575")]
interface IVideoSink2 : public IUnknown {
STDMETHOD(NotifyFrame)(HANDLE hEvent) = 0;
STDMETHOD(GetFrameFormat)(unsigned *type, unsigned *width, unsigned *height, unsigned *arx, unsigned *ary, __int64 *def_duration) = 0;
};
HRESULT CreateVideoSink(IBaseFilter **pVS);
#endif

View File

@ -119,11 +119,6 @@
/////////////// LOW PRIORITY ////////////
// Enable DirectShow video provider
// Requires: DirectShow "baseclasses", DirectX SDK
//#define WITH_DIRECTSHOW
// Enable Perl scripting
// Requires: perl library (ActivePerl comes with one for Visual C++ under lib\core\)
//#define WITH_PERL

View File

@ -103,9 +103,6 @@ AboutScreen::AboutScreen(wxWindow *parent)
#ifdef __WINDOWS__
libString += _T(" Matroska Parser - Copyright (c) Mike Matsnev;\n");
#endif
#ifdef WITH_DIRECTSHOW
libString += _T(" VideoSink - Copyright (c) Mike Matsnev;\n");
#endif
#ifdef WITH_FREETYPE2
libString += _T(" Freetype - Copyright (c) David Turner, Robert Wilhelm, Werner Lemberg;\n");
#endif

View File

@ -141,17 +141,6 @@
#pragma comment(lib,"portaudio_x86.lib")
#endif
//////////////
// DirectShow
#ifdef WITH_DIRECTSHOW
#pragma comment(lib, "strmiids.lib")
#ifdef __WXDEBUG__
#pragma comment(lib, "strmbasdu.lib")
#else
#pragma comment(lib, "strmbaseu.lib")
#endif
#endif
////////////////
// Direct Sound

View File

@ -1,554 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro, Mike Matsnev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#include "config.h"
#ifdef WITH_DIRECTSHOW
#pragma warning(disable: 4995)
#pragma warning(disable: 4238)
#include <wx/wxprec.h>
#ifdef __WINDOWS__
#include <wx/image.h>
#include <dshow.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <windows.h>
#include <tchar.h>
#include <initguid.h>
#include "utils.h"
#include "vfr.h"
#include "videosink.h"
#include "gl_wrap.h"
#include "options.h"
#include "video_provider_dshow.h"
///////////////
// Constructor
// Based on Haali's code for DirectShowSource2
DirectShowVideoProvider::DirectShowVideoProvider(Aegisub::String _filename) {
fps = 0;
m_registered = false;
m_hFrameReady = CreateEvent(NULL, FALSE, FALSE, NULL);
HRESULT hr = OpenVideo(_filename);
if (FAILED(hr)) throw _T("Failed opening DirectShow content.");
}
//////////////
// Destructor
DirectShowVideoProvider::~DirectShowVideoProvider() {
CloseVideo();
}
////////////
// Get pin
// Code by Haali
#define ENUM_FILTERS(graph, var) for (CComPtr<IEnumFilters> __pEF__; !__pEF__ && SUCCEEDED(graph->EnumFilters(&__pEF__)); ) for (CComPtr<IBaseFilter> var; __pEF__->Next(1, &var, NULL) == S_OK; var.Release())
#define ENUM_PINS(filter, var) for (CComPtr<IEnumPins> __pEP__; !__pEP__ && SUCCEEDED(filter->EnumPins(&__pEP__)); ) for (CComPtr<IPin> var; __pEP__->Next(1, &var, NULL) == S_OK; var.Release())
class MTPtr {
AM_MEDIA_TYPE *pMT;
MTPtr(const MTPtr&);
MTPtr& operator=(const MTPtr&);
public:
MTPtr() : pMT(NULL) { }
~MTPtr() { DeleteMediaType(pMT); }
AM_MEDIA_TYPE *operator->() { return pMT; }
const AM_MEDIA_TYPE *operator->() const { return pMT; }
operator AM_MEDIA_TYPE *() { return pMT; }
AM_MEDIA_TYPE **operator&() { DeleteMediaType(pMT); pMT = NULL; return &pMT; }
static void FreeMediaType(AM_MEDIA_TYPE *pMT) {
if (pMT == NULL)
return;
if (pMT->cbFormat > 0) {
CoTaskMemFree(pMT->pbFormat);
pMT->pbFormat = NULL;
pMT->cbFormat = 0;
}
if (pMT->pUnk) {
pMT->pUnk->Release();
pMT->pUnk = NULL;
}
}
static void DeleteMediaType(AM_MEDIA_TYPE *pMT) {
if (pMT == NULL)
return;
if (pMT->cbFormat > 0)
CoTaskMemFree(pMT->pbFormat);
if (pMT->pUnk)
pMT->pUnk->Release();
CoTaskMemFree(pMT);
}
};
#define ENUM_MT(pin, var) for (CComPtr<IEnumMediaTypes> __pEMT__; !__pEMT__ && SUCCEEDED(pin->EnumMediaTypes(&__pEMT__)); ) for (MTPtr var; __pEMT__->Next(1, &var, NULL) == S_OK; )
CComPtr<IPin> GetPin(IBaseFilter *pF, bool include_connected, PIN_DIRECTION dir, const GUID *pMT = NULL) {
if (pF == NULL)
return CComPtr<IPin>();
ENUM_PINS(pF, pP) {
PIN_DIRECTION pd;
if (FAILED(pP->QueryDirection(&pd)))
continue;
if (pd == dir) {
if (!include_connected) {
CComPtr<IPin> pQ;
if (SUCCEEDED(pP->ConnectedTo(&pQ)))
continue;
}
if (pMT == NULL)
return pP;
ENUM_MT(pP, MT)
if (MT->majortype == *pMT)
return pP;
}
}
return CComPtr<IPin>();
}
////////////////////
// More Haali stuff
void DirectShowVideoProvider::RegROT() {
if (!m_pGC || m_registered)
return;
CComPtr<IRunningObjectTable> rot;
if (FAILED(GetRunningObjectTable(0, &rot)))
return;
CStringA name;
name.Format("FilterGraph %08p pid %08x (avss)", m_pGC.p, GetCurrentProcessId());
CComPtr<IMoniker> mk;
if (FAILED(CreateItemMoniker(L"!", CA2W(name), &mk)))
return;
if (SUCCEEDED(rot->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, m_pGC, mk, &m_rot_cookie)))
m_registered = true;
}
void DirectShowVideoProvider::UnregROT() {
if (!m_registered)
return;
CComPtr<IRunningObjectTable> rot;
if (FAILED(GetRunningObjectTable(0, &rot)))
return;
if (SUCCEEDED(rot->Revoke(m_rot_cookie)))
m_registered = false;
}
//////////////
// Open video
HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
HRESULT hr;
// Create an instance of the Filter Graph
CComPtr<IGraphBuilder> pG;
if (FAILED(hr = pG.CoCreateInstance(CLSID_FilterGraph))) return hr;
// Create an Instance of the Video Sink
//CComPtr<IBaseFilter> pR;
//CLSID CLSID_VideoSink;
//CLSIDFromString(L"{F13D3732-96BD-4108-AFEB-E85F68FF64DC}",&CLSID_VideoSink);
//if (FAILED(hr = pR.CoCreateInstance(CLSID_VideoSink))) return hr;
CComPtr<IBaseFilter> pR;
hr = CreateVideoSink(&pR);
// Add VideoSink to graph
pG->AddFilter(pR, L"VideoSink");
// Query interface from sink
CComQIPtr<IVideoSink> sink(pR);
if (!sink) return E_NOINTERFACE;
CComQIPtr<IVideoSink2> sink2(pR);
if (!sink2) return E_NOINTERFACE;
// Set allowed types for sink
unsigned int types = IVS_RGB24 | IVS_RGB32;
sink->SetAllowedTypes(types);
// Pass the event to sink, so it gets set when a frame is available
ResetEvent(m_hFrameReady);
sink2->NotifyFrame(m_hFrameReady);
// Create source filter and add it to graph
CComPtr<IBaseFilter> pS;
if (FAILED(hr = pG->AddSourceFilter(_filename.wc_str(), NULL, &pS))) return hr;
// Property bag? The heck is this?
// Is this supposed to make it "interactive", enabling some actions?
// I have no clue.
CComQIPtr<IPropertyBag> pPB(pS);
if (pPB) pPB->Write(L"ui.interactive", &CComVariant(0u, VT_UI4));
// Get source's output pin
CComPtr<IPin> pO(GetPin(pS, false, PINDIR_OUTPUT, &MEDIATYPE_Video));
if (!pO) pO = GetPin(pS, false, PINDIR_OUTPUT, &MEDIATYPE_Stream);
// Get sink's input pin
CComPtr<IPin> pI(GetPin(pR, false, PINDIR_INPUT));
// Check if pins are ok
if (!pO || !pI) return E_FAIL;
// Connect pins
if (FAILED(hr = pG->Connect(pO, pI))) return hr;
// Query the control interfaces from the graph
CComQIPtr<IMediaControl> mc(pG);
CComQIPtr<IMediaSeeking> ms(pG);
// See if they were created correctly
if (!mc || !ms) return E_NOINTERFACE;
// Run MediaControl, initiating the data flow through it
if (FAILED(hr = mc->Run())) return hr;
// Get state from media seeking (??)
OAFilterState fs;
if (FAILED(hr = mc->GetState(2000, &fs))) return hr;
// Wait up to 5 seconds for the first frame to arrive
if (WaitForSingleObject(m_hFrameReady, 5000) != WAIT_OBJECT_0) return E_FAIL;
// Get frame format
unsigned type, arx, ary;
if (FAILED(hr = sink2->GetFrameFormat(&type, &width, &height, &arx, &ary, &defd))) return hr;
// Get video duration
if (FAILED(hr = ms->GetDuration(&duration))) return hr;
// Set FPS and frame duration
if (defd == 0) defd = 417083;
if (fps != 0.0) defd = int64_t (10000000.0 / fps) + 1;
else fps = 10000000.0 / double(++defd);
// Set number of frames
last_fnum = 0;
num_frames = duration / defd;
// Store filters
m_pR = sink;
m_pGC = mc;
m_pGS = ms;
// Flag frame as ready?
SetEvent(m_hFrameReady);
// Register graph with Running Objects Table for remote graphedit connection
RegROT();
// Read keyframes and timecodes from MKV file
isVfr = false;
FrameRate temp;
double overFps = 0;
bool mkvOpen = MatroskaWrapper::wrapper.IsOpen();
KeyFrames.Clear();
wxString extension = _filename.Right(4).Lower();
if (extension == _T(".mkv") || mkvOpen) {
// Parse mkv
if (!mkvOpen) MatroskaWrapper::wrapper.Open(_filename);
// Get keyframes
KeyFrames = MatroskaWrapper::wrapper.GetKeyFrames();
keyFramesLoaded = true;
// Ask to override timecodes
int override = wxYES;
if (VFR_Output.IsLoaded()) override = wxMessageBox(_("You already have timecodes loaded. Replace them with the timecodes from the Matroska file?"),_("Replace timecodes?"),wxYES_NO | wxICON_QUESTION);
if (override == wxYES) {
MatroskaWrapper::wrapper.SetToTimecodes(temp);
isVfr = temp.GetFrameRateType() == VFR;
if (isVfr) {
overFps = temp.GetCommonFPS();
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Input);
MatroskaWrapper::wrapper.SetToTimecodes(VFR_Output);
trueFrameRate = temp;
}
}
// Close mkv
MatroskaWrapper::wrapper.Close();
}
else if (extension == _T(".avi")) {
keyFramesLoaded = false;
KeyFrames.Clear();
KeyFrames = VFWWrapper::GetKeyFrames(_filename);
keyFramesLoaded = true;
}
// Check if the file is all keyframes
bool isAllKeyFrames = true;
for (unsigned int i=1; i<KeyFrames.GetCount(); i++) {
// Is the last keyframe not this keyframe -1?
if (KeyFrames[i-1] != (int)(i-1)) {
// It's not all keyframes, go ahead
isAllKeyFrames = false;
break;
}
}
// If it is all keyframes, discard the keyframe info as it is useless
if (isAllKeyFrames) {
KeyFrames.Clear();
keyFramesLoaded = false;
}
//NextFrame();
// Set frame count
//m_f.SetCount(m_vi.num_frames);
return hr;
}
///////////////
// Close video
void DirectShowVideoProvider::CloseVideo() {
rdf.frame.Clear();
CComQIPtr<IVideoSink2> pVS2(m_pR);
if (pVS2) pVS2->NotifyFrame(NULL);
UnregROT();
m_pR.Release();
m_pGC.Release();
m_pGS.Release();
ResetEvent(m_hFrameReady);
CloseHandle(m_hFrameReady);
}
/////////////////////////
// Read DirectShow frame
void DirectShowVideoProvider::ReadFrame(int64_t timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, int stride, unsigned arx, unsigned ary, void *arg) {
// Set frame
DF *df = (DF*) arg;
df->timestamp = timestamp;
// Create frame
const unsigned char * src = frame;
if (stride < 0) {
src += stride*(height-1);
stride = -stride;
df->frame.flipped = true;
}
else df->frame.flipped = false;
df->frame.w = width;
df->frame.h = height;
df->frame.pitch[0] = stride;
df->frame.cppAlloc = false;
df->frame.invertChannels = true;
// Set format
df->frame.format = FORMAT_RGB32;
// Allocate and copy data
df->frame.Allocate();
memcpy(df->frame.data[0],src,df->frame.pitch[0]*height + (df->frame.pitch[1]+df->frame.pitch[2])*height/2);
}
/////////////////////
// Get Next DS Frame
int DirectShowVideoProvider::NextFrame(DF &df,int &_fn) {
// Keep reading until it gets a good frame
while (true) {
// Set object and receive data
if (WaitForSingleObject(m_hFrameReady, INFINITE) != WAIT_OBJECT_0) return 1;
// Read frame
HRESULT hr = m_pR->ReadFrame(ReadFrame, &df);
if (FAILED(hr)) {
//df.frame.Clear();
return 2;
}
// End of file
if (hr == S_FALSE) {
//df.frame.Clear();
return 3;
}
// Valid timestamp
if (df.timestamp >= 0) {
// CFR frame number
int frameno = -1;
if (frameTime.size() == 0) frameno = (int)((double)df.timestamp / defd + 0.5);
// VFR
else {
for (unsigned int i=0;i<frameTime.size();i++) {
if (df.timestamp < (int64_t) frameTime[i] * 10000) {
frameno = i-1;
break;
}
}
if (frameno == -1) frameno = frameTime.size()-1;
}
// Got a good one
if (frameno >= 0) {
_fn = frameno;
//_df = df;
return 0;
}
}
//df.frame.Clear();
}
}
/////////////
// Get frame
const AegiVideoFrame DirectShowVideoProvider::GetFrame(int n) {
// Normalize frame number
if (n >= (signed) num_frames) n = num_frames-1;
if (n < 0) n = 0;
// Variables
//DF df;
int fn;
// Time to seek to
REFERENCE_TIME cur;
cur = defd * n + 10001;
if (frameTime.size() > (unsigned) n) cur = frameTime[n] * 10000 + 10001;
if (cur < 0) cur = 0;
// Is next
if (n == (signed)last_fnum + 1) {
//rdf.frame.Clear();
NextFrame(rdf,fn);
last_fnum = n;
return rdf.frame;
}
// Not the next, reset and seek first
seek:
ResetEvent(m_hFrameReady);
// Seek
if (FAILED(m_pGS->SetPositions(&cur, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning))) return AegiVideoFrame(width,height);
// Set time
REFERENCE_TIME timestamp = -1;
// Actually get data
while (true) {
// Get frame
int fn = -1;
int result = NextFrame(rdf,fn);
// Preroll
if (result == 0 && fn < n) {
continue;
}
// Right frame
else if (fn == n) {
// we want this frame, compare timestamps to account for decimation
// we see this for the first time
if (timestamp < 0) timestamp = rdf.timestamp;
// early, ignore
if (rdf.timestamp < timestamp) {
continue;
}
// this is the frame we want
last_fnum = n;
//rdf.frame.Clear();
//rdf.frame = df.frame;
return rdf.frame;
}
// Passed or end of file, seek back and try again
else if (result == 0 || result == 3) {
cur -= defd;
goto seek;
}
// Failed
else {
return AegiVideoFrame(width,height);
}
}
}
////////////////
// Refresh subs
void DirectShowVideoProvider::RefreshSubtitles() {
}
///////////////////
// Get float frame
void DirectShowVideoProvider::GetFloatFrame(float* Buffer, int n) {
}
////////////////////////
// Override frame times
void DirectShowVideoProvider::OverrideFrameTimeList(Aegisub::IntArray list) {
frameTime = list;
num_frames = frameTime.size();
}
#endif
#endif // WITH_DIRECTSHOW

View File

@ -1,143 +0,0 @@
// Copyright (c) 2006, Rodrigo Braz Monteiro, Mike Matsnev
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
///////////
// Headers
#ifdef WITH_DIRECTSHOW
#pragma warning(disable: 4995)
#include <wx/wxprec.h>
#ifdef __WINDOWS__
#include <dshow.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlstr.h>
#include <atlcoll.h>
#include <windows.h>
#include <tchar.h>
#include <initguid.h>
#include "include/aegisub/video_provider.h"
#include "videosink.h"
#include "vfr.h"
#include "vfw_wrap.h"
#include "mkv_wrap.h"
///////////////////////////////////
// DirectShow Video Provider class
class DirectShowVideoProvider: public VideoProvider {
struct DF {
public:
REFERENCE_TIME timestamp; // DS timestamp that we used for this frame
AegiVideoFrame frame;
DF() : timestamp(-1) { }
DF(AegiVideoFrame f) : timestamp(-1), frame(f) { }
DF(const DF& f) { operator=(f); }
DF& operator=(const DF& f) { timestamp = f.timestamp; frame = f.frame; return *this; }
};
private:
Aegisub::IntArray frameTime;
unsigned int last_fnum;
unsigned int width;
unsigned int height;
unsigned int num_frames;
double fps;
__int64 defd;
wxArrayInt KeyFrames;
bool keyFramesLoaded;
bool isVfr;
FrameRate trueFrameRate;
HRESULT OpenVideo(wxString _filename);
void CloseVideo();
static void ReadFrame(__int64 timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, int stride, unsigned arx, unsigned ary, void *arg);
int NextFrame(DF &df,int &fn);
void RegROT();
void UnregROT();
REFERENCE_TIME duration;
DF rdf;
CComPtr<IVideoSink> m_pR;
CComPtr<IMediaControl> m_pGC;
CComPtr<IMediaSeeking> m_pGS;
HANDLE m_hFrameReady;
bool m_registered;
DWORD m_rot_cookie;
public:
DirectShowVideoProvider(Aegisub::String _filename);
~DirectShowVideoProvider();
void RefreshSubtitles();
const AegiVideoFrame GetFrame(int n);
void GetFloatFrame(float* Buffer, int n);
int GetPosition() { return last_fnum; };
int GetFrameCount() { return num_frames; };
double GetFPS() { return fps; };
int GetWidth() { return width; };
int GetHeight() { return height; };
bool AreKeyFramesLoaded() { return keyFramesLoaded; };
wxArrayInt GetKeyFrames() { return KeyFrames; };
bool IsVFR() { return isVfr; };
FrameRate GetTrueFrameRate() { return isVfr ? trueFrameRate : FrameRate(); };
Aegisub::String GetDecoderName() { return L"DirectShow"; }
bool IsNativelyByFrames() { return false; }
void OverrideFrameTimeList(Aegisub::IntArray list);
int GetDesiredCacheSize() { return 8; }
};
///////////
// Factory
class DirectShowVideoProviderFactory : public VideoProviderFactory {
public:
VideoProvider *CreateProvider(Aegisub::String video) { return new DirectShowVideoProvider(video); }
};
#endif
#endif

View File

@ -45,9 +45,6 @@
#ifdef WITH_AVISYNTH
#include "video_provider_avs.h"
#endif
#ifdef WITH_DIRECTSHOW
#include "video_provider_dshow.h"
#endif
#ifdef WITH_FFMPEGSOURCE
#include "video_provider_ffmpegsource.h"
#endif
@ -116,9 +113,6 @@ void VideoProviderFactoryManager::RegisterProviders() {
#ifdef WITH_AVISYNTH
RegisterFactory(new AvisynthVideoProviderFactory(),_T("Avisynth"));
#endif
#ifdef WITH_DIRECTSHOW
RegisterFactory(new DirectShowVideoProviderFactory(),_T("DirectShow"));
#endif
#ifdef WITH_FFMPEGSOURCE
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
#endif