第四篇 DirectShow 采集调用结构关系

第一篇: DirectShow视频采集_会头痛的可达鸭的博客-CSDN博客

一、GraphBuilder

1、IFilterGraph2、IGraphBuilder、ICaptureGraphBuiler2

(1)、CLSID

IFilterGraph           CLSID_FilterGraphIFilterGraph2          CLSID_CaptureGraphBuilderIGraphBuilder          CLSID_CaptureGraphBuilderICaptureGraphBuiler2   CLSID_CaptureGraphBuilder2

(2)、IFilterGraph2还有一个IFilterGraph,IFilterGraph3.

继承关系:

IFilterGraph——>IGraphBuilder——>IFilterGraph2——>IFilterGraph3

(3)、如果仅仅只需要预览 USB Video, 可以只使用IFilterGraph2

通过

pFilterGraph2->AddSourceFilterForMoniker()

用Moniker指针将filter添加到graph,则不必创建IcaptureGraphBuiler2这个接口。

如果需要需要视频流,则需要使用IFilterGraph

ICaptureGraphBuilder2->SetFiltergraph(IFilterGraph)

(4)、ICaptureGraphBuiler2是一个专门用来进行视频,音频捕捉的增强型接口;如果要特别的编解码,用它就很方便

创建了IcaptureGraphBuiler2,仍然需要创建IGraphBuilder ​ 因为在预览视频时处理播放,暂停,停止这些动作,需要用到IGraphBuilder,而这些功能IcaptureGraphBuiler2 ​ 是没有的,所以需要而这协调处理。 ​ IcaptureGraphBuiler2创建后,要将IGraphBuilder的指针与他关联:

pCaptureGraphBuiler2->captureGraphBuiler2(pGraphBuilder).

2、绑定并获取基础过滤器

