Недавний план работы заключался в переписывании класса управления CameraCtrl и реализации принудительной потоковой передачи. Однако из-за изменения спроса от предыдущего исследования отказались, поэтому я пока оставлю его здесь.
Подробный адрес: libudev Reference Manul
Похожие адреса:
Video for Linux Two API Specification
Оригинальный дизайнерский замысел,Разработанный в то время Идеидля общегоCameraManagerВ качестве модуля управления камерой,Используется для управления камер,В основном длягорячая заменасобытие, соответствующие добавления и удаления, а также управление push-уведомлениями. и достичь кроссплатформенности,совместимыйwindows&&linux(X86_64,arm,аарх64). В настоящее время объясняются только части, связанные с событиями. Модуль управления необходимо разработать в соответствии с реальными потребностями бизнеса.
src/deviceManager/cameraManager
├── cameraEvent.cpp
├── cameraEvent.h
├── cameraManager.cpp
├── cameraManager.h
└── README.md
tests
├── camera.cpp
├── CMakeLists.txt
└── conanfile.py
Основная информационная структура определения выглядит следующим образом:
FormatInfo: информация о кадре . Ширина рамы . Высота рамы . Частота кадров
CameraCardBindDeviceName: Имя привязки камеры: Оригинальное название камеры, Имя драйвера камеры
CameraInfo: Информация о камере: Имя камеры(Внешнее имя камеры),Оригинальное название камеры,Имя драйвера камеры,идентификатор камеры, видео камеры,список кадров
EventInfo: информация о событиях (в основном записывает события ежедневного подключения и отключения, но есть и другие события, поэтому они не называются событиями горячего подключения) событиетип,Имя камеры,Имя драйвера камеры,видео с веб-камеры,идентификатор камеры
struct FormatInfo
{
unsigned int width;
unsigned int height;
unsigned int rate;
};
struct CameraCardBindDeviceName
{
std::string cardNameOld;
std::string cameraDeviceName;
};
//Поскольку устройство камеры имеет одно и то же имя, невозможно отличить требуемую камеру от имени камеры, поэтому создается псевдоним для различения устройства камеры и управления им.
//Правила именования: eg. Есть два устройства камеры под названием CameraLog, и первое, полученное в процессе обхода, — CameraLog, используя исходное имя, второе полученное имя устройства Журнал камеры(1). то есть используя псевдонимы
struct CameraInfo
{
std::string cameraCardName; //Псевдоним камеры — это имя камеры
std::string cameraCardNameOld; //Оригинальное имя камеры
std::string cameraDeviceName;
std::string pid;
std::string vid;
std::list<FormatInfo> formats;
};
struct EventInfo
{
bool action; //true:add false:remove
std::string cameraName;
std::string cameraDeviceName;
std::string vid;
std::string pid;
};
Класс событий камеры, основной рабочий класс, предоставляет внешний интерфейс. Отвечает за бизнес, связанный с событиями камеры (сбор списка, события горячего подключения, информация о камере)
Интерфейс функции push не имеет практического значения и не будет здесь подробно описываться.
class CameraEvent
{
private:
/* data */
public:
~CameraEvent();
static CameraEvent* instance();
/**
* @name: Получить список камер
* @msg:
* @param {*}
* @return Вернуться к списку камер — карта
*/
std::map<std::string, CameraCardBindDeviceName> getCameraList();
/**
* @name: Получить список разрешений камеры
* @msg:
* @param {string} devicename - Имя драйвера камеры
* @return {*} Список разрешений камеры
*/
std::list<FormatInfo> getCameraResolutions(std::string devicename);
/**
* @name: Получить список форматов изображений камеры
* @msg:
* @param {*}
* @return {*} Вернуться к списку всей информации
*/
std::list<CameraInfo> getCameraFormats();
/**
* @name: Получить список vid.pid устройства ввода событий камеры
* @msg:
* @param {*}
* @return {*} Вид событий входа камеры, список pid
*/
std::map<std::string, std::string> getInputVPIDs();
/**
* @name: Добавить камеру в список камер
* @msg:
* @param {string} devicename Имя драйвера камеры
* @param {string} vid
* @param {string} pid
* @param {list<CameraInfo>} &cameras Список камер
* @return {*} Вставить результаты
*/
bool addCameraInfo(std::string devicename, std::string vid, std::string pid, std::list<CameraInfo> &cameras);
/**
* @name: Список камер Удалить камеру
* @msg:
* @param {string} devicename Имя драйвера камеры
* @param {list<CameraInfo>} &cameras Список камер
* @return {*} Удалить результаты
*/
bool removeCameraInfo(std::string devicename, std::list<CameraInfo> &cameras);
/**
* @name: Начнется потоковая передача с камеры
* @msg:
* @param {string} devicename Имя драйвера камеры
* @param {int} width По всему разрешению
* @param {int} height Разрешение-Высокое
* @param {string} host адрес целевого хоста
* @param {string} port целевой хост-порт
* @return {*}
*/
void cameraGstPushStreamStart(std::string devicename, int width, int height, std::string host, std::string port);
/**
* @name: Потоковая передача с камеры остановлена
* @msg:
* @param {string} devicename Имя драйвера камеры
* @return {*}
*/
void cameraGstPushStreamStop(std::string devicename);
#ifdef __linux__
/**
* @name: udev admMonitor инициализация
* @msg:
* @param {udev} *udev указатель udev
* @param {udev_monitor*} &kernelMonitor
* @param {fd_set} &readFds
* @return {*}
*/
int udevadmMonitor(struct udev *udev, struct udev_monitor* &kernelMonitor, fd_set &readFds);
/**
* @name: udev admmonitor item дочерний элементсобытие * @msg:
* @param {udev_monitor*} &kernelMonitor
* @param {fd_set} &readFds
* @return {*}
*/
EventInfo udevadmMonitorItem(struct udev_monitor* &kernelMonitor, fd_set &readFds);
#endif
private:
CameraEvent(/* args */);
//Контейнер управления ручками управления камерой
boost::unordered_map<std::string, Poco::ProcessHandle> _mapHandle;
};
CameraEvent* CameraEvent::instance()
{
static CameraEvent cameraEvent;
return &cameraEvent;
}
getCameraList()
Основной рабочий процесс: просмотр класса видео в папке /dev/, сохранение, фильтрация и сортировка. Просмотрите, отфильтруйте и получите необходимый список камер.
В убунту 18.04. Когда камера вставлена, будет два файла /dev/video. Файлы, отсортированные по порядку. Причина в том, что в 18.04 камеру не различает V4L2_CAP_META_CAPTURE и V4L2_CAP_VIDEO_CAPTURE В результате выводятся два /dev/video файл, при фактическом использовании потоковой передачи с камеры, это использовать V4L2_CAP_VIDEO_CAPTURE Тип камера, поэтому ее нужно различать при фильтрации.
Video Capture = V4L2_CAP_STREAMING + V4L2_CAP_EXT_PIX_FORMAT + V4L2_CAP_VIDEO_CAPTURE
Metadata Capture = V4L2_CAP_STREAMING + V4L2_CAP_EXT_PIX_FORMAT + V4L2_CAP_META_CAPTURE
ioctl(fd, VIDIOC_QUERYCAP, &vcap) Получать vcap.device_caps ценить выполнить фильтрацию различия.
Ссылки по теме:Почему одна камера соответствует двум видео в ubuntu18.04 в /dev?
std::map<std::string, CameraCardBindDeviceName> CameraEvent::getCameraList()
{
std::map<std::string, CameraCardBindDeviceName> cameras;
#ifdef _WIN32
#elif __linux__
DIR *dp;
struct dirent *ep;
dev_vec files;
struct v4l2_capability vcap;
dp = opendir("/dev");
if (dp == nullptr) {
perror ("Couldn't open the directory");
return {};
}
while ((ep = readdir(dp)))
if (is_v4l_dev(ep->d_name) && std::string(ep->d_name).find("video") != std::string::npos)
files.push_back(std::string("/dev/") + ep->d_name);
closedir(dp);
std::sort(files.begin(), files.end(), sort_on_device_name);
for (const auto &file : files) {
int fd = open(file.c_str(), O_RDWR);
std::string bus_info;
std::string card;
if (fd < 0)
continue;
int err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
bool is_mate = 0;
if (err) {
} else {
if(vcap.device_caps == (V4L2_CAP_STREAMING + V4L2_CAP_EXT_PIX_FORMAT + V4L2_CAP_VIDEO_CAPTURE))
{
bus_info = reinterpret_cast<const char *>(vcap.bus_info);
card = reinterpret_cast<const char *>(vcap.card);
#ifdef service_debug
std::cout << std::string(card) <<" "<< std::string(file) << " " << std::string(bus_info) << std::endl;
#elif
LOG(INFO) << std::string(card) << std::string(file) << std::string(bus_info);
#endif
}else if(vcap.device_caps == (V4L2_CAP_STREAMING + V4L2_CAP_META_CAPTURE + V4L2_CAP_EXT_PIX_FORMAT))
is_mate = true;
}
close(fd);
if (err || is_mate)
continue;
std::string cameraNameOld = card;
if(cameras.count(std::string(card)))
card = getCardName(cameras, card, 1);
cameras[std::string(card)] = {cameraNameOld, file};
}
#endif
#ifdef service_debug
for(auto it : cameras)
{
std::cout << it.first << " " << it.second.cardNameOld << " " << it.second.cameraDeviceName << std::endl;
}
#endif
return cameras;
}
Получите разрешение камеры на основе имени устройства, например, /dev/video0 получает соответствующее разрешение камеры.
на практике,Камеры обычно поддерживают несколько видеоформатов.,yuyv, mjeg и другие форматы,Но в реальном использовании блогеры,Просто используйте формат yuyv,Таким образом получается только список разрешений, соответствующий yuyv.
if(fmt.pixelformat == V4L2_PIX_FMT_YUYV) фильтровать.
std::list<FormatInfo> CameraEvent::getCameraResolutions(std::string dev)
{
std::list<FormatInfo> resolutions = {};
#ifdef _WIN32
#elif __linux__
int fd = open(dev.c_str(), O_RDONLY);
if (fd < 0)
{
#ifdef service_debug
std::cout << dev << ":Open fail!!!" << std::endl;;
#elif
LOG(ERROR) << dev << ":Open fail!!!";
#endif
}
struct v4l2_format vfmt = {.type=V4L2_BUF_TYPE_VIDEO_OUTPUT};
if(ioctl(fd,VIDIOC_G_FMT, &vfmt))
{
#ifdef service_debug
std::string format = (vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) ? "YUYV" : std::to_string(vfmt.fmt.pix.pixelformat);
std::cout << format << " " << vfmt.fmt.pix.width << " " << vfmt.fmt.pix.height << std::endl;
#elif
LOG(ERROR) << dev << ":Open fail!!!";
#endif
}else
{
#ifdef service_debug
std::cout << "vfmt:get fail!" << std::endl;
#elif
LOG(ERROR) << dev << ":Open fail!!!";
#endif
}
struct v4l2_fmtdesc fmt = {.index=0, .type=V4L2_BUF_TYPE_VIDEO_CAPTURE};
#ifdef service_debug
std::cout << "Start Search format resolutions" << std::endl;;
#elif
LOG(ERROR) << << "Start Search format resolutions";
#endif
while(ioctl(fd, VIDIOC_ENUM_FMT, &fmt) >=0 )
{
#ifdef service_debug
std::cout << "Picture Format:" << fmt.description << std::endl;
#elif
LOG(INFO) << "Picture Format:" << fmt.description;
#endif
if(fmt.pixelformat == V4L2_PIX_FMT_YUYV)
{
#ifdef service_debug
std::cout << "Picture Format is YUYV" << std::endl;
#elif
LOG(INFO) << "Picture Format is YUYV";
#endif
FormatInfo fmtInfo;
struct v4l2_frmsizeenum frmsize = {.index=0, .pixel_format=fmt.pixelformat};
while(ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
{
fmtInfo.width = frmsize.discrete.width;
fmtInfo.height = frmsize.discrete.height;
fmtInfo.rate = 0;
#ifdef service_debug
std::cout << "Resolution: " << fmtInfo.width << "X" << fmtInfo.height << std::endl;
#elif
LOG(INFO) << "Resolution: " << fmtInfo.width << "X" << fmtInfo.height;
#endif
struct v4l2_frmivalenum frmival = {.index=0, .pixel_format=frmsize.pixel_format, .width=frmsize.discrete.width, .height=frmsize.discrete.height};
while(ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) >= 0)
{
unsigned int maxRate = 0;
if(frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE)
{
#ifdef service_debug
std::cout << '\t' << "frmival.discrete: " << fract2fps_int(frmival.discrete) << std::endl;
#elif
LOG(INFO) << '\t' << "frmival.discrete: " << fract2fps_int(frmival.stepwise.max);
#endif
maxRate = fract2fps_int(frmival.discrete);
}
else if (frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS || frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE)
{
#ifdef service_debug
std::cout << "stepwise.max: " << fract2fps(frmival.stepwise.max) << std::endl;
#elif
LOG(INFO) << "stepwise.max: " << fract2fps_int(frmival.stepwise.max);
#endif
maxRate = fract2fps_int(frmival.stepwise.max);
}
fmtInfo.rate = (maxRate > fmtInfo.rate) ? maxRate : fmtInfo.rate;
frmival.index++ ;
}
resolutions.push_back(fmtInfo);
frmsize.index++;
}
break;
}
else
fmt.index ++;
}
#ifdef service_debug
std::cout << "End Search format resolutions" << std::endl;;
#elif
LOG(ERROR) << "End Search format resolutions";
#endif
close(fd);
#endif
return resolutions;
}
Получите список информации о формате камеры.
std::list<CameraInfo> CameraEvent::getCameraFormats()
{
std::list<CameraInfo> cameraInfos;
std::map<std::string, CameraCardBindDeviceName> cameras = getCameraList();
#ifdef service_debug
std::cout << "Start Search USB Camera VID and PID" << std::endl;
#endif
#ifdef _WIN32
#elif __linux__
std::map<std::string, std::string> vpIDs = getInputVPIDs();
for(auto it=cameras.begin(); it != cameras.end(); it++)
{
CameraInfo camInfo = {.cameraCardName = it->first, .cameraCardNameOld = it->second.cardNameOld, .cameraDeviceName=it->second.cameraDeviceName};
camInfo.formats = getCameraResolutions(camInfo.cameraDeviceName);
camInfo.vid = vpIDs[camInfo.cameraCardNameOld].substr(0, 4);
camInfo.pid = vpIDs[camInfo.cameraCardNameOld].substr(5, 4);
cameraInfos.push_back(camInfo);
}
#endif
#ifdef service_debug
std::cout << "Output Cameras Info:" << std::endl;
for(auto it: cameraInfos)
{
std::cout << it.cameraCardName << " " << it.cameraCardNameOld << " " << it.cameraDeviceName << " " << it.vid << " " << it.pid << std::endl;
for(auto itr : it.formats)
{
std::cout << itr.height << " " << itr.width << " " << itr.rate << std::endl;
}
}
#endif
return cameraInfos;
}
Получите VID и PID устройства камеры. При проверке соответствующей информации часто можно увидеть, что информация VID.PID получается через имя камеры. Однако на практике полное имя камеры не получается. Другой метод — получить его через фильтрацию входных событий. конкретная ссылка и исходный код не публикуются. Но фильтровать напрямую — неправильно. «вид», «пид».
Есть две ситуации, в которых блоггеры могут получить VID и PID. один для Имеющееся видеооборудование. проходить ioctl(fd, EVIOCGID, &inputId) Получите соответствующую информацию.
Второй тип – это горячая заменасобытие, фильтр видео,pid по входусобытие.
static int get_intputdevice_info(std::string file, std::string &cardname, std::string &vpID)
{
int fd = open(file.c_str(), O_RDWR);
std::string bus_info;
char cardName[256] = "";
struct input_id inputId;
if (fd < 0)
return 1;
int err_id = ioctl(fd, EVIOCGID, &inputId);
if (err_id) {
#ifdef service_debug
std::cout << "err_id:" << err_id << std::endl;
#elif
LOG(INFO) << "err_id:" << err_id << std::string(cardName);
#endif
} else {
std::stringstream buf;
buf << std::hex << std::setw(4) << std::setfill('0') << inputId.vendor << ":" << std::setw(4) << std::setfill('0') << inputId.product;
buf >> vpID;
int len = ioctl(fd, EVIOCGNAME(sizeof(cardName)), cardName);
#ifdef service_debug
std::cout << "cardName:" << std::string(cardName, len) << " VID/PID value:" << vpID << std::endl;
#elif
LOG(INFO) << "cardName:" << std::string(cardName, len) << " VID/PID value:" << vpID;
#endif
}
close(fd);
cardname = reinterpret_cast<const char *>(cardName);;
return err_id;
}
std::map<std::string, std::string> CameraEvent::getInputVPIDs()
{
std::map<std::string, std::string> inputInfos;
#ifdef _WIN32
#elif __linux__
DIR *dp;
struct dirent *ep;
dev_vec files;
dp = opendir("/dev/input");
if (dp == nullptr) {
perror ("Couldn't open the directory");
return {};
}
while ((ep = readdir(dp)))
if (std::string(ep->d_name).find("event") != std::string::npos)
files.push_back(std::string("/dev/input/") + ep->d_name);
closedir(dp);
std::sort(files.begin(), files.end(), sort_on_device_name);
for (const auto &file : files) {
std::string card,vpID;
int err_id = get_intputdevice_info(file, card, vpID);
if(err_id)
continue;
if(!inputInfos.count(card)){
inputInfos[card] = vpID;
}
}
#endif
return inputInfos;
}
Горячее подключение: событие подключения
bool CameraEvent::addCameraInfo(std::string devicename, std::string vid, std::string pid, std::list<CameraInfo> &cameras)
{
CameraInfo info = {.cameraCardName = "", .cameraCardNameOld = "", .cameraDeviceName = devicename, .pid = pid, .vid = vid};
#ifdef _WIN32
#elif __linux__
int fd = open(devicename.c_str(), O_RDWR);
std::string bus_info;
std::string card;
struct v4l2_capability vcap;
if (fd < 0){
#ifdef service_debug
std::cout << "Open file fail:" << devicename << std::endl;
#elif
LOG(WARNING) << "Open file fail:" << devicename << std::string(bus_info);
#endif
return false;
}
int err = ioctl(fd, VIDIOC_QUERYCAP, &vcap);
bool is_mate = 0;
if (err) {
} else {
if(vcap.device_caps == (V4L2_CAP_STREAMING + V4L2_CAP_EXT_PIX_FORMAT + V4L2_CAP_VIDEO_CAPTURE))
{
bus_info = reinterpret_cast<const char *>(vcap.bus_info);
card = reinterpret_cast<const char *>(vcap.card);
#ifdef service_debug
std::cout << std::string(card) <<" "<< std::string(devicename) << " " << std::string(bus_info) << std::endl;
#elif
LOG(INFO) << std::string(card) << std::string(devicename) << std::string(bus_info);
#endif
}else if(vcap.device_caps == (V4L2_CAP_STREAMING + V4L2_CAP_META_CAPTURE + V4L2_CAP_EXT_PIX_FORMAT))
is_mate = true;
}
close(fd);
if(err || is_mate)
{
#ifdef service_debug
std::cout << "Open devicename fail:" << devicename << " or deveice type is mate" <<std::endl;
#elif
LOG(WARNING) << "Open devicename fail:" << devicename << " or deveice type is mate";
#endif
return false;
}
bool InsertFlags = false;
int count = 0;;
for(auto it: cameras)
{
if(std::string(card) == it.cameraCardNameOld)
{
count++;
InsertFlags = true;
}
}
info.cameraCardName = (count) ? card + "(" + std::to_string(count) + ")" : card;
info.cameraCardNameOld = card;
info.formats = getCameraResolutions(devicename);
#endif
cameras.push_back(info);
return true;
}
Горячее подключение: событие отключения
bool CameraEvent::removeCameraInfo(std::string cardName, std::list<CameraInfo> &cameras)
{
auto it = cameras.begin();
bool ret = false;
for(it; it != cameras.end(); it++)
{
if((*it).cameraCardName == cardName)
{
ret = true;
it = cameras.erase(it);
cameraGstPushStreamStop((*it).cameraDeviceName);
}
}
return ret;
}
Событие обнаружения горячего подключения
#ifdef __linux__
int CameraEvent::udevadmMonitor(struct udev *udev, struct udev_monitor* &kernelMonitor, fd_set &readFds)
{
if(getuid() != 0)
{
#ifdef service_debug
std::cout << "root privileges needed to subscribe to kernel events." << std::endl;
#elif
LOG(INFO) << "root privileges needed to subscribe to kernel events." ;
#endif
udev_monitor_unref(kernelMonitor);
return 0;
}
#ifdef service_debug
std::cout << "monitor will print the received events." << std::endl;
#elif
LOG(INFO) << "monitor will print the received events." ;
#endif
kernelMonitor = udev_monitor_new_from_netlink(udev, "udev");
if(kernelMonitor == nullptr) {
udev_monitor_unref(kernelMonitor);
return 3;
}
//событие фильтр: фильтр video4linux событие
udev_monitor_filter_add_match_subsystem_devtype(kernelMonitor, "video4linux", nullptr);
if(udev_monitor_enable_receiving(kernelMonitor) < 0) {
udev_monitor_unref(kernelMonitor);
return 4;
}
#ifdef service_debug
std::cout << "UEVENT the kernel uevent:" << std::endl;
#elif
LOG(INFO) << "UEVENT the kernel uevent:" ;
#endif
return 1;
}
//Сбор информации об одном событии
EventInfo CameraEvent::udevadmMonitorItem(struct udev_monitor* &kernelMonitor, fd_set &readFds)
{
EventInfo info;
int fdCount = 0;
FD_ZERO(&readFds);
if(kernelMonitor != nullptr) {
FD_SET(udev_monitor_get_fd(kernelMonitor), &readFds);
}
fdCount = select(udev_monitor_get_fd(kernelMonitor)+1, &readFds, nullptr, nullptr, nullptr);
if(!fdCount)
{
if(errno != EINTR) {
#ifdef service_debug
std::cout << "error receiving uevent message" << std::endl;
#elif
LOG(INFO) << "error receiving uevent message:" ;
#endif
}
return {};
}
if((kernelMonitor != nullptr) && FD_ISSET(udev_monitor_get_fd(kernelMonitor), &readFds))
{
struct udev_device *device = udev_monitor_receive_device(kernelMonitor);
if(device == nullptr)
{
return {};
}
if(std::string(udev_device_get_action(device)) == std::string("add") || std::string(udev_device_get_action(device)) == std::string("remove"))
{
struct udev_list_entry *devAttributes;
udev_list_entry_foreach(devAttributes, udev_device_get_properties_list_entry(device))
{
std::string name(udev_list_entry_get_name(devAttributes));
std::string value(udev_list_entry_get_value(devAttributes));
if(name == std::string("ACTION"))
info.action = (value == std::string("add")) ? true : false;
if(name == std::string("ID_V4L_PRODUCT"))
info.cameraName = value;
if(name == std::string("ID_MODEL_ID"))
info.pid = value;
if(name == std::string("ID_VENDOR_ID"))
info.vid = value;
}
info.cameraDeviceName = reinterpret_cast<const char *>(udev_device_get_devnode(device));
#ifdef service_debug
std::cout << udev_device_get_action(device) << " "
<< udev_device_get_devpath(device) << " "
<< udev_device_get_subsystem(device) << " "
<< udev_device_get_devnode(device) << " "
<< info.cameraName << " "
<< info.vid << " "
<< info.pid << " "
<< std::endl;
#elif
LOG(INFO) << std::string(udev_device_get_action(device)) << " "
<< std::string(udev_device_get_devpath(device)) << " "
<< std::string(udev_device_get_subsystem(device)) << " "
<< std::string(udev_device_get_devnode(device)) << " "
<< info.cameraName << " "
<< info.vid << " "
<< info.pid;
#endif
}
udev_device_unref(device);
}
return info;
}
#endif
#include "cameraEvent.h"
#include <libudev.h>
#include <signal.h>
#undef asmlinkage
#ifdef __i386__
#define asmlinkage __attribute__((regparm(0)))
#else
#define asmlinkage
#endif
static int udev_exit = 0;
static void asmlinkage sig_handler(int signum)
{
if (signum == SIGINT || signum == SIGTERM)
udev_exit = 1;
}
int main()
{
struct sigaction act;
memset(&act, 0x00, sizeof(struct sigaction));
act.sa_handler = (void (*)(int)) sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, nullptr);
sigaction(SIGTERM, &act, nullptr);
std::list<CameraInfo> cameras = CameraEvent::instance()->getCameraFormats();
CameraEvent::instance()->cameraGstPushStreamStart((*cameras.begin()).cameraDeviceName, 640, 480, "172.26.106.87", "5600");
struct udev *udev = udev_new();
if(udev == nullptr) {
udev_unref(udev);
return 0;
}
fd_set readFds;
struct udev_monitor* kernelMonitor = nullptr;
int ret = CameraEvent::instance()->udevadmMonitor(udev, kernelMonitor, readFds);
if(kernelMonitor == nullptr)
{
std::cout << "kernelMonitor == nullptr" << std::endl;
return 0;
}
while(!udev_exit)
{
EventInfo info = CameraEvent::instance()->udevadmMonitorItem(kernelMonitor, readFds);
if(info.cameraName == "")
continue;
if(info.action)
{
bool ret = CameraEvent::instance()->addCameraInfo(info.cameraDeviceName, info.vid, info.pid, cameras);
std::cout << "Add: " << cameras.size() << std::endl;
}
else
{
bool ret = CameraEvent::instance()->removeCameraInfo(info.cameraName, cameras);
std::cout << "Remove: " << cameras.size() << std::endl;
}
}
std::cout << "Ouput result: " << ret << std::endl;
udev_unref(udev);
CameraEvent::instance()->cameraGstPushStreamStop((*cameras.begin()).cameraDeviceName);
return 0;
}
cmake_minimum_required(VERSION 3.10)
# Название проекта
project(CameraTest)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fpermissive -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -fpermissive -g")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
set(service_debug true)
add_definitions(-Dservice_debug)
find_package(Poco)
# включить файлы заголовков
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../src/deviceManager/cameraManager) # Заголовочный файл включает каталог
include_directories(${Poco_INCLUDE_DIRS})
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} SOURCE_FILES)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/../src/deviceManager/cameraManager camer_FILES)
add_executable(CameraTest
${camer_FILES}
${SOURCE_FILES}
)
target_link_libraries(CameraTest udev ${CONAN_LIBS})
from conans import ConanFile, CMake, tools
import os
class CameraManager(ConanFile):
name = "CameraManger"
version = "1.0.0"
settings = "os", "compiler", "build_type", "arch"
generators = [("cmake"), ("cmake_find_package"), ("gcc")]
build_policy = "always"
def export_sources(self):
self.copy("CMakeLists.txt")
self.copy("*", dst="src", src="src")
self.copy("*", dst="config", src="config")
self.copy("*", dst="deployment", src="deployment")
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def imports(self):
self.copy("*.dll", dst="bin", src="bin")
self.copy("*.dylib*", dst="bin", src="lib")
self.copy('*.so*', dst='bin', src='lib')
def package(self):
self.copy("*", dst='bin', src='bin')
def requirements(self):
self.requires("boost/1.69.0")
self.requires("caf/0.17.6")
self.requires("yaml-cpp/0.7.0")
self.requires("poco/1.11.0")
Прочее: предусмотрены не все интерфейсы.,Только что предоставил тестовый образец и описание интерфейса ключевых функций. CMakeLists.txt и conanfile.py Он не является универсальным и его необходимо изменить в соответствии с вашей фактической конфигурацией.