文档章节

将桌面捕获到虚拟摄像头

一个灰
 一个灰
发布于 2018/10/21 14:38
字数 1131
阅读 186
收藏 0

当然你可以直接用现成的虚拟摄像头软件实现这个功能。不过当初我开发这个插件的原因是,需要在Flash产品里面共享桌面,如果此时需要引导用户安装一个第三方的虚拟摄像头体验不好,所以公司希望我自己开发一个虚拟摄像头,一键安装减少用户的使用门槛。所谓的虚拟摄像头实际上在windows系统上注册了一个特殊dll,这个dll是一个COM组件。

虚拟摄像头需要用到Direct Show编程。

下载Direct Show开发代码

里面有如下的文件夹,我只需要用到第一个文件夹里面的代码—— baseclasses

baseclasses
capture
common
dmo
dvd
filters
misc
players
vmr9

创建工程

打开Visual Studio ,新建一个win32 Dll项目。 打开属性页,在VC++ 目录一栏中的库目录里面添加刚才的baseclasses的路径,这样我们就能在项目中引用这个目录里的代码了。 在C/C++属性页里面的附加库目录里面也把baseclasses的路径填入。 在dll.cpp中,我们需要把Filter注册成COM组件。 分别需要调用AMovieSetupRegisterServer函数、CreateComObject函数以及IFilterMapper2接口的RegisterFilter函数完成注册。

主逻辑

在头文件中,我们需要声明两个类

class CVCamStream;
class CVCam : public CSource
{
public:
    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);

    IFilterGraph *GetGraph() {return m_pGraph;}
	static int cx, cy;
	static HANDLE SocketThread;
	static SOCKET ClientSocket;
private:

    CVCam(LPUNKNOWN lpunk, HRESULT *phr);
};

class CVCamStream : public CSourceStream, public IAMDroppedFrames,public IAMStreamConfig, public IKsPropertySet
{
public:

COM组件只需要实现CUnknown接口即可。我们继承了Direct Show的CSource类,那么就已经实现了这个接口。 CVCamStream类用来实现图像数据的输出。 在CVCam的构造函数里面我们创建CVCamStream类的实例

m_paStreams = (CSourceStream **) new CVCamStream*[1];
m_paStreams[0] = new CVCamStream(phr, this, L"Flex COM");

在实现COM接口的QueryInterface函数中,我们调用了CVCamStream类的QueryInterface

HRESULT CVCam::QueryInterface(REFIID riid, void **ppv)
{
    //Forward request for IAMStreamConfig & IKsPropertySet to the pin
    if(riid == _uuidof(IAMStreamConfig) || 
		riid == _uuidof(IAMDroppedFrames)  ||
		riid == _uuidof(IKsPropertySet))
        return m_paStreams[0]->QueryInterface(riid, ppv);
    else
        return CSource::QueryInterface(riid, ppv);
}

定义媒体类型

HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt)

在这个函数中,我们配置了媒体的具体的格式参数,比如24位RGB格式,图像的宽高等等。 另外还需要对GetStreamCaps函数进行实现,配置媒体的格式。

HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)

捕获桌面

系统会调用FillBuffer函数,在这个函数中,我们将捕获到的数据填充到缓冲里面,Direct Show会处理剩下的事情。

HRESULT CVCamStream::FillBuffer(IMediaSample *pms)

捕获桌面只需要用到一个函数CopyScreenToBitmap

 HANDLE hDib = CopyScreenToBitmap(&ScreenRect, pData, (BITMAPINFO *)&(pVih->bmiHeader), m_hCursor);
    if (hDib)   DeleteObject(hDib);

pData是我们定义的一个指针,通过下面的代码,我们的pData就指向了缓存,数据填充到pData指向的内存中。

BYTE *pData;
pms->GetPointer(&pData);

进阶

实际产品会有很多需求,光实现捕获桌面是远远不够的,我们需要对这个捕获进行控制,比如捕获制定区域,停止捕获,恢复捕获等等。那么就涉及到和COM进行通讯了。 我们可以通过VS的窗口设计器创建一个windows窗口,然后提供一个用户操作界面。 窗口设计器 如何响应这个窗口的用户操作呢? 通过windows消息

