"Fossies" - the Fresh Open Source Software Archive

Member "motion-Release-4.3.0/src/video_bktr.c" (14 Jan 2020, 29956 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_bktr.c" see the Fossies "Dox" file reference documentation.

    1 /*    video_bktr.c
    2  *
    3  *    BSD Video stream functions for motion.
    4  *    Copyright 2004 by Angel Carpintero (motiondevelop@gmail.com)
    5  *    This software is distributed under the GNU public license version 2
    6  *    See also the file 'COPYING'.
    7  *
    8  */
    9 
   10 /* For rotation */
   11 #include "translate.h"
   12 #include "rotate.h"     /* Already includes motion.h */
   13 #include "video_common.h"
   14 #include "video_bktr.h"
   15 
   16 #ifdef HAVE_BKTR
   17 
   18 #include <sys/mman.h>
   19 
   20 #if defined(HAVE_DEV_IC_BT8XX_H)
   21     #include <dev/ic/bt8xx.h>
   22 #endif
   23 
   24 #if defined(HAVE_DEV_BKTR_IOCTL_METEOR_H)
   25     #include <dev/bktr/ioctl_meteor.h>
   26 #endif
   27 
   28 #if defined(HAVE_DEV_BKTR_IOCTL_BT848_H)
   29     #include <dev/bktr/ioctl_bt848.h>
   30 #endif
   31 
   32 #define array_elem(x) (sizeof(x) / sizeof((x)[0]))
   33 
   34 #define BKTR_PAL                   0
   35 #define BKTR_NTSC                  1
   36 #define BKTR_SECAM                 2
   37 #define BKTR_PAL_NC                3
   38 
   39 #define BKTR_PAL_HEIGHT          576
   40 #define BKTR_SECAM_HEIGHT        576
   41 #define BKTR_NTSC_HEIGHT         480
   42 
   43 #define BKTR_IN_COMPOSITE          0
   44 #define BKTR_IN_TV                 1
   45 #define BKTR_IN_COMPOSITE2         2
   46 #define BKTR_IN_SVIDEO             3
   47 
   48 #define BKTR_NORM_DEFAULT      BT848_IFORM_F_AUTO
   49 #define BKTR_NORM_PAL          BT848_IFORM_F_PALBDGHI
   50 #define BKTR_NORM_NTSC         BT848_IFORM_F_NTSCM
   51 #define BKTR_NORM_SECAM        BT848_IFORM_F_SECAM
   52 
   53 
   54 volatile sig_atomic_t bktr_frame_waiting;
   55 
   56 static pthread_mutex_t bktr_mutex;
   57 
   58 static struct video_dev *viddevs = NULL;
   59 
   60 static void catchsignal(int sig ATTRIBUTE_UNUSED)
   61 {
   62     bktr_frame_waiting++;
   63 }
   64 
   65 static int bktr_set_hue(int viddev, int new_hue) {
   66     signed char ioctlval = new_hue;
   67 
   68     if (ioctl(viddev, METEORSHUE, &ioctlval) < 0) {
   69         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
   70             ,_("METEORSHUE Error setting hue [%d]"),new_hue);
   71         return -1;
   72     }
   73 
   74     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
   75 
   76     return ioctlval;
   77 }
   78 
   79 static int bktr_get_hue(int viddev , int *hue) {
   80     signed char ioctlval;
   81 
   82     if (ioctl(viddev, METEORGHUE, &ioctlval) < 0) {
   83         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO,_("METEORGHUE Error getting hue"));
   84         return -1;
   85     }
   86 
   87     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
   88 
   89     *hue = ioctlval;
   90     return ioctlval;
   91 }
   92 
   93 static int bktr_set_saturation(int viddev, int new_saturation) {
   94     unsigned char ioctlval= new_saturation;
   95 
   96     if (ioctl(viddev, METEORSCSAT, &ioctlval) < 0) {
   97         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
   98             ,_("METEORSCSAT Error setting saturation [%d]"), new_saturation);
   99         return -1;
  100     }
  101 
  102     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  103 
  104     return ioctlval;
  105 }
  106 
  107 static int bktr_get_saturation(int viddev , int *saturation) {
  108     unsigned char ioctlval;
  109 
  110     if (ioctl(viddev, METEORGCSAT, &ioctlval) < 0) {
  111         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  112             ,_("METEORGCSAT Error getting saturation"));
  113         return -1;
  114     }
  115 
  116     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  117 
  118     *saturation = ioctlval;
  119     return ioctlval;
  120 }
  121 
  122 static int bktr_set_contrast(int viddev, int new_contrast) {
  123     unsigned char ioctlval = new_contrast;
  124 
  125     if (ioctl(viddev, METEORSCONT, &ioctlval) < 0) {
  126         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  127             ,_("METEORSCONT Error setting contrast [%d]"), new_contrast);
  128         return 0;
  129     }
  130 
  131     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  132 
  133     return ioctlval;
  134 }
  135 
  136 static int bktr_get_contrast(int viddev, int *contrast) {
  137     unsigned char ioctlval;
  138 
  139     if (ioctl(viddev, METEORGCONT, &ioctlval) < 0) {
  140         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  141             ,_("METEORGCONT Error getting contrast"));
  142         return -1;
  143     }
  144 
  145     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  146 
  147     *contrast = ioctlval;
  148     return ioctlval;
  149 }
  150 
  151 static int bktr_set_brightness(int viddev, int new_bright)
  152 {
  153     unsigned char ioctlval = new_bright;
  154 
  155     if (ioctl(viddev, METEORSBRIG, &ioctlval) < 0) {
  156         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  157             ,_("METEORSBRIG  brightness [%d]"), new_bright);
  158         return -1;
  159     }
  160 
  161     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  162 
  163     return ioctlval;
  164 }
  165 
  166 static int bktr_get_brightness(int viddev, int *brightness)
  167 {
  168     unsigned char ioctlval;
  169 
  170     if (ioctl(viddev, METEORGBRIG, &ioctlval) < 0) {
  171         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  172             ,_("METEORGBRIG  getting brightness"));
  173         return -1;
  174     }
  175 
  176     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d]"), ioctlval);
  177 
  178     *brightness = ioctlval;
  179     return ioctlval;
  180 }
  181 
  182 static int bktr_set_freq(struct video_dev *viddev, unsigned long freq)
  183 {
  184     int tuner_fd = viddev->bktr_fdtuner;
  185     int old_audio;
  186 
  187     MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Not implemented"));
  188     return 0;
  189 
  190     /* HACK maybe not need it , but seems that is needed to mute before changing frequency */
  191     if (ioctl(tuner_fd, BT848_GAUDIO, &old_audio) < 0) {
  192         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "BT848_GAUDIO");
  193         return -1;
  194     }
  195 
  196     if (ioctl(tuner_fd, TVTUNER_SETFREQ, &freq) < 0) {
  197         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "Tuning (TVTUNER_SETFREQ) failed, ",
  198                    "freq [%lu]", freq);
  199         return -1;
  200     }
  201 
  202     old_audio &= AUDIO_MUTE;
  203     if (old_audio) {
  204         old_audio = AUDIO_MUTE;
  205         if (ioctl(tuner_fd , BT848_SAUDIO, &old_audio) < 0) {
  206             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "BT848_SAUDIO %i",
  207                        old_audio);
  208             return -1;
  209         }
  210     }
  211 
  212     return 0;
  213 }
  214 
  215 static int bktr_set_input_device(struct video_dev *viddev, unsigned input)
  216 {
  217     int actport;
  218     int portdata[] = { METEOR_INPUT_DEV0, METEOR_INPUT_DEV1,
  219                        METEOR_INPUT_DEV2, METEOR_INPUT_DEV3,
  220                        METEOR_INPUT_DEV_SVIDEO  };
  221 
  222     if (input >= array_elem(portdata)) {
  223         MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("Device Input %d out of range (0-4)"), input);
  224         return -1;
  225     }
  226 
  227     actport = portdata[ input ];
  228     if (ioctl(viddev->fd_device, METEORSINPUT, &actport) < 0) {
  229         if (input != BKTR_IN_COMPOSITE) {
  230             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  231                 ,_("METEORSINPUT %d invalid -Trying composite %d")
  232                 , input, BKTR_IN_COMPOSITE);
  233             input = BKTR_IN_COMPOSITE;
  234             actport = portdata[ input ];
  235             if (ioctl(viddev->fd_device, METEORSINPUT, &actport) < 0) {
  236                 MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "METEORSINPUT %d init", input);
  237                 return -1;
  238             }
  239         } else {
  240             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "METEORSINPUT %d init",
  241                        input);
  242             return -1;
  243         }
  244     }
  245 
  246     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "to [%d]", input);
  247 
  248     return input;
  249 }
  250 
  251 static int bktr_set_input_format(struct video_dev *viddev, unsigned newformat)
  252 {
  253     int input_format[] = { BKTR_NORM_PAL, BKTR_NORM_NTSC, BKTR_NORM_SECAM, BKTR_NORM_DEFAULT};
  254     int format;
  255 
  256     if (newformat >= array_elem(input_format)) {
  257         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO, "Input format %d out of range (0-2)",
  258                    newformat);
  259         return -1;
  260     }
  261 
  262     format = input_format[newformat];
  263 
  264     if (ioctl(viddev->fd_device, BT848SFMT, &format) < 0) {
  265         MOTION_LOG(WRN, TYPE_VIDEO, SHOW_ERRNO
  266             ,_("BT848SFMT, Couldn't set the input format, try again with default"));
  267         format = BKTR_NORM_DEFAULT;
  268         newformat = 3;
  269 
  270         if (ioctl(viddev->fd_device, BT848SFMT, &format) < 0) {
  271             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  272                 ,_("BT848SFMT, Couldn't set the input format either default"));
  273             return -1;
  274         }
  275     }
  276 
  277     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "to %d", newformat);
  278 
  279     return newformat;
  280 }
  281 
  282 static int bktr_set_geometry(struct video_dev *viddev, int width, int height)
  283 {
  284     struct meteor_geomet geom;
  285     int h_max;
  286 
  287     geom.columns = width;
  288     geom.rows = height;
  289     geom.oformat = METEOR_GEO_YUV_422 | METEOR_GEO_YUV_12;
  290 
  291     /* FIXME:  These seem to be problematic on whether they work the same on bktr...*/
  292     /* FIXME:  Best result in testing was only a BW picture with no color.*/
  293     /*
  294     The following are supported pixel format types:
  295     METEOR_GEO_RGB16        16-bit RGB
  296     METEOR_GEO_RGB24        24-bit RGB in 32 bits
  297     METEOR_GEO_YUV_PACKED   16-bit 4:2:2 YUV
  298     METEOR_GEO_YUV_PLANAR   16-bit 4:2:2 YUV
  299     METEOR_GEO_YUV_UNSIGNED unsigned UV
  300     METEOR_GEO_YUV_422
  301     METEOR_GEO_YUV_12
  302     METEOR_GEO_YUV_9
  303     */
  304     viddev->pixfmt_src = geom.oformat;
  305 
  306     switch (viddev->norm) {
  307     case BKTR_PAL:
  308         h_max = BKTR_PAL_HEIGHT;
  309         break;
  310     case BKTR_NTSC:
  311         h_max = BKTR_NTSC_HEIGHT;
  312         break;
  313     case BKTR_SECAM:
  314         h_max = BKTR_SECAM_HEIGHT;
  315         break;
  316     default:
  317         h_max = BKTR_PAL_HEIGHT;
  318     }
  319 
  320     if (height <= h_max / 2)
  321         geom.oformat |= METEOR_GEO_EVEN_ONLY;
  322 
  323     geom.frames = 1;
  324 
  325     if (ioctl(viddev->fd_device, METEORSETGEO, &geom) < 0) {
  326         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO,_("Couldn't set the geometry"));
  327         return -1;
  328     }
  329 
  330     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("to [%d/%d] Norm %d")
  331         ,width, height, viddev->norm);
  332 
  333     return 0;
  334 }
  335 
  336 static void bktr_picture_controls(struct context *cnt, struct video_dev *viddev) {
  337 
  338     int dev = viddev->fd_device;
  339     int indx_user, retcd;
  340     struct vdev_usrctrl_ctx *usritem;
  341 
  342     if (!cnt->vdev->update_parms) return;
  343 
  344     retcd = vid_parms_parse(cnt);
  345     if (retcd < 0) return;
  346 
  347     for (indx_user=0; indx_user<cnt->vdev->usrctrl_count; indx_user++){
  348         usritem=&cnt->vdev->usrctrl_array[indx_user];
  349         if (!strcasecmp(usritem->ctrl_name,"contrast")) bktr_set_contrast(dev,usritem->ctrl_value);
  350         if (!strcasecmp(usritem->ctrl_name,"hue")) bktr_set_hue(dev,usritem->ctrl_value);
  351         if (!strcasecmp(usritem->ctrl_name,"brightness")) bktr_set_brightness(dev,usritem->ctrl_value);
  352         if (!strcasecmp(usritem->ctrl_name,"saturation")) bktr_set_saturation(dev,usritem->ctrl_value);
  353     }
  354 
  355     cnt->vdev->update_parms = FALSE;
  356 
  357 }
  358 
  359 static unsigned char *bktr_device_init(struct video_dev *viddev, int width, int height,
  360                                 unsigned input, unsigned norm, unsigned long freq)
  361 {
  362     int dev_bktr = viddev->fd_device;
  363     struct sigaction act, old;
  364     //int dev_tunner = viddev->bktr_fdtuner;
  365     /* to ensure that all device will be support the capture mode
  366       _TODO_ : Autodected the best capture mode .
  367     */
  368     int dummy = 1;
  369     //    int pixelformat = BSD_VIDFMT_I420;
  370 
  371     void *map;
  372 
  373     /* If we have choose the tuner is needed to setup the frequency. */
  374     if ((viddev->bktr_tuner != NULL) && (input == BKTR_IN_TV)) {
  375         if (!freq) {
  376             MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  377                 ,_("Not valid Frequency [%lu] for Source input [%i]"), freq, input);
  378             return NULL;
  379         } else if (bktr_set_freq(viddev, freq) == -1) {
  380             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  381                 ,_("Frequency [%lu] Source input [%i]"), freq, input);
  382             return NULL;
  383         }
  384     }
  385 
  386     /* FIXME if we set as input tuner , we need to set option for tuner not for bktr */
  387     if ((dummy = bktr_set_input_device(viddev, input)) == -1) {
  388         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("set input [%d]"), input);
  389         return NULL;
  390     }
  391 
  392     viddev->input = dummy;
  393 
  394     if ((dummy = bktr_set_input_format(viddev, norm)) == -1) {
  395         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  396             ,_("set input format [%d]"), norm);
  397         return NULL;
  398     }
  399 
  400     viddev->norm = dummy;
  401 
  402     if (bktr_set_geometry(viddev, width, height) == -1) {
  403         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  404             ,_("set geometry [%d]x[%d]"), width, height);
  405         return NULL;
  406     }
  407 
  408     if (freq) {
  409         MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO
  410             ,_("Frequency set (no implemented yet"));
  411     }
  412 
  413     /*
  414      * Set capture mode and capture buffers
  415      * That is the buffer size for capture images ,
  416      * so is dependent of color space of input format / FIXME
  417      */
  418      /* FIXME:  These seem to be problematic on whether they work the same on bktr...*/
  419      /* FIXME:  Spec says some of these should be 3/2 but testing indicates it is too small.*/
  420     switch (viddev->pixfmt_src) {
  421     case METEOR_GEO_RGB16:
  422         /*FALLTHROUGH*/
  423     case METEOR_GEO_RGB24:
  424         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Sizing buffer to 3x"));
  425         viddev->bktr_bufsize = ((width * height * 3) * sizeof(unsigned char));
  426     case METEOR_GEO_YUV_PACKED:
  427         /*FALLTHROUGH*/
  428     case METEOR_GEO_YUV_PLANAR:
  429         /*FALLTHROUGH*/
  430     case METEOR_GEO_YUV_422:
  431         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Sizing buffer to 3/2x"));
  432         viddev->bktr_bufsize = (((width * height * 3 / 2)) * sizeof(unsigned char));
  433         break;
  434     case METEOR_GEO_YUV_9:
  435         /*FALLTHROUGH*/
  436     case METEOR_GEO_YUV_12:
  437         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Sizing buffer to 3x"));
  438         viddev->bktr_bufsize = ((width * height * 3) * sizeof(unsigned char));
  439         break;
  440     default:
  441         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Sizing buffer to 3/2x"));
  442         viddev->bktr_bufsize = (((width * height * 3 / 2)) * sizeof(unsigned char));
  443     }
  444 
  445     map = mmap((caddr_t)0, viddev->bktr_bufsize, PROT_READ|PROT_WRITE, MAP_SHARED,
  446                dev_bktr, (off_t)0);
  447 
  448     if (map == MAP_FAILED) {
  449         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO,_("mmap failed"));
  450         return NULL;
  451     }
  452 
  453     /* FIXME double buffer */
  454     if (0) {
  455         viddev->bktr_maxbuffer = 2;
  456         viddev->bktr_buffers[0] = map;
  457         viddev->bktr_buffers[1] = (unsigned char *)map + 0; /* 0 is not valid just a test */
  458         //viddev->bktr_buffers[1] = map+vid_buf.offsets[1];
  459     } else {
  460         viddev->bktr_buffers[0] = map;
  461         viddev->bktr_maxbuffer = 1;
  462     }
  463 
  464     viddev->bktr_curbuffer = 0;
  465 
  466     /* Clear the buffer */
  467     if (ioctl(dev_bktr, BT848SCBUF, &dummy) < 0) {
  468         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO, "BT848SCBUF");
  469         return NULL;
  470     }
  471 
  472     /* Signal handler to know when data is ready to be read() */
  473     memset(&act, 0, sizeof(act));
  474     sigemptyset(&act.sa_mask);
  475     act.sa_handler = catchsignal;
  476     sigaction(SIGUSR2, &act, &old);
  477 
  478     dummy = SIGUSR2;
  479 
  480     //viddev->bktr_method = METEOR_CAP_CONTINOUS;
  481     //viddev->bktr_method = METEOR_CAP_SINGLE;
  482 
  483     if ((viddev->bktr_method == METEOR_CAP_CONTINOUS) &&
  484         (ioctl(dev_bktr, METEORSSIGNAL, &dummy) < 0)) {
  485         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "METEORSSIGNAL");
  486 
  487         viddev->bktr_method = METEOR_CAP_SINGLE;
  488 
  489         if (ioctl(dev_bktr, METEORCAPTUR, &viddev->bktr_method) < 0) {
  490             MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  491                 ,_("METEORCAPTUR using single method Error capturing"));
  492             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  493                 ,_("METEORCAPTUR using single method Error capturing"));
  494         }
  495     } else {
  496         if (ioctl(dev_bktr, METEORCAPTUR, &viddev->bktr_method) < 0) {
  497             viddev->bktr_method = METEOR_CAP_SINGLE;
  498 
  499             if (ioctl(dev_bktr, METEORCAPTUR, &viddev->bktr_method) < 0) {
  500                 MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  501                     ,_("METEORCAPTUR using single method Error capturing"));
  502             }
  503         }
  504     }
  505 
  506     if (viddev->bktr_method == METEOR_CAP_CONTINOUS)
  507         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "METEORCAPTUR METEOR_CAP_CONTINOUS");
  508     else
  509         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "METEORCAPTUR METEOR_CAP_SINGLE");
  510 
  511     SLEEP(1, 0);
  512 
  513     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "HUE [%d]",
  514                bktr_get_hue(dev_bktr, &dummy));
  515     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "SATURATION [%d]",
  516                bktr_get_saturation(dev_bktr, &dummy));
  517     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "BRIGHTNESS [%d]",
  518                bktr_get_brightness(dev_bktr, &dummy));
  519     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "CONTRAST [%d]",
  520                bktr_get_contrast(dev_bktr, &dummy));
  521 
  522     return map;
  523 }
  524 
  525 /**
  526  * bktr_capture fetches a video frame from a v4l device
  527  * Parameters:
  528  *     viddev     Pointer to struct containing video device handle
  529  *     map        Pointer to the buffer in which the function puts the new image
  530  *     width      Width of image in pixels
  531  *     height     Height of image in pixels
  532  *
  533  * Returns
  534  *     0          Success
  535  *    -1          Fatal error
  536  *     1          Non fatal error (not implemented)
  537  */
  538 static int bktr_capture(struct video_dev *viddev, unsigned char *map, int width, int height) {
  539     int dev_bktr = viddev->fd_device;
  540     unsigned char *cap_map = NULL;
  541     unsigned char *common_buffer;
  542     int single = METEOR_CAP_SINGLE;
  543     sigset_t set, old;
  544 
  545 
  546     /* ONLY MMAP method is used to Capture */
  547 
  548     /*
  549      * Allocates a new mmap buffer
  550      * Block signals during IOCTL
  551      */
  552     sigemptyset (&set);
  553     sigaddset (&set, SIGCHLD);
  554     sigaddset (&set, SIGALRM);
  555     sigaddset (&set, SIGUSR1);
  556     sigaddset (&set, SIGTERM);
  557     sigaddset (&set, SIGHUP);
  558     pthread_sigmask(SIG_BLOCK, &set, &old);
  559     cap_map = viddev->bktr_buffers[viddev->bktr_curbuffer];
  560 
  561     viddev->bktr_curbuffer++;
  562     if (viddev->bktr_curbuffer >= viddev->bktr_maxbuffer)
  563         viddev->bktr_curbuffer = 0;
  564 
  565     /* Capture */
  566 
  567     if (viddev->bktr_method == METEOR_CAP_CONTINOUS) {
  568         if (bktr_frame_waiting)
  569             bktr_frame_waiting = 0;
  570 
  571     } else if (ioctl(dev_bktr, METEORCAPTUR, &single) < 0) {
  572         MOTION_LOG(ERR, TYPE_VIDEO, SHOW_ERRNO
  573             ,_("Error capturing using single method"));
  574         sigprocmask(SIG_UNBLOCK, &old, NULL);
  575         return -1;
  576     }
  577 
  578     /* Undo the signal blocking */
  579     pthread_sigmask(SIG_UNBLOCK, &old, NULL);
  580     /*
  581     METEOR_GEO_RGB16        16-bit RGB
  582     METEOR_GEO_RGB24        24-bit RGB in 32 bits
  583     METEOR_GEO_YUV_PACKED   16-bit 4:2:2 YUV
  584     METEOR_GEO_YUV_PLANAR   16-bit 4:2:2 YUV
  585     METEOR_GEO_YUV_422
  586     METEOR_GEO_YUV_12
  587     METEOR_GEO_YUV_9
  588     */
  589     /* FIXME:  These seem to be problematic on whether they work the same on bktr...*/
  590     switch (viddev->pixfmt_src) {
  591     case METEOR_GEO_RGB16:
  592         /*FALLTHROUGH*/
  593     case METEOR_GEO_RGB24:
  594         vid_rgb24toyuv420p(map, cap_map, width, height);
  595         break;
  596     case METEOR_GEO_YUV_PACKED:
  597         /*FALLTHROUGH*/
  598     case METEOR_GEO_YUV_422:
  599         vid_yuv422to420p(map, cap_map, width, height);
  600         break;
  601     case METEOR_GEO_YUV_PLANAR:
  602         vid_yuv422pto420p(map, cap_map, width, height);
  603         break;
  604     case METEOR_GEO_YUV_9:
  605         /*FALLTHROUGH*/
  606     case METEOR_GEO_YUV_12:
  607         common_buffer = mymalloc(width * height * 3);
  608         vid_y10torgb24(common_buffer, cap_map, width, height, 2);
  609         vid_rgb24toyuv420p(map, common_buffer, width, height);
  610         free(common_buffer);
  611         break;
  612     default:
  613         memcpy(map, cap_map, ((width*height*3)/2));
  614     }
  615 
  616     return 0;
  617 }
  618 
  619 static void bktr_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width,
  620                           int height, int input, int norm, int skip, unsigned long freq)
  621 {
  622     if (input != viddev->input || norm != viddev->norm || freq != viddev->frequency) {
  623         int dummy;
  624         unsigned long frequnits = freq;
  625 
  626 
  627         if ((dummy = bktr_set_input_device(viddev, input)) == -1)
  628             return;
  629 
  630         viddev->input = dummy;
  631 
  632         if ((dummy = bktr_set_input_format(viddev, norm)) == -1)
  633             return;
  634 
  635         viddev->norm = dummy;
  636 
  637         if ((viddev->bktr_tuner != NULL) && (viddev->input == BKTR_IN_TV) &&
  638             (frequnits > 0)) {
  639             if (bktr_set_freq(viddev, freq) == -1)
  640                 return;
  641         }
  642 
  643         bktr_picture_controls(cnt, viddev);
  644 
  645         viddev->frequency = freq;
  646 
  647         /* skip a few frames if needed */
  648         for (dummy = 0; dummy < skip; dummy++)
  649             bktr_capture(viddev, map, width, height);
  650     } else {
  651         /* No round robin - we only adjust picture controls */
  652         bktr_picture_controls(cnt, viddev);
  653     }
  654 }
  655 
  656 #endif /* HAVE_BKTR */
  657 
  658 
  659 void bktr_mutex_init(void) {
  660 #ifdef HAVE_BKTR
  661     pthread_mutex_init(&bktr_mutex, NULL);
  662 #else
  663     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO,_("BKTR is not enabled."));
  664 #endif
  665 }
  666 
  667 void bktr_mutex_destroy(void) {
  668 #ifdef HAVE_BKTR
  669     pthread_mutex_destroy(&bktr_mutex);
  670 #else
  671     MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO,_("BKTR is not enabled."));
  672 #endif
  673 }
  674 
  675 void bktr_cleanup(struct context *cnt){
  676 #ifdef HAVE_BKTR
  677 
  678     struct video_dev *dev = viddevs;
  679     struct video_dev *prev = NULL;
  680     int indx;
  681 
  682     /* Cleanup the v4l part */
  683     pthread_mutex_lock(&bktr_mutex);
  684 
  685     while (dev) {
  686         if (dev->fd_device == cnt->video_dev)
  687             break;
  688         prev = dev;
  689         dev = dev->next;
  690     }
  691 
  692     pthread_mutex_unlock(&bktr_mutex);
  693 
  694     /* Set it as closed in thread context. */
  695     cnt->video_dev = -1;
  696 
  697     /* free the information we collected regarding the controls */
  698     if (cnt->vdev != NULL){
  699         if (cnt->vdev->usrctrl_count > 0){
  700             for (indx=0;indx<cnt->vdev->usrctrl_count;indx++){
  701                 free(cnt->vdev->usrctrl_array[indx].ctrl_name);
  702                 cnt->vdev->usrctrl_array[indx].ctrl_name=NULL;
  703             }
  704         }
  705         cnt->vdev->usrctrl_count = 0;
  706         if (cnt->vdev->usrctrl_array != NULL){
  707             free(cnt->vdev->usrctrl_array);
  708             cnt->vdev->usrctrl_array = NULL;
  709         }
  710 
  711         free(cnt->vdev);
  712     }
  713 
  714     if (dev == NULL) {
  715         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO,_("Unable to find video device"));
  716         return;
  717     }
  718 
  719     if (--dev->usage_count == 0) {
  720         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  721             ,_("Closing video device %s"), dev->video_device);
  722 
  723         if (dev->bktr_fdtuner > 0)
  724             close(dev->bktr_fdtuner);
  725 
  726         if (dev->fd_device > 0) {
  727             if (dev->bktr_method == METEOR_CAP_CONTINOUS) {
  728                 dev->bktr_fdtuner = METEOR_CAP_STOP_CONT;
  729                 ioctl(dev->fd_device, METEORCAPTUR, &dev->bktr_fdtuner);
  730             }
  731             close(dev->fd_device);
  732             dev->bktr_fdtuner = -1;
  733         }
  734 
  735 
  736         munmap(viddevs->bktr_buffers[0], viddevs->bktr_bufsize);
  737         viddevs->bktr_buffers[0] = MAP_FAILED;
  738 
  739         dev->fd_device = -1;
  740         pthread_mutex_lock(&bktr_mutex);
  741 
  742         /* Remove from list */
  743         if (prev == NULL)
  744             viddevs = dev->next;
  745         else
  746             prev->next = dev->next;
  747 
  748         pthread_mutex_unlock(&bktr_mutex);
  749 
  750         pthread_mutexattr_destroy(&dev->attr);
  751         pthread_mutex_destroy(&dev->mutex);
  752         free(dev);
  753     } else {
  754         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  755             ,_("Still %d users of video device %s, so we don't close it now")
  756             , dev->usage_count, dev->video_device);
  757         /*
  758          * There is still at least one thread using this device
  759          * If we own it, release it.
  760          */
  761         if (dev->owner == cnt->threadnr) {
  762                 dev->frames = 0;
  763                 dev->owner = -1;
  764                 pthread_mutex_unlock(&dev->mutex);
  765         }
  766     }
  767 
  768 #else
  769     if (!cnt) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO,_("BKTR is not enabled."));
  770 #endif
  771 
  772 }
  773 
  774 int bktr_start(struct context *cnt) {
  775 #ifdef HAVE_BKTR
  776 
  777     struct config *conf = &cnt->conf;
  778     struct video_dev *dev;
  779     int bktr_fdtuner = -1;
  780     int width, height, bktr_method;
  781     unsigned input, norm;
  782     unsigned long frequency;
  783     int fd_device = -1;
  784 
  785     MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO, "[%s]", conf->video_device);
  786 
  787     /*
  788      * We use width and height from conf in this function. They will be assigned
  789      * to width and height in imgs here, and capture_width_norm and capture_height_norm in
  790      * rotate_data won't be set until in rotate_init.
  791      * Motion requires that width and height are multiples of 8 so we check for this.
  792      */
  793     if (conf->width % 8) {
  794         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO
  795             ,_("config image width (%d) is not modulo 8"), conf->width);
  796         return -2;
  797     }
  798 
  799     if (conf->height % 8) {
  800         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO
  801             ,_("config image height (%d) is not modulo 8"), conf->height);
  802         return -2;
  803     }
  804 
  805     width = conf->width;
  806     height = conf->height;
  807     input = conf->input;
  808     norm = conf->norm;
  809     frequency = conf->frequency;
  810     bktr_method = METEOR_CAP_CONTINOUS;
  811 
  812     pthread_mutex_lock(&bktr_mutex);
  813 
  814     /*
  815      * Transfer width and height from conf to imgs. The imgs values are the ones
  816      * that is used internally in Motion. That way, setting width and height via
  817      * http remote control won't screw things up.
  818      */
  819     cnt->imgs.width = width;
  820     cnt->imgs.height = height;
  821 
  822     cnt->vdev = mymalloc(sizeof(struct vdev_context));
  823     memset(cnt->vdev, 0, sizeof(struct vdev_context));
  824     cnt->vdev->usrctrl_array = NULL;
  825     cnt->vdev->usrctrl_count = 0;
  826     cnt->vdev->update_parms = TRUE;     /*Set trigger that we have updated user parameters */
  827 
  828     /*
  829      * First we walk through the already discovered video devices to see
  830      * if we have already setup the same device before. If this is the case
  831      * the device is a Round Robin device and we set the basic settings
  832      * and return the file descriptor.
  833      */
  834     dev = viddevs;
  835     while (dev) {
  836         if (!strcmp(conf->video_device, dev->video_device)) {
  837             int dummy = METEOR_CAP_STOP_CONT;
  838             dev->usage_count++;
  839 
  840             if (ioctl(dev->fd_device, METEORCAPTUR, &dummy) < 0) {
  841                 MOTION_LOG(CRT, TYPE_VIDEO, SHOW_ERRNO,_("Stopping capture"));
  842                 return -1;
  843             }
  844 
  845             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  846                 ,_("Reusing [%s] inputs [%d,%d] Change capture"
  847                 " method METEOR_CAP_SINGLE")
  848                 , dev->video_device, dev->input, conf->input);
  849 
  850             dev->bktr_method = METEOR_CAP_SINGLE;
  851 
  852 
  853             MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO
  854                 ,_("VIDEO_PALETTE_YUV420P setting"
  855                 " imgs.size_norm and imgs.motionsize"));
  856             cnt->imgs.motionsize = width * height;
  857             cnt->imgs.size_norm = (width * height * 3) / 2;
  858 
  859             pthread_mutex_unlock(&bktr_mutex);
  860             return dev->fd_device; // FIXME return bktr_fdtuner ?!
  861         }
  862         dev = dev->next;
  863     }
  864 
  865 
  866     dev = mymalloc(sizeof(struct video_dev));
  867 
  868     fd_device = open(conf->video_device, O_RDWR|O_CLOEXEC);
  869 
  870     if (fd_device < 0) {
  871         MOTION_LOG(CRT, TYPE_VIDEO, SHOW_ERRNO,_("open video device %s"),
  872                    conf->video_device);
  873         free(dev);
  874         pthread_mutex_unlock(&bktr_mutex);
  875         return -1;
  876     }
  877 
  878     /* Only open tuner if conf->tuner_device has set , freq and input is 1. */
  879     if ((conf->tuner_device != NULL) && (frequency > 0) && (input == BKTR_IN_TV)) {
  880         bktr_fdtuner = open(conf->tuner_device, O_RDWR|O_CLOEXEC);
  881         if (bktr_fdtuner < 0) {
  882             MOTION_LOG(CRT, TYPE_VIDEO, SHOW_ERRNO,_("open tuner device %s"),
  883                        conf->tuner_device);
  884             free(dev);
  885             pthread_mutex_unlock(&bktr_mutex);
  886             return -1;
  887         }
  888     }
  889 
  890     pthread_mutexattr_init(&dev->attr);
  891     pthread_mutex_init(&dev->mutex, &dev->attr);
  892 
  893     dev->usage_count = 1;
  894     dev->video_device = conf->video_device;
  895     dev->bktr_tuner = conf->tuner_device;
  896     dev->fd_device = fd_device;
  897     dev->bktr_fdtuner = bktr_fdtuner;
  898     dev->input = input;
  899     dev->height = height;
  900     dev->width = width;
  901     dev->frequency = frequency;
  902     dev->owner = -1;
  903     dev->bktr_method = bktr_method;
  904 
  905     /*
  906      * We set brightness, contrast, saturation and hue = 0 so that they only get
  907      * set if the config is not zero.
  908      */
  909 
  910     dev->owner = -1;
  911 
  912     /* Default palette */
  913     dev->pixfmt_src = METEOR_GEO_YUV_422;
  914     dev->bktr_curbuffer = 0;
  915     dev->bktr_maxbuffer = 1;
  916 
  917     if (!bktr_device_init(dev, width, height, input, norm, frequency)) {
  918         close(dev->fd_device);
  919         pthread_mutexattr_destroy(&dev->attr);
  920         pthread_mutex_destroy(&dev->mutex);
  921         free(dev);
  922 
  923         pthread_mutex_unlock(&bktr_mutex);
  924         return -1;
  925     }
  926 
  927     cnt->imgs.size_norm = (width * height * 3) / 2;
  928     cnt->imgs.motionsize = width * height;
  929 
  930     /* Insert into linked list */
  931     dev->next = viddevs;
  932     viddevs = dev;
  933 
  934     pthread_mutex_unlock(&bktr_mutex);
  935 
  936     return fd_device;
  937 #else
  938     if (!cnt) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO,_("BKTR is not enabled."));
  939     return -1;
  940 #endif
  941 
  942 }
  943 
  944 int bktr_next(struct context *cnt,  struct image_data *img_data) {
  945 #ifdef HAVE_BKTR
  946 
  947     struct config *conf = &cnt->conf;
  948     struct video_dev *dev;
  949     int width, height;
  950     int dev_bktr = cnt->video_dev;
  951     int ret = -1;
  952 
  953     /* NOTE: Since this is a capture, we need to use capture dimensions. */
  954     width = cnt->rotate_data.capture_width_norm;
  955     height = cnt->rotate_data.capture_height_norm;
  956 
  957     pthread_mutex_lock(&bktr_mutex);
  958     dev = viddevs;
  959 
  960     while (dev) {
  961         if (dev->fd_device == dev_bktr)
  962             break;
  963         dev = dev->next;
  964     }
  965 
  966     pthread_mutex_unlock(&bktr_mutex);
  967 
  968     if (dev == NULL) return -1;
  969 
  970     if (dev->owner != cnt->threadnr) {
  971         pthread_mutex_lock(&dev->mutex);
  972         dev->owner = cnt->threadnr;
  973         dev->frames = conf->roundrobin_frames;
  974     }
  975 
  976     bktr_set_input(cnt, dev, img_data->image_norm, width, height, conf->input, conf->norm,
  977                   conf->roundrobin_skip, conf->frequency);
  978 
  979     ret = bktr_capture(dev, img_data->image_norm, width, height);
  980 
  981     if (--dev->frames <= 0) {
  982         dev->owner = -1;
  983         dev->frames = 0;
  984         pthread_mutex_unlock(&dev->mutex);
  985     }
  986 
  987     /* Rotate the image as specified */
  988     rotate_map(cnt, img_data);
  989 
  990     return ret;
  991 #else
  992     if (!cnt || !img_data) MOTION_LOG(DBG, TYPE_VIDEO, NO_ERRNO,_("BKTR is not enabled."));
  993     return -1;
  994 #endif
  995 
  996 }
  997 
  998