将程序输出传递给DirectShow源过滤器以供Lync选取?

时间:2022-06-13 17:18:05

Goal

Broadly, I want to accomplish the following:

从广义上讲,我想完成以下工作:

  1. Generate a series of images in real-time from a program
  2. 从程序实时生成一系列图像
  3. Pass the images to a DirectShow source filter, which is registered as a capture source
  4. 将图像传递给DirectShow源过滤器,该过滤器已注册为捕获源
  5. Select the resulting "virtual webcam" in a program like Lync
  6. 在Lync等程序中选择生成的“虚拟网络摄像头”

The image generation is already written and must leverage an existing framework. I am currently working on the interface between the framework and DirectShow. My current implementation for passing the images is described below.

图像生成已经编写,必须利用现有框架。我目前正在研究框架和DirectShow之间的接口。我目前用于传递图像的实现如下所述。

Interfacing

A COM interface is described in an .idl file, and the generated .c/.h files are included in the source filter and, by extension, the framework module.

在.idl文件中描述了COM接口,生成的.c / .h文件包含在源过滤器中,并且通过扩展包含在框架模块中。

Additional methods allow for specifying a media format to support and tuning parameters based on the rate of image generation.

其他方法允许指定媒体格式以基于图像生成速率支持和调整参数。

The passImage method passes a pointer to a generated image buffer and the size of the buffer. This is called by a framework sink module when it receives new data to pass.

passImage方法将指针传递给生成的图像缓冲区和缓冲区的大小。当接收要传递的新数据时,框架接收器模块会调用此方法。

MyInterface.idl

MyInterface.idl

[
object,
uuid("46B4BD3C-CD67-4158-BB83-89EA95306A4D"),
] interface IExtLiveSrc : IUnknown
{
    ...
    HRESULT passImage
    (
        [in] unsigned long size,
        [in, size_is(size)] BYTE **img
    );
};

DirectShow Source Filter

The source filter is implemented as two classes and an associated CLSID that are exported as a DLL and registered using regsvr32. The DLLRegisterServer method is implemented appropriately to register the COM object under CLSID_VideoInputDeviceCategory.

源过滤器实现为两个类和一个关联的CLSID,它们作为DLL导出并使用regsvr32注册。适当地实现DLLRegisterServer方法以在CLSID_VideoInputDeviceCategory下注册COM对象。

MyFilter.h

MyFilter.h

class CVSource : public CSource {
    static CUnknown *WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
    // private constructor
}

class CVSourceStream : public CSourceStream
    , public virtual IKsPropertySet
    , public virtual IAMStreamConfig
    , public virtual IExtLiveSrc
{
    // constructor, IUnknown, IKsPropertySet, IAMStreamConfig methods
    ...
    HRESULT FillBuffer(IMediaSample *pms);
    STDMETHODIMP passImage(unsigned long size, BYTE **img);
}

Note: the pin (CSourceStream-derived class) implements the interface used to pass images. Assume that buffer size negotiation has already been established.

注意:pin(CSourceStream派生类)实现用于传递图像的接口。假设已经建立了缓冲区大小协商。

passImage()

passImage()

STDMETHODIMP CVSourceStream::passImage(unsigned long size, BYTE **img) {
    memcpy_s(this->bufferedImg, size, *img, size);
    return S_OK;
}    

FillBuffer()

FillBuffer()

HRESULT CVSourceStream::FillBuffer(IMediaSample *pms) {
    // Set timestamp on IMediaSample instance
    ...
    BYTE *pData;
    pms->GetPointer(&pData);
    long lDataLen = pms->GetSize();
    memcpy_s(pData, lDataLen, this->bufferedImg, lDataLen);
    return S_OK;
}

Question

Ignoring locking and synchronization for the moment (I know that FillBuffer() should block until data is available), I've made the following observations.

暂时忽略锁定和同步(我知道FillBuffer()应该阻塞,直到数据可用),我做了以下观察。

  • Adding a generated test sequence of buffers directly to FillBuffer() leads to Lync correctly displaying them.
  • 将生成的缓冲区测试序列直接添加到FillBuffer()会导致Lync正确显示它们。
  • When running my program, passImage() behaves correctly and the buffer instance variable receives the correct data. However, FillBuffer() never seems to be called when debugging.
  • 运行我的程序时,passImage()行为正常,缓冲区实例变量接收正确的数据。但是,调试时似乎永远不会调用FillBuffer()。

Based on research I've done, it appears my issue is that the two different processes (my framework program and Lync) don't share the same data in the source filter DLL due to creating two separate instances of the filter graph.

基于我已经完成的研究,我的问题似乎是由于创建了两个独立的过滤器图实例,两个不同的进程(我的框架程序和Lync)在源过滤器DLL中不共享相同的数据。

What is the cleanest way for Lync's instance of the filter graph to share data with the images my program is despositing? I've seen "inter-process communication" tossed around. Though I'm not familiar with the concept, what would be a clear list of steps I would need to take towards my goal (pipes, sockets, shared memory, registry, etc.)?

Lync的过滤器图实例与我的程序所述的图像共享数据的最简洁方法是什么?我看到“进程间通信”被抛到了一边。虽然我不熟悉这个概念,但是我需要采取哪些步骤(管道,套接字,共享内存,注册表等)?

Links

A similar discussion on the MSDN forums.

在MSDN论坛上进行类似的讨论。

There's discussion of a similar problem to what I have but not enough concrete details, and I don't want to post on an old thread.

有一个类似问题的讨论,但我没有足够的具体细节,我不想发布一个旧的线程。

A similar question on stack overflow.

关于堆栈溢出的类似问题。

This is actually quite similar to what I already have. However, I need to run a new application that presumably creates its own filter graph.

这实际上与我已经拥有的非常相似。但是,我需要运行一个新的应用程序,可能会创建自己的过滤器图形。

1 个解决方案

#1


1  

You have to pass data between processes: Lync will always use the filter in its process, without asking where it takes data from. And since it is supposed to take data from external process, it has to deal with interprocess communication and "somehow connect" to remote process where the data comes from.

您必须在进程之间传递数据:Lync将始终在其进程中使用筛选器,而不会询问从何处获取数据。由于它应该从外部进程获取数据,因此它必须处理进程间通信并“以某种方式连接”到数据来自的远程进程。

There are options how you can implement this "somehow" exactly. I would prefer using memory mapped files and events/mutexes for synchronization. Producer process generates data and stores them in MMF, then consumer filter inside Lync processes reads this and delivers as generated video.

有些选项可以完全按照“某种方式”实现。我更喜欢使用内存映射文件和事件/互斥体进行同步。生产者进程生成数据并将其存储在MMF中,然后Lync进程内的使用者筛选器读取此数据并将其作为生成的视频传递。

#1


1  

You have to pass data between processes: Lync will always use the filter in its process, without asking where it takes data from. And since it is supposed to take data from external process, it has to deal with interprocess communication and "somehow connect" to remote process where the data comes from.

您必须在进程之间传递数据:Lync将始终在其进程中使用筛选器,而不会询问从何处获取数据。由于它应该从外部进程获取数据,因此它必须处理进程间通信并“以某种方式连接”到数据来自的远程进程。

There are options how you can implement this "somehow" exactly. I would prefer using memory mapped files and events/mutexes for synchronization. Producer process generates data and stores them in MMF, then consumer filter inside Lync processes reads this and delivers as generated video.

有些选项可以完全按照“某种方式”实现。我更喜欢使用内存映射文件和事件/互斥体进行同步。生产者进程生成数据并将其存储在MMF中,然后Lync进程内的使用者筛选器读取此数据并将其作为生成的视频传递。