// 写法1: 将视频设备绑定到基础过滤器上
IBaseFilter* GetDeviceFilter(const char* deviceUniqueIdUTF8,char* productUniqueIdUTF8,uint32_t productUniqueIdUTF8Length) 
{const int32_t deviceUniqueIdUTF8Length = (int32_t)strlen((char*)deviceUniqueIdUTF8);  // UTF8 is also NULL terminatedif (deviceUniqueIdUTF8Length >= kVideoCaptureUniqueNameLength) {RTC_LOG(LS_INFO) << "Device name too long";return NULL;}
​// enumerate all video capture devicesRELEASE_AND_CLEAR(_dsMonikerDevEnum);HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&_dsMonikerDevEnum, 0);if (hr != NOERROR) {RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"<< rtc::ToHex(hr) << ". No webcam exist?";return 0;}_dsMonikerDevEnum->Reset();ULONG cFetched;IMoniker* pM;
​IBaseFilter* captureFilter = NULL;bool deviceFound = false;while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound) {IPropertyBag* pBag;hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);if (S_OK == hr) {// Find the description or friendly name.VARIANT varName;VariantInit(&varName);if (deviceUniqueIdUTF8Length > 0) {hr = pBag->Read(L"DevicePath", &varName, 0);if (FAILED(hr)) {hr = pBag->Read(L"Description", &varName, 0);if (FAILED(hr)) {hr = pBag->Read(L"FriendlyName", &varName, 0);}}if (SUCCEEDED(hr)) {char tempDevicePathUTF8[256];tempDevicePathUTF8[0] = 0;WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,tempDevicePathUTF8, sizeof(tempDevicePathUTF8),NULL, NULL);if (strncmp(tempDevicePathUTF8, (const char*)deviceUniqueIdUTF8,deviceUniqueIdUTF8Length) == 0) {// We have found the requested devicedeviceFound = true;hr = pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&captureFilter);if(FAILED(hr)){RTC_LOG(LS_ERROR) << "Failed to bind to the selected ""capture device " << hr;}
​if (productUniqueIdUTF8 &&productUniqueIdUTF8Length > 0)  // Get the device name{GetProductId(deviceUniqueIdUTF8, productUniqueIdUTF8,productUniqueIdUTF8Length);}}}}VariantClear(&varName);pBag->Release();}pM->Release();}return captureFilter;
}
​
//写法2:枚举设备并绑定设备
BOOL BindToVideoDev(int deviceId, IBaseFilter **pFilter)
{if (deviceId < 0){return FALSE;}CComPtr<ICreateDevEnum> pCreateDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void**)&pCreateDevEnum);if (hr != NOERROR){//ERR_DEBUG("Instance DeviceEnum Failed");return FALSE;}CComPtr<IEnumMoniker> pEm;hr = pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,&pEm, 0);if (hr != NOERROR){//ERR_DEBUG("Enum VideoInputDeviceCategory Failed");return FALSE;}pEm->Reset();ULONG cFetched;IMoniker *pM=NULL;
​int index = 0;while((( pEm->Next(1, &pM, &cFetched))==S_OK)&&( index <= deviceId)){IPropertyBag *pBag=NULL;if (pM==NULL){break;}hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pBag);if(pBag!=NULL) {VARIANT var;var.vt = VT_BSTR;hr = pBag->Read(L"FriendlyName", &var, NULL);if (hr == NOERROR) {if (index == deviceId){//将视频设备绑定到基础过滤器上pM->BindToObject(0, 0, IID_IBaseFilter, (void**)pFilter);}SysFreeString(var.bstrVal);pBag->Release();}}pM->Release();index++;}return TRUE;
}
// 添加到过滤器
// AddFilter调用过滤器的IBaseFilter::JoinFilterGraph方法来通知过滤器它已被添加
// AddFilter必须在尝试使用IGraphBuilder::Connect、IFilterGraph::ConnectDirect或IGraphBuilder::Render
// 方法连接或渲染属于添加的过滤器的引脚之前调用
IFilterGraph->AddFilter(IBaseFilter, "name");
// 获取InputPin
IPin* GetInputPin(IBaseFilter* filter)
{IPin* pin = NULL;IEnumPins* pPinEnum = NULL;filter->EnumPins(&pPinEnum);if (pPinEnum == NULL) {return NULL;}// get first unconnected pinpPinEnum->Reset();  // set to first pin
​while (S_OK == pPinEnum->Next(1, &pin, NULL)) {PIN_DIRECTION pPinDir;pin->QueryDirection(&pPinDir);if (PINDIR_INPUT == pPinDir)  // This is an input pin{IPin* tempPin = NULL;if (S_OK != pin->ConnectedTo(&tempPin))  // The pint is not connected{pPinEnum->Release();return pin;}}pin->Release();}pPinEnum->Release();return NULL;
}

3、设置采集的分辨率

HRESULT SetVideoSize(int nPreview,CString strRGBBytes,int nFrameRate,int iWidth , int iHeight)
{HRESULT hr=E_FAIL;if(m_pCaptureGraphBulid==NULL)return hr;
​IAMStreamConfig *pAMStreamConfig=NULL;if(nPreview==0){hr = m_pCaptureGraphBulid->FindInterface(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,m_pBaseFilter,IID_IAMStreamConfig,(void **)&pAMStreamConfig);}else{hr = m_pCaptureGraphBulid->FindInterface(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Video,m_pBaseFilter,IID_IAMStreamConfig,(void **)&pAMStreamConfig);}
​if(FAILED( hr )){SAFE_RELEASE(pAMStreamConfig);return hr;}//得到视频格式大小AM_MEDIA_TYPE *pmt;pAMStreamConfig->GetFormat(&pmt);
​//设置视频格式pmt->majortype = MEDIATYPE_Video;pmt->subtype  = GetMediaTypeGuid(strRGBBytes);
​
​VIDEOINFOHEADER *pvih = reinterpret_cast<VIDEOINFOHEADER *>(pmt->pbFormat);//设置回去int nDefualWidth = pvih->bmiHeader.biWidth;int nDefualHeight = pvih->bmiHeader.biHeight;
​pvih->bmiHeader.biWidth = iWidth; pvih->bmiHeader.biHeight = iHeight;pvih->bmiHeader.biSizeImage = pmt->lSampleSize = iWidth*iHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;pvih->AvgTimePerFrame = (LONGLONG)(10000000/nFrameRate);
​hr = pAMStreamConfig->SetFormat(pmt);if(FAILED(hr)){//如果设置失败可以选用默认的,但运用之后,小屏幕初始化时会出现闪动的情况   pvih->bmiHeader.biWidth = nDefualWidth; pvih->bmiHeader.biHeight = nDefualHeight;pvih->bmiHeader.biSizeImage = pmt->lSampleSize = nDefualWidth*nDefualHeight*pvih->bmiHeader.biPlanes*pvih->bmiHeader.biBitCount/8;hr = pAMStreamConfig->SetFormat(pmt);if(FAILED(hr)){SAFE_RELEASE(pAMStreamConfig);FreeMediaType(*pmt);//ERR_DEBUG("初始化设置视频格式失败");return hr;}}SAFE_RELEASE(pAMStreamConfig);FreeMediaType(*pmt);//return hr;
}

4、流程

(1)、创建CLSID_FilterGraph---- CoCreateInstance--- IFilterGraph

(2)、创建IID_IMediaControl --- IFilterGraph->QueryInterface --- IMediaControl

(3)、获取并连接:IBaseFilter---GetDeviceFilter---BindToObject

IFilterGraph->AddFilter(IBaseFilter, L"VideoCaptureFilter")

(4)、创建自定义的IBaseFilter(成员有IPin)---CaptureSinkFilter

IFilterGraph->AddFilter(CaptureSinkFilter)

(5)、获取InputPin,通过自定义的CaptureSinkFilter,并连接CaptureInputPin::ConnectedTo

(6)、连接OutputPin和InputPin(直接连接两个引脚, 无需中间滤波器)

IFilterGraph->ConnectDirect(OutputPin, InputPin, NULL)

三、VideoCaptureDS

1、初始化

// 基类: VideoCaptureImpl
VideoCaptureDS :public VideoCaptureImpl
// 初始化并且创建:
// IBaseFilter          DirectShow主要过滤器     
// IGraphBuilder        DirectShow图形生成器
// IMediaControl        DirectShow媒体控制器
// CaptureSinkFilter
// IPin
VideoCaptureDS::Init  

2、CaptureSinkFilter

// 基类
// 创建 CaptureInputPin
CaptureSinkFilter : public IBaseFilter 

3、CaptureInputPin

// Input Pin--->camera input
// 负责绑定: receive_pin 和 媒体类型
// 接受视频数据发送给observer
class CaptureInputPin : public IMemInputPin, public IPin 

4、DeviceInfoDS

// 主要提供设备能力、获取设备信息、获取Filter
DeviceInfoDS : public DeviceInfoImpl

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/68557.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零碎的C++

构造函数和析构函数 构造函数不能是虚函数&#xff0c;而析构函数可以是虚函数。原因如下&#xff1a; 构造函数不能是虚函数&#xff0c;因为在执行构造函数时&#xff0c;对象还没有完全创建&#xff0c;还没有分配内存空间&#xff0c;也没有初始化虚函数表指针。如果构造…

Jetsonnano B01 笔记1:基础理解—网络配置—远程连接

今日开始学习 Jetsonnano B01&#xff0c;这是一台小电脑&#xff0c;可以用来&#xff1a; 运行现代 AI 负载&#xff0c;并行运行多个神经网络&#xff0c;以及同时处理来自多个高清传感器的数据&#xff0c;可广泛应用与图像分类、对象检测、图像分割、语音处 理等领域。它…

【python爬虫】15.Scrapy框架实战(热门职位爬取)

文章目录 前言明确目标分析过程企业排行榜的公司信息公司详情页面的招聘信息 代码实现创建项目定义item 创建和编写爬虫文件存储文件修改设置 代码实操总结 前言 上一关&#xff0c;我们学习了Scrapy框架&#xff0c;知道了Scrapy爬虫公司的结构和工作原理。 在Scrapy爬虫公司…

配置本地maven

安装maven安装包 修改环境变量 vim ~/.bash_profile export JMETER_HOME/Users/yyyyjinying/apache-jmeter-5.4.1 export GOROOT/usr/local/go export GOPATH/Users/yyyyjinying/demo-file/git/backend/go export GROOVY_HOME/Users/yyyyjinying/sortware/groovy-4.0.14 exp…

手写Mybatis:第10章-使用策略模式,调用参数处理器

文章目录 一、目标&#xff1a;参数处理器二、设计&#xff1a;参数处理器三、实现&#xff1a;参数处理器3.1 工程结构3.2 参数处理器关系图3.3 入参数校准3.4 参数策略处理器3.4.1 JDBC枚举类型修改3.4.2 类型处理器接口3.4.3 模板模式&#xff1a;类型处理器抽象基类3.4.4 类…

linux 进程隔离Namespace 学习

一、linux namespace 介绍 1.1、概念 Linux Namespace是Linux内核提供的一种机制&#xff0c;它用于隔离不同进程的资源视图&#xff0c;使得每个进程都拥有独立的资源空间&#xff0c;从而实现进程之间的隔离和资源管理。 Linux Namespace的设计目标是为了解决多个进程之间…

微服务设计和高并发实践

文章目录 1、微服务的设计原则1.1、服务拆分方法1.2、微服务的设计原则1.3、微服务架构 2、高并发系统的一些优化经验2.1、提高性能2.1.1、数据库优化2.1.2、使用缓存2.1.3、服务调用优化2.1.4、动静分离2.1.5、数据库读写分离 2.2、服务高可用2.2.1、限流和服务降级2.2.2、隔离…

C语言插入排序

前言&#xff1a; 本文主要讲解插入排序中的直接插入排序和希尔排序。 1、直接插入排序&#xff1a; 1.1基本思想 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是把待排序的数值按照大小顺序逐个插入到一个已经排好序的有序序列中&#xff0c;直到将所有记录…

Spring Cloud--从零开始搭建微服务基础环境【四】

&#x1f600;前言 本篇博文是关于Spring Cloud–从零开始搭建微服务基础环境【四】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;…

QT day5

服务器&#xff1a; #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//给服务器指针实例化对象server new QTcpServer(this); }Widget::~Widget() {delete ui…

Java“牵手”京东商品评论数据接口方法,京东商品评论接口,京东商品评价接口,行业数据监测,京东API实现批量商品评论内容数据抓取示例

京东平台商品评论数据接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片、评论内容、评论日期、评论图片、追评内容等详细信息 。 获取商品评论接口API是一种用于获取…

el-select 加多选框使用

解决方法&#xff1a; el-select 添加属性 multiple&#xff0c; <el-form-item label"订单来源&#xff1a;"><el-selectv-model"tableFrom.userType"clearablemultipleplaceholder"请选择"class"selWidth"><el-opt…

LeetCode-53-最大子数组和-贪心算法

贪心算法理论基础&#xff1a; 局部最优推全局最优 贪心无套路~ 没有什么规律~ 重点&#xff1a;每个阶段的局部最优是什么&#xff1f; 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#…

Python AttributeError: module ‘distutils‘ has no attribute ‘version‘

1, 问题 在安装或运行使用 PyTorch 的 Python 代码时&#xff0c;您可能会看到一个错误: AttributeError: module distutils has no attribute version本文将帮助您理解发生此错误的原因以及如何解决此错误。 2&#xff0c;为什么 AttributeError: module ‘distutils’ has…

开发工具——IDE安装 / IDEA子module依赖导入失败编译提示xx找不到符号 / IDEA在Git提交时卡顿

近期换了工作电脑&#xff0c;公司的IT团队不够给力&#xff0c;不能复制电脑系统&#xff0c;所以又到了需要重装IDE配置开发环境的时候了&#xff1b;在安装和导入Java编译器IDEA的时候遇到一些"棘手"问题&#xff0c;这里整理下解决方法以备不时之需&#xff1b; …

【python爬虫】16.爬虫知识点总结复习

文章目录 前言爬虫总复习工具解析与提取&#xff08;一&#xff09;解析与提取&#xff08;二&#xff09;更厉害的请求存储更多的爬虫更强大的爬虫——框架给爬虫加上翅膀 爬虫进阶路线指引解析与提取 存储数据分析与可视化更多的爬虫更强大的爬虫——框架项目训练 反爬虫应对…

Linux的命令

Linux的命令分为四个类型&#xff1a;文件操作命令、系统操作命令、文本处理命令和网络操作命令。下面简单介绍一下常用的Linux命令&#xff1a; 文件操作命令 ls&#xff1a;列出目录下的所有文件和目录。 cd&#xff1a;切换当前目录。 mkdir&#xff1a;创建一个新目录。…

Linux系统的安装

文章目录 1 Linux介绍1.1 Linux是什么1.2 Linux的特点1.3 Linux的应用1.4 Linux的发行版本1.5 Linux的Shell 2 Linux安装2.1 安装方式2.2 什么是VMware2.3 VMware主要功能2.4 什么是CentOS2.5 VMware与CentOS与Linux的关系2.6 VMware安装CentOS的步骤 1 Linux介绍 1.1 Linux是…

Jenkins详解(三)

Jenkins详解(三) 目录 Jenkins详解(三) 1、Jenkins介绍2、Jenkins CI/CD 流程3、部署环境 3.1 环境准备3.2 安装GitLab3.3 初始化GitLab3.4 GitLab中文社区版补丁包安装3.5 修改GitLab配置文件/etc/gitlab/gitlab.rb3.6 在宿主机输入 http://192.168.200.26:88 地址就可以访问了…

【网络安全带你练爬虫-100练】第22练:数据包中参数提取与处理

目录 一、目标1&#xff1a;GET数据包的处理 1、GET数据包中参数的提取 2、GET请求中 统计参数个数 二、目标2&#xff1a;POST数据包的处理 1、post中参数个数的提取 2、POST请求中 统计参数个数 一、目标1&#xff1a;GET数据包的处理 1、GET数据包中参数的提取 impo…