はじめに
Advanced/W-ZERO3 [es]にはカメラが内蔵されています。前回の記事では、カメラのプレビュー画像を表示するところまで作成しました。今回は静止画撮影を行い、JPEG形式でファイルに保存する方法を紹介します。
これまでの記事
- Advanced/W-ZERO3[es]で簡易音声レコーダを作ろう
- Advanced/W-ZERO3[es]で簡易音声レコーダを作ろう Part 2
- Advanced/W-ZERO3[es]でカメラアプリを作ろう
対象読者
以下のアプリケーションを開発したことがある人。
- C++言語を使ったアプリケーション
- Windows Mobile用アプリケーション
- COMを使ったアプリケーション
本稿は前回の続きです。まだお読みでない方は、こちらを先にお読みになることをお勧めします。
静止画撮影の実装
静止画撮影は、Video Capture FilterのStillピンから静止画を取得してファイルに出力します。手順を以下に示します。
- 撮影画像サイズを設定する。
- 撮影用フィルタグラフを構築する。
- Stillピンから撮影を実行する。
- 撮影完了イベントを捕捉する。
撮影画像サイズを設定する
Video Capture FilterのStillピンに撮影画像サイズを設定します。WMCamera::SetPinProp
を次のように修正します。
HRESULT SetPinProp(void) { IEnumPins *pEP=NULL; pCam->EnumPins(&pEP); IPin *pPin = NULL; while(pEP->Next(1,&pPin,NULL)==S_OK) { PIN_INFO pInfo; pPin->QueryPinInfo(&pInfo); if(lstrcmp(pInfo.achName,L"Preview")!=0 && lstrcmp(pInfo.achName,L"Still")!=0){ //ここを追加 SAFE_RELEASE(pPin); continue; } IAMStreamConfig *pConfig = NULL; //(以下略)
これで、PreviewピンとStillピンに対して画像サイズがQVGA(240×320)となるように設定されます。PreviewピンとStillピンの画像サイズを一致させる必要はありません。高解像度で撮影したいときはStillピンだけVGA(480×640)にすると良いでしょう。
撮影用フィルタグラフを構築する
前回構築したフィルタグラフをベースに、撮影用フィルタグラフに拡張します(図1)。
まず、Image Sink Filterを作成し、フィルタグラフへ追加します。Image Sink FilterとはWindows Mobileに内蔵されているフィルタで、受け取った静止画像をJPEG形式などでファイルに保存することのできるフィルタです。
次に、RenderStream
でStillピンとImage Sink Filterを接続します。このとき、引数に指定するカテゴリをPIN_CATEGORY_STILL
とすれば、Video Capture Filterの3つある出力ピンからStillピンを指定して接続できます。これをWMCamera::Build
に実装します。
// 追加するメンバ変数 IBaseFilter *pIMGSink; // Image Sink Filter用 // 以下をPreviewピンの接続(RenderStream)が終わった直後に追加 CoCreateInstance(CLSID_IMGSinkFilter, NULL , CLSCTX_INPROC, IID_IBaseFilter, (void**)&pIMGSink); pFG->AddFilter(pIMGSink, L"ImgSink"); pGB->RenderStream(&PIN_CATEGORY_STILL , &MEDIATYPE_Video, pCam, NULL, pIMGSink);
Stillピンから撮影を実行する
撮影処理をWMCamera::Take
として実装します。このメソッドをWM_LBUTTONDOWN
メッセージ受信時に呼び出すことにより、画面上をタップして撮影できるようにします。撮影処理は非同期的に行われるため、画面を素早く連打した時にメソッドが二重実行とならないように注意しなければなりません。
//追加するメンバ変数 int TakeCount; // 0 に初期化しておく bool Taking; // 撮影中フラグ false に初期化しておく //WM_LBUTTONDOWNメッセージを受信したら呼び出す void Take(HWND hwnd) { if(Taking) { MessageBeep(-1); return; } Taking=true; // 撮影中フラグをtrueにする //(続く)
Image Sink FilterからIFileSinkFilter2
インターフェースを取得し、出力するファイル名を指定します。更にファイルが存在する場合は上書きするように指定します。
//(WMCamera::Takeの続き) IFileSinkFilter2 *pFSK=NULL; pIMGSink->QueryInterface(IID_IFileSinkFilter2, (void**)&pFSK); TCHAR filename[MAX_PATH]; _snwprintf(filename, MAX_PATH , TEXT("\\My Documents\\test_picture%d.jpg") ,TakeCount); pFSK->SetFileName(filename,NULL); pFSK->SetMode(AM_FILE_OVERWRITE); SAFE_RELEASE(pFSK); //(続く)
Video Capture FilterのIAMVideoControl::SetMode
を使うと静止画の撮影が開始されます。引数にStillピンのインターフェースIPin
を渡すので、あらかじめFindPin
で取得しておきます。
//(WMCamera::Takeの続き) IAMVideoControl *pCtrl=NULL; IPin *pStillPin=NULL; pGB->FindPin(pCam, PINDIR_OUTPUT , &PIN_CATEGORY_STILL , &MEDIATYPE_Video, FALSE, 0, &pStillPin); pCam->QueryInterface(IID_IAMVideoControl, (void**)&pCtrl); pCtrl->SetMode(pStillPin, VideoControlFlag_Trigger); SAFE_RELEASE(pCtrl); SAFE_RELEASE(pStillPin); }
撮影完了イベントを捕捉する。
撮影完了イベントを捕捉する処理を実装します。イベントを捕捉するには、IMediaEventEx::SetNotifyWindow
を使います。これによりイベント発生時にウィンドウメッセージが生成されるようになります。ここでは、WM_APP+1
というウィンドウメッセージが生成されるようにしています。
IMediaEventEx *pME; //追加するメンバ変数 // WMCamera::Build に追加 pFG->QueryInterface(IID_IMediaEventEx, (void**)&pME); pME->SetNotifyWindow((OAHWND)hwnd, (WM_APP+1), (LPARAM)0);
イベントはIMediaEvent::GetEvent
で取得できます。撮影完了時は、出力値であるイベントコードがEC_CAP_FILE_COMPLETED
となっています。
// (WM_APP+1)メッセージを受信したときに呼び出す void DshowEvent(HWND hwnd) { long evCode; // イベントコード long lParam1, lParam2; while(pME && pME->GetEvent(&evCode, &lParam1, &lParam2, 0)==S_OK) { switch(evCode) { case EC_CAP_FILE_COMPLETED: OutputDebugString(L"EC_CAP_FILE_COMPLETED\n"); ++TakeCount; Taking=false; // 撮影中フラグを false に戻す break; // 他にイベントを取得する場合は、case文を追加する } pME->FreeEventParams(evCode, lParam1, lParam2); } }