我有一個使用DirectShow.NET的攝像頭控件。我創建了一個自定義控件來顯示視頻並從網絡攝像頭捕捉圖像。我在另一個WPF窗口中使用該自定義控件。我在自定義控件中有一個函數public Bitmap CaptureImage()
來抽象出一點DirectShow編程,並簡單地返回一個Bitmap
。由於圖像相對較大(1920x1080),IVMRWindowlessControl9
的GetCurrentImage()
功能需要相當長的時間來處理(2-3秒)。我已經瀏覽了我的代碼,可以確認此調用是唯一需要很長時間才能處理的調用。在後臺運行IVMRWindowlessControl9.GetCurrentImage()
因此,我的主WPF窗口中的GUI線程掛起,導致它幾秒鐘無響應,所以如果我想在捕獲圖像時顯示進度微調器,它將保持凍結狀態。
這裏是CaptureImage()
代碼:
public Bitmap CaptureImage()
{
if (!IsCapturing)
return null;
this.mediaControl.Stop();
IntPtr currentImage = IntPtr.Zero;
Bitmap bmp = null;
try
{
int hr = this.windowlessControl.GetCurrentImage(out currentImage);
DsError.ThrowExceptionForHR(hr);
if (currentImage != IntPtr.Zero)
{
BitmapInfoHeader bih = new BitmapInfoHeader();
Marshal.PtrToStructure(currentImage, bih);
...
// Irrelevant code removed
...
bmp = new Bitmap(bih.Width, bih.Height, stride, pixelFormat, new IntPtr(currentImage.ToInt64() + Marshal.SizeOf(bih)));
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
}
}
catch (Exception ex)
{
MessageBox.Show("Failed to capture image:" + ex.Message);
}
finally
{
Marshal.FreeCoTaskMem(currentImage);
}
return bmp;
}
爲了解決這個問題,我試圖如下運行此作爲後臺任務:
public async void CaptureImageAsync()
{
try
{
await Task.Run(() =>
{
CaptureImage();
});
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
我試過多次包括使用BackgroundWorker
s的方法,但似乎任何時候我異步進行此調用,都會產生此錯誤:
Unable to cast COM object of type 'DirectShowLib.VideoMixingRenderer9' to interface type 'DirectShowLib.IVMRWindowlessControl9'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{8F537D09-F85E-4414-B23B-502E54C79927}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
錯誤總是發生在這條線時:
int hr = this.windowlessControl.GetCurrentImage(out currentImage);
調用CaptureImage()
同步產生的正常結果。圖像被捕獲,一切按預期工作。但是,切換到使用任何類型的異步功能會導致該錯誤。
很好的解釋 - 你可以擴展一下「最流行但笨拙的是採樣採樣」的說法嗎?爲什麼樣本抓取方式笨拙,什麼是更好的方法? –
@Roman R.你能否提供一些關於如何爲DirectShow相關代碼實現MTA線程池的更多細節?我無法在MTA線程中打開一個WPF窗口,因爲它要求它的線程是STA。我一直在試圖實現你提到的方法,但似乎無法提出一個可行的解決方案。 –
@MikeDinescu:我認爲這超出了這個問題的範圍,我在稍後的一段時間做了一個註釋說明。 –