From 01632677553945457ece960b6f9354bff308322f Mon Sep 17 00:00:00 2001 From: MrDave Date: Sat, 5 Dec 2020 15:42:49 -0700 Subject: [PATCH] Remove roundrobin --- src/alg.cpp | 43 -- src/alg.hpp | 1 - src/conf.cpp | 162 ----- src/conf.hpp | 7 - src/motion_loop.cpp | 1 - src/motionplus.cpp | 4 - src/motionplus.hpp | 11 +- src/video_v4l2.cpp | 1563 ++++++++++++++++++------------------------- src/video_v4l2.hpp | 55 +- src/webu.cpp | 5 +- 10 files changed, 730 insertions(+), 1122 deletions(-) diff --git a/src/alg.cpp b/src/alg.cpp index c1088876..1e27c471 100644 --- a/src/alg.cpp +++ b/src/alg.cpp @@ -1002,49 +1002,6 @@ void alg_lightswitch(struct ctx_cam *cam) } } -void alg_switchfilter(struct ctx_cam *cam) -{ - - /* TODO: This function needs evaluation. - * Lots of random numbers and unknown logic - */ - int linediff; - unsigned char *out; - int y, x, line; - int lines = 0, vertlines = 0; - - if (!cam->conf->roundrobin_switchfilter || - cam->current_image->diffs < cam->threshold) return; - - linediff = cam->current_image->diffs / cam->imgs.height; - out = cam->imgs.image_motion.image_norm; - - for (y = 0; y < cam->imgs.height; y++) { - line = 0; - for (x = 0; x < cam->imgs.width; x++) { - if (*(out++)) line++; - } - if (line > cam->imgs.width / 18) vertlines++; - if (line > linediff * 2) lines++; - } - - if (vertlines > cam->imgs.height / 10 && lines < vertlines / 3 && - (vertlines > cam->imgs.height / 4 || lines - vertlines > lines / 2)) { - if (cam->conf->text_changes) { - char tmp[80]; - sprintf(tmp, "%d %d", lines, vertlines); - draw_text(cam->current_image->image_norm, cam->imgs.width, cam->imgs.height - , cam->imgs.width - 10, 20, tmp, cam->conf->text_scale); - } - return; - } - - cam->current_image->diffs = 0; - MOTION_LOG(INF, TYPE_ALL, NO_ERRNO, _("Switchfilter detected")); - - return; -} - /** * alg_update_reference_frame * diff --git a/src/alg.hpp b/src/alg.hpp index 5e12ee36..1cc5fa24 100644 --- a/src/alg.hpp +++ b/src/alg.hpp @@ -25,7 +25,6 @@ void alg_locate_center_size(struct ctx_images *, int width, int height, struct ctx_coord *); void alg_diff(struct ctx_cam *cam); void alg_lightswitch(struct ctx_cam *cam); - void alg_switchfilter(struct ctx_cam *cam); void alg_noise_tune(struct ctx_cam *cam, unsigned char *); void alg_threshold_tune(struct ctx_cam *cam, int, int); void alg_despeckle(struct ctx_cam *cam); diff --git a/src/conf.cpp b/src/conf.cpp index 89cce32f..14fa3fdd 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -99,34 +99,6 @@ struct ctx_parm config_parms[] = { "# Parameters to control video device. See motionplus_guide.html", 0,PARM_TYP_STRING,PARM_CAT_01,WEBUI_LEVEL_LIMITED}, { - "v4l2_palette", - "# Preferred color palette to be used for the video device", - 0, PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED}, - { - "input", - "# The input number to be used on the video device.", - 0, PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, - { - "norm", - "# The video norm to use for video capture and TV tuner cards.", - 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_ADVANCED }, - { - "frequency", - "# The frequency to set the tuner to (kHz) for TV tuner cards", - 0,PARM_TYP_INT, PARM_CAT_01,WEBUI_LEVEL_ADVANCED }, - { - "roundrobin_frames", - "# Number of frames to capture in each roundrobin step", - 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_LIMITED }, - { - "roundrobin_skip", - "# Number of frames to skip before each roundrobin step", - 0,PARM_TYP_INT, PARM_CAT_01, WEBUI_LEVEL_LIMITED }, - { - "roundrobin_switchfilter", - "# Try to filter out noise generated by roundrobin", - 0,PARM_TYP_BOOL, PARM_CAT_01, WEBUI_LEVEL_LIMITED}, - { "netcam_url", "# The full URL of the network camera stream.", 0, PARM_TYP_STRING, PARM_CAT_01, WEBUI_LEVEL_ADVANCED}, @@ -1108,133 +1080,6 @@ static void conf_edit_v4l2_params(struct ctx_cam *cam, std::string &parm, enum P MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","v4l2_params",_("v4l2_params")); } -static void conf_edit_v4l2_palette(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->v4l2_palette = 17; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < 0) || (parm_in >21)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid v4l2_palette %d"),parm_in); - } else { - cam->conf->v4l2_palette = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->v4l2_palette); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","v4l2_palette",_("v4l2_palette")); -} - -static void conf_edit_input(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->input = -1; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < -1) || (parm_in > 7)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid input %d"),parm_in); - } else { - cam->conf->input = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->input); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","input",_("input")); -} - -static void conf_edit_norm(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->norm = 0; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < 0) || (parm_in > 3)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid norm %d"),parm_in); - } else { - cam->conf->norm = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->norm); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","norm",_("norm")); -} - -static void conf_edit_frequency(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->frequency = 0; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < 0) || (parm_in > 999999)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid frequency %d"),parm_in); - } else { - cam->conf->frequency = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->frequency); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","frequency",_("frequency")); -} - -static void conf_edit_roundrobin_frames(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->roundrobin_frames = 1; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < 1) || (parm_in > 2147483647)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid roundrobin_frames %d"),parm_in); - } else { - cam->conf->roundrobin_frames = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->roundrobin_frames); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_frames",_("roundrobin_frames")); -} - -static void conf_edit_roundrobin_skip(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - int parm_in; - if (pact == PARM_ACT_DFLT){ - cam->conf->roundrobin_skip = 1; - } else if (pact == PARM_ACT_SET){ - parm_in = atoi(parm.c_str()); - if ((parm_in < 1) || (parm_in > 2147483647)) { - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Invalid roundrobin_skip %d"),parm_in); - } else { - cam->conf->roundrobin_skip = parm_in; - } - } else if (pact == PARM_ACT_GET){ - parm = std::to_string(cam->conf->roundrobin_skip); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_skip",_("roundrobin_skip")); -} - -static void conf_edit_roundrobin_switchfilter(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) -{ - if (pact == PARM_ACT_DFLT){ - cam->conf->roundrobin_switchfilter = FALSE; - } else if (pact == PARM_ACT_SET){ - conf_edit_set_bool(cam->conf->roundrobin_switchfilter, parm); - } else if (pact == PARM_ACT_GET){ - conf_edit_get_bool(parm, cam->conf->roundrobin_switchfilter); - } - return; - MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO,"%s:%s","roundrobin_switchfilter",_("roundrobin_switchfilter")); -} - static void conf_edit_netcam_url(struct ctx_cam *cam, std::string &parm, enum PARM_ACT pact) { if (pact == PARM_ACT_DFLT) { @@ -3247,13 +3092,6 @@ static void conf_edit_cat01(struct ctx_cam *cam, std::string parm_nm, std::strin } else if (parm_nm == "target_dir"){ conf_edit_target_dir(cam, parm_val, pact); } else if (parm_nm == "v4l2_device"){ conf_edit_v4l2_device(cam, parm_val, pact); } else if (parm_nm == "v4l2_params"){ conf_edit_v4l2_params(cam, parm_val, pact); - } else if (parm_nm == "v4l2_palette"){ conf_edit_v4l2_palette(cam, parm_val, pact); - } else if (parm_nm == "input"){ conf_edit_input(cam, parm_val, pact); - } else if (parm_nm == "norm"){ conf_edit_norm(cam, parm_val, pact); - } else if (parm_nm == "frequency"){ conf_edit_frequency(cam, parm_val, pact); - } else if (parm_nm == "roundrobin_frames"){ conf_edit_roundrobin_frames(cam, parm_val, pact); - } else if (parm_nm == "roundrobin_skip"){ conf_edit_roundrobin_skip(cam, parm_val, pact); - } else if (parm_nm == "roundrobin_switchfilter"){ conf_edit_roundrobin_switchfilter(cam, parm_val, pact); } else if (parm_nm == "netcam_url"){ conf_edit_netcam_url(cam, parm_val, pact); } else if (parm_nm == "netcam_params"){ conf_edit_netcam_params(cam, parm_val, pact); } else if (parm_nm == "netcam_high_url"){ conf_edit_netcam_high_url(cam, parm_val, pact); diff --git a/src/conf.hpp b/src/conf.hpp index f46a0df1..43f2ca24 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -35,13 +35,6 @@ /* Capture device configuration parameters */ std::string v4l2_device; std::string v4l2_params; - int v4l2_palette; - int input; - int norm; - unsigned long frequency; - int roundrobin_frames; - int roundrobin_skip; - int roundrobin_switchfilter; std::string netcam_url; std::string netcam_params; diff --git a/src/motion_loop.cpp b/src/motion_loop.cpp index 53f8071a..03b7d9c0 100644 --- a/src/motion_loop.cpp +++ b/src/motion_loop.cpp @@ -1030,7 +1030,6 @@ static void mlp_detection(struct ctx_cam *cam) if (cam->conf->primary_method == 0){ alg_diff(cam); alg_lightswitch(cam); - alg_switchfilter(cam); alg_despeckle(cam); alg_tune_smartmask(cam); } else if (cam->conf->primary_method == 1) { diff --git a/src/motionplus.cpp b/src/motionplus.cpp index 6fa33cc7..09eee273 100644 --- a/src/motionplus.cpp +++ b/src/motionplus.cpp @@ -277,8 +277,6 @@ static void motion_shutdown(struct ctx_motapp *motapp) conf_deinit(motapp); - v4l2_mutex_destroy(); - } static void motion_camera_ids(struct ctx_cam **cam_list) @@ -412,8 +410,6 @@ static void motion_startup(struct ctx_motapp *motapp, int daemonize, int argc, c webu_init(motapp); - v4l2_mutex_init(); - } /** Start a camera thread */ diff --git a/src/motionplus.hpp b/src/motionplus.hpp index cd85f196..4b0f393b 100644 --- a/src/motionplus.hpp +++ b/src/motionplus.hpp @@ -62,6 +62,14 @@ extern "C" { #include } +#ifdef HAVE_V4L2 + #if defined(HAVE_LINUX_VIDEODEV2_H) + #include + #else + #include + #endif +#endif + /* Forward declarations, used in functional definitions of headers */ struct ctx_rotate; struct ctx_images; @@ -73,6 +81,7 @@ struct ctx_netcam; struct ctx_algsec; struct ctx_config; struct ctx_track; +struct ctx_v4l2cam; #define MYFFVER (LIBAVFORMAT_VERSION_MAJOR * 1000)+LIBAVFORMAT_VERSION_MINOR @@ -288,7 +297,7 @@ struct ctx_cam { struct ctx_mmalcam *mmalcam; struct ctx_netcam *netcam; /* this structure contains the context for normal RTSP connection */ struct ctx_netcam *netcam_high; /* this structure contains the context for high resolution RTSP connection */ - struct ctx_params *vdev; + struct ctx_v4l2cam *v4l2cam; struct ctx_image_data *current_image; /* Pointer to a structure where the image, diffs etc is stored */ struct ctx_algsec *algsec; struct ctx_rotate *rotate_data; /* rotation data is thread-specific */ diff --git a/src/video_v4l2.cpp b/src/video_v4l2.cpp index 0fe32682..ff771f5b 100644 --- a/src/video_v4l2.cpp +++ b/src/video_v4l2.cpp @@ -26,102 +26,15 @@ #include "video_v4l2.hpp" #include -struct vid_devctrl_ctx { - char *ctrl_name; /* The name as provided by the device */ - char *ctrl_iddesc; /* A motion description of the ID number for the control*/ - int ctrl_minimum; /* The minimum value permitted as reported by device*/ - int ctrl_maximum; /* The maximum value permitted as reported by device*/ - int ctrl_default; /* The default value for the control*/ - int ctrl_currval; /* The current value the control was set to */ - int ctrl_newval; /* The new value to set for the control */ - unsigned int ctrl_id; /* The ID number for the control as provided by the device*/ - unsigned int ctrl_type; /* The type of control as reported by the device*/ - int ctrl_menuitem; /* bool for whether item is a menu item description */ -}; - -struct video_dev { - struct video_dev *next; - int usage_count; - int fd_device; - char v4l2_device[PATH_MAX]; - int input; - int norm; - int width; - int height; - unsigned long frequency; - int fps; - int owner; - int frames; - int pixfmt_src; - int buffer_count; - pthread_mutex_t mutex; - pthread_mutexattr_t attr; - void *v4l2_private; - struct vid_devctrl_ctx *devctrl_array; /*Array of all the controls in the device*/ - int devctrl_count; /*Count of the controls in the device*/ - int starting; /*Bool for whether the device is just starting*/ - int device_type; /*Camera, tuner, etc as provided by driver enum*/ - int device_tuner; /*Tuner number if applicable from driver*/ - -}; +#define MMAP_BUFFERS 4 +#define MIN_MMAP_BUFFERS 2 +#define V4L2_PALETTE_COUNT_MAX 21 #ifdef HAVE_V4L2 - #if defined(HAVE_LINUX_VIDEODEV2_H) - #include - #else - #include - #endif - #define u8 unsigned char - #define u16 unsigned short - #define u32 unsigned int - #define s32 signed int - - #define MMAP_BUFFERS 4 - #define MIN_MMAP_BUFFERS 2 - #define V4L2_PALETTE_COUNT_MAX 21 - - #define MAX2(x, y) ((x) > (y) ? (x) : (y)) - #define MIN2(x, y) ((x) < (y) ? (x) : (y)) - - static pthread_mutex_t v4l2_mutex; - static struct video_dev *v4l2_devices = NULL; - - typedef struct video_image_buff { - unsigned char *ptr; - int content_length; - size_t size; /* total allocated size */ - size_t used; /* bytes already used */ - struct timeval image_time; /* time this image was received */ - } video_buff; - - typedef struct { - int fd_device; - u32 fps; - - struct v4l2_capability cap; - struct v4l2_format src_fmt; - struct v4l2_format dst_fmt; - struct v4l2_requestbuffers req; - struct v4l2_buffer buf; - - video_buff *buffers; - - s32 pframe; - - u32 ctrl_flags; - volatile unsigned int *finish; /* End the thread */ - - } src_v4l2_t; - - typedef struct palette_item_struct{ - u32 v4l2id; - char fourcc[5]; - } palette_item; static void v4l2_palette_init(palette_item *palette_array) { - int indx; /* When adding here, update the max defined as V4L2_PALETTE_COUNT_MAX above */ @@ -148,7 +61,7 @@ static void v4l2_palette_init(palette_item *palette_array) palette_array[20].v4l2id = V4L2_PIX_FMT_GREY; palette_array[21].v4l2id = V4L2_PIX_FMT_H264; - for (indx=0; indx <=V4L2_PALETTE_COUNT_MAX; indx++ ){ + for (indx = 0; indx <= V4L2_PALETTE_COUNT_MAX; indx++) { sprintf(palette_array[indx].fourcc ,"%c%c%c%c" ,palette_array[indx].v4l2id >> 0 ,palette_array[indx].v4l2id >> 8 @@ -158,239 +71,220 @@ static void v4l2_palette_init(palette_item *palette_array) } -static int xioctl(src_v4l2_t *vid_source, unsigned long request, void *arg) +/* Execute the request to the device */ +static int xioctl(ctx_v4l2cam *v4l2cam, unsigned long request, void *arg) { - int ret; + int retcd; - do - ret = ioctl(vid_source->fd_device, request, arg); - while (-1 == ret && EINTR == errno && !vid_source->finish); - - return ret; -} - -static void v4l2_vdev_deinit(struct ctx_cam *cam) -{ - - if (cam->vdev != NULL){ - util_parms_free(cam->vdev); - - free(cam->vdev); - cam->vdev = NULL; + if (v4l2cam->fd_device < 0) { + return -1; } + do { + retcd = ioctl(v4l2cam->fd_device, request, arg); + } while (-1 == retcd && EINTR == errno && !v4l2cam->finish); + + return retcd; } -static int v4l2_vdev_init(struct ctx_cam *cam) +/* Get the count of how many controls and menu items the device supports */ +static int v4l2_ctrls_count(ctx_v4l2cam *v4l2cam) { - - cam->vdev =(struct ctx_params*) mymalloc(sizeof(struct ctx_params)); - memset(cam->vdev, 0, sizeof(struct ctx_params)); - cam->vdev->params_array = NULL; - cam->vdev->params_count = 0; - cam->vdev->update_params = TRUE; /*Set trigger that we have updated user parameters */ - - return 0; - -} - -static int v4l2_ctrls_count(struct video_dev *curdev) -{ - - /* Get the count of how many controls and menu items the device supports */ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; struct v4l2_queryctrl vid_ctrl; struct v4l2_querymenu vid_menu; int indx; - curdev->devctrl_count = 0; + v4l2cam->devctrl_count = 0; memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl)); vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - while (xioctl (vid_source, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) { - if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS){ + + while (xioctl (v4l2cam, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) { + if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; continue; } - curdev->devctrl_count++; + v4l2cam->devctrl_count++; if (vid_ctrl.type == V4L2_CTRL_TYPE_MENU) { - for (indx = vid_ctrl.minimum; indx<=vid_ctrl.maximum; indx++){ + 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 = indx; - if (xioctl(vid_source, VIDIOC_QUERYMENU, &vid_menu) == 0) curdev->devctrl_count++; + if (xioctl(v4l2cam, VIDIOC_QUERYMENU, &vid_menu) == 0) { + v4l2cam->devctrl_count++; + } } } vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; } return 0; - } -static int v4l2_ctrls_list(struct video_dev *curdev) +/* Print the device controls to the log */ +static void v4l2_ctrls_log(ctx_v4l2cam *v4l2cam) { + int indx; - /* Get the names of the controls and menu items the device supports */ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - struct v4l2_queryctrl vid_ctrl; - struct v4l2_querymenu vid_menu; - int indx, indx_ctrl; - - curdev->devctrl_array = NULL; - if (curdev->devctrl_count == 0 ){ - MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("No Controls found for device")); - return 0; - } - - curdev->devctrl_array =(vid_devctrl_ctx*) malloc(curdev->devctrl_count * sizeof(struct vid_devctrl_ctx)); - - memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl)); - vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - indx_ctrl = 0; - while (xioctl (vid_source, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) { - if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS){ - vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - continue; - } - - curdev->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id; - curdev->devctrl_array[indx_ctrl].ctrl_type = vid_ctrl.type; - curdev->devctrl_array[indx_ctrl].ctrl_default = vid_ctrl.default_value; - curdev->devctrl_array[indx_ctrl].ctrl_currval = vid_ctrl.default_value; - curdev->devctrl_array[indx_ctrl].ctrl_newval = vid_ctrl.default_value; - curdev->devctrl_array[indx_ctrl].ctrl_menuitem = FALSE; - - curdev->devctrl_array[indx_ctrl].ctrl_name =(char*) malloc(32); - sprintf(curdev->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_ctrl.name); - - curdev->devctrl_array[indx_ctrl].ctrl_iddesc =(char*) malloc(15); - sprintf(curdev->devctrl_array[indx_ctrl].ctrl_iddesc,"ID%08d",vid_ctrl.id); - - curdev->devctrl_array[indx_ctrl].ctrl_minimum = vid_ctrl.minimum; - curdev->devctrl_array[indx_ctrl].ctrl_maximum = vid_ctrl.maximum; - - 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 = indx; - if (xioctl(vid_source, VIDIOC_QUERYMENU, &vid_menu) == 0){ - - indx_ctrl++; - curdev->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id; - curdev->devctrl_array[indx_ctrl].ctrl_type = 0; - curdev->devctrl_array[indx_ctrl].ctrl_menuitem = TRUE; - - curdev->devctrl_array[indx_ctrl].ctrl_name =(char*) malloc(32); - sprintf(curdev->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_menu.name); - - curdev->devctrl_array[indx_ctrl].ctrl_iddesc =(char*) malloc(40); - sprintf(curdev->devctrl_array[indx_ctrl].ctrl_iddesc,"menu item: Value %d",indx); - - curdev->devctrl_array[indx_ctrl].ctrl_minimum = 0; - curdev->devctrl_array[indx_ctrl].ctrl_maximum = 0; - } - } - } - indx_ctrl++; - vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - } - - if (curdev->devctrl_count != 0 ){ + if (v4l2cam->devctrl_count != 0 ) { MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("---------Controls---------")); MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _(" V4L2 ID Name and Range")); - for (indx=0; indx < curdev->devctrl_count; indx++){ - if (curdev->devctrl_array[indx].ctrl_menuitem){ + for (indx = 0; indx < v4l2cam->devctrl_count; indx++) { + if (v4l2cam->devctrl_array[indx].ctrl_menuitem) { MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, " %s %s" - ,curdev->devctrl_array[indx].ctrl_iddesc - ,curdev->devctrl_array[indx].ctrl_name); + ,v4l2cam->devctrl_array[indx].ctrl_iddesc + ,v4l2cam->devctrl_array[indx].ctrl_name); } else { MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s %s, %d to %d" - ,curdev->devctrl_array[indx].ctrl_iddesc - ,curdev->devctrl_array[indx].ctrl_name - ,curdev->devctrl_array[indx].ctrl_minimum - ,curdev->devctrl_array[indx].ctrl_maximum); + ,v4l2cam->devctrl_array[indx].ctrl_iddesc + ,v4l2cam->devctrl_array[indx].ctrl_name + ,v4l2cam->devctrl_array[indx].ctrl_minimum + ,v4l2cam->devctrl_array[indx].ctrl_maximum); } } MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "--------------------------"); } - return 0; +} + +/* Get names of the controls and menu items the device supports */ +static void v4l2_ctrls_list(ctx_v4l2cam *v4l2cam) +{ + struct v4l2_queryctrl vid_ctrl; + struct v4l2_querymenu vid_menu; + int indx, indx_ctrl; + + v4l2cam->devctrl_array = NULL; + if (v4l2cam->devctrl_count == 0) { + MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("No Controls found for device")); + return; + } + + v4l2cam->devctrl_array =(ctx_v4l2cam_ctrl*) malloc(v4l2cam->devctrl_count * sizeof(ctx_v4l2cam_ctrl)); + + memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl)); + vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; + indx_ctrl = 0; + while (xioctl (v4l2cam, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) { + if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { + vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + continue; + } + + v4l2cam->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id; + v4l2cam->devctrl_array[indx_ctrl].ctrl_type = vid_ctrl.type; + v4l2cam->devctrl_array[indx_ctrl].ctrl_default = vid_ctrl.default_value; + v4l2cam->devctrl_array[indx_ctrl].ctrl_currval = vid_ctrl.default_value; + v4l2cam->devctrl_array[indx_ctrl].ctrl_newval = vid_ctrl.default_value; + v4l2cam->devctrl_array[indx_ctrl].ctrl_menuitem = FALSE; + + v4l2cam->devctrl_array[indx_ctrl].ctrl_name =(char*) malloc(32); + sprintf(v4l2cam->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_ctrl.name); + + v4l2cam->devctrl_array[indx_ctrl].ctrl_iddesc =(char*) malloc(15); + sprintf(v4l2cam->devctrl_array[indx_ctrl].ctrl_iddesc,"ID%08d",vid_ctrl.id); + + v4l2cam->devctrl_array[indx_ctrl].ctrl_minimum = vid_ctrl.minimum; + v4l2cam->devctrl_array[indx_ctrl].ctrl_maximum = vid_ctrl.maximum; + + 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 = indx; + + if (xioctl(v4l2cam, VIDIOC_QUERYMENU, &vid_menu) == 0) { + indx_ctrl++; + v4l2cam->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id; + v4l2cam->devctrl_array[indx_ctrl].ctrl_type = 0; + v4l2cam->devctrl_array[indx_ctrl].ctrl_menuitem = TRUE; + + v4l2cam->devctrl_array[indx_ctrl].ctrl_name =(char*) malloc(32); + sprintf(v4l2cam->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_menu.name); + + v4l2cam->devctrl_array[indx_ctrl].ctrl_iddesc =(char*) malloc(40); + sprintf(v4l2cam->devctrl_array[indx_ctrl].ctrl_iddesc,"menu item: Value %d",indx); + + v4l2cam->devctrl_array[indx_ctrl].ctrl_minimum = 0; + v4l2cam->devctrl_array[indx_ctrl].ctrl_maximum = 0; + } + } + } + indx_ctrl++; + vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + } + + v4l2_ctrls_log(v4l2cam); + + return; } -static int v4l2_ctrls_set(struct video_dev *curdev) +/* Set the control array items to the device */ +static void v4l2_ctrls_set(ctx_v4l2cam *v4l2cam) { - - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - struct vid_devctrl_ctx *devitem; + struct ctx_v4l2cam_ctrl *devitem; struct v4l2_control vid_ctrl; int indx_dev, retcd; - if (vid_source == NULL){ - MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Device not ready")); - return -1; - } - - for (indx_dev= 0;indx_devdevctrl_count;indx_dev++){ - devitem=&curdev->devctrl_array[indx_dev]; + for (indx_dev = 0; indx_dev < v4l2cam->devctrl_count; indx_dev++) { + devitem=&v4l2cam->devctrl_array[indx_dev]; if (!devitem->ctrl_menuitem) { if (devitem->ctrl_currval != devitem->ctrl_newval) { memset(&vid_ctrl, 0, sizeof (struct v4l2_control)); vid_ctrl.id = devitem->ctrl_id; vid_ctrl.value = devitem->ctrl_newval; - retcd = xioctl(vid_source, VIDIOC_S_CTRL, &vid_ctrl); + retcd = xioctl(v4l2cam, VIDIOC_S_CTRL, &vid_ctrl); if (retcd < 0) { MOTION_LOG(WRN, TYPE_VIDEO, SHOW_ERRNO ,_("setting control %s \"%s\" to %d failed with return code %d") ,devitem->ctrl_iddesc, devitem->ctrl_name ,devitem->ctrl_newval,retcd); } else { - if (curdev->starting) - MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO - ,_("Set control \"%s\" to value %d") - ,devitem->ctrl_name, devitem->ctrl_newval); + MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO + ,_("Set control \"%s\" to value %d") + ,devitem->ctrl_name, devitem->ctrl_newval); devitem->ctrl_currval = devitem->ctrl_newval; } - } } } - return 0; + return; } -static int v4l2_parms_set(struct ctx_cam *cam, struct video_dev *curdev) -{ - struct vid_devctrl_ctx *devitem; +static int v4l2_parms_set(ctx_v4l2cam *v4l2cam) +{ + struct ctx_v4l2cam_ctrl *devitem; struct ctx_params_item *usritem; int indx_dev, indx_user; - if (cam->conf->roundrobin_skip < 0) cam->conf->roundrobin_skip = 1; - - if (curdev->devctrl_count == 0){ - cam->vdev->update_params = FALSE; + if (v4l2cam->devctrl_count == 0) { + v4l2cam->params->update_params = FALSE; return 0; } - for (indx_dev=0; indx_devdevctrl_count; indx_dev++ ) { - devitem=&curdev->devctrl_array[indx_dev]; + for (indx_dev = 0; indx_dev < v4l2cam->devctrl_count; indx_dev++) { + + devitem=&v4l2cam->devctrl_array[indx_dev]; devitem->ctrl_newval = devitem->ctrl_default; - for (indx_user=0; indx_uservdev->params_count; indx_user++){ - usritem=&cam->vdev->params_array[indx_user]; + + for (indx_user = 0; indx_user < v4l2cam->params->params_count; indx_user++){ + + usritem=&v4l2cam->params->params_array[indx_user]; + if ((mystrceq(devitem->ctrl_iddesc,usritem->param_name)) || (mystrceq(devitem->ctrl_name ,usritem->param_name))) { switch (devitem->ctrl_type) { case V4L2_CTRL_TYPE_MENU: /*FALLTHROUGH*/ case V4L2_CTRL_TYPE_INTEGER: - if (atoi(usritem->param_value) < devitem->ctrl_minimum){ + if (atoi(usritem->param_value) < devitem->ctrl_minimum) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("%s control option value %s is below minimum. Skipping...") ,devitem->ctrl_name, usritem->param_value, devitem->ctrl_minimum); - } else if (atoi(usritem->param_value) > devitem->ctrl_maximum){ + } else if (atoi(usritem->param_value) > devitem->ctrl_maximum) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("%s control option value %s is above maximum. Skipping...") ,devitem->ctrl_name, usritem->param_value, devitem->ctrl_maximum); @@ -413,24 +307,19 @@ static int v4l2_parms_set(struct ctx_cam *cam, struct video_dev *curdev) } -static int v4l2_input_select(struct ctx_cam *cam, struct video_dev *curdev) +/* Set the device to the input number requested by user */ +static int v4l2_set_input(ctx_v4l2cam *v4l2cam) { - - /* Set the input number for the device if applicable */ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; struct v4l2_input input; - if ((cam->conf->input == curdev->input) && - (!curdev->starting)) return 0; - memset(&input, 0, sizeof (struct v4l2_input)); - if (cam->conf->input == -1) { + if (v4l2cam->input == -1) { input.index = 0; } else { - input.index = cam->conf->input; + input.index = v4l2cam->input; } - if (xioctl(vid_source, VIDIOC_ENUMINPUT, &input) == -1) { + if (xioctl(v4l2cam, VIDIOC_ENUMINPUT, &input) == -1) { MOTION_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") @@ -438,68 +327,56 @@ static int v4l2_input_select(struct ctx_cam *cam, struct video_dev *curdev) return -1; } - if (curdev->starting){ - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - ,_("Name = \"%s\", type 0x%08X, status %08x") - ,input.name, input.type, input.status); - } + MOTION_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) && (curdev->starting)){ + if (input.type & V4L2_INPUT_TYPE_TUNER) { MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Name = \"%s\",- TUNER"),input.name); + ,_("Name = \"%s\",- TUNER"), input.name); } - - if ((input.type & V4L2_INPUT_TYPE_CAMERA) && (curdev->starting)){ - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Name = \"%s\"- CAMERA"),input.name); + if (input.type & V4L2_INPUT_TYPE_CAMERA) { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Name = \"%s\"- CAMERA"), input.name); } - if (xioctl(vid_source, VIDIOC_S_INPUT, &input.index) == -1) { + if (xioctl(v4l2cam, VIDIOC_S_INPUT, &input.index) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO , _("Error selecting input %d VIDIOC_S_INPUT"), input.index); return -1; } - curdev->input = cam->conf->input; - curdev->device_type = input.type; - curdev->device_tuner = input.tuner; + v4l2cam->device_type = input.type; + v4l2cam->device_tuner = input.tuner; return 0; } -static int v4l2_norm_select(struct ctx_cam *cam, struct video_dev *curdev) +/* Set the video standard(norm) for the device to the user requested value*/ +static void v4l2_set_norm(ctx_v4l2cam *v4l2cam) { - - /* Set the video standard (norm) for the device NTSC/PAL/etc*/ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; struct v4l2_standard standard; v4l2_std_id std_id; - int norm; - if ((cam->conf->norm == curdev->norm) && - (!curdev->starting)) return 0; - - norm = cam->conf->norm; - if (xioctl(vid_source, VIDIOC_G_STD, &std_id) == -1) { - if (curdev->starting){ - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Device does not support specifying PAL/NTSC norm")); - } - norm = std_id = 0; // V4L2_STD_UNKNOWN = 0 + if (xioctl(v4l2cam, VIDIOC_G_STD, &std_id) == -1) { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO + ,_("Device does not support specifying PAL/NTSC norm")); + v4l2cam->norm = std_id = 0; // V4L2_STD_UNKNOWN = 0 } if (std_id) { memset(&standard, 0, sizeof(struct v4l2_standard)); standard.index = 0; - while (xioctl(vid_source, VIDIOC_ENUMSTD, &standard) == 0) { - if ((standard.id & std_id) && (curdev->starting)) + while (xioctl(v4l2cam, VIDIOC_ENUMSTD, &standard) == 0) { + if (standard.id & std_id) { MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO ,_("- video standard %s"), standard.name); + } standard.index++; } - switch (norm) { + switch (v4l2cam->norm) { case 1: std_id = V4L2_STD_NTSC; break; @@ -510,142 +387,122 @@ static int v4l2_norm_select(struct ctx_cam *cam, struct video_dev *curdev) std_id = V4L2_STD_PAL; } - if (xioctl(vid_source, VIDIOC_S_STD, &std_id) == -1){ + if (xioctl(v4l2cam, VIDIOC_S_STD, &std_id) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Error selecting standard method %d VIDIOC_S_STD") ,(int)std_id); } - if (curdev->starting) { - if (std_id == V4L2_STD_NTSC) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to NTSC")); - } else if (std_id == V4L2_STD_SECAM) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to SECAM")); - } else { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to PAL")); - } + if (std_id == V4L2_STD_NTSC) { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to NTSC")); + } else if (std_id == V4L2_STD_SECAM) { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to SECAM")); + } else { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to PAL")); } } - curdev->norm = cam->conf->norm; - - return 0; + return; } -static int v4l2_frequency_select(struct ctx_cam *cam, struct video_dev *curdev) +/* Set the frequency on the device to the user requested value */ +static void v4l2_set_frequency(ctx_v4l2cam *v4l2cam) { - - /* Set the frequency for the tuner */ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; struct v4l2_tuner tuner; struct v4l2_frequency freq; - if ((curdev->frequency == cam->conf->frequency)&& - (!curdev->starting)) return 0; - /* If this input is attached to a tuner, set the frequency. */ - if (curdev->device_type & V4L2_INPUT_TYPE_TUNER) { + if (v4l2cam->device_type & V4L2_INPUT_TYPE_TUNER) { /* Query the tuners capabilities. */ memset(&tuner, 0, sizeof(struct v4l2_tuner)); - tuner.index = curdev->device_tuner; + tuner.index = v4l2cam->device_tuner; - if (xioctl(vid_source, VIDIOC_G_TUNER, &tuner) == -1) { + if (xioctl(v4l2cam, VIDIOC_G_TUNER, &tuner) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("tuner %d VIDIOC_G_TUNER"), tuner.index); - return 0; + return; } - if (curdev->starting){ - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set tuner %d"), tuner.index); - } + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set tuner %d"), tuner.index); /* Set the frequency. */ memset(&freq, 0, sizeof(struct v4l2_frequency)); - freq.tuner = curdev->device_tuner; + freq.tuner = v4l2cam->device_tuner; freq.type = V4L2_TUNER_ANALOG_TV; - freq.frequency = (cam->conf->frequency / 1000) * 16; + freq.frequency = (v4l2cam->frequency / 1000) * 16; - if (xioctl(vid_source, VIDIOC_S_FREQUENCY, &freq) == -1) { + if (xioctl(v4l2cam, VIDIOC_S_FREQUENCY, &freq) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("freq %ul VIDIOC_S_FREQUENCY"), freq.frequency); - return 0; + return; } - if (curdev->starting){ - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set Frequency to %ul"), freq.frequency); - } + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set Frequency to %ul"), freq.frequency); } - curdev->frequency = cam->conf->frequency; - - return 0; + return; } -static int v4l2_pixfmt_set(struct ctx_cam *cam, struct video_dev *curdev, u32 pixformat) +/* Set the pixel format on the device */ +static int v4l2_set_pixfmt(ctx_v4l2cam *v4l2cam, unsigned int pixformat) { - /* Set the pixel format for the camera*/ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; + memset(&v4l2cam->dst_fmt, 0, sizeof(struct v4l2_format)); - memset(&vid_source->dst_fmt, 0, sizeof(struct v4l2_format)); + v4l2cam->dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2cam->dst_fmt.fmt.pix.width = v4l2cam->width; + v4l2cam->dst_fmt.fmt.pix.height = v4l2cam->height; + v4l2cam->dst_fmt.fmt.pix.pixelformat = pixformat; + v4l2cam->dst_fmt.fmt.pix.field = V4L2_FIELD_ANY; - vid_source->dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vid_source->dst_fmt.fmt.pix.width = cam->conf->width; - vid_source->dst_fmt.fmt.pix.height = cam->conf->height; - vid_source->dst_fmt.fmt.pix.pixelformat = pixformat; - vid_source->dst_fmt.fmt.pix.field = V4L2_FIELD_ANY; - - if (xioctl(vid_source, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 && - vid_source->dst_fmt.fmt.pix.pixelformat == pixformat) { + if (xioctl(v4l2cam, VIDIOC_TRY_FMT, &v4l2cam->dst_fmt) != -1 && + v4l2cam->dst_fmt.fmt.pix.pixelformat == pixformat) { MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO ,_("Testing palette %c%c%c%c (%dx%d)") ,pixformat >> 0, pixformat >> 8 ,pixformat >> 16, pixformat >> 24 - ,cam->conf->width, cam->conf->height); + ,v4l2cam->width, v4l2cam->height); - curdev->width = vid_source->dst_fmt.fmt.pix.width; - curdev->height = vid_source->dst_fmt.fmt.pix.height; - - if (vid_source->dst_fmt.fmt.pix.width != (unsigned int) cam->conf->width || - vid_source->dst_fmt.fmt.pix.height != (unsigned int) cam->conf->height) { + if (v4l2cam->dst_fmt.fmt.pix.width != (unsigned int) v4l2cam->width || + v4l2cam->dst_fmt.fmt.pix.height != (unsigned int) v4l2cam->height) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("Adjusting resolution from %ix%i to %ix%i.") - ,cam->conf->width, cam->conf->height - ,vid_source->dst_fmt.fmt.pix.width - ,vid_source->dst_fmt.fmt.pix.height); + ,v4l2cam->width, v4l2cam->height + ,v4l2cam->dst_fmt.fmt.pix.width + ,v4l2cam->dst_fmt.fmt.pix.height); - if ((curdev->width % 8) || (curdev->height % 8)) { + v4l2cam->width = v4l2cam->dst_fmt.fmt.pix.width; + v4l2cam->height = v4l2cam->dst_fmt.fmt.pix.height; + + if ((v4l2cam->width % 8) || (v4l2cam->height % 8)) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO ,_("Adjusted resolution not modulo 8.")); MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO ,_("Specify different palette or width/height in config file.")); return -1; } - cam->conf->width = curdev->width; - cam->conf->height = curdev->height; + } - if (xioctl(vid_source, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) { + if (xioctl(v4l2cam, VIDIOC_S_FMT, &v4l2cam->dst_fmt) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Error setting pixel format.\nVIDIOC_S_FMT: ")); return -1; } - curdev->pixfmt_src = pixformat; + v4l2cam->pixfmt_src = pixformat; - if (curdev->starting) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Using palette %c%c%c%c (%dx%d)") - ,pixformat >> 0 , pixformat >> 8 - ,pixformat >> 16, pixformat >> 24 - ,cam->conf->width, cam->conf->height); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - ,_("Bytesperlines %d sizeimage %d colorspace %08x") - ,vid_source->dst_fmt.fmt.pix.bytesperline - ,vid_source->dst_fmt.fmt.pix.sizeimage - ,vid_source->dst_fmt.fmt.pix.colorspace); - } + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO + ,_("Using palette %c%c%c%c (%dx%d)") + ,pixformat >> 0 , pixformat >> 8 + ,pixformat >> 16, pixformat >> 24 + ,v4l2cam->width, v4l2cam->height); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO + ,_("Bytesperlines %d sizeimage %d colorspace %08x") + ,v4l2cam->dst_fmt.fmt.pix.bytesperline + ,v4l2cam->dst_fmt.fmt.pix.sizeimage + ,v4l2cam->dst_fmt.fmt.pix.colorspace); return 0; } @@ -653,78 +510,82 @@ static int v4l2_pixfmt_set(struct ctx_cam *cam, struct video_dev *curdev, u32 pi return -1; } -static int v4l2_pixfmt_select(struct ctx_cam *cam, struct video_dev *curdev) +/* If needed adjust sizes to be modulo 8 */ +static void v4l2_validate_sizes(ctx_v4l2cam *v4l2cam) { + if (v4l2cam->width % 8) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO + ,_("config image width (%d) is not modulo 8"), v4l2cam->width); + v4l2cam->width = v4l2cam->width - (v4l2cam->width % 8) + 8; + MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO + , _("Adjusting to width (%d)"), v4l2cam->width); + } - /* Find and select the pixel format for camera*/ + if (v4l2cam->height % 8) { + MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO + ,_("config image height (%d) is not modulo 8"), v4l2cam->height); + v4l2cam->height = v4l2cam->height - (v4l2cam->height % 8) + 8; + MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO + ,_("Adjusting to height (%d)"), v4l2cam->height); + } - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; +} + +/* Find and select the pixel format for camera*/ +static int v4l2_set_palette(ctx_v4l2cam *v4l2cam) +{ struct v4l2_fmtdesc fmtd; int v4l2_pal, indx_palette, indx, retcd; palette_item *palette_array; palette_array =(palette_item*) malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1)); - v4l2_palette_init(palette_array); - if (cam->conf->width % 8) { - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO - ,_("config image width (%d) is not modulo 8"), cam->conf->width); - cam->conf->width = cam->conf->width - (cam->conf->width % 8) + 8; - MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO - , _("Adjusting to width (%d)"), cam->conf->width); - } + v4l2_validate_sizes(v4l2cam); - if (cam->conf->height % 8) { - MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO - ,_("config image height (%d) is not modulo 8"), cam->conf->height); - cam->conf->height = cam->conf->height - (cam->conf->height % 8) + 8; - MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO - ,_("Adjusting to height (%d)"), cam->conf->height); - } - - if (cam->conf->v4l2_palette == 21 ) { + if (v4l2cam->palette == 21) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("H264(21) format not supported via v4l2_device. Changing to default palette")); - cam->conf->v4l2_palette = 17; + v4l2cam->palette = 17; } /* First we try setting the config file value */ - indx_palette = cam->conf->v4l2_palette; + indx_palette = v4l2cam->palette; if ((indx_palette >= 0) && (indx_palette <= V4L2_PALETTE_COUNT_MAX)) { - retcd = v4l2_pixfmt_set(cam, curdev,palette_array[indx_palette].v4l2id); - if (retcd >= 0){ + retcd = v4l2_set_pixfmt(v4l2cam, palette_array[indx_palette].v4l2id); + if (retcd >= 0) { free(palette_array); return 0; } MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO ,_("Configuration palette index %d (%s) for %dx%d doesn't work.") , indx_palette, palette_array[indx_palette].fourcc - ,cam->conf->width, cam->conf->height); + ,v4l2cam->width, v4l2cam->height); } memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc)); fmtd.index = v4l2_pal = 0; fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - indx_palette = -1; /* -1 says not yet chosen */ + indx_palette = -1; /* -1 says not yet selected */ MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Supported palettes:")); - while (xioctl(vid_source, VIDIOC_ENUM_FMT, &fmtd) != -1) { - if (curdev->starting) { - MOTION_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); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - ,_("%d - %s (compressed : %d) (%#x)") - ,fmtd.index, fmtd.description, fmtd.flags, fmtd.pixelformat); - } - /* Adjust indx_palette if larger value found */ - /* Prevent the selection of H264 since this module does not support it */ - for (indx = 0; indx <= V4L2_PALETTE_COUNT_MAX; indx++) + while (xioctl(v4l2cam, VIDIOC_ENUM_FMT, &fmtd) != -1) { + MOTION_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); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO + ,_("%d - %s (compressed : %d) (%#x)") + ,fmtd.index, fmtd.description, fmtd.flags, fmtd.pixelformat); + + /* Adjust indx_palette if larger value found */ + /* Prevent the selection of H264 since this module does not support it */ + for (indx = 0; indx <= V4L2_PALETTE_COUNT_MAX; indx++) { if ((palette_array[indx].v4l2id == fmtd.pixelformat) && - (palette_array[indx].v4l2id != V4L2_PIX_FMT_H264)) + (palette_array[indx].v4l2id != V4L2_PIX_FMT_H264)) { indx_palette = indx; + } + } memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc)); fmtd.index = ++v4l2_pal; @@ -732,13 +593,11 @@ static int v4l2_pixfmt_select(struct ctx_cam *cam, struct video_dev *curdev) } if (indx_palette >= 0) { - retcd = v4l2_pixfmt_set(cam, curdev, palette_array[indx_palette].v4l2id); - if (retcd >= 0){ - if (curdev->starting) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Selected palette %s") - ,palette_array[indx_palette].fourcc); - } + retcd = v4l2_set_pixfmt(v4l2cam, palette_array[indx_palette].v4l2id); + if (retcd >= 0) { + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO + ,_("Selected palette %s") + ,palette_array[indx_palette].fourcc); free(palette_array); return 0; } @@ -754,51 +613,50 @@ static int v4l2_pixfmt_select(struct ctx_cam *cam, struct video_dev *curdev) return -1; - } -static int v4l2_mmap_set(struct video_dev *curdev) +/* Set the memory mapping from device to Motion*/ +static int v4l2_set_mmap(ctx_v4l2cam *v4l2cam) { - - /* Set the memory mapping from device to Motion*/ - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; enum v4l2_buf_type type; int buffer_index; /* Does the device support streaming? */ - if (!(vid_source->cap.capabilities & V4L2_CAP_STREAMING)) return -1; - - memset(&vid_source->req, 0, sizeof(struct v4l2_requestbuffers)); - - vid_source->req.count = MMAP_BUFFERS; - vid_source->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vid_source->req.memory = V4L2_MEMORY_MMAP; - if (xioctl(vid_source, VIDIOC_REQBUFS, &vid_source->req) == -1) { - MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO - ,_("Error requesting buffers %d for memory map. VIDIOC_REQBUFS") - ,vid_source->req.count); + if (!(v4l2cam->cap.capabilities & V4L2_CAP_STREAMING)) { return -1; } - curdev->buffer_count = vid_source->req.count; + + memset(&v4l2cam->req, 0, sizeof(struct v4l2_requestbuffers)); + + v4l2cam->req.count = MMAP_BUFFERS; + v4l2cam->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2cam->req.memory = V4L2_MEMORY_MMAP; + if (xioctl(v4l2cam, VIDIOC_REQBUFS, &v4l2cam->req) == -1) { + MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO + ,_("Error requesting buffers %d for memory map. VIDIOC_REQBUFS") + ,v4l2cam->req.count); + return -1; + } + v4l2cam->buffer_count = v4l2cam->req.count; MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - ,_("mmap information: frames=%d"), curdev->buffer_count); + ,_("mmap information: frames=%d"), v4l2cam->buffer_count); - if (curdev->buffer_count < MIN_MMAP_BUFFERS) { + if (v4l2cam->buffer_count < MIN_MMAP_BUFFERS) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Insufficient buffer memory %d < MIN_MMAP_BUFFERS.") - ,curdev->buffer_count); + ,v4l2cam->buffer_count); return -1; } - vid_source->buffers =(video_buff*) calloc(curdev->buffer_count, sizeof(video_buff)); - if (!vid_source->buffers) { + v4l2cam->buffers =(video_buff*) calloc(v4l2cam->buffer_count, sizeof(video_buff)); + if (!v4l2cam->buffers) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, _("Out of memory.")); - vid_source->buffers = NULL; + v4l2cam->buffers = NULL; return -1; } - for (buffer_index = 0; buffer_index < curdev->buffer_count; buffer_index++) { + for (buffer_index = 0; buffer_index < v4l2cam->buffer_count; buffer_index++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(struct v4l2_buffer)); @@ -806,40 +664,40 @@ static int v4l2_mmap_set(struct video_dev *curdev) buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = buffer_index; - if (xioctl(vid_source, VIDIOC_QUERYBUF, &buf) == -1) { + if (xioctl(v4l2cam, VIDIOC_QUERYBUF, &buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Error querying buffer %i\nVIDIOC_QUERYBUF: ") ,buffer_index); - free(vid_source->buffers); - vid_source->buffers = NULL; + free(v4l2cam->buffers); + v4l2cam->buffers = NULL; return -1; } - vid_source->buffers[buffer_index].size = buf.length; - vid_source->buffers[buffer_index].ptr =(unsigned char*) mmap(NULL, buf.length, PROT_READ | PROT_WRITE, - MAP_SHARED, vid_source->fd_device, buf.m.offset); + v4l2cam->buffers[buffer_index].size = buf.length; + v4l2cam->buffers[buffer_index].ptr =(unsigned char*) mmap(NULL, buf.length, PROT_READ | PROT_WRITE, + MAP_SHARED, v4l2cam->fd_device, buf.m.offset); - if (vid_source->buffers[buffer_index].ptr == MAP_FAILED) { + if (v4l2cam->buffers[buffer_index].ptr == MAP_FAILED) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Error mapping buffer %i mmap"), buffer_index); - free(vid_source->buffers); - vid_source->buffers = NULL; + free(v4l2cam->buffers); + v4l2cam->buffers = NULL; return -1; } MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO ,_("%i length=%d Address (%x)") - ,buffer_index, buf.length, vid_source->buffers[buffer_index].ptr); + ,buffer_index, buf.length, v4l2cam->buffers[buffer_index].ptr); } - for (buffer_index = 0; buffer_index < curdev->buffer_count; buffer_index++) { - memset(&vid_source->buf, 0, sizeof(struct v4l2_buffer)); + for (buffer_index = 0; buffer_index < v4l2cam->buffer_count; buffer_index++) { + memset(&v4l2cam->buf, 0, sizeof(struct v4l2_buffer)); - vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vid_source->buf.memory = V4L2_MEMORY_MMAP; - vid_source->buf.index = buffer_index; + v4l2cam->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2cam->buf.memory = V4L2_MEMORY_MMAP; + v4l2cam->buf.index = buffer_index; - if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) { + if (xioctl(v4l2cam, VIDIOC_QBUF, &v4l2cam->buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF"); return -1; } @@ -847,7 +705,7 @@ static int v4l2_mmap_set(struct video_dev *curdev) type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(vid_source, VIDIOC_STREAMON, &type) == -1) { + if (xioctl(v4l2cam, VIDIOC_STREAMON, &type) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,_("Error starting stream. VIDIOC_STREAMON")); return -1; @@ -856,33 +714,23 @@ static int v4l2_mmap_set(struct video_dev *curdev) return 0; } -static int v4l2_imgs_set(struct ctx_cam *cam, struct video_dev *curdev) +/* Assign the resulting sizes to the camera context items */ +static void v4l2_set_imgs(ctx_cam *cam) { - /* Set the items on the imgs */ - - cam->imgs.width = curdev->width; - cam->imgs.height = curdev->height; + cam->imgs.width = cam->v4l2cam->width; + cam->imgs.height = cam->v4l2cam->height; cam->imgs.motionsize = cam->imgs.width * cam->imgs.height; cam->imgs.size_norm = (cam->imgs.motionsize * 3) / 2; - cam->conf->width = curdev->width; - cam->conf->height = curdev->height; - - return 0; + cam->conf->width = cam->v4l2cam->width; + cam->conf->height = cam->v4l2cam->height; } -static int v4l2_capture(struct ctx_cam *cam, struct video_dev *curdev, unsigned char *map) +/* Capture the image into the buffer */ +static int v4l2_capture_buffer(ctx_v4l2cam *v4l2cam) { - - /* Capture a image */ - /* FIXME: This function needs to be refactored*/ - + int retcd; sigset_t set, old; - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - int shift, width, height, retcd; - - width = cam->conf->width; - height = cam->conf->height; /* Block signals during IOCTL */ sigemptyset(&set); @@ -893,43 +741,41 @@ static int v4l2_capture(struct ctx_cam *cam, struct video_dev *curdev, unsigned sigaddset(&set, SIGHUP); pthread_sigmask(SIG_BLOCK, &set, &old); - //MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - // ,_("1) vid_source->pframe %i"), vid_source->pframe); - - if (vid_source->pframe >= 0) { - if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) { + if (v4l2cam->pframe >= 0) { + if (xioctl(v4l2cam, VIDIOC_QBUF, &v4l2cam->buf) == -1) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF"); pthread_sigmask(SIG_UNBLOCK, &old, NULL); return -1; } } - memset(&vid_source->buf, 0, sizeof(struct v4l2_buffer)); + memset(&v4l2cam->buf, 0, sizeof(struct v4l2_buffer)); - vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vid_source->buf.memory = V4L2_MEMORY_MMAP; - vid_source->buf.bytesused = 0; + v4l2cam->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + v4l2cam->buf.memory = V4L2_MEMORY_MMAP; + v4l2cam->buf.bytesused = 0; - if (xioctl(vid_source, VIDIOC_DQBUF, &vid_source->buf) == -1) { + if (xioctl(v4l2cam, VIDIOC_DQBUF, &v4l2cam->buf) == -1) { /* * Some drivers return EIO when there is no signal, * driver might dequeue an (empty) buffer despite * returning an error, or even stop capturing. */ if (errno == EIO) { - vid_source->pframe++; + v4l2cam->pframe++; - if ((u32)vid_source->pframe >= vid_source->req.count) - vid_source->pframe = 0; + if (v4l2cam->pframe >= (int)v4l2cam->req.count) { + v4l2cam->pframe = 0; + } - vid_source->buf.index = vid_source->pframe; - MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO + v4l2cam->buf.index = v4l2cam->pframe; + MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO ,"VIDIOC_DQBUF: EIO " - "(vid_source->pframe %d)", vid_source->pframe); - retcd = 1; + "(vid_source->pframe %ud)", v4l2cam->pframe); + retcd = 1; } else if (errno == EAGAIN) { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF: EAGAIN" - " (vid_source->pframe %d)", vid_source->pframe); + " (vid_source->pframe %ud)", v4l2cam->pframe); retcd = 1; } else { MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF"); @@ -940,326 +786,336 @@ static int v4l2_capture(struct ctx_cam *cam, struct video_dev *curdev, unsigned return retcd; } - //MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "2) vid_source->pframe %i", vid_source->pframe); - - vid_source->pframe = vid_source->buf.index; - vid_source->buffers[vid_source->buf.index].used = vid_source->buf.bytesused; - vid_source->buffers[vid_source->buf.index].content_length = vid_source->buf.bytesused; - - //MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "3) vid_source->pframe %i " - // "vid_source->buf.index %i", vid_source->pframe, vid_source->buf.index); + v4l2cam->pframe = v4l2cam->buf.index; + v4l2cam->buffers[v4l2cam->buf.index].used = v4l2cam->buf.bytesused; + v4l2cam->buffers[v4l2cam->buf.index].content_length = v4l2cam->buf.bytesused; pthread_sigmask(SIG_UNBLOCK, &old, NULL); /*undo the signal blocking */ - { - video_buff *the_buffer = &vid_source->buffers[vid_source->buf.index]; + return 0; - //MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO - // ,_("the_buffer index %d Address (%x)") - // ,vid_source->buf.index, the_buffer->ptr); - shift = 0; - /*The FALLTHROUGH is a special comment required by compiler. Do not edit it*/ - switch (curdev->pixfmt_src) { - case V4L2_PIX_FMT_RGB24: - vid_rgb24toyuv420p(map, the_buffer->ptr, width, height); - return 0; +} - case V4L2_PIX_FMT_UYVY: - vid_uyvyto420p(map, the_buffer->ptr, (unsigned)width, (unsigned)height); - return 0; +/* Convert captured image to the standard motion pixel format*/ +static int v4l2_capture_convert(ctx_cam *cam, ctx_v4l2cam *v4l2cam, unsigned char *img_norm) +{ + int shift; + video_buff *the_buffer = &v4l2cam->buffers[v4l2cam->buf.index]; - case V4L2_PIX_FMT_YUYV: - vid_yuv422to420p(map, the_buffer->ptr, width, height); - return 0; - case V4L2_PIX_FMT_YUV422P: - vid_yuv422pto420p(map, the_buffer->ptr, width, height); - return 0; + shift = 0; + /*The FALLTHROUGH is a special comment required by compiler. */ + switch (v4l2cam->pixfmt_src) { + case V4L2_PIX_FMT_RGB24: + vid_rgb24toyuv420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + return 0; - case V4L2_PIX_FMT_YUV420: - memcpy(map, the_buffer->ptr, the_buffer->content_length); - return 0; + case V4L2_PIX_FMT_UYVY: + vid_uyvyto420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + return 0; - case V4L2_PIX_FMT_PJPG: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_JPEG: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_MJPEG: - return vid_mjpegtoyuv420p(map, the_buffer->ptr, width, height - ,the_buffer->content_length); + case V4L2_PIX_FMT_YUYV: + vid_yuv422to420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + return 0; - /* FIXME: quick hack to allow work all bayer formats */ - case V4L2_PIX_FMT_SBGGR16: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_SGBRG8: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_SGRBG8: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_SBGGR8: /* bayer */ - vid_bayer2rgb24(cam->imgs.common_buffer, the_buffer->ptr, width, height); - vid_rgb24toyuv420p(map, cam->imgs.common_buffer, width, height); - return 0; + case V4L2_PIX_FMT_YUV422P: + vid_yuv422pto420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + return 0; - case V4L2_PIX_FMT_SPCA561: - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_SN9C10X: - vid_sonix_decompress(map, the_buffer->ptr, width, height); - vid_bayer2rgb24(cam->imgs.common_buffer, map, width, height); - vid_rgb24toyuv420p(map, cam->imgs.common_buffer, width, height); - return 0; - case V4L2_PIX_FMT_Y12: - shift += 2; - /*FALLTHROUGH*/ - case V4L2_PIX_FMT_Y10: - shift += 2; - vid_y10torgb24(cam->imgs.common_buffer, the_buffer->ptr, width, height, shift); - vid_rgb24toyuv420p(map, cam->imgs.common_buffer, width, height); - return 0; - case V4L2_PIX_FMT_GREY: - vid_greytoyuv420p(map, the_buffer->ptr, width, height); - return 0; - } + case V4L2_PIX_FMT_YUV420: + memcpy(img_norm, the_buffer->ptr, the_buffer->content_length); + return 0; + + case V4L2_PIX_FMT_PJPG: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_JPEG: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_MJPEG: + return vid_mjpegtoyuv420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height + ,the_buffer->content_length); + + case V4L2_PIX_FMT_SBGGR16: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_SGBRG8: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_SGRBG8: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_SBGGR8: /* bayer */ + vid_bayer2rgb24(cam->imgs.common_buffer, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + vid_rgb24toyuv420p(img_norm, cam->imgs.common_buffer, v4l2cam->width, v4l2cam->height); + return 0; + + case V4L2_PIX_FMT_SPCA561: + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_SN9C10X: + vid_sonix_decompress(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + vid_bayer2rgb24(cam->imgs.common_buffer, img_norm, v4l2cam->width, v4l2cam->height); + vid_rgb24toyuv420p(img_norm, cam->imgs.common_buffer, v4l2cam->width, v4l2cam->height); + return 0; + + case V4L2_PIX_FMT_Y12: + shift += 2; + /*FALLTHROUGH*/ + case V4L2_PIX_FMT_Y10: + shift += 2; + vid_y10torgb24(cam->imgs.common_buffer, the_buffer->ptr, v4l2cam->width, v4l2cam->height, shift); + vid_rgb24toyuv420p(img_norm, cam->imgs.common_buffer, v4l2cam->width, v4l2cam->height); + return 0; + + case V4L2_PIX_FMT_GREY: + vid_greytoyuv420p(img_norm, the_buffer->ptr, v4l2cam->width, v4l2cam->height); + return 0; } return 1; + } -static int v4l2_device_init(struct ctx_cam *cam, struct video_dev *curdev) +static int v4l2_device_init(ctx_cam *cam) { + int retcd, indx; - src_v4l2_t *vid_source; + cam->v4l2cam = (struct ctx_v4l2cam*)mymalloc(sizeof(struct ctx_v4l2cam)); + cam->v4l2cam->devctrl_array = NULL; + cam->v4l2cam->devctrl_count = 0; + cam->v4l2cam->buffer_count= 0; + cam->v4l2cam->pframe = -1; + cam->v4l2cam->finish = &cam->finish_cam; + cam->v4l2cam->buffers = NULL; - /* Allocate memory for the state structure. */ - if (!(vid_source =(src_v4l2_t*) calloc(1, sizeof(src_v4l2_t)))) { - MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, _("Out of memory.")); - vid_source = NULL; + cam->v4l2cam->params =(struct ctx_params*) mymalloc(sizeof(struct ctx_params)); + memset(cam->v4l2cam->params, 0, sizeof(struct ctx_params)); + cam->v4l2cam->params->params_array = NULL; + cam->v4l2cam->params->params_count = 0; + cam->v4l2cam->params->update_params = TRUE; /*Set trigger to update the params */ + + retcd = util_parms_parse(cam->v4l2cam->params, cam->conf->v4l2_params); + if (retcd < 0) { + util_parms_free(cam->v4l2cam->params); + free(cam->v4l2cam); return -1; } - pthread_mutexattr_init(&curdev->attr); - pthread_mutex_init(&curdev->mutex, &curdev->attr); + util_parms_add_default(cam->v4l2cam->params, "input", "-1"); + util_parms_add_default(cam->v4l2cam->params, "palette", "17"); + util_parms_add_default(cam->v4l2cam->params, "norm", "0"); + util_parms_add_default(cam->v4l2cam->params, "frequency", "0"); - curdev->usage_count = 1; - curdev->input = cam->conf->input; - curdev->norm = cam->conf->norm; - curdev->frequency = cam->conf->frequency; - curdev->height = cam->conf->height; - curdev->width = cam->conf->width; - curdev->devctrl_array = NULL; - curdev->devctrl_count = 0; - curdev->owner = -1; - curdev->fps = 0; - curdev->buffer_count= 0; + for (indx = 0; indx < cam->v4l2cam->params->params_count; indx++) { + if (mystreq(cam->v4l2cam->params->params_array[indx].param_name,"input")) { + cam->v4l2cam->input = atoi(cam->v4l2cam->params->params_array[indx].param_value); + } + if (mystreq(cam->v4l2cam->params->params_array[indx].param_name,"palette")) { + cam->v4l2cam->palette = atoi(cam->v4l2cam->params->params_array[indx].param_value); + } + if (mystreq(cam->v4l2cam->params->params_array[indx].param_name,"norm")) { + cam->v4l2cam->norm = atoi(cam->v4l2cam->params->params_array[indx].param_value); + } + if (mystreq(cam->v4l2cam->params->params_array[indx].param_name,"frequency")) { + cam->v4l2cam->frequency = atol(cam->v4l2cam->params->params_array[indx].param_value); + } + } - curdev->v4l2_private = vid_source; - vid_source->fd_device = curdev->fd_device; - vid_source->fps = cam->conf->framerate; - vid_source->pframe = -1; - vid_source->finish = &cam->finish_cam; - vid_source->buffers = NULL; + cam->v4l2cam->height = cam->conf->height; + cam->v4l2cam->width = cam->conf->width; + cam->v4l2cam->fps =cam->conf->framerate; return 0; } -static void v4l2_device_select(struct ctx_cam *cam, struct video_dev *curdev, unsigned char *map) +/* Update and set user params if needed */ +static void v4l2_device_select(ctx_cam *cam) { + int retcd; - int indx, retcd; + if (cam->v4l2cam->params->update_params == TRUE) { - if (curdev->v4l2_private == NULL){ - MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Device not ready")); - return; - } - - if (cam->conf->input != curdev->input || - cam->conf->frequency != curdev->frequency || - cam->conf->norm != curdev->norm) { - - retcd = v4l2_input_select(cam, curdev); - if (retcd == 0) retcd = v4l2_norm_select(cam, curdev); - if (retcd == 0) retcd = v4l2_frequency_select(cam, curdev); - if (retcd == 0) retcd = util_parms_parse(cam->vdev, cam->conf->v4l2_params); - if (retcd == 0) retcd = v4l2_parms_set(cam, curdev); - if (retcd == 0) retcd = v4l2_ctrls_set(curdev); - if (retcd < 0 ){ - MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO - ,_("Errors occurred during device select")); - } - - /* Clear the buffers from previous "robin" pictures*/ - for (indx =0; indx < curdev->buffer_count; indx++){ - v4l2_capture(cam, curdev, map); - } - - /* Skip the requested round robin frame count */ - for (indx = 1; indx < cam->conf->roundrobin_skip; indx++){ - v4l2_capture(cam, curdev, map); - } - - } else { - /* No round robin - we only adjust picture controls */ - retcd = util_parms_parse(cam->vdev, cam->conf->v4l2_params); - if (retcd == 0) retcd = v4l2_parms_set(cam, curdev); - if (retcd == 0) retcd = v4l2_ctrls_set(curdev); + retcd = util_parms_parse(cam->v4l2cam->params, cam->conf->v4l2_params); if (retcd < 0 ) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO - ,_("Errors occurred during device select")); + ,_("Error parsing the user parameters")); + return; } + + retcd = v4l2_parms_set(cam->v4l2cam); + if (retcd < 0 ) { + MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO + ,_("Error setting device controls")); + return; + } + + v4l2_ctrls_set(cam->v4l2cam); } - - } -static int v4l2_device_open(struct ctx_cam *cam, struct video_dev *curdev) +/* Open the device */ +static int v4l2_device_open(ctx_cam *cam) { int fd_device; - /* Open the video device */ - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Using v4l2_device %s and input %d") - ,cam->conf->v4l2_device.c_str(), cam->conf->input); - cam->conf->v4l2_device.copy(curdev->v4l2_device,PATH_MAX); - - curdev->fd_device = -1; + cam->v4l2cam->fd_device = -1; fd_device = -1; cam->watchdog = 60; - fd_device = open(curdev->v4l2_device, O_RDWR|O_CLOEXEC); + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO + , _("Opening video device %s") + , cam->conf->v4l2_device.c_str()); + + fd_device = open(cam->conf->v4l2_device.c_str(), O_RDWR|O_CLOEXEC); if (fd_device > 0) { - curdev->fd_device = fd_device; - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - vid_source->fd_device = fd_device; - return 0; + cam->v4l2cam->fd_device = fd_device; + } else { + MOTION_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO + , _("Failed to open video device %s") + , cam->conf->v4l2_device.c_str()); + return -1; } - MOTION_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO - ,_("Failed to open video device %s") - ,cam->conf->v4l2_device.c_str()); - return -1; - -} - -static void v4l2_device_close(struct video_dev *curdev) -{ - - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - enum v4l2_buf_type type; - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (vid_source != NULL){ - xioctl(vid_source, VIDIOC_STREAMOFF, &type); - } - - if (vid_source->fd_device != -1){ - close(vid_source->fd_device); - vid_source->fd_device = -1; - } -} - -static void v4l2_device_cleanup(struct video_dev *curdev) -{ - - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - - unsigned int indx; - int indx2; - - if (vid_source->buffers != NULL) { - for (indx = 0; indx < vid_source->req.count; indx++){ - munmap(vid_source->buffers[indx].ptr, vid_source->buffers[indx].size); - } - free(vid_source->buffers); - vid_source->buffers = NULL; - } - - if (vid_source != NULL){ - free(vid_source); - curdev->v4l2_private = NULL; - } - - if (curdev->devctrl_count != 0 ){ - for (indx2=0; indx2 < curdev->devctrl_count; indx2++){ - free(curdev->devctrl_array[indx2].ctrl_iddesc); - free(curdev->devctrl_array[indx2].ctrl_name); - curdev->devctrl_array[indx2].ctrl_iddesc = NULL; - curdev->devctrl_array[indx2].ctrl_name = NULL; - } - free(curdev->devctrl_array); - curdev->devctrl_array = NULL; - } - curdev->devctrl_count=0; - -} - -static int v4l2_device_capability(struct video_dev *curdev) -{ - - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; - - if (xioctl(vid_source, VIDIOC_QUERYCAP, &vid_source->cap) < 0) { + if (xioctl(cam->v4l2cam, VIDIOC_QUERYCAP, &cam->v4l2cam->cap) < 0) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Not a V4L2 device?")); return -1; } - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------"); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.driver: \"%s\"",vid_source->cap.driver); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.card: \"%s\"",vid_source->cap.card); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.bus_info: \"%s\"",vid_source->cap.bus_info); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.capabilities=0x%08X",vid_source->cap.capabilities); - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------"); - - if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_CAPTURE"); - if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OUTPUT"); - if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OVERLAY"); - if (vid_source->cap.capabilities & V4L2_CAP_VBI_CAPTURE) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VBI_CAPTURE"); - if (vid_source->cap.capabilities & V4L2_CAP_VBI_OUTPUT) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VBI_OUTPUT"); - if (vid_source->cap.capabilities & V4L2_CAP_RDS_CAPTURE) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- RDS_CAPTURE"); - if (vid_source->cap.capabilities & V4L2_CAP_TUNER) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- TUNER"); - if (vid_source->cap.capabilities & V4L2_CAP_AUDIO) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- AUDIO"); - if (vid_source->cap.capabilities & V4L2_CAP_READWRITE) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- READWRITE"); - if (vid_source->cap.capabilities & V4L2_CAP_ASYNCIO) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- ASYNCIO"); - if (vid_source->cap.capabilities & V4L2_CAP_STREAMING) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- STREAMING"); - if (vid_source->cap.capabilities & V4L2_CAP_TIMEPERFRAME) - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- TIMEPERFRAME"); - - if (!(vid_source->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + if (!(cam->v4l2cam->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Device does not support capturing.")); return -1; } return 0; + } -static int v4l2_fps_set(struct ctx_cam *cam, struct video_dev *curdev) +static void v4l2_log_types(ctx_v4l2cam *v4l2cam) { - src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private; + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------"); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.driver: \"%s\"",v4l2cam->cap.driver); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.card: \"%s\"",v4l2cam->cap.card); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.bus_info: \"%s\"",v4l2cam->cap.bus_info); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.capabilities=0x%08X",v4l2cam->cap.capabilities); + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------"); + + if (v4l2cam->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_CAPTURE"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OUTPUT"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OVERLAY"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_VBI_CAPTURE) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VBI_CAPTURE"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_VBI_OUTPUT) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- VBI_OUTPUT"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_RDS_CAPTURE) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- RDS_CAPTURE"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_TUNER) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- TUNER"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_AUDIO) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- AUDIO"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_READWRITE) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- READWRITE"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_ASYNCIO) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- ASYNCIO"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_STREAMING) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- STREAMING"); + } + if (v4l2cam->cap.capabilities & V4L2_CAP_TIMEPERFRAME) { + MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "- TIMEPERFRAME"); + } + + return; +} + +static void v4l2_log_formats(ctx_v4l2cam *v4l2cam) +{ + palette_item *palette_array; + struct v4l2_fmtdesc dev_format; + struct v4l2_frmsizeenum dev_sizes; + struct v4l2_frmivalenum dev_frameint; + int indx_format, indx_sizes, indx_frameint; + + palette_array = (palette_item *)malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1)); + + v4l2_palette_init(palette_array); + + memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc)); + dev_format.index = indx_format = 0; + dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + while (xioctl(v4l2cam, VIDIOC_ENUM_FMT, &dev_format) != -1) { + MOTION_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(v4l2cam, VIDIOC_ENUM_FRAMESIZES, &dev_sizes) != -1) { + MOTION_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(v4l2cam, VIDIOC_ENUM_FRAMEINTERVALS, &dev_frameint) != -1) { + MOTION_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 = ++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 = ++indx_sizes; + dev_sizes.pixel_format = dev_format.pixelformat; + } + memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc)); + dev_format.index = ++indx_format; + dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + + free(palette_array); + + return; +} + +static void v4l2_set_fps(ctx_v4l2cam *v4l2cam) +{ struct v4l2_streamparm setfps; int retcd; + 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 = cam->conf->framerate; + setfps.parm.capture.timeperframe.denominator = v4l2cam->fps; MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO , _("Trying to set fps to %d") , setfps.parm.capture.timeperframe.denominator); - retcd = xioctl(vid_source, VIDIOC_S_PARM, &setfps); + retcd = xioctl(v4l2cam, VIDIOC_S_PARM, &setfps); if (retcd != 0) { MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO ,_("Error setting fps. Return code %d"), retcd); @@ -1269,211 +1125,120 @@ static int v4l2_fps_set(struct ctx_cam *cam, struct video_dev *curdev) , _("Device set fps to %d") , setfps.parm.capture.timeperframe.denominator); - return 0; + return; } #endif /* HAVE_V4L2 */ -void v4l2_mutex_init(void) +void v4l2_cleanup(ctx_cam *cam) { #ifdef HAVE_V4L2 - pthread_mutex_init(&v4l2_mutex, NULL); + + enum v4l2_buf_type type; + int indx; + + MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO + ,_("Closing video device %s"), cam->conf->v4l2_device.c_str()); + + if (cam->v4l2cam == NULL) { + return; + } + + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (cam->v4l2cam->fd_device != -1) { + xioctl(cam->v4l2cam, VIDIOC_STREAMOFF, &type); + + close(cam->v4l2cam->fd_device); + cam->v4l2cam->fd_device = -1; + } + + if (cam->v4l2cam->buffers != NULL) { + for (indx = 0; indx < (int)cam->v4l2cam->req.count; indx++){ + munmap(cam->v4l2cam->buffers[indx].ptr, cam->v4l2cam->buffers[indx].size); + } + free(cam->v4l2cam->buffers); + cam->v4l2cam->buffers = NULL; + } + + if (cam->v4l2cam->devctrl_count != 0) { + for (indx = 0; indx < cam->v4l2cam->devctrl_count; indx++){ + free(cam->v4l2cam->devctrl_array[indx].ctrl_iddesc); + free(cam->v4l2cam->devctrl_array[indx].ctrl_name); + cam->v4l2cam->devctrl_array[indx].ctrl_iddesc = NULL; + cam->v4l2cam->devctrl_array[indx].ctrl_name = NULL; + } + free(cam->v4l2cam->devctrl_array); + cam->v4l2cam->devctrl_array = NULL; + } + cam->v4l2cam->devctrl_count=0; + + util_parms_free(cam->v4l2cam->params); + + free(cam->v4l2cam->params); + + free(cam->v4l2cam); + cam->v4l2cam = NULL; + #else - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled")); + (void)cam; #endif // HAVE_V4L2 } -void v4l2_mutex_destroy(void) -{ - #ifdef HAVE_V4L2 - pthread_mutex_destroy(&v4l2_mutex); - #else - MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled")); - #endif // HAVE_V4L2 -} -int v4l2_start(struct ctx_cam *cam) +int v4l2_start(ctx_cam *cam) { #ifdef HAVE_V4L2 int retcd; - struct video_dev *curdev; - pthread_mutex_lock(&v4l2_mutex); - - /* If device is already open and initialized use it*/ - curdev = v4l2_devices; - while (curdev) { - if (mystreq(cam->conf->v4l2_device.c_str(), curdev->v4l2_device)) { - retcd = v4l2_vdev_init(cam); - if (retcd == 0) retcd = util_parms_parse(cam->vdev, cam->conf->v4l2_params); - if (retcd == 0) retcd = v4l2_imgs_set(cam, curdev); - if (retcd == 0) { - curdev->usage_count++; - retcd = curdev->fd_device; - } - pthread_mutex_unlock(&v4l2_mutex); - return retcd; - } - curdev = curdev->next; - } - - curdev = (struct video_dev*)mymalloc(sizeof(struct video_dev)); - - curdev->starting = TRUE; - - retcd = v4l2_device_init(cam, curdev); - if (retcd == 0) retcd = v4l2_vdev_init(cam); - if (retcd == 0) retcd = v4l2_device_open(cam, curdev); - if (retcd == 0) retcd = v4l2_device_capability(curdev); - if (retcd == 0) retcd = v4l2_input_select(cam, curdev); - if (retcd == 0) retcd = v4l2_norm_select(cam, curdev); - if (retcd == 0) retcd = v4l2_frequency_select(cam, curdev); - if (retcd == 0) retcd = v4l2_pixfmt_select(cam, curdev); - if (retcd == 0) retcd = v4l2_fps_set(cam, curdev); - if (retcd == 0) retcd = v4l2_ctrls_count(curdev); - if (retcd == 0) retcd = v4l2_ctrls_list(curdev); - if (retcd == 0) retcd = util_parms_parse(cam->vdev, cam->conf->v4l2_params); - if (retcd == 0) retcd = v4l2_parms_set(cam, curdev); - if (retcd == 0) retcd = v4l2_ctrls_set(curdev); - if (retcd == 0) retcd = v4l2_mmap_set(curdev); - if (retcd == 0) retcd = v4l2_imgs_set(cam, curdev); - if (retcd < 0){ - /* These may need more work to consider all the fail scenarios*/ - if (curdev->v4l2_private != NULL){ - free(curdev->v4l2_private); - curdev->v4l2_private = NULL; - } - pthread_mutexattr_destroy(&curdev->attr); - pthread_mutex_destroy(&curdev->mutex); - v4l2_vdev_deinit(cam); - if (curdev->fd_device != -1) close(curdev->fd_device); - free(curdev); - pthread_mutex_unlock(&v4l2_mutex); + retcd = v4l2_device_init(cam); + if (retcd == 0) retcd = v4l2_device_open(cam); + if (retcd == 0) v4l2_log_types(cam->v4l2cam); + if (retcd == 0) v4l2_log_formats(cam->v4l2cam); + if (retcd == 0) retcd = v4l2_set_input(cam->v4l2cam); + if (retcd == 0) v4l2_set_norm(cam->v4l2cam); + if (retcd == 0) v4l2_set_frequency(cam->v4l2cam); + if (retcd == 0) retcd = v4l2_set_palette(cam->v4l2cam); + if (retcd == 0) v4l2_set_fps(cam->v4l2cam); + if (retcd == 0) retcd = v4l2_ctrls_count(cam->v4l2cam); + if (retcd == 0) v4l2_ctrls_list(cam->v4l2cam); + if (retcd == 0) v4l2_ctrls_set(cam->v4l2cam); + if (retcd == 0) retcd = v4l2_set_mmap(cam->v4l2cam); + if (retcd == 0) v4l2_set_imgs(cam); + if (retcd < 0) { + v4l2_cleanup(cam); return retcd; } - curdev->starting = FALSE; - - /* Insert into linked list. */ - curdev->next = v4l2_devices; - v4l2_devices = curdev; - - pthread_mutex_unlock(&v4l2_mutex); - - return curdev->fd_device; + return cam->v4l2cam->fd_device; #else (void)cam; return -1; #endif // HAVE_V4l2 } -void v4l2_cleanup(struct ctx_cam *cam) +int v4l2_next(ctx_cam *cam, ctx_image_data *img_data) { #ifdef HAVE_V4L2 + int retcd; - struct video_dev *dev = v4l2_devices; - struct video_dev *prev = NULL; + v4l2_device_select(cam); - /* Cleanup the v4l2 part */ - pthread_mutex_lock(&v4l2_mutex); - while (dev) { - if (dev->fd_device == cam->video_dev) - break; - prev = dev; - dev = dev->next; - } - pthread_mutex_unlock(&v4l2_mutex); - - /* Set it as closed in thread ctx_cam. */ - cam->video_dev = -1; - - v4l2_vdev_deinit(cam); - - if (dev == NULL) { - MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO, _("Unable to find video device")); - return; + retcd = v4l2_capture_buffer(cam->v4l2cam); + if (retcd != 0) { + return retcd; } - if (--dev->usage_count == 0) { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Closing video device %s"), dev->v4l2_device); - - v4l2_device_close(dev); - v4l2_device_cleanup(dev); - - dev->fd_device = -1; - - /* Remove from list */ - if (prev == NULL) - v4l2_devices = dev->next; - else - prev->next = dev->next; - - pthread_mutexattr_destroy(&dev->attr); - pthread_mutex_destroy(&dev->mutex); - free(dev); - - } else { - MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO - ,_("Still %d users of video device %s, so we don't close it now") - ,dev->usage_count, dev->v4l2_device); - /* - * There is still at least one thread using this device - * If we own it, release it. - */ - if (dev->owner == cam->threadnr) { - dev->frames = 0; - dev->owner = -1; - pthread_mutex_unlock(&dev->mutex); - } - } - - - #else - (void)cam; - #endif // HAVE_V4L2 -} - -int v4l2_next(struct ctx_cam *cam, struct ctx_image_data *img_data) -{ - #ifdef HAVE_V4L2 - int ret = -2; - struct ctx_config *conf = cam->conf; - struct video_dev *dev; - - pthread_mutex_lock(&v4l2_mutex); - dev = v4l2_devices; - while (dev) { - if (dev->fd_device == cam->video_dev) - break; - dev = dev->next; - } - pthread_mutex_unlock(&v4l2_mutex); - - if (dev == NULL){ - return -1; - } - - if (dev->owner != cam->threadnr) { - pthread_mutex_lock(&dev->mutex); - dev->owner = cam->threadnr; - dev->frames = conf->roundrobin_frames; - } - - v4l2_device_select(cam, dev, img_data->image_norm); - ret = v4l2_capture(cam, dev, img_data->image_norm); - - if (--dev->frames <= 0) { - dev->owner = -1; - dev->frames = 0; - pthread_mutex_unlock(&dev->mutex); + retcd = v4l2_capture_convert(cam, cam->v4l2cam, img_data->image_norm); + if (retcd != 0) { + return retcd; } /* Rotate the image as specified. */ rotate_map(cam, img_data); - return ret; + return retcd; #else (void)cam; (void)img_data; diff --git a/src/video_v4l2.hpp b/src/video_v4l2.hpp index 2b0d3eae..8ceb9dbd 100644 --- a/src/video_v4l2.hpp +++ b/src/video_v4l2.hpp @@ -20,8 +20,59 @@ #ifndef _INCLUDE_VIDEO_V4L2_H #define _INCLUDE_VIDEO_V4L2_H - void v4l2_mutex_init(void); - void v4l2_mutex_destroy(void); +typedef struct video_image_buff { + unsigned char *ptr; + int content_length; + size_t size; /* total allocated size */ + size_t used; /* bytes already used */ + struct timeval image_time; /* time this image was received */ +} video_buff; + +typedef struct palette_item_struct{ + unsigned int v4l2id; + char fourcc[5]; +} palette_item; + +struct ctx_v4l2cam_ctrl { + char *ctrl_name; /* The name as provided by the device */ + char *ctrl_iddesc; /* A motion description of the ID number for the control*/ + int ctrl_minimum; /* The minimum value permitted as reported by device*/ + int ctrl_maximum; /* The maximum value permitted as reported by device*/ + int ctrl_default; /* The default value for the control*/ + int ctrl_currval; /* The current value the control was set to */ + int ctrl_newval; /* The new value to set for the control */ + unsigned int ctrl_id; /* The ID number for the control as provided by the device*/ + unsigned int ctrl_type; /* The type of control as reported by the device*/ + int ctrl_menuitem; /* bool for whether item is a menu item description */ +}; + +struct ctx_v4l2cam { + int fd_device; + int input; + int norm; + int width; + int height; + unsigned long frequency; + int palette; + int fps; + int pixfmt_src; + int buffer_count; + ctx_v4l2cam_ctrl *devctrl_array; /*Array of all the controls in the device*/ + int devctrl_count; /*Count of the controls in the device*/ + int device_type; /*Camera, tuner, etc as provided by driver enum*/ + int device_tuner; /*Tuner number if applicable from driver*/ + struct ctx_params *params; /*User parameters for the camera */ + video_buff *buffers; + int pframe; + volatile unsigned int *finish; /* End the thread */ + #ifdef HAVE_V4L2 + struct v4l2_capability cap; + struct v4l2_format src_fmt; + struct v4l2_format dst_fmt; + struct v4l2_requestbuffers req; + struct v4l2_buffer buf; + #endif +}; int v4l2_start(struct ctx_cam *cam); int v4l2_next(struct ctx_cam *cam, struct ctx_image_data *img_data); diff --git a/src/webu.cpp b/src/webu.cpp index 4eb71b32..d2db05f2 100644 --- a/src/webu.cpp +++ b/src/webu.cpp @@ -54,6 +54,7 @@ #include "webu_text.hpp" #include "webu_stream.hpp" #include "track.hpp" +#include "video_v4l2.hpp" @@ -684,8 +685,8 @@ static int webu_process_config_set(struct webui_ctx *webui) /*If we are updating vid parms, set the flag to update the device.*/ if ((config_parms[indx].parm_name == "v4l2_parms") && - (webui->camlst[webui->thread_nbr]->vdev != NULL)) { - webui->camlst[webui->thread_nbr]->vdev->update_params = TRUE; + (webui->camlst[webui->thread_nbr]->v4l2cam->params != NULL)) { + webui->camlst[webui->thread_nbr]->v4l2cam->params->update_params = TRUE; } /* If changing language, do it now */