📄 video_common.c
字号:
/* video_common.c * * Video stream functions for motion. * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) * 2006 by Krzysztof Blaszkowski (kb@sysmikro.com.pl) * 2007 by Angel Carpinteo (ack@telefonica.net) * This software is distributed under the GNU public license version 2 * See also the file 'COPYING'. * *///#include "motion.h"/* for rotation */#include "rotate.h" /* already includes motion.h */#include "video.h"/* for rotation *///#include "rotate.h"#ifdef MJPEGT #include <mjpegtools/jpegutils.h>#include <mjpegtools/mjpeg_types.h>#endiftypedef unsigned char uint8_t;typedef unsigned short int uint16_t;typedef unsigned int uint32_t;#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x))typedef struct { int is_abs; int len; int val;} code_table_t;/* * sonix_decompress_init * ===================== * pre-calculates a locally stored table for efficient huffman-decoding. * * Each entry at index x in the table represents the codeword * present at the MSB of byte x. * */static void sonix_decompress_init(code_table_t * table){ int i; int is_abs, val, len; for (i = 0; i < 256; i++) { is_abs = 0; val = 0; len = 0; if ((i & 0x80) == 0) { /* code 0 */ val = 0; len = 1; } else if ((i & 0xE0) == 0x80) { /* code 100 */ val = +4; len = 3; } else if ((i & 0xE0) == 0xA0) { /* code 101 */ val = -4; len = 3; } else if ((i & 0xF0) == 0xD0) { /* code 1101 */ val = +11; len = 4; } else if ((i & 0xF0) == 0xF0) { /* code 1111 */ val = -11; len = 4; } else if ((i & 0xF8) == 0xC8) { /* code 11001 */ val = +20; len = 5; } else if ((i & 0xFC) == 0xC0) { /* code 110000 */ val = -20; len = 6; } else if ((i & 0xFC) == 0xC4) { /* code 110001xx: unknown */ val = 0; len = 8; } else if ((i & 0xF0) == 0xE0) { /* code 1110xxxx */ is_abs = 1; val = (i & 0x0F) << 4; len = 8; } table[i].is_abs = is_abs; table[i].val = val; table[i].len = len; }}/* * sonix_decompress * ================ * decompresses an image encoded by a SN9C101 camera controller chip. * * IN width * height * inp pointer to compressed frame (with header already stripped) * OUT outp pointer to decompressed frame * * Returns 0 if the operation was successful. * Returns <0 if operation failed. * */int sonix_decompress(unsigned char *outp, unsigned char *inp, int width, int height){ int row, col; int val; int bitpos; unsigned char code; unsigned char *addr; /* local storage */ static code_table_t table[256]; static int init_done = 0; if (!init_done) { init_done = 1; sonix_decompress_init(table); /* do sonix_decompress_init first! */ //return -1; // so it has been done and now fall through } bitpos = 0; for (row = 0; row < height; row++) { col = 0; /* first two pixels in first two rows are stored as raw 8-bit */ if (row < 2) { addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); bitpos += 8; *outp++ = code; addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); bitpos += 8; *outp++ = code; col += 2; } while (col < width) { /* get bitcode from bitstream */ addr = inp + (bitpos >> 3); code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); /* update bit position */ bitpos += table[code].len; /* calculate pixel value */ val = table[code].val; if (!table[code].is_abs) { /* value is relative to top and left pixel */ if (col < 2) { /* left column: relative to top pixel */ val += outp[-2 * width]; } else if (row < 2) { /* top row: relative to left pixel */ val += outp[-2]; } else { /* main area: average of left pixel and top pixel */ val += (outp[-2] + outp[-2 * width]) / 2; } } /* store pixel */ *outp++ = CLAMP(val); col++; } } return 0;}/* * BAYER2RGB24 ROUTINE TAKEN FROM: * * Sonix SN9C10x based webcam basic I/F routines * Takafumi Mizuno <taka-qce@ls-a.jp> * */void bayer2rgb24(unsigned char *dst, unsigned char *src, long int width, long int height){ long int i; unsigned char *rawpt, *scanpt; long int size; rawpt = src; scanpt = dst; size = width * height; for (i = 0; i < size; i++) { if (((i / width) & 1) == 0) { // %2 changed to & 1 if ((i & 1) == 0) { /* B */ if ((i > width) && ((i % width) > 0)) { *scanpt++ = *rawpt; /* B */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt + width) + *(rawpt - width)) / 4; /* G */ *scanpt++ = (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / 4; /* R */ } else { /* first line or left column */ *scanpt++ = *rawpt; /* B */ *scanpt++ = (*(rawpt + 1) + *(rawpt + width)) / 2; /* G */ *scanpt++ = *(rawpt + width + 1); /* R */ } } else { /* (B)G */ if ((i > width) && ((i % width) < (width - 1))) { *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* B */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* R */ } else { /* first line or right column */ *scanpt++ = *(rawpt - 1); /* B */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt + width); /* R */ } } } else { if ((i & 1) == 0) { /* G(R) */ if ((i < (width * (height - 1))) && ((i % width) > 0)) { *scanpt++ = (*(rawpt + width) + *(rawpt - width)) / 2; /* B */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1)) / 2; /* R */ } else { /* bottom line or left column */ *scanpt++ = *(rawpt - width); /* B */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt + 1); /* R */ } } else { /* R */ if (i < (width * (height - 1)) && ((i % width) < (width - 1))) { *scanpt++ = (*(rawpt - width - 1) + *(rawpt - width + 1) + *(rawpt + width - 1) + *(rawpt + width + 1)) / 4; /* B */ *scanpt++ = (*(rawpt - 1) + *(rawpt + 1) + *(rawpt - width) + *(rawpt + width)) / 4; /* G */ *scanpt++ = *rawpt; /* R */ } else { /* bottom line or right column */ *scanpt++ = *(rawpt - width - 1); /* B */ *scanpt++ = (*(rawpt - 1) + *(rawpt - width)) / 2; /* G */ *scanpt++ = *rawpt; /* R */ } } } rawpt++; }}void conv_yuv422to420p(unsigned char *map, unsigned char *cap_map, int width, int height){ unsigned char *src, *dest, *src2, *dest2; int i, j; /* Create the Y plane */ src = cap_map; dest = map; for (i = width * height; i > 0; i--) { *dest++ = *src; src += 2; } /* Create U and V planes */ src = cap_map + 1; src2 = cap_map + width * 2 + 1; dest = map + width * height; dest2 = dest + (width * height) / 4; for (i = height / 2; i > 0; i--) { for (j = width / 2; j > 0; j--) { *dest = ((int) *src + (int) *src2) / 2; src += 2; src2 += 2; dest++; *dest2 = ((int) *src + (int) *src2) / 2; src += 2; src2 += 2; dest2++; } src += width * 2; src2 += width * 2; }}void conv_uyvyto420p(unsigned char *map, unsigned char *cap_map, unsigned int width, unsigned int height){ uint8_t *pY = map; uint8_t *pU = pY + (width * height); uint8_t *pV = pU + (width * height)/4; uint32_t uv_offset = width * 4 * sizeof(uint8_t); uint32_t ix, jx; for (ix = 0; ix < height; ix++) { for (jx = 0; jx < width; jx += 2) { uint16_t calc; if ((ix&1) == 0) { calc = *cap_map; calc += *(cap_map + uv_offset); calc /= 2; *pU++ = (uint8_t) calc; } cap_map++; *pY++ = *cap_map++; if ((ix&1) == 0) { calc = *cap_map; calc += *(cap_map + uv_offset); calc /= 2; *pV++ = (uint8_t) calc; } cap_map++; *pY++ = *cap_map++; } }}void conv_rgb24toyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height){ unsigned char *y, *u, *v; unsigned char *r, *g, *b; int i, loop; b = cap_map; g = b + 1; r = g + 1; y = map; u = y + width * height; v = u + (width * height) / 4; memset(u, 0, width * height / 4); memset(v, 0, width * height / 4); for (loop = 0; loop < height; loop++) { for (i = 0; i < width; i += 2) { *y++ = (9796 ** r + 19235 ** g + 3736 ** b) >> 15; *u += ((-4784 ** r - 9437 ** g + 14221 ** b) >> 17) + 32; *v += ((20218 ** r - 16941 ** g - 3277 ** b) >> 17) + 32; r += 3; g += 3; b += 3; *y++ = (9796 ** r + 19235 ** g + 3736 ** b) >> 15; *u += ((-4784 ** r - 9437 ** g + 14221 ** b) >> 17) + 32; *v += ((20218 ** r - 16941 ** g - 3277 ** b) >> 17) + 32; r += 3; g += 3; b += 3; u++; v++; } if ((loop & 1) == 0) { u -= width / 2; v -= width / 2; } }}int conv_jpeg2yuv420(struct context *cnt, unsigned char *dst, netcam_buff * buff, int width, int height){ netcam_context netcam; if (!buff || !dst) return 3; if (!buff->ptr) return 2; /* Error decoding MJPEG frame */ memset(&netcam, 0, sizeof(netcam)); netcam.imgcnt_last = 1; netcam.latest = buff; netcam.width = width; netcam.height = height; netcam.cnt = cnt; pthread_mutex_init(&netcam.mutex, NULL); pthread_cond_init(&netcam.cap_cond, NULL); pthread_cond_init(&netcam.pic_ready, NULL); pthread_cond_init(&netcam.exiting, NULL); if (setjmp(netcam.setjmp_buffer)) { return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR; } return netcam_proc_jpeg(&netcam, dst);}#ifdef MJPEGT void mjpegtoyuv420p(unsigned char *map, unsigned char *cap_map, int width, int height, unsigned int size){ uint8_t *yuv[3]; unsigned char *y, *u, *v; int loop; yuv[0] = malloc(width * height * sizeof(yuv[0][0])); yuv[1] = malloc(width * height / 4 * sizeof(yuv[1][0])); yuv[2] = malloc(width * height / 4 * sizeof(yuv[2][0])); decode_jpeg_raw(cap_map, size, 0, 420, width, height, yuv[0], yuv[1], yuv[2]); y=map; u=y+width*height; v=u+(width*height)/4; memset(y, 0, width*height); memset(u, 0, width*height/4); memset(v, 0, width*height/4); for(loop=0; loop<width*height; loop++) { *map++=yuv[0][loop]; } for(loop=0; loop<width*height/4; loop++) { *map++=yuv[1][loop]; } for(loop=0; loop<width*height/4; loop++) { *map++=yuv[2][loop]; } free(yuv[0]); free(yuv[1]); free(yuv[2]);}#endif#define MAX2(x, y) ((x) > (y) ? (x) : (y))#define MIN2(x, y) ((x) < (y) ? (x) : (y))/* Constants used by auto brightness feature * Defined as constant to make it easier for people to tweak code for a * difficult camera. * The experience gained from people could help improving the feature without * adding too many new options. * AUTOBRIGHT_HYSTERESIS sets the minimum the light intensity must change before * we adjust brigtness. * AUTOBRIGHTS_DAMPER damps the speed with which we adjust the brightness * When the brightness changes a lot we step in large steps and as we approach the * target value we slow down to avoid overshoot and oscillations. If the camera * adjusts too slowly decrease the DAMPER value. If the camera oscillates try * increasing the DAMPER value. DAMPER must be minimum 1. * MAX and MIN are the max and min values of brightness setting we will send to * the camera device. */#define AUTOBRIGHT_HYSTERESIS 10#define AUTOBRIGHT_DAMPER 5#define AUTOBRIGHT_MAX 255#define AUTOBRIGHT_MIN 0int vid_do_autobright(struct context *cnt, struct video_dev *viddev){ int brightness_window_high; int brightness_window_low; int brightness_target; int i, j = 0, avg = 0, step = 0; unsigned char *image = cnt->imgs.image_virgin; /* Or cnt->current_image ? */ int make_change = 0; if (cnt->conf.brightness) brightness_target = cnt->conf.brightness; else brightness_target = 128; brightness_window_high = MIN2(brightness_target + AUTOBRIGHT_HYSTERESIS, 255); brightness_window_low = MAX2(brightness_target - AUTOBRIGHT_HYSTERESIS, 1); for (i = 0; i < cnt->imgs.motionsize; i += 101) { avg += image[i];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -