1st step to
understand DirectShow その5 (SampleGrabber SampleCB) EXTERN_C const CLSID CLSID_SampleGrabber; EXTERN_C const IID IID_ISampleGrabberCB; MIDL_INTERFACE("0579154A-2B53-4994-B0D0-E773148EFF85") ISampleGrabberCB : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SampleCB( double
SampleTime,IMediaSample *pSample) = 0; virtual HRESULT STDMETHODCALLTYPE BufferCB( double SampleTime,BYTE
*pBuffer,long BufferLen) = 0; }; EXTERN_C const IID IID_ISampleGrabber; MIDL_INTERFACE("6B652FFF-11FE-4fce-92AD-0266B5D7C78F") ISampleGrabber : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetOneShot( BOOL OneShot) = 0; virtual HRESULT STDMETHODCALLTYPE SetMediaType( const AM_MEDIA_TYPE
*pType) = 0; virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType( AM_MEDIA_TYPE
*pType) = 0; virtual HRESULT STDMETHODCALLTYPE SetBufferSamples( BOOL BufferThem) =
0; virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer( long
*pBufferSize, long *pBuffer) = 0; virtual HRESULT STDMETHODCALLTYPE GetCurrentSample( IMediaSample
**ppSample) = 0; virtual HRESULT STDMETHODCALLTYPE SetCallback( ISampleGrabberCB
*pCallback,long WhichMethodToCallback) = 0; }; // === END ELEMENTS FROM QEDIT.H === class CGrabCB: public
ISampleGrabberCB //pSample->SetActualDataLength(2048); long
x=pSample->GetActualDataLength(); STDMETHODIMP BufferCB(double SampleTime, BYTE
*pBuffer, long BufferLen) return E_NOTIMPL; } // 参照カウントに見せかける。 STDMETHODIMP QueryInterface(REFIID riid, void
**ppvObject) }; HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
void RemoveFromRot(DWORD pdwRegister) HRESULT GetUnconnectedPin( HRESULT ConnectFilters( // ダウンストリーム フィルタの入力ピンを検索する。 // 最初のフィルタの出力ピンを検索する。 CoInitialize(NULL); ////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// CGrabCB *pGrabCB=new CGrabCB(); IBaseFilter
*pGrabberF=0; ISampleGrabber *pGrabber=0; hr=pGrabberF->QueryInterface( IID_ISampleGrabber,
(void**)&pGrabber ); } IBaseFilter *pSrc; hr=ConnectFilters(pGraph,pGrabberF,pNullRenderer); hr=pGrabber->SetOneShot(FALSE); IMediaControl *pMediaControl = NULL; ////////////////////////////////////////////////////////////// pGraph->Release(); CoUninitialize();
1.Callback関数を設定する
私のような、comの知識がないものにとって、Callback関数の設定は、難しいです。
メディアサンプルの獲得は、DirectX8のdocumentですが、
ここの例のCallback関数をコピーすると、えらい難儀します。
このcallback関数は、以下の通りです。
#include <streams.h>
// Strmbase.lib にリンクする
class CGrabCB: public CUnknown, public ISampleGrabberCB
{
public:
DECLARE_IUNKNOWN;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
if( riid == IID_ISampleGrabberCB )
{
return GetInterface((ISampleGrabberCB*)this, ppv);
}
return CUnknown::NonDelegatingQueryInterface(riid, ppv);
}
// ISampleGrabberCB のメソッド
STDMETHODIMP SampleCB(double SampleTime, IMediaSample *pSample)
{
printf("Sample time: %f\n", SampleTime);
return S_OK;
}
STDMETHODIMP BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen)
{
return E_NOTIMPL;
}
// コンストラクタ
CGrabCB( ) : CUnknown("SGCB", NULL)
{ }
};
CUnknownを継承しているのですが、このCUnknownの定義は、一体何処に?
探し回って、みつけました。
Windows
SDK ....BaseClasses
Streams.h
も、同じdirectoryにあります。
で、やっと、Build すると、
エラー 1 error
C3861: 'CheckPointer': 識別子が見つかりませんでした c:\documents and
settings\junzo\my
documents\visualc\directx\capture_graph1
\combase.h 275
と、エラーがでます。
止む無く、CheckPointerを、combase.hに、付け加えると
#define
CheckPointer(p,ret) { if ((p) == NULL) return (ret); }
やっと、Buildが通ります。
========== ビルド: 1 正常終了、0 失敗、0 更新、0
スキップ ==========
2.上記の方法は、スマートではない
なんとか、CUnknownを使わない方法が、ないものか.... 探し回りました。
見つけました!
静止画ピンからの画像のキャプチャ
ここに、スマートな方法が書いてあります。
こうやって、探し回るのが、楽しみでも、ありますね。
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
// 参照カウントに見せかける。
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
{
if (NULL == ppvObject) return E_POINTER;
if (riid == __uuidof(IUnknown))
{
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (riid == __uuidof(ISampleGrabberCB))
{
*ppvObject = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample)
{
return E_NOTIMPL;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen)
{
if ((g_StillMediaType.majortype != MEDIATYPE_Video) ||
(g_StillMediaType.formattype != FORMAT_VideoInfo) ||
(g_StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER)) ||
(g_StillMediaType.pbFormat == NULL))
{
return VFW_E_INVALIDMEDIATYPE;
}
HANDLE hf = CreateFile("C:\\Example.bmp", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hf == INVALID_HANDLE_VALUE)
{
return E_FAIL;
}
long cbBitmapInfoSize = g_StillMediaType.cbFormat - SIZE_PREHEADER;
VIDEOINFOHEADER *pVideoHeader =
(VIDEOINFOHEADER*)g_StillMediaType.pbFormat;
BITMAPFILEHEADER bfh;
ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 'MB'; // "MB" のリトルエンディアン。
bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
// ファイル ヘッダーを書き込む。
DWORD dwWritten = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);
WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
CloseHandle( hf );
return S_OK;
}
}; (原文通り)
combase.h streams.h 共に不要です...... うれしい
#include
"stdafx.h"
#include
"Dshow.h"
これだけの hファイルでOKです。
こうして、callback関数を実行したものが、最初の画像です。
以下は、今回のプログラム全体
//Sample
Grabber{C1F400A0-3F08-11D3-9F0B-006008039E37}
#include
"stdafx.h"
#include "Dshow.h"
// Since we are using DX9, we cannot include qedit.h. Necessary API
elements, copied below.
EXTERN_C const CLSID
CLSID_NullRenderer;
////////// Callback function class
//////////////////////////////////////////////////////////////////////////////////
{
public:
// ISampleGrabberCB のメソッド
STDMETHODIMP SampleCB(double SampleTime, IMediaSample
*pSample)
{
printf("Sample time: %f....",
SampleTime);
printf("Bufferlen:%ld\n",x);
//
printf("Sample time: %f\n",
SampleTime);
return
S_OK;
}
{
//printf("Sample time: %f....",
SampleTime);
//printf("Bufferlen:%ld\n",BufferLen);
//return S_OK;
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
{
if (NULL == ppvObject)
return E_POINTER;
if (riid
== __uuidof(IUnknown))
{
*ppvObject =
static_cast<IUnknown*>(this);
return S_OK;
}
if (riid ==
__uuidof(ISampleGrabberCB))
{
*ppvObject =
static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return
E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////////////////////////
{
IMoniker * pMoniker;
IRunningObjectTable *pROT;
if
(FAILED(GetRunningObjectTable(0, &pROT)))
{
return
E_FAIL;
}
WCHAR
wsz[256];
wsprintfW(wsz, L"FilterGraph %08p pid
%08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
HRESULT hr =
CreateItemMoniker(L"!", wsz,
&pMoniker);
if (SUCCEEDED(hr))
{
hr =
pROT->Register(0,
pUnkGraph, pMoniker,
pdwRegister);
pMoniker->Release();
}
pROT->Release();
return hr;
}
{
IRunningObjectTable *pROT;
if
(SUCCEEDED(GetRunningObjectTable(0, &pROT)))
{
pROT->Revoke(pdwRegister);
pROT->Release();
}
}
IBaseFilter
*pFilter, // フィルタへのポインタ。
PIN_DIRECTION
PinDir, // 検索するピンの方向。
IPin
**ppPin) //
ピンへのポインタを受け取る。
{
*ppPin =
0;
IEnumPins *pEnum = 0;
IPin
*pPin = 0;
HRESULT 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 =
0;
hr =
pPin->ConnectedTo(&pTmp);
if (SUCCEEDED(hr)) //
既に接続済み、必要なピンではない。
{
pTmp->Release();
}
else //
未接続、これが必要なピンである。
{
pEnum->Release();
*ppPin =
pPin;
return
S_OK;
}
}
pPin->Release();
}
pEnum->Release();
//
一致するピンが見つからなかった。
return E_FAIL;
}
HRESULT AddFilterByCLSID(
IGraphBuilder
*pGraph, // フィルタ グラフ マネージャへのポインタ。
const
GUID& clsid, // 作成するフィルタの
CLSID。
LPCWSTR
wszName, //
フィルタの名前。
IBaseFilter
**ppF) //
フィルタへのポインタを受け取る。
{
if (!pGraph || ! ppF) return
E_POINTER;
*ppF = 0;
IBaseFilter *pF = 0;
HRESULT hr =
CoCreateInstance(clsid, 0,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
reinterpret_cast<void**>(&pF));
if
(SUCCEEDED(hr))
{
hr =
pGraph->AddFilter(pF,
wszName);
if
(SUCCEEDED(hr))
*ppF = pF;
else
pF->Release();
}
return
hr;
}
IGraphBuilder *pGraph, //
フィルタ グラフ マネージャ。
IPin
*pOut,
// アップストリーム フィルタの出力ピン。
IBaseFilter
*pDest) // ダウンストリーム フィルタ。
{
if
((pGraph == NULL) || (pOut == NULL) || (pDest ==
NULL))
{
return
E_POINTER;
}
#ifdef
debug
PIN_DIRECTION
PinDir;
pOut->QueryDirection(&PinDir);
_ASSERTE(PinDir == PINDIR_OUTPUT);
#endif
IPin *pIn = 0;
HRESULT hr =
GetUnconnectedPin(pDest,
PINDIR_INPUT, &pIn);
if
(FAILED(hr))
{
return
hr;
}
//
接続を試す。
hr = pGraph->Connect(pOut,
pIn);
pIn->Release();
return hr;
}
HRESULT ConnectFilters(
IGraphBuilder
*pGraph,
IBaseFilter *pSrc,
IBaseFilter *pDest)
{
if ((pGraph == NULL) ||
(pSrc == NULL) || (pDest == NULL))
{
return
E_POINTER;
}
IPin
*pOut = 0;
HRESULT hr =
GetUnconnectedPin(pSrc,
PINDIR_OUTPUT, &pOut);
if (FAILED(hr))
{
return hr;
}
hr =
ConnectFilters(pGraph, pOut, pDest);
pOut->Release();
return hr;
}
int _tmain(int argc, _TCHAR*
argv[])
{
HRESULT
hr;
IGraphBuilder *pGraph;
// フィルタ グラフ
マネージャを作成する。
CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&pGraph);
DWORD dwRegister;
#ifdef _DEBUG
hr =
AddToRot(pGraph,
&dwRegister);
#endif
int *buffer =
NULL; //32bit=int
long bufsize = 0;
hr=CoCreateInstance(CLSID_SampleGrabber,NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void**)&pGrabberF);
hr=pGraph->AddFilter(pGrabberF,L"Sample
Grabber");
AM_MEDIA_TYPE
mt;
if(hr==S_OK)
{
ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
mt.majortype=MEDIATYPE_Audio;
//mt.subtype=MEDIASUBTYPE_None;
mt.formattype=FORMAT_WaveFormatEx
;
pGrabber->SetMediaType(&mt);
hr=
pGraph->AddSourceFilter(L"mywave.wav",L"Source",&pSrc);
if(hr!=S_OK)
{
}
hr=ConnectFilters(pGraph,pSrc,pGrabberF);
if(hr!=S_OK)
{
}
IBaseFilter
*pNullRenderer;
hr=CoCreateInstance(CLSID_NullRenderer,NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,(void**)&pNullRenderer);
hr=pGraph->AddFilter(pNullRenderer,L"Null
Renderer");
hr=pGrabber->SetBufferSamples(FALSE);
hr=pGrabber->SetCallback((ISampleGrabberCB
*)pGrabCB,0);
pGraph->QueryInterface(IID_IMediaControl, (void
**)&pMediaControl);
pMediaControl->Run();
::getchar();
pMediaControl->Stop();
delete[]
buffer;
//////////////////////////////////////////////////////////////
#ifdef
_DEBUG
RemoveFromRot(dwRegister);
#endif
done:
pGrabCB->Release();
pNullRenderer->Release();
pSrc->Release();
pMediaControl->Release();
pGrabber->Release();
pGrabberF->Release();
}
H.20.3.6