mirror of
https://github.com/Motion-Project/motion.git
synced 2026-06-11 15:24:42 -04:00
1185 lines
34 KiB
C++
1185 lines
34 KiB
C++
/*
|
|
* This file is part of MotionPlus.
|
|
*
|
|
* MotionPlus is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MotionPlus is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MotionPlus. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "motionplus.hpp"
|
|
#include "camera.hpp"
|
|
#include "conf.hpp"
|
|
#include "logger.hpp"
|
|
#include "util.hpp"
|
|
#include "rotate.hpp"
|
|
#include "video_convert.hpp"
|
|
#include "video_v4l2.hpp"
|
|
#include <sys/mman.h>
|
|
|
|
#define MMAP_BUFFERS 4
|
|
#define MIN_MMAP_BUFFERS 2
|
|
|
|
#ifdef HAVE_V4L2
|
|
|
|
void cls_v4l2cam::palette_add(uint p_v4l2id)
|
|
{
|
|
char tmp4cc[5];
|
|
ctx_palette_item p_itm;
|
|
|
|
sprintf(tmp4cc,"%c%c%c%c"
|
|
, p_v4l2id >> 0 , p_v4l2id >> 8
|
|
, p_v4l2id >> 16, p_v4l2id >> 24);
|
|
p_itm.v4l2id = p_v4l2id;
|
|
p_itm.fourcc = tmp4cc;
|
|
palette.push_back(p_itm);
|
|
}
|
|
|
|
void cls_v4l2cam::palette_init()
|
|
{
|
|
palette.clear();
|
|
|
|
palette_add(V4L2_PIX_FMT_SN9C10X);
|
|
palette_add(V4L2_PIX_FMT_SBGGR16);
|
|
palette_add(V4L2_PIX_FMT_SBGGR8);
|
|
palette_add(V4L2_PIX_FMT_SPCA561);
|
|
palette_add(V4L2_PIX_FMT_SGBRG8);
|
|
palette_add(V4L2_PIX_FMT_SGRBG8);
|
|
palette_add(V4L2_PIX_FMT_PAC207);
|
|
palette_add(V4L2_PIX_FMT_PJPG);
|
|
palette_add(V4L2_PIX_FMT_MJPEG);
|
|
palette_add(V4L2_PIX_FMT_JPEG);
|
|
palette_add(V4L2_PIX_FMT_RGB24);
|
|
palette_add(V4L2_PIX_FMT_SPCA501);
|
|
palette_add(V4L2_PIX_FMT_SPCA505);
|
|
palette_add(V4L2_PIX_FMT_SPCA508);
|
|
palette_add(V4L2_PIX_FMT_UYVY);
|
|
palette_add(V4L2_PIX_FMT_YUYV);
|
|
palette_add(V4L2_PIX_FMT_YUV422P);
|
|
palette_add(V4L2_PIX_FMT_YUV420);
|
|
palette_add(V4L2_PIX_FMT_Y10);
|
|
palette_add(V4L2_PIX_FMT_Y12);
|
|
palette_add(V4L2_PIX_FMT_GREY);
|
|
palette_add(V4L2_PIX_FMT_SRGGB8);
|
|
}
|
|
|
|
/* Execute the request to the device */
|
|
int cls_v4l2cam::xioctl(unsigned long request, void *arg)
|
|
{
|
|
int retcd;
|
|
|
|
if (fd_device < 0) {
|
|
return -1;
|
|
}
|
|
|
|
do {
|
|
retcd = ioctl(fd_device, request, arg);
|
|
} while (-1 == retcd && EINTR == errno);
|
|
|
|
return retcd;
|
|
}
|
|
|
|
void cls_v4l2cam::device_close()
|
|
{
|
|
close(fd_device);
|
|
fd_device = -1;
|
|
}
|
|
|
|
/* Print the device controls to the log */
|
|
void cls_v4l2cam::ctrls_log()
|
|
{
|
|
it_v4l2ctrl it;
|
|
|
|
if (device_ctrls.size() >0) {
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("---------Controls---------"));
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, _(" V4L2 ID : Name : Range"));
|
|
for (it = device_ctrls.begin();it!=device_ctrls.end();it++){
|
|
if (it->ctrl_menuitem) {
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, " %s : %s"
|
|
,it->ctrl_iddesc.c_str()
|
|
,it->ctrl_name.c_str());
|
|
} else {
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s : %s : %d to %d"
|
|
,it->ctrl_iddesc.c_str()
|
|
,it->ctrl_name.c_str()
|
|
,it->ctrl_minimum
|
|
,it->ctrl_maximum);
|
|
}
|
|
}
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, "--------------------------");
|
|
}
|
|
}
|
|
|
|
/* Get names of the controls and menu items the device supports */
|
|
void cls_v4l2cam::ctrls_list()
|
|
{
|
|
int indx;
|
|
v4l2_queryctrl vid_ctrl;
|
|
v4l2_querymenu vid_menu;
|
|
ctx_v4l2ctrl_item vid_item;
|
|
char tmp_desc[40];
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
device_ctrls.clear();
|
|
memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl));
|
|
vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
|
|
while (xioctl(VIDIOC_QUERYCTRL, &vid_ctrl) == 0) {
|
|
if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) {
|
|
vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
|
|
continue;
|
|
}
|
|
vid_item.ctrl_id = vid_ctrl.id;
|
|
vid_item.ctrl_type = vid_ctrl.type;
|
|
vid_item.ctrl_default = vid_ctrl.default_value;
|
|
vid_item.ctrl_currval = vid_ctrl.default_value;
|
|
vid_item.ctrl_newval = vid_ctrl.default_value;
|
|
vid_item.ctrl_menuitem = false;
|
|
vid_item.ctrl_name =(char*)vid_ctrl.name;
|
|
sprintf(tmp_desc,"ID%08d",vid_ctrl.id);
|
|
vid_item.ctrl_iddesc = tmp_desc;
|
|
vid_item.ctrl_minimum = vid_ctrl.minimum;
|
|
vid_item.ctrl_maximum = vid_ctrl.maximum;
|
|
device_ctrls.push_back(vid_item);
|
|
|
|
if (vid_ctrl.type == V4L2_CTRL_TYPE_MENU) {
|
|
for (indx = vid_ctrl.minimum; indx <= vid_ctrl.maximum; indx++) {
|
|
memset(&vid_menu, 0, sizeof(struct v4l2_querymenu));
|
|
vid_menu.id = vid_ctrl.id;
|
|
vid_menu.index = (uint)indx;
|
|
if (xioctl(VIDIOC_QUERYMENU, &vid_menu) == 0) {
|
|
vid_item.ctrl_id = vid_ctrl.id;
|
|
vid_item.ctrl_type = 0;
|
|
vid_item.ctrl_menuitem = true;
|
|
vid_item.ctrl_name =(char*)vid_menu.name;
|
|
sprintf(tmp_desc,"menu item: Value %d",indx);
|
|
vid_item.ctrl_iddesc = tmp_desc;
|
|
vid_item.ctrl_minimum = 0;
|
|
vid_item.ctrl_maximum = 0;
|
|
device_ctrls.push_back(vid_item);
|
|
}
|
|
}
|
|
}
|
|
vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
|
|
}
|
|
|
|
if (device_ctrls.size() == 0) {
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("No Controls found for device"));
|
|
return;
|
|
}
|
|
|
|
ctrls_log();
|
|
|
|
}
|
|
|
|
/* Set the control array items to the device */
|
|
void cls_v4l2cam::ctrls_set()
|
|
{
|
|
int retcd;
|
|
struct v4l2_control vid_ctrl;
|
|
it_v4l2ctrl it;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
for (it = device_ctrls.begin();it!=device_ctrls.end();it++) {
|
|
if (it->ctrl_menuitem == false) {
|
|
if (it->ctrl_currval != it->ctrl_newval) {
|
|
memset(&vid_ctrl, 0, sizeof (struct v4l2_control));
|
|
vid_ctrl.id = it->ctrl_id;
|
|
vid_ctrl.value = it->ctrl_newval;
|
|
retcd = xioctl(VIDIOC_S_CTRL, &vid_ctrl);
|
|
if (retcd < 0) {
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("setting control %s \"%s\" to %d failed with return code %d")
|
|
,it->ctrl_iddesc.c_str(), it->ctrl_name.c_str()
|
|
,it->ctrl_newval, retcd);
|
|
} else {
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
|
|
,_("Set control \"%s\" to value %d")
|
|
,it->ctrl_name.c_str(), it->ctrl_newval);
|
|
it->ctrl_currval = it->ctrl_newval;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void cls_v4l2cam::parms_set()
|
|
{
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it_p;
|
|
it_v4l2ctrl it_d;
|
|
|
|
if (device_ctrls.size() == 0) {
|
|
params->update_params = false;
|
|
return;
|
|
}
|
|
|
|
for (it_d = device_ctrls.begin(); it_d != device_ctrls.end(); it_d++) {
|
|
it_d->ctrl_newval = it_d->ctrl_default;
|
|
for (it_p = lst->begin(); it_p != lst->end(); it_p++) {
|
|
if ((it_d->ctrl_iddesc == it_p->param_name) ||
|
|
(it_d->ctrl_name == it_p->param_name)) {
|
|
switch (it_d->ctrl_type) {
|
|
case V4L2_CTRL_TYPE_MENU:
|
|
/*FALLTHROUGH*/
|
|
case V4L2_CTRL_TYPE_INTEGER:
|
|
if (mtoi(it_p->param_value.c_str()) < it_d->ctrl_minimum) {
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("%s control option value %s is below minimum. Skipping...")
|
|
, it_d->ctrl_name.c_str()
|
|
, it_p->param_value.c_str()
|
|
, it_d->ctrl_minimum);
|
|
} else if (mtoi(it_p->param_value.c_str()) > it_d->ctrl_maximum) {
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("%s control option value %s is above maximum. Skipping...")
|
|
, it_d->ctrl_name.c_str()
|
|
, it_p->param_value.c_str()
|
|
, it_d->ctrl_maximum);
|
|
} else {
|
|
it_d->ctrl_newval = mtoi(it_p->param_value.c_str());
|
|
}
|
|
break;
|
|
case V4L2_CTRL_TYPE_BOOLEAN:
|
|
it_d->ctrl_newval = mtob(it_p->param_value.c_str()) ? 1 : 0;
|
|
break;
|
|
default:
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("control type not supported"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the device to the input number requested by user */
|
|
void cls_v4l2cam::set_input()
|
|
{
|
|
int spec;
|
|
struct v4l2_input input;
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
spec = -1;
|
|
for (it = lst->begin(); it != lst->end(); it++) {
|
|
if (it->param_name == "input") {
|
|
spec = mtoi(it->param_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
memset(&input, 0, sizeof (struct v4l2_input));
|
|
if (spec == -1) {
|
|
input.index = 0;
|
|
} else {
|
|
input.index = (uint)spec;
|
|
}
|
|
|
|
if (xioctl(VIDIOC_ENUMINPUT, &input) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Unable to query input %d."
|
|
" VIDIOC_ENUMINPUT, if you use a WEBCAM change input value in conf by -1")
|
|
,input.index);
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_("Name = \"%s\", type 0x%08X, status %08x")
|
|
,input.name, input.type, input.status);
|
|
|
|
if (input.type & V4L2_INPUT_TYPE_TUNER) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Name = \"%s\",- TUNER"), input.name);
|
|
}
|
|
|
|
if (input.type & V4L2_INPUT_TYPE_CAMERA) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Name = \"%s\"- CAMERA"), input.name);
|
|
}
|
|
|
|
if (xioctl(VIDIOC_S_INPUT, &input.index) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
, _("Error selecting input %d VIDIOC_S_INPUT"), input.index);
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
device_type = (int)input.type;
|
|
device_tuner = (int)input.tuner;
|
|
|
|
return;
|
|
}
|
|
|
|
/* Set the video standard(norm) for the device to the user requested value*/
|
|
void cls_v4l2cam::set_norm()
|
|
{
|
|
int spec;
|
|
struct v4l2_standard standard;
|
|
v4l2_std_id std_id;
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
spec = 1;
|
|
for (it = lst->begin(); it != lst->end(); it++) {
|
|
if (it->param_name == "norm") {
|
|
spec = mtoi(it->param_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (xioctl(VIDIOC_G_STD, &std_id) == -1) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_("Device does not support specifying PAL/NTSC norm"));
|
|
return;
|
|
}
|
|
|
|
if (std_id) {
|
|
memset(&standard, 0, sizeof(struct v4l2_standard));
|
|
standard.index = 0;
|
|
|
|
while (xioctl(VIDIOC_ENUMSTD, &standard) == 0) {
|
|
if (standard.id & std_id) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("- video standard %s"), standard.name);
|
|
}
|
|
standard.index++;
|
|
}
|
|
|
|
switch (spec) {
|
|
case 1:
|
|
std_id = V4L2_STD_NTSC;
|
|
break;
|
|
case 2:
|
|
std_id = V4L2_STD_SECAM;
|
|
break;
|
|
default:
|
|
std_id = V4L2_STD_PAL;
|
|
}
|
|
|
|
if (xioctl(VIDIOC_S_STD, &std_id) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error selecting standard method %d VIDIOC_S_STD")
|
|
,(int)std_id);
|
|
}
|
|
|
|
if (std_id == V4L2_STD_NTSC) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to NTSC"));
|
|
} else if (std_id == V4L2_STD_SECAM) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to SECAM"));
|
|
} else {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to PAL"));
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/* Set the frequency on the device to the user requested value */
|
|
void cls_v4l2cam::set_frequency()
|
|
{
|
|
long spec;
|
|
struct v4l2_tuner tuner;
|
|
struct v4l2_frequency freq;
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
spec = 0;
|
|
for (it = lst->begin(); it != lst->end(); it++) {
|
|
if (it->param_name == "frequency") {
|
|
spec = mtol(it->param_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If this input is attached to a tuner, set the frequency. */
|
|
if (device_type & V4L2_INPUT_TYPE_TUNER) {
|
|
/* Query the tuners capabilities. */
|
|
memset(&tuner, 0, sizeof(struct v4l2_tuner));
|
|
tuner.index = (uint)device_tuner;
|
|
|
|
if (xioctl(VIDIOC_G_TUNER, &tuner) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("tuner %d VIDIOC_G_TUNER"), tuner.index);
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set tuner %d"), tuner.index);
|
|
|
|
/* Set the frequency. */
|
|
memset(&freq, 0, sizeof(struct v4l2_frequency));
|
|
freq.tuner = (uint)device_tuner;
|
|
freq.type = V4L2_TUNER_ANALOG_TV;
|
|
freq.frequency = (uint)((spec / 1000) * 16);
|
|
|
|
if (xioctl(VIDIOC_S_FREQUENCY, &freq) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("freq %ul VIDIOC_S_FREQUENCY"), freq.frequency);
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set Frequency to %ul"), freq.frequency);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int cls_v4l2cam::pixfmt_try(uint pixformat)
|
|
{
|
|
int retcd;
|
|
|
|
memset(&vidfmt, 0, sizeof(struct v4l2_format));
|
|
|
|
vidfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vidfmt.fmt.pix.width = (uint)cam->cfg->width;
|
|
vidfmt.fmt.pix.height = (uint)cam->cfg->height;
|
|
vidfmt.fmt.pix.pixelformat = pixformat;
|
|
vidfmt.fmt.pix.field = V4L2_FIELD_ANY;
|
|
|
|
retcd = xioctl(VIDIOC_TRY_FMT, &vidfmt);
|
|
if ((retcd == -1) || (vidfmt.fmt.pix.pixelformat != pixformat)) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Unable to use palette %c%c%c%c (%dx%d)")
|
|
,pixformat >> 0, pixformat >> 8
|
|
,pixformat >> 16, pixformat >> 24
|
|
,cam->cfg->width, cam->cfg->height);
|
|
return -1;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Testing palette %c%c%c%c (%dx%d)")
|
|
,pixformat >> 0, pixformat >> 8
|
|
,pixformat >> 16, pixformat >> 24
|
|
,cam->cfg->width, cam->cfg->height);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int cls_v4l2cam::pixfmt_stride()
|
|
{
|
|
int wd, bpl, wps;
|
|
|
|
cam->cfg->width = (int)vidfmt.fmt.pix.width;
|
|
cam->cfg->height = (int)vidfmt.fmt.pix.height;
|
|
|
|
bpl = (int)vidfmt.fmt.pix.bytesperline;
|
|
wd = cam->cfg->width;
|
|
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
, _("Checking image size %dx%d with stride %d")
|
|
, cam->cfg->width, cam->cfg->height, bpl);
|
|
|
|
if (bpl == 0) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
, _("No stride value provided from device."));
|
|
return 0;
|
|
}
|
|
|
|
if (wd > bpl) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
, _("Width(%d) must be less than stride(%d)"), wd, bpl);
|
|
return -1;
|
|
}
|
|
|
|
/* For perfect multiples of width and stride, no adjustment needed */
|
|
if ((wd == bpl) || ((bpl % wd) == 0)) {
|
|
return 0;
|
|
}
|
|
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
, _("The image width(%d) is not multiple of the stride(%d)")
|
|
, wd, bpl);
|
|
|
|
/* Width per stride */
|
|
wps = bpl / wd;
|
|
if (wps < 1) {
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
, _("Impossible condition: Width(%d), Stride(%d), Per stride(%d)")
|
|
, wd, bpl, wps);
|
|
}
|
|
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
, _("Image width will be padded %d bytes"), ((bpl % wd)/wps));
|
|
|
|
cam->cfg->width = wd + ((bpl % wd)/wps);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
int cls_v4l2cam::pixfmt_adjust()
|
|
{
|
|
if ((vidfmt.fmt.pix.width != (uint)cam->cfg->width) ||
|
|
(vidfmt.fmt.pix.height != (uint)cam->cfg->height)) {
|
|
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("Adjusting resolution from %ix%i to %ix%i.")
|
|
,cam->cfg->width, cam->cfg->height
|
|
,vidfmt.fmt.pix.width
|
|
,vidfmt.fmt.pix.height);
|
|
|
|
cam->cfg->width = (int)vidfmt.fmt.pix.width;
|
|
cam->cfg->height = (int)vidfmt.fmt.pix.height;
|
|
|
|
if ((cam->cfg->width % 8) || (cam->cfg->height % 8)) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("Adjusted resolution not modulo 8."));
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("Specify different palette or width/height in config file."));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Set the pixel format on the device */
|
|
int cls_v4l2cam::pixfmt_set(uint pixformat)
|
|
{
|
|
int retcd;
|
|
|
|
retcd = pixfmt_try(pixformat);
|
|
if (retcd != 0) {
|
|
return -1;
|
|
}
|
|
retcd = pixfmt_stride();
|
|
if (retcd != 0) {
|
|
return -1;
|
|
}
|
|
retcd = pixfmt_adjust();
|
|
if (retcd != 0) {
|
|
return -1;
|
|
}
|
|
retcd = xioctl(VIDIOC_S_FMT, &vidfmt);
|
|
if (retcd == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error setting pixel format."));
|
|
return -1;
|
|
}
|
|
|
|
pixfmt_src = (int)pixformat;
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Using palette %c%c%c%c (%dx%d)")
|
|
,pixformat >> 0 , pixformat >> 8
|
|
,pixformat >> 16, pixformat >> 24
|
|
,cam->cfg->width, cam->cfg->height);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void cls_v4l2cam::params_check()
|
|
{
|
|
int spec;
|
|
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it;
|
|
|
|
if (cam->cfg->width % 8) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("config image width (%d) is not modulo 8"), cam->cfg->width);
|
|
cam->cfg->width = cam->cfg->width - (cam->cfg->width % 8) + 8;
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
, _("Adjusting to width (%d)"), cam->cfg->width);
|
|
}
|
|
|
|
if (cam->cfg->height % 8) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("config image height (%d) is not modulo 8"), cam->cfg->height);
|
|
cam->cfg->height = cam->cfg->height - (cam->cfg->height % 8) + 8;
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("Adjusting to height (%d)"), cam->cfg->height);
|
|
}
|
|
|
|
spec = 17;
|
|
for (it = lst->begin(); it != lst->end(); it++) {
|
|
if (it->param_name == "palette") {
|
|
spec = mtoi(it->param_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((spec < 0) || (spec > (int)palette.size())) {
|
|
MOTPLS_LOG(WRN, TYPE_VIDEO, NO_ERRNO
|
|
,_("Invalid palette. Changing to default"));
|
|
util_parms_add(params,"palette","17");
|
|
}
|
|
|
|
}
|
|
|
|
/*List camera palettes and return index of one that Motionplus supports*/
|
|
int cls_v4l2cam::pixfmt_list()
|
|
{
|
|
int v4l2_pal, indx_palette, indx;
|
|
struct v4l2_fmtdesc fmtd;
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Supported palettes:"));
|
|
|
|
v4l2_pal = 0;
|
|
memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
|
|
fmtd.index = (uint)v4l2_pal;
|
|
fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
indx_palette = -1; /* -1 says not yet selected */
|
|
|
|
while (xioctl(VIDIOC_ENUM_FMT, &fmtd) != -1) {
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
, "(%i) %c%c%c%c (%s)", v4l2_pal
|
|
, fmtd.pixelformat >> 0, fmtd.pixelformat >> 8
|
|
, fmtd.pixelformat >> 16, fmtd.pixelformat >> 24
|
|
, fmtd.description);
|
|
for (indx = 0; indx < (int)palette.size(); indx++) {
|
|
if (palette[(uint)indx].v4l2id == fmtd.pixelformat) {
|
|
indx_palette = indx;
|
|
}
|
|
}
|
|
|
|
v4l2_pal++;
|
|
memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
|
|
fmtd.index = (uint)v4l2_pal;
|
|
fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
}
|
|
|
|
return indx_palette;
|
|
}
|
|
|
|
/* Find and select the pixel format for camera*/
|
|
void cls_v4l2cam::palette_set()
|
|
{
|
|
int indxp, retcd;
|
|
p_lst *lst = ¶ms->params_array;
|
|
p_it it;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
params_check();
|
|
|
|
indxp = 17;
|
|
for (it = lst->begin(); it != lst->end(); it++) {
|
|
if (it->param_name == "palette") {
|
|
indxp = mtoi(it->param_value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
retcd = pixfmt_set(palette[(uint)indxp].v4l2id);
|
|
if (retcd == 0) {
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Configuration palette index %d (%s) for %dx%d doesn't work.")
|
|
, indxp, palette[(uint)indxp].fourcc.c_str()
|
|
,cam->cfg->width, cam->cfg->height);
|
|
|
|
indxp = pixfmt_list();
|
|
if (indxp < 0) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("Unable to find a compatible palette format."));
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
retcd = pixfmt_set(palette[(uint)indxp].v4l2id);
|
|
if (retcd < 0) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
, _("Palette selection failed for format %s")
|
|
, palette[(uint)indxp].fourcc.c_str());
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Selected palette index %d (%s)")
|
|
,indxp, palette[(uint)indxp].fourcc.c_str());
|
|
|
|
}
|
|
|
|
/* Set the memory mapping from device to Motion*/
|
|
void cls_v4l2cam::set_mmap()
|
|
{
|
|
enum v4l2_buf_type type;
|
|
int buffer_index;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
if (!(vidcap.capabilities & V4L2_CAP_STREAMING)) {
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
memset(&vidreq, 0, sizeof(struct v4l2_requestbuffers));
|
|
|
|
vidreq.count = MMAP_BUFFERS;
|
|
vidreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vidreq.memory = V4L2_MEMORY_MMAP;
|
|
if (xioctl(VIDIOC_REQBUFS, &vidreq) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error requesting buffers %d for memory map. VIDIOC_REQBUFS")
|
|
,vidreq.count);
|
|
device_close();
|
|
return;
|
|
}
|
|
buffer_count = (int)vidreq.count;
|
|
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_("mmap information: frames=%d"), buffer_count);
|
|
|
|
if (buffer_count < MIN_MMAP_BUFFERS) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Insufficient buffer memory %d < MIN_MMAP_BUFFERS.")
|
|
,buffer_count);
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
buffers =(video_buff*) calloc((uint)buffer_count, sizeof(video_buff));
|
|
if (buffers == nullptr) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, _("Out of memory."));
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
for (buffer_index = 0; buffer_index < buffer_count; buffer_index++) {
|
|
struct v4l2_buffer p_buf;
|
|
|
|
memset(&p_buf, 0, sizeof(struct v4l2_buffer));
|
|
|
|
p_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
p_buf.memory = V4L2_MEMORY_MMAP;
|
|
p_buf.index = (uint)buffer_index;
|
|
if (xioctl(VIDIOC_QUERYBUF, &p_buf) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error querying buffer %i\nVIDIOC_QUERYBUF: ")
|
|
,buffer_index);
|
|
myfree(buffers);
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
buffers[buffer_index].size = p_buf.length;
|
|
buffers[buffer_index].ptr =(unsigned char*) mmap(
|
|
nullptr, p_buf.length, PROT_READ | PROT_WRITE
|
|
, MAP_SHARED, fd_device, p_buf.m.offset);
|
|
|
|
if (buffers[buffer_index].ptr == MAP_FAILED) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error mapping buffer %i mmap"), buffer_index);
|
|
myfree(buffers);
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_("%i length=%d Address (%x)")
|
|
,buffer_index, p_buf.length, buffers[buffer_index].ptr);
|
|
}
|
|
|
|
for (buffer_index = 0; buffer_index < buffer_count; buffer_index++) {
|
|
memset(&vidbuf, 0, sizeof(struct v4l2_buffer));
|
|
|
|
vidbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vidbuf.memory = V4L2_MEMORY_MMAP;
|
|
vidbuf.index = (uint)buffer_index;
|
|
|
|
if (xioctl(VIDIOC_QBUF, &vidbuf) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF");
|
|
device_close();
|
|
return;
|
|
}
|
|
}
|
|
|
|
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
if (xioctl(VIDIOC_STREAMON, &type) == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
|
|
,_("Error starting stream. VIDIOC_STREAMON"));
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/* Assign the resulting sizes to the camera context items */
|
|
void cls_v4l2cam::set_imgs()
|
|
{
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
cam->imgs.width = cam->cfg->width;
|
|
cam->imgs.height = cam->cfg->height;
|
|
cam->imgs.motionsize = cam->imgs.width * cam->imgs.height;
|
|
cam->imgs.size_norm = (cam->imgs.motionsize * 3) / 2;
|
|
|
|
convert = new cls_convert(cam, pixfmt_src, cam->cfg->width, cam->cfg->height);
|
|
|
|
}
|
|
|
|
/* Capture the image into the buffer */
|
|
int cls_v4l2cam::capture()
|
|
{
|
|
int retcd;
|
|
sigset_t set, old;
|
|
|
|
/* Block signals during IOCTL */
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGCHLD);
|
|
sigaddset(&set, SIGALRM);
|
|
sigaddset(&set, SIGUSR1);
|
|
sigaddset(&set, SIGTERM);
|
|
sigaddset(&set, SIGHUP);
|
|
|
|
pthread_sigmask(SIG_BLOCK, &set, &old);
|
|
|
|
if (pframe >= 0) {
|
|
retcd = xioctl(VIDIOC_QBUF, &vidbuf);
|
|
if (retcd == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF");
|
|
pthread_sigmask(SIG_UNBLOCK, &old, nullptr);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
memset(&vidbuf, 0, sizeof(struct v4l2_buffer));
|
|
|
|
vidbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
vidbuf.memory = V4L2_MEMORY_MMAP;
|
|
vidbuf.bytesused = 0;
|
|
|
|
retcd = xioctl(VIDIOC_DQBUF, &vidbuf);
|
|
if (retcd == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF");
|
|
pthread_sigmask(SIG_UNBLOCK, &old, nullptr);
|
|
return -1;
|
|
}
|
|
|
|
pframe = (int)vidbuf.index;
|
|
buffers[vidbuf.index].used = vidbuf.bytesused;
|
|
buffers[vidbuf.index].content_length = (int)vidbuf.bytesused;
|
|
pthread_sigmask(SIG_UNBLOCK, &old, nullptr); /*undo the signal blocking */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
void cls_v4l2cam::init_vars()
|
|
{
|
|
buffer_count= 0;
|
|
pframe = -1;
|
|
buffers = nullptr;
|
|
convert = nullptr;
|
|
|
|
params = new ctx_params;
|
|
params->params_count = 0;
|
|
params->update_params = true;
|
|
util_parms_parse(params, "v4l2_params", cam->cfg->v4l2_params);
|
|
util_parms_add_default(params, "input", "-1");
|
|
util_parms_add_default(params, "palette", "17");
|
|
util_parms_add_default(params, "norm", "0");
|
|
util_parms_add_default(params, "frequency", "0");
|
|
|
|
palette_init();
|
|
}
|
|
|
|
/* Open the device */
|
|
void cls_v4l2cam::device_open()
|
|
{
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
, _("Opening video device %s")
|
|
, cam->cfg->v4l2_device.c_str());
|
|
|
|
cam->watchdog = 60;
|
|
fd_device = open(cam->cfg->v4l2_device.c_str(), O_RDWR|O_CLOEXEC);
|
|
if (fd_device <= 0) {
|
|
MOTPLS_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO
|
|
, _("Failed to open video device %s")
|
|
, cam->cfg->v4l2_device.c_str());
|
|
fd_device = -1;
|
|
return;
|
|
}
|
|
|
|
if (xioctl(VIDIOC_QUERYCAP, &vidcap) < 0) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Not a V4L2 device?"));
|
|
device_close();
|
|
return;
|
|
}
|
|
|
|
if (!(vidcap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Device does not support capturing."));
|
|
device_close();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void cls_v4l2cam::log_types()
|
|
{
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------");
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.driver: \"%s\"",vidcap.driver);
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.card: \"%s\"",vidcap.card);
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.bus_info: \"%s\"",vidcap.bus_info);
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.capabilities=0x%08X",vidcap.capabilities);
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------");
|
|
|
|
if (vidcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_CAPTURE");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_VIDEO_OUTPUT) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OUTPUT");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_VIDEO_OVERLAY) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OVERLAY");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_VBI_CAPTURE) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VBI_CAPTURE");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_VBI_OUTPUT) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VBI_OUTPUT");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_RDS_CAPTURE) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- RDS_CAPTURE");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_TUNER) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- TUNER");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_AUDIO) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- AUDIO");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_READWRITE) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- READWRITE");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_ASYNCIO) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- ASYNCIO");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_STREAMING) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- STREAMING");
|
|
}
|
|
if (vidcap.capabilities & V4L2_CAP_TIMEPERFRAME) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- TIMEPERFRAME");
|
|
}
|
|
|
|
}
|
|
|
|
void cls_v4l2cam::log_formats()
|
|
{
|
|
struct v4l2_fmtdesc dev_format;
|
|
struct v4l2_frmsizeenum dev_sizes;
|
|
struct v4l2_frmivalenum dev_frameint;
|
|
int indx_format, indx_sizes, indx_frameint;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc));
|
|
dev_format.index = indx_format = 0;
|
|
dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
while (xioctl(VIDIOC_ENUM_FMT, &dev_format) != -1) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_("Supported palette %s (%c%c%c%c)")
|
|
,dev_format.description
|
|
,dev_format.pixelformat >> 0
|
|
,dev_format.pixelformat >> 8
|
|
,dev_format.pixelformat >> 16
|
|
,dev_format.pixelformat >> 24);
|
|
|
|
memset(&dev_sizes, 0, sizeof(struct v4l2_frmsizeenum));
|
|
dev_sizes.index = indx_sizes = 0;
|
|
dev_sizes.pixel_format = dev_format.pixelformat;
|
|
while (xioctl(VIDIOC_ENUM_FRAMESIZES, &dev_sizes) != -1) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_(" Width: %d, Height %d")
|
|
,dev_sizes.discrete.width
|
|
,dev_sizes.discrete.height);
|
|
|
|
memset(&dev_frameint, 0, sizeof(struct v4l2_frmivalenum));
|
|
dev_frameint.index = indx_frameint = 0;
|
|
dev_frameint.pixel_format = dev_format.pixelformat;
|
|
dev_frameint.width = dev_sizes.discrete.width;
|
|
dev_frameint.height = dev_sizes.discrete.height;
|
|
while (xioctl(VIDIOC_ENUM_FRAMEINTERVALS, &dev_frameint) != -1) {
|
|
MOTPLS_LOG(DBG, TYPE_VIDEO, NO_ERRNO
|
|
,_(" Framerate %d/%d")
|
|
,dev_frameint.discrete.numerator
|
|
,dev_frameint.discrete.denominator);
|
|
memset(&dev_frameint, 0, sizeof(struct v4l2_frmivalenum));
|
|
dev_frameint.index = (uint)(++indx_frameint);
|
|
dev_frameint.pixel_format = dev_format.pixelformat;
|
|
dev_frameint.width = dev_sizes.discrete.width;
|
|
dev_frameint.height = dev_sizes.discrete.height;
|
|
}
|
|
memset(&dev_sizes, 0, sizeof(struct v4l2_frmsizeenum));
|
|
dev_sizes.index = (uint)(++indx_sizes);
|
|
dev_sizes.pixel_format = dev_format.pixelformat;
|
|
}
|
|
memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc));
|
|
dev_format.index = (uint)(++indx_format);
|
|
dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
}
|
|
|
|
}
|
|
|
|
void cls_v4l2cam::set_fps()
|
|
{
|
|
int retcd;
|
|
|
|
struct v4l2_streamparm setfps;
|
|
|
|
if (fd_device == -1) {
|
|
return;
|
|
}
|
|
|
|
memset(&setfps, 0, sizeof(struct v4l2_streamparm));
|
|
|
|
setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
setfps.parm.capture.timeperframe.numerator = 1;
|
|
setfps.parm.capture.timeperframe.denominator = (uint)cam->cfg->framerate;
|
|
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
|
|
, _("Trying to set fps to %d")
|
|
, setfps.parm.capture.timeperframe.denominator);
|
|
|
|
retcd = xioctl(VIDIOC_S_PARM, &setfps);
|
|
if (retcd != 0) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO
|
|
,_("Error setting fps. Return code %d"), retcd);
|
|
}
|
|
|
|
MOTPLS_LOG(INF, TYPE_VIDEO, NO_ERRNO
|
|
, _("Device set fps to %d")
|
|
, setfps.parm.capture.timeperframe.denominator);
|
|
|
|
}
|
|
|
|
void cls_v4l2cam::stop_cam()
|
|
{
|
|
enum v4l2_buf_type p_type;
|
|
int indx;
|
|
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO
|
|
,_("Closing video device %s"), cam->cfg->v4l2_device.c_str());
|
|
|
|
p_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
if (fd_device != -1) {
|
|
xioctl(VIDIOC_STREAMOFF, &p_type);
|
|
device_close();
|
|
}
|
|
|
|
if (buffers != nullptr) {
|
|
for (indx = 0; indx < (int)vidreq.count; indx++){
|
|
munmap(buffers[indx].ptr, buffers[indx].size);
|
|
}
|
|
myfree(buffers);
|
|
}
|
|
|
|
if (convert != nullptr) {
|
|
delete convert;
|
|
}
|
|
|
|
delete params;
|
|
}
|
|
|
|
void cls_v4l2cam::start_cam()
|
|
{
|
|
MOTPLS_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening V4L2 device"));
|
|
init_vars();
|
|
device_open();
|
|
log_types();
|
|
log_formats();
|
|
set_input();
|
|
set_norm();
|
|
set_frequency();
|
|
palette_set();
|
|
set_fps();
|
|
ctrls_list();
|
|
ctrls_set();
|
|
set_mmap();
|
|
set_imgs();
|
|
if (fd_device == -1) {
|
|
MOTPLS_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("V4L2 device failed to open"));
|
|
stop_cam();
|
|
return;
|
|
}
|
|
cam->device_status = STATUS_OPENED;
|
|
|
|
}
|
|
|
|
#endif /* HAVE_V4L2 */
|
|
|
|
int cls_v4l2cam::next(ctx_image_data *img_data)
|
|
{
|
|
#ifdef HAVE_V4L2
|
|
int retcd;
|
|
|
|
retcd = capture();
|
|
if (retcd != 0) {
|
|
return CAPTURE_FAILURE;
|
|
}
|
|
|
|
retcd = convert->process(
|
|
img_data->image_norm
|
|
, buffers[vidbuf.index].ptr
|
|
, buffers[vidbuf.index].content_length);
|
|
if (retcd != 0) {
|
|
return CAPTURE_FAILURE;
|
|
}
|
|
|
|
cam->rotate->process(img_data);
|
|
|
|
return CAPTURE_SUCCESS;
|
|
#else
|
|
(void)img_data;
|
|
return CAPTURE_FAILURE;
|
|
#endif // HAVE_V4L2
|
|
}
|
|
|
|
cls_v4l2cam::cls_v4l2cam(cls_camera *p_cam)
|
|
{
|
|
cam = p_cam;
|
|
#ifdef HAVE_V4L2
|
|
start_cam();
|
|
#else
|
|
cam->device_status = STATUS_CLOSED;
|
|
#endif // HAVE_V4l2
|
|
}
|
|
|
|
cls_v4l2cam::~cls_v4l2cam()
|
|
{
|
|
#ifdef HAVE_V4L2
|
|
stop_cam();
|
|
#endif
|
|
cam->device_status = STATUS_CLOSED;
|
|
}
|