之前在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

通过Windows DShow获取设备名、支持的编解码及视频size列表实现相关推荐

  1. Linux下通过v4l2获取视频设备名、支持的编解码及视频size列表实现

    早些时候给出了在Windows下通过dshow获取视频设备信息的实现,包括获取视频设备名.获取每种视频设备支持的编解码格式列表.每种编解码格式支持的video size列表,见:https://blo ...

  2. WebRTC android 端支持H264编解码

    一.WebRTC源码中默认使用的H264编解码的库 1.WebRTC源码的video_coding模块中,包含了H264编解码相关的类 打开画红线的两个头文件,分别可以看到解码类中导入了ffmpeg的 ...

  3. 各种与视频编解码以及视频图像处理的应用相关的新技术,新方法,各种软件开发相关的算法,思想。...

    1. 各种视频压缩标准(MPEG2, MPEG4, H261/2/3/4,X264, T264以及H264(AVC)和HEVC(H265)等的优化,改进,创新. 2. 各种不同平台的(CPU, GPU ...

  4. ffmpeg获取设备支持的分辨率_Qt音视频开发6-ffmpeg解码处理

    一.前言 采用ffmpeg解码,是所有视频监控开发人员必备的技能,绕不过去的一个玩意,甚至可以说是所有音视频开发人员的必备技能.FFmpeg是一套可以用来记录.转换数字音频.视频,并能将其转化为流的开 ...

  5. 树莓派编译ffmpeg支持x264硬解码播放视频

    树莓派编译ffmpeg支持h264_mmal硬解码 1,x264源码编译 1.1下载x264源码,解压 1.2添加一个脚本文件config_x264_rpi.sh ,放入1.1解压之后的文件夹中 1. ...

  6. 视频编解码——主流视频编码标准的发展(H.261/H.263/MPEG-1/MPEG-2/MPEG-4))

    目录 制定标准的组织 两种编码方式 基于波形的编码 基于内容的编码 H.261 系统图 信源编码器 复合编码器 H.263 MPEG-1 码流结构 MPEG-2 码流结构 MPEG-4 制定标准的组织 ...

  7. mips uclibc 交叉编译ffmpeg,支持 G711A 编解码

    1 说明 使用 ffmpeg 源码,进行交叉编译,支持 H264 和 G711A 编码支持 2 环境说明 硬件环境: mips 架构芯片 软件环境: Linux 任意版本 3 原理 (1)下载 ffm ...

  8. 让WebRTC支持H264编解码

    最近实验了下如何让WebRTC支持H264编码,记录下,供有需要的人参考. 说明一下,我是在 Ubuntu Server 14.04 下编译的 WebRTC ,使用 native(C++) api 开 ...

  9. ffmpeg获取设备支持的分辨率_短视频字幕提取合成超简单,掌握ffmpeg这个小技巧

    引言 现在的短视频非常流行.大多数情况下我们会开着音量或者戴着耳机收看视频.但有些时候不是太方便,如果视频能有一个字幕就好了. 好消息是,字幕制作的软件很专业很好用,而且上手超级简单. 坏消息是,如何 ...

最新文章

  1. php实际开发过程,4.工作实际开发应用
  2. Ubuntu下安装Chrome浏览器的两个方法
  3. [转载] 将一个整数型字符串转换为一个整数
  4. 荣耀Magic2 发布:滑盖全面屏、前后6摄、屏下指纹、麒麟980
  5. mybatis中的mapper代理模式的数据传参的应用
  6. 演化博弈及Python实现
  7. 微信小程序云数据库使用讲解
  8. MyBatis事务管理
  9. 教你制作挂件头像 | 小程序七十二变之 canvas 绘制国旗头像
  10. 华为太空人智能表盘代码仅需100行?
  11. 三分钟学会网络地址相关计算
  12. 线性动态系统LDS(别名:卡尔曼滤波)
  13. 原创wallpaper Engine冷高轮时间电脑动态时钟壁纸 动态小人人体形状造型数字 动态手势数字 动态麻将数字 动态扑克数字 动态时钟壁纸
  14. Linux----软件安装及程序管理
  15. 华为OD机试真题2022(JAVA)
  16. En-Tan-Mo(ETM)项目周报(7.26-8.1)
  17. 基于小梅哥AC620开发板的NIOS II LWIP百兆以太网例程移植到自己做的板子上
  18. 中国软件行业协会成立25周年庆典 《程序员》荣获杰出传媒奖
  19. Python ORM之peewee模块
  20. sql和php是什么,SQL是什么

热门文章

  1. C++:多线程中的小白(3)线程传参详解
  2. 基于pytorch的模型剪枝+模型量化+BN合并+TRT部署(cifar数据)(2)
  3. 1 字节的 utf-8 序列的字节 1 无效_字节码文件结构详解
  4. class没有发布到tomcat_Tomcat 在 SpringBoot 中是如何启动的
  5. 如何快速坐地铁高铁?舒工为您带来满满的都是干货~
  6. python多线程下的信号处理程序示例
  7. Ubuntu 14.04 64位上安装wps office软件
  8. Unity创建游戏VFX视觉特效-初级到中级
  9. Unity电子游戏优化终极指南 The Ultimate Guide to Video Game Optimisation
  10. 管理分布式session的四种方式。