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 ////////////
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
#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
|
||||
|
|
Loading…
Reference in New Issue