Hi Stack Overflow成员,
我是C#编程的新手。我正在开发基本的相机流媒体并仍然捕捉应用程序。一旦用户静止不动,我将使用VMR9的位图混合概念在叠加层上显示它。
我做了什么?
我面临什么问题?
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。如何处理这种跨线程操作?
答案 0 :(得分:4)
异常是乱的,在COM中并不罕见。它的真正含义是“我不知道如何为您提供一个可以在工作线程中使用的接口引用”。这是一种常见的事故,这些COM组件根本就不是线程安全的。并且他们通过处理它来强制执行,将工作线程中的调用自动编组到所有者线程。或者根本不让你从另一个线程中使用它们,因为编组将毫无意义,使其变得太慢。 VMR属于后一类。
这与.NET非常不同,它还有一个很多类完全不符合线程的类。基本的东西,例如,没有集合类。但是它允许你在一个线程中使用这些类,让你自己使它成为线程安全的。这当然经常出错,使用正确的锁定是一种技巧。
COM一直是设计中的线程感知。由于线程很难做到正确的理念所以应该由聪明的人来照顾。其中95%的时间都是如此。并在剩下的时间给你一个主要的偏头痛。当COM负责穿线时,由难以诊断的差导致诱发的偏头痛类型。如果没有,那就是糟糕的错误报告。
嗯,没法,你真的必须从创建VMR实例的同一个线程中使用该接口。没办法。
答案 1 :(得分:1)
在尝试使用Delphi库中的Listener / Event处理程序对象时,我遇到了错误E_NOINTERFACE。解决编组和编组的问题不同的线程我保存了分配监听器的线程调度程序,然后使用它来触发事件。
接口:
[ComVisible(true)]
[Guid("2FFC2C20-A27B-4D67-AEA3-350223D3655F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDataSystemInterfaceEventListener
{
void OnIntializeCompleted(int status);
void OnTerminateCompleted(int status);
void OnRunCompleted(int status);
}
[ComVisible(true)]
[Guid("B9953413-A8C9-4CE2-9263-B488CA02E7EC")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDataSystemInterface
{
void Intialize(string config);
void StartRun(string conditions);
void StopRun();
void Terminate();
IDataSystemInterfaceEventListener Listener { get; set; }
}
然后实现(通知Dispatcher.CurrentDispatcher存储)
[ComVisible(true)]
[Guid("0818F830-DA37-4167-BF31-3A2C55A9BF2B")]
public class DataSystemModule : IDataSystemInterface
{
private Dispatcher m_dispatcherListener = null;
private IDataSystemInterfaceEventListener m_listener = null;
public IDataSystemInterfaceEventListener Listener
{
get
{
return m_listener;
}
set
{
m_dispatcherListener = Dispatcher.CurrentDispatcher;
m_listener = value;
}
}
}
然后在代码中:
if (Listener != null)
{
m_dispatcherListener.Invoke((Action)delegate()
{
Listener.OnTerminateCompleted((int)TerminateStatus.Completed);
});
}
如果在不同的线程中调用Listener,它将产生错误