日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

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

發(fā)布時(shí)間:2023/11/27 生活经验 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通过Windows DShow获取设备名、支持的编解码及视频size列表实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前在https://blog.csdn.net/fengbingchun/article/details/102641967中介紹過通過DShow獲取Camera視頻的實(shí)現(xiàn),即調(diào)用VideoCapture類。在OpenCV的VideoCapture類中并沒有提供獲取Camera設(shè)備列表、支持的編解碼類型列表及支持的video size列表接口,這里基于已有的VideoCapture類增加對這些的實(shí)現(xiàn)。

獲取Camera設(shè)備名:在videoInput類中有兩個(gè)函數(shù),一個(gè)是getDeviceCount用于獲取設(shè)備數(shù),一個(gè)是getDeviceName用于根據(jù)索引獲取設(shè)備名。在CvCaputreCAM_DShow類中增加函數(shù)getDevicesList,實(shí)現(xiàn)如下,在此函數(shù)中調(diào)用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;
}

增加一個(gè)對外調(diào)用的接口get_camera_names,實(shí)現(xiàn)如下:

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:這部分的實(shí)現(xiàn)參考了FFmpeg中的源碼libavdevice/dshow.c,并把其中的一些code移了過來。首先在videoInput類中增加一個(gè)變量infolist,用于存放設(shè)備索引名、編解碼類型、視頻size信息;增加一個(gè)函數(shù)getCodecAndVideoSize,用于實(shí)現(xiàn)獲取編解碼和video size;增加一個(gè)getCodecList用于供CvCaptureCAM_DShow調(diào)用獲取編解碼列表;增加一個(gè)getVideoSizeList用于供CvCaptureCAM_DShow調(diào)用獲取video size列表。CvCaptureCAM_DShow中也有對應(yīng)的這兩個(gè)函數(shù),用于供VideoCapture調(diào)用。它們的實(shí)現(xiàn)如下:執(zhí)行完VD->streamConf->GetStreamCaps后,結(jié)構(gòu)體scc中的MinOutputSize和MaxOutputSize成員變量值即是video size。通過計(jì)算結(jié)構(gòu)體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類中雖然有接收設(shè)備名的接口,但是好像并不能運(yùn)行,只能通過設(shè)備索引來獲取視頻。在一臺PC機(jī)上插入多個(gè)USB攝像頭時(shí)并不清楚哪個(gè)索引對應(yīng)哪個(gè)設(shè)備名,這里對VideoCapture(const std::string& filename)的實(shí)現(xiàn)進(jìn)行了修改,使其可以通過輸入設(shè)備名獲取視頻,實(shí)現(xiàn)如下:首先通過索引0獲取到設(shè)備列表,然后根據(jù)輸入的設(shè)備名在設(shè)備列表中是否可以映射到對應(yīng)的索引值,如果有匹配的,則再通過對應(yīng)的索引值打開設(shè)備。

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
}

執(zhí)行結(jié)果如下:

GitHub:https://github.com//fengbingchun/OpenCV_Test

總結(jié)

以上是生活随笔為你收集整理的通过Windows DShow获取设备名、支持的编解码及视频size列表实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。