📄 grabberds.cpp
字号:
// Begin
/*
grabberds.cpp - file with implementation of interfaces declared in grabber.h
(c) 2005 - 2007 Aleksei Kazantsev (ajk.xyz@gmail.com)
VERSION 1.0
last-modified: 2007/05/19
It is free software and is distributed under
the terms of the GNU Lesser General Public License Version 2.1.
This software comes with ABSOLUTELY NO WARRANTY.
*/
//
#include <streams.h>
#include <dvdmedia.h>
#include <mpconfig.h>
#include "grabberds.h"
//
//
HRESULT GetUnconnectedPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin)
{
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
*ppPin = NULL;
HRESULT hr;
hr = pFilter->EnumPins(&pEnum);
if(FAILED(hr))
return hr;
while(pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if(ThisPinDir == PinDir)
{
IPin *pTmp = NULL;
if(SUCCEEDED(pPin->ConnectedTo(&pTmp)))
pTmp->Release();
else
{
pEnum->Release();
*ppPin = pPin;
return S_OK;
}
}
pPin->Release();
}
pEnum->Release();
return E_FAIL;
}
//
//
HRESULT ConnectPins(IFilterGraph2 *fg, IBaseFilter *sp, IBaseFilter *video, IBaseFilter *audio)
{
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
HRESULT hr = sp->EnumPins(&pEnum);
if(FAILED(hr))
return hr;
while(pEnum->Next(1, &pPin, NULL) == S_OK)
{
PIN_DIRECTION ThisPinDir;
pPin->QueryDirection(&ThisPinDir);
if(ThisPinDir == PINDIR_OUTPUT)
{
IPin *pTmp = NULL;
if(SUCCEEDED(pPin->ConnectedTo(&pTmp)))
pTmp->Release();
else
fg->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
}
pPin->Release();
}
pEnum->Release();
return S_OK;
}
//
//
HRESULT FindVideoCaptureSource(LPCWSTR szName, IBaseFilter **pCapture)
{
IEnumMoniker *pEnum;
HRESULT hr;
hr = EnumVideoCaptureSourcesStart((IUnknown**)&pEnum);
if(hr != S_OK)
goto L_EXIT;
VARIANT vName;
IMoniker *pMoniker;
IBaseFilter *pCap = NULL;
while((!pCap) && ((hr = EnumVideoCaptureSourcesNext(pEnum, &vName, (IUnknown**)&pMoniker)) == S_OK))
{
if(szName)
{
if(!lstrcmpiW(vName.bstrVal, szName))
{
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if(FAILED(hr))
pCap = NULL;
}
}
else
{
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if(FAILED(hr))
pCap = NULL;
}
VariantClear(&vName);
pMoniker->Release();
}
EnumVideoCaptureSourcesEnd(pEnum);
if(pCap)
{
*pCapture = pCap;
hr = S_OK;
}
else
hr = E_INVALIDARG;
L_EXIT:
return hr;
}
//
//
BOOL PinMatchesCategory(IPin *pPin, const GUID& Category)
{
if(!pPin)
return E_POINTER;
BOOL bFound = FALSE;
IKsPropertySet *pKs;
HRESULT hr = pPin->QueryInterface(IID_IKsPropertySet, (void**)&pKs);
if(SUCCEEDED(hr))
{
GUID PinCategory;
DWORD cbReturned;
hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
&PinCategory, sizeof(GUID), &cbReturned);
if(SUCCEEDED(hr))
bFound = (PinCategory == Category);
pKs->Release();
}
return bFound;
}
//
//
HRESULT FindPinByCategory(IBaseFilter *pF, PIN_DIRECTION PinDir,
const GUID& Category, IPin **ppPin)
{
if((!pF) || (!ppPin))
return E_POINTER;
*ppPin = 0;
HRESULT hr;
IEnumPins *pEnum = 0;
if(SUCCEEDED(pF->EnumPins(&pEnum)))
{
IPin *pPin = 0;
while((hr = pEnum->Next(1, &pPin, 0)) == S_OK)
{
PIN_DIRECTION ThisPinDir;
hr = pPin->QueryDirection(&ThisPinDir);
if(FAILED(hr))
{
pPin->Release();
pEnum->Release();
return E_UNEXPECTED;
}
if((ThisPinDir == PinDir) && (PinMatchesCategory(pPin, Category)))
{
*ppPin = pPin;
pEnum->Release();
return S_OK;
}
pPin->Release();
}
pEnum->Release();
}
return E_FAIL;
}
//
//
class CMixerPinConfig : public IMixerPinConfig
{
// Attributes
public:
IUnknown *unk;
// IMixerPinConfig
public:
virtual HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)
{
return unk->QueryInterface(iid, ppv);
}
//
virtual ULONG __stdcall AddRef()
{
return unk->AddRef();
}
//
virtual ULONG __stdcall Release()
{
return unk->Release();
}
//
virtual HRESULT __stdcall SetRelativePosition(DWORD dwLeft, DWORD dwTop,
DWORD dwRight, DWORD dwBottom)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetRelativePosition(DWORD *pdwLeft, DWORD *pdwTop,
DWORD *pdwRight, DWORD *pdwBottom)
{
return S_OK;
}
//
virtual HRESULT __stdcall SetZOrder(DWORD dwZOrder)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetZOrder(DWORD *pdwZOrder)
{
return S_OK;
}
//
virtual HRESULT __stdcall SetColorKey(COLORKEY *pColorKey)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetColorKey(COLORKEY *pColorKey, DWORD *pColor)
{
return S_OK;
}
//
virtual HRESULT __stdcall SetBlendingParameter(DWORD dwBlendingParameter)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetBlendingParameter(DWORD *pdwBlendingParameter)
{
return S_OK;
}
//
virtual HRESULT __stdcall SetAspectRatioMode(AM_ASPECT_RATIO_MODE amAspectRatioMode)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetAspectRatioMode(AM_ASPECT_RATIO_MODE *pamAspectRatioMode)
{
return S_OK;
}
//
virtual HRESULT __stdcall SetStreamTransparent(BOOL bStreamTransparent)
{
return S_OK;
}
//
virtual HRESULT __stdcall GetStreamTransparent(BOOL *pbStreamTransparent)
{
return S_OK;
}
};
//
//
class CVPin : public CRendererInputPin
{
// Attributes
public:
CMixerPinConfig config;
// Construction/Destruction
public:
CVPin(CBaseRenderer *pRenderer, HRESULT *phr, LPCWSTR Name) :
CRendererInputPin(pRenderer, phr, Name)
{
QueryInterface(IID_IUnknown, (void**)&config.unk);
Release();
}
//
~CVPin()
{
}
// Overridables
public:
virtual HRESULT __stdcall QueryInterface(REFIID iid, void **ppv)
{
if(iid == IID_IMixerPinConfig)
{
*ppv = (IMixerPinConfig*)&config;
AddRef();
return S_OK;
}
return CRendererInputPin::QueryInterface(iid, ppv);
}
};
//
//
interface IVideoGrabberX
{
// Destroys the object
virtual void __fastcall ReleaseVG() = 0;
// Enables video subtype (all disabled by default)
// Supported subtypes: MEDIASUBTYPE_RGB32, MEDIASUBTYPE_ARGB32,
// MEDIASUBTYPE_RGB24, MEDIASUBTYPE_RGB555, MEDIASUBTYPE_RGB565,
// MEDIASUBTYPE_YUY2, MEDIASUBTYPE_UYVY, MEDIASUBTYPE_YV12, MEDIASUBTYPE_NV12
virtual void __fastcall EnableSubtype(const GUID *subtype, BOOL enable = TRUE) = 0;
// Gets current video subtype
virtual const GUID* __fastcall GetSubtype() = 0;
// Returns the frame width
virtual DWORD __fastcall GetCX() = 0;
// Returns the frame height
virtual DWORD __fastcall GetCY() = 0;
// Returns the aspect ratio X
virtual DWORD __fastcall GetAspectX() = 0;
// Returns the aspect ratio Y
virtual DWORD __fastcall GetAspectY() = 0;
// Renders the selected file without running it
virtual HRESULT __fastcall RenderMediaFile(LPCWSTR szFile, BOOL enable_audio = FALSE) = 0;
// Renders the video capture source without running it
// is szName is NULL - renders the first available video capture source
virtual HRESULT __fastcall RenderVideoCaptureSource(LPCWSTR szName) = 0;
// Sets the callback function
virtual void __fastcall SetCallback(vg_callback callback) = 0;
// Sets the user object to retrieve it later with GetUserObject
virtual void __fastcall SetUserObject(void *obj) = 0;
// Get the user object set by SetUserObject
virtual void* __fastcall GetUserObject() = 0;
// Gets the IMediaControl interface without incrementing its reference count
virtual IUnknown* __fastcall GetMediaControl() = 0;
// Enables or disables repeating of the media file
virtual void __fastcall EnableLoop(BOOL bEnable) = 0;
// Suggests the video format for video capture source pin
// - call this function before call to RenderVideoCaptureSource
// - fill subtype with GUID_NULL for default video format suggestion
virtual void __fastcall SuggestVideoCaptureFormat(const GUID *subtype, SIZE sz, float fps) = 0;
// Gets the video format for video capture source pin
// - call this function after call to RenderVideoCaptureSource
virtual HRESULT __fastcall GetVideoCaptureFormat(GUID *subtype, SIZE *sz, float *fps) = 0;
// TRUE if filter graph contains video renderer
virtual BOOL __fastcall IsVideo() = 0;
// TRUE if filter graph contains audio renderer
virtual BOOL __fastcall IsAudio() = 0;
};
//
//
const GUID g_subtypes[] =
{ MEDIASUBTYPE_YV12, MEDIASUBTYPE_RGB32, MEDIASUBTYPE_YUY2, MEDIASUBTYPE_ARGB32,
MEDIASUBTYPE_UYVY, MEDIASUBTYPE_NV12, MEDIASUBTYPE_RGB24, MEDIASUBTYPE_RGB555, MEDIASUBTYPE_RGB565 };
//
//
#define N_SUBTYPES (sizeof(g_subtypes) / sizeof(GUID))
//
//
class CVRenderer : public CBaseVideoRenderer,
public IVideoGrabberX
{
// Attributes
public:
BYTE *pBits;
//
BITMAPINFOHEADER bih;
//
DWORD aspect_x, aspect_y;
//
BOOL subtypes_enabled[N_SUBTYPES];
//
vg_callback callback;
//
void *user_obj;
//
IGraphBuilder *m_DSI_GB;
IFilterGraph2 *m_DSI_FG;
IBaseFilter *m_DSI_BF_source;
IBaseFilter *m_DSI_BF_audio;
IBaseFilter *vR;
IMediaControl *m_DSI_MC;
IMediaSeeking *m_DSI_MS;
//
HANDLE event;
BOOL end_of_stream;
//
BOOL co_initialized;
//
BOOL b_loop_enabled;
HWND m_hwnd;
//
GUID capture_subtype;
SIZE capture_sz;
float capture_fps;
//
BOOL b_video, b_audio;
const GUID *current_subtype;
// Construction/Destruction
public:
CVRenderer(HRESULT *phr) : CBaseVideoRenderer(CLSID_NULL, "V-Renderer", NULL, phr)
{
pBits = NULL;
ZeroMemory(subtypes_enabled, sizeof(subtypes_enabled));
callback = NULL;
user_obj = NULL;
m_DSI_GB = NULL;
m_DSI_FG = NULL;
m_DSI_BF_source = NULL;
m_DSI_BF_audio = NULL;
vR = NULL;
m_DSI_MC = NULL;
m_DSI_MS = NULL;
event = CreateEvent(NULL, TRUE, FALSE, NULL);
end_of_stream = TRUE;
co_initialized = FALSE;
b_loop_enabled = FALSE;
m_hwnd = NULL;
capture_subtype = GUID_NULL;
capture_sz.cx = 0;
capture_sz.cy = 0;
capture_fps = 0;
b_video = FALSE;
b_audio = FALSE;
current_subtype = &GUID_NULL;
}
//
~CVRenderer()
{
if(m_hwnd)
{
SetWindowLong(m_hwnd, GWL_USERDATA, 0);
PostMessage(m_hwnd, WM_CLOSE, 0, 0);
m_hwnd = NULL;
}
ReleaseDShow();
end_of_stream = TRUE;
if(event)
CloseHandle(event);
if(co_initialized)
CoUninitialize();
}
// Operations
public:
void ReleaseDShow()
{
if(m_DSI_MC)
m_DSI_MC->Stop();
SAFE_RELEASE(m_DSI_MS);
SAFE_RELEASE(m_DSI_MC);
SAFE_RELEASE(m_DSI_BF_audio);
SAFE_RELEASE(m_DSI_BF_source);
SAFE_RELEASE(m_DSI_FG);
SAFE_RELEASE(m_DSI_GB);
SAFE_RELEASE(vR);
}
//
LRESULT WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_USER:
if(m_DSI_MS)
{
LONGLONG cur = NULL;
m_DSI_MS->SetPositions(&cur, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
if(m_DSI_MC)
m_DSI_MC->Run();
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
// IVideoGrabberX
public:
virtual void __fastcall ReleaseVG()
{
ReleaseDShow();
((IBaseFilter*)this)->Release();
}
//
virtual void __fastcall EnableSubtype(const GUID *subtype, BOOL enable)
{
for(DWORD i = 0; i < N_SUBTYPES; i++)
if(g_subtypes[i] == *subtype)
{
subtypes_enabled[i] = enable;
break;
}
}
//
virtual const GUID* __fastcall GetSubtype()
{
return current_subtype;
}
//
virtual DWORD __fastcall GetCX()
{
return bih.biWidth;
}
//
virtual DWORD __fastcall GetCY()
{
return bih.biHeight;
}
//
virtual DWORD __fastcall GetAspectX()
{
return aspect_x;
}
//
virtual DWORD __fastcall GetAspectY()
{
return aspect_y;
}
//
virtual HRESULT __fastcall RenderMediaFile(LPCWSTR szFile, BOOL enable_audio = FALSE)
{
HRESULT hr;
IPin *Pin = NULL;
// Get the interface for DirectShow's GraphBuilder
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (VOID **)&m_DSI_GB);
if(FAILED(hr))
{
if(hr != CO_E_NOTINITIALIZED)
goto L_ERR;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(FAILED(hr))
goto L_ERR;
co_initialized = TRUE;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (VOID **)&m_DSI_GB);
if(FAILED(hr))
goto L_ERR;
}
hr = m_DSI_GB->QueryInterface(IID_IFilterGraph2, (void**)&m_DSI_FG);
if(FAILED(hr))
goto L_ERR;
hr = m_DSI_GB->AddSourceFilter(szFile, L"Source Filter", &m_DSI_BF_source);
if(FAILED(hr))
goto L_ERR;
if(enable_audio)
{
hr = CoCreateInstance(CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&m_DSI_BF_audio);
if(FAILED(hr))
goto L_ERR;
hr = m_DSI_GB->AddFilter(m_DSI_BF_audio, L"Sound Renderer");
if(FAILED(hr))
goto L_ERR;
}
vR = (IBaseFilter*)this;
vR->AddRef();
hr = m_DSI_GB->AddFilter(vR, L"V-Renderer");
if(FAILED(hr))
goto L_ERR;
hr = ConnectPins(m_DSI_FG, m_DSI_BF_source, vR, m_DSI_BF_audio);
if(FAILED(hr))
goto L_ERR;
GetUnconnectedPin(vR, PINDIR_INPUT, &Pin);
if(Pin)
{
Pin->Release();
Pin = NULL;
m_DSI_FG->RemoveFilter(vR);
}
else
b_video = TRUE;
if(m_DSI_BF_audio)
{
GetUnconnectedPin(m_DSI_BF_audio, PINDIR_INPUT, &Pin);
if(Pin)
{
Pin->Release();
Pin = NULL;
m_DSI_FG->RemoveFilter(m_DSI_BF_audio);
m_DSI_BF_audio->Release();
m_DSI_BF_audio = NULL;
}
else
b_audio = TRUE;
}
// QueryInterface for DirectShow
hr = m_DSI_GB->QueryInterface(IID_IMediaControl, (void**)&m_DSI_MC);
if(FAILED(hr))
goto L_ERR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -