整理代码
This commit is contained in:
commit
c7b4e178ec
364 changed files with 59691 additions and 0 deletions
16
video/v4l2/Access.cpp
Executable file
16
video/v4l2/Access.cpp
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
#include "Access.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
Access::Access(Device* device): m_device(device)
|
||||
{
|
||||
}
|
||||
|
||||
Access::~Access()
|
||||
{
|
||||
delete m_device;
|
||||
}
|
||||
}
|
||||
}
|
||||
73
video/v4l2/Access.h
Executable file
73
video/v4l2/Access.h
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
#include "Device.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
class Access
|
||||
{
|
||||
public:
|
||||
explicit Access(Device* device);
|
||||
virtual ~Access();
|
||||
|
||||
int getFd()
|
||||
{
|
||||
return m_device->getFd();
|
||||
}
|
||||
unsigned int getBufferSize()
|
||||
{
|
||||
return m_device->getBufferSize();
|
||||
}
|
||||
unsigned int getFormat()
|
||||
{
|
||||
return m_device->getFormat();
|
||||
}
|
||||
unsigned int getWidth()
|
||||
{
|
||||
return m_device->getWidth();
|
||||
}
|
||||
unsigned int getHeight()
|
||||
{
|
||||
return m_device->getHeight();
|
||||
}
|
||||
const std::string getName()
|
||||
{
|
||||
return m_device->getName();
|
||||
}
|
||||
|
||||
void queryFormat()
|
||||
{
|
||||
m_device->queryFormat();
|
||||
}
|
||||
int setFormat(unsigned int format, unsigned int width, unsigned int height)
|
||||
{
|
||||
return m_device->setFormat(format, width, height);
|
||||
}
|
||||
int setFps(int fps)
|
||||
{
|
||||
return m_device->setFps(fps);
|
||||
}
|
||||
|
||||
int isReady()
|
||||
{
|
||||
return m_device->isReady();
|
||||
}
|
||||
int start()
|
||||
{
|
||||
return m_device->start();
|
||||
}
|
||||
int stop()
|
||||
{
|
||||
return m_device->stop();
|
||||
}
|
||||
|
||||
private:
|
||||
Access(const Access&);
|
||||
Access& operator=(const Access&);
|
||||
|
||||
protected:
|
||||
Device* m_device;
|
||||
};
|
||||
}
|
||||
}
|
||||
63
video/v4l2/Capture.cpp
Executable file
63
video/v4l2/Capture.cpp
Executable file
|
|
@ -0,0 +1,63 @@
|
|||
#include <linux/videodev2.h>
|
||||
|
||||
#include "Capture.h"
|
||||
#include "MmapDevice.h"
|
||||
#include "ReadWriteDevice.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
Capture* Capture::create(const DeviceParameters& param)
|
||||
{
|
||||
Capture* videoCapture = NULL;
|
||||
Device* videoDevice = NULL;
|
||||
int caps = V4L2_CAP_VIDEO_CAPTURE;
|
||||
switch (param.m_iotype)
|
||||
{
|
||||
case IOTYPE_MMAP:
|
||||
videoDevice = new MmapDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
||||
caps |= V4L2_CAP_STREAMING;
|
||||
break;
|
||||
case IOTYPE_READWRITE:
|
||||
videoDevice = new ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
||||
caps |= V4L2_CAP_READWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (videoDevice && !videoDevice->init(caps))
|
||||
{
|
||||
delete videoDevice;
|
||||
videoDevice = NULL;
|
||||
}
|
||||
|
||||
if (videoDevice)
|
||||
{
|
||||
videoCapture = new Capture(videoDevice);
|
||||
}
|
||||
return videoCapture;
|
||||
}
|
||||
|
||||
Capture::Capture(Device* device): Access(device)
|
||||
{
|
||||
}
|
||||
|
||||
Capture::~Capture()
|
||||
{
|
||||
}
|
||||
|
||||
bool Capture::isReadable(timeval* tv)
|
||||
{
|
||||
int fd = m_device->getFd();
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
return (select(fd + 1, &fdset, NULL, NULL, tv) == 1);
|
||||
}
|
||||
|
||||
size_t Capture::read(char* buffer, size_t bufferSize)
|
||||
{
|
||||
return m_device->readInternal(buffer, bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
video/v4l2/Capture.h
Executable file
22
video/v4l2/Capture.h
Executable file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "Access.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
class Capture: public Access
|
||||
{
|
||||
protected:
|
||||
explicit Capture(Device* device);
|
||||
|
||||
public:
|
||||
static Capture* create(const DeviceParameters& param);
|
||||
virtual ~Capture();
|
||||
|
||||
size_t read(char* buffer, size_t bufferSize);
|
||||
bool isReadable(timeval* tv);
|
||||
};
|
||||
}
|
||||
}
|
||||
254
video/v4l2/Device.cpp
Executable file
254
video/v4l2/Device.cpp
Executable file
|
|
@ -0,0 +1,254 @@
|
|||
#include "Device.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
std::string Device::fourcc(unsigned int format)
|
||||
{
|
||||
char formatArray[] = {(char)(format & 0xff), (char)((format >> 8) & 0xff), (char)((format >> 16) & 0xff),
|
||||
(char)((format >> 24) & 0xff), 0};
|
||||
return std::string(formatArray, strlen(formatArray));
|
||||
}
|
||||
|
||||
unsigned int Device::fourcc(const char* format)
|
||||
{
|
||||
char fourcc[4];
|
||||
memset(&fourcc, 0, sizeof(fourcc));
|
||||
if (format != NULL)
|
||||
{
|
||||
strncpy(fourcc, format, 4);
|
||||
}
|
||||
return v4l2_fourcc(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
|
||||
}
|
||||
|
||||
Device::Device(const DeviceParameters& params, v4l2_buf_type deviceType)
|
||||
: m_params(params), m_fd(-1), m_deviceType(deviceType), m_bufferSize(0), m_format(0)
|
||||
{
|
||||
}
|
||||
|
||||
Device::~Device()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
void Device::close()
|
||||
{
|
||||
if (m_fd != -1)
|
||||
::close(m_fd);
|
||||
|
||||
m_fd = -1;
|
||||
}
|
||||
|
||||
void Device::queryFormat()
|
||||
{
|
||||
struct v4l2_format fmt;
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
fmt.type = m_deviceType;
|
||||
if (0 == ioctl(m_fd, VIDIOC_G_FMT, &fmt))
|
||||
{
|
||||
m_format = fmt.fmt.pix.pixelformat;
|
||||
m_width = fmt.fmt.pix.width;
|
||||
m_height = fmt.fmt.pix.height;
|
||||
m_bufferSize = fmt.fmt.pix.sizeimage;
|
||||
|
||||
logger().debug("%s: %s size: %ux%u bufferSize: %u", m_params.m_devName, fourcc(m_format), (uint32_t)m_width,
|
||||
(uint32_t)m_height, (uint32_t)m_bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
bool Device::init(unsigned int mandatoryCapabilities)
|
||||
{
|
||||
struct stat sb;
|
||||
if ((stat(m_params.m_devName.c_str(), &sb) == 0) && ((sb.st_mode & S_IFMT) == S_IFCHR))
|
||||
{
|
||||
if (initdevice(m_params.m_devName.c_str(), mandatoryCapabilities) == -1)
|
||||
{
|
||||
logger().error("%s: Cannot init device", m_params.m_devName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fd = open(m_params.m_devName.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
|
||||
}
|
||||
return (m_fd != -1);
|
||||
}
|
||||
|
||||
int Device::initdevice(const char* dev_name, unsigned int mandatoryCapabilities)
|
||||
{
|
||||
m_fd = open(dev_name, m_params.m_openFlags);
|
||||
if (m_fd < 0)
|
||||
{
|
||||
logger().error("%s: Cannot open device", m_params.m_devName);
|
||||
this->close();
|
||||
return -1;
|
||||
}
|
||||
if (checkCapabilities(m_fd, mandatoryCapabilities) != 0)
|
||||
{
|
||||
this->close();
|
||||
return -1;
|
||||
}
|
||||
if (configureFormat(m_fd) != 0)
|
||||
{
|
||||
this->close();
|
||||
return -1;
|
||||
}
|
||||
if (configureParam(m_fd, m_params.m_fps) != 0)
|
||||
{
|
||||
this->close();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
int Device::checkCapabilities(int fd, unsigned int mandatoryCapabilities)
|
||||
{
|
||||
struct v4l2_capability cap;
|
||||
memset(&(cap), 0, sizeof(cap));
|
||||
if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
|
||||
{
|
||||
logger().error("%s: Cannot get capabilities: %d(%s)", m_params.m_devName, errno, std::string(strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string str = "";
|
||||
if ((cap.capabilities & V4L2_CAP_VIDEO_OUTPUT))
|
||||
str += "output,";
|
||||
|
||||
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
str += "capture,";
|
||||
|
||||
if ((cap.capabilities & V4L2_CAP_READWRITE))
|
||||
str += "read/write,";
|
||||
|
||||
if ((cap.capabilities & V4L2_CAP_STREAMING))
|
||||
str += "streaming,";
|
||||
|
||||
if ((cap.capabilities & V4L2_CAP_TIMEPERFRAME))
|
||||
str += "timeperframe";
|
||||
|
||||
m_name = (char*)cap.card;
|
||||
logger().debug("%s(%s): support: %s", m_params.m_devName, m_name, str);
|
||||
|
||||
if ((cap.capabilities & mandatoryCapabilities) != mandatoryCapabilities)
|
||||
{
|
||||
logger().error("%s: Mandatory capability not available for device", m_params.m_devName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::configureFormat(int fd)
|
||||
{
|
||||
this->queryFormat();
|
||||
|
||||
unsigned int width = m_width;
|
||||
unsigned int height = m_height;
|
||||
if (m_params.m_width != 0)
|
||||
{
|
||||
width = m_params.m_width;
|
||||
}
|
||||
if (m_params.m_height != 0)
|
||||
{
|
||||
height = m_params.m_height;
|
||||
}
|
||||
if ((m_params.m_formatList.size() == 0) && (m_format != 0))
|
||||
{
|
||||
m_params.m_formatList.push_back(m_format);
|
||||
}
|
||||
|
||||
std::list<unsigned int>::iterator it;
|
||||
for (it = m_params.m_formatList.begin(); it != m_params.m_formatList.end(); ++it)
|
||||
{
|
||||
unsigned int format = *it;
|
||||
if (this->configureFormat(fd, format, width, height) == 0)
|
||||
{
|
||||
this->queryFormat();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Device::configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height)
|
||||
{
|
||||
struct v4l2_format fmt;
|
||||
memset(&(fmt), 0, sizeof(fmt));
|
||||
fmt.type = m_deviceType;
|
||||
if (ioctl(m_fd, VIDIOC_G_FMT, &fmt) == -1)
|
||||
{
|
||||
logger().error("%s: Cannot get format: %d(%s)", m_params.m_devName, errno, std::string(strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
if (width != 0)
|
||||
{
|
||||
fmt.fmt.pix.width = width;
|
||||
}
|
||||
if (height != 0)
|
||||
{
|
||||
fmt.fmt.pix.height = height;
|
||||
}
|
||||
if (format != 0)
|
||||
{
|
||||
fmt.fmt.pix.pixelformat = format;
|
||||
}
|
||||
|
||||
if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1)
|
||||
{
|
||||
logger().error("%s: Cannot set format: %d(%s)", m_params.m_devName, errno, std::string(strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fmt.fmt.pix.pixelformat != format)
|
||||
{
|
||||
logger().error("%s: Cannot set pixelformat to: %s format is ", m_params.m_devName, fourcc(format),
|
||||
fourcc(fmt.fmt.pix.pixelformat));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fmt.fmt.pix.width != width) || (fmt.fmt.pix.height != height))
|
||||
{
|
||||
logger().warning("%s: Cannot set size to: %ux%u size is: %ux%u", m_params.m_devName, (uint32_t)width,
|
||||
(uint32_t)height, (uint32_t)fmt.fmt.pix.width, (uint32_t)fmt.fmt.pix.height);
|
||||
}
|
||||
|
||||
m_format = fmt.fmt.pix.pixelformat;
|
||||
m_width = fmt.fmt.pix.width;
|
||||
m_height = fmt.fmt.pix.height;
|
||||
m_bufferSize = fmt.fmt.pix.sizeimage;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Device::configureParam(int fd, int fps)
|
||||
{
|
||||
if (fps != 0)
|
||||
{
|
||||
struct v4l2_streamparm param;
|
||||
memset(&(param), 0, sizeof(param));
|
||||
param.type = m_deviceType;
|
||||
param.parm.capture.timeperframe.numerator = 1;
|
||||
param.parm.capture.timeperframe.denominator = fps;
|
||||
|
||||
if (ioctl(fd, VIDIOC_S_PARM, ¶m) == -1)
|
||||
{
|
||||
logger().warning("%s: Cannot set param for device: %d(%s)", m_params.m_devName, errno,
|
||||
std::string(strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
165
video/v4l2/Device.h
Executable file
165
video/v4l2/Device.h
Executable file
|
|
@ -0,0 +1,165 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <linux/videodev2.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifndef V4L2_PIX_FMT_VP8
|
||||
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_VP9
|
||||
#define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0')
|
||||
#endif
|
||||
#ifndef V4L2_PIX_FMT_HEVC
|
||||
#define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C')
|
||||
#endif
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
enum V4l2IoType
|
||||
{
|
||||
IOTYPE_READWRITE,
|
||||
IOTYPE_MMAP
|
||||
};
|
||||
|
||||
struct DeviceParameters
|
||||
{
|
||||
DeviceParameters(const char* devname, const std::list<unsigned int>& formatList, unsigned int width,
|
||||
unsigned int height, int fps, V4l2IoType ioType = IOTYPE_MMAP, int verbose = 0,
|
||||
int openFlags = O_RDWR | O_NONBLOCK)
|
||||
: m_devName(devname), m_formatList(formatList), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType),
|
||||
m_verbose(verbose), m_openFlags(openFlags)
|
||||
{
|
||||
}
|
||||
|
||||
DeviceParameters(const char* devname, unsigned int format, unsigned int width, unsigned int height, int fps,
|
||||
V4l2IoType ioType = IOTYPE_MMAP, int verbose = 0, int openFlags = O_RDWR | O_NONBLOCK)
|
||||
: m_devName(devname), m_width(width), m_height(height), m_fps(fps), m_iotype(ioType), m_verbose(verbose),
|
||||
m_openFlags(openFlags)
|
||||
{
|
||||
if (format)
|
||||
{
|
||||
m_formatList.push_back(format);
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_devName;
|
||||
std::list<unsigned int> m_formatList;
|
||||
unsigned int m_width;
|
||||
unsigned int m_height;
|
||||
int m_fps;
|
||||
V4l2IoType m_iotype;
|
||||
int m_verbose;
|
||||
int m_openFlags;
|
||||
};
|
||||
|
||||
class Device
|
||||
{
|
||||
friend class Capture;
|
||||
friend class Output;
|
||||
|
||||
protected:
|
||||
void close();
|
||||
|
||||
int initdevice(const char* dev_name, unsigned int mandatoryCapabilities);
|
||||
int checkCapabilities(int fd, unsigned int mandatoryCapabilities);
|
||||
int configureFormat(int fd);
|
||||
int configureFormat(int fd, unsigned int format, unsigned int width, unsigned int height);
|
||||
int configureParam(int fd, int fps);
|
||||
|
||||
virtual bool init(unsigned int mandatoryCapabilities);
|
||||
virtual size_t writeInternal(char*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual bool startPartialWrite()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual size_t writePartialInternal(char*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual bool endPartialWrite()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual size_t readInternal(char*, size_t)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
public:
|
||||
Device(const DeviceParameters& params, v4l2_buf_type deviceType);
|
||||
virtual ~Device();
|
||||
|
||||
virtual bool isReady()
|
||||
{
|
||||
return (m_fd != -1);
|
||||
}
|
||||
virtual bool start()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
virtual bool stop()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
unsigned int getBufferSize()
|
||||
{
|
||||
return m_bufferSize;
|
||||
}
|
||||
unsigned int getFormat()
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
unsigned int getWidth()
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
unsigned int getHeight()
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
int getFd()
|
||||
{
|
||||
return m_fd;
|
||||
}
|
||||
void queryFormat();
|
||||
|
||||
int setFormat(unsigned int format, unsigned int width, unsigned int height)
|
||||
{
|
||||
return this->configureFormat(m_fd, format, width, height);
|
||||
}
|
||||
int setFps(int fps)
|
||||
{
|
||||
return this->configureParam(m_fd, fps);
|
||||
}
|
||||
|
||||
static std::string fourcc(unsigned int format);
|
||||
static unsigned int fourcc(const char* format);
|
||||
|
||||
protected:
|
||||
DeviceParameters m_params;
|
||||
int m_fd;
|
||||
v4l2_buf_type m_deviceType;
|
||||
|
||||
unsigned int m_bufferSize;
|
||||
unsigned int m_format;
|
||||
unsigned int m_width;
|
||||
unsigned int m_height;
|
||||
|
||||
struct v4l2_buffer m_partialWriteBuf;
|
||||
bool m_partialWriteInProgress;
|
||||
std::string m_name;
|
||||
};
|
||||
}
|
||||
}
|
||||
158
video/v4l2/Input.cpp
Normal file
158
video/v4l2/Input.cpp
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Input.h"
|
||||
#include "Capture.h"
|
||||
#include "InputFormat.h"
|
||||
#include "../core/System.h"
|
||||
#include "Logger.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
Input::Input(const std::string& name): VideoComponent(name), _task(name)
|
||||
{
|
||||
}
|
||||
|
||||
Input::~Input()
|
||||
{
|
||||
}
|
||||
|
||||
void Input::start()
|
||||
{
|
||||
_task.run(
|
||||
[this](std::atomic<bool>& isCancelled) -> void
|
||||
{
|
||||
const std::string path = getPath();
|
||||
|
||||
setCodecID(Core::CodecID::MJPEG);
|
||||
setSignalLost(true);
|
||||
|
||||
while (!isCancelled)
|
||||
{
|
||||
Poco::SharedPtr<Capture> pCapture;
|
||||
InputFormat::Collection formats;
|
||||
try
|
||||
{
|
||||
InputFormat::enumerate(path, formats);
|
||||
|
||||
if (formats.empty())
|
||||
{
|
||||
Poco::Thread::sleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto& c : formats)
|
||||
{
|
||||
if (V4L2_PIX_FMT_MJPEG == c.pixelFormat && !c.resolutions.empty())
|
||||
{
|
||||
auto p = c.resolutions.begin();
|
||||
uint64_t maxProduct = 0;
|
||||
for (auto it = c.resolutions.begin(); it != c.resolutions.end(); ++it)
|
||||
{
|
||||
uint32_t fps = it->width * it->height > 3686400 ? 30 : 60;
|
||||
if (it->width <= 2560 && it->height <= 1440 && it->fps <= fps)
|
||||
{
|
||||
uint64_t product = static_cast<uint64_t>(it->width) * it->height * it->fps;
|
||||
if (product > maxProduct)
|
||||
{
|
||||
logger().debug("%s: ", name());
|
||||
maxProduct = product;
|
||||
p = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeviceParameters param(path.c_str(), c.pixelFormat, p->width, p->height, p->fps);
|
||||
pCapture = Capture::create(param);
|
||||
if (pCapture.isNull())
|
||||
continue;
|
||||
|
||||
logger().information("%s: Camera [%s] found, %s, %ux%u@%u", name(), pCapture->getName(),
|
||||
c.description, p->width, p->height, p->fps);
|
||||
|
||||
setWidth(p->width);
|
||||
setHeight(p->height);
|
||||
setFrameRate(p->fps);
|
||||
setSignalLost(false);
|
||||
serialCodeManager().increment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Poco::Thread::sleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t* pBuffer = nullptr;
|
||||
;
|
||||
while (!isCancelled)
|
||||
{
|
||||
try
|
||||
{
|
||||
struct timeval tv = {1, 0};
|
||||
if (!pCapture->isReadable(&tv))
|
||||
break;
|
||||
|
||||
int len = pCapture->getBufferSize();
|
||||
pBuffer = new uint8_t[len];
|
||||
int rsize = pCapture->read((char*)pBuffer, len);
|
||||
if (rsize < 0)
|
||||
{
|
||||
logger().error("%s: Failed to read frame!", pCapture->getName());
|
||||
delete pBuffer;
|
||||
pBuffer = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
int64_t ts = Core::System::timestamp();
|
||||
Core::Packet::Ptr pPacket = new Core::Packet(
|
||||
serialCodeManager().code(), Core::Packet::FLAG_IS_VIDEO, pBuffer, rsize, ts, ts);
|
||||
|
||||
pBuffer = nullptr;
|
||||
postToNextComponents(sharedFromThis(), pPacket, Core::MediaType::VIDEO);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (pBuffer)
|
||||
{
|
||||
delete pBuffer;
|
||||
pBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSignalLost(true);
|
||||
logger().warning("%s: Camera [%s] lost!", name(), pCapture->getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Input::stop()
|
||||
{
|
||||
_task.cancel();
|
||||
}
|
||||
|
||||
void Input::onConfigChanged(ParameterNames& names)
|
||||
{
|
||||
if (!started())
|
||||
return;
|
||||
|
||||
if (names.exists(_Path))
|
||||
{
|
||||
stop();
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
video/v4l2/Input.h
Normal file
44
video/v4l2/Input.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef A523395E_7DEF_449B_B4DD_5FEE9147BE39
|
||||
#define A523395E_7DEF_449B_B4DD_5FEE9147BE39
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "../core/VideoComponent.h"
|
||||
#include "util/SimpleFactory.h"
|
||||
#include "util/Task.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
class Input: public Core::VideoComponent, public ::Util::SimpleFactory<Input, const std::string&>
|
||||
{
|
||||
public:
|
||||
using Ptr = Poco::AutoPtr<Input>;
|
||||
|
||||
public:
|
||||
Input(const std::string& name);
|
||||
~Input();
|
||||
|
||||
public:
|
||||
CONFIGURABLE_DECLARE_PARAMETER(CodecID, Core::CodecID);
|
||||
CONFIGURABLE_DECLARE_PARAMETER(Path, std::string);
|
||||
|
||||
protected:
|
||||
void start() override;
|
||||
void stop() override;
|
||||
void onConfigChanged(ParameterNames& names) override;
|
||||
|
||||
private:
|
||||
Util::Task _task;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
83
video/v4l2/InputFormat.cpp
Normal file
83
video/v4l2/InputFormat.cpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "InputFormat.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include <Poco/Format.h>
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DEFINE
|
||||
*******************************************************************************
|
||||
*/
|
||||
void InputFormat::enumerate(const std::string& deviceName, InputFormat::Collection& c)
|
||||
{
|
||||
int fd = open(deviceName.c_str(), O_RDWR);
|
||||
if (fd < 0)
|
||||
throw Poco::InvalidAccessException(Poco::format("Video::V4l2::InputFormat: Open %s FAIL: %d", deviceName, fd));
|
||||
|
||||
struct v4l2_fmtdesc fmt;
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmt.index = 0;
|
||||
while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) == 0)
|
||||
{
|
||||
InputFormat format;
|
||||
format.pixelFormat = fmt.pixelformat;
|
||||
format.description = (char*)fmt.description;
|
||||
|
||||
struct v4l2_frmsizeenum frmsize;
|
||||
frmsize.index = 0;
|
||||
frmsize.pixel_format = fmt.pixelformat;
|
||||
while (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
|
||||
{
|
||||
switch (frmsize.type)
|
||||
{
|
||||
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
||||
{
|
||||
struct v4l2_frmivalenum frameinterval;
|
||||
|
||||
frameinterval.width = frmsize.discrete.width;
|
||||
frameinterval.height = frmsize.discrete.height;
|
||||
frameinterval.pixel_format = fmt.pixelformat;
|
||||
frameinterval.type = V4L2_FRMIVAL_TYPE_DISCRETE;
|
||||
frameinterval.index = 0;
|
||||
while (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameinterval) == 0)
|
||||
{
|
||||
InputFormat::Resolution resolution;
|
||||
resolution.width = frameinterval.width;
|
||||
resolution.height = frameinterval.height;
|
||||
resolution.fps = frameinterval.discrete.denominator / frameinterval.discrete.numerator;
|
||||
format.resolutions.push_back(resolution);
|
||||
|
||||
frameinterval.index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
frmsize.index++;
|
||||
}
|
||||
|
||||
format.resolutions.sort([](auto& a, auto& b) { return a.width * a.height > b.width * b.height; });
|
||||
|
||||
c.push_back(format);
|
||||
fmt.index++;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
video/v4l2/InputFormat.h
Normal file
39
video/v4l2/InputFormat.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef D1EA41B1_FDDE_44D4_BDD5_2BA3EEBAC3B5
|
||||
#define D1EA41B1_FDDE_44D4_BDD5_2BA3EEBAC3B5
|
||||
/*
|
||||
*******************************************************************************
|
||||
* INCLUDE
|
||||
*******************************************************************************
|
||||
*/
|
||||
#include "Capture.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
/*
|
||||
*******************************************************************************
|
||||
* CLASS DECLARE
|
||||
*******************************************************************************
|
||||
*/
|
||||
struct InputFormat
|
||||
{
|
||||
struct Resolution
|
||||
{
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t fps;
|
||||
};
|
||||
|
||||
using Collection = std::list<InputFormat>;
|
||||
|
||||
uint32_t pixelFormat;
|
||||
std::string description;
|
||||
std::list<Resolution> resolutions;
|
||||
|
||||
public:
|
||||
static void enumerate(const std::string& deviceName, Collection& c);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
299
video/v4l2/MmapDevice.cpp
Executable file
299
video/v4l2/MmapDevice.cpp
Executable file
|
|
@ -0,0 +1,299 @@
|
|||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "MmapDevice.h"
|
||||
#include "Logger.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
MmapDevice::MmapDevice(const DeviceParameters& params, v4l2_buf_type deviceType)
|
||||
: Device(params, deviceType), n_buffers(0)
|
||||
{
|
||||
memset(&m_buffer, 0, sizeof(m_buffer));
|
||||
}
|
||||
|
||||
bool MmapDevice::init(unsigned int mandatoryCapabilities)
|
||||
{
|
||||
bool ret = Device::init(mandatoryCapabilities);
|
||||
if (ret)
|
||||
{
|
||||
ret = this->start();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MmapDevice::~MmapDevice()
|
||||
{
|
||||
this->stop();
|
||||
}
|
||||
|
||||
bool MmapDevice::start()
|
||||
{
|
||||
bool success = true;
|
||||
struct v4l2_requestbuffers req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.count = V4L2MMAP_NBBUFFER;
|
||||
req.type = m_deviceType;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req))
|
||||
{
|
||||
if (EINVAL == errno)
|
||||
{
|
||||
logger().error("%s: does not support memory mapping", m_params.m_devName);
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().error("VIDIOC_REQBUFS");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&m_buffer, 0, sizeof(m_buffer));
|
||||
for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = m_deviceType;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = n_buffers;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_QUERYBUF, &buf))
|
||||
{
|
||||
logger().error("VIDIOC_QUERYBUF");
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().debug("%s: [%u]: size: %u offset: %u", m_params.m_devName, (uint32_t)n_buffers,
|
||||
(uint32_t)buf.length, (uint32_t)buf.m.offset);
|
||||
|
||||
m_buffer[n_buffers].length = buf.length;
|
||||
if (!m_buffer[n_buffers].length)
|
||||
{
|
||||
m_buffer[n_buffers].length = buf.bytesused;
|
||||
}
|
||||
m_buffer[n_buffers].start =
|
||||
mmap(NULL, m_buffer[n_buffers].length, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, buf.m.offset);
|
||||
|
||||
if (MAP_FAILED == m_buffer[n_buffers].start)
|
||||
{
|
||||
logger().error("mmap");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = m_deviceType;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
logger().error("VIDIOC_QBUF");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
int type = m_deviceType;
|
||||
if (-1 == ioctl(m_fd, VIDIOC_STREAMON, &type))
|
||||
{
|
||||
logger().error("VIDIOC_STREAMON");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool MmapDevice::stop()
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
int type = m_deviceType;
|
||||
if (-1 == ioctl(m_fd, VIDIOC_STREAMOFF, &type))
|
||||
{
|
||||
logger().error("VIDIOC_STREAMOFF");
|
||||
success = false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < n_buffers; ++i)
|
||||
{
|
||||
if (-1 == munmap(m_buffer[i].start, m_buffer[i].length))
|
||||
{
|
||||
logger().error("munmap");
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
struct v4l2_requestbuffers req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.count = 0;
|
||||
req.type = m_deviceType;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
if (-1 == ioctl(m_fd, VIDIOC_REQBUFS, &req))
|
||||
{
|
||||
logger().error("VIDIOC_REQBUFS");
|
||||
success = false;
|
||||
}
|
||||
|
||||
n_buffers = 0;
|
||||
return success;
|
||||
}
|
||||
|
||||
size_t MmapDevice::readInternal(char* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t size = 0;
|
||||
if (n_buffers > 0)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = m_deviceType;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf))
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
size = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger().error("VIDIOC_DQBUF");
|
||||
size = -1;
|
||||
}
|
||||
}
|
||||
else if (buf.index < n_buffers)
|
||||
{
|
||||
size = buf.bytesused;
|
||||
if (size > bufferSize)
|
||||
{
|
||||
size = bufferSize;
|
||||
logger().warning("%s: buffer truncated available: %u needed: %u", m_params.m_devName,
|
||||
(uint32_t)bufferSize, (uint32_t)buf.bytesused);
|
||||
}
|
||||
memcpy(buffer, m_buffer[buf.index].start, size);
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
logger().error("VIDIOC_QBUF");
|
||||
size = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t MmapDevice::writeInternal(char* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t size = 0;
|
||||
if (n_buffers > 0)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = m_deviceType;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &buf))
|
||||
{
|
||||
logger().error("VIDIOC_DQBUF");
|
||||
size = -1;
|
||||
}
|
||||
else if (buf.index < n_buffers)
|
||||
{
|
||||
size = bufferSize;
|
||||
if (size > buf.length)
|
||||
{
|
||||
logger().warning("%s: buffer truncated available: %u needed: %u", m_params.m_devName,
|
||||
(uint32_t)buf.length, (uint32_t)size);
|
||||
size = buf.length;
|
||||
}
|
||||
memcpy(m_buffer[buf.index].start, buffer, size);
|
||||
buf.bytesused = size;
|
||||
|
||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
logger().error("VIDIOC_QBUF");
|
||||
size = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool MmapDevice::startPartialWrite()
|
||||
{
|
||||
if (n_buffers <= 0)
|
||||
return false;
|
||||
if (m_partialWriteInProgress)
|
||||
return false;
|
||||
memset(&m_partialWriteBuf, 0, sizeof(m_partialWriteBuf));
|
||||
m_partialWriteBuf.type = m_deviceType;
|
||||
m_partialWriteBuf.memory = V4L2_MEMORY_MMAP;
|
||||
if (-1 == ioctl(m_fd, VIDIOC_DQBUF, &m_partialWriteBuf))
|
||||
{
|
||||
logger().error("VIDIOC_DQBUF");
|
||||
return false;
|
||||
}
|
||||
m_partialWriteBuf.bytesused = 0;
|
||||
m_partialWriteInProgress = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t MmapDevice::writePartialInternal(char* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t new_size = 0;
|
||||
size_t size = 0;
|
||||
if ((n_buffers > 0) && m_partialWriteInProgress)
|
||||
{
|
||||
if (m_partialWriteBuf.index < n_buffers)
|
||||
{
|
||||
new_size = m_partialWriteBuf.bytesused + bufferSize;
|
||||
if (new_size > m_partialWriteBuf.length)
|
||||
{
|
||||
logger().warning("%s: buffer truncated available: %u needed: %u", m_params.m_devName,
|
||||
(uint32_t)m_partialWriteBuf.length, (uint32_t)new_size);
|
||||
new_size = m_partialWriteBuf.length;
|
||||
}
|
||||
size = new_size - m_partialWriteBuf.bytesused;
|
||||
memcpy(&((char*)m_buffer[m_partialWriteBuf.index].start)[m_partialWriteBuf.bytesused], buffer, size);
|
||||
|
||||
m_partialWriteBuf.bytesused += size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool MmapDevice::endPartialWrite()
|
||||
{
|
||||
if (!m_partialWriteInProgress)
|
||||
return false;
|
||||
if (n_buffers <= 0)
|
||||
{
|
||||
m_partialWriteInProgress = false;
|
||||
return true;
|
||||
}
|
||||
if (-1 == ioctl(m_fd, VIDIOC_QBUF, &m_partialWriteBuf))
|
||||
{
|
||||
logger().error("VIDIOC_QBUF");
|
||||
m_partialWriteInProgress = false;
|
||||
return true;
|
||||
}
|
||||
m_partialWriteInProgress = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
video/v4l2/MmapDevice.h
Executable file
43
video/v4l2/MmapDevice.h
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "Device.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
#define V4L2MMAP_NBBUFFER 10
|
||||
|
||||
class MmapDevice: public Device
|
||||
{
|
||||
protected:
|
||||
size_t writeInternal(char* buffer, size_t bufferSize);
|
||||
bool startPartialWrite();
|
||||
size_t writePartialInternal(char*, size_t);
|
||||
bool endPartialWrite();
|
||||
size_t readInternal(char* buffer, size_t bufferSize);
|
||||
|
||||
public:
|
||||
MmapDevice(const DeviceParameters& params, v4l2_buf_type deviceType);
|
||||
virtual ~MmapDevice();
|
||||
|
||||
virtual bool init(unsigned int mandatoryCapabilities);
|
||||
virtual bool isReady()
|
||||
{
|
||||
return ((m_fd != -1) && (n_buffers != 0));
|
||||
}
|
||||
virtual bool start();
|
||||
virtual bool stop();
|
||||
|
||||
protected:
|
||||
unsigned int n_buffers;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
void* start;
|
||||
size_t length;
|
||||
};
|
||||
buffer m_buffer[V4L2MMAP_NBBUFFER];
|
||||
};
|
||||
}
|
||||
}
|
||||
81
video/v4l2/Output.cpp
Executable file
81
video/v4l2/Output.cpp
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#include "Output.h"
|
||||
#include "MmapDevice.h"
|
||||
#include "ReadWriteDevice.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
Output* Output::create(const DeviceParameters& param)
|
||||
{
|
||||
Output* videoOutput = NULL;
|
||||
Device* videoDevice = NULL;
|
||||
int caps = V4L2_CAP_VIDEO_OUTPUT;
|
||||
switch (param.m_iotype)
|
||||
{
|
||||
case IOTYPE_MMAP:
|
||||
videoDevice = new MmapDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
||||
caps |= V4L2_CAP_STREAMING;
|
||||
break;
|
||||
|
||||
case IOTYPE_READWRITE:
|
||||
videoDevice = new ReadWriteDevice(param, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
||||
caps |= V4L2_CAP_READWRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (videoDevice && !videoDevice->init(caps))
|
||||
{
|
||||
delete videoDevice;
|
||||
videoDevice = NULL;
|
||||
}
|
||||
|
||||
if (videoDevice)
|
||||
{
|
||||
videoOutput = new Output(videoDevice);
|
||||
}
|
||||
return videoOutput;
|
||||
}
|
||||
|
||||
Output::Output(Device* device): Access(device)
|
||||
{
|
||||
}
|
||||
|
||||
Output::~Output()
|
||||
{
|
||||
}
|
||||
|
||||
bool Output::isWritable(timeval* tv)
|
||||
{
|
||||
int fd = m_device->getFd();
|
||||
fd_set fdset;
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(fd, &fdset);
|
||||
return (select(fd + 1, NULL, &fdset, NULL, tv) == 1);
|
||||
}
|
||||
|
||||
size_t Output::write(char* buffer, size_t bufferSize)
|
||||
{
|
||||
return m_device->writeInternal(buffer, bufferSize);
|
||||
}
|
||||
|
||||
bool Output::startPartialWrite()
|
||||
{
|
||||
return m_device->startPartialWrite();
|
||||
}
|
||||
|
||||
size_t Output::writePartial(char* buffer, size_t bufferSize)
|
||||
{
|
||||
return m_device->writePartialInternal(buffer, bufferSize);
|
||||
}
|
||||
|
||||
bool Output::endPartialWrite()
|
||||
{
|
||||
return m_device->endPartialWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
25
video/v4l2/Output.h
Executable file
25
video/v4l2/Output.h
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "Access.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
class Output: public Access
|
||||
{
|
||||
protected:
|
||||
explicit Output(Device* device);
|
||||
|
||||
public:
|
||||
static Output* create(const DeviceParameters& param);
|
||||
virtual ~Output();
|
||||
|
||||
size_t write(char* buffer, size_t bufferSize);
|
||||
bool isWritable(timeval* tv);
|
||||
bool startPartialWrite();
|
||||
size_t writePartial(char* buffer, size_t bufferSize);
|
||||
bool endPartialWrite();
|
||||
};
|
||||
}
|
||||
}
|
||||
23
video/v4l2/ReadWriteDevice.cpp
Executable file
23
video/v4l2/ReadWriteDevice.cpp
Executable file
|
|
@ -0,0 +1,23 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "ReadWriteDevice.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
ReadWriteDevice::ReadWriteDevice(const DeviceParameters& params, v4l2_buf_type deviceType): Device(params, deviceType)
|
||||
{
|
||||
}
|
||||
|
||||
size_t ReadWriteDevice::writeInternal(char* buffer, size_t bufferSize)
|
||||
{
|
||||
return ::write(m_fd, buffer, bufferSize);
|
||||
}
|
||||
|
||||
size_t ReadWriteDevice::readInternal(char* buffer, size_t bufferSize)
|
||||
{
|
||||
return ::read(m_fd, buffer, bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
video/v4l2/ReadWriteDevice.h
Executable file
19
video/v4l2/ReadWriteDevice.h
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "Device.h"
|
||||
|
||||
namespace Video
|
||||
{
|
||||
namespace V4L2
|
||||
{
|
||||
class ReadWriteDevice: public Device
|
||||
{
|
||||
protected:
|
||||
virtual size_t writeInternal(char* buffer, size_t bufferSize);
|
||||
virtual size_t readInternal(char* buffer, size_t bufferSize);
|
||||
|
||||
public:
|
||||
ReadWriteDevice(const DeviceParameters& params, v4l2_buf_type deviceType);
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue