"Fossies" - the Fresh Open Source Software Archive

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

    1 /*      video_common.c
    2  *
    3  *      Video stream functions for motion.
    4  *      Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org)
    5  *                2006 by Krzysztof Blaszkowski (kb@sysmikro.com.pl)
    6  *                2007 by Angel Carpintero (motiondevelop@gmail.com)
    7  *      This software is distributed under the GNU public license version 2
    8  *      See also the file 'COPYING'.
    9  *
   10  */
   11 #include "translate.h"
   12 #include "motion.h"
   13 #include "video_common.h"
   14 #include "video_v4l2.h"
   15 #include "video_bktr.h"
   16 #include "jpegutils.h"
   17 
   18 typedef unsigned char uint8_t;
   19 typedef unsigned short int uint16_t;
   20 typedef unsigned int uint32_t;
   21 
   22 #define CLAMP(x)  ((x) < 0 ? 0 : ((x) > 255) ? 255 : (x))
   23 
   24 typedef struct {
   25     int is_abs;
   26     int len;
   27     int val;
   28 } code_table_t;
   29 
   30 /**
   31  * sonix_decompress_init
   32  *   pre-calculates a locally stored table for efficient huffman-decoding.
   33  *
   34  *   Each entry at index x in the table represents the codeword
   35  *   present at the MSB of byte x.
   36  *
   37  */
   38 static void vid_sonix_decompress_init(code_table_t * table)
   39 {
   40 
   41     int i;
   42     int is_abs, val, len;
   43 
   44     for (i = 0; i < 256; i++) {
   45         is_abs = 0;
   46         val = 0;
   47         len = 0;
   48         if ((i & 0x80) == 0) {
   49             /* code 0 */
   50             val = 0;
   51             len = 1;
   52         } else if ((i & 0xE0) == 0x80) {
   53             /* code 100 */
   54             val = +4;
   55             len = 3;
   56         } else if ((i & 0xE0) == 0xA0) {
   57             /* code 101 */
   58             val = -4;
   59             len = 3;
   60         } else if ((i & 0xF0) == 0xD0) {
   61             /* code 1101 */
   62             val = +11;
   63             len = 4;
   64         } else if ((i & 0xF0) == 0xF0) {
   65             /* code 1111 */
   66             val = -11;
   67             len = 4;
   68         } else if ((i & 0xF8) == 0xC8) {
   69             /* code 11001 */
   70             val = +20;
   71             len = 5;
   72         } else if ((i & 0xFC) == 0xC0) {
   73             /* code 110000 */
   74             val = -20;
   75             len = 6;
   76         } else if ((i & 0xFC) == 0xC4) {
   77             /* code 110001xx: unknown */
   78             val = 0;
   79             len = 8;
   80         } else if ((i & 0xF0) == 0xE0) {
   81             /* code 1110xxxx */
   82             is_abs = 1;
   83             val = (i & 0x0F) << 4;
   84             len = 8;
   85         }
   86         table[i].is_abs = is_abs;
   87         table[i].val = val;
   88         table[i].len = len;
   89     }
   90 }
   91 
   92 /**
   93  * sonix_decompress
   94  *      Decompresses an image encoded by a SN9C101 camera controller chip.
   95  *
   96  *   IN    width
   97  *         height
   98  *         inp     pointer to compressed frame (with header already stripped)
   99  *   OUT   outp    pointer to decompressed frame
  100  *
  101  *         Returns 0 if the operation was successful.
  102  *         Returns <0 if operation failed.
  103  *
  104  */
  105 int vid_sonix_decompress(unsigned char *outp, unsigned char *inp, int width, int height)
  106 {
  107     int row, col;
  108     int val;
  109     int bitpos;
  110     unsigned char code;
  111     unsigned char *addr;
  112 
  113     /* Local storage */
  114     static code_table_t table[256];
  115     static int init_done = 0;
  116 
  117     if (!init_done) {
  118         init_done = 1;
  119         vid_sonix_decompress_init(table);
  120         /* Do sonix_decompress_init first! */
  121         //return -1; // so it has been done and now fall through
  122     }
  123 
  124     bitpos = 0;
  125     for (row = 0; row < height; row++) {
  126 
  127         col = 0;
  128 
  129         /* First two pixels in first two rows are stored as raw 8-bit. */
  130         if (row < 2) {
  131             addr = inp + (bitpos >> 3);
  132             code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
  133             bitpos += 8;
  134             *outp++ = code;
  135 
  136             addr = inp + (bitpos >> 3);
  137             code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
  138             bitpos += 8;
  139             *outp++ = code;
  140 
  141             col += 2;
  142         }
  143 
  144         while (col < width) {
  145             /* Get bitcode from bitstream. */
  146             addr = inp + (bitpos >> 3);
  147             code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7)));
  148 
  149             /* Update bit position. */
  150             bitpos += table[code].len;
  151 
  152             /* Calculate pixel value. */
  153             val = table[code].val;
  154             if (!table[code].is_abs) {
  155                 /* Value is relative to top and left pixel. */
  156                 if (col < 2) {
  157                     /* Left column: relative to top pixel. */
  158                     val += outp[-2 * width];
  159                 } else if (row < 2) {
  160                     /* Top row: relative to left pixel. */
  161                     val += outp[-2];
  162                 } else {
  163                     /* Main area: average of left pixel and top pixel. */
  164                     val += (outp[-2] + outp[-2 * width]) / 2;
  165                 }
  166             }
  167 
  168             /* Store pixel */
  169             *outp++ = CLAMP(val);
  170             col++;
  171         }
  172     }
  173 
  174     return 0;
  175 }
  176 
  177 /**
  178  * bayer2rgb24
  179  * BAYER2RGB24 ROUTINE TAKEN FROM:
  180  *
  181  * Sonix SN9C10x based webcam basic I/F routines
  182  * Takafumi Mizuno <taka-qce@ls-a.jp>
  183  *
  184  */
  185 void vid_bayer2rgb24(unsigned char *dst, unsigned char *src, long int width, long int height)
  186 {
  187     long int i;
  188     unsigned char *rawpt, *scanpt;
  189     long int size;
  190 
  191     rawpt = src;
  192     scanpt = dst;
  193     size = width * height;
  194 
  195     for (i = 0; i < size; i++) {
  196         if (((i / width) & 1) == 0) {    // %2 changed to & 1
  197             if ((i & 1) == 0) {
  198                 /* B */
  199                 if ((i > width) && ((i % width) > 0)) {
  200                     *scanpt++ = *rawpt;     /* B */
  201                     *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) +
  202                                 *(rawpt + width) + *(rawpt - width)) / 4;    /* G */
  203                     *scanpt++ = (*(rawpt - width - 1) + *(rawpt - width + 1) +
  204                                 *(rawpt + width - 1) + *(rawpt + width + 1)) / 4;    /* R */
  205                 } else {
  206                     /* First line or left column. */
  207                     *scanpt++ = *rawpt;     /* B */
  208                     *scanpt++ = (*(rawpt + 1) + *(rawpt + width)) / 2;    /* G */
  209                     *scanpt++ = *(rawpt + width + 1);       /* R */
  210                 }
  211             } else {
  212                 /* (B)G */
  213                 if ((i > width) && ((i % width) < (width - 1))) {
  214                     *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2;  /* B */
  215                     *scanpt++ = *rawpt;    /* G */
  216                     *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2;  /* R */
  217                 } else {
  218                     /* First line or right column. */
  219                     *scanpt++ = *(rawpt - 1);       /* B */
  220                     *scanpt++ = *rawpt;    /* G */
  221                     *scanpt++ = *(rawpt + width);   /* R */
  222                 }
  223             }
  224         } else {
  225             if ((i & 1) == 0) {
  226                 /* G(R) */
  227                 if ((i < (width * (height - 1))) && ((i % width) > 0)) {
  228                     *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2;  /* B */
  229                     *scanpt++ = *rawpt;    /* G */
  230                     *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2;  /* R */
  231                 } else {
  232                     /* Bottom line or left column. */
  233                     *scanpt++ = *(rawpt - width);   /* B */
  234                     *scanpt++ = *rawpt;    /* G */
  235                     *scanpt++ = *(rawpt + 1);       /* R */
  236                 }
  237             } else {
  238                 /* R */
  239                 if (i < (width * (height - 1)) && ((i % width) < (width - 1))) {
  240                     *scanpt++ = (*(rawpt - width - 1) + *(rawpt - width + 1) +
  241                                 *(rawpt + width - 1) + *(rawpt + width + 1)) / 4;    /* B */
  242                     *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) +
  243                                 *(rawpt - width) + *(rawpt + width)) / 4;    /* G */
  244                     *scanpt++ = *rawpt;     /* R */
  245                 } else {
  246                     /* Bottom line or right column. */
  247                     *scanpt++ = *(rawpt - width - 1);       /* B */
  248                     *scanpt++ = (*(rawpt - 1) + *(rawpt - width)) / 2;    /* G */
  249                     *scanpt++ = *rawpt;     /* R */
  250                 }
  251             }
  252         }
  253         rawpt++;
  254     }
  255 
  256 }
  257 
  258 void vid_yuv422to420p(unsigned char *map, unsigned char *cap_map, int width, int height)
  259 {
  260     unsigned char *src, *dest, *src2, *dest2;
  261     int i, j;
  262 
  263     /* Create the Y plane. */
  264     src = cap_map;
  265     dest = map;
  266     for (i = width * height; i > 0; i--) {
  267         *dest++ = *src;
  268         src += 2;
  269     }
  270     /* Create U and V planes. */
  271     src = cap_map + 1;
  272     src2 = cap_map + width * 2 + 1;
  273     dest = map + width * height;
  274     dest2 = dest + (width * height) / 4;
  275     for (i = height / 2; i > 0; i--) {
  276         for (j = width / 2; j > 0; j--) {
  277             *dest = ((int) *src + (int) *src2) / 2;
  278             src += 2;
  279             src2 += 2;
  280             dest++;
  281             *dest2 = ((int) *src + (int) *src2) / 2;
  282             src += 2;
  283             src2 += 2;
  284             dest2++;
  285         }
  286         src += width * 2;
  287         src2 += width * 2;
  288     }
  289 }
  290 
  291 void vid_yuv422pto420p(unsigned char *map, unsigned char *cap_map, int width, int height)
  292 {
  293     unsigned char *src, *dest, *dest2;
  294     unsigned char *src_u, *src_u2, *src_v, *src_v2;
  295 
  296     int i, j;
  297     /*Planar version of 422 */
  298     /* Create the Y plane. */
  299     src = cap_map;
  300     dest = map;
  301     for (i = width * height; i > 0; i--) {
  302         *dest++ = *src++;
  303     }
  304 
  305     /* Create U and V planes. */
  306     dest = map + width * height;
  307     dest2 = dest + (width * height) / 4;
  308     for (i = 0; i< (height / 2); i++) {
  309         src_u = cap_map + (width * height) + ((i*2) * (width/2));
  310         src_u2 = src_u  + (width/2);
  311         src_v = src_u + (width/2 * height);
  312         src_v2 = src_v  + (width/2);
  313 
  314         for (j = 0; j < (width / 2); j++) {
  315             *dest = ((int) *src_u + (int) *src_u2) / 2;
  316             src_u ++;
  317             src_u2++;
  318             dest++;
  319 
  320             *dest2 = ((int) *src_v + (int) *src_v2) / 2;
  321             src_v ++;
  322             src_v2++;
  323             dest2++;
  324         }
  325     }
  326 }
  327 
  328 void vid_uyvyto420p(unsigned char *map, unsigned char *cap_map, int width, int height)
  329 {
  330     uint8_t *pY = map;
  331     uint8_t *pU = pY + (width * height);
  332     uint8_t *pV = pU + (width * height) / 4;
  333     uint32_t uv_offset = width * 2 * sizeof(uint8_t);
  334     int ix, jx;
  335 
  336     for (ix = 0; ix < height; ix++) {
  337         for (jx = 0; jx < width; jx += 2) {
  338             uint16_t calc;
  339 
  340             if ((ix&1) == 0) {
  341                 calc = *cap_map;
  342                 calc += *(cap_map + uv_offset);
  343                 calc /= 2;
  344                 *pU++ = (uint8_t) calc;
  345             }
  346 
  347             cap_map++;
  348             *pY++ = *cap_map++;
  349 
  350             if ((ix&1) == 0) {
  351                 calc = *cap_map;
  352                 calc += *(cap_map + uv_offset);
  353                 calc /= 2;
  354                 *pV++ = (uint8_t) calc;
  355             }
  356 
  357             cap_map++;
  358             *pY++ = *cap_map++;
  359         }
  360     }
  361 }
  362 
  363 void vid_rgb24toyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height)
  364 {
  365     unsigned char *y, *u, *v;
  366     unsigned char *r, *g, *b;
  367     int i, loop;
  368 
  369     r = cap_map;
  370     g = r + 1;
  371     b = g + 1;
  372 
  373     y = map;
  374     u = y + width * height;
  375     v = u + (width * height) / 4;
  376     memset(u, 0, width * height / 4);
  377     memset(v, 0, width * height / 4);
  378 
  379     for (loop = 0; loop < height; loop++) {
  380         for (i = 0; i < width; i += 2) {
  381             *y++ = (9796 ** r + 19235 ** g + 3736 ** b) >> 15;
  382             *u += ((-4784 ** r - 9437 ** g + 14221 ** b) >> 17) + 32;
  383             *v += ((20218 ** r - 16941 ** g - 3277 ** b) >> 17) + 32;
  384             r += 3;
  385             g += 3;
  386             b += 3;
  387             *y++ = (9796 ** r + 19235 ** g + 3736 ** b) >> 15;
  388             *u += ((-4784 ** r - 9437 ** g + 14221 ** b) >> 17) + 32;
  389             *v += ((20218 ** r - 16941 ** g - 3277 ** b) >> 17) + 32;
  390             r += 3;
  391             g += 3;
  392             b += 3;
  393             u++;
  394             v++;
  395         }
  396 
  397         if ((loop & 1) == 0) {
  398             u -= width / 2;
  399             v -= width / 2;
  400         }
  401     }
  402 }
  403 
  404 /**
  405  * mjpegtoyuv420p
  406  *
  407  * Return values
  408  *  -1 on fatal error
  409  *  0  on success
  410  *  2  if jpeg lib threw a "corrupt jpeg data" warning.
  411  *     in this case, "a damaged output image is likely."
  412  */
  413 int vid_mjpegtoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height, unsigned int size)
  414 {
  415     unsigned char *ptr_buffer;
  416     size_t soi_pos = 0;
  417     int ret = 0;
  418 
  419     ptr_buffer = memmem(cap_map, size, "\xff\xd8", 2);
  420     if (ptr_buffer == NULL) {
  421         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO,_("Corrupt image ... continue"));
  422         return 1;
  423     }
  424     /**
  425      Some cameras are sending multiple SOIs in the buffer.
  426      Move the pointer to the last SOI in the buffer and proceed.
  427     */
  428     while (ptr_buffer != NULL && ((size - soi_pos - 1) > 2) ){
  429         soi_pos = ptr_buffer - cap_map;
  430         ptr_buffer = memmem(cap_map + soi_pos + 1, size - soi_pos - 1, "\xff\xd8", 2);
  431     }
  432 
  433     if (soi_pos != 0){
  434         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO,_("SOI position adjusted by %d bytes."), soi_pos);
  435     }
  436 
  437     memmove(cap_map, cap_map + soi_pos, size - soi_pos);
  438     size -= soi_pos;
  439 
  440     ret = jpgutl_decode_jpeg(cap_map,size, width, height, map);
  441 
  442     if (ret == -1) {
  443         MOTION_LOG(CRT, TYPE_VIDEO, NO_ERRNO,_("Corrupt image ... continue"));
  444         ret = 1;
  445     }
  446     return ret;
  447 }
  448 
  449 void vid_y10torgb24(unsigned char *map, unsigned char *cap_map, int width, int height, int shift)
  450 {
  451     /* Source code: raw2rgbpnm project */
  452     /* url: http://salottisipuli.retiisi.org.uk/cgi-bin/gitweb.cgi?p=~sailus/raw2rgbpnm.git;a=summary */
  453 
  454     /* bpp - bits per pixel */
  455     /* bpp: 'Pixels are stored in 16-bit words with unused high bits padded with 0' */
  456     /* url: https://linuxtv.org/downloads/v4l-dvb-apis/V4L2-PIX-FMT-Y12.html */
  457     /* url: https://linuxtv.org/downloads/v4l-dvb-apis/V4L2-PIX-FMT-Y10.html */
  458 
  459     int src_size[2] = {width,height};
  460     int bpp = 16;
  461     unsigned int src_stride = (src_size[0] * bpp) / 8;
  462     unsigned int rgb_stride = src_size[0] * 3;
  463     int a = 0;
  464     int src_x = 0, src_y = 0;
  465     int dst_x = 0, dst_y = 0;
  466 
  467     for (src_y = 0, dst_y = 0; dst_y < src_size[1]; src_y++, dst_y++) {
  468         for (src_x = 0, dst_x = 0; dst_x < src_size[0]; src_x++, dst_x++) {
  469             a = (cap_map[src_y*src_stride + src_x*2+0] |
  470                 (cap_map[src_y*src_stride + src_x*2+1] << 8)) >> shift;
  471             map[dst_y*rgb_stride+3*dst_x+0] = a;
  472             map[dst_y*rgb_stride+3*dst_x+1] = a;
  473             map[dst_y*rgb_stride+3*dst_x+2] = a;
  474         }
  475     }
  476 }
  477 
  478 void vid_greytoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height)
  479 {
  480 
  481     memcpy(map, cap_map, (width*height));
  482     memset(map+(width*height), 128, (width * height) / 2);
  483 
  484 }
  485 
  486 static void vid_parms_add(struct vdev_context *vdevctx, char *config_name, char *config_val){
  487 
  488     /* Add the parameter and value to our user control array*/
  489     struct vdev_usrctrl_ctx *tmp;
  490     int indx;
  491 
  492     tmp = mymalloc(sizeof(struct vdev_usrctrl_ctx)*(vdevctx->usrctrl_count+1));
  493     for (indx=0;indx<vdevctx->usrctrl_count;indx++){
  494         tmp[indx].ctrl_name = mymalloc(strlen(vdevctx->usrctrl_array[indx].ctrl_name)+1);
  495         sprintf(tmp[indx].ctrl_name,"%s",vdevctx->usrctrl_array[indx].ctrl_name);
  496         free(vdevctx->usrctrl_array[indx].ctrl_name);
  497         vdevctx->usrctrl_array[indx].ctrl_name=NULL;
  498         tmp[indx].ctrl_value = vdevctx->usrctrl_array[indx].ctrl_value;
  499     }
  500     if (vdevctx->usrctrl_array != NULL){
  501       free(vdevctx->usrctrl_array);
  502       vdevctx->usrctrl_array =  NULL;
  503     }
  504 
  505     vdevctx->usrctrl_array = tmp;
  506     vdevctx->usrctrl_array[vdevctx->usrctrl_count].ctrl_name = mymalloc(strlen(config_name)+1);
  507     sprintf(vdevctx->usrctrl_array[vdevctx->usrctrl_count].ctrl_name,"%s",config_name);
  508     vdevctx->usrctrl_array[vdevctx->usrctrl_count].ctrl_value=atoi(config_val);
  509     vdevctx->usrctrl_count++;
  510 
  511 }
  512 
  513 int vid_parms_parse(struct context *cnt){
  514 
  515     /* Parse through the configuration option to get values
  516      * The values are separated by commas but may also have
  517      * double quotes around the names which include a comma.
  518      * Examples:
  519      * vid_control_parms ID01234= 1, ID23456=2
  520      * vid_control_parms "Brightness, auto" = 1, ID23456=2
  521      * vid_control_parms ID23456=2, "Brightness, auto" = 1,ID2222=5
  522      */
  523     int indx_parm;
  524     int parmval_st , parmval_len;
  525     int parmdesc_st, parmdesc_len;
  526     int qte_open;
  527     struct vdev_context *vdevctx;
  528     char tst;
  529     char *parmdesc, *parmval;
  530 
  531     if (!cnt->vdev->update_parms) return 0;
  532 
  533     vdevctx = cnt->vdev;
  534 
  535     for (indx_parm=0;indx_parm<vdevctx->usrctrl_count;indx_parm++){
  536         free(vdevctx->usrctrl_array[indx_parm].ctrl_name);
  537         vdevctx->usrctrl_array[indx_parm].ctrl_name=NULL;
  538     }
  539     if (vdevctx->usrctrl_array != NULL){
  540       free(vdevctx->usrctrl_array);
  541       vdevctx->usrctrl_array = NULL;
  542     }
  543     vdevctx->usrctrl_count = 0;
  544 
  545     if (cnt->conf.vid_control_params != NULL){
  546         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO,_("Parsing controls: %s"),cnt->conf.vid_control_params);
  547 
  548         indx_parm = 0;
  549         parmdesc_st  = parmval_st  = -1;
  550         parmdesc_len = parmval_len = 0;
  551         qte_open = FALSE;
  552         parmdesc = parmval = NULL;
  553         tst = cnt->conf.vid_control_params[indx_parm];
  554         while (tst != '\0') {
  555             if (!qte_open) {
  556                 if (tst == '\"') {                    /* This is the opening quotation */
  557                     qte_open = TRUE;
  558                     parmdesc_st = indx_parm + 1;
  559                     parmval_st  = -1;
  560                     parmdesc_len = parmval_len = 0;
  561                     if (parmdesc != NULL) free(parmdesc);
  562                     if (parmval  != NULL) free(parmval);
  563                     parmdesc = parmval = NULL;
  564                 } else if (tst == ','){               /* Designator for next parm*/
  565                     if ((parmval_st >= 0) && (parmval_len > 0)){
  566                         if (parmval  != NULL) free(parmval);
  567                         parmval = mymalloc(parmval_len);
  568                         snprintf(parmval, parmval_len,"%s",&cnt->conf.vid_control_params[parmval_st]);
  569                     }
  570                     parmdesc_st  = indx_parm + 1;
  571                     parmval_st  = -1;
  572                     parmdesc_len = parmval_len = 0;
  573                 } else if (tst == '='){               /* Designator for end of desc and start of value*/
  574                     if ((parmdesc_st >= 0) && (parmdesc_len > 0)) {
  575                         if (parmdesc != NULL) free(parmdesc);
  576                         parmdesc = mymalloc(parmdesc_len);
  577                         snprintf(parmdesc, parmdesc_len,"%s",&cnt->conf.vid_control_params[parmdesc_st]);
  578                     }
  579                     parmdesc_st = -1;
  580                     parmval_st = indx_parm + 1;
  581                     parmdesc_len = parmval_len = 0;
  582                     if (parmval != NULL) free(parmval);
  583                     parmval = NULL;
  584                 } else if (tst == ' '){               /* Skip leading spaces */
  585                     if (indx_parm == parmdesc_st) parmdesc_st++;
  586                     if (indx_parm == parmval_st) parmval_st++;
  587                 } else if (tst != ' '){               /* Revise the length making sure it is not a space*/
  588                     parmdesc_len = indx_parm - parmdesc_st + 2;
  589                     parmval_len = indx_parm - parmval_st + 2;
  590                     if (parmdesc_st == -1) parmdesc_st = indx_parm;
  591                 }
  592             } else if (tst == '\"') {                /* This is the closing quotation */
  593                 parmdesc_len = indx_parm - parmdesc_st + 1;
  594                 if (parmdesc_len > 0 ){
  595                     if (parmdesc != NULL) free(parmdesc);
  596                     parmdesc = mymalloc(parmdesc_len);
  597                     snprintf(parmdesc, parmdesc_len,"%s",&cnt->conf.vid_control_params[parmdesc_st]);
  598                 }
  599                 parmdesc_st = -1;
  600                 parmval_st = indx_parm + 1;
  601                 parmdesc_len = parmval_len = 0;
  602                 if (parmval != NULL) free(parmval);
  603                 parmval = NULL;
  604                 qte_open = FALSE;   /* Reset the open/close on quotation */
  605             }
  606             if ((parmdesc != NULL) && (parmval  != NULL)){
  607                 vid_parms_add(vdevctx, parmdesc, parmval);
  608                 free(parmdesc);
  609                 free(parmval);
  610                 parmdesc = parmval = NULL;
  611             }
  612 
  613             indx_parm++;
  614             tst = cnt->conf.vid_control_params[indx_parm];
  615         }
  616         /* Process the last parameter */
  617         if ((parmval_st >= 0) && (parmval_len > 0)){
  618             if (parmval  != NULL) free(parmval);
  619             parmval = mymalloc(parmval_len+1);
  620             snprintf(parmval, parmval_len,"%s",&cnt->conf.vid_control_params[parmval_st]);
  621         }
  622         if ((parmdesc != NULL) && (parmval  != NULL)){
  623             vid_parms_add(vdevctx, parmdesc, parmval);
  624             free(parmdesc);
  625             free(parmval);
  626             parmdesc = parmval = NULL;
  627         }
  628 
  629         if (parmdesc != NULL) free(parmdesc);
  630         if (parmval  != NULL) free(parmval);
  631     }
  632 
  633     cnt->vdev->update_parms = FALSE;
  634 
  635     return 0;
  636 
  637 }
  638 
  639 void vid_mutex_init(void)
  640 {
  641     v4l2_mutex_init();
  642     bktr_mutex_init();
  643 }
  644 
  645 void vid_mutex_destroy(void)
  646 {
  647     v4l2_mutex_destroy();
  648     bktr_mutex_destroy();
  649 }
  650 
  651 void vid_close(struct context *cnt) {
  652 
  653 #ifdef HAVE_MMAL
  654     if (cnt->mmalcam) {
  655         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO,_("calling mmalcam_cleanup"));
  656         mmalcam_cleanup(cnt->mmalcam);
  657         cnt->mmalcam = NULL;
  658         return;
  659     }
  660 #endif
  661 
  662     if (cnt->netcam) {
  663         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO,_("calling netcam_cleanup"));
  664         netcam_cleanup(cnt->netcam, 0);
  665         cnt->netcam = NULL;
  666         return;
  667     }
  668 
  669     if (cnt->rtsp) {
  670         /* This also cleans up high resolution */
  671         MOTION_LOG(INF, TYPE_VIDEO, NO_ERRNO,_("calling netcam_rtsp_cleanup"));
  672         netcam_rtsp_cleanup(cnt, 0);
  673         return;
  674     }
  675 
  676     if (cnt->camera_type == CAMERA_TYPE_V4L2) {
  677         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Cleaning up V4L2 device"));
  678         v4l2_cleanup(cnt);
  679         return;
  680     }
  681 
  682     if (cnt->camera_type == CAMERA_TYPE_BKTR) {
  683         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Cleaning up BKTR device"));
  684         bktr_cleanup(cnt);
  685         return;
  686     }
  687 
  688     MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("No Camera device cleanup (MMAL, Netcam, V4L2, BKTR)"));
  689     return;
  690 
  691 }
  692 
  693 /**
  694  * vid_start
  695  *
  696  * vid_start setup the capture device. This will be either a V4L device or a netcam.
  697  * The function does the following:
  698  * - If the camera is a netcam - netcam_start is called and function returns
  699  * - Width and height are checked for valid value (multiple of 8)
  700  * - Copy the config height and width to the imgs struct. Note that height and width are
  701  *   only copied to the from the conf struct to the imgs struct during program startup
  702  *   The width and height can no later be changed via http remote control as this would
  703  *   require major re-memory allocations of all image buffers.
  704  *
  705  * - if the camera is V4L2 v4l2_start is called
  706  *
  707  * Parameters:
  708  *     cnt        Pointer to the context for this thread
  709  *
  710  * Returns
  711  *     device number
  712  *     -1 if failed to open device.
  713  *     -3 image dimensions are not modulo 8
  714  */
  715 int vid_start(struct context *cnt) {
  716     int dev = -1;
  717 
  718 #ifdef HAVE_MMAL
  719     if (cnt->camera_type == CAMERA_TYPE_MMAL) {
  720         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening MMAL cam"));
  721         dev = mmalcam_start(cnt);
  722         if (dev < 0) {
  723             mmalcam_cleanup(cnt->mmalcam);
  724             cnt->mmalcam = NULL;
  725             MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("MMAL cam failed to open"));
  726         }
  727         return dev;
  728     }
  729 #endif
  730 
  731     if (cnt->camera_type == CAMERA_TYPE_NETCAM) {
  732         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening Netcam"));
  733         dev = netcam_start(cnt);
  734         if (dev < 0) {
  735             netcam_cleanup(cnt->netcam, 1);
  736             cnt->netcam = NULL;
  737             MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("Netcam failed to open"));
  738         }
  739         return dev;
  740     }
  741 
  742     if (cnt->camera_type == CAMERA_TYPE_RTSP) {
  743         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening Netcam RTSP"));
  744         dev = netcam_rtsp_setup(cnt);
  745         if (dev < 0) {
  746             netcam_rtsp_cleanup(cnt, 1);
  747             MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("Netcam RTSP failed to open"));
  748         }
  749         return dev;
  750     }
  751 
  752     if (cnt->camera_type == CAMERA_TYPE_V4L2) {
  753         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening V4L2 device"));
  754         dev = v4l2_start(cnt);
  755         if (dev < 0) {
  756             MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("V4L2 device failed to open"));
  757         }
  758         return dev;
  759     }
  760 
  761     if (cnt->camera_type == CAMERA_TYPE_BKTR) {
  762         MOTION_LOG(NTC, TYPE_VIDEO, NO_ERRNO,_("Opening BKTR device"));
  763         dev = bktr_start(cnt);
  764         if (dev < 0) {
  765             MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO,_("BKTR device failed to open"));
  766         }
  767         return dev;
  768     }
  769 
  770     MOTION_LOG(ERR, TYPE_VIDEO, NO_ERRNO
  771         ,_("No Camera device specified (MMAL, Netcam, V4L2, BKTR)"));
  772     return dev;
  773 
  774 }
  775 
  776 /**
  777  * vid_next
  778  *
  779  * vid_next fetches a video frame from a either v4l device or netcam
  780  *
  781  * Parameters:
  782  *     cnt        Pointer to the context for this thread
  783  *     map        Pointer to the buffer in which the function puts the new image
  784  *
  785  * Global variable
  786  *     viddevs    The viddevs struct is "global" within the context of video.c
  787  *                and used in functions vid_*.
  788  * Returns
  789  *     0                        Success
  790  *    -1                        Fatal V4L error
  791  *    -2                        Fatal Netcam error
  792  *    Positive numbers...
  793  *    with bit 0 set            Non fatal V4L error (copy grey image and discard this image)
  794  *    with bit 1 set            Non fatal Netcam error
  795  */
  796 int vid_next(struct context *cnt, struct image_data *img_data){
  797 
  798 #ifdef HAVE_MMAL
  799      if (cnt->camera_type == CAMERA_TYPE_MMAL) {
  800         if (cnt->mmalcam == NULL) {
  801             return NETCAM_GENERAL_ERROR;
  802         }
  803         return mmalcam_next(cnt, img_data);
  804     }
  805 #endif
  806 
  807     if (cnt->camera_type == CAMERA_TYPE_NETCAM) {
  808         if (cnt->video_dev == -1)
  809             return NETCAM_GENERAL_ERROR;
  810 
  811         return netcam_next(cnt, img_data);
  812     }
  813 
  814     if (cnt->camera_type == CAMERA_TYPE_RTSP) {
  815         if (cnt->video_dev == -1)
  816             return NETCAM_GENERAL_ERROR;
  817 
  818         return netcam_rtsp_next(cnt, img_data);
  819     }
  820 
  821     if (cnt->camera_type == CAMERA_TYPE_V4L2) {
  822         return v4l2_next(cnt, img_data);
  823    }
  824 
  825     if (cnt->camera_type == CAMERA_TYPE_BKTR) {
  826         return bktr_next(cnt, img_data);
  827     }
  828 
  829     return -2;
  830 }