将程序输出传递给 DirectShow 源过滤器以供 Lync 获取?
Pass program output to a DirectShow source filter to be picked up by Lync?
目标
总的来说,我想完成以下任务:
- 从程序实时生成一系列图像
- 将图像传递到注册为捕获源的 DirectShow 源过滤器
- Select 在像 Lync
这样的程序中得到的 "virtual webcam"
图像生成已经编写,必须利用现有框架。我目前正在研究框架和 DirectShow 之间的接口。我当前传递图像的实现如下所述。
接口
COM 接口在 .idl
文件中描述,生成的 .c
/.h
文件包含在源过滤器中,并扩展为框架模块。
其他方法允许指定要支持的媒体格式并根据图像生成速率调整参数。
passImage
方法传递指向生成的图像缓冲区的指针和缓冲区的大小。当接收到要传递的新数据时,框架接收器模块会调用它。
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 源过滤器
源过滤器实现为两个 classes 和一个关联的 CLSID,它们导出为 DLL 并使用 regsvr32
注册。 DLLRegisterServer
方法被适当地实现以在 CLSID_VideoInputDeviceCategory
.
下注册 COM 对象
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);
}
注意:pin(CSourceStream
-派生class)实现了用于传递图像的接口。假设缓冲区大小协商已经建立。
passImage()
STDMETHODIMP CVSourceStream::passImage(unsigned long size, BYTE **img) {
memcpy_s(this->bufferedImg, size, *img, size);
return S_OK;
}
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;
}
问题
暂时忽略锁定和同步(我知道 FillBuffer()
应该阻塞直到数据可用),我做了以下观察。
- 将生成的缓冲区测试序列直接添加到
FillBuffer()
会导致 Lync 正确显示它们。
- 当 运行ning 我的程序时,
passImage()
行为正确并且缓冲区实例变量接收到正确的数据。但是,FillBuffer()
似乎在调试时从未被调用。
根据我所做的研究,我的问题似乎是两个不同的进程(我的框架程序和 Lync)在源代码中不共享相同的 data由于创建了两个单独的过滤器图实例,过滤器 DLL。
Lync 的过滤器图实例与我的程序正在存储的图像共享数据的最简洁方法是什么?我看到 "inter-process communication" 被扔来扔去。虽然我不熟悉这个概念,但为了实现我的目标(管道、套接字、共享内存、注册表等),我需要采取哪些明确的步骤列表?
链接
A similar discussion on the MSDN forums.
有人讨论了与我所讨论的类似的问题,但没有足够具体的细节,我不想 post 在旧线程上讨论。
A similar question on stack overflow.
这实际上与我已有的非常相似。但是,我需要 运行 一个可能会创建自己的过滤器图的新应用程序。
您必须在进程之间传递数据:Lync 将始终在其进程中使用筛选器,而不询问从何处获取数据。并且由于它应该从外部进程获取数据,因此它必须处理进程间通信和 "somehow connect" 到数据来自的远程进程。
有一些选项可以让您准确地实现这个 "somehow"。我更喜欢使用内存映射文件和 events/mutexes 进行同步。生产者进程生成数据并将它们存储在 MMF 中,然后 Lync 进程中的消费者过滤器读取这些数据并作为生成的视频提供。
目标
总的来说,我想完成以下任务:
- 从程序实时生成一系列图像
- 将图像传递到注册为捕获源的 DirectShow 源过滤器
- Select 在像 Lync 这样的程序中得到的 "virtual webcam"
图像生成已经编写,必须利用现有框架。我目前正在研究框架和 DirectShow 之间的接口。我当前传递图像的实现如下所述。
接口
COM 接口在 .idl
文件中描述,生成的 .c
/.h
文件包含在源过滤器中,并扩展为框架模块。
其他方法允许指定要支持的媒体格式并根据图像生成速率调整参数。
passImage
方法传递指向生成的图像缓冲区的指针和缓冲区的大小。当接收到要传递的新数据时,框架接收器模块会调用它。
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 源过滤器
源过滤器实现为两个 classes 和一个关联的 CLSID,它们导出为 DLL 并使用 regsvr32
注册。 DLLRegisterServer
方法被适当地实现以在 CLSID_VideoInputDeviceCategory
.
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);
}
注意:pin(CSourceStream
-派生class)实现了用于传递图像的接口。假设缓冲区大小协商已经建立。
passImage()
STDMETHODIMP CVSourceStream::passImage(unsigned long size, BYTE **img) {
memcpy_s(this->bufferedImg, size, *img, size);
return S_OK;
}
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;
}
问题
暂时忽略锁定和同步(我知道 FillBuffer()
应该阻塞直到数据可用),我做了以下观察。
- 将生成的缓冲区测试序列直接添加到
FillBuffer()
会导致 Lync 正确显示它们。 - 当 运行ning 我的程序时,
passImage()
行为正确并且缓冲区实例变量接收到正确的数据。但是,FillBuffer()
似乎在调试时从未被调用。
根据我所做的研究,我的问题似乎是两个不同的进程(我的框架程序和 Lync)在源代码中不共享相同的 data由于创建了两个单独的过滤器图实例,过滤器 DLL。
Lync 的过滤器图实例与我的程序正在存储的图像共享数据的最简洁方法是什么?我看到 "inter-process communication" 被扔来扔去。虽然我不熟悉这个概念,但为了实现我的目标(管道、套接字、共享内存、注册表等),我需要采取哪些明确的步骤列表?
链接
A similar discussion on the MSDN forums.
有人讨论了与我所讨论的类似的问题,但没有足够具体的细节,我不想 post 在旧线程上讨论。
A similar question on stack overflow.
这实际上与我已有的非常相似。但是,我需要 运行 一个可能会创建自己的过滤器图的新应用程序。
您必须在进程之间传递数据:Lync 将始终在其进程中使用筛选器,而不询问从何处获取数据。并且由于它应该从外部进程获取数据,因此它必须处理进程间通信和 "somehow connect" 到数据来自的远程进程。
有一些选项可以让您准确地实现这个 "somehow"。我更喜欢使用内存映射文件和 events/mutexes 进行同步。生产者进程生成数据并将它们存储在 MMF 中,然后 Lync 进程中的消费者过滤器读取这些数据并作为生成的视频提供。