録音機能の実装(1/2)
DirectShowを使う準備ができたら、いよいよ肝となる録音機能を実装していきます。
DirectShowの概要
DirectShowでは「フィルタ」と呼ばれるコンポーネットを繋ぐことにより映像や音声を処理します。フィルタには1つ以上の「ピン」と呼ばれるフィルタ同士の接続ポイントがあります。ピンには「入力ピン」と「出力ピン」があり、データは出力ピンから入力ピンに向かって流れます。
フィルタを繋いでいくと、いわゆる有向グラフとなります。これを「フィルタグラフ」と呼びます。

DirectShowにはさまざまな機能を持ったフィルタが用意されています(もちろん自分で作ることもできます)。開発者は目的に合わせてフィルタを選択し、フィルタグラフを構築します。本稿で構築するフィルタグラフのイメージを下図に示します。

フィルタグラフを構築する準備をする
フィルタグラフを構築するために、表1に示すインターフェイスを取得します。これらはCOMのAPIである、CoCreateInstanceを使って作成します。
| 名称 | フィルタグラフ | キャプチャグラフビルダ |
| クラス ID | CLSID_FilterGraph | CLSID_CaptureGraphBuilder |
| インターフェイス ID | IID_IGraphBuilder | IID_ICaptureGraphBuilder2 |
| 型 | IGraphBuilder | ICaptureGraphBuilder2 |
| 役割 | フィルタグラフを構築する。 フィルタ同士を接続する。 |
フィルタ同士の接続を容易にする。 |
さらに、フィルタグラフ制御用にIGraphBuilderからIMediaControlインターフェイスをIUnknown::QueryInterfaceを使って取得します。
まずはここまで実装してみます。フィルタグラフを制御するクラスをCDshowRecクラスとして「DshowRec.h」に実装します。「stdafx.h」に#include "DshowRec.h"を追加します。
#pragma once #define SAFE_RELEASE(p) { if((p)!=NULL) { (p)->Release(); (p)=NULL; }} // DirectShow による WMA の音声レコーダクラス class CDshowRec { ICaptureGraphBuilder2 *m_pGB; IGraphBuilder *m_pFG; IMediaControl *m_pMC; IBaseFilter *m_pAudioCap; IBaseFilter *m_pAsfWriter; public: CDshowRec() : m_pGB(NULL), m_pFG(NULL), m_pMC(NULL), m_pAudioCap(NULL), m_pAsfWriter(NULL) { } void Init() { OUT_MSG(_T("Init")); OUT_HR(CoCreateInstance(CLSID_CaptureGraphBuilder, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)&m_pGB)); OUT_HR(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pFG)); OUT_HR(m_pGB->SetFiltergraph(m_pFG)); OUT_HR(m_pFG->QueryInterface(IID_IMediaControl, (void**)&m_pMC)); // ( ... 続く)
フィルタを作成し、フィルタグラフへ追加する
CoCreateInstanceを使ってフィルタを作成し、フィルタグラフへ追加します。作成するフィルタを表2に挙げます。
| 名称 | オーディオキャプチャフィルタ | WM ASF ライタ |
| クラス ID | CLSID_AudioCapture | CLSID_ASFWriter |
| インターフェイス ID | IID_IBaseFilter | IID_IBaseFilter |
| 型 | IBaseFilter | IBaseFilter |
| 役割 | 音声をキャプチャする。 | ASF 形式でファイルに出力。 |
オーディオキャプチャフィルタは、マイクから音声を取得するフィルタです。オーディオキャプチャフィルタを追加する前にIPersistPropertyBagインターフェイスを取得し、IPersistPropertyBag::Loadを呼び出しておきます。
WM ASFライタフィルタは、ASF形式でファイルに出力するフィルタです。IFileSinkFilterインターフェイスを取得し、IFileSinkFilter::SetFileNameでファイル名を指定します。指定されたファイル名でASF形式のファイルが出力されます。
オーディオキャプチャフィルタとWM ASFライタをICaptureGraphBuilder2::RenderStreamを使って接続します。
// (CDshowRec::Init の続き) // AudioCapture フィルタの初期化 OUT_HR(CoCreateInstance(CLSID_AudioCapture, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&m_pAudioCap)); IPersistPropertyBag *pPSBag=NULL; OUT_HR(m_pAudioCap->QueryInterface(IID_IPersistPropertyBag, (void**)&pPSBag)); OUT_HR(pPSBag->Load(NULL, NULL)); SAFE_RELEASE(pPSBag); // ASF ライタ フィルタの追加と出力ファイル名の設定 OUT_HR(CoCreateInstance(CLSID_ASFWriter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **)&m_pAsfWriter)); IFileSinkFilter *pSink=NULL; OUT_HR(m_pAsfWriter->QueryInterface(IID_IFileSinkFilter, (void**)&pSink)); OUT_HR(pSink->SetFileName( L"\\My Documents\\my_voice_memo.asf", NULL)); SAFE_RELEASE(pSink); // フィルタをフィルタグラフへ追加し、接続する OUT_HR(m_pFG->AddFilter(m_pAudioCap,_T(""))); OUT_HR(m_pFG->AddFilter(m_pAsfWriter,_T(""))); SetAudioOutProp(); // あとで実装する OUT_HR(m_pGB->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, m_pAudioCap, NULL, m_pAsfWriter)); }
