Stack Overflow メンバーの皆様、こんにちは。
私はC#プログラミングの初心者です。基本的なカメラ ストリーミングとキャプチャ アプリケーションを開発しています。ユーザーが撮影したら、VMR9 のビットマップ ミキシング コンセプトを使用してオーバーレイに表示します。
私がしたこと?
- ここからC#ダイレクトショーライブラリを利用しています
- まず、必要なフィルター インターフェイスをすべて取得します。接続されているキャプチャ デバイスを見つけます。PREVIEW ピンのソース フィルターと vmr9 でレンダー ストリームと呼ばれます。STILL PIN のソース フィルター、サンプル グラバー、ヌル レンダラー。
- 私は3つのメニューボタンを持っています->静止画を撮り、オーバーレイを表示し、オーバーレイを非表示にします。
- そのライブラリで提供されているビットマップ ミキサー サンプルを利用しています。
- ユーザーが [Take Still] メニューを押すたびに、画像がデスクトップに保存され、小さな解像度にサイズ変更されてビデオ オーバーレイに表示されます。
- オーバーレイの表示とオーバーレイの非表示は、vmr9 フィルターから VMR9BitmapMixer インターフェイスを照会する操作を実行する ShowHideBitmap() を呼び出し、VMR9AlphaBitmap 構造を埋めてから IVMRMixerBitmap9.SetAlphaBitmap 関数を呼び出します。
私が直面している問題は何ですか?
- 静止画を撮影した後、メニュー オプションから ShowHideBitmap() を呼び出すと、撮影した静止画がオーバーレイ上で完全に更新されます。
- これは、静止画像が保存されるとすぐにオーバーレイの自動更新を実行する別のオプションです。イベントベースのスレッドを作成し、EventWaitHandle を使用して作成された更新イベントを待機するようにしました。samplegrabber BufferCB 関数から戻る前に、この更新イベントを設定します。次に、待機中のスレッドに進みます。スレッド内で ShowHideBitmap 関数を呼び出します。このシナリオでは、次のようなエラー メッセージが表示されます。
Unable to case COM object of type 'DirectShowLib.VideoMixingRenderer9' to interface type 'DirectShowLib.IVMRMixerBitmap9'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{ced175e5-1935-4820-81bd-ff6ad00c9108}' failed due to the following error: No such interface supported (Exception from HRESULT: 0X80040002 (E_NOINTERFACE)
ShowHideBitmap 関数のコード ブロックは次のとおりです。
//Declarations
private static IBaseFilter vmr9 = null;
private static IVMRMixerBitmap9 vmr9mixerBitmap = null;
private IVMRWindowlessControl9 vmr9windowlessCtrl = null;
private static void ShowHideBitmap(Boolean bEnable)
{
int hr = 0;
VMR9AlphaBitmap alphaBmp;
if (!bEnable)
{
if (vmr9mixerBitmap != null)
{
// Get current Alpha Bitmap Parameters
hr = vmr9mixerBitmap.GetAlphaBitmapParameters(out alphaBmp);
DsError.ThrowExceptionForHR(hr);
// Disable them
alphaBmp.dwFlags = VMR9AlphaBitmapFlags.Disable;
// Update the Alpha Bitmap Parameters
hr = vmr9mixerBitmap.UpdateAlphaBitmapParameters(ref alphaBmp);
DsError.ThrowExceptionForHR(hr);
// Create a surface from our alpha bitmap
surface.Dispose();
vmr9mixerBitmap = null;
//Release this alpha bitmap source.
if (alphaBitmap != null)
{
alphaBitmap.Dispose();
}
}
return;
}
else
{
try
{
alphaBitmap = BitmapGenerator.GenerateAlphaBitmap();
// Create a surface from our alpha bitmap
if(surface == null)
surface = new Surface(device, alphaBitmap, Pool.SystemMemory);
// Get the unmanaged pointer
unmanagedSurface = surface.GetObjectByValue(DxMagicNumber);
if (vmr9mixerBitmap == null)
vmr9mixerBitmap = (IVMRMixerBitmap9)vmr9;
// Set Alpha Bitmap Parameters for using a Direct3D surface
alphaBmp = new VMR9AlphaBitmap();
alphaBmp.dwFlags = VMR9AlphaBitmapFlags.EntireDDS;
alphaBmp.pDDS = unmanagedSurface;
alphaBmp.rDest = GetDestRectangle();
alphaBmp.fAlpha = 1.0f;
// Set Alpha Bitmap Parameters
hr = vmr9mixerBitmap.SetAlphaBitmap(ref alphaBmp);
DsError.ThrowExceptionForHR(hr);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
そして、これが更新イベントを待つスレッドです。
Thread overlayupdatethreadhandle = new Thread(new ThreadStart(overlayupdatethread));
overlayupdatethreadhandle.Start();
private void overlayupdatethread()
{
do
{
overlayupdateeventhandle.WaitOne();
ShowHideBitmap(GlobalVar.m_ShowOverlay);
} while (true);
}
バックグラウンドで100ミリ秒間隔で実行されていたタイマーを使用して、このオーバーレイを更新しようとしました。タイマーの使用はうまく機能していましたが、この操作ではタイマーの使用は不適切です。だから私はスレッドの概念で動いた。
スレッドからの呼び出し中にインターフェイスの取得に失敗し、メニュー オプションから呼び出したときにうまく機能するのはなぜですか? 特別な世話をする必要がありますか?パラメータ化されたスレッドも試しましたが、うまくいきません。
よろしくお願いします。
編集: ShowHideBitmap がメイン スレッドから呼び出された場合、すべて正常に動作します。ワーカー スレッドから ShowHideBitmap が呼び出されると、COM オブジェクトは Exception を作成します。このクロススレッド操作を処理する方法は?