1st step to understand DirectShow (DirectShow
入門 その2 ) HRESULT GetUnconnectedPin( HRESULT ConnectFilters( // ダウンストリーム
フィルタの入力ピンを検索する。 //
最初のフィルタの出力ピンを検索する。 /*typedef struct _GUID
{ //guiddef.h GUID
CLSID_WAVEParser={0xD51BD5A1,0x7548,0x11cf,0xA5,0x20,0x00,0x80,0xC7,0x7E,0xF5,0x8A}; IBaseFilter *pSrc = NULL, *pWaveDest = NULL, *pWriter =
NULL; // 省略 : システム デバイス列挙子を使ってオーディオ キャプチャ ICreateDevEnum *pSysDevEnum = NULL; if (hr == S_OK)
//
フィルタのインスタンスを作成するには、次の処理を行う。 // フィルタ グラフにオーディオ キャプチャ
フィルタを追加する。 AM_MEDIA_TYPE
*pmt=0; if (hr==S_OK) //ここで、WAVEFORMATEX構造体を書き換えてしまう。
ex->wFormatTag=
WAVE_FORMAT_IEEE_FLOAT; //WAVE_FORMAT_PCM
;//WAVE_FORMAT_IEEE_FLOAT hr=pConfig->SetFormat(pmt); } // フィルタを接続する。 ::getchar(); //
録音終了 //
終了処理 pSrc->Release();
CoUninitialize(); return
0;
1.DirectShowの使用を、早くも、あきらめかけた。
AUDIO_STREAM_CONFIG_CAPS
なるものを使って、調べたのですが、
この中の MaximumSampleFrequency
44100Hz
を、見て、がっくり。
これでは、48KHz, 96KHz sampling できません。
他の方法を探します。 早とちりでした、涙....
もしかしたら、出来るかも知れないと思い、プログラムを組んでみました。
.............
プログラムエラーは出ないのですが、 結果は、
出力された 48KHz
sampled wavファイルの、ファイルサイズが ゼロ byte... こら、あかん。
2. あきらめないで、よかった.....
実は、できたようだ...
「できたようだ」 とは、私のプログラムでは、まだ、それが確認でいないからです。
ほら、44.1KHz samplingみたいになってしまいますので。
できているようなのを、偉大なる Rockyで、確かめたからです。
48KHz
samplingした、ファイルを、Rockyで再生すると、帯域の端は、しっかりと、 24KHzになっているではありませんか...
私のプログラムで、それを再現できないのは、
ファイルをmedia
playerで、先ず.再生して、
それを、Prodigy7.1XTのドライバで、ASIOと繋いでいるからだと、思います。
3.どうやって、うまく行ったか?
前節のプログラムを発展させたのです。
以下の部分は、前節と全く同じです。
#include
"stdafx.h"
#include "Dshow.h"
#include "mmreg.h"
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;
unsigned long
Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[ 8
];
}
GUID;
*/
//3C78B8E2-6C4D-11D1-ADE2-0000F8754B99
GUID
CLSID_WavDest={
0x3C78B8E2, 0x6C4D, 0x11D1, 0xAD, 0xE2,
0x00, 0x00, 0xF8, 0x75, 0x4B, 0x99};
//CLSID_WAVEParser
{D51BD5A1-7548-11cf-A520-0080C77EF58A}
// COMを初期化
CoInitialize(NULL);
IFileSinkFilter *pSink=
NULL;
IGraphBuilder *pGraph;
//
フィルタ グラフ マネージャを作成する。
CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&pGraph);
// フィルタを作成する。
hr =
CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void
**)&pSysDevEnum);
if (FAILED(hr))
{
return
hr;
}
IEnumMoniker *pEnumCat = NULL;
hr =
pSysDevEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory,
&pEnumCat, 0);
{
//
モニカを列挙する。
IMoniker *pMoniker =
NULL;
ULONG cFetched;
//
while(pEnumCat->Next(1, &pMoniker, &cFetched) ==
S_OK)
//pEnumCat->Next(1, &pMoniker,
&cFetched);
if(pEnumCat->Next(1,
&pMoniker, &cFetched) ==
S_OK)//最初のデバイスを入力とする
{
IPropertyBag
*pPropBag;
hr =
pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if
(SUCCEEDED(hr))
{
//
フィルタのフレンドリ名を取得するには、次の処理を行う。
VARIANT
varName;
VariantInit(&varName);
hr = pPropBag->Read(L"FriendlyName", &varName,
0);
if
(SUCCEEDED(hr))
{
// なんらかの方法で UI
に名前を表示する。
printf("%S\n",varName.pcVal);
}
VariantClear(&varName);
// IBaseFilter
*pFilter;
hr = pMoniker->BindToObject(NULL, NULL,
IID_IBaseFilter,
(void**)&pSrc);
//
ここでグラフにフィルタを追加する。
// 後で忘れずに pFilter
を解放すること。
pPropBag->Release();
}
pMoniker->Release();
}
pEnumCat->Release();
}
pSysDevEnum->Release();
pGraph->AddFilter(pSrc, L"Capture");
そして、ここから、オーディオ キャプチャ
フィルタの出力ピンの状態を調べて、
WaveformatEXを書き換えてしまうのです。
//接続する前に 出力pinを、調べる
IPin
*pin;
hr=GetUnconnectedPin(pSrc,PINDIR_OUTPUT,&pin);
////////////////////////////////////////////////////////////////////////
IAMStreamConfig
*pConfig = NULL;
AUDIO_STREAM_CONFIG_CAPS scc;
//先ず、このpinで、IAMStreamConfig を取得する
//QueryInterfaceは、こんな方法もある。
hr=pin->QueryInterface((IAMStreamConfig**)&pConfig);
{
//このIAMStreamConfig から、AM_MEDIA_TYPE 、AUDIO_STREAM_CONFIG_CAPS
を得ておく
pConfig->GetFormat(&pmt);
hr = pConfig->GetStreamCaps(0, &pmt,
reinterpret_cast<BYTE*>(&scc));
WAVEFORMATEX
*ex=reinterpret_cast<WAVEFORMATEX*>(pmt->pbFormat);
ex->nChannels=2;
ex->wBitsPerSample=32;
ex->nSamplesPerSec=48000;
ex->nBlockAlign=(ex->nChannels*ex->wBitsPerSample)/8;
ex->nAvgBytesPerSec=ex->nSamplesPerSec*ex->nBlockAlign;
ex->cbSize=0;
if(hr!=S_OK)
{
printf("%s\n","fail to
change sample rate");
::getchar();
return 1;
}
後は、前節のプログラムの続きを書きます。
// WavDest とファイル ライタを追加する。
AddFilterByCLSID(pGraph,
CLSID_WavDest, L"WavDest", &pWaveDest);
AddFilterByCLSID(pGraph,
CLSID_FileWriter, L"File Writer", &pWriter);
//
ファイル名を設定する。
pWriter->QueryInterface(IID_IFileSinkFilter,
(void**)&pSink);
pSink->SetFileName(L"MyWavFile.wav",
NULL);
ConnectFilters(pGraph,
pSrc, pWaveDest);
ConnectFilters(pGraph, pWaveDest,
pWriter);
//
MediaControlインターフェース取得
IMediaControl *pMediaControl
= NULL;
pGraph->QueryInterface(IID_IMediaControl,(LPVOID
*)&pMediaControl);
//
録音開始
pMediaControl->Run();
pMediaControl->Stop();
pMediaControl->Release();
pWaveDest->Release();
pWriter->Release()
;
pSink->Release();
pGraph->Release();
次は、 私のプログラムと、waveファイルを、プログラム上で繋ぐ事を考えないと、なりませんね、超難しそう....
H.20.2.25