DirectShow関係
3.キャプチャ
前回カメラから表示させた映像をファイルに保存する方法を説明します。
まずは前回同様、GraphEditでグラフを設計します。
今回も当然カメラを使いますので、カメラのフィルタを追加します。
次にInfinite Pin Tee Filterというフィルタを追加します。(DirectShow
Filtersカテゴリにあります)
このフィルタは入力が1つで、出力が複数(可変)のフィルタで、
データの流れを2つに以上に分けることができます。
今回はファイルに出力しながらプレビュー表示も行いたいので
ファイル出力する流れと、画面に表示する流れの2つに分けます。
2つのフィルタが追加された状態で、
カメラの出力ピン(~Capture)からRender Pinを行います。
(出力ピンで右クリック、ポップアップメニューからRender
Pinをクリック)
これでプレビューの流れが完成しました。
次にファイルに出力する流れを作ります。
AVI MuxフィルタとFile
writerフィルタを追加します。(どちらもDirectShow
Filtersカテゴリにあります)
File writerフィルタを追加しようとすると、ファイル名を入力するダイアログが表示されます。
ここで出力するファイル名を入力してください。
AVI Muxフィルタは通常ビデオの流れと音声の流れを入力し、AVI形式のストリームを出力します。
で、出力されたAVI形式のストリームをFile writerフィルタでファイルに出力すれば
AVIファイルが出来上がるわけです。
最後にInfinite Pin Tee Filterの出力ピンで開いているピンでRenderPinを行えば
AVI MuxフィルタとFile writerフィルタが接続され、グラフが完成します。
Infinite Pin Tee Filterの出力ピンは何度も接続/切断を繰り返していると名前が変わってきますが特に問題はないです。
これでグラフを実行すれば別ウィンドウでプレビューが表示されつつ、AVIファイルが出力されます。
このままだと無圧縮のAVIファイルで出力されます。
何らかの圧縮(コーディック)を行いたいならば、AVI
Muxフィルタの前にコーディックフィルタを追加します。
コーディックフィルタはVideo Compressorsカテゴリにあります。
上図はMpeg4コーディックを追加したみた例です。(MPEG4圧縮されたAVIファイルが出力されます)
ではVBで同じことを行うコードを紹介します。
Option Explicit
'カメラのフィルタ名
Private Const CAMERA_FILTER_NAME$ = "STV0680 Camera" 'Che-es! SPYZ
Private Const CAMERA_OUTPUTPIN_NAME$ = "~Capture"
'グラフ
Private mGrp As QuartzTypeLib.FilgraphManager
'Previewボタン
Private Sub Command1_Click()
'プレビューを開始
MakePreviewGraph
mGrp.Run
End Sub
'Captureボタン
Private Sub Command2_Click()
'キャプチャを開始
MakeCaptureGraph
mGrp.Run
End Sub
'Stopボタン
Private Sub Command3_Click()
If Not mGrp Is Nothing Then
mGrp.Stop
End If
End Sub
'プレビューグラフの作成
Private Sub MakePreviewGraph()
'新しいグラフの作成
Set mGrp = New QuartzTypeLib.FilgraphManager
'グラフにキャプチャ(カメラ)フィルタを追加する
Dim cameraflt As QuartzTypeLib.IFilterInfo
Set cameraflt = AddFilter(mGrp, CAMERA_FILTER_NAME$)
'カメラの出力ピンを取得
Dim camerapin As QuartzTypeLib.IPinInfo
cameraflt.FindPin CAMERA_OUTPUTPIN_NAME$, camerapin
'カメラの出力ピンからフィルタを接続し、グラフを構築する
camerapin.Render
End Sub
'キャプチャグラフの作成
Private Sub MakeCaptureGraph()
'新しいグラフの作成
Set mGrp = New QuartzTypeLib.FilgraphManager
'グラフにキャプチャ(カメラ)フィルタを追加する
Dim cameraflt As QuartzTypeLib.IFilterInfo
Set cameraflt = AddFilter(mGrp, CAMERA_FILTER_NAME$)
'カメラの出力ピンを取得
Dim camerapin As QuartzTypeLib.IPinInfo
cameraflt.FindPin CAMERA_OUTPUTPIN_NAME$, camerapin
'Infinite Pin Tee Filterを追加
Dim infflt As QuartzTypeLib.IFilterInfo
Set infflt = AddFilter(mGrp, "Infinite Pin Tee Filter")
'プレビュー用の流れを繋げる
camerapin.Render
'AVI Muxフィルタを追加
AddFilter mGrp, "AVI Mux"
'FileWriterフィルタを追加
Dim writerflt As QuartzTypeLib.IFilterInfo
Set writerflt = AddFilter(mGrp, "File writer")
'出力ファイル名の設定
Dim snk As DshowForVBLib.IFileSinkFilterForVB
Set snk = writerflt.Filter
snk.SetFileName Text1.Text, Nothing
'Infinite Pin Tee Filterの開いている出力ピンを探す
Dim pn As QuartzTypeLib.IPinInfo
Dim pn2 As QuartzTypeLib.IPinInfo
Dim infpin As QuartzTypeLib.IPinInfo
For Each pn In infflt.Pins
On Error Resume Next
Set pn2 = pn.ConnectedTo
If Err Then
Set pn2 = Nothing
End If
On Error GoTo 0
If pn2 Is Nothing Then
Set infpin = pn
Exit For
End If
Next
'キャプチャの流れを繋げる
infpin.Render
End Sub
'レジストリに登録されているフィルタをグラフに追加する
Public Function AddFilter(ByRef Grp As QuartzTypeLib.FilgraphManager, ByVal FilterName$) As IFilterInfo
Dim regflt As QuartzTypeLib.IRegFilterInfo
For Each regflt In Grp.RegFilterCollection
If regflt.Name = FilterName$ Then
regflt.Filter AddFilter
Exit Function
End If
Next
End Function
|
今回はフォームもあります。
コントロール |
名前 |
適用 |
テキストボックス |
Text1 |
出力するファイル名を入力する。 |
コマンドボタン |
Command1 |
表示名「Preview」。プレビュー表示を開始する。 |
コマンドボタン |
Command2 |
表示名「Capture」。キャプチャを開始する。 |
コマンドボタン |
Command3 |
表示名「Stop」。プレビュー又はキャプチャを終了する。 |
また参照設定で下記のタイプライブラリを指定する必要があります。
DshowForVBLib
これはデフォルトでは一覧に表示されていないと思います。
実はこのタイプライブラリはSDKのサンプルディレクトリにあります。
(SDKインストールフォルダ)\samples\Multimedia\VBSamples\DirectShow\Editing\DShowVBLib\dshowvblib.tlb
このタイプライブラリを参照設定ダイアログの参照ボタンで選択してください。
使い方は、起動後Previewボタンを押すとプレビューを始め、
Captureボタンを押すとキャプチャを開始します。Stopボタンで終了です。
キャプチャ前にテキストボックスに出力ファイル名を入力しておきます。
例によって順に説明していきます。
Option Explicit
'カメラのフィルタ名
Private Const CAMERA_FILTER_NAME$ = "STV0680 Camera" 'Che-es! SPYZ
Private Const CAMERA_OUTPUTPIN_NAME$ = "~Capture"
'フィルタグラフマネージャ
Private mGrp As QuartzTypeLib.FilgraphManager
|
モジュールセクションは前回とまったく同じです。流用して作ったので(笑
'Previewボタン
Private Sub Command1_Click()
'プレビューを開始
MakePreviewGraph
mGrp.Run
End Sub
|
'プレビューグラフの作成
Private Sub MakePreviewGraph()
'新しいグラフの作成
Set mGrp = New QuartzTypeLib.FilgraphManager
'グラフにキャプチャ(カメラ)フィルタを追加する
Dim cameraflt As QuartzTypeLib.IFilterInfo
Set cameraflt = AddFilter(mGrp, CAMERA_FILTER_NAME$)
'カメラの出力ピンを取得
Dim camerapin As QuartzTypeLib.IPinInfo
cameraflt.FindPin CAMERA_OUTPUTPIN_NAME$, camerapin
'カメラの出力ピンからフィルタを接続し、グラフを構築する
camerapin.Render
End Sub |
Previewボタン押下時の処理で、プレビュー用のグラフを作成し実行しています。
コードは前回と同じなので前のページを参照してください。(この辺も前回のをコピペしただけ〜)
'Captureボタン
Private Sub Command2_Click()
'キャプチャを開始
MakeCaptureGraph
mGrp.Run
End Sub
|
'キャプチャグラフの作成
Private Sub MakeCaptureGraph()
'新しいグラフの作成
Set mGrp = New QuartzTypeLib.FilgraphManager
'グラフにキャプチャ(カメラ)フィルタを追加する
Dim cameraflt As QuartzTypeLib.IFilterInfo
Set cameraflt = AddFilter(mGrp, CAMERA_FILTER_NAME$)
'カメラの出力ピンを取得
Dim camerapin As QuartzTypeLib.IPinInfo
cameraflt.FindPin CAMERA_OUTPUTPIN_NAME$, camerapin
'Infinite Pin Tee Filterを追加
Dim infflt As QuartzTypeLib.IFilterInfo
Set infflt = AddFilter(mGrp, "Infinite Pin Tee Filter")
'プレビュー用の流れを繋げる
camerapin.Render
'AVI Muxフィルタを追加
AddFilter mGrp, "AVI Mux"
'FileWriterフィルタを追加
Dim writerflt As QuartzTypeLib.IFilterInfo
Set writerflt = AddFilter(mGrp, "File writer")
'出力ファイル名の設定
Dim snk As DshowForVBLib.IFileSinkFilterForVB
Set snk = writerflt.Filter
snk.SetFileName Text1.Text, Nothing
'Infinite Pin Tee Filterの開いている出力ピンを探す
Dim pn As QuartzTypeLib.IPinInfo
Dim pn2 As QuartzTypeLib.IPinInfo
Dim infpin As QuartzTypeLib.IPinInfo
For Each pn In infflt.Pins
On Error Resume Next
Set pn2 = pn.ConnectedTo
If Err Then
Set pn2 = Nothing
End If
On Error GoTo 0
If pn2 Is Nothing Then
Set infpin = pn
Exit For
End If
Next
'キャプチャの流れを繋げる
infpin.Render
End Sub
|
今回の肝の部分です。長いですが順に説明します。
'キャプチャグラフの作成
Private Sub MakeCaptureGraph()
'新しいグラフの作成
Set mGrp = New QuartzTypeLib.FilgraphManager
'グラフにキャプチャ(カメラ)フィルタを追加する
Dim cameraflt As QuartzTypeLib.IFilterInfo
Set cameraflt = AddFilter(mGrp, CAMERA_FILTER_NAME$)
'カメラの出力ピンを取得
Dim camerapin As QuartzTypeLib.IPinInfo
cameraflt.FindPin CAMERA_OUTPUTPIN_NAME$, camerapin
|
個々まではプレビューと同じです。
カメラフィルタを追加して、出力ピンを取得しています。
'Infinite Pin Tee Filterを追加
Dim infflt As QuartzTypeLib.IFilterInfo
Set infflt = AddFilter(mGrp, "Infinite Pin Tee Filter")
'プレビュー用の流れを繋げる
camerapin.Render
|
Infinite Pin Tee Filterを追加して、プレビュー用の流れを作っています。
やり方は他のフィルタの追加と変わりません。
この状態で、上の2番目の図の状態になります。
'AVI Muxフィルタを追加
AddFilter mGrp, "AVI Mux"
'FileWriterフィルタを追加
Dim writerflt As QuartzTypeLib.IFilterInfo
Set writerflt = AddFilter(mGrp, "File writer")
|
AVI MuxフィルタとFile writerフィルタを追加しています。
AVI Muxフィルタはあとでなにかする必要がないので、戻り値は破棄してます。
'出力ファイル名の設定
Dim snk As DshowForVBLib.IFileSinkFilterForVB
Set snk = writerflt.Filter
snk.SetFileName Text1.Text, Nothing
|
File writerフィルタからIFileSinkFilterForVBインターフェースを取得し、
SetFileNameプロパティでファイル名を設定します。
2番目の引数はNothingでかまいません(メディアタイプを指定したりします)。
'Infinite Pin Tee Filterの開いている出力ピンを探す
Dim pn As QuartzTypeLib.IPinInfo
Dim pn2 As QuartzTypeLib.IPinInfo
Dim infpin As QuartzTypeLib.IPinInfo
For Each pn In infflt.Pins
On Error Resume Next
Set pn2 = pn.ConnectedTo
If Err Then
Set pn2 = Nothing
End If
On Error GoTo 0
If pn2 Is Nothing Then
Set infpin = pn
Exit For
End If
Next
'キャプチャの流れを繋げる
infpin.Render
End Sub
|
キャプチャ用の流れを繋げるために、Infinite Pin Tee Filterの開いている出力ピンを検索し、
Renderメソッドでつなげています。
FindPinで"Output2"とかを探させれば楽なのですが、
名前が変わる可能性があるのちゃんと検索してみました。
ConnectedToメソッドで接続されている相手のピンを取得できるのですが、
その戻りが無いもの(=エラーが発生するもの)を探して
そのピンからRenderメソッドを呼び出してつなげてます。
これでキャプチャ用のグラフ(プレビュー表示付き)が作成されます。
このままだと無圧縮のAVIが出力されますが、
キャプチャ用のRenderを行う前にエンコーダフィルタを追加すれば
MPEGなどのエンコードをかけることもできます。
今回はカメラからソースを取得しましたが、
既に存在するファイルからグラフを作成すれば、
エンコード形式を変換する変換ツールも作れます。
ファイルに動画をキャプチャするときに大切なのは出力ファイル名を指定する部分です。
それ以外は前回までのテクニックの組み合わせですが、
出力するには今回使ったDshowForVBLibなどを使う必要があります。
ファイル名を指定する方法はヘルプに記述がみあたらなかったのですが、
サンプルプログラムをみればすぐに見つかりました。
DirectXはVer2から使ってますが、
DirectXの場合サンプルソースもヘルプの一部と考えるべきだと思いますね。
上に戻る