2011-02-03 16 views
4

私はWPFとDirectShowを使用してアプリケーションを作成しており、問題は発生しています。私のアプリケーションは、DirectShowNet(DSのC#ラッパークラス)を使用して記述された静的クラスで、静的メソッドStart()およびStop()を使用してDSを使用します。私はWPFウィンドウに(WindowsFormsHostオブジェクトを介して)グラフをレンダリングする必要があるWindowsフォームパネルを持っています。ここでは、アプリケーションの一般的な流れです:Start()メソッドは、グラフを構築し、それを開始します。私は、ウィンドウのフォームパネルのハンドルを渡し、IVideoWindowインターフェイスを使ってレンダリングします。 Start()が戻り、グラフがバックグラウンドで実行されます。ある時点で、Stop()が呼び出されます。このメソッドはグラフを停止し、グラフを破棄します。DirectShow/WPFスレッドの問題

Start()とStop()を同じスレッドから呼び出す限り、すべて正常に動作します。しかし、私は自分のアプリで別のスレッドからそれらを呼び出す必要があります。この場合、グラフを破棄するコードの部分(特にフィルタを列挙しようとしているとき)で例外が発生します。私はDirectShowで作業するときにマルチスレッドアパートメントを使用する必要があることを発見しました。これはWindows Formsアプリケーションでは簡単です。私は主な方法で[MTAThread]を投げるだけです。すべてが機能します。

私のWPFアプリケーションでは、これは明らかにオプションではありません。私の回避策は、Start()とStop()を呼び出す必要があるときに新しいMTAスレッドを起動することでした。これは例外を取り除きますが、別の問題をもたらしました。 Start()メソッドが戻ると、ビデオはレンダーパネルから消えます。 Start()メソッドの最後にSleepを置くと、Sleepが終了するまでビデオが表示されます。さらに、私は、グラフが消えてからグラフが実行され続けることを確認しました。誰にどのように進むべきかアドバイスはありますか?ありがとう。

ケビン

+1

ポストコードを記入するかポストしますか?私は最初に行くだろう。 –

+2

なぜDirectShowを使用していますか? WPFはメディアを再生できます。 –

+1

@エモ - おそらく彼はファイルや通常のビデオストリームではないビデオソースを持っていますか?彼はある種のカスタムソースフィルタを持っているかもしれませんが、私はこれまでに遭遇しました。 – Kazar

答えて

0

FYI、WindowsフォームはMTAThreadメインスレッドをサポートしていません。それがうまくいけば、あなたはただ幸運になりました。

STAスレッドからDSオブジェクトを呼び出すことができるはずです - 私はDSに慣れていませんが、windowless modeを使用しているように聞こえますが、それはSTA 。

この場合、メインスレッドからいつもStart/Stopを呼び出してみませんか?別のスレッドがメインスレッドに停止または開始を伝える必要がある場合は、TaskScheduler.FromCurrentSynchronizationContextにタスクをキューイングしてメインスレッド上で実行するようにしてください。

1

例外はスローされますか?私は次のようなものを推測しています。「呼び出しスレッドは、別のスレッドが所有しているため、このオブジェクトにアクセスできません。

この場合、hereの説明に従って、正しいディスパッチャを使用して通話してください。

0

私は以前はあまり変わっていない問題に遭遇しましたが、WPFではそうではありませんでしたので、以下の(非常にハッキーな)提案を塩のピンチで取ります。

以下のメソッドは、基本的にdirectshowコマンドを実行する完全に別個のアプリケーションスレッドを作成しますが、WPFアプリケーションでホストされているWindowsフォームコントロールのハンドルを使用するようにダイレクトショーに指示します。

だから、最初に私たちは、ダミーのWinFormsは、我々は上のコールを呼び出すために使用できることを形成する必要があるが、それは決して、レンダリングを取得するつもりはありません:

/// <summary> 
/// Just a dummy invisible form. 
/// </summary> 
private class DummyForm : Form 
{ 

    protected override void SetVisibleCore(bool value) 
    { 
     //just override here, make sure that the form will never become visible 
     if (!IsHandleCreated) 
     { 
      CreateHandle(); 
     } 

     value = false; 
     base.SetVisibleCore(value); 
    } 
} 

次のステップは、我々は置くことができますスレッドを作成することですメッセージループ上:ダミーフォーム(およびそのスレッド)が作成された後

//this will need to be a class level variable, since all the directshow 
//calls will get invoked on this form 
DummyForm dumbForm; 
Thread separateThread; 


private void CreateDummyForm() 
{ 

    ManualResetEvent reset = new ManualResetEvent(false); 

    //create our thread 
    separateThread = new Thread((ThreadStart) 
    delegate 
    { 

     //we need a dummy form to invoke on 
     dumbForm = new DummyForm(); 

     //signal the calling method that it can continue 
     reset.Set(); 

     //now kick off the message loop 
     Application.Run(dumbForm); 
    }); 

    //set the apartment state of this new thread to MTA 
    separateThread.SetApartmentState(ApartmentState.MTA); 
    separateThread.IsBackground = true; 
    separateThread.Start(); 

    //we need to wait for the windowing thread to have initialised before we can 
    //say that initialisation is finished 
    reset.WaitOne(); 

    //wait for the form handle to be created, since this won't happen until the form 
    //loads inside Application.Run 
    while (!dumbForm.IsHandleCreated) 
    { 
     Thread.Sleep(0); 
    } 

} 

そう、あなたがそうのようなMTA アプリケーションスレッド上で呼び出しを呼び出すことができます。

あなたはすべてのDirectShowもので終わっその後

、そのようなシャットダウンあなたの個別のアプリケーションのスレッド:このアプローチの

//to end the separate thread and application loop, 
//just close your invisible form 
dumbForm.Close(); 

利点は、あなたがきちんと別のスレッドにDirectShowのサンドボックスということです。欠点は、Invoke呼び出しのコンテキスト切り替えと、別のアプリケーションスレッドを持つオーバーヘッドです。あなたはこれをあなたの現在のアーキテクチャに組み込むことが楽しいかもしれませんが、助けてください。

あなたはどのように乗っているか教えてください。私はこの作品がどれほどうまくいっているかに興味を持っています。