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