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  */
vid_sonix_decompress_init(code_table_t * table)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  */
vid_sonix_decompress(unsigned char * outp,unsigned char * inp,int width,int height)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  */
vid_bayer2rgb24(unsigned char * dst,unsigned char * src,long int width,long int height)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 
vid_yuv422to420p(unsigned char * map,unsigned char * cap_map,int width,int height)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 
vid_yuv422pto420p(unsigned char * map,unsigned char * cap_map,int width,int height)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 
vid_uyvyto420p(unsigned char * map,unsigned char * cap_map,int width,int height)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 
vid_rgb24toyuv420p(unsigned char * map,unsigned char * cap_map,int width,int height)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  */
vid_mjpegtoyuv420p(unsigned char * map,unsigned char * cap_map,int width,int height,unsigned int size)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 
vid_y10torgb24(unsigned char * map,unsigned char * cap_map,int width,int height,int shift)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 
vid_greytoyuv420p(unsigned char * map,unsigned char * cap_map,int width,int height)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 
vid_parms_add(struct vdev_context * vdevctx,char * config_name,char * config_val)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 
vid_parms_parse(struct context * cnt)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 
vid_mutex_init(void)639 void vid_mutex_init(void)
640 {
641     v4l2_mutex_init();
642     bktr_mutex_init();
643 }
644 
vid_mutex_destroy(void)645 void vid_mutex_destroy(void)
646 {
647     v4l2_mutex_destroy();
648     bktr_mutex_destroy();
649 }
650 
vid_close(struct context * cnt)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  */
vid_start(struct context * cnt)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  */
vid_next(struct context * cnt,struct image_data * img_data)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 }
831