DirectShowその2(CComPtr(ATL)導入)
C++的には、Com用のスマートポインタが是非とも必要だ。
調べたところ、CComPtrというものがATLに含まれることがわかった。
ATLはMFCと関係があるらしい?が、MFCは守備範囲外なので避けたいところだ・・・
で、WinDdkからMFC共々入手可能らしい。
- http://blogs.yahoo.co.jp/elku_simple/30240752.html
- http://ysmt.blog21.fc2.com/blog-entry-244.html
- http://d.hatena.ne.jp/sea-show/20100517/1274104239
CComPtrとCComQIPtrを使う
素晴らしくシンプルになった。
#include <tchar.h> #include <iostream> #include <string> #include <vector> #include <atlbase.h> #include <dshow.h> #pragma comment(lib, "strmiids") class Com { public: Com() { CoInitialize(NULL); } ~Com() { CoUninitialize(); } }; static std::wstring to_WideChar(UINT uCodePage, const std::string &text) { int size=MultiByteToWideChar(uCodePage, 0, text.c_str(), -1, NULL, 0); std::vector<wchar_t> buf(size); size=MultiByteToWideChar(uCodePage, 0, text.c_str(), -1, &buf[0], buf.size()); return std::wstring(buf.begin(), buf.begin()+size); } int main(int argc, char **argv) { if(argc<2){ std::cout << "usage: " << argv[0] << " {file}" << std::endl; return 0; } Com com; CComPtr<IGraphBuilder> gb; if(FAILED(gb.CoCreateInstance(CLSID_FilterGraph))){ return 1; } CComQIPtr<IMediaControl> mc(gb); if(!mc){ return 2; } std::wstring file=to_WideChar(CP_OEMCP, argv[1]); if(FAILED(gb->RenderFile(file.c_str(), NULL))){ return 3; } mc->Run(); std::cout << "hit any key" << std::endl; std::string line; std::getline(std::cin, line); return 0; }
CComPtrは
C:\WinDDK\7600.16385.1\inc\atl71\atlcomcli.h
に書いてあるので見てAddRef, Releaseの動きを把握する。
QueryInterfaceで取得するものは、CComQIPtrを使う。
classとIID_XXXXが一意に結びついているので
iidは__uuidof(class)で取得できるらしく、故に明示的に指定する必要が無いということですな。
リンク時に警告が出るw
ddkとvc2010のバージョンがあっていないとかか?
main.obj : warning LNK4254: セクション 'ATL' (50000040) は '.rdata' (40000040) に異なる属性を伴ってマージされています
問題なく動いたが、無視できる警告なのかは知らない
DirectShowプログラミング開始
OpenCVとかKinectに行く前の下準備で、DirectShowをマスターすることにした。
はじめての動画処理プログラミング―Win32APIとDirectXで実装する動画処理の基礎 (プログラミング・マスタ・シリーズ)
- 作者: 土井滋貴
- 出版社/メーカー: CQ出版
- 発売日: 2007/02/01
- メディア: 単行本
- クリック: 80回
- この商品を含むブログ (10件) を見る
VC2010 expressedition
を使う。
DirectShowのインストール?
VCとDirectXのバージョンによって情報が錯綜しているのだけど、
VC2010 expresseditionに関しては下記にdshow.hが存在した。
最初から入っているということでよさげ。
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include
動作確認
本の最初のDirectShowサンプルをC++風?に書いてみた。
#include <iostream> #include <string> #include <dshow.h> #include <vector> #pragma comment(lib, "strmiids") class Com { public: Com() { CoInitialize(NULL); } ~Com() { CoUninitialize(); } }; class ComGraphBuilder { IGraphBuilder *pigb; public: ComGraphBuilder() : pigb(0) { HRESULT hr=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**) &pigb); } ~ComGraphBuilder() { if(pigb){ pigb->Release(); } } bool RenderFile(const std::wstring &file) { return pigb->RenderFile(file.c_str(), NULL)==S_OK; } IGraphBuilder* Get(){ return pigb; } }; class ComMediaControl { IMediaControl *pimc; public: ComMediaControl(IGraphBuilder *pigb) : pimc(0) { HRESULT hr=pigb->QueryInterface(IID_IMediaControl, (void**)&pimc); } ~ComMediaControl() { if(pimc){ pimc->Release(); } } void Run() { pimc->Run(); } IMediaControl *Get(){ return pimc; } }; static std::wstring to_WideChar(UINT uCodePage, const std::string &text) { int size=MultiByteToWideChar(uCodePage, 0, text.c_str(), -1, NULL, 0); std::vector<wchar_t> buf(size); size=MultiByteToWideChar(uCodePage, 0, text.c_str(), -1, &buf[0], buf.size()); return std::wstring(buf.begin(), buf.begin()+size); } int main(int argc, char **argv) { if(argc<2){ std::cout << "usage: " << argv[0] << " {file}" << std::endl; return 0; } Com com; ComGraphBuilder gb; if(!gb.Get()){ return 1; } ComMediaControl mc(gb.Get()); if(!mc.Get()){ return 2; } if(!gb.RenderFile(to_WideChar(CP_OEMCP, argv[1]))){ return 3; } mc.Run(); std::cout << "hit any key" << std::endl; std::string line; std::getline(std::cin, line); return 0; }
チルト
積んであったkinectを動かしてみる。
SDK1.5でチルト角の調整。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using Microsoft.Kinect; namespace Tilt { public partial class Form1 : Form { KinectSensor kinect; public Form1() { InitializeComponent(); kinect = KinectSensor.KinectSensors[0]; kinect.Start(); kinectTilt.Value = kinect.ElevationAngle; } private void numericUpDown1_ValueChanged(object sender, EventArgs e) { try { kinect.ElevationAngle = (int)kinectTilt.Value; } catch (InvalidOperationException ex) { MessageBox.Show(ex.ToString()); } } } }
ネット上によくある
using Microsoft.Research.Kinect;
とか
Runtime
というのが変わっているぽいのでSDK1.5版のメモ。
とりあえずVertexBuffer
PmxのVertexとIndices部分だけのパーサを書いて、VertexBufferの描画までやってみた。
次はモーションの実装をする。
bulletsharpを使う予定。
NUnit導入
テスト駆動開発にすべく取り入れる。
いくつかはまりポイントがあったのでメモ。
nunit.exeをC#4.0のランタイムで起動する。
[File]-[Select Runtime]で選択できるように見えるのだが、メニューから変更する方法がわからなかった。
たまたまnunit.exe.configを開いたら変更方法が書いてあったを見つけた。
<startup useLegacyV2RuntimeActivationPolicy="true"> <!-- Comment out the next line to force use of .NET 4.0 --> <!-- <supportedRuntime version="v2.0.50727" /> --> <supportedRuntime version="v4.0.30319" /> </startup>
読み込み時に以下のエラーがでる。
Test load failed! System.IO.FileNotFoundException: ファイルまたはアセンブリ'nunit.framework, Version=2.6.0.12051, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77'、またはその依存関係の1つが読み込めませんでした。指定されたファイルが見つかりません。 For further information, use the Exception Details menu item
nunit.framework.dllを見つけることができないのが原因なのだが、PATHを通してもうまくいかなかった。テスト対象のdllと同じディレクトリにnunit.frameworkd.dllをコピーしたら直った。
premake4でC#開発
vimじゃないとだめなのでちょっと寄り道。
こちら
を参考にIDEから降りる道を模索。
premake4でC#向けのMakefileの自動生成
premake4.lua
-- A solution contains projects, and defines the available configurations solution "Sample" configurations { "Release", "Debug" } configuration "windows*" do end configuration "Debug" do flags { "Symbols" } targetdir "debug" end configuration "Release" do flags { "Optimize" } targetdir "release" end configuration {} ------------------------------------------------------------------------------ -- Project ------------------------------------------------------------------------------ project "Sample" --language "C" --language "C++" language "C#" --kind "StaticLib" --kind "DynamicLib" kind "ConsoleApp" --kind "WindowedApp" files { "*.cs", } defines { } includedirs { } libdirs { "C:/Program Files (x86)/SlimDX SDK (January 2012)/Bin/net40/x86", } links { "SlimDX", }
$ export PATH=/cygdrive/C/WINDOWS/Microsoft.NET/Framework/v4.0.30319:$PATH $ premake4 --dotnet=msnet gmake $ make verbose=t ==== Building Sample (release) ==== Creating obj/Release mkdir -p obj/Release csc /nologo /out:release/Sample.exe /optimize /t:exe /lib:C:/Program\ Files\ \(x86\)/SlimDX\ SDK\ \(January\ 2012\)/Bin/net40/ x86 /r:SlimDX.dll Hello.cs $ ./release/Sample.exe hello world
VCのソリューションも以下の方法で作れる。
$ premake4 vs2008
# vs2010は未対応だった premake4.3