DirectShow関係3(VB2005)


1.動画の再生

VB6の時と同様にもっとも簡単と思われる動画ファイル再生からやってみます。

DirectShow(COM)を直接操作する場合、
その手順は基本的にVC++などでの操作と同じになります。
動画を再生する簡単な方法は下記のようになります。

 @フィルタグラフマネージャのインスタンスを作成する

 Aフィルタグラフを作成する

 Bグラフを実行する

動画を再生するだけのサンプルプログラムは下記になります。
実行すると「c:\media\test.avi」というファイルをいきなり再生します。

'名前空間のインポート
Imports System
Imports System.Runtime.InteropServices

'DirectShowインターフェースの定義
Module DirectShowDefine

    'IGraphBuilderインターフェース
    <ComVisible(True), ComImport(), Guid("56a868a9-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IGraphBuilder
        <PreserveSig()> Function AddFilter(<[In]()> ByVal pFilter As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pName As String) As Integer
        <PreserveSig()> Function RemoveFilter(<[In]()> ByVal pFilter As IntPtr) As Integer
        <PreserveSig()> Function EnumFilters(<Out()> ByRef ppEnum As IntPtr) As Integer
        <PreserveSig()> Function FindFilterByName(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pName As String, <Out()> ByRef ppFilter As IntPtr) As Integer
        <PreserveSig()> Function ConnectDirect(<[In]()> ByVal ppinOut As IntPtr, <[In]()> ByVal ppinIn As IntPtr, <[In](), MarshalAs(UnmanagedType.LPStruct)> ByVal pmt As IntPtr) As Integer
        <PreserveSig()> Function Reconnect(<[In]()> ByVal ppin As IntPtr) As Integer
        <PreserveSig()> Function Disconnect(<[In]()> ByVal ppin As IntPtr) As Integer
        <PreserveSig()> Function SetDefaultSyncSource() As Integer

        <PreserveSig()> Function Connect(<[In]()> ByVal ppinOut As IntPtr, <[In]()> ByVal ppinIn As IntPtr) As Integer
        <PreserveSig()> Function Render(<[In]()> ByVal ppinOut As IntPtr) As Integer
        <PreserveSig()> Function RenderFile(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFile As String, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrPlayList As String) As Integer
        <PreserveSig()> Function AddSourceFilter(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFileName As String, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFilterName As String, <Out()> ByRef ppFilter As IntPtr) As Integer
        <PreserveSig()> Function SetLogFile(ByVal hFile As IntPtr) As Integer
        <PreserveSig()> Function Abort() As Integer
        <PreserveSig()> Function ShouldOperationContinue() As Integer
    End Interface

    'IMediaControlインターフェース
    <ComVisible(True), ComImport(), Guid("56a868b1-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsDual)> _
    Public Interface IMediaControl
        <PreserveSig()> Function Run() As Integer
        <PreserveSig()> Function Pause() As Integer
        <PreserveSig()> Function [Stop]() As Integer
        <PreserveSig()> Function GetState(ByVal msTimeout As Integer, ByRef pfs As Integer) As Integer
        <PreserveSig()> Function RenderFile(ByVal strFilename As String) As Integer
        <PreserveSig()> Function AddSourceFilter(<[In]()> ByVal strFilename As String, <Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function get_FilterCollection(<Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function get_RegFilterCollection(<Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function StopWhenReady() As Integer
    End Interface

End Module

Public Class Form1

    'グラフビルダー
    Private mGrp As IGraphBuilder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'タイプの取得
        Dim comtype As Type
        comtype = Type.GetTypeFromCLSID(New Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"))

        'インスタンス作成
        Dim comobj As Object
        comobj = Activator.CreateInstance(comtype)
        mGrp = CType(comobj, IGraphBuilder)
        comobj = Nothing
        comtype = Nothing

        'グラフ作成
        mGrp.RenderFile("c:\media\test.avi", "")

        '再生
        Dim ctl As IMediaControl
        ctl = CType(mGrp, IMediaControl)
        ctl.Run()

    End Sub

End Class


このサンプルプログラムは、
VB2005の「新しいプロジェクト」で「Windowsアプリケーション」を選択し、
Form1にコードを書いたものです。
以後、このソースを元に説明していきます。


まず、DirectShow(COM)のインターフェースを定義してやる必要があります。
いきなりですが、定義は下記のようになります。

'名前空間のインポート
Imports System
Imports System.Runtime.InteropServices

'DirectShowインターフェースの定義
Module DirectShowDefine

    'IGraphBuilderインターフェース
    <ComVisible(True), ComImport(), Guid("56a868a9-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
    Public Interface IGraphBuilder
        <PreserveSig()> Function AddFilter(<[In]()> ByVal pFilter As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pName As String) As Integer
        <PreserveSig()> Function RemoveFilter(<[In]()> ByVal pFilter As IntPtr) As Integer
        <PreserveSig()> Function EnumFilters(<Out()> ByRef ppEnum As IntPtr) As Integer
        <PreserveSig()> Function FindFilterByName(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pName As String, <Out()> ByRef ppFilter As IntPtr) As Integer
        <PreserveSig()> Function ConnectDirect(<[In]()> ByVal ppinOut As IntPtr, <[In]()> ByVal ppinIn As IntPtr, <[In](), MarshalAs(UnmanagedType.LPStruct)> ByVal pmt As IntPtr) As Integer
        <PreserveSig()> Function Reconnect(<[In]()> ByVal ppin As IntPtr) As Integer
        <PreserveSig()> Function Disconnect(<[In]()> ByVal ppin As IntPtr) As Integer
        <PreserveSig()> Function SetDefaultSyncSource() As Integer

        <PreserveSig()> Function Connect(<[In]()> ByVal ppinOut As IntPtr, <[In]()> ByVal ppinIn As IntPtr) As Integer
        <PreserveSig()> Function Render(<[In]()> ByVal ppinOut As IntPtr) As Integer
        <PreserveSig()> Function RenderFile(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFile As String, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrPlayList As String) As Integer
        <PreserveSig()> Function AddSourceFilter(<[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFileName As String, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal lpcwstrFilterName As String, <Out()> ByRef ppFilter As IntPtr) As Integer
        <PreserveSig()> Function SetLogFile(ByVal hFile As IntPtr) As Integer
        <PreserveSig()> Function Abort() As Integer
        <PreserveSig()> Function ShouldOperationContinue() As Integer
    End Interface

    'IMediaControlインターフェース
    <ComVisible(True), ComImport(), Guid("56a868b1-0ad4-11ce-b03a-0020af0ba770"), InterfaceType(ComInterfaceType.InterfaceIsDual)> _
    Public Interface IMediaControl
        <PreserveSig()> Function Run() As Integer
        <PreserveSig()> Function Pause() As Integer
        <PreserveSig()> Function [Stop]() As Integer
        <PreserveSig()> Function GetState(ByVal msTimeout As Integer, ByRef pfs As Integer) As Integer
        <PreserveSig()> Function RenderFile(ByVal strFilename As String) As Integer
        <PreserveSig()> Function AddSourceFilter(<[In]()> ByVal strFilename As String, <Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function get_FilterCollection(<Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function get_RegFilterCollection(<Out(), MarshalAs(UnmanagedType.IDispatch)> ByRef ppUnk As Object) As Integer
        <PreserveSig()> Function StopWhenReady() As Integer
    End Interface

End Module


最初のImportsは、System及びSystem.Runtime.InteropServices
名前空間に属する関数等を使うための宣言になります。

Module DirectShowDefine〜End Moduleでは動画を再生するために必要な
二つのインターフェースを定義しています。

IGraphBuilderはフィルタグラフを作成するメソッドからなるインターフェースです。
IMediaControlはフィルタグラフの動作を制御するメソッドからなるインターフェースです。
つまりIGraphBuilderでグラフを作り、IMediaControlでグラフを実行します。

インターフェースは「Interface」文で定義します。
各インターフェースのメソッドや引数などは
C用のヘッダファイなどをみて定義することになります。
またSDK内のIDLファイルも参考になります。

ちなみにインターフェース定義のコードについてはヘルプを参照してください。
実は正直に言いますと、あんまり自信がありません。(笑
「こうやったらできた」程度の精度ですので、疑問があったらこのコードは信じないで調べてくださいませ。
(個々のキーワードはわかるのですが・・・ COMに関する自分の知識が不安になってくる・・・)


以降はロジック部分になります。

Public Class Form1

    'グラフビルダー
    Private mGrp As IGraphBuilder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'タイプの取得
        Dim comtype As Type
        comtype = Type.GetTypeFromCLSID(New Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"))

        'インスタンス作成
        Dim comobj As Object
        comobj = Activator.CreateInstance(comtype)
        mGrp = CType(comobj, IGraphBuilder)
        comobj = Nothing
        comtype = Nothing

        'グラフ作成
        mGrp.RenderFile("c:\media\test.avi", "")

        '再生
        Dim ctl As IMediaControl
        ctl = CType(mGrp, IMediaControl)
        ctl.Run()

    End Sub

End Class


各動作ごとに詳細を説明していきます。

Public Class Form1

    'グラフビルダー
    Private mGrp As IGraphBuilder

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Form1クラスのモジュールセクションに定義しているmGrp
変数の型はIGraphBuilderになってますが、
実体はフィルタグラフマネージャになります。

フィルタグラフマネージャ」というオブジェクトを
IGraphBuilderという色眼鏡をかけてみていると思ってください。
同様にこのサンプルコードでは、同じオブジェクトに対して
IMediaControlという色眼鏡ででもみています。
実体は同じなのですが、見方によってやれることが違うってことです。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'タイプの取得
        Dim comtype As Type
        comtype = Type.GetTypeFromCLSID(New Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"))

まず「フィルタグラフマネージャ」のタイプを取得します。
「フィルタグラフマネージャ」のクラスIDを指定して
関連付けられている型を取得します。
これは次のインスタンス化のときに必要となります。

        'インスタンス作成
        Dim comobj As Object
        comobj = Activator.CreateInstance(comtype)
        mGrp = CType(comobj, IGraphBuilder)
        comobj = Nothing
        comtype = Nothing

ActivatorCreateInstanceメソッドにて
「フィルタグラフマネージャ」のインスタンスを作成します。
作成したインスタンスはとりあえずmGrpに入れてます。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'タイプの取得
        Dim comtype As Type
        comtype = Type.GetTypeFromCLSID(New Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"))

        'インスタンス作成
        Dim comobj As Object
        comobj = Activator.CreateInstance(comtype)
        mGrp = CType(comobj, IGraphBuilder)
        comobj = Nothing
        comtype = Nothing

        'グラフ作成
        mGrp.RenderFile("c:\media\test.avi", "")

        '再生
        Dim ctl As IMediaControl
        ctl = CType(mGrp, IMediaControl)
        ctl.Run()

    End Sub

End Class

「フィルタグラフマネージャ」が持っている
IGraphBuilderインタフェース」の「RenderFile」メソッドで
動画ファイルからフィルタグラフを作成します。
動画ファイルを再生するだけなら
この一行だけでフィルタグラフが作成されます。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'タイプの取得
        Dim comtype As Type
        comtype = Type.GetTypeFromCLSID(New Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"))

        'インスタンス作成
        Dim comobj As Object
        comobj = Activator.CreateInstance(comtype)
        mGrp = CType(comobj, IGraphBuilder)
        comobj = Nothing
        comtype = Nothing

        'グラフ作成
        mGrp.RenderFile("c:\media\test.avi", "")

        '再生
        Dim ctl As IMediaControl
        ctl = CType(mGrp, IMediaControl)
        ctl.Run()

    End Sub

End Class

最後にグラフを実行させます。
mGrpから「IMediaControlインターフェース」を取得し
Runメソッド」にてグラフを実行させます。


先にも書きましたが、この方法でDirectShowを使うときの手順は、
基本的にVC用のヘルプを参照することになります。
インスタンス化やキャストの部分はVB2005用に読み違える必要がありますが、
流れとしてはまったく同じ操作になります。

問題なのはインターフェースの定義ぐらいでしょうか。(^^;
とりあえず私が(自分用に)作成した基本的なインターフェースの定義を
近いうちにアップしてみます。


上に戻る