通过Windows DShow获取设备名、支持的编解码及视频size列表实现
之前在https://blog.csdn.net/fengbingchun/article/details/102641967中介绍过通过DShow获取Camera视频的实现,即调用VideoCapture类。在OpenCV的VideoCapture类中并没有提供获取Camera设备列表、支持的编解码类型列表及支持的video size列表接口,这里基于已有的VideoCapture类增加对这些的实现。
获取Camera设备名:在videoInput类中有两个函数,一个是getDeviceCount用于获取设备数,一个是getDeviceName用于根据索引获取设备名。在CvCaputreCAM_DShow类中增加函数getDevicesList,实现如下,在此函数中调用videoInput中的getDeviceCount和getDeviceName。
bool CvCaptureCAM_DShow::getDevicesList(std::map<int, std::string>& devicelist) const
{devicelist.clear();for (int i = 0; i < VI.getDeviceCount(); ++i) {devicelist[i] = VI.getDeviceName(i);}return true;
}
增加一个对外调用的接口get_camera_names,实现如下:
bool FBC_EXPORTS get_camera_names(std::map<int, std::string>& names)
{VideoCapture capture(0);if (!capture.isOpened()) {fprintf(stderr, "fail to open capture\n");return false;}return capture.getDevicesList(names);
}
获取Camera支持的编解码类型和video size:这部分的实现参考了FFmpeg中的源码libavdevice/dshow.c,并把其中的一些code移了过来。首先在videoInput类中增加一个变量infolist,用于存放设备索引名、编解码类型、视频size信息;增加一个函数getCodecAndVideoSize,用于实现获取编解码和video size;增加一个getCodecList用于供CvCaptureCAM_DShow调用获取编解码列表;增加一个getVideoSizeList用于供CvCaptureCAM_DShow调用获取video size列表。CvCaptureCAM_DShow中也有对应的这两个函数,用于供VideoCapture调用。它们的实现如下:执行完VD->streamConf->GetStreamCaps后,结构体scc中的MinOutputSize和MaxOutputSize成员变量值即是video size。通过计算结构体pmtConfig中的BITMAPINFOHEADER即可获取codec type。
void videoInput::getCodecAndVideoSize(videoDevice *VD)
{infolist[VD->myID].clear();int iCount = 0;int iSize = 0;HRESULT hr = VD->streamConf->GetNumberOfCapabilities(&iCount, &iSize);if (hr != S_OK) {fprintf(stderr, "fail to get number of capabilities\n");return;}if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {std::map<int, std::map<int, std::set<std::vector<int>>>> info;//For each format type RGB24 YUV2 etcfor (int iFormat = 0; iFormat < iCount; iFormat++) {VIDEO_STREAM_CONFIG_CAPS scc;AM_MEDIA_TYPE *pmtConfig;hr = VD->streamConf->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);if (SUCCEEDED(hr)){//his is how many diff sizes are available for the formatint stepX = scc.OutputGranularityX;int stepY = scc.OutputGranularityY;//Don't want to get stuck in a loopif (stepX < 1 || stepY < 1) continue;std::vector<int> size_min{ scc.MinOutputSize.cx, scc.MinOutputSize.cy }, size_max{ scc.MaxOutputSize.cx, scc.MaxOutputSize.cy };VIDEOINFOHEADER* pVih = reinterpret_cast<VIDEOINFOHEADER*>(pmtConfig->pbFormat);BITMAPINFOHEADER* bih = &pVih->bmiHeader;const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };enum AVPixelFormat pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);if (pix_fmt == AV_PIX_FMT_NONE) {enum AVCodecID codec_id = av_codec_get_id(tags, bih->biCompression);if (codec_id != AV_CODEC_ID_NONE) {if (codec_id == AV_CODEC_ID_MJPEG) {info[VD->myID][VIDEO_CODEC_TYPE_MJPEG].insert(size_min);info[VD->myID][VIDEO_CODEC_TYPE_MJPEG].insert(size_max);}else if (codec_id == AV_CODEC_ID_H264) {info[VD->myID][VIDEO_CODEC_TYPE_H264].insert(size_min);info[VD->myID][VIDEO_CODEC_TYPE_H264].insert(size_max);}else if (codec_id == AV_CODEC_ID_H265) {info[VD->myID][VIDEO_CODEC_TYPE_H265].insert(size_min);info[VD->myID][VIDEO_CODEC_TYPE_H265].insert(size_max);}}}else {info[VD->myID][VIDEO_CODEC_TYPE_RAWVIDEO].insert(size_min);info[VD->myID][VIDEO_CODEC_TYPE_RAWVIDEO].insert(size_max);}MyDeleteMediaType(pmtConfig);}}for (auto codec_id = 0; codec_id < info[VD->myID].size(); ++codec_id) {for (auto it = info[VD->myID][codec_id].cbegin(); it != info[VD->myID][codec_id].cend(); ++it) {std::string size = std::to_string((*it)[0]);size += "x";size += std::to_string((*it)[1]);infolist[VD->myID][codec_id].push_back(size);}}}else {fprintf(stderr, "fail to get codec and video size\n");return;}
}bool videoInput::getCodecList(int device_id, std::vector<int>& codecids)
{codecids.clear();if (infolist[device_id].size() == 0) return false;for (auto it = infolist[device_id].cbegin(); it != infolist[device_id].cend(); ++it) {codecids.push_back(it->first);}return true;
}bool videoInput::getVideoSizeList(int device_id, int codec_id, std::vector<std::string>& sizelist)
{if (device_id >= getDeviceCount()) return false;sizelist = this->infolist[device_id][codec_id];return true;
}
OpenCV中的VideoCapture类中虽然有接收设备名的接口,但是好像并不能运行,只能通过设备索引来获取视频。在一台PC机上插入多个USB摄像头时并不清楚哪个索引对应哪个设备名,这里对VideoCapture(const std::string& filename)的实现进行了修改,使其可以通过输入设备名获取视频,实现如下:首先通过索引0获取到设备列表,然后根据输入的设备名在设备列表中是否可以映射到对应的索引值,如果有匹配的,则再通过对应的索引值打开设备。
bool VideoCapture::open(const std::string& filename)
{if (isOpened()) release();open(0);if (!cap) return false;std::map<int, std::string> devices_name;cap->getDevicesList(devices_name);if (devices_name.size() == 0) return false;if (isOpened()) release();int device = -1;for (auto it = devices_name.cbegin(); it != devices_name.cend(); ++it) {if (filename.compare((*it).second) == 0)device = (*it).first;}if (device == -1) return false;return open(device);
}
测试代码如下:
#include "fbc_cv_funset.hpp"
#include <videocapture.hpp>
#include <opencv2/opencv.hpp>int test_get_camera_info()
{
#ifdef _MSC_VERstd::map<int, std::string> camera_names;fbc::get_camera_names(camera_names);fprintf(stdout, "camera count: %d\n", camera_names.size());for (auto it = camera_names.cbegin(); it != camera_names.cend(); ++it) {fprintf(stdout, "camera index: %d, name: %s\n", (*it).first, (*it).second.c_str());}fbc::VideoCapture capture(0);if (!capture.isOpened()) {fprintf(stderr, "fail to open capture\n");return -1;}std::vector<int> codecids;capture.getCodecList(codecids);fprintf(stdout, "support codec type(video_codec_type_t: 0: h264; 1: h265; 2: mjpeg; 3: rawvideo): ");for (auto i = 0; i < codecids.size(); ++i) {fprintf(stdout, "%d ", codecids[i]);}fprintf(stdout, "\n");std::vector<std::string> sizelist;int codec_type = fbc::VIDEO_CODEC_TYPE_MJPEG;capture.getVideoSizeList(codec_type, sizelist);fprintf(stdout, "codec type: %d, support video size list:(width*height)\n", codec_type);for (auto it = sizelist.cbegin(); it != sizelist.cend(); ++it) {fprintf(stdout, "\t%s\n", (*it).c_str());}return 0;
#elsefprintf(stderr, "Error: only support windows platform\n");return -1;
#endif
}
执行结果如下:
GitHub:https://github.com//fengbingchun/OpenCV_Test
相关文章:
15篇论文全面概览BERT压缩方法
作者 | Mitchell A. Gordon译者 | 孙薇出品 | AI科技大本营(ID:rgznai100)模型压缩可减少受训神经网络的冗余——由于几乎没有BERT或者BERT-Large模型可用于GPU及智能手机上,这一点就非常有用了。另外,内存与推理速度的提高也能节…

iOS下JS与OC互相调用(七)--Cordova 基础
Cordova 简介 在介绍Cordova之前,必须先提一下PhoneGap。PhoneGap 是Nitobi软件公司2008年推出的一个框架,旨在弥补web 和iOS 之间的不足,使得web 和 iPhone SDK 之间的交互更容易。后来又加入了Android SDK 和BlackBerry SDK,再然…

在linux上MySQL的三种安装方式
安装MySQL的方式常见的有三种:方式一:rpm安装(1) 操作系统发行商提供的(2) MySQL官方提供的(版本更新,修复了更多常见BUG)www.mysql.com/downloads关于MySQL中rpm包类型的介绍:MySQL-client 客户端…

通过libjpeg-turbo实现对jpeg图像的解码
之前在https://blog.csdn.net/fengbingchun/article/details/89715416中介绍过通过libjpeg-turbo接口实现将数据编码或压缩成jpeg数据并通过FILE的fwrite接口将其直接保存成*.jpg图像,当时用的是libjpeg的接口,其实还可以使用turbojpeg api的接口即tjCom…
AI+大数据顶级技术盛会开幕在即,6.6折特惠票限时抢购
2019年12月5-7日,由中国计算机学会主办,CCF 大数据专家委员会承办,CSDN、中科天玑数据科技股份有限公司协办的中国大数据技术大会(BDTC 2019)将于北京长城饭店隆重举行。届时,超过百位顶尖技术专家将齐聚于…

iOS下JS与OC互相调用(八)--Cordova详解+实战
1.新建工程,添加Cordova 关键类 我这里用Xcode 8 新建了一个工程,叫 JS_OC_Cordova,然后将Cordova关键类添加进工程。 有哪些关键类呢? 这里添加config.xml 、Private 和 Public 两个文件夹里的所有文件。工程目录结构如下: 然后…

iOS多线程编程之NSOperation和NSOperationQueue的使用
使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation。 另一种是继承NSOperation 如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一样,NSOpe…

Swift - 使用SwiftHTTP通过HTTPS进行网络请求,及证书的使用
(本文代码已升级至Swift3)一,证书的生成,以及服务器配置参考我前面写的这篇文章:Tomcat服务器配置https双向认证(使用keytool生成证书)文章详细介绍了HTTPS,SSL/TLS。还有使用key to…

Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现
早些时候给出了在Windows下通过dshow获取视频设备信息的实现,包括获取视频设备名、获取每种视频设备支持的编解码格式列表、每种编解码格式支持的video size列表,见:https://blog.csdn.net/fengbingchun/article/details/102806822 下面给出…
12种主流编程语言输出“ Hello World ”,把我给难住了!
作为一名程序员,在初步学习编程想必都绕不开一个最为基础的入门级示例“Hello World”,那么,你真的了解各个语言“Hello World”的正确写法吗?在我们刚开始打开编程世界的时候,往往写的第一个程序都是简单的文本输出&a…

军哥lnmp一键安装包nginx支持pathinfo配置
ssh里执行:cat > /usr/local/nginx/conf/pathinfo.conf << EOF set $real_script_name $fastcgi_script_name; if ($fastcgi_script_name ~ "(.?\.php)(/.*)") { set $real_script_name $1; set $path_info $2; } fastcgi_param SCRIPT_FILENAM…

Effective STL 50条有效使用STL的经验笔记
Scott Meyers大师Effective三部曲:Effective C、More Effective C、Effective STL,这三本书出版已很多年,后来又出版了Effective Modern C。 Effective C的笔记见:https://blog.csdn.net/fengbingchun/article/details/102761542…

HTTPS网络加密双向验证-使用AFNetworking封装
1.首先使用OC封装请求头 #import <Foundation/Foundation.h> #import "AFNetworking.h" interface HttpsHandler : NSObject (AFHTTPSessionManager *)setHttpsMange; end 2.实现方法 (AFHTTPSessionManager *)setHttpsMange; { NSString *certFilePath […
30分钟搞定数据竞赛刷分夺冠神器LightGBM!
作者 | 梁云1991来源 | Python与算法之美(ID:Python_Ai_Road)【导读】LightGBM可以看成是XGBoost的升级加强版本,2017年经微软推出后,便成为各种数据竞赛中刷分夺冠的神兵利器。一,LightGBM和XGBoost对比正如其名字中的Light所蕴含…

js模块化例子
最近在看一本书,里面提到js的模块化,觉得很有必要,所以记录下来 Game.js /*** This is the main class that handles the game life cycle. It initializes* other components like Board and BoardModel, listens to the DOM events and* tr…

swift3.0提示框新用法
var alert: UIAlertController! alert UIAlertController(title: "提示", message: "添加照片", preferredStyle: UIAlertControllerStyle.actionSheet) let cleanAction UIAlertAction(title: "取消", style: UIAlertActionStyle.cancel,han…

FFmpeg在Windows上通过dshow编解码方式设置为mjpeg并实时显示测试代码
Windows上默认的内置摄像头一般支持两种编解码格式:rawvideo和mjpeg。在调用FFmpeg接口时默认的采用rawvideo。这里通过DirectShow实现为mjpeg进行编解码。 通过命令行调用FFmpeg可执行文件: (1). 可获取Windows上连接的视频设备,命令如下&…
基于深度学习的低光照图像增强方法总结(2017-2019)| CSDN博文精选
扫码参与CSDN“原力计划”作者 | hyk_1996来源 | CSDN博客精选之前在做光照对于高层视觉任务的影响的相关工作,看了不少基于深度学习的低光照增强(low-light enhancement)的文章[3,4,5,7,8,9,10],于是决定简单梳理一下。光照估计&…

ios多线程和进程的区别(转载)
很想写点关于多进程和多线程的东西,我确实很爱他们。但是每每想动手写点关于他们的东西,却总是求全心理作祟,始终动不了手。 今天终于下了决心,写点东西,以后可以再修修补补也无妨。 一.为何需要多进程(或者…

OC封装的轮播图-只用调用即可
先来使用方法 1.//创建显示本地图片view UIView *imageScorll[WTImageScroll ShowLocationImageScrollWithFream:CGRectMake(0, 0, SCREENWIDTH, 200) andImageArray:array andBtnClick:^(NSInteger tagValue) { NSLog("点击的图片----%",(tagValue)); self.didSele…
多核时代,并行编程为何“臭名昭著”?
作者 | Yan Gu来源 | 转载自知乎用户Yan Gu【导读】随着计算机技术的发展,毫无疑问现代计算机的处理速度和计算能力也越来越强。然而细心的同学们可能早已注意到,从2005年起,单核的 CPU 性能就没有显著的提升了。究其原因,是人们发…

Linux下获取usb视频设备vendor id和product id的8种方法
在使用usb摄像头获取视频时,有时需要获取此摄像头供应商ID(vendor id, vid)和产品ID(product id, pid),这里在Linux下提供获取vid和pid的8种方法: 1. 通过v4l2中结构体v4l2_capability的成员变量card:此变量中会包含设备名、vid、…

JAVA 设计模式 模板方法模式
定义 模板方法模式 (Template Method) 定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代…
这类程序员成华为宠儿,分分钟秒杀众应届毕业生
近日,华为20亿奖励员工的新闻频频刷屏。其中20亿奖金不是面向所有的华为员工,20亿奖金包涉及到的是研发体系、造AI芯片和建设生态的员工。从5G开始部署以来,华为获得了来自全球各地运营商的订单,签订了40多个5G商用合同。另外华为…

Swift 使用CoreLocation获取定位与位置信息
大多数情况下APP会在开启应用的时候获取当前的位置,所以我写在APPDelegate里第一步 import CoreLocationvar locationManager CLLocationManager() 第二步func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: …

FFmpeg在Windows上设置dshow mjpeg编码+libyuv解码显示测试代码
之前在https://blog.csdn.net/fengbingchun/article/details/103444891中介绍过在Windows上通过ffmpeg dshow设置为mjpeg编解码方式进行实时显示的测试代码。这里测试仅调用ffmpeg的mjpeg编码接口,获取到packet后,通过libyuvlibjpeg-turbo对mjpeg进行解码…

转:浅谈Linux的内存管理机制
一 物理内存和虚拟内存 我们知道,直接从物理内存读写数据要比从硬盘读写数据要快的多,因此,我们希望所有数据的读取和写入都在内存完成,而内存是有限的,这样就引出了物理内存与虚拟内存的概念。 物理内存就是系统硬件提…

swift3.0阿里百川反馈
闲言少叙 直接上不熟 1.导入自己工程阿里百川demo中的Util文件,并引用其中的头文件 2.剩余就是swift3.0代码.在自己需要的地方书写 (前提是你已经申请了APPKey) 3.代码 //调用意见反馈 func actionOpenFeedback(){ //key self.appKey "此处填写自己申请的key" s…
通俗易懂:8大步骤图解注意力机制
作者 | Raimi Karim译者 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】这是一份用图片和代码详解自注意力机制的指南,请收好。BERT、RoBERTa、ALBERT、SpanBERT、DistilBERT、SesameBERT、SemBERT、MobileBERT、TinyBERT和CamemBERT的共同…

Windows上VS2017单步调试FFmpeg源码的方法
之前在https://blog.csdn.net/fengbingchun/article/details/90114411 介绍过如何在Windows7/10上通过MinGW方式编译FFmpeg 4.1.3源码生成库的步骤,那时只能生成最终的库,却不能产生vs工程,无法进行单步调试。GitHub上有个项目ShiftMediaProj…