"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/video_v4l2.c" (14 Jan 2020, 61376 Bytes) of package /linux/misc/motion-Release-4.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "video_v4l2.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  *    video_v4l2.c
    3  *
    4  *    V4L2 interface with basically JPEG decompression support and even more ...
    5  *    Copyright 2006 Krzysztof Blaszkowski (kb@sysmikro.com.pl)
    6  *              2007 Angel Carpintero (motiondevelop@gmail.com)
    7  *    Refactor/rewrite code:  2018 MrDave
    8  *
    9  * This program is free software; you can redistribute it and/or modify it
   10  * under the terms of the GNU General Public License as published by the
   11  * Free Software Foundation; either version 2 of the License, or (at your
   12  * option) any later version.
   13  *
   14  * This program is distributed in the hope that it will be useful, but
   15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   17  * for more details.
   18  *
   19 */
   20 #include "translate.h"
   21 #include "rotate.h"    /* Already includes motion.h */
   22 #include "video_common.h"
   23 #include "video_v4l2.h"
   24 #include <sys/mman.h>
   25 
   26 
   27 #ifdef HAVE_V4L2
   28 
   29 #if defined(HAVE_LINUX_VIDEODEV2_H)
   30 #include <linux/videodev2.h>
   31 #else
   32 #include <sys/videoio.h>
   33 #endif
   34 
   35 #define u8 unsigned char
   36 #define u16 unsigned short
   37 #define u32 unsigned int
   38 #define s32 signed int
   39 
   40 #define MMAP_BUFFERS            4
   41 #define MIN_MMAP_BUFFERS        2
   42 #define V4L2_PALETTE_COUNT_MAX 21
   43 
   44 #define MAX2(x, y) ((x) > (y) ? (x) : (y))
   45 #define MIN2(x, y) ((x) < (y) ? (x) : (y))
   46 
   47 static pthread_mutex_t   v4l2_mutex;
   48 static struct video_dev *video_devices = NULL;
   49 
   50 typedef struct video_image_buff {
   51     unsigned char *ptr;
   52     int content_length;
   53     size_t size;                    /* total allocated size */
   54     size_t used;                    /* bytes already used */
   55     struct timeval image_time;      /* time this image was received */
   56 } video_buff;
   57 
   58 typedef struct {
   59     int fd_device;
   60     u32 fps;
   61 
   62     struct v4l2_capability cap;
   63     struct v4l2_format src_fmt;
   64     struct v4l2_format dst_fmt;
   65     struct v4l2_requestbuffers req;
   66     struct v4l2_buffer buf;
   67 
   68     video_buff *buffers;
   69 
   70     s32 pframe;
   71 
   72     u32 ctrl_flags;
   73     volatile unsigned int *finish;      /* End the thread */
   74 
   75 } src_v4l2_t;
   76 
   77 typedef struct palette_item_struct{
   78     u32      v4l2id;
   79     char     fourcc[5];
   80 } palette_item;
   81 
   82 static void v4l2_palette_init(palette_item *palette_array){
   83 
   84     int indx;
   85 
   86     /* When adding here, update the max defined as V4L2_PALETTE_COUNT_MAX above */
   87     palette_array[0].v4l2id = V4L2_PIX_FMT_SN9C10X;
   88     palette_array[1].v4l2id = V4L2_PIX_FMT_SBGGR16;
   89     palette_array[2].v4l2id = V4L2_PIX_FMT_SBGGR8;
   90     palette_array[3].v4l2id = V4L2_PIX_FMT_SPCA561;
   91     palette_array[4].v4l2id = V4L2_PIX_FMT_SGBRG8;
   92     palette_array[5].v4l2id = V4L2_PIX_FMT_SGRBG8;
   93     palette_array[6].v4l2id = V4L2_PIX_FMT_PAC207;
   94     palette_array[7].v4l2id = V4L2_PIX_FMT_PJPG;
   95     palette_array[8].v4l2id = V4L2_PIX_FMT_MJPEG;
   96     palette_array[9].v4l2id = V4L2_PIX_FMT_JPEG;
   97     palette_array[10].v4l2id = V4L2_PIX_FMT_RGB24;
   98     palette_array[11].v4l2id = V4L2_PIX_FMT_SPCA501;
   99     palette_array[12].v4l2id = V4L2_PIX_FMT_SPCA505;
  100     palette_array[13].v4l2id = V4L2_PIX_FMT_SPCA508;
  101     palette_array[14].v4l2id = V4L2_PIX_FMT_UYVY;
  102     palette_array[15].v4l2id = V4L2_PIX_FMT_YUYV;
  103     palette_array[16].v4l2id = V4L2_PIX_FMT_YUV422P;
  104     palette_array[17].v4l2id = V4L2_PIX_FMT_YUV420; /* most efficient for motion */
  105     palette_array[18].v4l2id = V4L2_PIX_FMT_Y10;
  106     palette_array[19].v4l2id = V4L2_PIX_FMT_Y12;
  107     palette_array[20].v4l2id = V4L2_PIX_FMT_GREY;
  108     palette_array[21].v4l2id = V4L2_PIX_FMT_H264;
  109 
  110     for (indx=0; indx <=V4L2_PALETTE_COUNT_MAX; indx++ ){
  111         sprintf(palette_array[indx].fourcc ,"%c%c%c%c"
  112                 ,palette_array[indx].v4l2id >> 0
  113                 ,palette_array[indx].v4l2id >> 8
  114                 ,palette_array[indx].v4l2id >> 16
  115                 ,palette_array[indx].v4l2id >> 24);
  116     }
  117 
  118 }
  119 
  120 #if defined (BSD)
  121 static int xioctl(src_v4l2_t *vid_source, unsigned long request, void *arg)
  122 #else
  123 static int xioctl(src_v4l2_t *vid_source, int request, void *arg)
  124 #endif
  125 {
  126     int ret;
  127 
  128     do
  129         ret = ioctl(vid_source->fd_device, request, arg);
  130     while (-1 == ret && EINTR == errno && !vid_source->finish);
  131 
  132     return ret;
  133 }
  134 
  135 static void v4l2_vdev_free(struct context *cnt){
  136     int indx;
  137 
  138     /* free the information we collected regarding the controls */
  139     if (cnt->vdev != NULL){
  140         if (cnt->vdev->usrctrl_count > 0){
  141             for (indx=0;indx<cnt->vdev->usrctrl_count;indx++){
  142                 free(cnt->vdev->usrctrl_array[indx].ctrl_name);
  143                 cnt->vdev->usrctrl_array[indx].ctrl_name=NULL;
  144             }
  145         }
  146         cnt->vdev->usrctrl_count = 0;
  147         if (cnt->vdev->usrctrl_array != NULL){
  148             free(cnt->vdev->usrctrl_array);
  149             cnt->vdev->usrctrl_array = NULL;
  150         }
  151 
  152         free(cnt->vdev);
  153         cnt->vdev = NULL;
  154     }
  155 }
  156 
  157 static int v4l2_vdev_init(struct context *cnt){
  158 
  159     /* Create the v4l2 context within the main thread context  */
  160     cnt->vdev = mymalloc(sizeof(struct vdev_context));
  161     memset(cnt->vdev, 0, sizeof(struct vdev_context));
  162     cnt->vdev->usrctrl_array = NULL;
  163     cnt->vdev->usrctrl_count = 0;
  164     cnt->vdev->update_parms = TRUE;     /*Set trigger that we have updated user parameters */
  165 
  166     return 0;
  167 
  168 }
  169 
  170 static int v4l2_ctrls_count(struct video_dev *curdev){
  171 
  172     /* Get the count of how many controls and menu items the device supports */
  173     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  174     struct v4l2_queryctrl       vid_ctrl;
  175     struct v4l2_querymenu       vid_menu;
  176     int indx;
  177 
  178     curdev->devctrl_count = 0;
  179 
  180     memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl));
  181     vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
  182     while (xioctl (vid_source, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) {
  183         if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS){
  184             vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
  185             continue;
  186         }
  187         curdev->devctrl_count++;
  188         if (vid_ctrl.type == V4L2_CTRL_TYPE_MENU) {
  189             for (indx = vid_ctrl.minimum; indx<=vid_ctrl.maximum; indx++){
  190                 memset(&vid_menu, 0, sizeof(struct v4l2_querymenu));
  191                 vid_menu.id = vid_ctrl.id;
  192                 vid_menu.index = indx;
  193                 if (xioctl(vid_source, VIDIOC_QUERYMENU, &vid_menu) == 0) curdev->devctrl_count++;
  194             }
  195         }
  196         vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
  197     }
  198 
  199     return 0;
  200 
  201 }
  202 
  203 static int v4l2_ctrls_list(struct video_dev *curdev){
  204 
  205     /* Get the names of the controls and menu items the device supports */
  206     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  207     struct v4l2_queryctrl       vid_ctrl;
  208     struct v4l2_querymenu       vid_menu;
  209     int indx, indx_ctrl;
  210 
  211     curdev->devctrl_array = NULL;
  212     if (curdev->devctrl_count == 0 ){
  213         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("No Controls found for device"));
  214         return 0;
  215     }
  216 
  217     curdev->devctrl_array = malloc(curdev->devctrl_count * sizeof(struct vid_devctrl_ctx));
  218 
  219     memset(&vid_ctrl, 0, sizeof(struct v4l2_queryctrl));
  220     vid_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
  221     indx_ctrl = 0;
  222     while (xioctl (vid_source, VIDIOC_QUERYCTRL, &vid_ctrl) == 0) {
  223         if (vid_ctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS){
  224             vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
  225             continue;
  226         }
  227 
  228         curdev->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id;
  229         curdev->devctrl_array[indx_ctrl].ctrl_type = vid_ctrl.type;
  230         curdev->devctrl_array[indx_ctrl].ctrl_default = vid_ctrl.default_value;
  231         curdev->devctrl_array[indx_ctrl].ctrl_currval = vid_ctrl.default_value;
  232         curdev->devctrl_array[indx_ctrl].ctrl_newval = vid_ctrl.default_value;
  233         curdev->devctrl_array[indx_ctrl].ctrl_menuitem = FALSE;
  234 
  235         curdev->devctrl_array[indx_ctrl].ctrl_name = malloc(32);
  236         sprintf(curdev->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_ctrl.name);
  237 
  238         curdev->devctrl_array[indx_ctrl].ctrl_iddesc = malloc(15);
  239         sprintf(curdev->devctrl_array[indx_ctrl].ctrl_iddesc,"ID%08d",vid_ctrl.id);
  240 
  241         curdev->devctrl_array[indx_ctrl].ctrl_minimum = vid_ctrl.minimum;
  242         curdev->devctrl_array[indx_ctrl].ctrl_maximum = vid_ctrl.maximum;
  243 
  244         if (vid_ctrl.type == V4L2_CTRL_TYPE_MENU) {
  245             for (indx = vid_ctrl.minimum; indx<=vid_ctrl.maximum; indx++){
  246                 memset(&vid_menu, 0, sizeof(struct v4l2_querymenu));
  247                 vid_menu.id = vid_ctrl.id;
  248                 vid_menu.index = indx;
  249                 if (xioctl(vid_source, VIDIOC_QUERYMENU, &vid_menu) == 0){
  250 
  251                     indx_ctrl++;
  252                     curdev->devctrl_array[indx_ctrl].ctrl_id = vid_ctrl.id;
  253                     curdev->devctrl_array[indx_ctrl].ctrl_type = 0;
  254                     curdev->devctrl_array[indx_ctrl].ctrl_menuitem = TRUE;
  255 
  256                     curdev->devctrl_array[indx_ctrl].ctrl_name = malloc(32);
  257                     sprintf(curdev->devctrl_array[indx_ctrl].ctrl_name,"%s",vid_menu.name);
  258 
  259                     curdev->devctrl_array[indx_ctrl].ctrl_iddesc = malloc(40);
  260                     sprintf(curdev->devctrl_array[indx_ctrl].ctrl_iddesc,"menu item: Value %d",indx);
  261 
  262                     curdev->devctrl_array[indx_ctrl].ctrl_minimum = 0;
  263                     curdev->devctrl_array[indx_ctrl].ctrl_maximum = 0;
  264                 }
  265             }
  266         }
  267         indx_ctrl++;
  268         vid_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
  269     }
  270 
  271     if (curdev->devctrl_count != 0 ){
  272         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("---------Controls---------"));
  273         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, _("  V4L2 ID   Name and Range"));
  274         for (indx=0; indx < curdev->devctrl_count; indx++){
  275             if (curdev->devctrl_array[indx].ctrl_menuitem){
  276                 MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "  %s %s"
  277                            ,curdev->devctrl_array[indx].ctrl_iddesc
  278                            ,curdev->devctrl_array[indx].ctrl_name);
  279             } else {
  280                 MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "%s %s, %d to %d"
  281                            ,curdev->devctrl_array[indx].ctrl_iddesc
  282                            ,curdev->devctrl_array[indx].ctrl_name
  283                            ,curdev->devctrl_array[indx].ctrl_minimum
  284                            ,curdev->devctrl_array[indx].ctrl_maximum);
  285             }
  286         }
  287         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "--------------------------");
  288     }
  289 
  290     return 0;
  291 
  292 }
  293 
  294 static int v4l2_ctrls_set(struct video_dev *curdev) {
  295 
  296     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  297     struct vid_devctrl_ctx *devitem;
  298     struct v4l2_control     vid_ctrl;
  299     int indx_dev, retcd;
  300 
  301     if (vid_source == NULL){
  302         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Device not ready"));
  303         return -1;
  304     }
  305 
  306     for (indx_dev= 0;indx_dev<curdev->devctrl_count;indx_dev++){
  307         devitem=&curdev->devctrl_array[indx_dev];
  308         if (!devitem->ctrl_menuitem) {
  309             if (devitem->ctrl_currval != devitem->ctrl_newval) {
  310                 memset(&vid_ctrl, 0, sizeof (struct v4l2_control));
  311                 vid_ctrl.id = devitem->ctrl_id;
  312                 vid_ctrl.value = devitem->ctrl_newval;
  313                 retcd = xioctl(vid_source, VIDIOC_S_CTRL, &vid_ctrl);
  314                 if (retcd < 0) {
  315                     MOTION_LOG(WRN, TYPE_VIDEO, SHOW_ERRNO
  316                         ,_("setting control %s \"%s\" to %d failed with return code %d")
  317                         ,devitem->ctrl_iddesc, devitem->ctrl_name
  318                         ,devitem->ctrl_newval,retcd);
  319                 } else {
  320                     if (curdev->starting)
  321                         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO
  322                             ,_("Set control \"%s\" to value %d")
  323                             ,devitem->ctrl_name, devitem->ctrl_newval);
  324                    devitem->ctrl_currval = devitem->ctrl_newval;
  325                 }
  326 
  327             }
  328         }
  329      }
  330 
  331     return 0;
  332 }
  333 
  334 static int v4l2_parms_set(struct context *cnt, struct video_dev *curdev){
  335 
  336     struct vid_devctrl_ctx  *devitem;
  337     struct vdev_usrctrl_ctx *usritem;
  338     int indx_dev, indx_user;
  339 
  340     if (cnt->conf.roundrobin_skip < 0) cnt->conf.roundrobin_skip = 1;
  341 
  342     if (curdev->devctrl_count == 0){
  343         cnt->vdev->update_parms = FALSE;
  344         return 0;
  345     }
  346 
  347     for (indx_dev=0; indx_dev<curdev->devctrl_count; indx_dev++ ) {
  348         devitem=&curdev->devctrl_array[indx_dev];
  349         devitem->ctrl_newval = devitem->ctrl_default;
  350         for (indx_user=0; indx_user<cnt->vdev->usrctrl_count; indx_user++){
  351             usritem=&cnt->vdev->usrctrl_array[indx_user];
  352             if ((!strcasecmp(devitem->ctrl_iddesc,usritem->ctrl_name)) ||
  353                 (!strcasecmp(devitem->ctrl_name  ,usritem->ctrl_name))) {
  354                 switch (devitem->ctrl_type) {
  355                 case V4L2_CTRL_TYPE_MENU:
  356                     /*FALLTHROUGH*/
  357                 case V4L2_CTRL_TYPE_INTEGER:
  358                     if (usritem->ctrl_value < devitem->ctrl_minimum){
  359                         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  360                             ,_("%s control option value %d is below minimum.  Using minimum")
  361                             ,devitem->ctrl_name, usritem->ctrl_value, devitem->ctrl_minimum);
  362                         devitem->ctrl_newval = devitem->ctrl_minimum;
  363                         usritem->ctrl_value  = devitem->ctrl_minimum;
  364                     } else if (usritem->ctrl_value > devitem->ctrl_maximum){
  365                         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  366                             ,_("%s control option value %d is above maximum.  Using maximum")
  367                             ,devitem->ctrl_name, usritem->ctrl_value, devitem->ctrl_maximum);
  368                         devitem->ctrl_newval = devitem->ctrl_maximum;
  369                         usritem->ctrl_value  = devitem->ctrl_maximum;
  370                     } else {
  371                         devitem->ctrl_newval = usritem->ctrl_value;
  372                     }
  373                     break;
  374                 case V4L2_CTRL_TYPE_BOOLEAN:
  375                     devitem->ctrl_newval = usritem->ctrl_value ? 1 : 0;
  376                     break;
  377                 default:
  378                     MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  379                         ,_("control type not supported yet"));
  380                 }
  381             }
  382         }
  383     }
  384 
  385     return 0;
  386 
  387 }
  388 
  389 static int v4l2_autobright(struct context *cnt, struct video_dev *curdev, int method) {
  390 
  391     struct vid_devctrl_ctx  *devitem;
  392     struct vdev_usrctrl_ctx *usritem;
  393     unsigned char           *image;
  394     int                      window_high;
  395     int                      window_low;
  396     int                      target;
  397     int indx, device_value, make_change;
  398     int pixel_count, avg, step;
  399     int parm_hysteresis, parm_damper, parm_max, parm_min;
  400     char cid_exp[15],cid_expabs[15],cid_bright[15];
  401 
  402 
  403     if ((method == 0) || (method > 3)) return 0;
  404 
  405     /* Set the values for the control variables */
  406     parm_hysteresis = 20;
  407     parm_damper = 20;
  408     parm_max = 255;
  409     parm_min = 0;
  410 
  411     target = -1;
  412 
  413     sprintf(cid_bright,"ID%08d",V4L2_CID_BRIGHTNESS);
  414     sprintf(cid_exp,"ID%08d",V4L2_CID_EXPOSURE);
  415     sprintf(cid_expabs,"ID%08d",V4L2_CID_EXPOSURE_ABSOLUTE);
  416 
  417     for (indx = 0;indx < cnt->vdev->usrctrl_count; indx++){
  418         usritem=&cnt->vdev->usrctrl_array[indx];
  419         if ((method == 1) &&
  420             ((!strcasecmp(usritem->ctrl_name,"brightness")) ||
  421              (!strcasecmp(usritem->ctrl_name,cid_bright)))) {
  422                target = usritem->ctrl_value;
  423         } else if ((method == 2) &&
  424             ((!strcasecmp(usritem->ctrl_name,"exposure")) ||
  425              (!strcasecmp(usritem->ctrl_name,cid_exp)))) {
  426                target = usritem->ctrl_value;
  427         } else if ((method == 3) &&
  428             ((!strcasecmp(usritem->ctrl_name,"exposure (absolute)")) ||
  429              (!strcasecmp(usritem->ctrl_name,cid_expabs)))) {
  430                target = usritem->ctrl_value;
  431         }
  432     }
  433 
  434     device_value = -1;
  435     for (indx = 0;indx < curdev->devctrl_count; indx++){
  436         devitem=&curdev->devctrl_array[indx];
  437         if ((method == 1) &&
  438             (devitem->ctrl_id == V4L2_CID_BRIGHTNESS)) {
  439             device_value = devitem->ctrl_currval;
  440             parm_max = devitem->ctrl_maximum;
  441             parm_min = devitem->ctrl_minimum;
  442             if (target == -1){
  443                 target = (int) ((devitem->ctrl_maximum - devitem->ctrl_minimum)/2);
  444             }
  445         } else if ((method == 2) &&
  446             (devitem->ctrl_id == V4L2_CID_EXPOSURE)) {
  447             device_value = devitem->ctrl_currval;
  448             parm_max = devitem->ctrl_maximum;
  449             parm_min = devitem->ctrl_minimum;
  450             if (target == -1){
  451                 target = (int) ((devitem->ctrl_maximum - devitem->ctrl_minimum)/2);
  452             }
  453         } else if ((method == 3) &&
  454             (devitem->ctrl_id == V4L2_CID_EXPOSURE_ABSOLUTE)) {
  455             device_value = devitem->ctrl_currval;
  456             parm_max = devitem->ctrl_maximum;
  457             parm_min = devitem->ctrl_minimum;
  458             if (target == -1){
  459                 target = (int) ((devitem->ctrl_maximum - devitem->ctrl_minimum)/2);
  460             }
  461         }
  462     }
  463     /* If we can not find control just give up */
  464     if (device_value == -1) return 0;
  465 
  466     avg = 0;
  467     pixel_count = 0;
  468     image = cnt->imgs.image_vprvcy.image_norm;
  469     for (indx = 0; indx < cnt->imgs.motionsize; indx += 10) {
  470         avg += image[indx];
  471         pixel_count++;
  472     }
  473     /* The compiler seems to mandate this be done in separate steps */
  474     /* Must be an integer math thing..must read up on this...*/
  475     avg = (avg / pixel_count);
  476     avg = avg * (parm_max - parm_min);
  477     avg = avg / 255;
  478 
  479     make_change = FALSE;
  480     step = 0;
  481     window_high = MIN2(target + parm_hysteresis, parm_max);
  482     window_low  = MAX2(target - parm_hysteresis, parm_min);
  483 
  484     /* Average is above window - turn down exposure - go for the target. */
  485     if (avg > window_high) {
  486         step = MIN2((avg - target) / parm_damper + 1, device_value - parm_min);
  487         if (device_value > step + 1 - parm_min) {
  488             device_value -= step;
  489             make_change = TRUE;
  490         } else {
  491             device_value = parm_min;
  492             make_change = TRUE;
  493         }
  494         //MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "Down Avg %d step: %d device:%d",avg,step,device_value);
  495     } else if (avg < window_low) {
  496         /* Average is below window - turn up exposure - go for the target. */
  497         step = MIN2((target - avg) / parm_damper + 1, parm_max - device_value);
  498         if (device_value < parm_max - step) {
  499             device_value += step;
  500             make_change = TRUE;
  501         } else {
  502             device_value = parm_max;
  503             make_change = TRUE;
  504         }
  505         //MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO, "Up Avg %d step: %d device:%d",avg,step,device_value);
  506     }
  507 
  508     if (make_change){
  509         for (indx = 0;indx < curdev->devctrl_count; indx++){
  510             devitem=&curdev->devctrl_array[indx];
  511             if ((method == 1) &&
  512                 (devitem->ctrl_id == V4L2_CID_BRIGHTNESS)) {
  513                 devitem->ctrl_newval = device_value;
  514             } else if ((method == 2) &&
  515                 (devitem->ctrl_id == V4L2_CID_EXPOSURE)) {
  516                 devitem->ctrl_newval = device_value;
  517             } else if ((method == 3) &&
  518                 (devitem->ctrl_id == V4L2_CID_EXPOSURE_ABSOLUTE)) {
  519                 devitem->ctrl_newval = device_value;
  520             }
  521         }
  522     }
  523 
  524     return 0;
  525 }
  526 
  527 static int v4l2_input_select(struct context *cnt, struct video_dev *curdev) {
  528 
  529     /* Set the input number for the device if applicable */
  530     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  531     struct v4l2_input    input;
  532 
  533     if ((cnt->conf.input == curdev->input) &&
  534         (!curdev->starting)) return 0;
  535 
  536     memset(&input, 0, sizeof (struct v4l2_input));
  537     if (cnt->conf.input == DEF_INPUT) {
  538         input.index = 0;
  539     } else {
  540         input.index = cnt->conf.input;
  541     }
  542 
  543     if (xioctl(vid_source, VIDIOC_ENUMINPUT, &input) == -1) {
  544         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  545             ,_("Unable to query input %d."
  546             " VIDIOC_ENUMINPUT, if you use a WEBCAM change input value in conf by -1")
  547             ,input.index);
  548         return -1;
  549     }
  550 
  551     if (curdev->starting){
  552         MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
  553             ,_("Name = \"%s\", type 0x%08X, status %08x")
  554             ,input.name, input.type, input.status);
  555     }
  556 
  557     if ((input.type & V4L2_INPUT_TYPE_TUNER) && (curdev->starting)){
  558         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  559             ,_("Name = \"%s\",- TUNER"),input.name);
  560     }
  561 
  562 
  563     if ((input.type & V4L2_INPUT_TYPE_CAMERA) && (curdev->starting)){
  564         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Name = \"%s\"- CAMERA"),input.name);
  565     }
  566 
  567     if (xioctl(vid_source, VIDIOC_S_INPUT, &input.index) == -1) {
  568         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  569             , _("Error selecting input %d VIDIOC_S_INPUT"), input.index);
  570         return -1;
  571     }
  572 
  573     curdev->input        = cnt->conf.input;
  574     curdev->device_type  = input.type;
  575     curdev->device_tuner = input.tuner;
  576 
  577     return 0;
  578 }
  579 
  580 static int v4l2_norm_select(struct context *cnt, struct video_dev *curdev) {
  581 
  582     /* Set the video standard (norm) for the device NTSC/PAL/etc*/
  583     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  584     struct v4l2_standard standard;
  585     v4l2_std_id std_id;
  586     int norm;
  587 
  588     if ((cnt->conf.norm == curdev->norm) &&
  589         (!curdev->starting)) return 0;
  590 
  591     norm = cnt->conf.norm;
  592     if (xioctl(vid_source, VIDIOC_G_STD, &std_id) == -1) {
  593         if (curdev->starting){
  594             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  595                 ,_("Device does not support specifying PAL/NTSC norm"));
  596         }
  597         norm = std_id = 0;    // V4L2_STD_UNKNOWN = 0
  598     }
  599 
  600     if (std_id) {
  601         memset(&standard, 0, sizeof(struct v4l2_standard));
  602         standard.index = 0;
  603 
  604         while (xioctl(vid_source, VIDIOC_ENUMSTD, &standard) == 0) {
  605             if ((standard.id & std_id) && (curdev->starting))
  606                 MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  607                     ,_("- video standard %s"), standard.name);
  608             standard.index++;
  609         }
  610 
  611         switch (norm) {
  612         case 1:
  613             std_id = V4L2_STD_NTSC;
  614             break;
  615         case 2:
  616             std_id = V4L2_STD_SECAM;
  617             break;
  618         default:
  619             std_id = V4L2_STD_PAL;
  620         }
  621 
  622         if (xioctl(vid_source, VIDIOC_S_STD, &std_id) == -1){
  623             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  624                 ,_("Error selecting standard method %d VIDIOC_S_STD")
  625                 ,(int)std_id);
  626         }
  627 
  628         if (curdev->starting) {
  629             if (std_id == V4L2_STD_NTSC) {
  630                 MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to NTSC"));
  631             } else if (std_id == V4L2_STD_SECAM) {
  632                 MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to SECAM"));
  633             } else {
  634                 MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Video standard set to PAL"));
  635             }
  636         }
  637     }
  638 
  639     curdev->norm = cnt->conf.norm;
  640 
  641     return 0;
  642 }
  643 
  644 static int v4l2_frequency_select(struct context *cnt, struct video_dev *curdev) {
  645 
  646     /* Set the frequency for the tuner */
  647     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  648     struct v4l2_tuner     tuner;
  649     struct v4l2_frequency freq;
  650 
  651     if ((curdev->frequency == cnt->conf.frequency)&&
  652         (!curdev->starting)) return 0;
  653 
  654     /* If this input is attached to a tuner, set the frequency. */
  655     if (curdev->device_type & V4L2_INPUT_TYPE_TUNER) {
  656         /* Query the tuners capabilities. */
  657         memset(&tuner, 0, sizeof(struct v4l2_tuner));
  658         tuner.index = curdev->device_tuner;
  659 
  660         if (xioctl(vid_source, VIDIOC_G_TUNER, &tuner) == -1) {
  661             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  662             ,_("tuner %d VIDIOC_G_TUNER"), tuner.index);
  663             return 0;
  664         }
  665 
  666         if (curdev->starting){
  667             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set tuner %d"), tuner.index);
  668         }
  669 
  670         /* Set the frequency. */
  671         memset(&freq, 0, sizeof(struct v4l2_frequency));
  672         freq.tuner = curdev->device_tuner;
  673         freq.type = V4L2_TUNER_ANALOG_TV;
  674         freq.frequency = (cnt->conf.frequency / 1000) * 16;
  675 
  676         if (xioctl(vid_source, VIDIOC_S_FREQUENCY, &freq) == -1) {
  677             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  678             ,_("freq %ul VIDIOC_S_FREQUENCY"), freq.frequency);
  679             return 0;
  680         }
  681 
  682         if (curdev->starting){
  683             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Set Frequency to %ul"), freq.frequency);
  684         }
  685     }
  686 
  687     curdev->frequency = cnt->conf.frequency;
  688 
  689     return 0;
  690 }
  691 
  692 static int v4l2_pixfmt_set(struct context *cnt, struct video_dev *curdev, u32 pixformat){
  693 
  694     /* Set the pixel format for the camera*/
  695     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  696 
  697     memset(&vid_source->dst_fmt, 0, sizeof(struct v4l2_format));
  698 
  699     vid_source->dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  700     vid_source->dst_fmt.fmt.pix.width = cnt->conf.width;
  701     vid_source->dst_fmt.fmt.pix.height = cnt->conf.height;
  702     vid_source->dst_fmt.fmt.pix.pixelformat = pixformat;
  703     vid_source->dst_fmt.fmt.pix.field = V4L2_FIELD_ANY;
  704 
  705     if (xioctl(vid_source, VIDIOC_TRY_FMT, &vid_source->dst_fmt) != -1 &&
  706         vid_source->dst_fmt.fmt.pix.pixelformat == pixformat) {
  707         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  708             ,_("Testing palette %c%c%c%c (%dx%d)")
  709             ,pixformat >> 0, pixformat >> 8
  710             ,pixformat >> 16, pixformat >> 24
  711             ,cnt->conf.width, cnt->conf.height);
  712 
  713         curdev->width = vid_source->dst_fmt.fmt.pix.width;
  714         curdev->height = vid_source->dst_fmt.fmt.pix.height;
  715 
  716         if (vid_source->dst_fmt.fmt.pix.width != (unsigned int) cnt->conf.width ||
  717             vid_source->dst_fmt.fmt.pix.height != (unsigned int) cnt->conf.height) {
  718 
  719             MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  720                 ,_("Adjusting resolution from %ix%i to %ix%i.")
  721                 ,cnt->conf.width, cnt->conf.height
  722                 ,vid_source->dst_fmt.fmt.pix.width
  723                 ,vid_source->dst_fmt.fmt.pix.height);
  724 
  725             if ((curdev->width % 8) || (curdev->height % 8)) {
  726                 MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  727                     ,_("Adjusted resolution not modulo 8."));
  728                 MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  729                     ,_("Specify different palette or width/height in config file."));
  730                 return -1;
  731             }
  732             cnt->conf.width = curdev->width;
  733             cnt->conf.height = curdev->height;
  734         }
  735 
  736         if (xioctl(vid_source, VIDIOC_S_FMT, &vid_source->dst_fmt) == -1) {
  737             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  738                 ,_("Error setting pixel format.\nVIDIOC_S_FMT: "));
  739             return -1;
  740         }
  741 
  742         curdev->pixfmt_src = pixformat;
  743 
  744         if (curdev->starting) {
  745             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  746                 ,_("Using palette %c%c%c%c (%dx%d)")
  747                 ,pixformat >> 0 , pixformat >> 8
  748                 ,pixformat >> 16, pixformat >> 24
  749                 ,cnt->conf.width, cnt->conf.height);
  750             MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
  751                 ,_("Bytesperlines %d sizeimage %d colorspace %08x")
  752                 ,vid_source->dst_fmt.fmt.pix.bytesperline
  753                 ,vid_source->dst_fmt.fmt.pix.sizeimage
  754                 ,vid_source->dst_fmt.fmt.pix.colorspace);
  755         }
  756 
  757         return 0;
  758     }
  759 
  760     return -1;
  761 }
  762 
  763 static int v4l2_pixfmt_select(struct context *cnt, struct video_dev *curdev) {
  764 
  765     /* Find and select the pixel format for camera*/
  766 
  767     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  768     struct v4l2_fmtdesc fmtd;
  769     int v4l2_pal, indx_palette, indx, retcd;
  770     palette_item *palette_array;
  771 
  772     palette_array = malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1));
  773 
  774     v4l2_palette_init(palette_array);
  775 
  776     if (cnt->conf.width % 8) {
  777         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  778             ,_("config image width (%d) is not modulo 8"), cnt->conf.width);
  779         cnt->conf.width = cnt->conf.width - (cnt->conf.width % 8) + 8;
  780         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  781             , _("Adjusting to width (%d)"), cnt->conf.width);
  782     }
  783 
  784     if (cnt->conf.height % 8) {
  785         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  786             ,_("config image height (%d) is not modulo 8"), cnt->conf.height);
  787         cnt->conf.height = cnt->conf.height - (cnt->conf.height % 8) + 8;
  788         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  789             ,_("Adjusting to height (%d)"), cnt->conf.height);
  790     }
  791 
  792     if (cnt->conf.v4l2_palette == 21 ) {
  793         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  794             ,_("H264(21) format not supported via videodevice.  Changing to default palette"));
  795         cnt->conf.v4l2_palette = 17;
  796     }
  797 
  798     /* First we try setting the config file value */
  799     indx_palette = cnt->conf.v4l2_palette;
  800     if ((indx_palette >= 0) && (indx_palette <= V4L2_PALETTE_COUNT_MAX)) {
  801         retcd = v4l2_pixfmt_set(cnt, curdev,palette_array[indx_palette].v4l2id);
  802         if (retcd >= 0){
  803             free(palette_array);
  804             return 0;
  805         }
  806         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  807             ,_("Configuration palette index %d (%s) for %dx%d doesn't work.")
  808             , indx_palette, palette_array[indx_palette].fourcc
  809             ,cnt->conf.width, cnt->conf.height);
  810     }
  811 
  812     memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
  813     fmtd.index = v4l2_pal = 0;
  814     fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  815     indx_palette = -1; /* -1 says not yet chosen */
  816     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, _("Supported palettes:"));
  817 
  818     while (xioctl(vid_source, VIDIOC_ENUM_FMT, &fmtd) != -1) {
  819         if (curdev->starting) {
  820             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "(%i) %c%c%c%c (%s)",
  821                        v4l2_pal, fmtd.pixelformat >> 0,
  822                        fmtd.pixelformat >> 8, fmtd.pixelformat >> 16,
  823                        fmtd.pixelformat >> 24, fmtd.description);
  824             MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
  825                 ,_("%d - %s (compressed : %d) (%#x)")
  826                 ,fmtd.index, fmtd.description, fmtd.flags, fmtd.pixelformat);
  827         }
  828          /* Adjust indx_palette if larger value found */
  829          /* Prevent the selection of H264 since this module does not support it */
  830         for (indx = 0; indx <= V4L2_PALETTE_COUNT_MAX; indx++)
  831             if ((palette_array[indx].v4l2id == fmtd.pixelformat) &&
  832                 (palette_array[indx].v4l2id != V4L2_PIX_FMT_H264))
  833                 indx_palette = indx;
  834 
  835         memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
  836         fmtd.index = ++v4l2_pal;
  837         fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  838     }
  839 
  840     if (indx_palette >= 0) {
  841         retcd = v4l2_pixfmt_set(cnt, curdev, palette_array[indx_palette].v4l2id);
  842         if (retcd >= 0){
  843             if (curdev->starting) {
  844                 MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  845                     ,_("Selected palette %s")
  846                     ,palette_array[indx_palette].fourcc);
  847             }
  848             free(palette_array);
  849             return 0;
  850         }
  851         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  852             ,_("Palette selection failed for format %s")
  853             , palette_array[indx_palette].fourcc);
  854     }
  855 
  856     MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  857         ,_("Unable to find a compatible palette format."));
  858 
  859     free(palette_array);
  860 
  861     return -1;
  862 
  863 
  864 }
  865 
  866 static int v4l2_mmap_set(struct video_dev *curdev) {
  867 
  868     /* Set the memory mapping from device to Motion*/
  869     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  870     enum v4l2_buf_type type;
  871     int buffer_index;
  872 
  873     /* Does the device support streaming? */
  874     if (!(vid_source->cap.capabilities & V4L2_CAP_STREAMING)) return -1;
  875 
  876     memset(&vid_source->req, 0, sizeof(struct v4l2_requestbuffers));
  877 
  878     vid_source->req.count = MMAP_BUFFERS;
  879     vid_source->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  880     vid_source->req.memory = V4L2_MEMORY_MMAP;
  881     if (xioctl(vid_source, VIDIOC_REQBUFS, &vid_source->req) == -1) {
  882         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  883                    ,_("Error requesting buffers %d for memory map. VIDIOC_REQBUFS")
  884                    ,vid_source->req.count);
  885         return -1;
  886     }
  887     curdev->buffer_count = vid_source->req.count;
  888 
  889     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
  890         ,_("mmap information: frames=%d"), curdev->buffer_count);
  891 
  892     if (curdev->buffer_count < MIN_MMAP_BUFFERS) {
  893         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  894             ,_("Insufficient buffer memory %d < MIN_MMAP_BUFFERS.")
  895             ,curdev->buffer_count);
  896         return -1;
  897     }
  898 
  899     vid_source->buffers = calloc(curdev->buffer_count, sizeof(video_buff));
  900     if (!vid_source->buffers) {
  901         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, _("Out of memory."));
  902         vid_source->buffers = NULL;
  903         return -1;
  904     }
  905 
  906     for (buffer_index = 0; buffer_index < curdev->buffer_count; buffer_index++) {
  907         struct v4l2_buffer buf;
  908 
  909         memset(&buf, 0, sizeof(struct v4l2_buffer));
  910 
  911         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  912         buf.memory = V4L2_MEMORY_MMAP;
  913         buf.index = buffer_index;
  914         if (xioctl(vid_source, VIDIOC_QUERYBUF, &buf) == -1) {
  915             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  916                 ,_("Error querying buffer %i\nVIDIOC_QUERYBUF: ")
  917                 ,buffer_index);
  918             free(vid_source->buffers);
  919             vid_source->buffers = NULL;
  920             return -1;
  921         }
  922 
  923         vid_source->buffers[buffer_index].size = buf.length;
  924         vid_source->buffers[buffer_index].ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
  925                                                      MAP_SHARED, vid_source->fd_device, buf.m.offset);
  926 
  927         if (vid_source->buffers[buffer_index].ptr == MAP_FAILED) {
  928             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  929                 ,_("Error mapping buffer %i mmap"), buffer_index);
  930             free(vid_source->buffers);
  931             vid_source->buffers = NULL;
  932             return -1;
  933         }
  934 
  935         MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
  936             ,_("%i length=%d Address (%x)")
  937             ,buffer_index, buf.length, vid_source->buffers[buffer_index].ptr);
  938     }
  939 
  940     for (buffer_index = 0; buffer_index < curdev->buffer_count; buffer_index++) {
  941         memset(&vid_source->buf, 0, sizeof(struct v4l2_buffer));
  942 
  943         vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  944         vid_source->buf.memory = V4L2_MEMORY_MMAP;
  945         vid_source->buf.index = buffer_index;
  946 
  947         if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) {
  948             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF");
  949             return -1;
  950         }
  951     }
  952 
  953     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  954 
  955     if (xioctl(vid_source, VIDIOC_STREAMON, &type) == -1) {
  956         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  957             ,_("Error starting stream. VIDIOC_STREAMON"));
  958         return -1;
  959     }
  960 
  961     return 0;
  962 }
  963 
  964 static int v4l2_imgs_set(struct context *cnt, struct video_dev *curdev) {
  965     /* Set the items on the imgs */
  966 
  967     cnt->imgs.width = curdev->width;
  968     cnt->imgs.height = curdev->height;
  969     cnt->imgs.motionsize = cnt->imgs.width * cnt->imgs.height;
  970     cnt->imgs.size_norm = (cnt->imgs.motionsize * 3) / 2;
  971     cnt->conf.width = curdev->width;
  972     cnt->conf.height = curdev->height;
  973 
  974     return 0;
  975 
  976 }
  977 
  978 static int v4l2_capture(struct context *cnt, struct video_dev *curdev, unsigned char *map) {
  979 
  980     /* Capture a image */
  981     /* FIXME:  This function needs to be refactored*/
  982 
  983     sigset_t set, old;
  984     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
  985     int shift, width, height, retcd;
  986 
  987     width = cnt->conf.width;
  988     height = cnt->conf.height;
  989 
  990     /* Block signals during IOCTL */
  991     sigemptyset(&set);
  992     sigaddset(&set, SIGCHLD);
  993     sigaddset(&set, SIGALRM);
  994     sigaddset(&set, SIGUSR1);
  995     sigaddset(&set, SIGTERM);
  996     sigaddset(&set, SIGHUP);
  997     pthread_sigmask(SIG_BLOCK, &set, &old);
  998 
  999     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
 1000         ,_("1) vid_source->pframe %i"), vid_source->pframe);
 1001 
 1002     if (vid_source->pframe >= 0) {
 1003         if (xioctl(vid_source, VIDIOC_QBUF, &vid_source->buf) == -1) {
 1004             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_QBUF");
 1005             pthread_sigmask(SIG_UNBLOCK, &old, NULL);
 1006             return -1;
 1007         }
 1008     }
 1009 
 1010     memset(&vid_source->buf, 0, sizeof(struct v4l2_buffer));
 1011 
 1012     vid_source->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1013     vid_source->buf.memory = V4L2_MEMORY_MMAP;
 1014     vid_source->buf.bytesused = 0;
 1015 
 1016     if (xioctl(vid_source, VIDIOC_DQBUF, &vid_source->buf) == -1) {
 1017         /*
 1018          * Some drivers return EIO when there is no signal,
 1019          * driver might dequeue an (empty) buffer despite
 1020          * returning an error, or even stop capturing.
 1021          */
 1022         if (errno == EIO) {
 1023             vid_source->pframe++;
 1024 
 1025             if ((u32)vid_source->pframe >= vid_source->req.count)
 1026                 vid_source->pframe = 0;
 1027 
 1028              vid_source->buf.index = vid_source->pframe;
 1029              MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
 1030                 ,"VIDIOC_DQBUF: EIO "
 1031                 "(vid_source->pframe %d)", vid_source->pframe);
 1032              retcd = 1;
 1033         } else if (errno == EAGAIN) {
 1034             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF: EAGAIN"
 1035                        " (vid_source->pframe %d)", vid_source->pframe);
 1036             retcd = 1;
 1037         } else {
 1038             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "VIDIOC_DQBUF");
 1039             retcd = -1;
 1040         }
 1041 
 1042         pthread_sigmask(SIG_UNBLOCK, &old, NULL);
 1043         return retcd;
 1044     }
 1045 
 1046     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "2) vid_source->pframe %i", vid_source->pframe);
 1047 
 1048     vid_source->pframe = vid_source->buf.index;
 1049     vid_source->buffers[vid_source->buf.index].used = vid_source->buf.bytesused;
 1050     vid_source->buffers[vid_source->buf.index].content_length = vid_source->buf.bytesused;
 1051 
 1052     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "3) vid_source->pframe %i "
 1053                "vid_source->buf.index %i", vid_source->pframe, vid_source->buf.index);
 1054 
 1055     pthread_sigmask(SIG_UNBLOCK, &old, NULL);    /*undo the signal blocking */
 1056 
 1057     {
 1058         video_buff *the_buffer = &vid_source->buffers[vid_source->buf.index];
 1059 
 1060         MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
 1061             ,_("the_buffer index %d Address (%x)")
 1062             ,vid_source->buf.index, the_buffer->ptr);
 1063         shift = 0;
 1064         /*The FALLTHROUGH is a special comment required by compiler.  Do not edit it*/
 1065         switch (curdev->pixfmt_src) {
 1066         case V4L2_PIX_FMT_RGB24:
 1067             vid_rgb24toyuv420p(map, the_buffer->ptr, width, height);
 1068             return 0;
 1069 
 1070         case V4L2_PIX_FMT_UYVY:
 1071             vid_uyvyto420p(map, the_buffer->ptr, (unsigned)width, (unsigned)height);
 1072             return 0;
 1073 
 1074         case V4L2_PIX_FMT_YUYV:
 1075             vid_yuv422to420p(map, the_buffer->ptr, width, height);
 1076             return 0;
 1077         case V4L2_PIX_FMT_YUV422P:
 1078             vid_yuv422pto420p(map, the_buffer->ptr, width, height);
 1079             return 0;
 1080 
 1081         case V4L2_PIX_FMT_YUV420:
 1082             memcpy(map, the_buffer->ptr, the_buffer->content_length);
 1083             return 0;
 1084 
 1085         case V4L2_PIX_FMT_PJPG:
 1086             /*FALLTHROUGH*/
 1087         case V4L2_PIX_FMT_JPEG:
 1088             /*FALLTHROUGH*/
 1089         case V4L2_PIX_FMT_MJPEG:
 1090             return vid_mjpegtoyuv420p(map, the_buffer->ptr, width, height
 1091                                       ,the_buffer->content_length);
 1092 
 1093         /* FIXME: quick hack to allow work all bayer formats */
 1094         case V4L2_PIX_FMT_SBGGR16:
 1095             /*FALLTHROUGH*/
 1096         case V4L2_PIX_FMT_SGBRG8:
 1097             /*FALLTHROUGH*/
 1098         case V4L2_PIX_FMT_SGRBG8:
 1099             /*FALLTHROUGH*/
 1100         case V4L2_PIX_FMT_SBGGR8:    /* bayer */
 1101             vid_bayer2rgb24(cnt->imgs.common_buffer, the_buffer->ptr, width, height);
 1102             vid_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height);
 1103             return 0;
 1104 
 1105         case V4L2_PIX_FMT_SPCA561:
 1106             /*FALLTHROUGH*/
 1107         case V4L2_PIX_FMT_SN9C10X:
 1108             vid_sonix_decompress(map, the_buffer->ptr, width, height);
 1109             vid_bayer2rgb24(cnt->imgs.common_buffer, map, width, height);
 1110             vid_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height);
 1111             return 0;
 1112         case V4L2_PIX_FMT_Y12:
 1113             shift += 2;
 1114             /*FALLTHROUGH*/
 1115         case V4L2_PIX_FMT_Y10:
 1116             shift += 2;
 1117             vid_y10torgb24(cnt->imgs.common_buffer, the_buffer->ptr, width, height, shift);
 1118             vid_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height);
 1119             return 0;
 1120         case V4L2_PIX_FMT_GREY:
 1121             vid_greytoyuv420p(map, the_buffer->ptr, width, height);
 1122             return 0;
 1123         }
 1124     }
 1125 
 1126     return 1;
 1127 }
 1128 
 1129 static int v4l2_device_init(struct context *cnt, struct video_dev *curdev) {
 1130 
 1131     src_v4l2_t *vid_source;
 1132 
 1133     /* Allocate memory for the state structure. */
 1134     if (!(vid_source = calloc(sizeof(src_v4l2_t), 1))) {
 1135         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, _("Out of memory."));
 1136         vid_source = NULL;
 1137         return -1;
 1138     }
 1139 
 1140     pthread_mutexattr_init(&curdev->attr);
 1141     pthread_mutex_init(&curdev->mutex, &curdev->attr);
 1142 
 1143     curdev->usage_count = 1;
 1144     curdev->input = cnt->conf.input;
 1145     curdev->norm = cnt->conf.norm;
 1146     curdev->frequency = cnt->conf.frequency;
 1147     curdev->height = cnt->conf.height;
 1148     curdev->width = cnt->conf.width;
 1149 
 1150     curdev->devctrl_array = NULL;
 1151     curdev->devctrl_count = 0;
 1152     curdev->owner = -1;
 1153     curdev->fps = 0;
 1154     curdev->buffer_count= 0;
 1155 
 1156     curdev->v4l2_private = vid_source;
 1157     vid_source->fd_device = curdev->fd_device;
 1158     vid_source->fps = cnt->conf.framerate;
 1159     vid_source->pframe = -1;
 1160     vid_source->finish = &cnt->finish;
 1161     vid_source->buffers = NULL;
 1162 
 1163     return 0;
 1164 }
 1165 
 1166 static void v4l2_device_select(struct context *cnt, struct video_dev *curdev, unsigned char *map) {
 1167 
 1168     int indx, retcd;
 1169 
 1170     if (curdev->v4l2_private == NULL){
 1171         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Device not ready"));
 1172         return;
 1173     }
 1174 
 1175     if (cnt->conf.input     != curdev->input ||
 1176         cnt->conf.frequency != curdev->frequency ||
 1177         cnt->conf.norm      != curdev->norm) {
 1178 
 1179         retcd = v4l2_input_select(cnt, curdev);
 1180         if (retcd == 0) retcd = v4l2_norm_select(cnt, curdev);
 1181         if (retcd == 0) retcd = v4l2_frequency_select(cnt, curdev);
 1182         if (retcd == 0) retcd = vid_parms_parse(cnt);
 1183         if (retcd == 0) retcd = v4l2_parms_set(cnt, curdev);
 1184         if (retcd == 0) retcd = v4l2_autobright(cnt, curdev, cnt->conf.auto_brightness);
 1185         if (retcd == 0) retcd = v4l2_ctrls_set(curdev);
 1186         if (retcd < 0 ){
 1187             MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
 1188                 ,_("Errors occurred during device select"));
 1189         }
 1190 
 1191         /* Clear the buffers from previous "robin" pictures*/
 1192         for (indx =0; indx < curdev->buffer_count; indx++){
 1193             v4l2_capture(cnt, curdev, map);
 1194         }
 1195 
 1196         /* Skip the requested round robin frame count */
 1197         for (indx = 1; indx < cnt->conf.roundrobin_skip; indx++){
 1198             v4l2_capture(cnt, curdev, map);
 1199         }
 1200 
 1201     } else {
 1202         /* No round robin - we only adjust picture controls */
 1203         retcd = vid_parms_parse(cnt);
 1204         if (retcd == 0) retcd = v4l2_parms_set(cnt, curdev);
 1205         if (retcd == 0) retcd = v4l2_autobright(cnt, curdev, cnt->conf.auto_brightness);
 1206         if (retcd == 0) retcd = v4l2_ctrls_set(curdev);
 1207         if (retcd < 0 ) {
 1208             MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
 1209                 ,_("Errors occurred during device select"));
 1210         }
 1211     }
 1212 
 1213 
 1214 }
 1215 
 1216 static int v4l2_device_open(struct context *cnt, struct video_dev *curdev) {
 1217 
 1218     int fd_device;
 1219     /* Open the video device */
 1220 
 1221     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
 1222         ,_("Using videodevice %s and input %d")
 1223         ,cnt->conf.video_device, cnt->conf.input);
 1224 
 1225     curdev->video_device = cnt->conf.video_device;
 1226     curdev->fd_device = -1;
 1227     fd_device = -1;
 1228 
 1229     fd_device = open(curdev->video_device, O_RDWR|O_CLOEXEC);
 1230     if (fd_device > 0) {
 1231         curdev->fd_device = fd_device;
 1232         src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
 1233         vid_source->fd_device = fd_device;
 1234         return 0;
 1235     }
 1236 
 1237     MOTION_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO
 1238         ,_("Failed to open video device %s")
 1239         ,cnt->conf.video_device);
 1240     return -1;
 1241 
 1242 }
 1243 
 1244 static void v4l2_device_close(struct video_dev *curdev) {
 1245 
 1246     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
 1247     enum v4l2_buf_type type;
 1248 
 1249     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1250 
 1251     if (vid_source != NULL){
 1252         xioctl(vid_source, VIDIOC_STREAMOFF, &type);
 1253     }
 1254 
 1255     if (vid_source->fd_device != -1){
 1256         close(vid_source->fd_device);
 1257         vid_source->fd_device = -1;
 1258     }
 1259 }
 1260 
 1261 static void v4l2_device_cleanup(struct video_dev *curdev) {
 1262 
 1263     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
 1264 
 1265     unsigned int indx;
 1266     int indx2;
 1267 
 1268     if (vid_source->buffers != NULL) {
 1269         for (indx = 0; indx < vid_source->req.count; indx++){
 1270             munmap(vid_source->buffers[indx].ptr, vid_source->buffers[indx].size);
 1271         }
 1272         free(vid_source->buffers);
 1273         vid_source->buffers = NULL;
 1274     }
 1275 
 1276     if (vid_source != NULL){
 1277         free(vid_source);
 1278         curdev->v4l2_private = NULL;
 1279     }
 1280 
 1281     if (curdev->devctrl_count != 0 ){
 1282         for (indx2=0; indx2 < curdev->devctrl_count; indx2++){
 1283             free(curdev->devctrl_array[indx2].ctrl_iddesc);
 1284             free(curdev->devctrl_array[indx2].ctrl_name);
 1285             curdev->devctrl_array[indx2].ctrl_iddesc = NULL;
 1286             curdev->devctrl_array[indx2].ctrl_name = NULL;
 1287         }
 1288         free(curdev->devctrl_array);
 1289         curdev->devctrl_array = NULL;
 1290     }
 1291     curdev->devctrl_count=0;
 1292 
 1293 }
 1294 
 1295 static int v4l2_device_capability(struct video_dev *curdev) {
 1296 
 1297     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
 1298 
 1299     if (xioctl(vid_source, VIDIOC_QUERYCAP, &vid_source->cap) < 0) {
 1300         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Not a V4L2 device?"));
 1301         return -1;
 1302     }
 1303 
 1304     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------");
 1305     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.driver: \"%s\"",vid_source->cap.driver);
 1306     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.card: \"%s\"",vid_source->cap.card);
 1307     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.bus_info: \"%s\"",vid_source->cap.bus_info);
 1308     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "cap.capabilities=0x%08X",vid_source->cap.capabilities);
 1309     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, "------------------------");
 1310 
 1311     if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
 1312         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_CAPTURE");
 1313     if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
 1314         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OUTPUT");
 1315     if (vid_source->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
 1316         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VIDEO_OVERLAY");
 1317     if (vid_source->cap.capabilities & V4L2_CAP_VBI_CAPTURE)
 1318         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VBI_CAPTURE");
 1319     if (vid_source->cap.capabilities & V4L2_CAP_VBI_OUTPUT)
 1320         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- VBI_OUTPUT");
 1321     if (vid_source->cap.capabilities & V4L2_CAP_RDS_CAPTURE)
 1322         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- RDS_CAPTURE");
 1323     if (vid_source->cap.capabilities & V4L2_CAP_TUNER)
 1324         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- TUNER");
 1325     if (vid_source->cap.capabilities & V4L2_CAP_AUDIO)
 1326         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- AUDIO");
 1327     if (vid_source->cap.capabilities & V4L2_CAP_READWRITE)
 1328         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- READWRITE");
 1329     if (vid_source->cap.capabilities & V4L2_CAP_ASYNCIO)
 1330         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- ASYNCIO");
 1331     if (vid_source->cap.capabilities & V4L2_CAP_STREAMING)
 1332         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- STREAMING");
 1333     if (vid_source->cap.capabilities & V4L2_CAP_TIMEPERFRAME)
 1334         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "- TIMEPERFRAME");
 1335 
 1336     if (!(vid_source->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
 1337         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO, _("Device does not support capturing."));
 1338         return -1;
 1339     }
 1340 
 1341     return 0;
 1342 }
 1343 
 1344 static int v4l2_fps_set(struct context *cnt, struct video_dev *curdev) {
 1345 
 1346     src_v4l2_t *vid_source = (src_v4l2_t *) curdev->v4l2_private;
 1347     struct v4l2_streamparm setfps;
 1348     int retcd;
 1349 
 1350     setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1351     setfps.parm.capture.timeperframe.numerator = 1;
 1352     setfps.parm.capture.timeperframe.denominator = cnt->conf.framerate;
 1353 
 1354     MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO
 1355         , _("Trying to set fps to %d")
 1356         , setfps.parm.capture.timeperframe.denominator);
 1357 
 1358     retcd = xioctl(vid_source, VIDIOC_S_PARM, &setfps);
 1359     if (retcd != 0) {
 1360         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
 1361             ,_("Error setting fps. Return code %d"), retcd);
 1362     }
 1363 
 1364     MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO
 1365         , _("Device set fps to %d")
 1366         , setfps.parm.capture.timeperframe.denominator);
 1367 
 1368     return 0;
 1369 }
 1370 
 1371 #endif /* HAVE_V4L2 */
 1372 
 1373 void v4l2_mutex_init(void) {
 1374 #ifdef HAVE_V4L2
 1375     pthread_mutex_init(&v4l2_mutex, NULL);
 1376 #else
 1377     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled"));
 1378 #endif // HAVE_V4L2
 1379 }
 1380 
 1381 void v4l2_mutex_destroy(void) {
 1382 #ifdef HAVE_V4L2
 1383     pthread_mutex_destroy(&v4l2_mutex);
 1384 #else
 1385     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled"));
 1386 #endif // HAVE_V4L2
 1387 }
 1388 
 1389 int v4l2_start(struct context *cnt) {
 1390 #ifdef HAVE_V4L2
 1391 
 1392     int retcd;
 1393     struct video_dev *curdev;
 1394 
 1395     pthread_mutex_lock(&v4l2_mutex);
 1396 
 1397     /* If device is already open and initialized use it*/
 1398     curdev = video_devices;
 1399     while (curdev) {
 1400         if (!strcmp(cnt->conf.video_device, curdev->video_device)) {
 1401             retcd = v4l2_vdev_init(cnt);
 1402             if (retcd == 0) retcd = vid_parms_parse(cnt);
 1403             if (retcd == 0) retcd = v4l2_imgs_set(cnt, curdev);
 1404             if (retcd == 0) {
 1405                 curdev->usage_count++;
 1406                 retcd = curdev->fd_device;
 1407             }
 1408             pthread_mutex_unlock(&v4l2_mutex);
 1409             return retcd;
 1410         }
 1411         curdev = curdev->next;
 1412     }
 1413 
 1414     curdev = mymalloc(sizeof(struct video_dev));
 1415 
 1416     curdev->starting = TRUE;
 1417 
 1418     retcd = v4l2_device_init(cnt, curdev);
 1419     if (retcd == 0) retcd = v4l2_vdev_init(cnt);
 1420     if (retcd == 0) retcd = v4l2_device_open(cnt, curdev);
 1421     if (retcd == 0) retcd = v4l2_device_capability(curdev);
 1422     if (retcd == 0) retcd = v4l2_input_select(cnt, curdev);
 1423     if (retcd == 0) retcd = v4l2_norm_select(cnt, curdev);
 1424     if (retcd == 0) retcd = v4l2_frequency_select(cnt, curdev);
 1425     if (retcd == 0) retcd = v4l2_pixfmt_select(cnt, curdev);
 1426     if (retcd == 0) retcd = v4l2_fps_set(cnt, curdev);
 1427     if (retcd == 0) retcd = v4l2_ctrls_count(curdev);
 1428     if (retcd == 0) retcd = v4l2_ctrls_list(curdev);
 1429     if (retcd == 0) retcd = vid_parms_parse(cnt);
 1430     if (retcd == 0) retcd = v4l2_parms_set(cnt, curdev);
 1431     if (retcd == 0) retcd = v4l2_ctrls_set(curdev);
 1432     if (retcd == 0) retcd = v4l2_mmap_set(curdev);
 1433     if (retcd == 0) retcd = v4l2_imgs_set(cnt, curdev);
 1434     if (retcd < 0){
 1435         /* These may need more work to consider all the fail scenarios*/
 1436         if (curdev->v4l2_private != NULL){
 1437             free(curdev->v4l2_private);
 1438             curdev->v4l2_private = NULL;
 1439         }
 1440         pthread_mutexattr_destroy(&curdev->attr);
 1441         pthread_mutex_destroy(&curdev->mutex);
 1442         v4l2_vdev_free(cnt);
 1443         if (curdev->fd_device != -1) close(curdev->fd_device);
 1444         free(curdev);
 1445         pthread_mutex_unlock(&v4l2_mutex);
 1446         return retcd;
 1447     }
 1448 
 1449     curdev->starting = FALSE;
 1450 
 1451     /* Insert into linked list. */
 1452     curdev->next = video_devices;
 1453     video_devices = curdev;
 1454 
 1455     pthread_mutex_unlock(&v4l2_mutex);
 1456 
 1457     return curdev->fd_device;
 1458 #else
 1459     if (!cnt) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled."));
 1460     return -1;
 1461 #endif // HAVE_V4l2
 1462 }
 1463 
 1464 void v4l2_cleanup(struct context *cnt) {
 1465 #ifdef HAVE_V4L2
 1466 
 1467     struct video_dev *dev = video_devices;
 1468     struct video_dev *prev = NULL;
 1469 
 1470     /* Cleanup the v4l2 part */
 1471     pthread_mutex_lock(&v4l2_mutex);
 1472     while (dev) {
 1473         if (dev->fd_device == cnt->video_dev)
 1474             break;
 1475         prev = dev;
 1476         dev = dev->next;
 1477     }
 1478     pthread_mutex_unlock(&v4l2_mutex);
 1479 
 1480     /* Set it as closed in thread context. */
 1481     cnt->video_dev = -1;
 1482 
 1483     v4l2_vdev_free(cnt);
 1484 
 1485     if (dev == NULL) {
 1486         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO, _("Unable to find video device"));
 1487         return;
 1488     }
 1489 
 1490     if (--dev->usage_count == 0) {
 1491         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
 1492             ,_("Closing video device %s"), dev->video_device);
 1493 
 1494         v4l2_device_close(dev);
 1495         v4l2_device_cleanup(dev);
 1496 
 1497         dev->fd_device = -1;
 1498 
 1499         /* Remove from list */
 1500         if (prev == NULL)
 1501             video_devices = dev->next;
 1502         else
 1503             prev->next = dev->next;
 1504 
 1505         pthread_mutexattr_destroy(&dev->attr);
 1506         pthread_mutex_destroy(&dev->mutex);
 1507         free(dev);
 1508 
 1509     } else {
 1510         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
 1511             ,_("Still %d users of video device %s, so we don't close it now")
 1512             ,dev->usage_count, dev->video_device);
 1513         /*
 1514          * There is still at least one thread using this device
 1515          * If we own it, release it.
 1516          */
 1517         if (dev->owner == cnt->threadnr) {
 1518             dev->frames = 0;
 1519             dev->owner = -1;
 1520             pthread_mutex_unlock(&dev->mutex);
 1521         }
 1522     }
 1523 
 1524 
 1525 #else
 1526     if (!cnt) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled."));
 1527 #endif // HAVE_V4L2
 1528 }
 1529 
 1530 int v4l2_next(struct context *cnt, struct image_data *img_data) {
 1531 #ifdef HAVE_V4L2
 1532     int ret = -2;
 1533     struct config *conf = &cnt->conf;
 1534     struct video_dev *dev;
 1535 
 1536     pthread_mutex_lock(&v4l2_mutex);
 1537     dev = video_devices;
 1538     while (dev) {
 1539         if (dev->fd_device == cnt->video_dev)
 1540             break;
 1541         dev = dev->next;
 1542     }
 1543     pthread_mutex_unlock(&v4l2_mutex);
 1544 
 1545     if (dev == NULL){
 1546         return -1;
 1547     }
 1548 
 1549     if (dev->owner != cnt->threadnr) {
 1550         pthread_mutex_lock(&dev->mutex);
 1551         dev->owner = cnt->threadnr;
 1552         dev->frames = conf->roundrobin_frames;
 1553     }
 1554 
 1555     v4l2_device_select(cnt, dev, img_data->image_norm);
 1556     ret = v4l2_capture(cnt, dev, img_data->image_norm);
 1557 
 1558     if (--dev->frames <= 0) {
 1559         dev->owner = -1;
 1560         dev->frames = 0;
 1561         pthread_mutex_unlock(&dev->mutex);
 1562     }
 1563 
 1564     /* Rotate the image as specified. */
 1565     rotate_map(cnt, img_data);
 1566 
 1567     return ret;
 1568 #else
 1569     if (!cnt || !img_data) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO, _("V4L2 is not enabled."));
 1570     return -1;
 1571 #endif // HAVE_V4L2
 1572 }
 1573 
 1574 int v4l2_palette_valid(char *video_device, int v4l2_palette) {
 1575 #ifdef HAVE_V4L2
 1576 
 1577     /* This function is a boolean that returns true(1) if the palette selected in the
 1578      * configuration file is valid for the device and false(0) if the palette is not valid
 1579      */
 1580 
 1581     palette_item *palette_array;
 1582     struct v4l2_fmtdesc fmtd;
 1583 
 1584     int device_palette;
 1585     int retcd;
 1586     src_v4l2_t *vid_source;
 1587 
 1588     palette_array = malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1));
 1589 
 1590     v4l2_palette_init(palette_array);
 1591 
 1592     vid_source = calloc(sizeof(src_v4l2_t), 1);
 1593     vid_source->fd_device = open(video_device, O_RDWR|O_CLOEXEC);
 1594     if (vid_source->fd_device < 0) {
 1595         MOTION_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO
 1596             ,_("Failed to open video device %s"),video_device);
 1597         free(vid_source);
 1598         free(palette_array);
 1599         return 0;
 1600     }
 1601 
 1602     memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
 1603     fmtd.index = device_palette = 0;
 1604     fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1605     retcd = 0;
 1606     while (xioctl(vid_source, VIDIOC_ENUM_FMT, &fmtd) != -1) {
 1607         if (palette_array[v4l2_palette].v4l2id == fmtd.pixelformat ) retcd = 1;
 1608 
 1609         memset(&fmtd, 0, sizeof(struct v4l2_fmtdesc));
 1610         fmtd.index = ++device_palette;
 1611         fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1612     }
 1613 
 1614     close(vid_source->fd_device);
 1615 
 1616     free(vid_source);
 1617 
 1618     free(palette_array);
 1619 
 1620     return retcd;
 1621 #else
 1622     /* We do not have v4l2 so we can not determine whether it is valid or not */
 1623     if ((video_device) || (v4l2_palette)) return 0;
 1624     return 0;
 1625 #endif // HAVE_V4L2
 1626 }
 1627 
 1628 void v4l2_palette_fourcc(int v4l2_palette, char *fourcc) {
 1629 #ifdef HAVE_V4L2
 1630 
 1631     /* This function populates the provided fourcc pointer with the fourcc code for the
 1632      * requested palette id code.  If the palette is not one of the ones that Motion supports
 1633      * it returns the string as "NULL"
 1634      */
 1635 
 1636     palette_item *palette_array;
 1637 
 1638     palette_array = malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1));
 1639 
 1640     v4l2_palette_init(palette_array);
 1641 
 1642     if ((v4l2_palette > V4L2_PALETTE_COUNT_MAX) || (v4l2_palette < 0)){
 1643         sprintf(fourcc,"%s","NULL");
 1644     } else {
 1645         sprintf(fourcc,"%s",palette_array[v4l2_palette].fourcc);
 1646     }
 1647 
 1648     free(palette_array);
 1649 
 1650     return;
 1651 #else
 1652     sprintf(fourcc,"%s","NULL");
 1653     if (v4l2_palette) return;
 1654     return;
 1655 #endif // HAVE_V4L2
 1656 }
 1657 
 1658 int v4l2_parms_valid(char *video_device, int v4l2_palette, int v4l2_fps, int v4l2_width, int v4l2_height){
 1659 #ifdef HAVE_V4L2
 1660 
 1661     /* This function is a boolean that returns true(1) if the parms selected in the
 1662      * configuration file are valid for the device and false(0) if not valid
 1663      */
 1664     palette_item *palette_array;
 1665     struct v4l2_fmtdesc         dev_format;
 1666     struct v4l2_frmsizeenum     dev_sizes;
 1667     struct v4l2_frmivalenum     dev_frameint;
 1668 
 1669     int retcd;
 1670     int indx_format, indx_sizes, indx_frameint;
 1671 
 1672     src_v4l2_t *vid_source;
 1673 
 1674     palette_array = malloc(sizeof(palette_item) * (V4L2_PALETTE_COUNT_MAX+1));
 1675 
 1676     v4l2_palette_init(palette_array);
 1677 
 1678     vid_source = calloc(sizeof(src_v4l2_t), 1);
 1679     vid_source->fd_device = open(video_device, O_RDWR|O_CLOEXEC);
 1680     if (vid_source->fd_device < 0) {
 1681         MOTION_LOG(ALR, TYPE_VIDEO, SHOW_ERRNO
 1682             ,_("Failed to open video device %s"),video_device);
 1683         free(vid_source);
 1684         free(palette_array);
 1685         return 0;
 1686     }
 1687 
 1688     retcd = 0;
 1689     memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc));
 1690     dev_format.index = indx_format = 0;
 1691     dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1692     while (xioctl(vid_source, VIDIOC_ENUM_FMT, &dev_format) != -1) {
 1693         MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
 1694             ,_("Testing palette %s (%c%c%c%c)")
 1695             ,dev_format.description
 1696             ,dev_format.pixelformat >> 0
 1697             ,dev_format.pixelformat >> 8
 1698             ,dev_format.pixelformat >> 16
 1699             ,dev_format.pixelformat >> 24);
 1700 
 1701         memset(&dev_sizes, 0, sizeof(struct v4l2_frmsizeenum));
 1702         dev_sizes.index = indx_sizes = 0;
 1703         dev_sizes.pixel_format = dev_format.pixelformat;
 1704         while (xioctl(vid_source, VIDIOC_ENUM_FRAMESIZES, &dev_sizes) != -1) {
 1705             MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
 1706                 ,_("  Width: %d, Height %d")
 1707                 ,dev_sizes.discrete.width
 1708                 ,dev_sizes.discrete.height);
 1709 
 1710             memset(&dev_frameint, 0, sizeof(struct v4l2_frmivalenum));
 1711             dev_frameint.index = indx_frameint = 0;
 1712             dev_frameint.pixel_format = dev_format.pixelformat;
 1713             dev_frameint.width = dev_sizes.discrete.width;
 1714             dev_frameint.height = dev_sizes.discrete.height;
 1715             while (xioctl(vid_source, VIDIOC_ENUM_FRAMEINTERVALS, &dev_frameint) != -1) {
 1716                 MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO
 1717                     ,_("    Framerate %d/%d")
 1718                     ,dev_frameint.discrete.numerator
 1719                     ,dev_frameint.discrete.denominator);
 1720                 if ((palette_array[v4l2_palette].v4l2id == dev_format.pixelformat) &&
 1721                     ((int)dev_sizes.discrete.width == v4l2_width) &&
 1722                     ((int)dev_sizes.discrete.height == v4l2_height) &&
 1723                     ((int)dev_frameint.discrete.numerator == 1) &&
 1724                     ((int)dev_frameint.discrete.denominator == v4l2_fps)) retcd = 1;
 1725                 memset(&dev_frameint, 0, sizeof(struct v4l2_frmivalenum));
 1726                 dev_frameint.index = ++indx_frameint;
 1727                 dev_frameint.pixel_format = dev_format.pixelformat;
 1728                 dev_frameint.width = dev_sizes.discrete.width;
 1729                 dev_frameint.height = dev_sizes.discrete.height;
 1730             }
 1731             memset(&dev_sizes, 0, sizeof(struct v4l2_frmsizeenum));
 1732             dev_sizes.index = ++indx_sizes;
 1733             dev_sizes.pixel_format = dev_format.pixelformat;
 1734         }
 1735         memset(&dev_format, 0, sizeof(struct v4l2_fmtdesc));
 1736         dev_format.index = ++indx_format;
 1737         dev_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 1738     }
 1739 
 1740     close(vid_source->fd_device);
 1741 
 1742     free(vid_source);
 1743 
 1744     free(palette_array);
 1745 
 1746     return retcd;
 1747 #else
 1748     /* We do not have v4l2 so we can not determine whether it is valid or not */
 1749     if ((video_device) || (v4l2_fps) || (v4l2_palette) ||
 1750         (v4l2_width)   || (v4l2_height) ) return 0;
 1751     return 0;
 1752 #endif // HAVE_V4L2
 1753 }
 1754