mirror of https://github.com/odrling/Aegisub
Remove the DirectShow VideoProvider. Fixes #930.
Originally committed to SVN as r3195.
This commit is contained in:
parent
5e902e2ef1
commit
352df194aa
|
@ -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
|
|
|
@ -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
|
|
|
@ -119,11 +119,6 @@
|
||||||
|
|
||||||
/////////////// LOW PRIORITY ////////////
|
/////////////// LOW PRIORITY ////////////
|
||||||
|
|
||||||
// Enable DirectShow video provider
|
|
||||||
// Requires: DirectShow "baseclasses", DirectX SDK
|
|
||||||
//#define WITH_DIRECTSHOW
|
|
||||||
|
|
||||||
|
|
||||||
// Enable Perl scripting
|
// Enable Perl scripting
|
||||||
// Requires: perl library (ActivePerl comes with one for Visual C++ under lib\core\)
|
// Requires: perl library (ActivePerl comes with one for Visual C++ under lib\core\)
|
||||||
//#define WITH_PERL
|
//#define WITH_PERL
|
||||||
|
|
|
@ -103,9 +103,6 @@ AboutScreen::AboutScreen(wxWindow *parent)
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
libString += _T(" Matroska Parser - Copyright (c) Mike Matsnev;\n");
|
libString += _T(" Matroska Parser - Copyright (c) Mike Matsnev;\n");
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_DIRECTSHOW
|
|
||||||
libString += _T(" VideoSink - Copyright (c) Mike Matsnev;\n");
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_FREETYPE2
|
#ifdef WITH_FREETYPE2
|
||||||
libString += _T(" Freetype - Copyright (c) David Turner, Robert Wilhelm, Werner Lemberg;\n");
|
libString += _T(" Freetype - Copyright (c) David Turner, Robert Wilhelm, Werner Lemberg;\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -141,17 +141,6 @@
|
||||||
#pragma comment(lib,"portaudio_x86.lib")
|
#pragma comment(lib,"portaudio_x86.lib")
|
||||||
#endif
|
#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
|
// Direct Sound
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -45,9 +45,6 @@
|
||||||
#ifdef WITH_AVISYNTH
|
#ifdef WITH_AVISYNTH
|
||||||
#include "video_provider_avs.h"
|
#include "video_provider_avs.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_DIRECTSHOW
|
|
||||||
#include "video_provider_dshow.h"
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_FFMPEGSOURCE
|
#ifdef WITH_FFMPEGSOURCE
|
||||||
#include "video_provider_ffmpegsource.h"
|
#include "video_provider_ffmpegsource.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -116,9 +113,6 @@ void VideoProviderFactoryManager::RegisterProviders() {
|
||||||
#ifdef WITH_AVISYNTH
|
#ifdef WITH_AVISYNTH
|
||||||
RegisterFactory(new AvisynthVideoProviderFactory(),_T("Avisynth"));
|
RegisterFactory(new AvisynthVideoProviderFactory(),_T("Avisynth"));
|
||||||
#endif
|
#endif
|
||||||
#ifdef WITH_DIRECTSHOW
|
|
||||||
RegisterFactory(new DirectShowVideoProviderFactory(),_T("DirectShow"));
|
|
||||||
#endif
|
|
||||||
#ifdef WITH_FFMPEGSOURCE
|
#ifdef WITH_FFMPEGSOURCE
|
||||||
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
|
RegisterFactory(new FFmpegSourceVideoProviderFactory(),_T("FFmpegSource"));
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue