⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 grabberds.cpp

📁 Handle Videos in Forms Delphi... Play/Stop/Pause/FullScreen
💻 CPP
📖 第 1 页 / 共 2 页
字号:

// 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 + -