8

嗨 Stack Overflow 成员,

我是 C# 编程的新手。我正在开发一个基本的相机流和仍然捕捉应用程序。一旦用户静止不动,我将使用 VMR9 的位图混合概念在叠加层上显示它。

我做了什么?

  • 我从这里使用 C# 直接显示库
  • 首先,我得到所有必需的过滤器接口。找到附加的捕获设备。调用带有源过滤器的渲染流和用于 PREVIEW 引脚的 vmr9。STILL PIN 的源过滤器、样本采集器和空渲染器。
  • 我有三个菜单按钮-> 静止,显示覆盖和隐藏覆盖。
  • 我正在使用该库中提供的位图混合器示例。
  • 每次用户按下 Take Still 菜单时,图像将保存在桌面中,并将重新调整为小分辨率并显示在视频叠加层上。
  • Show Overlay 和 hide Overlay 调用 ShowHideBitmap() 执行从 vmr9 过滤器查询 VMR9BitmapMixer 接口的操作,填充 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 毫秒间隔运行的计时器来更新此叠加层。使用 timer 效果很好,但对于这个操作,使用 timer 是一个不好的选择。所以我用线程概念移动。

为什么从线程调用时获取接口失败,而从菜单选项调用时效果很好?我应该照顾任何特殊的事情吗?我什至尝试过参数化线程,但没有运气。

在此先感谢您的帮助。

编辑:如果从主线程调用 ShowHideBitmap,则一切正常。如果从工作线程调用 ShowHideBitmap,COM 对象会创建异常。如何处理这种跨线程操作?

4

2 回答 2

4

例外情况很糟糕,在 COM 中并不少见。它的真正含义是“我不知道如何为您提供可以从工作线程中使用的接口引用”。这是一种常见的事故,这些 COM 组件根本不是线程安全的。他们通过处理它,自动将来自工作线程的调用编组到所有者线程来强制执行这一点。或者根本不让您从另一个线程使用它们,因为编组将毫无意义,使其太慢。VMR 属于后一类。

这与 .NET 非常不同,它还有很多完全线程不安全的类。基本的东西,例如,没有一个集合类。但是它允许你在一个线程中使用这些类,让你来确保它是线程安全的。当然,这经常出错,使用适当的锁定是一项技能。

COM 在设计上一直是线程感知的。由于线程很难正确处理,因此应该由聪明的人来处理。这在 95% 的时间里都非常有效。并且在剩下的时间里给你一个严重的偏头痛。当 COM 处理线程时,由于难以诊断性能不佳而引起的偏头痛。当它没有时,糟糕的错误报告。

好吧,没办法,您确实必须从创建 VMR 实例的同一线程中使用该接口。没办法。

于 2013-03-27T13:51:07.220 回答
2

尝试使用 Delphi 库中的侦听器/事件处理程序对象时出现错误 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);
    });
}

如果在不同的线程中调用侦听器,则没有分派器,它将产生错误

于 2014-01-08T13:03:22.977 回答