INT_PTR CALLBACK WindowMessage(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

当然最关键是需要在Flash产品的程序里面唤起这个窗口,需要用的socket编程。

SOCKET Listen_Sock = socket(AF_INET, SOCK_STREAM, 0);
	SOCKADDR_IN serverAddr;
	ZeroMemory((char *)&serverAddr, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(1234);
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	bind(Listen_Sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	listen(Listen_Sock, 5);

C++的socket编程十分的繁琐,其他语言都会进行封装,让开发变的十分便利。 在一个线程里面写个死循环进行读取socket的数据,这是比较初级的多线程阻塞式的socket编程。对于我们这个程序是绰绰有余了。毕竟不是服务器,不需要面对并发的问题。

源码

https://github.com/langhuihui/FlexCOM

© 著作权归作者所有

一个灰
粉丝 28
博文 33
码字总数 21699
作品 3
南京
高级程序员
私信 提问
基于 Metal 的 ARKit 使用指南(上)

原文地址:Using ARKit with Metal 原文作者:Marius Horga 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:RichardLeeH 校对者:Danny1451 基于 Metal 的 ARKit 使用...

LeviDing
2017/12/02
0
0
靠人脸识别人类情绪还不够,机器人又开始学习人类的肢体语言了 | 潮科技

当你在因为机器人代替了你的工作而掩面哭泣时,机器人可能会给你递上一张纸巾。 如果你的朋友紧攥着拳头对你说她现在感觉很放松,你一定会觉得她在说谎,但机器人却会相信她说的话。我们的肢...

图普科技
2017/08/07
0
0
V4L2运行原理

Linux内核用一个被称为V4L2的机制来管理摄像头图像信息,它的核心工作原理就像日本料理店常见的流转餐桌,大厨将美食不断放到空盘子里,客人不断拿来吃。 拓展: 在内核中,摄像头所捕获的视...

林世霖
2016/03/06
0
0
五款优秀的 Linux 视频捕获工具

Webcam是一种视频捕捉设备,能通过USB端口直接连接计算机或计算机网络。新的上网本和笔记本多有内置的网络摄像头。Webcam可用于实时视频聊天和网络广播,丰富在线交流。这个小小的摄像机让用...

红薯
2010/11/08
2.7K
2
Android开发者指南-摄像头-Camera[原创译文]

Camera 版本:Android 4.0 r1 在本文中 需要考虑的问题 概述 Manifest声明 使用内置的摄像头应用程序 捕获图像的intent 捕获视频的intent 接收摄像头intent的结果 创建摄像头应用程序 检测摄...

微笑的江豚
2016/08/24
21
0

没有更多内容

加载失败,请刷新页面

加载更多

掌握生成对抗网络(GANs),召唤专属二次元老婆(老公)不是梦

全文共6706字,预计学习时长12分钟或更长 近日,《狮子王》热映,其逼真的外形,几乎可以以假乱真,让观众不禁大呼:awsl,这也太真实了吧! 实体模型、CGI动画、实景拍摄、VR等技术娴熟运用...

读芯术
29分钟前
1
0
C#经典面试题100道

1. .NET和C#有什么区别 答:.NET一般指 .NET FrameWork框架,它是一种平台,一种技术。 C#是一种编程语言,可以基于.NET平台的应用。 2.一列数的规则如下: 1、1、2、3、5、8、13、21、34......

元歌
33分钟前
0
0
重磅!容器集群监控利器 阿里云Prometheus 正式免费公测

Prometheus 作为容器生态下集群监控的首选方案,是一套开源的系统监控报警框架。它启发于 Google 的 borgmon 监控系统,并于 2015 年正式发布。2016 年,Prometheus 正式加入 Cloud Native C...

阿里云云栖社区
34分钟前
1
0
LeetCode 160: 相交链表 Intersection of Two Linked Lists

爱写Bug(ID:iCodeBugs) 编写一个程序,找到两个单链表相交的起始节点。 Write a program to find the node at which the intersection of two singly linked lists begins. 如下面的两个链...

iCodeBugs
36分钟前
2
0
hadoop yarn漏洞 8088端口进入挖矿病毒处理记录

早上发现服务器cpu使用异常 进程如图所示 按照挖矿病毒的套路 肯定是定时任务不停地执行脚本 遂查看定时任务 进入/var/spool/cron 查看定时任务 发现里面有一个root文件 定时任务每分钟执行一...

詹姆斯-高斯林
40分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部