From c9c11b775f91c5dc43aa18f830f0bc016183bd1d Mon Sep 17 00:00:00 2001 From: AngelCarpintero Date: Thu, 17 Jul 2008 13:00:18 +0000 Subject: [PATCH] More code standard --- alg.c | 1763 ++++++++++----------- draw.c | 2281 +++++++++++++-------------- event.c | 905 +++++------ ffmpeg.c | 929 +++++------ motion.c | 3922 +++++++++++++++++++++++----------------------- netcam.c | 3437 ++++++++++++++++++++-------------------- netcam_ftp.c | 1120 ++++++------- netcam_wget.c | 344 ++-- picture.c | 936 +++++------ rotate.c | 475 +++--- video.c | 913 +++++------ video2.c | 1196 +++++++------- video_common.c | 1205 +++++++------- webhttpd.c | 4050 ++++++++++++++++++++++++------------------------ 14 files changed, 11829 insertions(+), 11647 deletions(-) diff --git a/alg.c b/alg.c index bb69ab5a..bda467b7 100644 --- a/alg.c +++ b/alg.c @@ -1,9 +1,9 @@ -/* alg.c +/* alg.c * - * Detect changes in a video stream. - * Copyright 2001 by Jeroen Vreeken (pe1rxq@amsat.org) - * This software is distributed under the GNU public license version 2 - * See also the file 'COPYING'. + * Detect changes in a video stream. + * Copyright 2001 by Jeroen Vreeken (pe1rxq@amsat.org) + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. * */ #include "motion.h" @@ -20,170 +20,172 @@ /* locate the center and size of the movement. */ void alg_locate_center_size(struct images *imgs, int width, int height, struct coord *cent) { - unsigned char *out=imgs->out; - int *labels=imgs->labels; - int x, y, centc=0, xdist=0, ydist=0; + unsigned char *out=imgs->out; + int *labels=imgs->labels; + int x, y, centc=0, xdist=0, ydist=0; - cent->x=0; - cent->y=0; - cent->maxx=0; - cent->maxy=0; - cent->minx=width; - cent->miny=height; + cent->x=0; + cent->y=0; + cent->maxx=0; + cent->maxy=0; + cent->minx=width; + cent->miny=height; - /* If Labeling enabled - locate center of largest labelgroup */ - if (imgs->labelsize_max) { - /* Locate largest labelgroup */ - for (y=0; yx += x; - cent->y += y; - centc++; - } - } - } - } else { - /* Locate movement */ - for (y=0; yx += x; - cent->y += y; - centc++; - } - } - } - } - if (centc) { - cent->x=cent->x/centc; - cent->y=cent->y/centc; - } - - /* Now we find the size of the Motion */ + /* If Labeling enabled - locate center of largest labelgroup */ + if (imgs->labelsize_max) { + /* Locate largest labelgroup */ + for (y=0; yx += x; + cent->y += y; + centc++; + } + } + } + } else { + /* Locate movement */ + for (y=0; yx += x; + cent->y += y; + centc++; + } + } + } + } + if (centc) { + cent->x=cent->x/centc; + cent->y=cent->y/centc; + } + + /* Now we find the size of the Motion */ - /* First reset pointers back to initial value */ - centc=0; - labels=imgs->labels; - out=imgs->out; + /* First reset pointers back to initial value */ + centc=0; + labels=imgs->labels; + out=imgs->out; - /* If Labeling then we find the area around largest labelgroup instead */ - if (imgs->labelsize_max) { - for (y=0; y cent->x) - xdist += x - cent->x; - else if (x < cent->x) - xdist += cent->x - x; - if (y > cent->y) - ydist += y - cent->y; - else if (y < cent->y) - ydist += cent->y - y; - centc++; - } - } - } - } else { - for (y=0; y cent->x) - xdist += x - cent->x; - else if (x < cent->x) - xdist += cent->x - x; - if (y > cent->y) - ydist += y - cent->y; - else if (y < cent->y) - ydist += cent->y - y; - centc++; - } - } - } - } - - if (centc) { - cent->minx = cent->x - xdist/centc*2; - cent->maxx = cent->x + xdist/centc*2; - /* Make the box a little bigger in y direction to make sure the - heads fit in so we multiply by 3 instead of 2 which seems to - to work well in practical */ - cent->miny = cent->y - ydist/centc*3; - cent->maxy = cent->y + ydist/centc*2; - } - if (cent->maxx > width - 1) - cent->maxx = width - 1; - else if (cent->maxx < 0) - cent->maxx = 0; - if (cent->maxy > height - 1) - cent->maxy = height - 1; - else if (cent->maxy < 0) - cent->maxy = 0; - if (cent->minx > width - 1) - cent->minx = width - 1; - else if (cent->minx < 0) - cent->minx = 0; - if (cent->miny > height - 1) - cent->miny = height - 1; - else if (cent->miny < 0) - cent->miny = 0; - - cent->width = cent->maxx - cent->minx; - cent->height = cent->maxy - cent->miny; - - /* We want to center Y coordinate to be the center of the action. - The head of a person is important so we correct the cent.y coordinate - to match the correction to include a persons head that we just did above */ - cent->y = (cent->miny + cent->maxy)/2; - + /* If Labeling then we find the area around largest labelgroup instead */ + if (imgs->labelsize_max) { + for (y=0; y cent->x) + xdist += x - cent->x; + else if (x < cent->x) + xdist += cent->x - x; + if (y > cent->y) + ydist += y - cent->y; + else if (y < cent->y) + ydist += cent->y - y; + centc++; + } + } + } + } else { + for (y=0; y cent->x) + xdist += x - cent->x; + else if (x < cent->x) + xdist += cent->x - x; + if (y > cent->y) + ydist += y - cent->y; + else if (y < cent->y) + ydist += cent->y - y; + centc++; + } + } + } + } + + if (centc) { + cent->minx = cent->x - xdist/centc*2; + cent->maxx = cent->x + xdist/centc*2; + /* Make the box a little bigger in y direction to make sure the + heads fit in so we multiply by 3 instead of 2 which seems to + to work well in practical */ + cent->miny = cent->y - ydist/centc*3; + cent->maxy = cent->y + ydist/centc*2; + } + if (cent->maxx > width - 1) + cent->maxx = width - 1; + else if (cent->maxx < 0) + cent->maxx = 0; + if (cent->maxy > height - 1) + cent->maxy = height - 1; + else if (cent->maxy < 0) + cent->maxy = 0; + if (cent->minx > width - 1) + cent->minx = width - 1; + else if (cent->minx < 0) + cent->minx = 0; + if (cent->miny > height - 1) + cent->miny = height - 1; + else if (cent->miny < 0) + cent->miny = 0; + + cent->width = cent->maxx - cent->minx; + cent->height = cent->maxy - cent->miny; + + /* We want to center Y coordinate to be the center of the action. + The head of a person is important so we correct the cent.y coordinate + to match the correction to include a persons head that we just did above */ + cent->y = (cent->miny + cent->maxy)/2; + } /* draw a box around the movement */ void alg_draw_location(struct coord *cent, struct images *imgs, int width, unsigned char *new, int mode) { - unsigned char *out=imgs->out; - int x, y; + unsigned char *out=imgs->out; + int x, y; - out=imgs->out; + out=imgs->out; - /* Draw a box around the movement */ - if (mode == LOCATE_BOTH){ /* both normal and motion image gets a box */ - int width_miny = width*cent->miny; - int width_maxy = width*cent->maxy; - for (x=cent->minx; x<=cent->maxx; x++) { - int width_miny_x = x+width_miny; - int width_maxy_x = x+width_maxy; - new[width_miny_x]=~new[width_miny_x]; - new[width_maxy_x]=~new[width_maxy_x]; - out[width_miny_x]=~out[width_miny_x]; - out[width_maxy_x]=~out[width_maxy_x]; - } - for (y=cent->miny; y<=cent->maxy; y++) { - int width_minx_y = cent->minx+y*width; - int width_maxx_y = cent->maxx+y*width; - new[width_minx_y]=~new[width_minx_y]; - new[width_maxx_y]=~new[width_maxx_y]; - out[width_minx_y]=~out[width_minx_y]; - out[width_maxx_y]=~out[width_maxx_y]; - } - } - else{ /* normal image only (e.g. preview shot) */ - int width_miny = width*cent->miny; - int width_maxy = width*cent->maxy; - for (x=cent->minx; x<=cent->maxx; x++) { - int width_miny_x = width_miny+x; - int width_maxy_x = width_maxy+x; - new[width_miny_x]=~new[width_miny_x]; - new[width_maxy_x]=~new[width_maxy_x]; - } - for (y=cent->miny; y<=cent->maxy; y++) { - int minx_y = cent->minx+y*width; - int maxx_y = cent->maxx+y*width; - new[minx_y]=~new[minx_y]; - new[maxx_y]=~new[maxx_y]; - } - } + /* Draw a box around the movement */ + if (mode == LOCATE_BOTH){ /* both normal and motion image gets a box */ + int width_miny = width*cent->miny; + int width_maxy = width*cent->maxy; + + for (x=cent->minx; x<=cent->maxx; x++) { + int width_miny_x = x+width_miny; + int width_maxy_x = x+width_maxy; + new[width_miny_x]=~new[width_miny_x]; + new[width_maxy_x]=~new[width_maxy_x]; + out[width_miny_x]=~out[width_miny_x]; + out[width_maxy_x]=~out[width_maxy_x]; + } + + for (y=cent->miny; y<=cent->maxy; y++) { + int width_minx_y = cent->minx+y*width; + int width_maxx_y = cent->maxx+y*width; + new[width_minx_y]=~new[width_minx_y]; + new[width_maxx_y]=~new[width_maxx_y]; + out[width_minx_y]=~out[width_minx_y]; + out[width_maxx_y]=~out[width_maxx_y]; + } + } else { /* normal image only (e.g. preview shot) */ + int width_miny = width*cent->miny; + int width_maxy = width*cent->maxy; + for (x=cent->minx; x<=cent->maxx; x++) { + int width_miny_x = width_miny+x; + int width_maxy_x = width_maxy+x; + new[width_miny_x]=~new[width_miny_x]; + new[width_maxy_x]=~new[width_maxy_x]; + } + + for (y=cent->miny; y<=cent->maxy; y++) { + int minx_y = cent->minx+y*width; + int maxx_y = cent->maxx+y*width; + new[minx_y]=~new[minx_y]; + new[maxx_y]=~new[maxx_y]; + } + } } @@ -196,62 +198,64 @@ void alg_draw_location(struct coord *cent, struct images *imgs, int width, unsig void alg_noise_tune(struct context *cnt, unsigned char *new) { - struct images *imgs=&cnt->imgs; - int i; - unsigned char *ref=imgs->ref; - int diff, sum=0, count=0; - unsigned char *mask=imgs->mask; - unsigned char *smartmask=imgs->smartmask_final; + struct images *imgs=&cnt->imgs; + int i; + unsigned char *ref=imgs->ref; + int diff, sum=0, count=0; + unsigned char *mask=imgs->mask; + unsigned char *smartmask=imgs->smartmask_final; - i=imgs->motionsize; - - for (; i>0; i--) { - diff = ABS(*ref - *new); - if (mask) - diff = ((diff * *mask++)/255); - if (*smartmask){ - sum += diff + 1; - count++; - } - ref++; - new++; - smartmask++; - } - if (count > 3) { /* avoid divide by zero */ - sum /= count / 3; - } - cnt->noise = 4 + (cnt->noise + sum) / 2; /* 5: safe, 4: regular, 3: more sensitive */ + i=imgs->motionsize; + + for (; i>0; i--) { + diff = ABS(*ref - *new); + if (mask) + diff = ((diff * *mask++)/255); + if (*smartmask){ + sum += diff + 1; + count++; + } + ref++; + new++; + smartmask++; + } + + if (count > 3) /* avoid divide by zero */ + sum /= count / 3; + + cnt->noise = 4 + (cnt->noise + sum) / 2; /* 5: safe, 4: regular, 3: more sensitive */ } void alg_threshold_tune(struct context *cnt, int diffs, int motion) { - int i; - int sum = 0, top = diffs; + int i; + int sum = 0, top = diffs; - if (!diffs) - return; + if (!diffs) + return; - if (motion) - diffs = cnt->threshold / 4; + if (motion) + diffs = cnt->threshold / 4; - for (i = 0; i < THRESHOLD_TUNE_LENGTH - 1; i++) - { - sum += cnt->diffs_last[i]; - if (cnt->diffs_last[i+1] && !motion) - cnt->diffs_last[i] = cnt->diffs_last[i+1]; - else - cnt->diffs_last[i] = cnt->threshold / 4; - if (cnt->diffs_last[i] > top) - top = cnt->diffs_last[i]; - } - sum += cnt->diffs_last[i]; - cnt->diffs_last[i] = diffs; + for (i = 0; i < THRESHOLD_TUNE_LENGTH - 1; i++) { + sum += cnt->diffs_last[i]; + if (cnt->diffs_last[i+1] && !motion) + cnt->diffs_last[i] = cnt->diffs_last[i+1]; + else + cnt->diffs_last[i] = cnt->threshold / 4; - sum /= THRESHOLD_TUNE_LENGTH / 4; - if (sum < top * 2) - sum = top * 2; - if (sum < cnt->conf.max_changes) - cnt->threshold = (cnt->threshold + sum) / 2; + if (cnt->diffs_last[i] > top) + top = cnt->diffs_last[i]; + } + sum += cnt->diffs_last[i]; + cnt->diffs_last[i] = diffs; + + sum /= THRESHOLD_TUNE_LENGTH / 4; + if (sum < top * 2) + sum = top * 2; + + if (sum < cnt->conf.max_changes) + cnt->threshold = (cnt->threshold + sum) / 2; } /* @@ -281,332 +285,335 @@ typedef struct {short y, xl, xr, dy;} Segment; static int iflood(int x, int y, int width, int height, unsigned char *out, int *labels, int newvalue, int oldvalue) { - int l, x1, x2, dy; - Segment stack[MAXS], *sp = stack; /* stack of filled segments */ - int count = 0; + int l, x1, x2, dy; + Segment stack[MAXS], *sp = stack; /* stack of filled segments */ + int count = 0; - if (x < 0 || x >= width || y < 0 || y >= height) - return 0; + if (x < 0 || x >= width || y < 0 || y >= height) + return 0; - PUSH(y, x, x, 1); /* needed in some cases */ - PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */ + PUSH(y, x, x, 1); /* needed in some cases */ + PUSH(y+1, x, x, -1); /* seed segment (popped 1st) */ - while (sp > stack) { - /* pop segment off stack and fill a neighboring scan line */ - POP(y, x1, x2, dy); - /* - * segment of scan line y-dy for x1<=x<=x2 was previously filled, - * now explore adjacent pixels in scan line y - */ - for (x = x1; x >= 0 && out[y*width+x] != 0 && labels[y*width+x] == oldvalue; x--) { - labels[y*width+x] = newvalue; - count++; - } - - if (x >= x1) - goto skip; - - l = x + 1; - - if (l < x1) - PUSH(y, l, x1-1, -dy); /* leak on left? */ - - x = x1 + 1; - - do { - for (; x < width && out[y*width+x] != 0 && labels[y*width+x]==oldvalue; x++) { - labels[y*width+x] = newvalue; - count++; - } - - PUSH(y, l, x-1, dy); - - if (x > x2+1) - PUSH(y, x2+1, x-1, -dy); /* leak on right? */ - - skip: - - for (x++; x <= x2 && !(out[y*width+x] != 0 && labels[y*width+x]==oldvalue); x++); - - l = x; - } while (x <= x2); - } - return count; + while (sp > stack) { + /* pop segment off stack and fill a neighboring scan line */ + POP(y, x1, x2, dy); + /* + * segment of scan line y-dy for x1<=x<=x2 was previously filled, + * now explore adjacent pixels in scan line y + */ + for (x = x1; x >= 0 && out[y*width+x] != 0 && labels[y*width+x] == oldvalue; x--) { + labels[y*width+x] = newvalue; + count++; + } + + if (x >= x1) + goto skip; + + l = x + 1; + + if (l < x1) + PUSH(y, l, x1-1, -dy); /* leak on left? */ + + x = x1 + 1; + + do { + for (; x < width && out[y * width + x] != 0 && labels[y * width + x] == oldvalue; x++) { + labels[y * width + x] = newvalue; + count++; + } + + PUSH(y, l, x - 1, dy); + + if (x > x2 + 1) + PUSH(y, x2 + 1, x - 1, -dy); /* leak on right? */ + + skip: + + for (x++; x <= x2 && !(out[y * width + x] != 0 && labels[y * width + x] == oldvalue); x++); + + l = x; + } while (x <= x2); + } + return count; } static int alg_labeling(struct context *cnt) { - struct images *imgs=&cnt->imgs; - unsigned char *out=imgs->out; - int *labels=imgs->labels; - int ix, iy, pixelpos; - int width=imgs->width; - int height=imgs->height; - int labelsize=0; - int current_label=2; - cnt->current_image->total_labels=0; - imgs->labelsize_max=0; - /* ALL labels above threshold are counted as labelgroup */ - imgs->labelgroup_max=0; - imgs->labels_above=0; + struct images *imgs=&cnt->imgs; + unsigned char *out=imgs->out; + int *labels=imgs->labels; + int ix, iy, pixelpos; + int width=imgs->width; + int height=imgs->height; + int labelsize=0; + int current_label=2; + cnt->current_image->total_labels=0; + imgs->labelsize_max=0; + /* ALL labels above threshold are counted as labelgroup */ + imgs->labelgroup_max=0; + imgs->labels_above=0; - /* init: 0 means no label set / not checked */ - memset(labels, 0, width*height*sizeof(labels)); - pixelpos = 0; - for( iy=0; iy 0) - continue; - labelsize=iflood(ix, iy, width, height, out, labels, current_label, 0); - - if( labelsize > 0 ) { - //printf( "Label: %i (%i) Size: %i (%i,%i)\n", current_label, cnt->current_image->total_labels, labelsize, ix, iy ); - /* Label above threshold? Mark it again (add 32768 to labelnumber) */ - if (labelsize > cnt->threshold){ - labelsize=iflood(ix, iy, width, height, out, labels, current_label+32768, current_label); - imgs->labelgroup_max+=labelsize; - imgs->labels_above++; - } - - if( imgs->labelsize_max < labelsize ){ - imgs->labelsize_max=labelsize; - imgs->largest_label=current_label; - } - - cnt->current_image->total_labels++; - current_label++; - } - } - pixelpos++; /* compensate for ixtotal_labels, imgs->labelsize_max, cnt->current_image->largest_label); - /* return group of significant labels */ - return imgs->labelgroup_max; + /* init: 0 means no label set / not checked */ + memset(labels, 0, width*height*sizeof(labels)); + pixelpos = 0; + for (iy = 0; iy < height - 1; iy++) { + for (ix = 0; ix < width - 1; ix++, pixelpos++) { + /* no motion - no label */ + if (out[pixelpos] == 0) { + labels[pixelpos] = 1; + continue; + } + + /* already visited by iflood */ + if (labels[pixelpos] > 0) + continue; + labelsize=iflood(ix, iy, width, height, out, labels, current_label, 0); + + if (labelsize > 0) { + //printf( "Label: %i (%i) Size: %i (%i,%i)\n", current_label, cnt->current_image->total_labels, labelsize, ix, iy ); + /* Label above threshold? Mark it again (add 32768 to labelnumber) */ + if (labelsize > cnt->threshold) { + labelsize=iflood(ix, iy, width, height, out, labels, current_label + 32768, current_label); + imgs->labelgroup_max+=labelsize; + imgs->labels_above++; + } + + if (imgs->labelsize_max < labelsize) { + imgs->labelsize_max=labelsize; + imgs->largest_label=current_label; + } + + cnt->current_image->total_labels++; + current_label++; + } + } + pixelpos++; /* compensate for ixtotal_labels, imgs->labelsize_max, cnt->current_image->largest_label); + /* return group of significant labels */ + return imgs->labelgroup_max; } /* Dilates a 3x3 box */ static int dilate9(unsigned char *img, int width, int height, void *buffer) { - /* - row1, row2 and row3 represent lines in the temporary buffer - * - window is a sliding window containing max values of the columns - * in the 3x3 matrix - * - widx is an index into the sliding window (this is faster than - * doing modulo 3 on i) - * - blob keeps the current max value - */ - int y, i, sum = 0, widx; - unsigned char *row1, *row2, *row3, *rowTemp,*yp; - unsigned char window[3], blob, latest; + /* - row1, row2 and row3 represent lines in the temporary buffer + * - window is a sliding window containing max values of the columns + * in the 3x3 matrix + * - widx is an index into the sliding window (this is faster than + * doing modulo 3 on i) + * - blob keeps the current max value + */ + int y, i, sum = 0, widx; + unsigned char *row1, *row2, *row3, *rowTemp,*yp; + unsigned char window[3], blob, latest; - /* Set up row pointers in the temporary buffer. */ - row1 = buffer; - row2 = row1 + width; - row3 = row2 + width; + /* Set up row pointers in the temporary buffer. */ + row1 = buffer; + row2 = row1 + width; + row3 = row2 + width; - /* Init rows 2 and 3. */ - memset(row2, 0, width); - memcpy(row3, img, width); + /* Init rows 2 and 3. */ + memset(row2, 0, width); + memcpy(row3, img, width); - /* Pointer to the current row in img. */ - yp = img; - - for (y = 0; y < height; y++) { - /* Move down one step; row 1 becomes the previous row 2 and so on. */ - rowTemp = row1; - row1 = row2; - row2 = row3; - row3 = rowTemp; + /* Pointer to the current row in img. */ + yp = img; + + for (y = 0; y < height; y++) { + /* Move down one step; row 1 becomes the previous row 2 and so on. */ + rowTemp = row1; + row1 = row2; + row2 = row3; + row3 = rowTemp; - /* If we're at the last row, fill with zeros, otherwise copy from img. */ - if(y == height - 1) - memset(row3, 0, width); - else - memcpy(row3, yp+width, width); - - /* Init slots 0 and 1 in the moving window. */ - window[0] = MAX3(row1[0], row2[0], row3[0]); - window[1] = MAX3(row1[1], row2[1], row3[1]); + /* If we're at the last row, fill with zeros, otherwise copy from img. */ + if (y == height - 1) + memset(row3, 0, width); + else + memcpy(row3, yp+width, width); + + /* Init slots 0 and 1 in the moving window. */ + window[0] = MAX3(row1[0], row2[0], row3[0]); + window[1] = MAX3(row1[1], row2[1], row3[1]); - /* Init blob to the current max, and set window index. */ - blob = MAX2(window[0], window[1]); - widx = 2; + /* Init blob to the current max, and set window index. */ + blob = MAX2(window[0], window[1]); + widx = 2; - /* Iterate over the current row; index i is off by one to eliminate - * a lot of +1es in the loop. - */ - for (i = 2; i <= width - 1; i++) { - /* Get the max value of the next column in the 3x3 matrix. */ - latest = window[widx] = MAX3(row1[i], row2[i], row3[i]); + /* Iterate over the current row; index i is off by one to eliminate + * a lot of +1es in the loop. + */ + for (i = 2; i <= width - 1; i++) { + /* Get the max value of the next column in the 3x3 matrix. */ + latest = window[widx] = MAX3(row1[i], row2[i], row3[i]); - /* If the value is larger than the current max, use it. Otherwise, - * calculate a new max (because the new value may not be the max. - */ - if(latest >= blob) - blob = latest; - else - blob = MAX3(window[0], window[1], window[2]); + /* If the value is larger than the current max, use it. Otherwise, + * calculate a new max (because the new value may not be the max. + */ + if (latest >= blob) + blob = latest; + else + blob = MAX3(window[0], window[1], window[2]); - /* Write the max value (blob) to the image. */ - if (blob != 0) { - *(yp + i - 1) = blob; - sum++; - } + /* Write the max value (blob) to the image. */ + if (blob != 0) { + *(yp + i - 1) = blob; + sum++; + } - /* Wrap around the window index if necessary. */ - if(++widx == 3) - widx = 0; - } + /* Wrap around the window index if necessary. */ + if (++widx == 3) + widx = 0; + } - /* Store zeros in the vertical sides. */ - *yp = *(yp + width - 1) = 0; - yp += width; - } - - return sum; + /* Store zeros in the vertical sides. */ + *yp = *(yp + width - 1) = 0; + yp += width; + } + + return sum; } /* Dilates a + shape */ static int dilate5(unsigned char *img, int width, int height, void *buffer) { - /* - row1, row2 and row3 represent lines in the temporary buffer - * - mem holds the max value of the overlapping part of two + shapes - */ - int y, i, sum = 0; - unsigned char *row1, *row2, *row3, *rowTemp, *yp; - unsigned char blob, mem, latest; - - /* Set up row pointers in the temporary buffer. */ - row1 = buffer; - row2 = row1 + width; - row3 = row2 + width; - - /* Init rows 2 and 3. */ - memset(row2, 0, width); - memcpy(row3, img, width); - - /* Pointer to the current row in img. */ - yp = img; + /* - row1, row2 and row3 represent lines in the temporary buffer + * - mem holds the max value of the overlapping part of two + shapes + */ + int y, i, sum = 0; + unsigned char *row1, *row2, *row3, *rowTemp, *yp; + unsigned char blob, mem, latest; + + /* Set up row pointers in the temporary buffer. */ + row1 = buffer; + row2 = row1 + width; + row3 = row2 + width; + + /* Init rows 2 and 3. */ + memset(row2, 0, width); + memcpy(row3, img, width); + + /* Pointer to the current row in img. */ + yp = img; - for (y = 0; y < height; y++) { - /* Move down one step; row 1 becomes the previous row 2 and so on. */ - rowTemp = row1; - row1 = row2; - row2 = row3; - row3 = rowTemp; - - /* If we're at the last row, fill with zeros, otherwise copy from img. */ - if (y == height - 1) - memset(row3, 0, width); - else - memcpy(row3, yp+width, width); + for (y = 0; y < height; y++) { + /* Move down one step; row 1 becomes the previous row 2 and so on. */ + rowTemp = row1; + row1 = row2; + row2 = row3; + row3 = rowTemp; + + /* If we're at the last row, fill with zeros, otherwise copy from img. */ + if (y == height - 1) + memset(row3, 0, width); + else + memcpy(row3, yp+width, width); - /* Init mem and set blob to force an evaluation of the entire + shape. */ - mem = MAX2(row2[0], row2[1]); - blob = 1; /* dummy value, must be > 0 */ - - for (i = 1; i < width - 1; i++) { - /* Get the max value of the "right edge" of the + shape. */ - latest = MAX3(row1[i], row2[i + 1], row3[i]); - - if (blob == 0) { - /* In case the last blob is zero, only latest matters. */ - blob = latest; - mem = row2[i + 1]; - } else { - /* Otherwise, we have to check both latest and mem. */ - blob = MAX2(mem, latest); - mem = MAX2(row2[i], row2[i+1]); - } + /* Init mem and set blob to force an evaluation of the entire + shape. */ + mem = MAX2(row2[0], row2[1]); + blob = 1; /* dummy value, must be > 0 */ + + for (i = 1; i < width - 1; i++) { + /* Get the max value of the "right edge" of the + shape. */ + latest = MAX3(row1[i], row2[i + 1], row3[i]); + + if (blob == 0) { + /* In case the last blob is zero, only latest matters. */ + blob = latest; + mem = row2[i + 1]; + } else { + /* Otherwise, we have to check both latest and mem. */ + blob = MAX2(mem, latest); + mem = MAX2(row2[i], row2[i + 1]); + } - /* Write the max value (blob) to the image. */ - if (blob != 0) { - *(yp + i) = blob; - sum++; - } - } + /* Write the max value (blob) to the image. */ + if (blob != 0) { + *(yp + i) = blob; + sum++; + } + } - /* Store zeros in the vertical sides. */ - *yp = *(yp + width - 1) = 0; - yp += width; - } - return sum; + /* Store zeros in the vertical sides. */ + *yp = *(yp + width - 1) = 0; + yp += width; + } + return sum; } /* Erodes a 3x3 box */ static int erode9(unsigned char *img, int width, int height, void *buffer, unsigned char flag) { - int y, i, sum = 0; - char *Row1,*Row2,*Row3; - Row1 = buffer; - Row2 = Row1 + width; - Row3 = Row1 + 2*width; - memset(Row2, flag, width); - memcpy(Row3, img, width); - for (y = 0; y < height; y++) { - memcpy(Row1, Row2, width); - memcpy(Row2, Row3, width); - if (y == height-1) - memset(Row3, flag, width); - else - memcpy(Row3, img+(y+1)*width, width); + int y, i, sum = 0; + char *Row1,*Row2,*Row3; + Row1 = buffer; + Row2 = Row1 + width; + Row3 = Row1 + 2*width; + memset(Row2, flag, width); + memcpy(Row3, img, width); + for (y = 0; y < height; y++) { + memcpy(Row1, Row2, width); + memcpy(Row2, Row3, width); + if (y == height - 1) + memset(Row3, flag, width); + else + memcpy(Row3, img+(y + 1) * width, width); - for (i = width-2; i >= 1; i--) { - if (Row1[i-1] == 0 || - Row1[i] == 0 || - Row1[i+1] == 0 || - Row2[i-1] == 0 || - Row2[i] == 0 || - Row2[i+1] == 0 || - Row3[i-1] == 0 || - Row3[i] == 0 || - Row3[i+1] == 0) - img[y*width+i] = 0; - else - sum++; - } - img[y*width] = img[y*width+width-1] = flag; - } - return sum; + for (i = width-2; i >= 1; i--) { + if (Row1[i-1] == 0 || + Row1[i] == 0 || + Row1[i+1] == 0 || + Row2[i-1] == 0 || + Row2[i] == 0 || + Row2[i+1] == 0 || + Row3[i-1] == 0 || + Row3[i] == 0 || + Row3[i+1] == 0) + img[y * width + i] = 0; + else + sum++; + } + img[y * width] = img[y * width + width - 1] = flag; + } + return sum; } /* Erodes in a + shape */ static int erode5(unsigned char *img, int width, int height, void *buffer, unsigned char flag) { - int y, i, sum = 0; - char *Row1,*Row2,*Row3; - Row1 = buffer; - Row2 = Row1 + width; - Row3 = Row1 + 2*width; - memset(Row2, flag, width); - memcpy(Row3, img, width); - for (y = 0; y < height; y++) { - memcpy(Row1, Row2, width); - memcpy(Row2, Row3, width); - if (y == height-1) - memset(Row3, flag, width); - else - memcpy(Row3, img+(y+1)*width, width); + int y, i, sum = 0; + char *Row1,*Row2,*Row3; + Row1 = buffer; + Row2 = Row1 + width; + Row3 = Row1 + 2 * width; + memset(Row2, flag, width); + memcpy(Row3, img, width); - for (i = width-2; i >= 1; i--) { - if (Row1[i] == 0 || - Row2[i-1] == 0 || - Row2[i] == 0 || - Row2[i+1] == 0 || - Row3[i] == 0) - img[y*width+i] = 0; - else - sum++; - } - img[y*width] = img[y*width+width-1] = flag; - } - return sum; + for (y = 0; y < height; y++) { + memcpy(Row1, Row2, width); + memcpy(Row2, Row3, width); + + if (y == height-1) + memset(Row3, flag, width); + else + memcpy(Row3, img + (y + 1) * width, width); + + for (i = width-2; i >= 1; i--) { + if (Row1[i] == 0 || + Row2[i-1] == 0 || + Row2[i] == 0 || + Row2[i+1] == 0 || + Row3[i] == 0) + img[y * width + i] = 0; + else + sum++; + } + + img[y * width] = img[y * width + width - 1] = flag; + } + return sum; } /* @@ -614,85 +621,87 @@ static int erode5(unsigned char *img, int width, int height, void *buffer, unsig */ int alg_despeckle(struct context *cnt, int olddiffs) { - int diffs = 0; - unsigned char *out = cnt->imgs.out; - int width = cnt->imgs.width; - int height= cnt->imgs.height; - int done = 0, i, len = strlen(cnt->conf.despeckle); - unsigned char *common_buffer = cnt->imgs.common_buffer; + int diffs = 0; + unsigned char *out = cnt->imgs.out; + int width = cnt->imgs.width; + int height= cnt->imgs.height; + int done = 0, i, len = strlen(cnt->conf.despeckle); + unsigned char *common_buffer = cnt->imgs.common_buffer; - for (i = 0; i < len; i++) { - switch (cnt->conf.despeckle[i]) { - case 'E': - if ((diffs = erode9(out, width, height, common_buffer, 0)) == 0) i=len; - done=1; - break; - case 'e': - if ((diffs = erode5(out, width, height, common_buffer, 0)) == 0) i=len; - done=1; - break; - case 'D': - diffs = dilate9(out, width, height, common_buffer); - done=1; - break; - case 'd': - diffs = dilate5(out, width, height, common_buffer); - done=1; - break; - /* no further despeckle after labeling! */ - case 'l': - diffs = alg_labeling(cnt); - i=len; - done=2; - break; - } - } + for (i = 0; i < len; i++) { + switch (cnt->conf.despeckle[i]) { + case 'E': + if ((diffs = erode9(out, width, height, common_buffer, 0)) == 0) + i = len; + done = 1; + break; + case 'e': + if ((diffs = erode5(out, width, height, common_buffer, 0)) == 0) + i = len; + done = 1; + break; + case 'D': + diffs = dilate9(out, width, height, common_buffer); + done = 1; + break; + case 'd': + diffs = dilate5(out, width, height, common_buffer); + done = 1; + break; + /* no further despeckle after labeling! */ + case 'l': + diffs = alg_labeling(cnt); + i = len; + done = 2; + break; + } + } - /* If conf.despeckle contains any valid action EeDdl */ - if (done){ - if (done != 2) cnt->imgs.labelsize_max = 0; // Disable Labeling - return diffs; - } - else - cnt->imgs.labelsize_max = 0; // Disable Labeling - - return olddiffs; + /* If conf.despeckle contains any valid action EeDdl */ + if (done){ + if (done != 2) cnt->imgs.labelsize_max = 0; // Disable Labeling + return diffs; + } else { + cnt->imgs.labelsize_max = 0; // Disable Labeling + } + + return olddiffs; } /* Generate actual smartmask. Calculate sensitivity based on motion */ void alg_tune_smartmask(struct context *cnt) { - int i, diff; - - int motionsize = cnt->imgs.motionsize; - unsigned char *smartmask = cnt->imgs.smartmask; - unsigned char *smartmask_final = cnt->imgs.smartmask_final; - int *smartmask_buffer = cnt->imgs.smartmask_buffer; - int sensitivity=cnt->lastrate*(11-cnt->smartmask_speed); + int i, diff; + + int motionsize = cnt->imgs.motionsize; + unsigned char *smartmask = cnt->imgs.smartmask; + unsigned char *smartmask_final = cnt->imgs.smartmask_final; + int *smartmask_buffer = cnt->imgs.smartmask_buffer; + int sensitivity=cnt->lastrate*(11-cnt->smartmask_speed); - for (i=0; i 0) - smartmask[i]--; - /* Increase smart_mask sensitivity based on the buffered values */ - diff = smartmask_buffer[i]/sensitivity; - if (diff){ - if (smartmask[i] <= diff+80) - smartmask[i]+=diff; - else - smartmask[i]=80; - smartmask_buffer[i]%=sensitivity; - } - /* Transfer raw mask to the final stage when above trigger value */ - if (smartmask[i]>20) - smartmask_final[i]=0; - else - smartmask_final[i]=255; - } - /* Further expansion (here:erode due to inverted logic!) of the mask */ - diff = erode9(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255); - diff = erode5(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255); + for (i = 0; i < motionsize; i++) { + + /* Decrease smart_mask sensitivity every 5*speed seconds only */ + if (smartmask[i] > 0) + smartmask[i]--; + /* Increase smart_mask sensitivity based on the buffered values */ + diff = smartmask_buffer[i]/sensitivity; + if (diff){ + if (smartmask[i] <= diff + 80) + smartmask[i] += diff; + else + smartmask[i]=80; + smartmask_buffer[i]%=sensitivity; + } + /* Transfer raw mask to the final stage when above trigger value */ + if (smartmask[i] > 20) + smartmask_final[i] = 0; + else + smartmask_final[i] = 255; + } + /* Further expansion (here:erode due to inverted logic!) of the mask */ + diff = erode9(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255); + diff = erode5(smartmask_final, cnt->imgs.width, cnt->imgs.height, cnt->imgs.common_buffer, 255); } /* Increment for *smartmask_buffer in alg_diff_standard. */ @@ -700,285 +709,284 @@ void alg_tune_smartmask(struct context *cnt) int alg_diff_standard (struct context *cnt, unsigned char *new) { - struct images *imgs=&cnt->imgs; - int i, diffs=0; - int noise=cnt->noise; - int smartmask_speed=cnt->smartmask_speed; - unsigned char *ref=imgs->ref; - unsigned char *out=imgs->out; - unsigned char *mask=imgs->mask; - unsigned char *smartmask_final=imgs->smartmask_final; - int *smartmask_buffer=imgs->smartmask_buffer; + struct images *imgs = &cnt->imgs; + int i, diffs = 0; + int noise = cnt->noise; + int smartmask_speed = cnt->smartmask_speed; + unsigned char *ref = imgs->ref; + unsigned char *out = imgs->out; + unsigned char *mask = imgs->mask; + unsigned char *smartmask_final=imgs->smartmask_final; + int *smartmask_buffer = imgs->smartmask_buffer; #ifdef HAVE_MMX - mmx_t mmtemp; /* used for transferring to/from memory */ - int unload; /* counter for unloading diff counts */ + mmx_t mmtemp; /* used for transferring to/from memory */ + int unload; /* counter for unloading diff counts */ #endif - i=imgs->motionsize; - memset(out+i, 128, i/2); /* motion pictures are now b/w i.o. green */ - /* Keeping this memset in the MMX case when zeroes are necessarily - * written anyway seems to be beneficial in terms of speed. Perhaps a - * cache thing? - */ - memset(out, 0, i); + i = imgs->motionsize; + memset(out + i, 128, i / 2); /* motion pictures are now b/w i.o. green */ + /* Keeping this memset in the MMX case when zeroes are necessarily + * written anyway seems to be beneficial in terms of speed. Perhaps a + * cache thing? + */ + memset(out, 0, i); #ifdef HAVE_MMX - /* NOTE: The Pentium has two instruction pipes: U and V. I have grouped MMX - * instructions in pairs according to how I think they will be scheduled in - * the U and V pipes. Due to pairing constraints, the V pipe will sometimes - * be empty (for example, memory access always goes into the U pipe). - * - * The following MMX registers are kept throughout the loop: - * mm5 - 8 separate diff counters (unloaded periodically) - * mm6 - mask: 00ff 00ff 00ff 00ff - * mm7 - noise level as 8 packed bytes - * - * -- Per Jonsson - */ + /* NOTE: The Pentium has two instruction pipes: U and V. I have grouped MMX + * instructions in pairs according to how I think they will be scheduled in + * the U and V pipes. Due to pairing constraints, the V pipe will sometimes + * be empty (for example, memory access always goes into the U pipe). + * + * The following MMX registers are kept throughout the loop: + * mm5 - 8 separate diff counters (unloaded periodically) + * mm6 - mask: 00ff 00ff 00ff 00ff + * mm7 - noise level as 8 packed bytes + * + * -- Per Jonsson + */ - /* To avoid a div, we work with differences multiplied by 255 in the - * default case and *mask otherwise. Thus, the limit to compare with is - * 255*(noise+1)-1). - */ - mmtemp.uw[0] = mmtemp.uw[1] = mmtemp.uw[2] = mmtemp.uw[3] = - (unsigned short)(noise * 255 + 254); - - /* Reset mm5 to zero, set the mm6 mask, and store the multiplied noise - * level as four words in mm7. - */ - movq_m2r(mmtemp, mm7); /* U */ - pcmpeqb_r2r(mm6, mm6); /* V */ - - pxor_r2r(mm5, mm5); /* U */ - psrlw_i2r(8, mm6); /* V */ + /* To avoid a div, we work with differences multiplied by 255 in the + * default case and *mask otherwise. Thus, the limit to compare with is + * 255*(noise+1)-1). + */ + mmtemp.uw[0] = mmtemp.uw[1] = mmtemp.uw[2] = mmtemp.uw[3] = (unsigned short)(noise * 255 + 254); + + /* Reset mm5 to zero, set the mm6 mask, and store the multiplied noise + * level as four words in mm7. + */ + movq_m2r(mmtemp, mm7); /* U */ + pcmpeqb_r2r(mm6, mm6); /* V */ + + pxor_r2r(mm5, mm5); /* U */ + psrlw_i2r(8, mm6); /* V */ - /* We must unload mm5 every 255th round, because the diffs accumulate - * in each packed byte, which can hold at most 255 diffs before it - * gets saturated. - */ - unload=255; - - for (; i>7; i-=8) { - /* Calculate abs(*ref-*new) for 8 pixels in parallel. */ - movq_m2r(*ref, mm0); /* U: mm0 = r7 r6 r5 r4 r3 r2 r1 r0 */ - pxor_r2r(mm4, mm4); /* V: mm4 = 0 */ + /* We must unload mm5 every 255th round, because the diffs accumulate + * in each packed byte, which can hold at most 255 diffs before it + * gets saturated. + */ + unload = 255; + + for (; i > 7; i -= 8) { + /* Calculate abs(*ref-*new) for 8 pixels in parallel. */ + movq_m2r(*ref, mm0); /* U: mm0 = r7 r6 r5 r4 r3 r2 r1 r0 */ + pxor_r2r(mm4, mm4); /* V: mm4 = 0 */ - movq_m2r(*new, mm1); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ - movq_r2r(mm0, mm2); /* V: mm2 = r7 r6 r5 r4 r3 r2 r1 r0 */ + movq_m2r(*new, mm1); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ + movq_r2r(mm0, mm2); /* V: mm2 = r7 r6 r5 r4 r3 r2 r1 r0 */ - /* These subtractions are saturated, i.e. won't go below 0. */ - psubusb_r2r(mm1, mm0); /* U: mm0 = (r7-n7) ... (r0-n0) */ - psubusb_r2r(mm2, mm1); /* V: mm1 = (n7-r7) ... (n0-r0) */ - - /* Each byte dX in mm0 is abs(nX-rX). */ - por_r2r(mm1, mm0); /* U: mm0 = d7 d6 d5 d4 d3 d2 d1 d0 */ + /* These subtractions are saturated, i.e. won't go below 0. */ + psubusb_r2r(mm1, mm0); /* U: mm0 = (r7-n7) ... (r0-n0) */ + psubusb_r2r(mm2, mm1); /* V: mm1 = (n7-r7) ... (n0-r0) */ + + /* Each byte dX in mm0 is abs(nX-rX). */ + por_r2r(mm1, mm0); /* U: mm0 = d7 d6 d5 d4 d3 d2 d1 d0 */ - /* Expand the absolute differences to words in mm0 and mm1. */ - movq_r2r(mm0, mm1); /* U: mm1 = d7 d6 d5 d4 d3 d2 d1 d0 */ - punpcklbw_r2r(mm4, mm0); /* V: mm0 = d3 d2 d1 d0 */ - - punpckhbw_r2r(mm4, mm1); /* U: mm1 = d7 d6 d5 d4 */ + /* Expand the absolute differences to words in mm0 and mm1. */ + movq_r2r(mm0, mm1); /* U: mm1 = d7 d6 d5 d4 d3 d2 d1 d0 */ + punpcklbw_r2r(mm4, mm0); /* V: mm0 = d3 d2 d1 d0 */ + + punpckhbw_r2r(mm4, mm1); /* U: mm1 = d7 d6 d5 d4 */ - if (mask) { - /* Load and expand 8 mask bytes to words in mm2 and mm3. Then - * multiply by mm0 and mm1, respectively. - */ - movq_m2r(*mask, mm2); /* U: mm2 = m7 m6 m5 m4 m3 m2 m1 m0 */ + if (mask) { + /* Load and expand 8 mask bytes to words in mm2 and mm3. Then + * multiply by mm0 and mm1, respectively. + */ + movq_m2r(*mask, mm2); /* U: mm2 = m7 m6 m5 m4 m3 m2 m1 m0 */ - movq_r2r(mm2, mm3); /* U: mm3 = m7 m6 m5 m4 m3 m2 m1 m0 */ - punpcklbw_r2r(mm4, mm2); /* v: mm2 = m3 m2 m1 m0 */ - - punpckhbw_r2r(mm4, mm3); /* U: mm3 = m7 m6 m5 m4 */ - pmullw_r2r(mm2, mm0); /* V: mm0 = (d3*m3) ... (d0*m0) */ - - pmullw_r2r(mm3, mm1); /* U: mm1 = (d7*m7) ... (d4*m4) */ + movq_r2r(mm2, mm3); /* U: mm3 = m7 m6 m5 m4 m3 m2 m1 m0 */ + punpcklbw_r2r(mm4, mm2); /* v: mm2 = m3 m2 m1 m0 */ + + punpckhbw_r2r(mm4, mm3); /* U: mm3 = m7 m6 m5 m4 */ + pmullw_r2r(mm2, mm0); /* V: mm0 = (d3*m3) ... (d0*m0) */ + + pmullw_r2r(mm3, mm1); /* U: mm1 = (d7*m7) ... (d4*m4) */ - mask+=8; - } - else { - /* Not using mask - multiply the absolute differences by 255. We - * do this by left-shifting 8 places and then subtracting dX. - */ - movq_r2r(mm0, mm2); /* U: mm2 = d3 d2 d1 d0 */ - psllw_i2r(8, mm0); /* V: mm2 = (256*d3) ... (256*d0) */ + mask+=8; + } else { + /* Not using mask - multiply the absolute differences by 255. We + * do this by left-shifting 8 places and then subtracting dX. + */ + movq_r2r(mm0, mm2); /* U: mm2 = d3 d2 d1 d0 */ + psllw_i2r(8, mm0); /* V: mm2 = (256*d3) ... (256*d0) */ - movq_r2r(mm1, mm3); /* U: mm3 = d7 d6 d5 d4 */ - psllw_i2r(8, mm1); /* V: mm3 = (256*d7) ... (256*d4) */ + movq_r2r(mm1, mm3); /* U: mm3 = d7 d6 d5 d4 */ + psllw_i2r(8, mm1); /* V: mm3 = (256*d7) ... (256*d4) */ - psubusw_r2r(mm2, mm0); /* U */ - psubusw_r2r(mm3, mm1); /* V */ - } + psubusw_r2r(mm2, mm0); /* U */ + psubusw_r2r(mm3, mm1); /* V */ + } - /* Next, compare the multiplied absolute differences with the multiplied - * noise level (repeated as 4 words in mm7), resulting in a "motion flag" - * for each pixel. - * - * Since pcmpgtw performs signed comparisons, we have to subtract noise, - * test for equality to 0 and then invert the result. - * - * Note that it is safe to generate the "motion flags" before the - * smartmask code, as all that can happen is that individual flags get - * reset to 0 because of the smartmask. - */ - psubusw_r2r(mm7, mm0); /* U: subtract by (multiplied) noise */ - psubusw_r2r(mm7, mm1); /* V */ + /* Next, compare the multiplied absolute differences with the multiplied + * noise level (repeated as 4 words in mm7), resulting in a "motion flag" + * for each pixel. + * + * Since pcmpgtw performs signed comparisons, we have to subtract noise, + * test for equality to 0 and then invert the result. + * + * Note that it is safe to generate the "motion flags" before the + * smartmask code, as all that can happen is that individual flags get + * reset to 0 because of the smartmask. + */ + psubusw_r2r(mm7, mm0); /* U: subtract by (multiplied) noise */ + psubusw_r2r(mm7, mm1); /* V */ - pcmpeqw_r2r(mm4, mm0); /* U: test for equality with 0 */ - pcmpeqw_r2r(mm4, mm1); /* V */ + pcmpeqw_r2r(mm4, mm0); /* U: test for equality with 0 */ + pcmpeqw_r2r(mm4, mm1); /* V */ - pand_r2r(mm6, mm0); /* U: convert 0xffff -> 0x00ff */ - pand_r2r(mm6, mm1); /* V */ + pand_r2r(mm6, mm0); /* U: convert 0xffff -> 0x00ff */ + pand_r2r(mm6, mm1); /* V */ - pxor_r2r(mm6, mm0); /* U: invert the result */ - pxor_r2r(mm6, mm1); /* V */ + pxor_r2r(mm6, mm0); /* U: invert the result */ + pxor_r2r(mm6, mm1); /* V */ - /* Each fX is the "motion flag" = 0 for no motion, 0xff for motion. */ - packuswb_r2r(mm1, mm0); /* U: mm0 = f7 f6 f5 f4 f3 f2 f1 f0 */ + /* Each fX is the "motion flag" = 0 for no motion, 0xff for motion. */ + packuswb_r2r(mm1, mm0); /* U: mm0 = f7 f6 f5 f4 f3 f2 f1 f0 */ - if (smartmask_speed) { - /* Apply the smartmask. Basically, if *smartmask_final is 0, the - * corresponding "motion flag" in mm0 will be reset. - */ - movq_m2r(*smartmask_final, mm3); /* U: mm3 = s7 s6 s5 s4 s3 s2 s1 s0 */ + if (smartmask_speed) { + /* Apply the smartmask. Basically, if *smartmask_final is 0, the + * corresponding "motion flag" in mm0 will be reset. + */ + movq_m2r(*smartmask_final, mm3); /* U: mm3 = s7 s6 s5 s4 s3 s2 s1 s0 */ - /* ...but move the "motion flags" to memory before, in order to - * increment *smartmask_buffer properly below. - */ - movq_r2m(mm0, mmtemp); /* U */ - pcmpeqb_r2r(mm4, mm3); /* V: mm3 = 0xff where sX==0 */ + /* ...but move the "motion flags" to memory before, in order to + * increment *smartmask_buffer properly below. + */ + movq_r2m(mm0, mmtemp); /* U */ + pcmpeqb_r2r(mm4, mm3); /* V: mm3 = 0xff where sX==0 */ - /* ANDN negates the target before anding. */ - pandn_r2r(mm0, mm3); /* U: mm3 = 0xff where dX>noise && sX>0 */ + /* ANDN negates the target before anding. */ + pandn_r2r(mm0, mm3); /* U: mm3 = 0xff where dX>noise && sX>0 */ - movq_r2r(mm3, mm0); /* U */ + movq_r2r(mm3, mm0); /* U */ - /* Add to *smartmask_buffer. This is probably the fastest way to do it. */ - if (cnt->event_nr != cnt->prev_event) { - if (mmtemp.ub[0]) smartmask_buffer[0]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[1]) smartmask_buffer[1]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[2]) smartmask_buffer[2]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[3]) smartmask_buffer[3]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[4]) smartmask_buffer[4]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[5]) smartmask_buffer[5]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[6]) smartmask_buffer[6]+=SMARTMASK_SENSITIVITY_INCR; - if (mmtemp.ub[7]) smartmask_buffer[7]+=SMARTMASK_SENSITIVITY_INCR; - } + /* Add to *smartmask_buffer. This is probably the fastest way to do it. */ + if (cnt->event_nr != cnt->prev_event) { + if (mmtemp.ub[0]) smartmask_buffer[0]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[1]) smartmask_buffer[1]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[2]) smartmask_buffer[2]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[3]) smartmask_buffer[3]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[4]) smartmask_buffer[4]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[5]) smartmask_buffer[5]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[6]) smartmask_buffer[6]+=SMARTMASK_SENSITIVITY_INCR; + if (mmtemp.ub[7]) smartmask_buffer[7]+=SMARTMASK_SENSITIVITY_INCR; + } - smartmask_buffer+=8; - smartmask_final+=8; - } + smartmask_buffer += 8; + smartmask_final += 8; + } - movq_m2r(*new, mm2); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ + movq_m2r(*new, mm2); /* U: mm1 = n7 n6 n5 n4 n3 n2 n1 n0 */ - /* Cancel out pixels in *new according to the "motion flags" in mm0. - * Each NX is either 0 or nX as from *new. - */ - pand_r2r(mm0, mm2); /* U: mm1 = N7 N6 N5 N4 N3 N2 N1 N0 */ - psubb_r2r(mm0, mm4); /* V: mm4 = 0x01 where dX>noise */ + /* Cancel out pixels in *new according to the "motion flags" in mm0. + * Each NX is either 0 or nX as from *new. + */ + pand_r2r(mm0, mm2); /* U: mm1 = N7 N6 N5 N4 N3 N2 N1 N0 */ + psubb_r2r(mm0, mm4); /* V: mm4 = 0x01 where dX>noise */ - /* mm5 holds 8 separate counts - each one is increased according to - * the contents of mm4 (where each byte is either 0x00 or 0x01). - */ - movq_r2m(mm2, *out); /* U: this will stall */ - paddusb_r2r(mm4, mm5); /* V: add counts to mm5 */ - - /* Every 255th turn, we need to unload mm5 into the diffs variable, - * because otherwise the packed bytes will get saturated. - */ - if (--unload==0) { - /* Unload mm5 to memory and reset it. */ - movq_r2m(mm5, mmtemp); /* U */ - pxor_r2r(mm5, mm5); /* V: mm5 = 0 */ + /* mm5 holds 8 separate counts - each one is increased according to + * the contents of mm4 (where each byte is either 0x00 or 0x01). + */ + movq_r2m(mm2, *out); /* U: this will stall */ + paddusb_r2r(mm4, mm5); /* V: add counts to mm5 */ + + /* Every 255th turn, we need to unload mm5 into the diffs variable, + * because otherwise the packed bytes will get saturated. + */ + if (--unload == 0) { + /* Unload mm5 to memory and reset it. */ + movq_r2m(mm5, mmtemp); /* U */ + pxor_r2r(mm5, mm5); /* V: mm5 = 0 */ - diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + - mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; - unload=255; - } + diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + + mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; + unload = 255; + } - out+=8; - ref+=8; - new+=8; - } + out+=8; + ref+=8; + new+=8; + } - /* Check if there are diffs left in mm5 that need to be copied to the - * diffs variable. - */ - if (unload<255) { - movq_r2m(mm5, mmtemp); - diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + - mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; - } + /* Check if there are diffs left in mm5 that need to be copied to the + * diffs variable. + */ + if (unload < 255) { + movq_r2m(mm5, mmtemp); + diffs += mmtemp.ub[0] + mmtemp.ub[1] + mmtemp.ub[2] + mmtemp.ub[3] + + mmtemp.ub[4] + mmtemp.ub[5] + mmtemp.ub[6] + mmtemp.ub[7]; + } - emms(); + emms(); #endif - /* Note that the non-MMX code is present even if the MMX code is present. - * This is necessary if the resolution is not a multiple of 8, in which - * case the non-MMX code needs to take care of the remaining pixels. - */ + /* Note that the non-MMX code is present even if the MMX code is present. + * This is necessary if the resolution is not a multiple of 8, in which + * case the non-MMX code needs to take care of the remaining pixels. + */ - for (; i>0; i--) { - register unsigned char curdiff=(int)(abs(*ref - *new)); /* using a temp variable is 12% faster */ - /* apply fixed mask */ - if (mask) - curdiff=((int)(curdiff * *mask++)/255); - - if (smartmask_speed) { - if (curdiff > noise) { - /* increase smart_mask sensitivity every frame when motion - is detected. (with speed=5, mask is increased by 1 every - second. To be able to increase by 5 every second (with - speed=10) we add 5 here. NOT related to the 5 at ratio- - calculation. */ - if (cnt->event_nr != cnt->prev_event) - (*smartmask_buffer) += SMARTMASK_SENSITIVITY_INCR; - /* apply smart_mask */ - if (!*smartmask_final) - curdiff=0; - } - smartmask_final++; - smartmask_buffer++; - } - /* Pixel still in motion after all the masks? */ - if (curdiff > noise) { - *out=*new; - diffs++; - } - out++; - ref++; - new++; - } - return diffs; + for (; i>0; i--) { + register unsigned char curdiff=(int)(abs(*ref - *new)); /* using a temp variable is 12% faster */ + /* apply fixed mask */ + if (mask) + curdiff=((int)(curdiff * *mask++)/255); + + if (smartmask_speed) { + if (curdiff > noise) { + /* increase smart_mask sensitivity every frame when motion + is detected. (with speed=5, mask is increased by 1 every + second. To be able to increase by 5 every second (with + speed=10) we add 5 here. NOT related to the 5 at ratio- + calculation. */ + if (cnt->event_nr != cnt->prev_event) + (*smartmask_buffer) += SMARTMASK_SENSITIVITY_INCR; + /* apply smart_mask */ + if (!*smartmask_final) + curdiff = 0; + } + smartmask_final++; + smartmask_buffer++; + } + /* Pixel still in motion after all the masks? */ + if (curdiff > noise) { + *out = *new; + diffs++; + } + out++; + ref++; + new++; + } + return diffs; } /* - Very fast diff function, does not apply mask overlaying. + Very fast diff function, does not apply mask overlaying. */ static char alg_diff_fast(struct context *cnt, int max_n_changes, unsigned char *new) { - struct images *imgs=&cnt->imgs; - int i, diffs=0, step=imgs->motionsize/10000; - int noise=cnt->noise; - unsigned char *ref=imgs->ref; + struct images *imgs = &cnt->imgs; + int i, diffs = 0, step=imgs->motionsize / 10000; + int noise=cnt->noise; + unsigned char *ref = imgs->ref; - if (!step%2) - step++; - /* we're checking only 1 of several pixels */ - max_n_changes /= step; + if (!step % 2) + step++; + /* we're checking only 1 of several pixels */ + max_n_changes /= step; - i=imgs->motionsize; - for (; i>0; i-=step) { - register unsigned char curdiff=(int)(abs((char)(*ref-*new))); /* using a temp variable is 12% faster */ - if (curdiff > noise) { - diffs++; - if (diffs > max_n_changes) - return 1; - } - ref+=step; - new+=step; - } + i = imgs->motionsize; - return 0; + for (; i > 0; i -= step) { + register unsigned char curdiff = (int)(abs((char)(*ref-*new))); /* using a temp variable is 12% faster */ + if (curdiff > noise) { + diffs++; + if (diffs > max_n_changes) + return 1; + } + ref += step; + new += step; + } + + return 0; } /* alg_diff uses diff_fast to quickly decide if there is anything worth @@ -986,12 +994,12 @@ static char alg_diff_fast(struct context *cnt, int max_n_changes, unsigned char */ int alg_diff(struct context *cnt, unsigned char *new) { - int diffs=0; - - if (alg_diff_fast(cnt, cnt->conf.max_changes/2, new)) - diffs=alg_diff_standard(cnt, new); + int diffs = 0; + + if (alg_diff_fast(cnt, cnt->conf.max_changes / 2, new)) + diffs=alg_diff_standard(cnt, new); - return diffs; + return diffs; } /* Detect a sudden massive change in the picture. @@ -1000,52 +1008,53 @@ int alg_diff(struct context *cnt, unsigned char *new) */ int alg_lightswitch(struct context *cnt, int diffs) { - struct images *imgs=&cnt->imgs; - - if (cnt->conf.lightswitch < 0) - cnt->conf.lightswitch = 0; - if (cnt->conf.lightswitch > 100) - cnt->conf.lightswitch = 100; - - /* is lightswitch percent of the image changed? */ - if (diffs > (imgs->motionsize * cnt->conf.lightswitch / 100)) - return 1; - - return 0; + struct images *imgs = &cnt->imgs; + + if (cnt->conf.lightswitch < 0) + cnt->conf.lightswitch = 0; + if (cnt->conf.lightswitch > 100) + cnt->conf.lightswitch = 100; + + /* is lightswitch percent of the image changed? */ + if (diffs > (imgs->motionsize * cnt->conf.lightswitch / 100)) + return 1; + + return 0; } int alg_switchfilter(struct context *cnt, int diffs, unsigned char *newimg) { - int linediff = diffs / cnt->imgs.height; - unsigned char *out = cnt->imgs.out; - int y, x, line; - int lines=0, vertlines=0; + int linediff = diffs / cnt->imgs.height; + unsigned char *out = cnt->imgs.out; + int y, x, line; + int lines = 0, vertlines = 0; - for (y=0; y < cnt->imgs.height; y++) { - line=0; - for (x=0; x < cnt->imgs.width; x++) { - if (*(out++)) { - line++; - } - } - if (line > cnt->imgs.width/18) { - vertlines++; - } - if (line > linediff*2) { - lines++; - } - } + for (y = 0; y < cnt->imgs.height; y++) { + line = 0; + for (x = 0; x < cnt->imgs.width; x++) { + if (*(out++)) { + line++; + } + } - if (vertlines > cnt->imgs.height/10 && lines < vertlines/3 && - (vertlines > cnt->imgs.height/4 || lines - vertlines > lines/2)) { - if (cnt->conf.text_changes) { - char tmp[80]; - sprintf(tmp, "%d %d", lines, vertlines); - draw_text(newimg, cnt->imgs.width-10, 20, cnt->imgs.width, tmp, cnt->conf.text_double); - } - return diffs; - } - return 0; + if (line > cnt->imgs.width / 18) + vertlines++; + + if (line > linediff * 2) + lines++; + + } + + if (vertlines > cnt->imgs.height / 10 && lines < vertlines / 3 && + (vertlines > cnt->imgs.height / 4 || lines - vertlines > lines / 2)) { + if (cnt->conf.text_changes) { + char tmp[80]; + sprintf(tmp, "%d %d", lines, vertlines); + draw_text(newimg, cnt->imgs.width-10, 20, cnt->imgs.width, tmp, cnt->conf.text_double); + } + return diffs; + } + return 0; } /** @@ -1066,48 +1075,46 @@ int alg_switchfilter(struct context *cnt, int diffs, unsigned char *newimg) #define EXCLUDE_LEVEL_PERCENT 20 void alg_update_reference_frame(struct context *cnt, int action) { - int accept_timer = cnt->lastrate * ACCEPT_STATIC_OBJECT_TIME; - int i, threshold_ref; - int *ref_dyn = cnt->imgs.ref_dyn; - unsigned char *image_virgin = cnt->imgs.image_virgin; - unsigned char *ref = cnt->imgs.ref; - unsigned char *smartmask = cnt->imgs.smartmask_final; - unsigned char *out = cnt->imgs.out; + int accept_timer = cnt->lastrate * ACCEPT_STATIC_OBJECT_TIME; + int i, threshold_ref; + int *ref_dyn = cnt->imgs.ref_dyn; + unsigned char *image_virgin = cnt->imgs.image_virgin; + unsigned char *ref = cnt->imgs.ref; + unsigned char *smartmask = cnt->imgs.smartmask_final; + unsigned char *out = cnt->imgs.out; - if (cnt->lastrate > 5) /* match rate limit */ - accept_timer /= (cnt->lastrate / 3); + if (cnt->lastrate > 5) /* match rate limit */ + accept_timer /= (cnt->lastrate / 3); - if (action == UPDATE_REF_FRAME) { /* black&white only for better performance */ - threshold_ref = cnt->noise * EXCLUDE_LEVEL_PERCENT / 100; - for (i = cnt->imgs.motionsize; i > 0; i--) { - /* exclude pixels from ref frame well below noise level */ - if (((int)(abs(*ref - *image_virgin)) > threshold_ref) && (*smartmask)) { - if (*ref_dyn == 0) { /* Always give new pixels a chance */ - *ref_dyn = 1; - } - else if (*ref_dyn > accept_timer) { /* Include static Object after some time */ - *ref_dyn = 0; - *ref = *image_virgin; - } - else if (*out) - (*ref_dyn)++; /* Motionpixel? Keep excluding from ref frame */ - else { - *ref_dyn = 0; /* Nothing special - release pixel */ - *ref = (*ref + *image_virgin) / 2; - } - } - else { /* No motion: copy to ref frame */ - *ref_dyn = 0; /* reset pixel */ - *ref = *image_virgin; - } - ref++; - image_virgin++; - smartmask++; - ref_dyn++; - out++; - } /* end for i */ - } else { /* action == RESET_REF_FRAME - also used to initialize the frame at startup */ - memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); /* copy fresh image */ - memset(cnt->imgs.ref_dyn, 0, cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); /* reset static objects */ - } + if (action == UPDATE_REF_FRAME) { /* black&white only for better performance */ + threshold_ref = cnt->noise * EXCLUDE_LEVEL_PERCENT / 100; + for (i = cnt->imgs.motionsize; i > 0; i--) { + /* exclude pixels from ref frame well below noise level */ + if (((int)(abs(*ref - *image_virgin)) > threshold_ref) && (*smartmask)) { + if (*ref_dyn == 0) { /* Always give new pixels a chance */ + *ref_dyn = 1; + } else if (*ref_dyn > accept_timer) { /* Include static Object after some time */ + *ref_dyn = 0; + *ref = *image_virgin; + } else if (*out) { + (*ref_dyn)++; /* Motionpixel? Keep excluding from ref frame */ + } else { + *ref_dyn = 0; /* Nothing special - release pixel */ + *ref = (*ref + *image_virgin) / 2; + } + + } else { /* No motion: copy to ref frame */ + *ref_dyn = 0; /* reset pixel */ + *ref = *image_virgin; + } + ref++; + image_virgin++; + smartmask++; + ref_dyn++; + out++; + } /* end for i */ + } else { /* action == RESET_REF_FRAME - also used to initialize the frame at startup */ + memcpy(cnt->imgs.ref, cnt->imgs.image_virgin, cnt->imgs.size); /* copy fresh image */ + memset(cnt->imgs.ref_dyn, 0, cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); /* reset static objects */ + } } diff --git a/draw.c b/draw.c index 9bc6ba35..cf96c7a2 100644 --- a/draw.c +++ b/draw.c @@ -1,11 +1,11 @@ /* - * draw.c + * draw.c * - * Routines for drawing text on images + * Routines for drawing text on images * - * Copyright 2000, Jeroen Vreeken - * This program is published under the GNU public license version 2 - * See also the file 'COPYING' + * Copyright 2000, Jeroen Vreeken + * This program is published under the GNU public license version 2 + * See also the file 'COPYING' * */ @@ -20,1056 +20,1056 @@ unsigned char *small_char_arr_ptr[ASCII_MAX]; unsigned char *big_char_arr_ptr[ASCII_MAX]; struct draw_char { - unsigned char ascii; - unsigned char pix[8][7]; + unsigned char ascii; + unsigned char pix[8][7]; }; struct big_char { - unsigned char ascii; - unsigned char pix[16][14]; + unsigned char ascii; + unsigned char pix[16][14]; }; struct draw_char draw_table[]= { - { - ' ', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '0', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,2,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,2,1,2,1}, - {1,2,2,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '1', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '2', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {0,1,1,2,2,1,0}, - {0,1,2,1,1,0,0}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,1,1,0} - } - }, - { - '3', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {0,1,1,2,2,1,0}, - {0,1,0,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '4', - { - {0,0,0,0,1,0,0}, - {0,0,0,1,2,1,0}, - {0,0,1,2,2,1,0}, - {0,1,2,1,2,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,2,1,0}, - {0,0,0,1,2,1,0}, - {0,0,0,0,1,0,0} - } - }, - { - '5', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,2,0}, - {0,1,1,1,1,2,0}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - '6', - { - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '7', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,1,2,1}, - {0,0,0,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,0,0,0}, - {0,1,2,1,0,0,0}, - {0,0,1,0,0,0,0} - } - }, - { - '8', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '9', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,1,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '"', - { - {0,0,1,0,1,0,0}, - {0,1,2,1,2,1,0}, - {0,1,2,1,2,1,0}, - {0,0,1,0,1,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '/', - { - {0,0,0,0,1,0,0}, - {0,0,0,1,2,1,0}, - {0,0,0,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,0,0,0}, - {0,1,2,1,0,0,0}, - {0,0,1,0,0,0,0} - } - }, - { - '(', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,0,0,0}, - {0,1,2,1,0,0,0}, - {0,1,2,1,0,0,0}, - {0,1,2,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - ')', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,2,1,0}, - {0,0,0,1,2,1,0}, - {0,0,0,1,2,1,0}, - {0,0,0,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - '@', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,2,2,2,1}, - {1,2,1,2,2,2,1}, - {1,2,1,1,1,1,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - '~', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,0,0,0,0}, - {0,1,2,1,0,1,0}, - {1,2,1,2,1,2,1}, - {0,1,0,1,2,1,0}, - {0,0,0,0,1,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '#', - { - {0,0,1,0,1,0,0}, - {0,1,2,1,2,1,0}, - {1,2,2,2,2,2,1}, - {0,1,2,1,2,1,0}, - {0,1,2,1,2,1,0}, - {1,2,2,2,2,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,0,1,0,0} - } - }, - { - '<', - { - {0,0,0,0,0,1,0}, - {0,0,0,1,1,2,1}, - {0,1,1,2,2,1,0}, - {1,2,2,1,1,0,0}, - {0,1,1,2,2,1,0}, - {0,0,0,1,1,2,1}, - {0,0,0,0,0,1,0}, - {0,0,0,0,0,0,0} - } - }, - { - '>', - { - {0,1,0,0,0,0,0}, - {1,2,1,1,0,0,0}, - {0,1,2,2,1,1,0}, - {0,0,1,1,2,2,1}, - {0,1,2,2,1,1,0}, - {1,2,1,1,0,0,0}, - {0,1,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '|', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - ',', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,0,0,0}, - {0,1,2,2,1,0,0}, - {0,1,2,2,1,0,0}, - {0,1,2,1,0,0,0}, - {0,0,1,0,0,0,0} - } - }, - { - '.', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,0,0,0}, - {0,1,2,2,1,0,0}, - {0,1,2,2,1,0,0}, - {0,0,1,1,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - ':', - { - {0,0,1,1,0,0,0}, - {0,1,2,2,1,0,0}, - {0,1,2,2,1,0,0}, - {0,0,1,1,0,0,0}, - {0,0,1,1,0,0,0}, - {0,1,2,2,1,0,0}, - {0,1,2,2,1,0,0}, - {0,0,1,1,0,0,0} - } - }, - { - '-', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '+', - { - {0,0,0,0,0,0,0}, - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - '_', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,1,1,0} - } - }, - { - '\'', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0} - } - }, - { - 'a', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,1,0} - } - }, - { - 'b', - { - {0,1,0,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'c', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {1,2,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,1,0} - } - }, - { - 'd', - { - {0,0,0,0,0,1,0}, - {0,0,0,0,1,2,1}, - {0,0,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,1,0} - } - }, - { - 'e', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,2,1,1,2,1}, - {1,2,1,2,2,1,0}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,1,0} - } - }, - { - 'f', - { - {0,0,0,0,1,1,0}, - {0,0,0,1,2,2,1}, - {0,0,1,2,1,1,0}, - {0,1,2,2,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - 'g', - { - {0,0,0,0,0,0,0}, - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,1,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'h', - { - {0,1,0,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,1,1,0,0}, - {1,2,1,2,2,1,0}, - {1,2,2,1,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'i', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'j', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,1,2,1,0,0}, - {1,2,2,1,0,0,0}, - {0,1,1,0,0,0,0} - } - }, - { - 'k', - { - {0,1,0,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,1,0,0}, - {1,2,1,1,2,1,0}, - {1,2,1,2,1,0,0}, - {1,2,2,1,2,1,0}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'l', - { - {0,0,1,1,0,0,0}, - {0,1,2,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,2,1,0}, - {0,0,0,0,1,0,0} - } - }, - { - 'm', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,1,0,1,0,0}, - {1,2,2,1,2,1,0}, - {1,2,1,2,1,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,2,1,2,1}, - {0,1,0,1,0,1,0} - } - }, - { - 'n', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,1,1,0,0}, - {1,2,1,2,2,1,0}, - {1,2,2,1,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'o', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'p', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,0,0}, - {1,2,1,0,0,0,0}, - } - }, - { - 'q', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,2,1}, - {0,0,0,0,1,2,1} - } - }, - { - 'r', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,1,1,0,0}, - {1,2,1,2,2,1,0}, - {1,2,2,1,1,2,1}, - {1,2,1,0,0,1,0}, - {1,2,1,0,0,0,0}, - {0,1,0,0,0,0,0} - } - }, - { - 's', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,2,2,1,1,0}, - {0,1,1,2,2,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 't', - { - {0,0,0,1,0,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,2,1,0}, - {0,0,0,0,1,0,0} - } - }, - { - 'u', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,1,2,2,1}, - {0,1,2,2,1,2,1}, - {0,0,1,1,0,1,0} - } - }, - { - 'v', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - 'w', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,2,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,0,1,0,0} - } - }, - { - 'x', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,0,1,0,0}, - {1,2,1,1,2,1,0}, - {0,1,2,2,1,0,0}, - {0,1,2,2,1,0,0}, - {1,2,1,1,2,1,0}, - {0,1,0,0,1,0,0} - } - }, - { - 'y', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,0,0,0}, - {1,2,1,0,0,0,0} - } - }, - { - 'z', - { - {0,0,0,0,0,0,0}, - {0,0,0,0,0,0,0}, - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {0,1,1,2,1,0,0}, - {0,1,2,1,1,0,0}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'A', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'B', - { - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'C', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,0,0,1,0}, - {1,2,1,0,0,1,0}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'D', - { - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'E', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,0,0}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,1,1,0} - } - }, - { - 'F', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,0,0,0}, - {0,1,0,0,0,0,0} - } - }, - { - 'G', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,1,0}, - {1,2,1,2,2,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'H', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'I', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'J', - { - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,2,1}, - {0,0,0,0,1,2,1}, - {0,1,0,0,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'K', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,1,2,1,0}, - {1,2,1,2,1,0,0}, - {1,2,2,2,1,0,0}, - {1,2,1,1,2,1,0}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'L', - { - {0,1,0,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'M', - { - {0,1,1,0,1,1,0}, - {1,2,2,1,2,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,1,1,2,}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'N', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,2,1,1,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,1,2,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'O', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,0,0} - } - }, - { - 'P', - { - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,0,0}, - {1,2,1,0,0,0,0}, - {1,2,1,0,0,0,0}, - {0,1,0,0,0,0,0} - } - }, - { - 'Q', - { - {0,0,1,1,1,0,0}, - {0,1,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,1,2,1,0}, - {0,1,2,2,1,2,1}, - {0,0,1,1,0,1,0} - } - }, - { - 'R', - { - {0,1,1,1,1,0,0}, - {1,2,2,2,2,1,0}, - {1,2,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {1,2,1,2,1,0,0}, - {1,2,1,1,2,1,0}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'S', - { - {0,0,1,1,1,1,0}, - {0,1,2,2,2,2,1}, - {1,2,1,1,1,1,0}, - {0,1,2,2,2,1,0}, - {0,0,1,1,1,2,1}, - {0,1,1,1,1,2,1}, - {1,2,2,2,2,1,0}, - {0,1,1,1,1,0,0} - } - }, - { - 'T', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,2,1,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - 'U', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {0,1,2,2,2,2,1}, - {0,0,1,1,1,1,0} - } - }, - { - 'V', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - 'W', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {1,2,1,0,1,2,1}, - {1,2,1,1,1,2,1}, - {1,2,1,2,1,2,1}, - {1,2,1,2,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,0,1,0,0} - } - }, - { - 'X', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,2,1,0}, - {1,2,1,0,1,2,1}, - {0,1,0,0,0,1,0} - } - }, - { - 'Y', - { - {0,1,0,0,0,1,0}, - {1,2,1,0,1,2,1}, - {0,1,2,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,1,2,1,0,0}, - {0,0,0,1,0,0,0} - } - }, - { - 'Z', - { - {0,1,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,2,1,0}, - {0,0,1,2,1,0,0}, - {0,1,2,1,0,0,0}, - {1,2,1,1,1,1,0}, - {1,2,2,2,2,2,1}, - {0,1,1,1,1,1,0} - } - } + { + ' ', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '0', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,2,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,2,1,2,1}, + {1,2,2,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '1', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '2', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {0,1,1,2,2,1,0}, + {0,1,2,1,1,0,0}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,1,1,0} + } + }, + { + '3', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {0,1,1,2,2,1,0}, + {0,1,0,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '4', + { + {0,0,0,0,1,0,0}, + {0,0,0,1,2,1,0}, + {0,0,1,2,2,1,0}, + {0,1,2,1,2,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,2,1,0}, + {0,0,0,1,2,1,0}, + {0,0,0,0,1,0,0} + } + }, + { + '5', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,2,0}, + {0,1,1,1,1,2,0}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + '6', + { + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '7', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,1,2,1}, + {0,0,0,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,0,0,0}, + {0,1,2,1,0,0,0}, + {0,0,1,0,0,0,0} + } + }, + { + '8', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '9', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,1,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '"', + { + {0,0,1,0,1,0,0}, + {0,1,2,1,2,1,0}, + {0,1,2,1,2,1,0}, + {0,0,1,0,1,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '/', + { + {0,0,0,0,1,0,0}, + {0,0,0,1,2,1,0}, + {0,0,0,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,0,0,0}, + {0,1,2,1,0,0,0}, + {0,0,1,0,0,0,0} + } + }, + { + '(', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,0,0,0}, + {0,1,2,1,0,0,0}, + {0,1,2,1,0,0,0}, + {0,1,2,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + ')', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,2,1,0}, + {0,0,0,1,2,1,0}, + {0,0,0,1,2,1,0}, + {0,0,0,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + '@', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,2,2,2,1}, + {1,2,1,2,2,2,1}, + {1,2,1,1,1,1,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + '~', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,0,0,0,0}, + {0,1,2,1,0,1,0}, + {1,2,1,2,1,2,1}, + {0,1,0,1,2,1,0}, + {0,0,0,0,1,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '#', + { + {0,0,1,0,1,0,0}, + {0,1,2,1,2,1,0}, + {1,2,2,2,2,2,1}, + {0,1,2,1,2,1,0}, + {0,1,2,1,2,1,0}, + {1,2,2,2,2,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,0,1,0,0} + } + }, + { + '<', + { + {0,0,0,0,0,1,0}, + {0,0,0,1,1,2,1}, + {0,1,1,2,2,1,0}, + {1,2,2,1,1,0,0}, + {0,1,1,2,2,1,0}, + {0,0,0,1,1,2,1}, + {0,0,0,0,0,1,0}, + {0,0,0,0,0,0,0} + } + }, + { + '>', + { + {0,1,0,0,0,0,0}, + {1,2,1,1,0,0,0}, + {0,1,2,2,1,1,0}, + {0,0,1,1,2,2,1}, + {0,1,2,2,1,1,0}, + {1,2,1,1,0,0,0}, + {0,1,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '|', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + ',', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,0,0,0}, + {0,1,2,2,1,0,0}, + {0,1,2,2,1,0,0}, + {0,1,2,1,0,0,0}, + {0,0,1,0,0,0,0} + } + }, + { + '.', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,0,0,0}, + {0,1,2,2,1,0,0}, + {0,1,2,2,1,0,0}, + {0,0,1,1,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + ':', + { + {0,0,1,1,0,0,0}, + {0,1,2,2,1,0,0}, + {0,1,2,2,1,0,0}, + {0,0,1,1,0,0,0}, + {0,0,1,1,0,0,0}, + {0,1,2,2,1,0,0}, + {0,1,2,2,1,0,0}, + {0,0,1,1,0,0,0} + } + }, + { + '-', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '+', + { + {0,0,0,0,0,0,0}, + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + '_', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,1,1,0} + } + }, + { + '\'', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0} + } + }, + { + 'a', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,1,0} + } + }, + { + 'b', + { + {0,1,0,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'c', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {1,2,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,1,0} + } + }, + { + 'd', + { + {0,0,0,0,0,1,0}, + {0,0,0,0,1,2,1}, + {0,0,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,1,0} + } + }, + { + 'e', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,2,1,1,2,1}, + {1,2,1,2,2,1,0}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,1,0} + } + }, + { + 'f', + { + {0,0,0,0,1,1,0}, + {0,0,0,1,2,2,1}, + {0,0,1,2,1,1,0}, + {0,1,2,2,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + 'g', + { + {0,0,0,0,0,0,0}, + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,1,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'h', + { + {0,1,0,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,1,1,0,0}, + {1,2,1,2,2,1,0}, + {1,2,2,1,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'i', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'j', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,1,2,1,0,0}, + {1,2,2,1,0,0,0}, + {0,1,1,0,0,0,0} + } + }, + { + 'k', + { + {0,1,0,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,1,0,0}, + {1,2,1,1,2,1,0}, + {1,2,1,2,1,0,0}, + {1,2,2,1,2,1,0}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'l', + { + {0,0,1,1,0,0,0}, + {0,1,2,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,2,1,0}, + {0,0,0,0,1,0,0} + } + }, + { + 'm', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,1,0,1,0,0}, + {1,2,2,1,2,1,0}, + {1,2,1,2,1,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,2,1,2,1}, + {0,1,0,1,0,1,0} + } + }, + { + 'n', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,1,1,0,0}, + {1,2,1,2,2,1,0}, + {1,2,2,1,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'o', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'p', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,0,0}, + {1,2,1,0,0,0,0}, + } + }, + { + 'q', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,2,1}, + {0,0,0,0,1,2,1} + } + }, + { + 'r', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,1,1,0,0}, + {1,2,1,2,2,1,0}, + {1,2,2,1,1,2,1}, + {1,2,1,0,0,1,0}, + {1,2,1,0,0,0,0}, + {0,1,0,0,0,0,0} + } + }, + { + 's', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,2,2,1,1,0}, + {0,1,1,2,2,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 't', + { + {0,0,0,1,0,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,2,1,0}, + {0,0,0,0,1,0,0} + } + }, + { + 'u', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,1,2,2,1}, + {0,1,2,2,1,2,1}, + {0,0,1,1,0,1,0} + } + }, + { + 'v', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + 'w', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,2,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,0,1,0,0} + } + }, + { + 'x', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,0,1,0,0}, + {1,2,1,1,2,1,0}, + {0,1,2,2,1,0,0}, + {0,1,2,2,1,0,0}, + {1,2,1,1,2,1,0}, + {0,1,0,0,1,0,0} + } + }, + { + 'y', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,0,0,0}, + {1,2,1,0,0,0,0} + } + }, + { + 'z', + { + {0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0}, + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {0,1,1,2,1,0,0}, + {0,1,2,1,1,0,0}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'A', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'B', + { + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'C', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,0,0,1,0}, + {1,2,1,0,0,1,0}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'D', + { + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'E', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,0,0}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,1,1,0} + } + }, + { + 'F', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,0,0,0}, + {0,1,0,0,0,0,0} + } + }, + { + 'G', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,1,0}, + {1,2,1,2,2,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'H', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'I', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'J', + { + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,2,1}, + {0,0,0,0,1,2,1}, + {0,1,0,0,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'K', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,1,2,1,0}, + {1,2,1,2,1,0,0}, + {1,2,2,2,1,0,0}, + {1,2,1,1,2,1,0}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'L', + { + {0,1,0,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'M', + { + {0,1,1,0,1,1,0}, + {1,2,2,1,2,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,1,1,2,}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'N', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,2,1,1,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,1,2,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'O', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,0,0} + } + }, + { + 'P', + { + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,0,0}, + {1,2,1,0,0,0,0}, + {1,2,1,0,0,0,0}, + {0,1,0,0,0,0,0} + } + }, + { + 'Q', + { + {0,0,1,1,1,0,0}, + {0,1,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,1,2,1,0}, + {0,1,2,2,1,2,1}, + {0,0,1,1,0,1,0} + } + }, + { + 'R', + { + {0,1,1,1,1,0,0}, + {1,2,2,2,2,1,0}, + {1,2,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {1,2,1,2,1,0,0}, + {1,2,1,1,2,1,0}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'S', + { + {0,0,1,1,1,1,0}, + {0,1,2,2,2,2,1}, + {1,2,1,1,1,1,0}, + {0,1,2,2,2,1,0}, + {0,0,1,1,1,2,1}, + {0,1,1,1,1,2,1}, + {1,2,2,2,2,1,0}, + {0,1,1,1,1,0,0} + } + }, + { + 'T', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,2,1,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + 'U', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {0,1,2,2,2,2,1}, + {0,0,1,1,1,1,0} + } + }, + { + 'V', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + 'W', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {1,2,1,0,1,2,1}, + {1,2,1,1,1,2,1}, + {1,2,1,2,1,2,1}, + {1,2,1,2,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,0,1,0,0} + } + }, + { + 'X', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,2,1,0}, + {1,2,1,0,1,2,1}, + {0,1,0,0,0,1,0} + } + }, + { + 'Y', + { + {0,1,0,0,0,1,0}, + {1,2,1,0,1,2,1}, + {0,1,2,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,1,2,1,0,0}, + {0,0,0,1,0,0,0} + } + }, + { + 'Z', + { + {0,1,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,2,1,0}, + {0,0,1,2,1,0,0}, + {0,1,2,1,0,0,0}, + {1,2,1,1,1,1,0}, + {1,2,2,2,2,2,1}, + {0,1,1,1,1,1,0} + } + } }; struct big_char big_table[sizeof(draw_table) / sizeof(struct draw_char)]; @@ -1078,101 +1078,116 @@ struct big_char big_table[sizeof(draw_table) / sizeof(struct draw_char)]; static int draw_textn (unsigned char *image, int startx, int starty, int width, const char *text, int len, unsigned short int factor) { - int pos, x, y, line_offset, next_char_offs; - unsigned char *image_ptr, *char_ptr, **char_arr_ptr; + int pos, x, y, line_offset, next_char_offs; + unsigned char *image_ptr, *char_ptr, **char_arr_ptr; - if (startx>width/2) - startx -= len*(6*(factor+1)); + if (startx > width / 2) + startx -= len * (6 * (factor + 1)); - if (startx < 0) - startx = 0; - - if (startx+len*6*(factor+1) >= width) - len = (width-startx-1)/(6*(factor+1)); - - line_offset = width - 7*(factor+1); - next_char_offs = width*8*(factor+1) - 6*(factor+1); - - image_ptr = image + startx + starty*width; + if (startx < 0) + startx = 0; + + if (startx + len * 6 * (factor + 1) >= width) + len = (width-startx-1)/(6*(factor+1)); + + line_offset = width - 7 * (factor + 1); + next_char_offs = width * 8 * (factor + 1) - 6 * (factor + 1); + + image_ptr = image + startx + starty * width; - char_arr_ptr = factor ? big_char_arr_ptr : small_char_arr_ptr; - - for (pos = 0; pos < len; pos++) { - char_ptr = char_arr_ptr[(int)text[pos]]; - for (y=8*(factor+1); y--;) { - for (x=7*(factor+1); x--;) { - switch(*char_ptr) { - case 1: - *image_ptr = 0; - break; - case 2: - *image_ptr = 255; - break; - default: - break; - } - image_ptr++; - char_ptr++; - } - image_ptr += line_offset; - } - image_ptr -= next_char_offs; - } - return 0; + char_arr_ptr = factor ? big_char_arr_ptr : small_char_arr_ptr; + + for (pos = 0; pos < len; pos++) { + char_ptr = char_arr_ptr[(int)text[pos]]; + + for (y = 8 * (factor + 1); y--;) { + for (x = 7 * (factor + 1); x--;) { + switch(*char_ptr) { + case 1: + *image_ptr = 0; + break; + case 2: + *image_ptr = 255; + break; + default: + break; + } + + image_ptr++; + char_ptr++; + } + + image_ptr += line_offset; + } + + image_ptr -= next_char_offs; + } + + return 0; } int draw_text (unsigned char *image, int startx, int starty, int width, const char *text, unsigned short int factor) { - int num_nl = 0; - const char *end, *begin; - const int line_space = (factor + 1) * 9; - - /* Count the number of newlines in "text" so we scroll it up the image */ - end = text; - while ((end = strstr(end, NEWLINE))) { - num_nl++; - end += sizeof(NEWLINE)-1; - } - starty -= line_space * num_nl; - - begin = end = text; - while ((end = strstr(end, NEWLINE))) { - int len = end-begin; - draw_textn(image, startx, starty, width, begin, len, factor); - end += sizeof(NEWLINE)-1; - begin = end; - starty += line_space; - } - draw_textn(image, startx, starty, width, begin, strlen(begin), factor); - return 0; + int num_nl = 0; + const char *end, *begin; + const int line_space = (factor + 1) * 9; + + /* Count the number of newlines in "text" so we scroll it up the image */ + end = text; + + while ((end = strstr(end, NEWLINE))) { + num_nl++; + end += sizeof(NEWLINE)-1; + } + + starty -= line_space * num_nl; + + begin = end = text; + + while ((end = strstr(end, NEWLINE))) { + int len = end-begin; + + draw_textn(image, startx, starty, width, begin, len, factor); + end += sizeof(NEWLINE)-1; + begin = end; + starty += line_space; + } + + draw_textn(image, startx, starty, width, begin, strlen(begin), factor); + + return 0; } int initialize_chars(void) { - unsigned int i=0, x, y; - - /* Fill the structure 'big_table' with double sized characters. */ - while(draw_table[i].ascii) { - big_table[i].ascii = draw_table[i].ascii; - for(x=0; x < 14; x++) { - for(y=0; y < 16; y++) { - big_table[i].pix[y][x] = draw_table[i].pix[y/2][x/2]; - } - } - i++; - } + unsigned int i, x, y; + size_t draw_table_size; + + draw_table_size = sizeof(draw_table) / sizeof(struct draw_char); - /* first init all char ptr's to a space character */ - for (i=0; i < ASCII_MAX; i++) { - small_char_arr_ptr[i]=&draw_table[0].pix[0][0]; - big_char_arr_ptr[i]=&big_table[0].pix[0][0]; - } - - /* build [big_]char_arr_ptr table to point to each available ascii */ - for (i=0; i < sizeof(draw_table) / sizeof(struct draw_char); i++) { - small_char_arr_ptr[(int)draw_table[i].ascii]=&draw_table[i].pix[0][0]; - big_char_arr_ptr[(int)draw_table[i].ascii]=&big_table[i].pix[0][0]; - } - return 0; + /* Fill the structure 'big_table' with double sized characters. */ + for (i = 0; i < draw_table_size; i++) { + big_table[i].ascii = draw_table[i].ascii; + + for(x = 0; x < 14; x++) { + for(y = 0; y < 16; y++) { + big_table[i].pix[y][x] = draw_table[i].pix[y/2][x/2]; + } + } + } + + /* first init all char ptr's to a space character */ + for (i = 0; i < ASCII_MAX; i++) { + small_char_arr_ptr[i] = &draw_table[0].pix[0][0]; + big_char_arr_ptr[i] = &big_table[0].pix[0][0]; + } + + /* build [big_]char_arr_ptr table to point to each available ascii */ + for (i = 0; i < draw_table_size; i++) { + small_char_arr_ptr[(int)draw_table[i].ascii] = &draw_table[i].pix[0][0]; + big_char_arr_ptr[(int)draw_table[i].ascii] = &big_table[i].pix[0][0]; + } + + return 0; } diff --git a/event.c b/event.c index 19e66bcb..14458f10 100644 --- a/event.c +++ b/event.c @@ -1,23 +1,23 @@ /* - event.c + event.c - Generalised event handling for motion + Generalised event handling for motion - Copyright Jeroen Vreeken, 2002 - This software is distributed under the GNU Public License Version 2 - see also the file 'COPYING'. + Copyright Jeroen Vreeken, 2002 + This software is distributed under the GNU Public License Version 2 + see also the file 'COPYING'. */ -#include "ffmpeg.h" /* must be first to avoid 'shadow' warning */ -#include "picture.h" /* already includes motion.h */ +#include "ffmpeg.h" /* must be first to avoid 'shadow' warning */ +#include "picture.h" /* already includes motion.h */ #include "event.h" #if (!defined(BSD)) #include "video.h" #endif /* - * Various functions (most doing the actual action) + * Various functions (most doing the actual action) */ /* Execute 'command' with 'arg' as its argument. @@ -28,42 +28,42 @@ */ static void exec_command(struct context *cnt, char *command, char *filename, int filetype) { - char stamp[PATH_MAX]; - mystrftime(cnt, stamp, sizeof(stamp), command, &cnt->current_image->timestamp_tm, filename, filetype); - - if (!fork()) { - int i; - - /* Detach from parent */ - setsid(); + char stamp[PATH_MAX]; + mystrftime(cnt, stamp, sizeof(stamp), command, &cnt->current_image->timestamp_tm, filename, filetype); + + if (!fork()) { + int i; + + /* Detach from parent */ + setsid(); - /* - * Close any file descriptor except console because we will - * like to see error messages - */ - for (i = getdtablesize(); i > 2; --i) - close(i); - - execl("/bin/sh", "sh", "-c", stamp, " &", NULL); + /* + * Close any file descriptor except console because we will + * like to see error messages + */ + for (i = getdtablesize(); i > 2; --i) + close(i); + + execl("/bin/sh", "sh", "-c", stamp, " &", NULL); - /* if above function succeeds the program never reach here */ - motion_log(LOG_ERR, 1, "Unable to start external command '%s'", stamp); + /* if above function succeeds the program never reach here */ + motion_log(LOG_ERR, 1, "Unable to start external command '%s'", stamp); - exit(1); - } - else if (cnt->conf.setup_mode) - motion_log(-1, 0, "Executing external command '%s'", stamp); + exit(1); + } else if (cnt->conf.setup_mode) { + motion_log(-1, 0, "Executing external command '%s'", stamp); + } } /* - * Event handlers + * Event handlers */ static void event_newfile(struct context *cnt ATTRIBUTE_UNUSED, int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *ftype, struct tm *tm ATTRIBUTE_UNUSED) { - motion_log(-1, 0, "File of type %ld saved to: %s", (unsigned long)ftype, filename); + motion_log(-1, 0, "File of type %ld saved to: %s", (unsigned long)ftype, filename); } @@ -73,8 +73,8 @@ static void event_beep(struct context *cnt, int type ATTRIBUTE_UNUSED, void *ftype ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (!cnt->conf.quiet) - printf("\a"); + if (!cnt->conf.quiet) + printf("\a"); } /* on_picture_save_command handles both on_picture_save and on_movie_start @@ -87,13 +87,13 @@ static void on_picture_save_command(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { - int filetype = (unsigned long)arg; + int filetype = (unsigned long)arg; - if ((filetype & FTYPE_IMAGE_ANY) != 0 && cnt->conf.on_picture_save) - exec_command(cnt, cnt->conf.on_picture_save, filename, filetype); + if ((filetype & FTYPE_IMAGE_ANY) != 0 && cnt->conf.on_picture_save) + exec_command(cnt, cnt->conf.on_picture_save, filename, filetype); - if ((filetype & FTYPE_MPEG_ANY) != 0 && cnt->conf.on_movie_start) - exec_command(cnt, cnt->conf.on_movie_start, filename, filetype); + if ((filetype & FTYPE_MPEG_ANY) != 0 && cnt->conf.on_movie_start) + exec_command(cnt, cnt->conf.on_movie_start, filename, filetype); } static void on_motion_detected_command(struct context *cnt, @@ -101,8 +101,8 @@ static void on_motion_detected_command(struct context *cnt, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->conf.on_motion_detected) - exec_command(cnt, cnt->conf.on_motion_detected, NULL, 0); + if (cnt->conf.on_motion_detected) + exec_command(cnt, cnt->conf.on_motion_detected, NULL, 0); } #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) @@ -111,60 +111,66 @@ static void event_sqlnewfile(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { - int sqltype = (unsigned long)arg; + int sqltype = (unsigned long)arg; - /* Only log the file types we want */ - if (!(cnt->conf.mysql_db || cnt->conf.pgsql_db) || (sqltype & cnt->sql_mask) == 0) - return; + /* Only log the file types we want */ + if (!(cnt->conf.mysql_db || cnt->conf.pgsql_db) || (sqltype & cnt->sql_mask) == 0) + return; - /* We place the code in a block so we only spend time making space in memory - * for the sqlquery and timestr when we actually need it. - */ - { - char sqlquery[PATH_MAX]; - int ret; - - mystrftime(cnt, sqlquery, sizeof(sqlquery), cnt->conf.sql_query, &cnt->current_image->timestamp_tm, filename, sqltype); - + /* We place the code in a block so we only spend time making space in memory + * for the sqlquery and timestr when we actually need it. + */ + { + char sqlquery[PATH_MAX]; + int ret; + + mystrftime(cnt, sqlquery, sizeof(sqlquery), cnt->conf.sql_query, + &cnt->current_image->timestamp_tm, filename, sqltype); + #ifdef HAVE_MYSQL - if (cnt->conf.mysql_db) { - ret = mysql_query(cnt->database, sqlquery); - if (ret != 0){ - int error_code = mysql_errno(cnt->database); - - motion_log(LOG_ERR, 1, "Mysql query failed %s error code %d", - mysql_error(cnt->database), error_code); - /* Try to reconnect ONCE if fails continue and discard this sql query */ - if (error_code >= 2000){ - cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cnt->database); - if (!mysql_real_connect(cnt->database, cnt->conf.mysql_host, - cnt->conf.mysql_user, cnt->conf.mysql_password, - cnt->conf.mysql_db, 0, NULL, 0)) { - motion_log(LOG_ERR, 0, "Cannot reconnect to MySQL database %s on host %s with user %s", cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user); - motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database)); - }else mysql_query(cnt->database, sqlquery); - } - - } - } + if (cnt->conf.mysql_db) { + ret = mysql_query(cnt->database, sqlquery); + + if (ret != 0) { + int error_code = mysql_errno(cnt->database); + + motion_log(LOG_ERR, 1, "Mysql query failed %s error code %d", + mysql_error(cnt->database), error_code); + /* Try to reconnect ONCE if fails continue and discard this sql query */ + if (error_code >= 2000) { + cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(cnt->database); + + if (!mysql_real_connect(cnt->database, cnt->conf.mysql_host, + cnt->conf.mysql_user, cnt->conf.mysql_password, + cnt->conf.mysql_db, 0, NULL, 0)) { + motion_log(LOG_ERR, 0, "Cannot reconnect to MySQL database %s on host %s with user %s", + cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user); + motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database)); + } else { + mysql_query(cnt->database, sqlquery); + } + } + + } + } #endif /* HAVE_MYSQL */ #ifdef HAVE_PGSQL - if (cnt->conf.pgsql_db) { - PGresult *res; + if (cnt->conf.pgsql_db) { + PGresult *res; - res = PQexec(cnt->database_pg, sqlquery); + res = PQexec(cnt->database_pg, sqlquery); - if (PQresultStatus(res) != PGRES_COMMAND_OK) { - motion_log(LOG_ERR, 1, "PGSQL query failed"); - PQclear(res); - } - } + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + motion_log(LOG_ERR, 1, "PGSQL query failed"); + PQclear(res); + } + } #endif /* HAVE_PGSQL */ - } + } } #endif /* defined HAVE_MYSQL || defined HAVE_PGSQL */ @@ -174,8 +180,8 @@ static void on_area_command(struct context *cnt, int type ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->conf.on_area_detected) - exec_command(cnt, cnt->conf.on_area_detected, NULL, 0); + if (cnt->conf.on_area_detected) + exec_command(cnt, cnt->conf.on_area_detected, NULL, 0); } static void on_event_start_command(struct context *cnt, int type ATTRIBUTE_UNUSED, @@ -183,8 +189,8 @@ static void on_event_start_command(struct context *cnt, int type ATTRIBUTE_UNUSE char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->conf.on_event_start) - exec_command(cnt, cnt->conf.on_event_start, NULL, 0); + if (cnt->conf.on_event_start) + exec_command(cnt, cnt->conf.on_event_start, NULL, 0); } static void on_event_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, @@ -192,8 +198,8 @@ static void on_event_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->conf.on_event_end) - exec_command(cnt, cnt->conf.on_event_end, NULL, 0); + if (cnt->conf.on_event_end) + exec_command(cnt, cnt->conf.on_event_end, NULL, 0); } static void event_stop_webcam(struct context *cnt, int type ATTRIBUTE_UNUSED, @@ -201,17 +207,17 @@ static void event_stop_webcam(struct context *cnt, int type ATTRIBUTE_UNUSED, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if ((cnt->conf.webcam_port) && (cnt->webcam.socket != -1)){ - webcam_stop(cnt); - } + if ((cnt->conf.webcam_port) && (cnt->webcam.socket != -1)) + webcam_stop(cnt); + } static void event_webcam_put(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->conf.webcam_port) - webcam_put(cnt, img); + if (cnt->conf.webcam_port) + webcam_put(cnt, img); } #ifndef WITHOUT_V4L @@ -220,10 +226,10 @@ static void event_vid_putpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy ATTRIBUTE_UNUSED, void *devpipe, struct tm *tm ATTRIBUTE_UNUSED) { - if (*(int *)devpipe >= 0) { - if (vid_putpipe(*(int *)devpipe, img, cnt->imgs.size) == -1) - motion_log(LOG_ERR, 1, "Failed to put image into video pipe"); - } + if (*(int *)devpipe >= 0) { + if (vid_putpipe(*(int *)devpipe, img, cnt->imgs.size) == -1) + motion_log(LOG_ERR, 1, "Failed to put image into video pipe"); + } } #endif /* BSD */ #endif /* WITHOUT_V4L */ @@ -231,222 +237,226 @@ static void event_vid_putpipe(struct context *cnt, int type ATTRIBUTE_UNUSED, const char *imageext(struct context *cnt) { - if (cnt->conf.ppm) - return "ppm"; - return "jpg"; + if (cnt->conf.ppm) + return "ppm"; + return "jpg"; } static void event_image_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, - unsigned char *newimg, char *dummy1 ATTRIBUTE_UNUSED, - void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) + unsigned char *newimg, char *dummy1 ATTRIBUTE_UNUSED, + void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { - char fullfilename[PATH_MAX]; - char filename[PATH_MAX]; + char fullfilename[PATH_MAX]; + char filename[PATH_MAX]; - if (cnt->new_img & NEWIMG_ON) { - const char *jpegpath; + if (cnt->new_img & NEWIMG_ON) { + const char *jpegpath; - /* conf.jpegpath would normally be defined but if someone deleted it by control interface - it is better to revert to the default than fail */ - if (cnt->conf.jpegpath) - jpegpath = cnt->conf.jpegpath; - else - jpegpath = DEF_JPEGPATH; - - mystrftime(cnt, filename, sizeof(filename), jpegpath, currenttime_tm, NULL, 0); - snprintf(fullfilename, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filename, imageext(cnt)); - - put_picture(cnt, fullfilename, newimg, FTYPE_IMAGE); - } + /* conf.jpegpath would normally be defined but if someone deleted it by control interface + it is better to revert to the default than fail */ + if (cnt->conf.jpegpath) + jpegpath = cnt->conf.jpegpath; + else + jpegpath = DEF_JPEGPATH; + + mystrftime(cnt, filename, sizeof(filename), jpegpath, currenttime_tm, NULL, 0); + snprintf(fullfilename, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filename, imageext(cnt)); + put_picture(cnt, fullfilename, newimg, FTYPE_IMAGE); + } } static void event_imagem_detect(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *newimg ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { - struct config *conf=&cnt->conf; - char fullfilenamem[PATH_MAX]; - char filename[PATH_MAX]; - char filenamem[PATH_MAX]; + struct config *conf=&cnt->conf; + char fullfilenamem[PATH_MAX]; + char filename[PATH_MAX]; + char filenamem[PATH_MAX]; - if (conf->motion_img) { - const char *jpegpath; + if (conf->motion_img) { + const char *jpegpath; - /* conf.jpegpath would normally be defined but if someone deleted it by control interface - it is better to revert to the default than fail */ - if (cnt->conf.jpegpath) - jpegpath = cnt->conf.jpegpath; - else - jpegpath = DEF_JPEGPATH; - - mystrftime(cnt, filename, sizeof(filename), jpegpath, currenttime_tm, NULL, 0); - /* motion images gets same name as normal images plus an appended 'm' */ - snprintf(filenamem, PATH_MAX, "%sm", filename); - snprintf(fullfilenamem, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filenamem, imageext(cnt)); + /* conf.jpegpath would normally be defined but if someone deleted it by control interface + it is better to revert to the default than fail */ + if (cnt->conf.jpegpath) + jpegpath = cnt->conf.jpegpath; + else + jpegpath = DEF_JPEGPATH; + + mystrftime(cnt, filename, sizeof(filename), jpegpath, currenttime_tm, NULL, 0); + /* motion images gets same name as normal images plus an appended 'm' */ + snprintf(filenamem, PATH_MAX, "%sm", filename); + snprintf(fullfilenamem, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filenamem, imageext(cnt)); - put_picture(cnt, fullfilenamem, cnt->imgs.out, FTYPE_IMAGE_MOTION); - } + put_picture(cnt, fullfilenamem, cnt->imgs.out, FTYPE_IMAGE_MOTION); + } } static void event_image_snapshot(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { - char fullfilename[PATH_MAX]; + char fullfilename[PATH_MAX]; - if ( strcmp(cnt->conf.snappath, "lastsnap") ) { - char filename[PATH_MAX]; - char filepath[PATH_MAX]; - char linkpath[PATH_MAX]; - const char *snappath; - /* conf.snappath would normally be defined but if someone deleted it by control interface - it is better to revert to the default than fail */ - if (cnt->conf.snappath) - snappath = cnt->conf.snappath; - else - snappath = DEF_SNAPPATH; - - mystrftime(cnt, filepath, sizeof(filepath), snappath, currenttime_tm, NULL, 0); - snprintf(filename, PATH_MAX, "%s.%s", filepath, imageext(cnt)); - snprintf(fullfilename, PATH_MAX, "%s/%s", cnt->conf.filepath, filename); - put_picture(cnt, fullfilename, img, FTYPE_IMAGE_SNAPSHOT); + if (strcmp(cnt->conf.snappath, "lastsnap")) { + char filename[PATH_MAX]; + char filepath[PATH_MAX]; + char linkpath[PATH_MAX]; + const char *snappath; + /* conf.snappath would normally be defined but if someone deleted it by control interface + it is better to revert to the default than fail */ + if (cnt->conf.snappath) + snappath = cnt->conf.snappath; + else + snappath = DEF_SNAPPATH; + + mystrftime(cnt, filepath, sizeof(filepath), snappath, currenttime_tm, NULL, 0); + snprintf(filename, PATH_MAX, "%s.%s", filepath, imageext(cnt)); + snprintf(fullfilename, PATH_MAX, "%s/%s", cnt->conf.filepath, filename); + put_picture(cnt, fullfilename, img, FTYPE_IMAGE_SNAPSHOT); - /* Update symbolic link *after* image has been written so that - the link always points to a valid file. */ - snprintf(linkpath, PATH_MAX, "%s/lastsnap.%s", cnt->conf.filepath, imageext(cnt)); - remove(linkpath); - if (symlink(filename, linkpath)) { - motion_log(LOG_ERR, 1, "Could not create symbolic link [%s]", filename); - return; - } - } else { - snprintf(fullfilename, PATH_MAX, "%s/lastsnap.%s", cnt->conf.filepath, imageext(cnt)); - remove(fullfilename); - put_picture(cnt, fullfilename, img, FTYPE_IMAGE_SNAPSHOT); - } + /* Update symbolic link *after* image has been written so that + the link always points to a valid file. */ + snprintf(linkpath, PATH_MAX, "%s/lastsnap.%s", cnt->conf.filepath, imageext(cnt)); + remove(linkpath); - cnt->snapshot = 0; + if (symlink(filename, linkpath)) { + motion_log(LOG_ERR, 1, "Could not create symbolic link [%s]", filename); + return; + } + } else { + snprintf(fullfilename, PATH_MAX, "%s/lastsnap.%s", cnt->conf.filepath, imageext(cnt)); + remove(fullfilename); + put_picture(cnt, fullfilename, img, FTYPE_IMAGE_SNAPSHOT); + } + + cnt->snapshot = 0; } static void event_camera_lost(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img ATTRIBUTE_UNUSED, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm ATTRIBUTE_UNUSED) { - if (cnt->conf.on_camera_lost) - exec_command(cnt, cnt->conf.on_camera_lost, NULL, 0); + if (cnt->conf.on_camera_lost) + exec_command(cnt, cnt->conf.on_camera_lost, NULL, 0); } #ifdef HAVE_FFMPEG static void grey2yuv420p(unsigned char *u, unsigned char *v, int width, int height) { - memset(u, 128, width*height/4); - memset(v, 128, width*height/4); + memset(u, 128, width * height / 4); + memset(v, 128, width * height / 4); } static void on_movie_end_command(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *dummy ATTRIBUTE_UNUSED, char *filename, void *arg, struct tm *tm ATTRIBUTE_UNUSED) { - int filetype = (unsigned long) arg; + int filetype = (unsigned long) arg; - if ((filetype & FTYPE_MPEG_ANY) && cnt->conf.on_movie_end) - exec_command(cnt, cnt->conf.on_movie_end, filename, filetype); + if ((filetype & FTYPE_MPEG_ANY) && cnt->conf.on_movie_end) + exec_command(cnt, cnt->conf.on_movie_end, filename, filetype); } static void event_ffmpeg_newfile(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { - int width=cnt->imgs.width; - int height=cnt->imgs.height; - unsigned char *convbuf, *y, *u, *v; - int fps=0; - char stamp[PATH_MAX]; - const char *mpegpath; + int width = cnt->imgs.width; + int height = cnt->imgs.height; + unsigned char *convbuf, *y, *u, *v; + int fps = 0; + char stamp[PATH_MAX]; + const char *mpegpath; - if (!cnt->conf.ffmpeg_cap_new && !cnt->conf.ffmpeg_cap_motion) - return; - - /* conf.mpegpath would normally be defined but if someone deleted it by control interface - it is better to revert to the default than fail */ - if (cnt->conf.mpegpath) - mpegpath = cnt->conf.mpegpath; - else - mpegpath = DEF_MPEGPATH; + if (!cnt->conf.ffmpeg_cap_new && !cnt->conf.ffmpeg_cap_motion) + return; + + /* conf.mpegpath would normally be defined but if someone deleted it by control interface + it is better to revert to the default than fail */ + if (cnt->conf.mpegpath) + mpegpath = cnt->conf.mpegpath; + else + mpegpath = DEF_MPEGPATH; - mystrftime(cnt, stamp, sizeof(stamp), mpegpath, currenttime_tm, NULL, 0); + mystrftime(cnt, stamp, sizeof(stamp), mpegpath, currenttime_tm, NULL, 0); - /* motion mpegs get the same name as normal mpegs plus an appended 'm' */ - /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */ - snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%sm", cnt->conf.filepath, stamp); - snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); + /* motion mpegs get the same name as normal mpegs plus an appended 'm' */ + /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */ + snprintf(cnt->motionfilename, PATH_MAX - 4, "%s/%sm", cnt->conf.filepath, stamp); + snprintf(cnt->newfilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); - if (cnt->conf.ffmpeg_cap_new) { - if (cnt->imgs.type==VIDEO_PALETTE_GREY) { - convbuf=mymalloc((width*height)/2); - y=img; - u=convbuf; - v=convbuf+(width*height)/4; - grey2yuv420p(u, v, width, height); - } else { - convbuf=NULL; - y=img; - u=img+width*height; - v=u+(width*height)/4; - } - fps=cnt->lastrate; + if (cnt->conf.ffmpeg_cap_new) { + if (cnt->imgs.type == VIDEO_PALETTE_GREY) { + convbuf=mymalloc((width * height) / 2); + y = img; + u = convbuf; + v = convbuf + (width * height) / 4; + grey2yuv420p(u, v, width, height); + } else { + convbuf = NULL; + y = img; + u = img + width * height; + v = u + (width * height) / 4; + } + fps=cnt->lastrate; - if (debug_level >= CAMERA_DEBUG) - motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,fps); + if (debug_level >= CAMERA_DEBUG) + motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__, fps); - if (fps>30) - fps=30; - if (fps<2) - fps=2; - if ( (cnt->ffmpeg_new = - ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->newfilename, y, u, v, - cnt->imgs.width, cnt->imgs.height, fps, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL) { - motion_log(LOG_ERR, 1, "ffopen_open error creating (new) file [%s]",cnt->newfilename); - cnt->finish=1; - return; - } - ((struct ffmpeg *)cnt->ffmpeg_new)->udata=convbuf; - event(cnt, EVENT_FILECREATE, NULL, cnt->newfilename, (void *)FTYPE_MPEG, NULL); - } - if (cnt->conf.ffmpeg_cap_motion) { - if (cnt->imgs.type==VIDEO_PALETTE_GREY) { - convbuf=mymalloc((width*height)/2); - y=cnt->imgs.out; - u=convbuf; - v=convbuf+(width*height)/4; - grey2yuv420p(u, v, width, height); - } else { - y=cnt->imgs.out; - u=cnt->imgs.out+width*height; - v=u+(width*height)/4; - convbuf=NULL; - } + if (fps > 30) + fps = 30; + else if (fps < 2) + fps = 2; - if (debug_level >= CAMERA_DEBUG) - motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,fps); + if ((cnt->ffmpeg_new = + ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->newfilename, y, u, v, + cnt->imgs.width, cnt->imgs.height, fps, cnt->conf.ffmpeg_bps, + cnt->conf.ffmpeg_vbr)) == NULL) { + motion_log(LOG_ERR, 1, "ffopen_open error creating (new) file [%s]",cnt->newfilename); + cnt->finish = 1; + return; + } + ((struct ffmpeg *)cnt->ffmpeg_new)->udata=convbuf; + event(cnt, EVENT_FILECREATE, NULL, cnt->newfilename, (void *)FTYPE_MPEG, NULL); + } - fps=cnt->lastrate; - if (fps>30) - fps=30; - if (fps<2) - fps=2; - if ( (cnt->ffmpeg_motion = - ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->motionfilename, y, u, v, - cnt->imgs.width, cnt->imgs.height, fps, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL){ - motion_log(LOG_ERR, 1, "ffopen_open error creating (motion) file [%s]", cnt->motionfilename); - cnt->finish=1; - return; - } - cnt->ffmpeg_motion->udata=convbuf; - event(cnt, EVENT_FILECREATE, NULL, cnt->motionfilename, (void *)FTYPE_MPEG_MOTION, NULL); - } + if (cnt->conf.ffmpeg_cap_motion) { + if (cnt->imgs.type == VIDEO_PALETTE_GREY) { + convbuf = mymalloc((width * height) / 2); + y = cnt->imgs.out; + u = convbuf; + v = convbuf + (width * height) / 4; + grey2yuv420p(u, v, width, height); + } else { + y = cnt->imgs.out; + u = cnt->imgs.out + width * height; + v = u + (width * height) / 4; + convbuf = NULL; + } + + if (debug_level >= CAMERA_DEBUG) + motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__, fps); + + fps = cnt->lastrate; + + if (fps > 30) + fps = 30; + else if (fps < 2) + fps = 2; + + if ((cnt->ffmpeg_motion = + ffmpeg_open((char *)cnt->conf.ffmpeg_video_codec, cnt->motionfilename, y, u, v, + cnt->imgs.width, cnt->imgs.height, fps, cnt->conf.ffmpeg_bps, + cnt->conf.ffmpeg_vbr)) == NULL){ + motion_log(LOG_ERR, 1, "ffopen_open error creating (motion) file [%s]", cnt->motionfilename); + cnt->finish=1; + return; + } + cnt->ffmpeg_motion->udata = convbuf; + event(cnt, EVENT_FILECREATE, NULL, cnt->motionfilename, (void *)FTYPE_MPEG_MOTION, NULL); + } } static void event_ffmpeg_timelapse(struct context *cnt, @@ -454,87 +464,86 @@ static void event_ffmpeg_timelapse(struct context *cnt, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *currenttime_tm) { - int width = cnt->imgs.width; - int height = cnt->imgs.height; - unsigned char *convbuf, *y, *u, *v; + int width = cnt->imgs.width; + int height = cnt->imgs.height; + unsigned char *convbuf, *y, *u, *v; - if (!cnt->ffmpeg_timelapse) { - char tmp[PATH_MAX]; - const char *timepath; + if (!cnt->ffmpeg_timelapse) { + char tmp[PATH_MAX]; + const char *timepath; - /* conf.timepath would normally be defined but if someone deleted it by control interface - it is better to revert to the default than fail */ - if (cnt->conf.timepath) - timepath = cnt->conf.timepath; - else - timepath = DEF_TIMEPATH; - - mystrftime(cnt, tmp, sizeof(tmp), timepath, currenttime_tm, NULL, 0); - - /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */ - snprintf(cnt->timelapsefilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, tmp); - - if (cnt->imgs.type == VIDEO_PALETTE_GREY) { - convbuf = mymalloc((width*height)/2); - y = img; - u = convbuf; - v = convbuf+(width*height)/4; - grey2yuv420p(u, v, width, height); - } else { - convbuf = NULL; - y = img; - u = img+width*height; - v = u+(width*height)/4; - } - - if ( (cnt->ffmpeg_timelapse = - ffmpeg_open((char *)TIMELAPSE_CODEC, cnt->timelapsefilename, y, u, v, - cnt->imgs.width, cnt->imgs.height, 24, cnt->conf.ffmpeg_bps, - cnt->conf.ffmpeg_vbr)) == NULL) { - motion_log(LOG_ERR, 1, "ffopen_open error creating (timelapse) file [%s]", cnt->timelapsefilename); - cnt->finish=1; - return; - } - - cnt->ffmpeg_timelapse->udata = convbuf; - event(cnt, EVENT_FILECREATE, NULL, cnt->timelapsefilename, (void *)FTYPE_MPEG_TIMELAPSE, NULL); - } - - y = img; - - if (cnt->imgs.type == VIDEO_PALETTE_GREY) - u = cnt->ffmpeg_timelapse->udata; - else - u = img+width*height; - - v = u+(width*height)/4; - ffmpeg_put_other_image(cnt->ffmpeg_timelapse, y, u, v); - + /* conf.timepath would normally be defined but if someone deleted it by control interface + it is better to revert to the default than fail */ + if (cnt->conf.timepath) + timepath = cnt->conf.timepath; + else + timepath = DEF_TIMEPATH; + + mystrftime(cnt, tmp, sizeof(tmp), timepath, currenttime_tm, NULL, 0); + + /* PATH_MAX - 4 to allow for .mpg to be appended without overflow */ + snprintf(cnt->timelapsefilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, tmp); + + if (cnt->imgs.type == VIDEO_PALETTE_GREY) { + convbuf = mymalloc((width * height) / 2); + y = img; + u = convbuf; + v = convbuf+(width * height) / 4; + grey2yuv420p(u, v, width, height); + } else { + convbuf = NULL; + y = img; + u = img + width * height; + v = u + (width * height) / 4; + } + + if ((cnt->ffmpeg_timelapse = + ffmpeg_open((char *)TIMELAPSE_CODEC, cnt->timelapsefilename, y, u, v, + cnt->imgs.width, cnt->imgs.height, 24, cnt->conf.ffmpeg_bps, + cnt->conf.ffmpeg_vbr)) == NULL) { + motion_log(LOG_ERR, 1, "ffopen_open error creating (timelapse) file [%s]", cnt->timelapsefilename); + cnt->finish=1; + return; + } + + cnt->ffmpeg_timelapse->udata = convbuf; + event(cnt, EVENT_FILECREATE, NULL, cnt->timelapsefilename, (void *)FTYPE_MPEG_TIMELAPSE, NULL); + } + + y = img; + + if (cnt->imgs.type == VIDEO_PALETTE_GREY) + u = cnt->ffmpeg_timelapse->udata; + else + u = img + width * height; + + v = u + (width * height) / 4; + ffmpeg_put_other_image(cnt->ffmpeg_timelapse, y, u, v); + } static void event_ffmpeg_put(struct context *cnt, int type ATTRIBUTE_UNUSED, unsigned char *img, char *dummy1 ATTRIBUTE_UNUSED, void *dummy2 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->ffmpeg_new) - { - int width=cnt->imgs.width; - int height=cnt->imgs.height; - unsigned char *y = img; - unsigned char *u, *v; - - if (cnt->imgs.type == VIDEO_PALETTE_GREY) - u = cnt->ffmpeg_timelapse->udata; - else - u = y + (width * height); - - v = u + (width * height) / 4; - ffmpeg_put_other_image(cnt->ffmpeg_new, y, u, v); - } - - if (cnt->ffmpeg_motion) { - ffmpeg_put_image(cnt->ffmpeg_motion); - } + if (cnt->ffmpeg_new) { + int width=cnt->imgs.width; + int height=cnt->imgs.height; + unsigned char *y = img; + unsigned char *u, *v; + + if (cnt->imgs.type == VIDEO_PALETTE_GREY) + u = cnt->ffmpeg_timelapse->udata; + else + u = y + (width * height); + + v = u + (width * height) / 4; + ffmpeg_put_other_image(cnt->ffmpeg_new, y, u, v); + } + + if (cnt->ffmpeg_motion) + ffmpeg_put_image(cnt->ffmpeg_motion); + } static void event_ffmpeg_closefile(struct context *cnt, @@ -542,23 +551,25 @@ static void event_ffmpeg_closefile(struct context *cnt, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - - if (cnt->ffmpeg_new) { - if (cnt->ffmpeg_new->udata) - free(cnt->ffmpeg_new->udata); - ffmpeg_close(cnt->ffmpeg_new); - cnt->ffmpeg_new=NULL; + + if (cnt->ffmpeg_new) { + if (cnt->ffmpeg_new->udata) + free(cnt->ffmpeg_new->udata); + ffmpeg_close(cnt->ffmpeg_new); + cnt->ffmpeg_new = NULL; - event(cnt, EVENT_FILECLOSE, NULL, cnt->newfilename, (void *)FTYPE_MPEG, NULL); - } - if (cnt->ffmpeg_motion) { - if (cnt->ffmpeg_motion->udata) - free(cnt->ffmpeg_motion->udata); - ffmpeg_close(cnt->ffmpeg_motion); - cnt->ffmpeg_motion=NULL; + event(cnt, EVENT_FILECLOSE, NULL, cnt->newfilename, (void *)FTYPE_MPEG, NULL); + } - event(cnt, EVENT_FILECLOSE, NULL, cnt->motionfilename, (void *)FTYPE_MPEG_MOTION, NULL); - } + if (cnt->ffmpeg_motion) { + if (cnt->ffmpeg_motion->udata) + free(cnt->ffmpeg_motion->udata); + + ffmpeg_close(cnt->ffmpeg_motion); + cnt->ffmpeg_motion = NULL; + + event(cnt, EVENT_FILECLOSE, NULL, cnt->motionfilename, (void *)FTYPE_MPEG_MOTION, NULL); + } } static void event_ffmpeg_timelapseend(struct context *cnt, @@ -566,123 +577,123 @@ static void event_ffmpeg_timelapseend(struct context *cnt, char *dummy2 ATTRIBUTE_UNUSED, void *dummy3 ATTRIBUTE_UNUSED, struct tm *tm ATTRIBUTE_UNUSED) { - if (cnt->ffmpeg_timelapse) { - if (cnt->ffmpeg_timelapse->udata) - free(cnt->ffmpeg_timelapse->udata); - ffmpeg_close(cnt->ffmpeg_timelapse); - cnt->ffmpeg_timelapse=NULL; + if (cnt->ffmpeg_timelapse) { + if (cnt->ffmpeg_timelapse->udata) + free(cnt->ffmpeg_timelapse->udata); + ffmpeg_close(cnt->ffmpeg_timelapse); + cnt->ffmpeg_timelapse = NULL; - event(cnt, EVENT_FILECLOSE, NULL, cnt->timelapsefilename, (void *)FTYPE_MPEG_TIMELAPSE, NULL); - } + event(cnt, EVENT_FILECLOSE, NULL, cnt->timelapsefilename, (void *)FTYPE_MPEG_TIMELAPSE, NULL); + } } #endif /* HAVE_FFMPEG */ /* - * Starting point for all events + * Starting point for all events */ struct event_handlers { - int type; - event_handler handler; + int type; + event_handler handler; }; struct event_handlers event_handlers[] = { #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) - { - EVENT_FILECREATE, - event_sqlnewfile - }, + { + EVENT_FILECREATE, + event_sqlnewfile + }, #endif - { - EVENT_FILECREATE, - on_picture_save_command - }, - { - EVENT_FILECREATE, - event_newfile - }, + { + EVENT_FILECREATE, + on_picture_save_command + }, + { + EVENT_FILECREATE, + event_newfile + }, - { - EVENT_MOTION, - event_beep - }, - { - EVENT_MOTION, - on_motion_detected_command - }, - { - EVENT_AREA_DETECTED, - on_area_command - }, - { - EVENT_FIRSTMOTION, - on_event_start_command - }, - { - EVENT_ENDMOTION, - on_event_end_command - }, - { - EVENT_IMAGE_DETECTED, - event_image_detect - }, - { - EVENT_IMAGEM_DETECTED, - event_imagem_detect - }, - { - EVENT_IMAGE_SNAPSHOT, - event_image_snapshot - }, + { + EVENT_MOTION, + event_beep + }, + { + EVENT_MOTION, + on_motion_detected_command + }, + { + EVENT_AREA_DETECTED, + on_area_command + }, + { + EVENT_FIRSTMOTION, + on_event_start_command + }, + { + EVENT_ENDMOTION, + on_event_end_command + }, + { + EVENT_IMAGE_DETECTED, + event_image_detect + }, + { + EVENT_IMAGEM_DETECTED, + event_imagem_detect + }, + { + EVENT_IMAGE_SNAPSHOT, + event_image_snapshot + }, #ifndef WITHOUT_V4L #if (!defined(BSD)) - { - EVENT_IMAGE | EVENT_IMAGEM, - event_vid_putpipe - }, + { + EVENT_IMAGE | EVENT_IMAGEM, + event_vid_putpipe + }, #endif /* BSD */ #endif /* WITHOUT_V4L */ - { - EVENT_WEBCAM, - event_webcam_put - }, + { + EVENT_WEBCAM, + event_webcam_put + }, #ifdef HAVE_FFMPEG - { - EVENT_FIRSTMOTION, - event_ffmpeg_newfile - }, - { - EVENT_IMAGE_DETECTED, - event_ffmpeg_put - }, - { - EVENT_ENDMOTION, - event_ffmpeg_closefile - }, - { - EVENT_TIMELAPSE, - event_ffmpeg_timelapse - }, - { - EVENT_TIMELAPSEEND, - event_ffmpeg_timelapseend - }, - { - EVENT_FILECLOSE, - on_movie_end_command - }, + { + EVENT_FIRSTMOTION, + event_ffmpeg_newfile + }, + { + EVENT_IMAGE_DETECTED, + event_ffmpeg_put + }, + { + EVENT_ENDMOTION, + event_ffmpeg_closefile + }, + { + EVENT_TIMELAPSE, + event_ffmpeg_timelapse + }, + { + EVENT_TIMELAPSEEND, + event_ffmpeg_timelapseend + }, + { + EVENT_FILECLOSE, + on_movie_end_command + }, #endif /* HAVE_FFMPEG */ - { - EVENT_CAMERA_LOST, - event_camera_lost - }, - { - EVENT_STOP, - event_stop_webcam - }, - {0, NULL} + { + EVENT_CAMERA_LOST, + event_camera_lost + }, + { + EVENT_STOP, + event_stop_webcam + }, + {0, NULL} }; @@ -698,10 +709,10 @@ struct event_handlers event_handlers[] = { */ void event(struct context *cnt, int type, unsigned char *image, char *filename, void *eventdata, struct tm *tm) { - int i=-1; + int i = -1; - while (event_handlers[++i].handler) { - if (type & event_handlers[i].type) - event_handlers[i].handler(cnt, type, image, filename, eventdata, tm); - } + while (event_handlers[++i].handler) { + if (type & event_handlers[i].type) + event_handlers[i].handler(cnt, type, image, filename, eventdata, tm); + } } diff --git a/ffmpeg.c b/ffmpeg.c index 47d0a5d8..6063a33f 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -20,20 +20,20 @@ * non-standard framerates. Previous builds contained a broken hack * that padded with B frames to obtain the correct framerate. */ -# define FFMPEG_NO_NONSTD_MPEG1 -# ifdef __GNUC__ +# define FFMPEG_NO_NONSTD_MPEG1 +# ifdef __GNUC__ /* #warning is a non-standard gcc extension */ -# warning ************************************************** -# warning Your version of FFmpeg is newer than version 0.4.8 -# warning Newer versions of ffmpeg do not support MPEG1 with -# warning non-standard framerate. MPEG1 will be disabled for -# warning normal video output. You can still use mpeg4 and -# warning and mpeg4ms which are both better in terms of size -# warning and quality. MPEG1 is always used for timelapse. -# warning Please read the Motion Guide for more information. -# warning Note that this is not an error message! -# warning ************************************************** -# endif /* __GNUC__ */ +# warning ************************************************** +# warning Your version of FFmpeg is newer than version 0.4.8 +# warning Newer versions of ffmpeg do not support MPEG1 with +# warning non-standard framerate. MPEG1 will be disabled for +# warning normal video output. You can still use mpeg4 and +# warning and mpeg4ms which are both better in terms of size +# warning and quality. MPEG1 is always used for timelapse. +# warning Please read the Motion Guide for more information. +# warning Note that this is not an error message! +# warning ************************************************** +# endif /* __GNUC__ */ #endif /* LIBAVCODEC_BUILD > 4680 */ @@ -42,7 +42,7 @@ * It now uses an AVPacket struct instead of direct parameters to the * function. The */ -# define FFMPEG_AVWRITEFRAME_NEWAPI +# define FFMPEG_AVWRITEFRAME_NEWAPI #endif /* LIBAVFORMAT_BUILD >= 4616 */ #if LIBAVFORMAT_BUILD >= 4629 @@ -50,9 +50,9 @@ * was changed to a pointer so changes to AVCodecContext shouldn't * break binary compatibility with AVStream. */ -# define AVSTREAM_CODEC_PTR(avs_ptr) (avs_ptr->codec) +# define AVSTREAM_CODEC_PTR(avs_ptr) (avs_ptr->codec) #else -# define AVSTREAM_CODEC_PTR(avs_ptr) (&avs_ptr->codec) +# define AVSTREAM_CODEC_PTR(avs_ptr) (&avs_ptr->codec) #endif /* LIBAVFORMAT_BUILD >= 4629 */ /* Name of custom file protocol for appending to existing files instead @@ -75,29 +75,29 @@ static unsigned char mpeg1_trailer[] = {0x00, 0x00, 0x01, 0xb7}; */ static int file_open_append(URLContext *h, const char *filename, int flags) { - const char *colon; - int access_flags, fd; + const char *colon; + int access_flags, fd; - /* Skip past the protocol part of filename. */ - colon = strchr(filename, ':'); - if (colon) { - filename = colon + 1; - } + /* Skip past the protocol part of filename. */ + colon = strchr(filename, ':'); + if (colon) + filename = colon + 1; + - if (flags & URL_RDWR) { - access_flags = O_CREAT | O_APPEND | O_RDWR; - } else if (flags & URL_WRONLY) { - access_flags = O_CREAT | O_APPEND | O_WRONLY; - } else { - access_flags = O_RDONLY; - } + if (flags & URL_RDWR) { + access_flags = O_CREAT | O_APPEND | O_RDWR; + } else if (flags & URL_WRONLY) { + access_flags = O_CREAT | O_APPEND | O_WRONLY; + } else { + access_flags = O_RDONLY; + } - fd = open(filename, access_flags, 0666); - if (fd < 0) { - return AVERROR(ENOENT); - } - h->priv_data = (void *)(size_t)fd; - return 0; + fd = open(filename, access_flags, 0666); + if (fd < 0) + return AVERROR(ENOENT); + + h->priv_data = (void *)(size_t)fd; + return 0; } /* URLProtocol entry for the append file protocol, which we use for mpeg1 videos @@ -110,8 +110,8 @@ static int file_open_append(URLContext *h, const char *filename, int flags) * The remaining functions (for writing, seeking etc.) are set in ffmpeg_init. */ URLProtocol mpeg1_file_protocol = { - .name = APPEND_PROTO, - .url_open = file_open_append + .name = APPEND_PROTO, + .url_open = file_open_append }; @@ -130,58 +130,59 @@ URLProtocol mpeg1_file_protocol = { static int file_open(URLContext *h, const char *filename, int flags) { - int access_flags, fd; + int access_flags, fd; - av_strstart(filename, "file:", &filename); + av_strstart(filename, "file:", &filename); - if (flags & URL_RDWR) { - access_flags = O_CREAT | O_TRUNC | O_RDWR; - } else if (flags & URL_WRONLY) { - access_flags = O_CREAT | O_TRUNC | O_WRONLY; - } else { - access_flags = O_RDONLY; - } + if (flags & URL_RDWR) { + access_flags = O_CREAT | O_TRUNC | O_RDWR; + } else if (flags & URL_WRONLY) { + access_flags = O_CREAT | O_TRUNC | O_WRONLY; + } else { + access_flags = O_RDONLY; + } #ifdef O_BINARY - access_flags |= O_BINARY; + access_flags |= O_BINARY; #endif - fd = open(filename, access_flags, 0666); - if (fd < 0) - return AVERROR(ENOENT); - h->priv_data = (void *)(size_t)fd; - return 0; + fd = open(filename, access_flags, 0666); + if (fd < 0) + return AVERROR(ENOENT); + + h->priv_data = (void *)(size_t)fd; + return 0; } static int file_read(URLContext *h, unsigned char *buf, int size) { - int fd = (size_t)h->priv_data; - return read(fd, buf, size); + int fd = (size_t)h->priv_data; + return read(fd, buf, size); } static int file_write(URLContext *h, unsigned char *buf, int size) { - int fd = (size_t)h->priv_data; - return write(fd, buf, size); + int fd = (size_t)h->priv_data; + return write(fd, buf, size); } static offset_t file_seek(URLContext *h, offset_t pos, int whence) { - int fd = (size_t)h->priv_data; - return lseek(fd, pos, whence); + int fd = (size_t)h->priv_data; + return lseek(fd, pos, whence); } static int file_close(URLContext *h) { - int fd = (size_t)h->priv_data; - return close(fd); + int fd = (size_t)h->priv_data; + return close(fd); } URLProtocol file_protocol = { - "file", - file_open, - file_read, - file_write, - file_seek, - file_close, + "file", + file_open, + file_read, + file_write, + file_seek, + file_close, }; #endif @@ -193,36 +194,36 @@ URLProtocol file_protocol = { static int mpeg1_write_trailer(AVFormatContext *s) { #if LIBAVFORMAT_BUILD >= (52<<16) - put_buffer(s->pb, mpeg1_trailer, 4); - put_flush_packet(s->pb); + put_buffer(s->pb, mpeg1_trailer, 4); + put_flush_packet(s->pb); #else - put_buffer(&s->pb, mpeg1_trailer, 4); - put_flush_packet(&s->pb); + put_buffer(&s->pb, mpeg1_trailer, 4); + put_flush_packet(&s->pb); #endif /* LIBAVFORMAT_BUILD >= (52<<16) */ - return 0; /* success */ + return 0; /* success */ } /* ffmpeg_init initializes for libavformat. */ void ffmpeg_init() { - motion_log(LOG_INFO, 0, "ffmpeg LIBAVCODEC_BUILD %d LIBAVFORMAT_BUILD %d", LIBAVCODEC_BUILD, LIBAVFORMAT_BUILD); - av_register_all(); + motion_log(LOG_INFO, 0, "ffmpeg LIBAVCODEC_BUILD %d LIBAVFORMAT_BUILD %d", LIBAVCODEC_BUILD, LIBAVFORMAT_BUILD); + av_register_all(); #if LIBAVCODEC_BUILD > 4680 - av_log_set_callback( (void *)ffmpeg_avcodec_log ); + av_log_set_callback( (void *)ffmpeg_avcodec_log ); #endif - /* Copy the functions to use for the append file protocol from the standard - * file protocol. - */ - mpeg1_file_protocol.url_read = file_protocol.url_read; - mpeg1_file_protocol.url_write = file_protocol.url_write; - mpeg1_file_protocol.url_seek = file_protocol.url_seek; - mpeg1_file_protocol.url_close = file_protocol.url_close; + /* Copy the functions to use for the append file protocol from the standard + * file protocol. + */ + mpeg1_file_protocol.url_read = file_protocol.url_read; + mpeg1_file_protocol.url_write = file_protocol.url_write; + mpeg1_file_protocol.url_seek = file_protocol.url_seek; + mpeg1_file_protocol.url_close = file_protocol.url_close; - /* Register the append file protocol. */ - register_protocol(&mpeg1_file_protocol); + /* Register the append file protocol. */ + register_protocol(&mpeg1_file_protocol); } /* Obtains the output format used for the specified codec. For mpeg4 codecs, @@ -231,74 +232,74 @@ void ffmpeg_init() */ static AVOutputFormat *get_oformat(const char *codec, char *filename) { - const char *ext; - AVOutputFormat *of = NULL; + const char *ext; + AVOutputFormat *of = NULL; - /* Here, we use guess_format to automatically setup the codec information. - * If we are using msmpeg4, manually set that codec here. - * We also dynamically add the file extension to the filename here. This was - * done to support both mpeg1 and mpeg4 codecs since they have different extensions. - */ - if ((strcmp(codec, TIMELAPSE_CODEC) == 0) + /* Here, we use guess_format to automatically setup the codec information. + * If we are using msmpeg4, manually set that codec here. + * We also dynamically add the file extension to the filename here. This was + * done to support both mpeg1 and mpeg4 codecs since they have different extensions. + */ + if ((strcmp(codec, TIMELAPSE_CODEC) == 0) #ifndef FFMPEG_NO_NONSTD_MPEG1 - || (strcmp(codec, "mpeg1") == 0) + || (strcmp(codec, "mpeg1") == 0) #endif - ) { - ext = ".mpg"; - /* We use "mpeg1video" for raw mpeg1 format. Using "mpeg" would - * result in a muxed output file, which isn't appropriate here. - */ - of = guess_format("mpeg1video", NULL, NULL); - if (of) { - /* But we want the trailer to be correctly written. */ - of->write_trailer = mpeg1_write_trailer; - } + ) { + ext = ".mpg"; + /* We use "mpeg1video" for raw mpeg1 format. Using "mpeg" would + * result in a muxed output file, which isn't appropriate here. + */ + of = guess_format("mpeg1video", NULL, NULL); + if (of) { + /* But we want the trailer to be correctly written. */ + of->write_trailer = mpeg1_write_trailer; + } #ifdef FFMPEG_NO_NONSTD_MPEG1 - } else if (strcmp(codec, "mpeg1") == 0) { - motion_log(LOG_ERR, 0, "*** mpeg1 support for normal videos has been disabled ***"); - return NULL; + } else if (strcmp(codec, "mpeg1") == 0) { + motion_log(LOG_ERR, 0, "*** mpeg1 support for normal videos has been disabled ***"); + return NULL; #endif - } else if (strcmp(codec, "mpeg4") == 0) { - ext = ".avi"; - of = guess_format("avi", NULL, NULL); - } else if (strcmp(codec, "msmpeg4") == 0) { - ext = ".avi"; - of = guess_format("avi", NULL, NULL); - if (of) { - /* Manually override the codec id. */ - of->video_codec = CODEC_ID_MSMPEG4V2; - } - } else if (strcmp(codec, "swf") == 0) { - ext = ".swf"; - of = guess_format("swf", NULL, NULL); - } else if (strcmp(codec, "flv") == 0) { - ext = ".flv"; - of = guess_format("flv", NULL, NULL); - } else if (strcmp(codec, "ffv1") == 0) { - ext = ".avi"; - of = guess_format("avi", NULL, NULL); - if (of) { - /* Use the FFMPEG Lossless Video codec (experimental!). - Requires strict_std_compliance to be <= -2 */ - of->video_codec = CODEC_ID_FLV1; - } - } else if (strcmp(codec, "mov") == 0) { - ext = ".mov"; - of = guess_format("mov", NULL, NULL); - } else { - motion_log(LOG_ERR, 0, "ffmpeg_video_codec option value %s is not supported", codec); - return NULL; - } + } else if (strcmp(codec, "mpeg4") == 0) { + ext = ".avi"; + of = guess_format("avi", NULL, NULL); + } else if (strcmp(codec, "msmpeg4") == 0) { + ext = ".avi"; + of = guess_format("avi", NULL, NULL); + if (of) { + /* Manually override the codec id. */ + of->video_codec = CODEC_ID_MSMPEG4V2; + } + } else if (strcmp(codec, "swf") == 0) { + ext = ".swf"; + of = guess_format("swf", NULL, NULL); + } else if (strcmp(codec, "flv") == 0) { + ext = ".flv"; + of = guess_format("flv", NULL, NULL); + } else if (strcmp(codec, "ffv1") == 0) { + ext = ".avi"; + of = guess_format("avi", NULL, NULL); + if (of) { + /* Use the FFMPEG Lossless Video codec (experimental!). + Requires strict_std_compliance to be <= -2 */ + of->video_codec = CODEC_ID_FLV1; + } + } else if (strcmp(codec, "mov") == 0) { + ext = ".mov"; + of = guess_format("mov", NULL, NULL); + } else { + motion_log(LOG_ERR, 0, "ffmpeg_video_codec option value %s is not supported", codec); + return NULL; + } - if (!of) { - motion_log(LOG_ERR, 0, "Could not guess format for %s", codec); - return NULL; - } + if (!of) { + motion_log(LOG_ERR, 0, "Could not guess format for %s", codec); + return NULL; + } - /* The 4 allows for ".avi" or ".mpg" to be appended */ - strncat(filename, ext, 4); + /* The 4 allows for ".avi" or ".mpg" to be appended */ + strncat(filename, ext, 4); - return of; + return of; } /* This function opens an mpeg file using the new libavformat method. Both mpeg1 @@ -310,214 +311,218 @@ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, unsigned char *y, unsigned char *u, unsigned char *v, int width, int height, int rate, int bps, int vbr) { - AVCodecContext *c; - AVCodec *codec; - struct ffmpeg *ffmpeg; - int is_mpeg1; + AVCodecContext *c; + AVCodec *codec; + struct ffmpeg *ffmpeg; + int is_mpeg1; - /* Allocate space for our ffmpeg structure. This structure contains all the - * codec and image information we need to generate movies. - * FIXME when motion exits we should close the movie to ensure that - * ffmpeg is freed. - */ - ffmpeg = mymalloc(sizeof(struct ffmpeg)); - memset(ffmpeg, 0, sizeof(struct ffmpeg)); + /* Allocate space for our ffmpeg structure. This structure contains all the + * codec and image information we need to generate movies. + * FIXME when motion exits we should close the movie to ensure that + * ffmpeg is freed. + */ + ffmpeg = mymalloc(sizeof(struct ffmpeg)); + memset(ffmpeg, 0, sizeof(struct ffmpeg)); - ffmpeg->vbr = vbr; - - /* store codec name in ffmpeg->codec, with buffer overflow check */ - snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); + ffmpeg->vbr = vbr; + + /* store codec name in ffmpeg->codec, with buffer overflow check */ + snprintf(ffmpeg->codec, sizeof(ffmpeg->codec), "%s", ffmpeg_video_codec); - /* allocation the output media context */ - ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); - if (!ffmpeg->oc) { - motion_log(LOG_ERR, 1, "Memory error while allocating output media context"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + /* allocation the output media context */ + ffmpeg->oc = av_mallocz(sizeof(AVFormatContext)); - /* Setup output format */ - ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); - if (!ffmpeg->oc->oformat) { - ffmpeg_cleanups(ffmpeg); - return NULL; - } + if (!ffmpeg->oc) { + motion_log(LOG_ERR, 1, "Memory error while allocating output media context"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } - snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); + /* Setup output format */ + ffmpeg->oc->oformat = get_oformat(ffmpeg_video_codec, filename); - /* Create a new video stream and initialize the codecs */ - ffmpeg->video_st = NULL; - if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { - ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); - if (!ffmpeg->video_st) { - motion_log(LOG_ERR, 1, "av_new_stream - could not alloc stream"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } - } else { - /* We did not get a proper video codec. */ - motion_log(LOG_ERR, 0, "Failed to obtain a proper video codec"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + if (!ffmpeg->oc->oformat) { + ffmpeg_cleanups(ffmpeg); + return NULL; + } - ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); - c->codec_id = ffmpeg->oc->oformat->video_codec; - c->codec_type = CODEC_TYPE_VIDEO; - is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; + snprintf(ffmpeg->oc->filename, sizeof(ffmpeg->oc->filename), "%s", filename); - if (strcmp(ffmpeg_video_codec, "ffv1") == 0) - c->strict_std_compliance = -2; + /* Create a new video stream and initialize the codecs */ + ffmpeg->video_st = NULL; - /* Uncomment to allow non-standard framerates. */ - //c->strict_std_compliance = -1; + if (ffmpeg->oc->oformat->video_codec != CODEC_ID_NONE) { + ffmpeg->video_st = av_new_stream(ffmpeg->oc, 0); + if (!ffmpeg->video_st) { + motion_log(LOG_ERR, 1, "av_new_stream - could not alloc stream"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } + } else { + /* We did not get a proper video codec. */ + motion_log(LOG_ERR, 0, "Failed to obtain a proper video codec"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } - /* Set default parameters */ - c->bit_rate = bps; - c->width = width; - c->height = height; + ffmpeg->c = c = AVSTREAM_CODEC_PTR(ffmpeg->video_st); + c->codec_id = ffmpeg->oc->oformat->video_codec; + c->codec_type = CODEC_TYPE_VIDEO; + is_mpeg1 = c->codec_id == CODEC_ID_MPEG1VIDEO; + + if (strcmp(ffmpeg_video_codec, "ffv1") == 0) + c->strict_std_compliance = -2; + + /* Uncomment to allow non-standard framerates. */ + //c->strict_std_compliance = -1; + + /* Set default parameters */ + c->bit_rate = bps; + c->width = width; + c->height = height; #if LIBAVCODEC_BUILD >= 4754 - /* frame rate = 1/time_base, so we set 1/rate, not rate/1 */ - c->time_base.num = 1; - c->time_base.den = rate; + /* frame rate = 1/time_base, so we set 1/rate, not rate/1 */ + c->time_base.num = 1; + c->time_base.den = rate; #else - c->frame_rate = rate; - c->frame_rate_base = 1; + c->frame_rate = rate; + c->frame_rate_base = 1; #endif /* LIBAVCODEC_BUILD >= 4754 */ - if (debug_level >= CAMERA_DEBUG) - motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,rate); + if (debug_level >= CAMERA_DEBUG) + motion_log(LOG_DEBUG, 0, "%s FPS %d",__FUNCTION__,rate); - if (vbr) - c->flags |= CODEC_FLAG_QSCALE; + if (vbr) + c->flags |= CODEC_FLAG_QSCALE; - /* Set codec specific parameters. */ - /* set intra frame distance in frames depending on codec */ - c->gop_size = is_mpeg1 ? 10 : 12; - - /* some formats want stream headers to be separate */ - if(!strcmp(ffmpeg->oc->oformat->name, "mp4") || - !strcmp(ffmpeg->oc->oformat->name, "mov") || - !strcmp(ffmpeg->oc->oformat->name, "3gp")) { - c->flags |= CODEC_FLAG_GLOBAL_HEADER; - } + /* Set codec specific parameters. */ + /* set intra frame distance in frames depending on codec */ + c->gop_size = is_mpeg1 ? 10 : 12; + + /* some formats want stream headers to be separate */ + if (!strcmp(ffmpeg->oc->oformat->name, "mp4") || + !strcmp(ffmpeg->oc->oformat->name, "mov") || + !strcmp(ffmpeg->oc->oformat->name, "3gp")) { + c->flags |= CODEC_FLAG_GLOBAL_HEADER; + } - /* set the output parameters (must be done even if no parameters). */ - if (av_set_parameters(ffmpeg->oc, NULL) < 0) { - motion_log(LOG_ERR, 0, "ffmpeg av_set_parameters error: Invalid output format parameters"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + /* set the output parameters (must be done even if no parameters). */ + if (av_set_parameters(ffmpeg->oc, NULL) < 0) { + motion_log(LOG_ERR, 0, "ffmpeg av_set_parameters error: Invalid output format parameters"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } - /* Dump the format settings. This shows how the various streams relate to each other */ - //dump_format(ffmpeg->oc, 0, filename, 1); + /* Dump the format settings. This shows how the various streams relate to each other */ + //dump_format(ffmpeg->oc, 0, filename, 1); - /* Now that all the parameters are set, we can open the video - codec and allocate the necessary encode buffers */ - codec = avcodec_find_encoder(c->codec_id); - if (!codec) { - motion_log(LOG_ERR, 1, "Codec not found"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } - - /* Set the picture format - need in ffmpeg starting round April-May 2005 */ - c->pix_fmt = PIX_FMT_YUV420P; + /* Now that all the parameters are set, we can open the video + codec and allocate the necessary encode buffers */ + codec = avcodec_find_encoder(c->codec_id); - /* Get a mutex lock. */ - pthread_mutex_lock(&global_lock); + if (!codec) { + motion_log(LOG_ERR, 1, "Codec not found"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } + + /* Set the picture format - need in ffmpeg starting round April-May 2005 */ + c->pix_fmt = PIX_FMT_YUV420P; - /* open the codec */ - if (avcodec_open(c, codec) < 0) { - /* Release the lock. */ - pthread_mutex_unlock(&global_lock); - motion_log(LOG_ERR, 1, "avcodec_open - could not open codec"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + /* Get a mutex lock. */ + pthread_mutex_lock(&global_lock); - /* Release the lock. */ - pthread_mutex_unlock(&global_lock); + /* open the codec */ + if (avcodec_open(c, codec) < 0) { + /* Release the lock. */ + pthread_mutex_unlock(&global_lock); + motion_log(LOG_ERR, 1, "avcodec_open - could not open codec"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } + + /* Release the lock. */ + pthread_mutex_unlock(&global_lock); - ffmpeg->video_outbuf = NULL; - if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { - /* allocate output buffer */ - /* XXX: API change will be done */ - /* ffmpeg->video_outbuf_size = 20000; */ - ffmpeg->video_outbuf_size = ffmpeg->c->width * 256; - ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); - } + ffmpeg->video_outbuf = NULL; + if (!(ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE)) { + /* allocate output buffer */ + /* XXX: API change will be done */ + /* ffmpeg->video_outbuf_size = 20000; */ + ffmpeg->video_outbuf_size = ffmpeg->c->width * 256; + ffmpeg->video_outbuf = mymalloc(ffmpeg->video_outbuf_size); + } - /* allocate the encoded raw picture */ - ffmpeg->picture = avcodec_alloc_frame(); - if (!ffmpeg->picture) { - motion_log(LOG_ERR, 1, "avcodec_alloc_frame - could not alloc frame"); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + /* allocate the encoded raw picture */ + ffmpeg->picture = avcodec_alloc_frame(); + if (!ffmpeg->picture) { + motion_log(LOG_ERR, 1, "avcodec_alloc_frame - could not alloc frame"); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } - /* set variable bitrate if requested */ - if (ffmpeg->vbr) { - ffmpeg->picture->quality = ffmpeg->vbr; - } + /* set variable bitrate if requested */ + if (ffmpeg->vbr) + ffmpeg->picture->quality = ffmpeg->vbr; + - /* set the frame data */ - ffmpeg->picture->data[0] = y; - ffmpeg->picture->data[1] = u; - ffmpeg->picture->data[2] = v; - ffmpeg->picture->linesize[0] = ffmpeg->c->width; - ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; - ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; + /* set the frame data */ + ffmpeg->picture->data[0] = y; + ffmpeg->picture->data[1] = u; + ffmpeg->picture->data[2] = v; + ffmpeg->picture->linesize[0] = ffmpeg->c->width; + ffmpeg->picture->linesize[1] = ffmpeg->c->width / 2; + ffmpeg->picture->linesize[2] = ffmpeg->c->width / 2; - /* open the output file, if needed */ - if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { - char file_proto[256]; + /* open the output file, if needed */ + if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { + char file_proto[256]; - /* Use append file protocol for mpeg1, to get the append behavior from - * url_fopen, but no protocol (=> default) for other codecs. - */ - if(is_mpeg1) { - snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); - } else { - snprintf(file_proto, sizeof(file_proto), "%s", filename); - } + /* Use append file protocol for mpeg1, to get the append behavior from + * url_fopen, but no protocol (=> default) for other codecs. + */ + if (is_mpeg1) + snprintf(file_proto, sizeof(file_proto), APPEND_PROTO ":%s", filename); + else + snprintf(file_proto, sizeof(file_proto), "%s", filename); + - if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { - /* path did not exist? */ - if (errno == ENOENT) { - /* create path for file (don't use file_proto)... */ - if (create_path(filename) == -1) { - ffmpeg_cleanups(ffmpeg); - return (NULL); - } + if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { + /* path did not exist? */ + if (errno == ENOENT) { + /* create path for file (don't use file_proto)... */ + if (create_path(filename) == -1) { + ffmpeg_cleanups(ffmpeg); + return (NULL); + } - /* and retry opening the file (use file_proto) */ - if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { - motion_log(LOG_ERR, 1, "url_fopen - error opening file %s",filename); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } - /* Permission denied */ - } else if (errno == EACCES) { - motion_log(LOG_ERR, 1, - "url_fopen - error opening file %s" - " ... check access rights to target directory", filename); - /* create path for file... */ - ffmpeg_cleanups(ffmpeg); - return (NULL); - } else { - motion_log(LOG_ERR, 1, "Error opening file %s", filename); - ffmpeg_cleanups(ffmpeg); - return (NULL); - } - } - } + /* and retry opening the file (use file_proto) */ + if (url_fopen(&ffmpeg->oc->pb, file_proto, URL_WRONLY) < 0) { + motion_log(LOG_ERR, 1, "url_fopen - error opening file %s",filename); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } + /* Permission denied */ + } else if (errno == EACCES) { + motion_log(LOG_ERR, 1, + "url_fopen - error opening file %s" + " ... check access rights to target directory", filename); + /* create path for file... */ + ffmpeg_cleanups(ffmpeg); + return (NULL); + } else { + motion_log(LOG_ERR, 1, "Error opening file %s", filename); + ffmpeg_cleanups(ffmpeg); + return (NULL); + } + } + } - /* write the stream header, if any */ - av_write_header(ffmpeg->oc); - - return ffmpeg; + /* write the stream header, if any */ + av_write_header(ffmpeg->oc); + + return ffmpeg; } /* @@ -525,95 +530,95 @@ struct ffmpeg *ffmpeg_open(char *ffmpeg_video_codec, char *filename, */ void ffmpeg_cleanups(struct ffmpeg *ffmpeg) { - unsigned int i; + unsigned int i; - /* close each codec */ - if (ffmpeg->video_st) { - pthread_mutex_lock(&global_lock); + /* close each codec */ + if (ffmpeg->video_st) { + pthread_mutex_lock(&global_lock); #if LIBAVCODEC_BUILD > 4680 - if (ffmpeg->video_st->codec->priv_data != NULL) + if (ffmpeg->video_st->codec->priv_data != NULL) #endif - avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); - pthread_mutex_unlock(&global_lock); - av_freep(&ffmpeg->picture); - free(ffmpeg->video_outbuf); - } + avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); + pthread_mutex_unlock(&global_lock); + av_freep(&ffmpeg->picture); + free(ffmpeg->video_outbuf); + } - /* free the streams */ - for (i = 0; i < ffmpeg->oc->nb_streams; i++) { - av_freep(&ffmpeg->oc->streams[i]); - } + /* free the streams */ + for (i = 0; i < ffmpeg->oc->nb_streams; i++) + av_freep(&ffmpeg->oc->streams[i]); + /* - if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { - // close the output file - if (ffmpeg->oc->pb) url_fclose(&ffmpeg->oc->pb); - } + if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { + // close the output file + if (ffmpeg->oc->pb) url_fclose(&ffmpeg->oc->pb); + } */ - /* free the stream */ - av_free(ffmpeg->oc); + /* free the stream */ + av_free(ffmpeg->oc); #if LIBAVFORMAT_BUILD >= 4629 - av_free(ffmpeg->c); + av_free(ffmpeg->c); #endif - free(ffmpeg); + free(ffmpeg); } /* Closes a video file. */ void ffmpeg_close(struct ffmpeg *ffmpeg) { - unsigned int i; + unsigned int i; - /* close each codec */ - if (ffmpeg->video_st) { - pthread_mutex_lock(&global_lock); - avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); - pthread_mutex_unlock(&global_lock); - av_freep(&ffmpeg->picture); - free(ffmpeg->video_outbuf); - } + /* close each codec */ + if (ffmpeg->video_st) { + pthread_mutex_lock(&global_lock); + avcodec_close(AVSTREAM_CODEC_PTR(ffmpeg->video_st)); + pthread_mutex_unlock(&global_lock); + av_freep(&ffmpeg->picture); + free(ffmpeg->video_outbuf); + } - /* write the trailer, if any */ - av_write_trailer(ffmpeg->oc); + /* write the trailer, if any */ + av_write_trailer(ffmpeg->oc); - /* free the streams */ - for (i = 0; i < ffmpeg->oc->nb_streams; i++) { - av_freep(&ffmpeg->oc->streams[i]); - } + /* free the streams */ + for (i = 0; i < ffmpeg->oc->nb_streams; i++) + av_freep(&ffmpeg->oc->streams[i]); + - if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { - /* close the output file */ + if (!(ffmpeg->oc->oformat->flags & AVFMT_NOFILE)) { + /* close the output file */ #if LIBAVFORMAT_BUILD >= (52<<16) - url_fclose(ffmpeg->oc->pb); + url_fclose(ffmpeg->oc->pb); #else - url_fclose(&ffmpeg->oc->pb); + url_fclose(&ffmpeg->oc->pb); #endif /* LIBAVFORMAT_BUILD >= (52<<16) */ - } + } - /* free the stream */ - av_free(ffmpeg->oc); + /* free the stream */ + av_free(ffmpeg->oc); #if LIBAVFORMAT_BUILD >= 4629 - av_free(ffmpeg->c); + av_free(ffmpeg->c); #endif - free(ffmpeg); + free(ffmpeg); } /* Puts the image pointed to by ffmpeg->picture. */ void ffmpeg_put_image(struct ffmpeg *ffmpeg) { - ffmpeg_put_frame(ffmpeg, ffmpeg->picture); + ffmpeg_put_frame(ffmpeg, ffmpeg->picture); } /* Puts an arbitrary picture defined by y, u and v. */ void ffmpeg_put_other_image(struct ffmpeg *ffmpeg, unsigned char *y, unsigned char *u, unsigned char *v) { - AVFrame *picture; - /* allocate the encoded raw picture */ - picture = ffmpeg_prepare_frame(ffmpeg, y, u, v); + AVFrame *picture; + /* allocate the encoded raw picture */ + picture = ffmpeg_prepare_frame(ffmpeg, y, u, v); - if (picture) { - ffmpeg_put_frame(ffmpeg, picture); - av_free(picture); - } + if (picture) { + ffmpeg_put_frame(ffmpeg, picture); + av_free(picture); + } } /* Encodes and writes a video frame using the av_write_frame API. This is @@ -621,56 +626,56 @@ void ffmpeg_put_other_image(struct ffmpeg *ffmpeg, unsigned char *y, */ void ffmpeg_put_frame(struct ffmpeg *ffmpeg, AVFrame *pic) { - int out_size, ret; + int out_size, ret; #ifdef FFMPEG_AVWRITEFRAME_NEWAPI - AVPacket pkt; + AVPacket pkt; - av_init_packet(&pkt); /* init static structure */ - pkt.stream_index = ffmpeg->video_st->index; + av_init_packet(&pkt); /* init static structure */ + pkt.stream_index = ffmpeg->video_st->index; #endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ - if (ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE) { - /* raw video case. The API will change slightly in the near future for that */ + if (ffmpeg->oc->oformat->flags & AVFMT_RAWPICTURE) { + /* raw video case. The API will change slightly in the near future for that */ #ifdef FFMPEG_AVWRITEFRAME_NEWAPI - pkt.flags |= PKT_FLAG_KEY; - pkt.data = (uint8_t *)pic; - pkt.size = sizeof(AVPicture); - ret = av_write_frame(ffmpeg->oc, &pkt); + pkt.flags |= PKT_FLAG_KEY; + pkt.data = (uint8_t *)pic; + pkt.size = sizeof(AVPicture); + ret = av_write_frame(ffmpeg->oc, &pkt); #else - ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, - (uint8_t *)pic, sizeof(AVPicture)); + ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, + (uint8_t *)pic, sizeof(AVPicture)); #endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ - } else { - /* encode the image */ - out_size = avcodec_encode_video(AVSTREAM_CODEC_PTR(ffmpeg->video_st), - ffmpeg->video_outbuf, - ffmpeg->video_outbuf_size, pic); + } else { + /* encode the image */ + out_size = avcodec_encode_video(AVSTREAM_CODEC_PTR(ffmpeg->video_st), + ffmpeg->video_outbuf, + ffmpeg->video_outbuf_size, pic); - /* if zero size, it means the image was buffered */ - if (out_size != 0) { - /* write the compressed frame in the media file */ - /* XXX: in case of B frames, the pts is not yet valid */ + /* if zero size, it means the image was buffered */ + if (out_size != 0) { + /* write the compressed frame in the media file */ + /* XXX: in case of B frames, the pts is not yet valid */ #ifdef FFMPEG_AVWRITEFRAME_NEWAPI - pkt.pts = AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->pts; - if (AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->key_frame) { - pkt.flags |= PKT_FLAG_KEY; - } - pkt.data = ffmpeg->video_outbuf; - pkt.size = out_size; - ret = av_write_frame(ffmpeg->oc, &pkt); + pkt.pts = AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->pts; + if (AVSTREAM_CODEC_PTR(ffmpeg->video_st)->coded_frame->key_frame) { + pkt.flags |= PKT_FLAG_KEY; + } + pkt.data = ffmpeg->video_outbuf; + pkt.size = out_size; + ret = av_write_frame(ffmpeg->oc, &pkt); #else - ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, - ffmpeg->video_outbuf, out_size); + ret = av_write_frame(ffmpeg->oc, ffmpeg->video_st->index, + ffmpeg->video_outbuf, out_size); #endif /* FFMPEG_AVWRITEFRAME_NEWAPI */ - } else { - ret = 0; - } - } - - if (ret != 0) { - motion_log(LOG_ERR, 1, "Error while writing video frame"); - return; - } + } else { + ret = 0; + } + } + + if (ret != 0) { + motion_log(LOG_ERR, 1, "Error while writing video frame"); + return; + } } /* Allocates and prepares a picture frame by setting up the U, Y and V pointers in @@ -683,28 +688,28 @@ void ffmpeg_put_frame(struct ffmpeg *ffmpeg, AVFrame *pic) AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, unsigned char *u, unsigned char *v) { - AVFrame *picture; + AVFrame *picture; - picture = avcodec_alloc_frame(); - if (!picture) { - motion_log(LOG_ERR, 1, "Could not alloc frame"); - return NULL; - } + picture = avcodec_alloc_frame(); + if (!picture) { + motion_log(LOG_ERR, 1, "Could not alloc frame"); + return NULL; + } - /* take care of variable bitrate setting */ - if (ffmpeg->vbr) { - picture->quality = ffmpeg->vbr; - } - - /* setup pointers and line widths */ - picture->data[0] = y; - picture->data[1] = u; - picture->data[2] = v; - picture->linesize[0] = ffmpeg->c->width; - picture->linesize[1] = ffmpeg->c->width / 2; - picture->linesize[2] = ffmpeg->c->width / 2; + /* take care of variable bitrate setting */ + if (ffmpeg->vbr) + picture->quality = ffmpeg->vbr; + + + /* setup pointers and line widths */ + picture->data[0] = y; + picture->data[1] = u; + picture->data[2] = v; + picture->linesize[0] = ffmpeg->c->width; + picture->linesize[1] = ffmpeg->c->width / 2; + picture->linesize[2] = ffmpeg->c->width / 2; - return picture; + return picture; } @@ -722,28 +727,28 @@ AVFrame *ffmpeg_prepare_frame(struct ffmpeg *ffmpeg, unsigned char *y, */ void ffmpeg_deinterlace(unsigned char *img, int width, int height) { - AVFrame *picture; - int width2 = width / 2; - - picture = avcodec_alloc_frame(); - if (!picture) { - motion_log(LOG_ERR, 1, "Could not alloc frame"); - return; - } - - picture->data[0] = img; - picture->data[1] = img+width*height; - picture->data[2] = picture->data[1]+(width*height)/4; - picture->linesize[0] = width; - picture->linesize[1] = width2; - picture->linesize[2] = width2; - - /* We assume using 'PIX_FMT_YUV420P' always */ - avpicture_deinterlace((AVPicture *)picture, (AVPicture *)picture, PIX_FMT_YUV420P, width, height); - - av_free(picture); - - return; + AVFrame *picture; + int width2 = width / 2; + + picture = avcodec_alloc_frame(); + if (!picture) { + motion_log(LOG_ERR, 1, "Could not alloc frame"); + return; + } + + picture->data[0] = img; + picture->data[1] = img+width*height; + picture->data[2] = picture->data[1]+(width*height)/4; + picture->linesize[0] = width; + picture->linesize[1] = width2; + picture->linesize[2] = width2; + + /* We assume using 'PIX_FMT_YUV420P' always */ + avpicture_deinterlace((AVPicture *)picture, (AVPicture *)picture, PIX_FMT_YUV420P, width, height); + + av_free(picture); + + return; } /** ffmpeg_avcodec_log @@ -760,17 +765,17 @@ void ffmpeg_deinterlace(unsigned char *img, int width, int height) */ void ffmpeg_avcodec_log(void *ignoreme ATTRIBUTE_UNUSED, int errno_flag, const char *fmt, va_list vl) { - char buf[1024]; + char buf[1024]; - /* Do not log the message coming from avcodec if the debug_level is not set. */ - if (debug_level) { + /* Do not log the message coming from avcodec if the debug_level is not set. */ + if (debug_level) { - /* Flatten the message coming in from avcodec */ - vsnprintf(buf, sizeof(buf), fmt, vl); + /* Flatten the message coming in from avcodec */ + vsnprintf(buf, sizeof(buf), fmt, vl); - /* If the debug_level is correct then send the message to the motion logging routine. */ - motion_log(LOG_ERR, 0, "ffmpeg_avcodec_log: %s - flag %d", buf, errno_flag); - } + /* If the debug_level is correct then send the message to the motion logging routine. */ + motion_log(LOG_ERR, 0, "ffmpeg_avcodec_log: %s - flag %d", buf, errno_flag); + } } #endif /* HAVE_FFMPEG */ diff --git a/motion.c b/motion.c index 1ee3853e..72423caf 100644 --- a/motion.c +++ b/motion.c @@ -1,9 +1,9 @@ -/* motion.c +/* motion.c * - * Detect changes in a video stream. - * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) - * This software is distributed under the GNU public license version 2 - * See also the file 'COPYING'. + * Detect changes in a video stream. + * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. * */ #include "ffmpeg.h" @@ -48,7 +48,7 @@ pthread_mutex_t global_lock; * * List of context structures, one for each main Motion thread. */ -struct context **cnt_list=NULL; +struct context **cnt_list = NULL; /** * threads_running @@ -56,7 +56,7 @@ struct context **cnt_list=NULL; * Keeps track of number of Motion threads currently running. Also used * by 'main' to know when all threads have exited. */ -volatile int threads_running=0; +volatile int threads_running = 0; /* * debug_level is for developers, normally used to control which @@ -66,7 +66,7 @@ unsigned short int debug_level; /* Set this when we want main to end or restart */ -volatile unsigned short int finish=0; +volatile unsigned short int finish = 0; /** * restart @@ -75,7 +75,7 @@ volatile unsigned short int finish=0; * finished running, 'main' checks if 'restart' is true and if so starts * up again (instead of just quitting). */ -unsigned short int restart=0; +unsigned short int restart = 0; /** * image_ring_resize @@ -92,49 +92,51 @@ unsigned short int restart=0; */ static void image_ring_resize(struct context *cnt, int new_size) { - /* Only resize if : - * Not in an event and - * decreasing at last position in new buffer - * increasing at last position in old buffer - * e.g. at end of smallest buffer */ - if (cnt->event_nr != cnt->prev_event) { - int smallest; - if (new_size < cnt->imgs.image_ring_size) { /* Decreasing */ - smallest = new_size; - } else { /* Increasing */ - smallest = cnt->imgs.image_ring_size; - } - if (cnt->imgs.image_ring_in == smallest - 1 || smallest == 0) { - motion_log(LOG_INFO, 0, "Resizing pre_capture buffer to %d items", new_size); + /* Only resize if : + * Not in an event and + * decreasing at last position in new buffer + * increasing at last position in old buffer + * e.g. at end of smallest buffer */ + if (cnt->event_nr != cnt->prev_event) { + int smallest; + + if (new_size < cnt->imgs.image_ring_size) { /* Decreasing */ + smallest = new_size; + } else { /* Increasing */ + smallest = cnt->imgs.image_ring_size; + } - /* Create memory for new ring buffer */ - struct image_data *tmp; - tmp = mymalloc(new_size * sizeof(struct image_data)); + if (cnt->imgs.image_ring_in == smallest - 1 || smallest == 0) { + motion_log(LOG_INFO, 0, "Resizing pre_capture buffer to %d items", new_size); - /* Copy all information from old to new - * Smallest is 0 at initial init */ - if (smallest > 0) { - memcpy(tmp, cnt->imgs.image_ring, sizeof(struct image_data) * smallest); - } + /* Create memory for new ring buffer */ + struct image_data *tmp; + tmp = mymalloc(new_size * sizeof(struct image_data)); - /* In the new buffers, allocate image memory */ - { - int i; - for(i = smallest; i < new_size; i++) { - tmp[i].image = mymalloc(cnt->imgs.size); - memset(tmp[i].image, 0x80, cnt->imgs.size); /* initialize to grey */ - } - } - - /* Free the old ring */ - free(cnt->imgs.image_ring); + /* Copy all information from old to new + * Smallest is 0 at initial init */ + if (smallest > 0) + memcpy(tmp, cnt->imgs.image_ring, sizeof(struct image_data) * smallest); + - /* Point to the new ring */ - cnt->imgs.image_ring = tmp; + /* In the new buffers, allocate image memory */ + { + int i; + for(i = smallest; i < new_size; i++) { + tmp[i].image = mymalloc(cnt->imgs.size); + memset(tmp[i].image, 0x80, cnt->imgs.size); /* initialize to grey */ + } + } + + /* Free the old ring */ + free(cnt->imgs.image_ring); - cnt->imgs.image_ring_size = new_size; - } - } + /* Point to the new ring */ + cnt->imgs.image_ring = tmp; + + cnt->imgs.image_ring_size = new_size; + } + } } /** @@ -150,22 +152,22 @@ static void image_ring_resize(struct context *cnt, int new_size) */ static void image_ring_destroy(struct context *cnt) { - unsigned short int i; - - /* Exit if don't have any ring */ - if (cnt->imgs.image_ring == NULL) - return; + unsigned short int i; + + /* Exit if don't have any ring */ + if (cnt->imgs.image_ring == NULL) + return; - /* Free all image buffers */ - for (i = 0; i < cnt->imgs.image_ring_size; i++) { - free(cnt->imgs.image_ring[i].image); - } - - /* Free the ring */ - free(cnt->imgs.image_ring); + /* Free all image buffers */ + for (i = 0; i < cnt->imgs.image_ring_size; i++) + free(cnt->imgs.image_ring[i].image); + + + /* Free the ring */ + free(cnt->imgs.image_ring); - cnt->imgs.image_ring = NULL; - cnt->imgs.image_ring_size = 0; + cnt->imgs.image_ring = NULL; + cnt->imgs.image_ring_size = 0; } /** @@ -182,26 +184,27 @@ static void image_ring_destroy(struct context *cnt) */ static void image_save_as_preview(struct context *cnt, struct image_data *img) { - void * image; - /* Save preview image pointer */ - image = cnt->imgs.preview_image.image; - /* Copy all info */ - memcpy(&cnt->imgs.preview_image.image, img, sizeof(struct image_data)); - /* restore image pointer */ - cnt->imgs.preview_image.image = image; + void * image; + /* Save preview image pointer */ + image = cnt->imgs.preview_image.image; + /* Copy all info */ + memcpy(&cnt->imgs.preview_image.image, img, sizeof(struct image_data)); + /* restore image pointer */ + cnt->imgs.preview_image.image = image; - /* Copy image */ - memcpy(cnt->imgs.preview_image.image, img->image, cnt->imgs.size); + /* Copy image */ + memcpy(cnt->imgs.preview_image.image, img->image, cnt->imgs.size); - /* If we set output_all to yes and during the event - * there is no image with motion, diffs is 0, we are not going to save the preview event */ - if (cnt->imgs.preview_image.diffs == 0) - cnt->imgs.preview_image.diffs = 1; + /* If we set output_all to yes and during the event + * there is no image with motion, diffs is 0, we are not going to save the preview event */ + if (cnt->imgs.preview_image.diffs == 0) + cnt->imgs.preview_image.diffs = 1; - /* If we have locate on it is already done */ - if (cnt->locate == LOCATE_PREVIEW) { - alg_draw_location(&img->location, &cnt->imgs, cnt->imgs.width, cnt->imgs.preview_image.image, LOCATE_NORMAL); - } + /* If we have locate on it is already done */ + if (cnt->locate == LOCATE_PREVIEW) + alg_draw_location(&img->location, &cnt->imgs, cnt->imgs.width, + cnt->imgs.preview_image.image, LOCATE_NORMAL); + } /** @@ -218,23 +221,23 @@ static void image_save_as_preview(struct context *cnt, struct image_data *img) */ static void context_init (struct context *cnt) { - /* - * We first clear the entire structure to zero, then fill in any - * values which have non-zero default values. Note that this - * assumes that a NULL address pointer has a value of binary 0 - * (this is also assumed at other places within the code, i.e. - * there are instances of "if (ptr)"). Just for possible future - * changes to this assumption, any pointers which are intended - * to be initialised to NULL are listed within a comment. - */ + /* + * We first clear the entire structure to zero, then fill in any + * values which have non-zero default values. Note that this + * assumes that a NULL address pointer has a value of binary 0 + * (this is also assumed at other places within the code, i.e. + * there are instances of "if (ptr)"). Just for possible future + * changes to this assumption, any pointers which are intended + * to be initialised to NULL are listed within a comment. + */ - memset(cnt, 0, sizeof(struct context)); - cnt->noise = 255; - cnt->lastrate = 25; + memset(cnt, 0, sizeof(struct context)); + cnt->noise = 255; + cnt->lastrate = 25; - memcpy(&cnt->track, &track_template, sizeof(struct trackoptions)); - cnt->pipe = -1; - cnt->mpipe = -1; + memcpy(&cnt->track, &track_template, sizeof(struct trackoptions)); + cnt->pipe = -1; + cnt->mpipe = -1; } @@ -252,21 +255,21 @@ static void context_init (struct context *cnt) */ static void context_destroy(struct context *cnt) { - unsigned short int j; + unsigned short int j; - /* Free memory allocated for config parameters */ - for (j = 0; config_params[j].param_name != NULL; j++) { - if (config_params[j].copy == copy_string) { - void **val; - val = (void *)((char *)cnt+(int)config_params[j].conf_value); - if (*val) { - free(*val); - *val = NULL; - } - } - } + /* Free memory allocated for config parameters */ + for (j = 0; config_params[j].param_name != NULL; j++) { + if (config_params[j].copy == copy_string) { + void **val; + val = (void *)((char *)cnt+(int)config_params[j].conf_value); + if (*val) { + free(*val); + *val = NULL; + } + } + } - free(cnt); + free(cnt); } /** @@ -276,60 +279,60 @@ static void context_destroy(struct context *cnt) */ static void sig_handler(int signo) { - short int i; + short int i; - switch(signo) { - case SIGALRM: - /* Somebody (maybe we ourself) wants us to make a snapshot - * This feature triggers snapshots on ALL threads that have - * snapshot_interval different from 0. - */ - if (cnt_list) { - i = -1; - while (cnt_list[++i]) { - if (cnt_list[i]->conf.snapshot_interval) { - cnt_list[i]->snapshot=1; - } - } - } - break; - case SIGUSR1: - /* Ouch! We have been hit from the outside! Someone wants us to - make a movie! */ - if (cnt_list) { - i = -1; - while (cnt_list[++i]) - cnt_list[i]->makemovie=1; - } - break; - case SIGHUP: - restart = 1; - /* Fall through, as the value of 'restart' is the only difference - * between SIGHUP and the ones below. - */ - case SIGINT: - case SIGQUIT: - case SIGTERM: - /* Somebody wants us to quit! We should better finish the actual - movie and end up! */ - if (cnt_list) { - i = -1; - while (cnt_list[++i]) { - cnt_list[i]->makemovie=1; - cnt_list[i]->finish=1; - /* don't restart thread when it ends, - * all threads restarts if global restart is set - */ - cnt_list[i]->restart=0; - } - } - /* Set flag we want to quit main check threads loop - * if restart is set (above) we start up again */ - finish = 1; - break; - case SIGSEGV: - exit(0); - } + switch(signo) { + case SIGALRM: + /* Somebody (maybe we ourself) wants us to make a snapshot + * This feature triggers snapshots on ALL threads that have + * snapshot_interval different from 0. + */ + if (cnt_list) { + i = -1; + while (cnt_list[++i]) { + if (cnt_list[i]->conf.snapshot_interval) + cnt_list[i]->snapshot=1; + + } + } + break; + case SIGUSR1: + /* Ouch! We have been hit from the outside! Someone wants us to + make a movie! */ + if (cnt_list) { + i = -1; + while (cnt_list[++i]) + cnt_list[i]->makemovie=1; + } + break; + case SIGHUP: + restart = 1; + /* Fall through, as the value of 'restart' is the only difference + * between SIGHUP and the ones below. + */ + case SIGINT: + case SIGQUIT: + case SIGTERM: + /* Somebody wants us to quit! We should better finish the actual + movie and end up! */ + if (cnt_list) { + i = -1; + while (cnt_list[++i]) { + cnt_list[i]->makemovie=1; + cnt_list[i]->finish=1; + /* don't restart thread when it ends, + * all threads restarts if global restart is set + */ + cnt_list[i]->restart=0; + } + } + /* Set flag we want to quit main check threads loop + * if restart is set (above) we start up again */ + finish = 1; + break; + case SIGSEGV: + exit(0); + } } /** @@ -341,9 +344,9 @@ static void sig_handler(int signo) static void sigchild_handler(int signo ATTRIBUTE_UNUSED) { #ifdef WNOHANG - while (waitpid(-1, NULL, WNOHANG) > 0) {}; + while (waitpid(-1, NULL, WNOHANG) > 0) {}; #endif /* WNOHANG */ - return; + return; } /** @@ -354,12 +357,12 @@ static void sigchild_handler(int signo ATTRIBUTE_UNUSED) */ static void motion_remove_pid(void) { - if ((cnt_list[0]->daemon) && (cnt_list[0]->conf.pid_file) && (restart == 0)) { - if (!unlink(cnt_list[0]->conf.pid_file)) - motion_log(LOG_INFO, 0, "Removed process id file (pid file)."); - else - motion_log(LOG_INFO, 1, "Error removing pid file"); - } + if ((cnt_list[0]->daemon) && (cnt_list[0]->conf.pid_file) && (restart == 0)) { + if (!unlink(cnt_list[0]->conf.pid_file)) + motion_log(LOG_INFO, 0, "Removed process id file (pid file)."); + else + motion_log(LOG_INFO, 1, "Error removing pid file"); + } } /** @@ -376,78 +379,77 @@ static void motion_remove_pid(void) */ static void motion_detected(struct context *cnt, int dev, struct image_data *img) { - struct config *conf = &cnt->conf; - struct images *imgs = &cnt->imgs; - struct coord *location = &img->location; + struct config *conf = &cnt->conf; + struct images *imgs = &cnt->imgs; + struct coord *location = &img->location; - /* Draw location */ - if (cnt->locate == LOCATE_ON) - alg_draw_location(location, imgs, imgs->width, img->image, LOCATE_BOTH); + /* Draw location */ + if (cnt->locate == LOCATE_ON) + alg_draw_location(location, imgs, imgs->width, img->image, LOCATE_BOTH); - /* Calculate how centric motion is if configured preview center*/ - if (cnt->new_img & NEWIMG_CENTER) { - unsigned int distX = abs((imgs->width/2) - location->x); - unsigned int distY = abs((imgs->height/2) - location->y); - - img->cent_dist = distX*distX + distY*distY; - } + /* Calculate how centric motion is if configured preview center*/ + if (cnt->new_img & NEWIMG_CENTER) { + unsigned int distX = abs((imgs->width/2) - location->x); + unsigned int distY = abs((imgs->height/2) - location->y); + img->cent_dist = distX*distX + distY*distY; + } - /* Do things only if we have got minimum_motion_frames */ - if (img->flags & IMAGE_TRIGGER) { - /* Take action if this is a new event and we have a trigger image */ - if (cnt->event_nr != cnt->prev_event) { - /* Reset prev_event number to current event and save event time - * in both time_t and struct tm format. - */ - cnt->prev_event = cnt->event_nr; - cnt->eventtime = img->timestamp; - localtime_r(&cnt->eventtime, cnt->eventtime_tm); + /* Do things only if we have got minimum_motion_frames */ + if (img->flags & IMAGE_TRIGGER) { + /* Take action if this is a new event and we have a trigger image */ + if (cnt->event_nr != cnt->prev_event) { + /* Reset prev_event number to current event and save event time + * in both time_t and struct tm format. + */ + cnt->prev_event = cnt->event_nr; + cnt->eventtime = img->timestamp; + localtime_r(&cnt->eventtime, cnt->eventtime_tm); - /* Since this is a new event we create the event_text_string used for - * the %C conversion specifier. We may already need it for - * on_motion_detected_commend so it must be done now. - */ - mystrftime(cnt, cnt->text_event_string, sizeof(cnt->text_event_string), - cnt->conf.text_event, cnt->eventtime_tm, NULL, 0); + /* Since this is a new event we create the event_text_string used for + * the %C conversion specifier. We may already need it for + * on_motion_detected_commend so it must be done now. + */ + mystrftime(cnt, cnt->text_event_string, sizeof(cnt->text_event_string), + cnt->conf.text_event, cnt->eventtime_tm, NULL, 0); - /* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */ - event(cnt, EVENT_FIRSTMOTION, img->image, NULL, NULL, &img->timestamp_tm); + /* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */ + event(cnt, EVENT_FIRSTMOTION, img->image, NULL, NULL, &img->timestamp_tm); - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Motion detected - starting event %d", cnt->event_nr); + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Motion detected - starting event %d", cnt->event_nr); - /* always save first motion frame as preview-shot, may be changed to an other one later */ - if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) { - image_save_as_preview(cnt, img); - } - } + /* always save first motion frame as preview-shot, may be changed to an other one later */ + if (cnt->new_img & (NEWIMG_FIRST | NEWIMG_BEST | NEWIMG_CENTER)) + image_save_as_preview(cnt, img); + + } - /* EVENT_MOTION triggers event_beep and on_motion_detected_command */ - event(cnt, EVENT_MOTION, NULL, NULL, NULL, &img->timestamp_tm); - } + /* EVENT_MOTION triggers event_beep and on_motion_detected_command */ + event(cnt, EVENT_MOTION, NULL, NULL, NULL, &img->timestamp_tm); + } - /* Limit framerate */ - if (img->shot < conf->frame_limit) { - /* If config option webcam_motion is enabled, send the latest motion detected image - * to the webcam but only if it is not the first shot within a second. This is to - * avoid double frames since we already have sent a frame to the webcam. - * We also disable this in setup_mode. - */ - if (conf->webcam_motion && !conf->setup_mode && img->shot != 1) { - event(cnt, EVENT_WEBCAM, img->image, NULL, NULL, &img->timestamp_tm); - } + /* Limit framerate */ + if (img->shot < conf->frame_limit) { + /* If config option webcam_motion is enabled, send the latest motion detected image + * to the webcam but only if it is not the first shot within a second. This is to + * avoid double frames since we already have sent a frame to the webcam. + * We also disable this in setup_mode. + */ + if (conf->webcam_motion && !conf->setup_mode && img->shot != 1) + event(cnt, EVENT_WEBCAM, img->image, NULL, NULL, &img->timestamp_tm); + - /* Save motion jpeg, if configured */ - /* Output the image_out (motion) picture. */ - if (conf->motion_img) { - event(cnt, EVENT_IMAGEM_DETECTED, NULL, NULL, NULL, &img->timestamp_tm); - } - } + /* Save motion jpeg, if configured */ + /* Output the image_out (motion) picture. */ + if (conf->motion_img) + event(cnt, EVENT_IMAGEM_DETECTED, NULL, NULL, NULL, &img->timestamp_tm); + + } - if (cnt->track.type) { - cnt->moved = track_move(cnt, dev, location, imgs, 0); - } + if (cnt->track.type) + cnt->moved = track_move(cnt, dev, location, imgs, 0); + } /** @@ -464,63 +466,63 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img #define IMAGE_BUFFER_FLUSH ((unsigned int)-1) static void process_image_ring(struct context *cnt, unsigned int max_images) { - /* we are going to send an event, in the events there is still - * some code that use cnt->current_image - * so set it temporary to our image */ - struct image_data *saved_current_image = cnt->current_image; + /* we are going to send an event, in the events there is still + * some code that use cnt->current_image + * so set it temporary to our image */ + struct image_data *saved_current_image = cnt->current_image; - /* If image is flaged to be saved and not saved yet, process it */ - do { - /* Check if we should save/send this image, breakout if not */ - if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & (IMAGE_SAVE | IMAGE_SAVED)) != IMAGE_SAVE) - break; + /* If image is flaged to be saved and not saved yet, process it */ + do { + /* Check if we should save/send this image, breakout if not */ + if ((cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & + (IMAGE_SAVE | IMAGE_SAVED)) != IMAGE_SAVE) + break; - /* Set inte global cotext that we are working with this image */ - cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_out]; + /* Set inte global cotext that we are working with this image */ + cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_out]; - if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot < cnt->conf.frame_limit) { - /* Output the picture to jpegs and ffmpeg */ - event(cnt, EVENT_IMAGE_DETECTED, - cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, - &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm); - } + if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].shot < cnt->conf.frame_limit) { + /* Output the picture to jpegs and ffmpeg */ + event(cnt, EVENT_IMAGE_DETECTED, + cnt->imgs.image_ring[cnt->imgs.image_ring_out].image, NULL, NULL, + &cnt->imgs.image_ring[cnt->imgs.image_ring_out].timestamp_tm); + } - /* Mark the image as saved */ - cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags |= IMAGE_SAVED; + /* Mark the image as saved */ + cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags |= IMAGE_SAVED; - /* Store it as a preview image, only if it have motion */ - if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_MOTION) - { - /* Check for most significant preview-shot when output_normal=best */ - if (cnt->new_img & NEWIMG_BEST) { - if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].diffs > cnt->imgs.preview_image.diffs) { - image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]); - } - } - /* Check for most significant preview-shot when output_normal=center */ - if (cnt->new_img & NEWIMG_CENTER) { - if(cnt->imgs.image_ring[cnt->imgs.image_ring_out].cent_dist < cnt->imgs.preview_image.cent_dist) { - image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]); - } - } - } + /* Store it as a preview image, only if it have motion */ + if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].flags & IMAGE_MOTION) { + + /* Check for most significant preview-shot when output_normal=best */ + if (cnt->new_img & NEWIMG_BEST) { + if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].diffs > cnt->imgs.preview_image.diffs) + image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]); + + } + /* Check for most significant preview-shot when output_normal=center */ + if (cnt->new_img & NEWIMG_CENTER) { + if (cnt->imgs.image_ring[cnt->imgs.image_ring_out].cent_dist < cnt->imgs.preview_image.cent_dist) + image_save_as_preview(cnt, &cnt->imgs.image_ring[cnt->imgs.image_ring_out]); + } + } - /* Increment to image after last sended */ - if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size) - cnt->imgs.image_ring_out = 0; + /* Increment to image after last sended */ + if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size) + cnt->imgs.image_ring_out = 0; - if (max_images != IMAGE_BUFFER_FLUSH) { - max_images--; - /* breakout if we have done max_images */ - if (max_images == 0) - break; - } + if (max_images != IMAGE_BUFFER_FLUSH) { + max_images--; + /* breakout if we have done max_images */ + if (max_images == 0) + break; + } - /* loop until out and in is same e.g. buffer empty */ - } while (cnt->imgs.image_ring_out != cnt->imgs.image_ring_in); + /* loop until out and in is same e.g. buffer empty */ + } while (cnt->imgs.image_ring_out != cnt->imgs.image_ring_in); - /* restore global context values */ - cnt->current_image = saved_current_image; + /* restore global context values */ + cnt->current_image = saved_current_image; } /** @@ -539,225 +541,232 @@ static void process_image_ring(struct context *cnt, unsigned int max_images) */ static int motion_init(struct context *cnt) { - int i; - FILE *picture; + int i; + FILE *picture; - /* Store thread number in TLS. */ - pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr)); + /* Store thread number in TLS. */ + pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr)); - cnt->currenttime_tm = mymalloc(sizeof(struct tm)); - cnt->eventtime_tm = mymalloc(sizeof(struct tm)); - /* Init frame time */ - cnt->currenttime = time(NULL); - localtime_r(&cnt->currenttime, cnt->currenttime_tm); + cnt->currenttime_tm = mymalloc(sizeof(struct tm)); + cnt->eventtime_tm = mymalloc(sizeof(struct tm)); + /* Init frame time */ + cnt->currenttime = time(NULL); + localtime_r(&cnt->currenttime, cnt->currenttime_tm); - cnt->smartmask_speed = 0; + cnt->smartmask_speed = 0; - /* We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so - * that certain code below does not run until motion has been detected the first time */ - cnt->event_nr = 1; - cnt->prev_event = 0; - cnt->lightswitch_framecounter = 0; - cnt->detecting_motion = 0; - cnt->makemovie = 0; + /* We initialize cnt->event_nr to 1 and cnt->prev_event to 0 (not really needed) so + * that certain code below does not run until motion has been detected the first time */ + cnt->event_nr = 1; + cnt->prev_event = 0; + cnt->lightswitch_framecounter = 0; + cnt->detecting_motion = 0; + cnt->makemovie = 0; - motion_log(LOG_DEBUG, 0, "Thread %d started", (unsigned long)pthread_getspecific(tls_key_threadnr)); + motion_log(LOG_DEBUG, 0, "Thread %d started", (unsigned long)pthread_getspecific(tls_key_threadnr)); - if (!cnt->conf.filepath) - cnt->conf.filepath = strdup("."); + if (!cnt->conf.filepath) + cnt->conf.filepath = strdup("."); - /* set the device settings */ - cnt->video_dev = vid_start(cnt); + /* set the device settings */ + cnt->video_dev = vid_start(cnt); - /* We failed to get an initial image from a camera - * So we need to guess height and width based on the config - * file options. - */ - if (cnt->video_dev < 0) { - motion_log(LOG_ERR, 0, "Could not fetch initial image from camera"); - motion_log(LOG_ERR, 0, "Motion continues using width and height from config file(s)"); - cnt->imgs.width = cnt->conf.width; - cnt->imgs.height = cnt->conf.height; - cnt->imgs.size = cnt->conf.width * cnt->conf.height * 3 / 2; - cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height; - cnt->imgs.type = VIDEO_PALETTE_YUV420P; - } + /* We failed to get an initial image from a camera + * So we need to guess height and width based on the config + * file options. + */ + if (cnt->video_dev < 0) { + motion_log(LOG_ERR, 0, "Could not fetch initial image from camera"); + motion_log(LOG_ERR, 0, "Motion continues using width and height from config file(s)"); + cnt->imgs.width = cnt->conf.width; + cnt->imgs.height = cnt->conf.height; + cnt->imgs.size = cnt->conf.width * cnt->conf.height * 3 / 2; + cnt->imgs.motionsize = cnt->conf.width * cnt->conf.height; + cnt->imgs.type = VIDEO_PALETTE_YUV420P; + } - image_ring_resize(cnt, 1); /* Create a initial precapture ring buffer with 1 frame */ + image_ring_resize(cnt, 1); /* Create a initial precapture ring buffer with 1 frame */ - cnt->imgs.ref = mymalloc(cnt->imgs.size); - cnt->imgs.out = mymalloc(cnt->imgs.size); - memset(cnt->imgs.out, 0, cnt->imgs.size); - cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); /* contains the moving objects of ref. frame */ - cnt->imgs.image_virgin = mymalloc(cnt->imgs.size); - cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize); - cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize); - cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.smartmask_buffer)); - cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.labels)); - cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(cnt->imgs.labelsize)); + cnt->imgs.ref = mymalloc(cnt->imgs.size); + cnt->imgs.out = mymalloc(cnt->imgs.size); + memset(cnt->imgs.out, 0, cnt->imgs.size); + /* contains the moving objects of ref. frame */ + cnt->imgs.ref_dyn = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.ref_dyn)); + cnt->imgs.image_virgin = mymalloc(cnt->imgs.size); + cnt->imgs.smartmask = mymalloc(cnt->imgs.motionsize); + cnt->imgs.smartmask_final = mymalloc(cnt->imgs.motionsize); + cnt->imgs.smartmask_buffer = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.smartmask_buffer)); + cnt->imgs.labels = mymalloc(cnt->imgs.motionsize * sizeof(cnt->imgs.labels)); + cnt->imgs.labelsize = mymalloc((cnt->imgs.motionsize/2+1) * sizeof(cnt->imgs.labelsize)); - /* allocate buffer here for preview buffer */ - cnt->imgs.preview_image.image = mymalloc(cnt->imgs.size); + /* allocate buffer here for preview buffer */ + cnt->imgs.preview_image.image = mymalloc(cnt->imgs.size); - /* Allocate a buffer for temp. usage in some places */ - /* Only despeckle & bayer2rgb24() for now for now... */ - cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height); + /* Allocate a buffer for temp. usage in some places */ + /* Only despeckle & bayer2rgb24() for now for now... */ + cnt->imgs.common_buffer = mymalloc(3 * cnt->imgs.width * cnt->imgs.height); - /* Now is a good time to init rotation data. Since vid_start has been - * called, we know that we have imgs.width and imgs.height. When capturing - * from a V4L device, these are copied from the corresponding conf values - * in vid_start. When capturing from a netcam, they get set in netcam_start, - * which is called from vid_start. - * - * rotate_init will set cap_width and cap_height in cnt->rotate_data. - */ - rotate_init(cnt); /* rotate_deinit is called in main */ + /* Now is a good time to init rotation data. Since vid_start has been + * called, we know that we have imgs.width and imgs.height. When capturing + * from a V4L device, these are copied from the corresponding conf values + * in vid_start. When capturing from a netcam, they get set in netcam_start, + * which is called from vid_start. + * + * rotate_init will set cap_width and cap_height in cnt->rotate_data. + */ + rotate_init(cnt); /* rotate_deinit is called in main */ - /* Capture first image, or we will get an alarm on start */ - if (cnt->video_dev > 0) { - for (i = 0; i < 5; i++) { - if (vid_next(cnt, cnt->imgs.image_virgin) == 0) - break; - SLEEP(2,0); - } - if (i >= 5) { - memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size); /* initialize to grey */ - draw_text(cnt->imgs.image_virgin, 10, 20, cnt->imgs.width, - "Error capturing first image", cnt->conf.text_double); - motion_log(LOG_ERR, 0, "Error capturing first image"); - } - } + /* Capture first image, or we will get an alarm on start */ + if (cnt->video_dev > 0) { + for (i = 0; i < 5; i++) { + if (vid_next(cnt, cnt->imgs.image_virgin) == 0) + break; + SLEEP(2,0); + } + if (i >= 5) { + memset(cnt->imgs.image_virgin, 0x80, cnt->imgs.size); /* initialize to grey */ + draw_text(cnt->imgs.image_virgin, 10, 20, cnt->imgs.width, + "Error capturing first image", cnt->conf.text_double); + motion_log(LOG_ERR, 0, "Error capturing first image"); + } + } - /* create a reference frame */ - alg_update_reference_frame(cnt, RESET_REF_FRAME); + /* create a reference frame */ + alg_update_reference_frame(cnt, RESET_REF_FRAME); #ifndef WITHOUT_V4L #if (!defined(BSD)) - /* open video loopback devices if enabled */ - if (cnt->conf.vidpipe) { - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Opening video loopback device for normal pictures"); - /* vid_startpipe should get the output dimensions */ - cnt->pipe = vid_startpipe(cnt->conf.vidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); - if (cnt->pipe < 0) { - motion_log(LOG_ERR, 0, "Failed to open video loopback"); - return -1; - } - } - if (cnt->conf.motionvidpipe) { - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Opening video loopback device for motion pictures"); - /* vid_startpipe should get the output dimensions */ - cnt->mpipe = vid_startpipe(cnt->conf.motionvidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); - if (cnt->mpipe < 0) { - motion_log(LOG_ERR, 0, "Failed to open video loopback"); - return -1; - } - } + /* open video loopback devices if enabled */ + if (cnt->conf.vidpipe) { + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Opening video loopback device for normal pictures"); + /* vid_startpipe should get the output dimensions */ + cnt->pipe = vid_startpipe(cnt->conf.vidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); + if (cnt->pipe < 0) { + motion_log(LOG_ERR, 0, "Failed to open video loopback"); + return -1; + } + } + if (cnt->conf.motionvidpipe) { + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Opening video loopback device for motion pictures"); + /* vid_startpipe should get the output dimensions */ + cnt->mpipe = vid_startpipe(cnt->conf.motionvidpipe, cnt->imgs.width, cnt->imgs.height, cnt->imgs.type); + if (cnt->mpipe < 0) { + motion_log(LOG_ERR, 0, "Failed to open video loopback"); + return -1; + } + } #endif /* BSD */ #endif /*WITHOUT_V4L*/ #ifdef HAVE_MYSQL - if(cnt->conf.mysql_db) { - cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); - mysql_init(cnt->database); - if (!mysql_real_connect(cnt->database, cnt->conf.mysql_host, cnt->conf.mysql_user, - cnt->conf.mysql_password, cnt->conf.mysql_db, 0, NULL, 0)) { - motion_log(LOG_ERR, 0, "Cannot connect to MySQL database %s on host %s with user %s", - cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user); - motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database)); - return -2; - } - #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012) - my_bool my_true = TRUE; - mysql_options(cnt->database,MYSQL_OPT_RECONNECT,&my_true); - #endif - } + if (cnt->conf.mysql_db) { + cnt->database = (MYSQL *) mymalloc(sizeof(MYSQL)); + mysql_init(cnt->database); + + if (!mysql_real_connect(cnt->database, cnt->conf.mysql_host, cnt->conf.mysql_user, + cnt->conf.mysql_password, cnt->conf.mysql_db, 0, NULL, 0)) { + motion_log(LOG_ERR, 0, "Cannot connect to MySQL database %s on host %s with user %s", + cnt->conf.mysql_db, cnt->conf.mysql_host, cnt->conf.mysql_user); + motion_log(LOG_ERR, 0, "MySQL error was %s", mysql_error(cnt->database)); + return -2; + } + #if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012) + my_bool my_true = TRUE; + mysql_options(cnt->database,MYSQL_OPT_RECONNECT,&my_true); + #endif + } #endif /* HAVE_MYSQL */ #ifdef HAVE_PGSQL - if (cnt->conf.pgsql_db) { - char connstring[255]; + if (cnt->conf.pgsql_db) { + char connstring[255]; - /* create the connection string. - Quote the values so we can have null values (blank)*/ - snprintf(connstring, 255, - "dbname='%s' host='%s' user='%s' password='%s' port='%d'", - cnt->conf.pgsql_db, /* dbname */ - (cnt->conf.pgsql_host ? cnt->conf.pgsql_host : ""), /* host (may be blank) */ - (cnt->conf.pgsql_user ? cnt->conf.pgsql_user : ""), /* user (may be blank) */ - (cnt->conf.pgsql_password ? cnt->conf.pgsql_password : ""), /* password (may be blank) */ - cnt->conf.pgsql_port - ); + /* create the connection string. + Quote the values so we can have null values (blank)*/ + snprintf(connstring, 255, + "dbname='%s' host='%s' user='%s' password='%s' port='%d'", + cnt->conf.pgsql_db, /* dbname */ + (cnt->conf.pgsql_host ? cnt->conf.pgsql_host : ""), /* host (may be blank) */ + (cnt->conf.pgsql_user ? cnt->conf.pgsql_user : ""), /* user (may be blank) */ + (cnt->conf.pgsql_password ? cnt->conf.pgsql_password : ""), /* password (may be blank) */ + cnt->conf.pgsql_port + ); - cnt->database_pg = PQconnectdb(connstring); - if (PQstatus(cnt->database_pg) == CONNECTION_BAD) { - motion_log(LOG_ERR, 0, "Connection to PostgreSQL database '%s' failed: %s", - cnt->conf.pgsql_db, PQerrorMessage(cnt->database_pg)); - return -2; - } - } + cnt->database_pg = PQconnectdb(connstring); + + if (PQstatus(cnt->database_pg) == CONNECTION_BAD) { + motion_log(LOG_ERR, 0, "Connection to PostgreSQL database '%s' failed: %s", + cnt->conf.pgsql_db, PQerrorMessage(cnt->database_pg)); + return -2; + } + } #endif /* HAVE_PGSQL */ #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) - /* Set the sql mask file according to the SQL config options*/ + /* Set the sql mask file according to the SQL config options*/ - cnt->sql_mask = cnt->conf.sql_log_image * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) + - cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT + - cnt->conf.sql_log_mpeg * (FTYPE_MPEG + FTYPE_MPEG_MOTION) + - cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE; + cnt->sql_mask = cnt->conf.sql_log_image * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) + + cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT + + cnt->conf.sql_log_mpeg * (FTYPE_MPEG + FTYPE_MPEG_MOTION) + + cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE; #endif /* defined(HAVE_MYSQL) || defined(HAVE_PGSQL) */ - /* Load the mask file if any */ - if (cnt->conf.mask_file) { - if ((picture = fopen(cnt->conf.mask_file, "r"))) { - /* NOTE: The mask is expected to have the output dimensions. I.e., the mask - * applies to the already rotated image, not the capture image. Thus, use - * width and height from imgs. - */ - cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height); - fclose(picture); - } else { - motion_log(LOG_ERR, 1, "Error opening mask file %s", cnt->conf.mask_file); - /* Try to write an empty mask file to make it easier - for the user to edit it */ - put_fixed_mask(cnt, cnt->conf.mask_file); - } - if (!cnt->imgs.mask) { - motion_log(LOG_ERR, 0, "Failed to read mask image. Mask feature disabled."); - } else { - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Maskfile \"%s\" loaded.",cnt->conf.mask_file); - } - } else - cnt->imgs.mask=NULL; + /* Load the mask file if any */ + if (cnt->conf.mask_file) { + if ((picture = fopen(cnt->conf.mask_file, "r"))) { + /* NOTE: The mask is expected to have the output dimensions. I.e., the mask + * applies to the already rotated image, not the capture image. Thus, use + * width and height from imgs. + */ + cnt->imgs.mask = get_pgm(picture, cnt->imgs.width, cnt->imgs.height); + fclose(picture); + } else { + motion_log(LOG_ERR, 1, "Error opening mask file %s", cnt->conf.mask_file); + /* Try to write an empty mask file to make it easier + for the user to edit it */ + put_fixed_mask(cnt, cnt->conf.mask_file); + } - /* Always initialize smart_mask - someone could turn it on later... */ - memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); - memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize); - memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize*sizeof(cnt->imgs.smartmask_buffer)); + if (!cnt->imgs.mask) { + motion_log(LOG_ERR, 0, "Failed to read mask image. Mask feature disabled."); + } else { + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Maskfile \"%s\" loaded.",cnt->conf.mask_file); + } + } else { + cnt->imgs.mask=NULL; + } - /* Set noise level */ - cnt->noise = cnt->conf.noise; + /* Always initialize smart_mask - someone could turn it on later... */ + memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); + memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize); + memset(cnt->imgs.smartmask_buffer, 0, cnt->imgs.motionsize*sizeof(cnt->imgs.smartmask_buffer)); - /* Set threshold value */ - cnt->threshold = cnt->conf.max_changes; + /* Set noise level */ + cnt->noise = cnt->conf.noise; - /* Initialize webcam server if webcam port is specified to not 0 */ - if (cnt->conf.webcam_port) { - if ( webcam_init(cnt) == -1 ) { - motion_log(LOG_ERR, 1, "Problem enabling stream server in port %d", cnt->conf.webcam_port); - cnt->finish = 1; - }else motion_log(LOG_DEBUG, 0, "Started stream webcam server in port %d", cnt->conf.webcam_port); - } + /* Set threshold value */ + cnt->threshold = cnt->conf.max_changes; - /* Prevent first few frames from triggering motion... */ - cnt->moved = 8; - /* 2 sec startup delay so FPS is calculated correct */ - cnt->startup_frames = cnt->conf.frame_limit * 2; + /* Initialize webcam server if webcam port is specified to not 0 */ + if (cnt->conf.webcam_port) { + if (webcam_init(cnt) == -1) { + motion_log(LOG_ERR, 1, "Problem enabling stream server in port %d", cnt->conf.webcam_port); + cnt->finish = 1; + } else { + motion_log(LOG_DEBUG, 0, "Started stream webcam server in port %d", cnt->conf.webcam_port); + } + } - return 0; + /* Prevent first few frames from triggering motion... */ + cnt->moved = 8; + /* 2 sec startup delay so FPS is calculated correct */ + cnt->startup_frames = cnt->conf.frame_limit * 2; + + return 0; } /** @@ -774,83 +783,94 @@ static int motion_init(struct context *cnt) */ static void motion_cleanup(struct context *cnt) { - /* Stop webcam */ - event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL); + /* Stop webcam */ + event(cnt, EVENT_STOP, NULL, NULL, NULL, NULL); - if (cnt->video_dev >= 0){ - motion_log(LOG_DEBUG, 0, "Calling vid_close() from motion_cleanup"); - vid_close(cnt); - } + if (cnt->video_dev >= 0) { + motion_log(LOG_DEBUG, 0, "Calling vid_close() from motion_cleanup"); + vid_close(cnt); + } - if (cnt->imgs.out) { - free(cnt->imgs.out); - cnt->imgs.out = NULL; - } - if (cnt->imgs.ref) { - free(cnt->imgs.ref); - cnt->imgs.ref = NULL; - } - if (cnt->imgs.ref_dyn) { - free(cnt->imgs.ref_dyn); - cnt->imgs.ref_dyn = NULL; - } - if (cnt->imgs.image_virgin) { - free(cnt->imgs.image_virgin); - cnt->imgs.image_virgin = NULL; - } - if (cnt->imgs.labels) { - free(cnt->imgs.labels); - cnt->imgs.labels = NULL; - } - if (cnt->imgs.labelsize) { - free(cnt->imgs.labelsize); - cnt->imgs.labelsize = NULL; - } - if (cnt->imgs.smartmask) { - free(cnt->imgs.smartmask); - cnt->imgs.smartmask = NULL; - } - if (cnt->imgs.smartmask_final) { - free(cnt->imgs.smartmask_final); - cnt->imgs.smartmask_final = NULL; - } - if (cnt->imgs.smartmask_buffer) { - free(cnt->imgs.smartmask_buffer); - cnt->imgs.smartmask_buffer = NULL; - } - if (cnt->imgs.common_buffer) { - free(cnt->imgs.common_buffer); - cnt->imgs.common_buffer = NULL; - } - if (cnt->imgs.preview_image.image) { - free(cnt->imgs.preview_image.image); - cnt->imgs.preview_image.image = NULL; - } + if (cnt->imgs.out) { + free(cnt->imgs.out); + cnt->imgs.out = NULL; + } - image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */ + if (cnt->imgs.ref) { + free(cnt->imgs.ref); + cnt->imgs.ref = NULL; + } - rotate_deinit(cnt); /* cleanup image rotation data */ + if (cnt->imgs.ref_dyn) { + free(cnt->imgs.ref_dyn); + cnt->imgs.ref_dyn = NULL; + } - if(cnt->pipe != -1) { - close(cnt->pipe); - cnt->pipe = -1; - } - if(cnt->mpipe != -1) { - close(cnt->mpipe); - cnt->mpipe = -1; - } + if (cnt->imgs.image_virgin) { + free(cnt->imgs.image_virgin); + cnt->imgs.image_virgin = NULL; + } - /* Cleanup the current time structure */ - if (cnt->currenttime_tm) { - free(cnt->currenttime_tm); - cnt->currenttime_tm = NULL; - } + if (cnt->imgs.labels) { + free(cnt->imgs.labels); + cnt->imgs.labels = NULL; + } - /* Cleanup the event time structure */ - if (cnt->eventtime_tm) { - free(cnt->eventtime_tm); - cnt->eventtime_tm = NULL; - } + if (cnt->imgs.labelsize) { + free(cnt->imgs.labelsize); + cnt->imgs.labelsize = NULL; + } + + if (cnt->imgs.smartmask) { + free(cnt->imgs.smartmask); + cnt->imgs.smartmask = NULL; + } + + if (cnt->imgs.smartmask_final) { + free(cnt->imgs.smartmask_final); + cnt->imgs.smartmask_final = NULL; + } + + if (cnt->imgs.smartmask_buffer) { + free(cnt->imgs.smartmask_buffer); + cnt->imgs.smartmask_buffer = NULL; + } + + if (cnt->imgs.common_buffer) { + free(cnt->imgs.common_buffer); + cnt->imgs.common_buffer = NULL; + } + + if (cnt->imgs.preview_image.image) { + free(cnt->imgs.preview_image.image); + cnt->imgs.preview_image.image = NULL; + } + + image_ring_destroy(cnt); /* Cleanup the precapture ring buffer */ + + rotate_deinit(cnt); /* cleanup image rotation data */ + + if (cnt->pipe != -1) { + close(cnt->pipe); + cnt->pipe = -1; + } + + if (cnt->mpipe != -1) { + close(cnt->mpipe); + cnt->mpipe = -1; + } + + /* Cleanup the current time structure */ + if (cnt->currenttime_tm) { + free(cnt->currenttime_tm); + cnt->currenttime_tm = NULL; + } + + /* Cleanup the event time structure */ + if (cnt->eventtime_tm) { + free(cnt->eventtime_tm); + cnt->eventtime_tm = NULL; + } } /** @@ -861,993 +881,1022 @@ static void motion_cleanup(struct context *cnt) */ static void *motion_loop(void *arg) { - struct context *cnt = arg; - int i, j, z = 0; - time_t lastframetime = 0; - int frame_buffer_size; - unsigned short int ref_frame_limit = 0; - int area_once = 0; - int area_minx[9], area_miny[9], area_maxx[9], area_maxy[9]; - int smartmask_ratio = 0; - int smartmask_count = 20; - int smartmask_lastrate = 0; - int olddiffs = 0; - int previous_diffs = 0, previous_location_x = 0, previous_location_y = 0; - unsigned short int text_size_factor; - unsigned short int passflag = 0; - long int *rolling_average_data = NULL; - long int rolling_average_limit, required_frame_time, frame_delay, delay_time_nsec; - int rolling_frame = 0; - struct timeval tv1, tv2; - unsigned long int rolling_average, elapsedtime; - unsigned long long int timenow = 0, timebefore = 0; - int vid_return_code = 0; /* Return code used when calling vid_next */ - int minimum_frame_time_downcounter = cnt->conf.minimum_frame_time; /* time in seconds to skip between capturing images */ - unsigned short int get_image = 1; /* Flag used to signal that we capture new image when we run the loop */ + struct context *cnt = arg; + int i, j, z = 0; + time_t lastframetime = 0; + int frame_buffer_size; + unsigned short int ref_frame_limit = 0; + int area_once = 0; + int area_minx[9], area_miny[9], area_maxx[9], area_maxy[9]; + int smartmask_ratio = 0; + int smartmask_count = 20; + int smartmask_lastrate = 0; + int olddiffs = 0; + int previous_diffs = 0, previous_location_x = 0, previous_location_y = 0; + unsigned short int text_size_factor; + unsigned short int passflag = 0; + long int *rolling_average_data = NULL; + long int rolling_average_limit, required_frame_time, frame_delay, delay_time_nsec; + int rolling_frame = 0; + struct timeval tv1, tv2; + unsigned long int rolling_average, elapsedtime; + unsigned long long int timenow = 0, timebefore = 0; + /* Return code used when calling vid_next */ + int vid_return_code = 0; + /* time in seconds to skip between capturing images */ + int minimum_frame_time_downcounter = cnt->conf.minimum_frame_time; + /* Flag used to signal that we capture new image when we run the loop */ + unsigned short int get_image = 1; - /* Next two variables are used for snapshot and timelapse feature - * time_last_frame is set to 1 so that first coming timelapse or second=0 - * is acted upon. - */ - unsigned long int time_last_frame=1, time_current_frame; + /* Next two variables are used for snapshot and timelapse feature + * time_last_frame is set to 1 so that first coming timelapse or second=0 + * is acted upon. + */ + unsigned long int time_last_frame=1, time_current_frame; - cnt->running = 1; - - if (motion_init(cnt) < 0) { - goto err; - } + cnt->running = 1; + + if (motion_init(cnt) < 0) + goto err; + - /* Initialize the double sized characters if needed. */ - if(cnt->conf.text_double) - text_size_factor = 2; - else - text_size_factor = 1; + /* Initialize the double sized characters if needed. */ + if (cnt->conf.text_double) + text_size_factor = 2; + else + text_size_factor = 1; - /* Initialize area detection */ - area_minx[0] = area_minx[3] = area_minx[6] = area_miny[0] = area_miny[1] = area_miny[2] = 0; - area_minx[1] = area_minx[4] = area_minx[7] = area_maxx[0] = area_maxx[3] = area_maxx[6] = cnt->imgs.width / 3; - area_minx[2] = area_minx[5] = area_minx[8] = area_maxx[1] = area_maxx[4] = area_maxx[7] = cnt->imgs.width / 3 * 2; - area_miny[3] = area_miny[4] = area_miny[5] = area_maxy[0] = area_maxy[1] = area_maxy[2] = cnt->imgs.height / 3; - area_miny[6] = area_miny[7] = area_miny[8] = area_maxy[3] = area_maxy[4] = area_maxy[5] = cnt->imgs.height / 3 * 2; - area_maxx[2] = area_maxx[5] = area_maxx[8] = cnt->imgs.width; - area_maxy[6] = area_maxy[7] = area_maxy[8] = cnt->imgs.height; - - /* Work out expected frame rate based on config setting */ - if (cnt->conf.frame_limit < 2) cnt->conf.frame_limit = 2; + /* Initialize area detection */ + area_minx[0] = area_minx[3] = area_minx[6] = 0; + area_miny[0] = area_miny[1] = area_miny[2] = 0; - required_frame_time = 1000000L / cnt->conf.frame_limit; + area_minx[1] = area_minx[4] = area_minx[7] = cnt->imgs.width / 3; + area_maxx[0] = area_maxx[3] = area_maxx[6] = cnt->imgs.width / 3; - frame_delay = required_frame_time; + area_minx[2] = area_minx[5] = area_minx[8] = cnt->imgs.width / 3 * 2; + area_maxx[1] = area_maxx[4] = area_maxx[7] = cnt->imgs.width / 3 * 2; - /* - * Reserve enough space for a 10 second timing history buffer. Note that, - * if there is any problem on the allocation, mymalloc does not return. - */ - rolling_average_limit = 10 * cnt->conf.frame_limit; - rolling_average_data = mymalloc(sizeof(rolling_average_data) * rolling_average_limit); + area_miny[3] = area_miny[4] = area_miny[5] = cnt->imgs.height / 3; + area_maxy[0] = area_maxy[1] = area_maxy[2] = cnt->imgs.height / 3; - /* Preset history buffer with expected frame rate */ - for (j=0; j< rolling_average_limit; j++) - rolling_average_data[j]=required_frame_time; + area_miny[6] = area_miny[7] = area_miny[8] = cnt->imgs.height / 3 * 2; + area_maxy[3] = area_maxy[4] = area_maxy[5] = cnt->imgs.height / 3 * 2; + + area_maxx[2] = area_maxx[5] = area_maxx[8] = cnt->imgs.width; + area_maxy[6] = area_maxy[7] = area_maxy[8] = cnt->imgs.height; + + /* Work out expected frame rate based on config setting */ + if (cnt->conf.frame_limit < 2) + cnt->conf.frame_limit = 2; + + required_frame_time = 1000000L / cnt->conf.frame_limit; + + frame_delay = required_frame_time; + + /* + * Reserve enough space for a 10 second timing history buffer. Note that, + * if there is any problem on the allocation, mymalloc does not return. + */ + rolling_average_limit = 10 * cnt->conf.frame_limit; + rolling_average_data = mymalloc(sizeof(rolling_average_data) * rolling_average_limit); + + /* Preset history buffer with expected frame rate */ + for (j=0; j< rolling_average_limit; j++) + rolling_average_data[j]=required_frame_time; - /* MAIN MOTION LOOP BEGINS HERE */ - /* Should go on forever... unless you bought vaporware :) */ + /* MAIN MOTION LOOP BEGINS HERE */ + /* Should go on forever... unless you bought vaporware :) */ - while (!cnt->finish || cnt->makemovie) { + while (!cnt->finish || cnt->makemovie) { - /***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/ - cnt->watchdog = WATCHDOG_TMO; + /***** MOTION LOOP - PREPARE FOR NEW FRAME SECTION *****/ + cnt->watchdog = WATCHDOG_TMO; - /* Get current time and preserver last time for frame interval calc. */ - timebefore = timenow; - gettimeofday(&tv1, NULL); - timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; + /* Get current time and preserver last time for frame interval calc. */ + timebefore = timenow; + gettimeofday(&tv1, NULL); + timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; - /* since we don't have sanity checks done when options are set, - * this sanity check must go in the main loop :(, before pre_captures - * are attempted. */ - if (cnt->conf.minimum_motion_frames < 1) - cnt->conf.minimum_motion_frames = 1; - if (cnt->conf.pre_capture < 0) - cnt->conf.pre_capture = 0; + /* since we don't have sanity checks done when options are set, + * this sanity check must go in the main loop :(, before pre_captures + * are attempted. */ + if (cnt->conf.minimum_motion_frames < 1) + cnt->conf.minimum_motion_frames = 1; + + if (cnt->conf.pre_capture < 0) + cnt->conf.pre_capture = 0; - /* Check if our buffer is still the right size - * If pre_capture or minimum_motion_frames has been changed - * via the http remote control we need to re-size the ring buffer - */ - frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames; - if (cnt->imgs.image_ring_size != frame_buffer_size) { - image_ring_resize(cnt, frame_buffer_size); - } + /* Check if our buffer is still the right size + * If pre_capture or minimum_motion_frames has been changed + * via the http remote control we need to re-size the ring buffer + */ + frame_buffer_size = cnt->conf.pre_capture + cnt->conf.minimum_motion_frames; + + if (cnt->imgs.image_ring_size != frame_buffer_size) + image_ring_resize(cnt, frame_buffer_size); + - /* Get time for current frame */ - cnt->currenttime = time(NULL); + /* Get time for current frame */ + cnt->currenttime = time(NULL); - /* localtime returns static data and is not threadsafe - * so we use localtime_r which is reentrant and threadsafe - */ - localtime_r(&cnt->currenttime, cnt->currenttime_tm); + /* localtime returns static data and is not threadsafe + * so we use localtime_r which is reentrant and threadsafe + */ + localtime_r(&cnt->currenttime, cnt->currenttime_tm); - /* If we have started on a new second we reset the shots variable - * lastrate is updated to be the number of the last frame. last rate - * is used as the ffmpeg framerate when motion is detected. - */ - if (lastframetime != cnt->currenttime) { - cnt->lastrate = cnt->shots + 1; - cnt->shots = -1; - lastframetime = cnt->currenttime; - if (cnt->conf.minimum_frame_time) { - minimum_frame_time_downcounter--; - if (minimum_frame_time_downcounter == 0) - get_image = 1; - } - else - get_image = 1; - } + /* If we have started on a new second we reset the shots variable + * lastrate is updated to be the number of the last frame. last rate + * is used as the ffmpeg framerate when motion is detected. + */ + if (lastframetime != cnt->currenttime) { + cnt->lastrate = cnt->shots + 1; + cnt->shots = -1; + lastframetime = cnt->currenttime; + if (cnt->conf.minimum_frame_time) { + minimum_frame_time_downcounter--; + if (minimum_frame_time_downcounter == 0) + get_image = 1; + } else { + get_image = 1; + } + } - /* Increase the shots variable for each frame captured within this second */ - cnt->shots++; + /* Increase the shots variable for each frame captured within this second */ + cnt->shots++; - if (cnt->startup_frames > 0) - cnt->startup_frames--; + if (cnt->startup_frames > 0) + cnt->startup_frames--; - if (get_image){ - if (cnt->conf.minimum_frame_time) { - minimum_frame_time_downcounter = cnt->conf.minimum_frame_time; - get_image = 0; - } + if (get_image){ + if (cnt->conf.minimum_frame_time) { + minimum_frame_time_downcounter = cnt->conf.minimum_frame_time; + get_image = 0; + } - /* ring_buffer_in is pointing to current pos, update before put in a new image */ - if (++cnt->imgs.image_ring_in >= cnt->imgs.image_ring_size) - cnt->imgs.image_ring_in = 0; + /* ring_buffer_in is pointing to current pos, update before put in a new image */ + if (++cnt->imgs.image_ring_in >= cnt->imgs.image_ring_size) + cnt->imgs.image_ring_in = 0; - /* Check if we have filled the ring buffer, throw away last image */ - if (cnt->imgs.image_ring_in == cnt->imgs.image_ring_out) { - if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size) - cnt->imgs.image_ring_out = 0; - } + /* Check if we have filled the ring buffer, throw away last image */ + if (cnt->imgs.image_ring_in == cnt->imgs.image_ring_out) { + if (++cnt->imgs.image_ring_out >= cnt->imgs.image_ring_size) + cnt->imgs.image_ring_out = 0; + } - /* cnt->current_image points to position in ring where to store image, diffs etc. */ - cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in]; + /* cnt->current_image points to position in ring where to store image, diffs etc. */ + cnt->current_image = &cnt->imgs.image_ring[cnt->imgs.image_ring_in]; - /* Init/clear current_image */ - { - /* Store time with pre_captured image */ - cnt->current_image->timestamp = cnt->currenttime; - localtime_r(&cnt->current_image->timestamp, &cnt->current_image->timestamp_tm); + /* Init/clear current_image */ + { + /* Store time with pre_captured image */ + cnt->current_image->timestamp = cnt->currenttime; + localtime_r(&cnt->current_image->timestamp, &cnt->current_image->timestamp_tm); - /* Store shot number with pre_captured image */ - cnt->current_image->shot = cnt->shots; + /* Store shot number with pre_captured image */ + cnt->current_image->shot = cnt->shots; - /* set diffs to 0 now, will be written after we calculated diffs in new image */ - cnt->current_image->diffs = 0; + /* set diffs to 0 now, will be written after we calculated diffs in new image */ + cnt->current_image->diffs = 0; - /* Set flags to 0 */ - cnt->current_image->flags = 0; - cnt->current_image->cent_dist = 0; + /* Set flags to 0 */ + cnt->current_image->flags = 0; + cnt->current_image->cent_dist = 0; - /* Clear location data */ - memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location)); - cnt->current_image->total_labels = 0; - } + /* Clear location data */ + memset(&cnt->current_image->location, 0, sizeof(cnt->current_image->location)); + cnt->current_image->total_labels = 0; + } - /***** MOTION LOOP - RETRY INITIALIZING SECTION *****/ - /* If a camera is not available we keep on retrying every 10 seconds - * until it shows up. - */ - if (cnt->video_dev < 0 && - cnt->currenttime % 10 == 0 && cnt->shots == 0) { - motion_log(LOG_ERR, 0, - "Retrying until successful connection with camera"); - cnt->video_dev = vid_start(cnt); + /***** MOTION LOOP - RETRY INITIALIZING SECTION *****/ + /* If a camera is not available we keep on retrying every 10 seconds + * until it shows up. + */ + if (cnt->video_dev < 0 && + cnt->currenttime % 10 == 0 && cnt->shots == 0) { + motion_log(LOG_ERR, 0, + "Retrying until successful connection with camera"); + cnt->video_dev = vid_start(cnt); - /* if the netcam has different dimensions than in the config file - * we need to restart Motion to re-allocate all the buffers - */ - if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) { - motion_log(LOG_ERR, 0, "Camera has finally become available"); - motion_log(LOG_ERR, 0, "Camera image has different width and height " - "from what is in the config file. You should fix that"); - motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all " - "image buffers to new picture dimensions"); - cnt->conf.width = cnt->imgs.width; - cnt->conf.height = cnt->imgs.height; - /* Break out of main loop terminating thread - * watchdog will start us again */ - break; - } - } + /* if the netcam has different dimensions than in the config file + * we need to restart Motion to re-allocate all the buffers + */ + if (cnt->imgs.width != cnt->conf.width || cnt->imgs.height != cnt->conf.height) { + motion_log(LOG_ERR, 0, "Camera has finally become available"); + motion_log(LOG_ERR, 0, "Camera image has different width and height " + "from what is in the config file. You should fix that"); + motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all " + "image buffers to new picture dimensions"); + cnt->conf.width = cnt->imgs.width; + cnt->conf.height = cnt->imgs.height; + /* Break out of main loop terminating thread + * watchdog will start us again */ + break; + } + } - /***** MOTION LOOP - IMAGE CAPTURE SECTION *****/ + /***** MOTION LOOP - IMAGE CAPTURE SECTION *****/ - /* Fetch next frame from camera - * If vid_next returns 0 all is well and we got a new picture - * Any non zero value is an error. - * 0 = OK, valid picture - * <0 = fatal error - leave the thread by breaking out of the main loop - * >0 = non fatal error - copy last image or show grey image with message - */ - if (cnt->video_dev >= 0) - vid_return_code = vid_next(cnt, cnt->current_image->image); - else - vid_return_code = 1; /* Non fatal error */ + /* Fetch next frame from camera + * If vid_next returns 0 all is well and we got a new picture + * Any non zero value is an error. + * 0 = OK, valid picture + * <0 = fatal error - leave the thread by breaking out of the main loop + * >0 = non fatal error - copy last image or show grey image with message + */ + if (cnt->video_dev >= 0) + vid_return_code = vid_next(cnt, cnt->current_image->image); + else + vid_return_code = 1; /* Non fatal error */ - // VALID PICTURE - if (vid_return_code == 0) { - cnt->lost_connection = 0; - cnt->connectionlosttime = 0; + // VALID PICTURE + if (vid_return_code == 0) { + cnt->lost_connection = 0; + cnt->connectionlosttime = 0; - /* If all is well reset missing_frame_counter */ - if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) { - /* If we previously logged starting a grey image, now log video re-start */ - motion_log(LOG_ERR, 0, "Video signal re-acquired"); - // event for re-acquired video signal can be called here - } - cnt->missing_frame_counter = 0; + /* If all is well reset missing_frame_counter */ + if (cnt->missing_frame_counter >= MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) + /* If we previously logged starting a grey image, now log video re-start */ + motion_log(LOG_ERR, 0, "Video signal re-acquired"); + // event for re-acquired video signal can be called here + + + cnt->missing_frame_counter = 0; #ifdef HAVE_FFMPEG - /* Deinterlace the image with ffmpeg, before the image is modified. */ - if(cnt->conf.ffmpeg_deinterlace) { - ffmpeg_deinterlace(cnt->current_image->image, cnt->imgs.width, cnt->imgs.height); - } + /* Deinterlace the image with ffmpeg, before the image is modified. */ + if (cnt->conf.ffmpeg_deinterlace) + ffmpeg_deinterlace(cnt->current_image->image, cnt->imgs.width, cnt->imgs.height); + #endif - /* save the newly captured still virgin image to a buffer - * which we will not alter with text and location graphics - */ - memcpy(cnt->imgs.image_virgin, cnt->current_image->image, cnt->imgs.size); - - /* If the camera is a netcam we let the camera decide the pace. - * Otherwise we will keep on adding duplicate frames. - * By resetting the timer the framerate becomes maximum the rate - * of the Netcam. - */ - if (cnt->conf.netcam_url) { - gettimeofday(&tv1, NULL); - timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; - } - // FATAL ERROR - leave the thread by breaking out of the main loop - } else if (vid_return_code < 0) { - /* Fatal error - Close video device */ - motion_log(LOG_ERR, 0, "Video device fatal error - Closing video device"); - vid_close(cnt); - /* Use virgin image, if we are not able to open it again next loop - * a gray image with message is applied - * flag lost_connection - */ - memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size); - cnt->lost_connection = 1; - /* NO FATAL ERROR - - * copy last image or show grey image with message - * flag on lost_connection if : - * vid_return_code == NETCAM_RESTART_ERROR - * cnt->video_dev < 0 - * cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) - */ - } else { - - if (debug_level >= CAMERA_VERBOSE) - motion_log(-1, 0, "vid_return_code %d", vid_return_code); - - /* Netcams that change dimensions while Motion is running will - * require that Motion restarts to reinitialize all the many - * buffers inside Motion. It will be a mess to try and recover any - * other way - */ - if (vid_return_code == NETCAM_RESTART_ERROR) { - motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all " - "image buffers"); - /* Break out of main loop terminating thread - * watchdog will start us again - * Set lost_connection flag on */ - - cnt->lost_connection = 1; - break; - } - - /* First missed frame - store timestamp - * Don't reset time when thread restarts*/ - if (cnt->connectionlosttime == 0) - cnt->connectionlosttime = cnt->currenttime; - - /* Increase missing_frame_counter - * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image - * After 30 seconds we put a grey error image in the buffer - * If we still have not yet received the initial image from a camera - * we go straight for the grey error image. - */ - ++cnt->missing_frame_counter; - if (cnt->video_dev >= 0 && - cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)) { - memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size); - } else { - const char *tmpin; - char tmpout[80]; - struct tm tmptime; - cnt->lost_connection = 1; - - if (cnt->video_dev >= 0) - tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T"; - else - tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T"; - localtime_r(&cnt->connectionlosttime, &tmptime); - memset(cnt->current_image->image, 0x80, cnt->imgs.size); - mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tmptime, NULL, 0); - draw_text(cnt->current_image->image, 10, 20 * text_size_factor, cnt->imgs.width, - tmpout, cnt->conf.text_double); - - /* Write error message only once */ - if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) { - motion_log(LOG_ERR, 0, "Video signal lost - Adding grey image"); - // Event for lost video signal can be called from here - event(cnt, EVENT_CAMERA_LOST, NULL, NULL, - NULL, cnt->currenttime_tm); - } - - /* If we don't get a valid frame for a long time, try to close/reopen device - * Only try this when a device is open */ - if ( (cnt->video_dev > 0) && - (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.frame_limit) ) { - motion_log(LOG_ERR, 0, "Video signal still lost - Trying to close video device"); - vid_close(cnt); - } - } - } - - /***** MOTION LOOP - MOTION DETECTION SECTION *****/ - - /* The actual motion detection takes place in the following - * diffs is the number of pixels detected as changed - * Make a differences picture in image_out - * - * alg_diff_standard is the slower full feature motion detection algorithm - * alg_diff first calls a fast detection algorithm which only looks at a - * fraction of the pixels. If this detects possible motion alg_diff_standard - * is called. - */ - if (cnt->threshold && !cnt->pause) { - /* if we've already detected motion and we want to see if there's - * still motion, don't bother trying the fast one first. IF there's - * motion, the alg_diff will trigger alg_diff_standard - * anyway - */ - if (cnt->detecting_motion || cnt->conf.setup_mode) - cnt->current_image->diffs = alg_diff_standard(cnt, cnt->imgs.image_virgin); - else - cnt->current_image->diffs = alg_diff(cnt, cnt->imgs.image_virgin); - - /* Lightswitch feature - has light intensity changed? - * This can happen due to change of light conditions or due to a sudden change of the camera - * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next - * 5 frames to allow the camera to settle. - * Don't check if we have lost connection, we detect "Lost signal" frame as lightswitch - */ - if (cnt->conf.lightswitch && !cnt->lost_connection) { - if (alg_lightswitch(cnt, cnt->current_image->diffs)) { - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Lightswitch detected"); - if (cnt->moved < 5) - cnt->moved = 5; - cnt->current_image->diffs = 0; - alg_update_reference_frame(cnt, RESET_REF_FRAME); - } - } - - /* Switchfilter feature tries to detect a change in the video signal - * from one camera to the next. This is normally used in the Round - * Robin feature. The algorithm is not very safe. - * The algorithm takes a little time so we only call it when needed - * ie. when feature is enabled and diffs>threshold. - * We do not suspend motion detection like we did for lightswitch - * because with Round Robin this is controlled by roundrobin_skip. - */ - if (cnt->conf.switchfilter && cnt->current_image->diffs > cnt->threshold) { - cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs, cnt->current_image->image); - if (cnt->current_image->diffs <= cnt->threshold) { - cnt->current_image->diffs = 0; - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Switchfilter detected"); - } - } - - /* Despeckle feature - * First we run (as given by the despeckle option iterations - * of erode and dilate algorithms. - * Finally we run the labelling feature. - * All this is done in the alg_despeckle code. - */ - cnt->current_image->total_labels = 0; - cnt->imgs.largest_label = 0; - olddiffs = 0; - if (cnt->conf.despeckle && cnt->current_image->diffs > 0) { - olddiffs = cnt->current_image->diffs; - cnt->current_image->diffs = alg_despeckle(cnt, olddiffs); - }else if (cnt->imgs.labelsize_max) - cnt->imgs.labelsize_max = 0; /* Disable labeling if enabled */ - - } else if (!cnt->conf.setup_mode) - cnt->current_image->diffs = 0; - - /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */ - if (cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) { - if (!--smartmask_count){ - alg_tune_smartmask(cnt); - smartmask_count = smartmask_ratio; - } - } - - /* cnt->moved is set by the tracking code when camera has been asked to move. - * When camera is moving we do not want motion to detect motion or we will - * get our camera chasing itself like crazy and we will get motion detected - * which is not really motion. So we pretend there is no motion by setting - * cnt->diffs = 0. - * We also pretend to have a moving camera when we start Motion and when light - * switch has been detected to allow camera to settle. - */ - if (cnt->moved) { - cnt->moved--; - cnt->current_image->diffs = 0; - } - - /***** MOTION LOOP - TUNING SECTION *****/ - - /* if noise tuning was selected, do it now. but only when - * no frames have been recorded and only once per second - */ - if (cnt->conf.noise_tune && cnt->shots == 0) { - if (!cnt->detecting_motion && (cnt->current_image->diffs <= cnt->threshold)) - alg_noise_tune(cnt, cnt->imgs.image_virgin); - } - - /* if we are not noise tuning lets make sure that remote controlled - * changes of noise_level are used. - */ - if (!cnt->conf.noise_tune) - cnt->noise = cnt->conf.noise; - - /* threshold tuning if enabled - * if we are not threshold tuning lets make sure that remote controlled - * changes of threshold are used. - */ - if (cnt->conf.threshold_tune) - alg_threshold_tune(cnt, cnt->current_image->diffs, cnt->detecting_motion); - else - cnt->threshold = cnt->conf.max_changes; - - /* If motion is detected (cnt->current_image->diffs > cnt->threshold) and before we add text to the pictures - we find the center and size coordinates of the motion to be used for text overlays and later - for adding the locate rectangle */ - if (cnt->current_image->diffs > cnt->threshold) - alg_locate_center_size(&cnt->imgs, cnt->imgs.width, cnt->imgs.height, &cnt->current_image->location); - - /* Update reference frame. */ - /* micro-lighswitch: e.g. neighbors cat switched on the motion sensitive * - * frontdoor illumination. Updates are rate-limited to 3 per second at * - * framerates above 5fps to save CPU resources and to keep sensitivity * - * at a constant level. * - */ - ref_frame_limit++; - if (ref_frame_limit >= (cnt->lastrate / 3)) { - ref_frame_limit = 0; - if ((cnt->current_image->diffs > cnt->threshold) && - (cnt->lightswitch_framecounter < (cnt->lastrate * 2)) && /* two seconds window */ - ((abs(previous_diffs - cnt->current_image->diffs)) < (previous_diffs / 15)) && - ((abs(cnt->current_image->location.x - previous_location_x)) <= (cnt->imgs.width / 150)) && - ((abs(cnt->current_image->location.y - previous_location_y)) <= (cnt->imgs.height / 150))) { - alg_update_reference_frame(cnt, RESET_REF_FRAME); - cnt->current_image->diffs = 0; - cnt->lightswitch_framecounter = 0; - if (cnt->conf.setup_mode) - motion_log(-1, 0, "micro-lightswitch!"); - } else { - alg_update_reference_frame(cnt, UPDATE_REF_FRAME); - } - previous_diffs = cnt->current_image->diffs; - previous_location_x = cnt->current_image->location.x; - previous_location_y = cnt->current_image->location.y; - } - - /***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/ - - /* Some overlays on top of the motion image - * Note that these now modifies the cnt->imgs.out so this buffer - * can no longer be used for motion detection features until next - * picture frame is captured. - */ - - /* Smartmask overlay */ - if (cnt->smartmask_speed && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) ) - overlay_smartmask(cnt, cnt->imgs.out); - - /* Largest labels overlay */ - if (cnt->imgs.largest_label && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) ) - overlay_largest_label(cnt, cnt->imgs.out); - - - /* Fixed mask overlay */ - if (cnt->imgs.mask && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode) ) - overlay_fixed_mask(cnt, cnt->imgs.out); - - /* Initialize the double sized characters if needed. */ - if(cnt->conf.text_double && text_size_factor == 1) - text_size_factor = 2; - - /* If text_double is set to off, then reset the scaling text_size_factor. */ - else if(!cnt->conf.text_double && text_size_factor == 2) { - text_size_factor = 1; - } - - /* Add changed pixels in upper right corner of the pictures */ - if (cnt->conf.text_changes) { - char tmp[15]; - - if (!cnt->pause) - sprintf(tmp, "%d", cnt->current_image->diffs); - else - sprintf(tmp, "-"); - - draw_text(cnt->current_image->image, cnt->imgs.width - 10, 10, cnt->imgs.width, tmp, cnt->conf.text_double); - } - - /* Add changed pixels to motion-images (for webcam) in setup_mode - and always overlay smartmask (not only when motion is detected) */ - if (cnt->conf.setup_mode) { - char tmp[PATH_MAX]; - sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs, cnt->current_image->total_labels, cnt->noise); - draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 30 * text_size_factor, - cnt->imgs.width, tmp, cnt->conf.text_double); - sprintf(tmp, "THREAD %d SETUP", cnt->threadnr); - draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor, - cnt->imgs.width, tmp, cnt->conf.text_double); - } - - /* Add text in lower left corner of the pictures */ - if (cnt->conf.text_left) { - char tmp[PATH_MAX]; - mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left, &cnt->current_image->timestamp_tm, NULL, 0); - draw_text(cnt->current_image->image, 10, cnt->imgs.height - 10 * text_size_factor, cnt->imgs.width, - tmp, cnt->conf.text_double); - } - - /* Add text in lower right corner of the pictures */ - if (cnt->conf.text_right) { - char tmp[PATH_MAX]; - mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right, &cnt->current_image->timestamp_tm, NULL, 0); - draw_text(cnt->current_image->image, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor, - cnt->imgs.width, tmp, cnt->conf.text_double); - } - - - /***** MOTION LOOP - ACTIONS AND EVENT CONTROL SECTION *****/ - - if (cnt->current_image->diffs > cnt->threshold) { - /* flag this image, it have motion */ - cnt->current_image->flags |= IMAGE_MOTION; - cnt->lightswitch_framecounter++; /* micro lightswitch */ - } else cnt->lightswitch_framecounter = 0; - - /* If motion has been detected we take action and start saving - * pictures and movies etc by calling motion_detected(). - * Is output_all enabled we always call motion_detected() - * If post_capture is enabled we also take care of this in the this - * code section. - */ - if ( cnt->conf.output_all && (cnt->startup_frames == 0) ) { - cnt->detecting_motion = 1; - /* Setup the postcap counter */ - cnt->postcap = cnt->conf.post_capture; - cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); - motion_detected(cnt, cnt->video_dev, cnt->current_image); - } else if ( (cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0) ) { - /* Did we detect motion (like the cat just walked in :) )? - * If so, ensure the motion is sustained if minimum_motion_frames - */ - - /* Count how many frames with motion there is in the last minimum_motion_frames in precap buffer */ - int frame_count = 0; - int pos = cnt->imgs.image_ring_in; - - for(i = 0; i < cnt->conf.minimum_motion_frames; i++) - { - if(cnt->imgs.image_ring[pos].flags & IMAGE_MOTION) - frame_count++; - if (pos == 0) { - pos = cnt->imgs.image_ring_size-1; - } else { - pos--; - } - } - - if (frame_count >= cnt->conf.minimum_motion_frames) { - cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); - cnt->detecting_motion = 1; - /* Setup the postcap counter */ - cnt->postcap = cnt->conf.post_capture; - /* Mark all images in image_ring to be saved */ - for(i = 0; i < cnt->imgs.image_ring_size; i++) { - cnt->imgs.image_ring[i].flags |= IMAGE_SAVE; - } - } - else if (cnt->postcap) { /* we have motion in this frame, but not enought frames for trigger. Check postcap */ - cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); - cnt->postcap--; - } else { - cnt->current_image->flags |= IMAGE_PRECAP; - } - - /* Always call motion_detected when we have a motion image */ - motion_detected(cnt, cnt->video_dev, cnt->current_image); - } else if (cnt->postcap) { - /* No motion, doing postcap */ - cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); - cnt->postcap--; - } else { - /* Done with postcap, so just have the image in the precap buffer */ - cnt->current_image->flags |= IMAGE_PRECAP; - cnt->detecting_motion = 0; - } - - /* Update last frame saved time, so we can end event after gap time */ - if (cnt->current_image->flags & IMAGE_SAVE) { - cnt->lasttime = cnt->current_image->timestamp; - } - - /* Simple hack to recognize motion in a specific area */ - /* Do we need a new coversion specifier as well?? */ - if ((cnt->conf.area_detect) && (cnt->event_nr != area_once) && (cnt->current_image->flags & IMAGE_TRIGGER)) { - j = strlen(cnt->conf.area_detect); - for (i = 0; i < j; i++) { - z = cnt->conf.area_detect[i] - 49; /* 1 becomes 0 */ - if ((z >= 0) && (z < 9)) { - if (cnt->current_image->location.x > area_minx[z] && - cnt->current_image->location.x < area_maxx[z] && - cnt->current_image->location.y > area_miny[z] && - cnt->current_image->location.y < area_maxy[z]) { - event(cnt, EVENT_AREA_DETECTED, NULL, NULL, - NULL, cnt->currenttime_tm); - area_once = cnt->event_nr; /* Fire script only once per event */ - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Motion in area %d detected.\n", z+1); - break; - } - } - } - } - - /* Is the mpeg movie to long? Then make movies - * First test for max mpegtime - */ - if (cnt->conf.maxmpegtime && cnt->event_nr == cnt->prev_event) - if (cnt->currenttime - cnt->eventtime >= cnt->conf.maxmpegtime) - cnt->makemovie = 1; - - /* Now test for quiet longer than 'gap' OR make movie as decided in - * previous statement. - */ - if (((cnt->currenttime - cnt->lasttime >= cnt->conf.gap) && cnt->conf.gap > 0) || cnt->makemovie) { - if (cnt->event_nr == cnt->prev_event || cnt->makemovie) { - - /* Flush image buffer */ - process_image_ring(cnt, IMAGE_BUFFER_FLUSH); - - /* Save preview_shot here at the end of event */ - if (cnt->imgs.preview_image.diffs) { - preview_save(cnt); - cnt->imgs.preview_image.diffs = 0; - } - - event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, cnt->currenttime_tm); - - /* if tracking is enabled we center our camera so it does not - * point to a place where it will miss the next action - */ - if (cnt->track.type) - cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0); - - if (cnt->conf.setup_mode) - motion_log(-1, 0, "End of event %d", cnt->event_nr); - - cnt->makemovie = 0; - /* Reset post capture */ - cnt->postcap = 0; - - /* Finally we increase the event number */ - cnt->event_nr++; - cnt->lightswitch_framecounter = 0; - - /* And we unset the text_event_string to avoid that buffered - * images get a timestamp from previous event. - */ - cnt->text_event_string[0] = '\0'; - } - } - - /* Save/send to movie some images */ - process_image_ring(cnt, 2); - - /***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/ - - /* If setup_mode enabled output some numbers to console */ - if (cnt->conf.setup_mode){ - char msg[1024] = "\0"; - char part[100]; - - if (cnt->conf.despeckle) { - snprintf(part, 99, "Raw changes: %5d - changes after '%s': %5d", - olddiffs, cnt->conf.despeckle, cnt->current_image->diffs); - strcat(msg, part); - if (strchr(cnt->conf.despeckle, 'l')){ - sprintf(part, " - labels: %3d", cnt->current_image->total_labels); - strcat(msg, part); - } - } - else{ - sprintf(part, "Changes: %5d", cnt->current_image->diffs); - strcat(msg, part); - } - if (cnt->conf.noise_tune){ - sprintf(part, " - noise level: %2d", cnt->noise); - strcat(msg, part); - } - if (cnt->conf.threshold_tune){ - sprintf(part, " - threshold: %d", cnt->threshold); - strcat(msg, part); - } - motion_log(-1, 0, "%s", msg); - } - - } /* get_image end */ - - /***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/ - - /* Did we get triggered to make a snapshot from control http? Then shoot a snap - * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap - * We actually allow the time to run over the interval in case we have a delay - * from slow camera. - * Note: Negative value means SIGALRM snaps are enabled - * httpd-control snaps are always enabled. - */ - - /* time_current_frame is used both for snapshot and timelapse features */ - time_current_frame = cnt->currenttime; - - if ( (cnt->conf.snapshot_interval > 0 && cnt->shots == 0 && - time_current_frame % cnt->conf.snapshot_interval <= time_last_frame % cnt->conf.snapshot_interval) || - cnt->snapshot) { - event(cnt, EVENT_IMAGE_SNAPSHOT, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); - cnt->snapshot = 0; - } - - - /***** MOTION LOOP - TIMELAPSE FEATURE SECTION *****/ + /* save the newly captured still virgin image to a buffer + * which we will not alter with text and location graphics + */ + memcpy(cnt->imgs.image_virgin, cnt->current_image->image, cnt->imgs.size); + + /* If the camera is a netcam we let the camera decide the pace. + * Otherwise we will keep on adding duplicate frames. + * By resetting the timer the framerate becomes maximum the rate + * of the Netcam. + */ + if (cnt->conf.netcam_url) { + gettimeofday(&tv1, NULL); + timenow = tv1.tv_usec + 1000000L * tv1.tv_sec; + } + // FATAL ERROR - leave the thread by breaking out of the main loop + } else if (vid_return_code < 0) { + /* Fatal error - Close video device */ + motion_log(LOG_ERR, 0, "Video device fatal error - Closing video device"); + vid_close(cnt); + /* Use virgin image, if we are not able to open it again next loop + * a gray image with message is applied + * flag lost_connection + */ + memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size); + cnt->lost_connection = 1; + /* NO FATAL ERROR - + * copy last image or show grey image with message + * flag on lost_connection if : + * vid_return_code == NETCAM_RESTART_ERROR + * cnt->video_dev < 0 + * cnt->missing_frame_counter > (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) + */ + } else { + + if (debug_level >= CAMERA_VERBOSE) + motion_log(-1, 0, "vid_return_code %d", vid_return_code); + + /* Netcams that change dimensions while Motion is running will + * require that Motion restarts to reinitialize all the many + * buffers inside Motion. It will be a mess to try and recover any + * other way + */ + if (vid_return_code == NETCAM_RESTART_ERROR) { + motion_log(LOG_ERR, 0, "Restarting Motion thread to reinitialize all " + "image buffers"); + /* Break out of main loop terminating thread + * watchdog will start us again + * Set lost_connection flag on */ + + cnt->lost_connection = 1; + break; + } + + /* First missed frame - store timestamp + * Don't reset time when thread restarts*/ + if (cnt->connectionlosttime == 0) + cnt->connectionlosttime = cnt->currenttime; + + /* Increase missing_frame_counter + * The first MISSING_FRAMES_TIMEOUT seconds we copy previous virgin image + * After 30 seconds we put a grey error image in the buffer + * If we still have not yet received the initial image from a camera + * we go straight for the grey error image. + */ + ++cnt->missing_frame_counter; + if (cnt->video_dev >= 0 && + cnt->missing_frame_counter < (MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit)) { + memcpy(cnt->current_image->image, cnt->imgs.image_virgin, cnt->imgs.size); + } else { + const char *tmpin; + char tmpout[80]; + struct tm tmptime; + cnt->lost_connection = 1; + + if (cnt->video_dev >= 0) + tmpin = "CONNECTION TO CAMERA LOST\\nSINCE %Y-%m-%d %T"; + else + tmpin = "UNABLE TO OPEN VIDEO DEVICE\\nSINCE %Y-%m-%d %T"; + + localtime_r(&cnt->connectionlosttime, &tmptime); + memset(cnt->current_image->image, 0x80, cnt->imgs.size); + mystrftime(cnt, tmpout, sizeof(tmpout), tmpin, &tmptime, NULL, 0); + draw_text(cnt->current_image->image, 10, 20 * text_size_factor, cnt->imgs.width, + tmpout, cnt->conf.text_double); + + /* Write error message only once */ + if (cnt->missing_frame_counter == MISSING_FRAMES_TIMEOUT * cnt->conf.frame_limit) { + motion_log(LOG_ERR, 0, "Video signal lost - Adding grey image"); + // Event for lost video signal can be called from here + event(cnt, EVENT_CAMERA_LOST, NULL, NULL, + NULL, cnt->currenttime_tm); + } + + /* If we don't get a valid frame for a long time, try to close/reopen device + * Only try this when a device is open */ + if ((cnt->video_dev > 0) && + (cnt->missing_frame_counter == (MISSING_FRAMES_TIMEOUT * 4) * cnt->conf.frame_limit)) { + motion_log(LOG_ERR, 0, "Video signal still lost - Trying to close video device"); + vid_close(cnt); + } + } + } + + /***** MOTION LOOP - MOTION DETECTION SECTION *****/ + + /* The actual motion detection takes place in the following + * diffs is the number of pixels detected as changed + * Make a differences picture in image_out + * + * alg_diff_standard is the slower full feature motion detection algorithm + * alg_diff first calls a fast detection algorithm which only looks at a + * fraction of the pixels. If this detects possible motion alg_diff_standard + * is called. + */ + if (cnt->threshold && !cnt->pause) { + /* if we've already detected motion and we want to see if there's + * still motion, don't bother trying the fast one first. IF there's + * motion, the alg_diff will trigger alg_diff_standard + * anyway + */ + if (cnt->detecting_motion || cnt->conf.setup_mode) + cnt->current_image->diffs = alg_diff_standard(cnt, cnt->imgs.image_virgin); + else + cnt->current_image->diffs = alg_diff(cnt, cnt->imgs.image_virgin); + + /* Lightswitch feature - has light intensity changed? + * This can happen due to change of light conditions or due to a sudden change of the camera + * sensitivity. If alg_lightswitch detects lightswitch we suspend motion detection the next + * 5 frames to allow the camera to settle. + * Don't check if we have lost connection, we detect "Lost signal" frame as lightswitch + */ + if (cnt->conf.lightswitch && !cnt->lost_connection) { + if (alg_lightswitch(cnt, cnt->current_image->diffs)) { + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Lightswitch detected"); + if (cnt->moved < 5) + cnt->moved = 5; + cnt->current_image->diffs = 0; + alg_update_reference_frame(cnt, RESET_REF_FRAME); + } + } + + /* Switchfilter feature tries to detect a change in the video signal + * from one camera to the next. This is normally used in the Round + * Robin feature. The algorithm is not very safe. + * The algorithm takes a little time so we only call it when needed + * ie. when feature is enabled and diffs>threshold. + * We do not suspend motion detection like we did for lightswitch + * because with Round Robin this is controlled by roundrobin_skip. + */ + if (cnt->conf.switchfilter && cnt->current_image->diffs > cnt->threshold) { + cnt->current_image->diffs = alg_switchfilter(cnt, cnt->current_image->diffs, + cnt->current_image->image); + + if (cnt->current_image->diffs <= cnt->threshold) { + cnt->current_image->diffs = 0; + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Switchfilter detected"); + } + } + + /* Despeckle feature + * First we run (as given by the despeckle option iterations + * of erode and dilate algorithms. + * Finally we run the labelling feature. + * All this is done in the alg_despeckle code. + */ + cnt->current_image->total_labels = 0; + cnt->imgs.largest_label = 0; + olddiffs = 0; + + if (cnt->conf.despeckle && cnt->current_image->diffs > 0) { + olddiffs = cnt->current_image->diffs; + cnt->current_image->diffs = alg_despeckle(cnt, olddiffs); + } else if (cnt->imgs.labelsize_max) { + cnt->imgs.labelsize_max = 0; /* Disable labeling if enabled */ + } + + } else if (!cnt->conf.setup_mode) { + cnt->current_image->diffs = 0; + } + + /* Manipulate smart_mask sensitivity (only every smartmask_ratio seconds) */ + if (cnt->smartmask_speed && (cnt->event_nr != cnt->prev_event)) { + if (!--smartmask_count) { + alg_tune_smartmask(cnt); + smartmask_count = smartmask_ratio; + } + } + + /* cnt->moved is set by the tracking code when camera has been asked to move. + * When camera is moving we do not want motion to detect motion or we will + * get our camera chasing itself like crazy and we will get motion detected + * which is not really motion. So we pretend there is no motion by setting + * cnt->diffs = 0. + * We also pretend to have a moving camera when we start Motion and when light + * switch has been detected to allow camera to settle. + */ + if (cnt->moved) { + cnt->moved--; + cnt->current_image->diffs = 0; + } + + /***** MOTION LOOP - TUNING SECTION *****/ + + /* if noise tuning was selected, do it now. but only when + * no frames have been recorded and only once per second + */ + if (cnt->conf.noise_tune && cnt->shots == 0) { + if (!cnt->detecting_motion && (cnt->current_image->diffs <= cnt->threshold)) + alg_noise_tune(cnt, cnt->imgs.image_virgin); + } + + /* if we are not noise tuning lets make sure that remote controlled + * changes of noise_level are used. + */ + if (!cnt->conf.noise_tune) + cnt->noise = cnt->conf.noise; + + /* threshold tuning if enabled + * if we are not threshold tuning lets make sure that remote controlled + * changes of threshold are used. + */ + if (cnt->conf.threshold_tune) + alg_threshold_tune(cnt, cnt->current_image->diffs, cnt->detecting_motion); + else + cnt->threshold = cnt->conf.max_changes; + + /* If motion is detected (cnt->current_image->diffs > cnt->threshold) and before we add text to the pictures + we find the center and size coordinates of the motion to be used for text overlays and later + for adding the locate rectangle */ + if (cnt->current_image->diffs > cnt->threshold) + alg_locate_center_size(&cnt->imgs, cnt->imgs.width, cnt->imgs.height, + &cnt->current_image->location); + + /* Update reference frame. */ + /* micro-lighswitch: e.g. neighbors cat switched on the motion sensitive * + * frontdoor illumination. Updates are rate-limited to 3 per second at * + * framerates above 5fps to save CPU resources and to keep sensitivity * + * at a constant level. * + */ + ref_frame_limit++; + if (ref_frame_limit >= (cnt->lastrate / 3)) { + ref_frame_limit = 0; + + if ((cnt->current_image->diffs > cnt->threshold) && + (cnt->lightswitch_framecounter < (cnt->lastrate * 2)) && /* two seconds window */ + ((abs(previous_diffs - cnt->current_image->diffs)) < (previous_diffs / 15)) && + ((abs(cnt->current_image->location.x - previous_location_x)) <= (cnt->imgs.width / 150)) && + ((abs(cnt->current_image->location.y - previous_location_y)) <= (cnt->imgs.height / 150))) { + alg_update_reference_frame(cnt, RESET_REF_FRAME); + cnt->current_image->diffs = 0; + cnt->lightswitch_framecounter = 0; + if (cnt->conf.setup_mode) + motion_log(-1, 0, "micro-lightswitch!"); + + } else { + alg_update_reference_frame(cnt, UPDATE_REF_FRAME); + } + + previous_diffs = cnt->current_image->diffs; + previous_location_x = cnt->current_image->location.x; + previous_location_y = cnt->current_image->location.y; + } + + /***** MOTION LOOP - TEXT AND GRAPHICS OVERLAY SECTION *****/ + + /* Some overlays on top of the motion image + * Note that these now modifies the cnt->imgs.out so this buffer + * can no longer be used for motion detection features until next + * picture frame is captured. + */ + + /* Smartmask overlay */ + if (cnt->smartmask_speed && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode)) + overlay_smartmask(cnt, cnt->imgs.out); + + /* Largest labels overlay */ + if (cnt->imgs.largest_label && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode)) + overlay_largest_label(cnt, cnt->imgs.out); + + + /* Fixed mask overlay */ + if (cnt->imgs.mask && (cnt->conf.motion_img || cnt->conf.ffmpeg_cap_motion || cnt->conf.setup_mode)) + overlay_fixed_mask(cnt, cnt->imgs.out); + + /* Initialize the double sized characters if needed. */ + if (cnt->conf.text_double && text_size_factor == 1) + text_size_factor = 2; + + /* If text_double is set to off, then reset the scaling text_size_factor. */ + else if (!cnt->conf.text_double && text_size_factor == 2) { + text_size_factor = 1; + } + + /* Add changed pixels in upper right corner of the pictures */ + if (cnt->conf.text_changes) { + char tmp[15]; + + if (!cnt->pause) + sprintf(tmp, "%d", cnt->current_image->diffs); + else + sprintf(tmp, "-"); + + draw_text(cnt->current_image->image, cnt->imgs.width - 10, 10, cnt->imgs.width, tmp, cnt->conf.text_double); + } + + /* Add changed pixels to motion-images (for webcam) in setup_mode + and always overlay smartmask (not only when motion is detected) */ + if (cnt->conf.setup_mode) { + char tmp[PATH_MAX]; + sprintf(tmp, "D:%5d L:%3d N:%3d", cnt->current_image->diffs, cnt->current_image->total_labels, cnt->noise); + draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 30 * text_size_factor, + cnt->imgs.width, tmp, cnt->conf.text_double); + sprintf(tmp, "THREAD %d SETUP", cnt->threadnr); + draw_text(cnt->imgs.out, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor, + cnt->imgs.width, tmp, cnt->conf.text_double); + } + + /* Add text in lower left corner of the pictures */ + if (cnt->conf.text_left) { + char tmp[PATH_MAX]; + mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_left, &cnt->current_image->timestamp_tm, NULL, 0); + draw_text(cnt->current_image->image, 10, cnt->imgs.height - 10 * text_size_factor, cnt->imgs.width, + tmp, cnt->conf.text_double); + } + + /* Add text in lower right corner of the pictures */ + if (cnt->conf.text_right) { + char tmp[PATH_MAX]; + mystrftime(cnt, tmp, sizeof(tmp), cnt->conf.text_right, &cnt->current_image->timestamp_tm, NULL, 0); + draw_text(cnt->current_image->image, cnt->imgs.width - 10, cnt->imgs.height - 10 * text_size_factor, + cnt->imgs.width, tmp, cnt->conf.text_double); + } + + + /***** MOTION LOOP - ACTIONS AND EVENT CONTROL SECTION *****/ + + if (cnt->current_image->diffs > cnt->threshold) { + /* flag this image, it have motion */ + cnt->current_image->flags |= IMAGE_MOTION; + cnt->lightswitch_framecounter++; /* micro lightswitch */ + } else cnt->lightswitch_framecounter = 0; + + /* If motion has been detected we take action and start saving + * pictures and movies etc by calling motion_detected(). + * Is output_all enabled we always call motion_detected() + * If post_capture is enabled we also take care of this in the this + * code section. + */ + if (cnt->conf.output_all && (cnt->startup_frames == 0)) { + cnt->detecting_motion = 1; + /* Setup the postcap counter */ + cnt->postcap = cnt->conf.post_capture; + cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); + motion_detected(cnt, cnt->video_dev, cnt->current_image); + } else if ((cnt->current_image->flags & IMAGE_MOTION) && (cnt->startup_frames == 0)) { + /* Did we detect motion (like the cat just walked in :) )? + * If so, ensure the motion is sustained if minimum_motion_frames + */ + + /* Count how many frames with motion there is in the last minimum_motion_frames in precap buffer */ + int frame_count = 0; + int pos = cnt->imgs.image_ring_in; + + for(i = 0; i < cnt->conf.minimum_motion_frames; i++) { + if (cnt->imgs.image_ring[pos].flags & IMAGE_MOTION) + frame_count++; + + if (pos == 0) + pos = cnt->imgs.image_ring_size-1; + else + pos--; + + } + + if (frame_count >= cnt->conf.minimum_motion_frames) { + cnt->current_image->flags |= (IMAGE_TRIGGER | IMAGE_SAVE); + cnt->detecting_motion = 1; + /* Setup the postcap counter */ + cnt->postcap = cnt->conf.post_capture; + /* Mark all images in image_ring to be saved */ + for(i = 0; i < cnt->imgs.image_ring_size; i++) + cnt->imgs.image_ring[i].flags |= IMAGE_SAVE; + + } else if (cnt->postcap) { /* we have motion in this frame, but not enought frames for trigger. Check postcap */ + cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); + cnt->postcap--; + } else { + cnt->current_image->flags |= IMAGE_PRECAP; + } + + /* Always call motion_detected when we have a motion image */ + motion_detected(cnt, cnt->video_dev, cnt->current_image); + } else if (cnt->postcap) { + /* No motion, doing postcap */ + cnt->current_image->flags |= (IMAGE_POSTCAP | IMAGE_SAVE); + cnt->postcap--; + } else { + /* Done with postcap, so just have the image in the precap buffer */ + cnt->current_image->flags |= IMAGE_PRECAP; + cnt->detecting_motion = 0; + } + + /* Update last frame saved time, so we can end event after gap time */ + if (cnt->current_image->flags & IMAGE_SAVE) + cnt->lasttime = cnt->current_image->timestamp; + + + /* Simple hack to recognize motion in a specific area */ + /* Do we need a new coversion specifier as well?? */ + if ((cnt->conf.area_detect) && (cnt->event_nr != area_once) && (cnt->current_image->flags & IMAGE_TRIGGER)) { + j = strlen(cnt->conf.area_detect); + + for (i = 0; i < j; i++) { + z = cnt->conf.area_detect[i] - 49; /* 1 becomes 0 */ + if ((z >= 0) && (z < 9)) { + if (cnt->current_image->location.x > area_minx[z] && + cnt->current_image->location.x < area_maxx[z] && + cnt->current_image->location.y > area_miny[z] && + cnt->current_image->location.y < area_maxy[z]) { + event(cnt, EVENT_AREA_DETECTED, NULL, NULL, + NULL, cnt->currenttime_tm); + area_once = cnt->event_nr; /* Fire script only once per event */ + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Motion in area %d detected.\n", z+1); + break; + } + } + } + } + + /* Is the mpeg movie to long? Then make movies + * First test for max mpegtime + */ + if (cnt->conf.maxmpegtime && cnt->event_nr == cnt->prev_event) + if (cnt->currenttime - cnt->eventtime >= cnt->conf.maxmpegtime) + cnt->makemovie = 1; + + /* Now test for quiet longer than 'gap' OR make movie as decided in + * previous statement. + */ + if (((cnt->currenttime - cnt->lasttime >= cnt->conf.gap) && cnt->conf.gap > 0) || cnt->makemovie) { + if (cnt->event_nr == cnt->prev_event || cnt->makemovie) { + + /* Flush image buffer */ + process_image_ring(cnt, IMAGE_BUFFER_FLUSH); + + /* Save preview_shot here at the end of event */ + if (cnt->imgs.preview_image.diffs) { + preview_save(cnt); + cnt->imgs.preview_image.diffs = 0; + } + + event(cnt, EVENT_ENDMOTION, NULL, NULL, NULL, cnt->currenttime_tm); + + /* if tracking is enabled we center our camera so it does not + * point to a place where it will miss the next action + */ + if (cnt->track.type) + cnt->moved = track_center(cnt, cnt->video_dev, 0, 0, 0); + + if (cnt->conf.setup_mode) + motion_log(-1, 0, "End of event %d", cnt->event_nr); + + cnt->makemovie = 0; + /* Reset post capture */ + cnt->postcap = 0; + + /* Finally we increase the event number */ + cnt->event_nr++; + cnt->lightswitch_framecounter = 0; + + /* And we unset the text_event_string to avoid that buffered + * images get a timestamp from previous event. + */ + cnt->text_event_string[0] = '\0'; + } + } + + /* Save/send to movie some images */ + process_image_ring(cnt, 2); + + /***** MOTION LOOP - SETUP MODE CONSOLE OUTPUT SECTION *****/ + + /* If setup_mode enabled output some numbers to console */ + if (cnt->conf.setup_mode) { + char msg[1024] = "\0"; + char part[100]; + + if (cnt->conf.despeckle) { + snprintf(part, 99, "Raw changes: %5d - changes after '%s': %5d", + olddiffs, cnt->conf.despeckle, cnt->current_image->diffs); + strcat(msg, part); + if (strchr(cnt->conf.despeckle, 'l')){ + sprintf(part, " - labels: %3d", cnt->current_image->total_labels); + strcat(msg, part); + } + } else { + sprintf(part, "Changes: %5d", cnt->current_image->diffs); + strcat(msg, part); + } + + if (cnt->conf.noise_tune) { + sprintf(part, " - noise level: %2d", cnt->noise); + strcat(msg, part); + } + + if (cnt->conf.threshold_tune) { + sprintf(part, " - threshold: %d", cnt->threshold); + strcat(msg, part); + } + + motion_log(-1, 0, "%s", msg); + } + + } /* get_image end */ + + /***** MOTION LOOP - SNAPSHOT FEATURE SECTION *****/ + + /* Did we get triggered to make a snapshot from control http? Then shoot a snap + * If snapshot_interval is not zero and time since epoch MOD snapshot_interval = 0 then snap + * We actually allow the time to run over the interval in case we have a delay + * from slow camera. + * Note: Negative value means SIGALRM snaps are enabled + * httpd-control snaps are always enabled. + */ + + /* time_current_frame is used both for snapshot and timelapse features */ + time_current_frame = cnt->currenttime; + + if ((cnt->conf.snapshot_interval > 0 && cnt->shots == 0 && + time_current_frame % cnt->conf.snapshot_interval <= time_last_frame % cnt->conf.snapshot_interval) || + cnt->snapshot) { + event(cnt, EVENT_IMAGE_SNAPSHOT, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); + cnt->snapshot = 0; + } + + + /***** MOTION LOOP - TIMELAPSE FEATURE SECTION *****/ #ifdef HAVE_FFMPEG - if (cnt->conf.timelapse) { + if (cnt->conf.timelapse) { - /* Check to see if we should start a new timelapse file. We start one when - * we are on the first shot, and and the seconds are zero. We must use the seconds - * to prevent the timelapse file from getting reset multiple times during the minute. - */ - if (cnt->current_image->timestamp_tm.tm_min == 0 && - (time_current_frame % 60 < time_last_frame % 60) && - cnt->shots == 0) { + /* Check to see if we should start a new timelapse file. We start one when + * we are on the first shot, and and the seconds are zero. We must use the seconds + * to prevent the timelapse file from getting reset multiple times during the minute. + */ + if (cnt->current_image->timestamp_tm.tm_min == 0 && + (time_current_frame % 60 < time_last_frame % 60) && + cnt->shots == 0) { - if (strcasecmp(cnt->conf.timelapse_mode,"manual") == 0) - ;/* No action */ + if (strcasecmp(cnt->conf.timelapse_mode,"manual") == 0) + ;/* No action */ - /* If we are daily, raise timelapseend event at midnight */ - else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) { - if (cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* If we are daily, raise timelapseend event at midnight */ + else if (strcasecmp(cnt->conf.timelapse_mode, "daily") == 0) { + if (cnt->current_image->timestamp_tm.tm_hour == 0) + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* handle the hourly case */ - else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) { - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* handle the hourly case */ + else if (strcasecmp(cnt->conf.timelapse_mode, "hourly") == 0) { + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */ - else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) { - if (cnt->current_image->timestamp_tm.tm_wday == 0 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* If we are weekly-sunday, raise timelapseend event at midnight on sunday */ + else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-sunday") == 0) { + if (cnt->current_image->timestamp_tm.tm_wday == 0 && cnt->current_image->timestamp_tm.tm_hour == 0) + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* If we are weekly-monday, raise timelapseend event at midnight on monday */ - else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) { - if (cnt->current_image->timestamp_tm.tm_wday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* If we are weekly-monday, raise timelapseend event at midnight on monday */ + else if (strcasecmp(cnt->conf.timelapse_mode, "weekly-monday") == 0) { + if (cnt->current_image->timestamp_tm.tm_wday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* If we are monthly, raise timelapseend event at midnight on first day of month */ - else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) { - if (cnt->current_image->timestamp_tm.tm_mday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* If we are monthly, raise timelapseend event at midnight on first day of month */ + else if (strcasecmp(cnt->conf.timelapse_mode, "monthly") == 0) { + if (cnt->current_image->timestamp_tm.tm_mday == 1 && cnt->current_image->timestamp_tm.tm_hour == 0) + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* If invalid we report in syslog once and continue in manual mode */ - else { - motion_log(LOG_ERR, 0, "Invalid timelapse_mode argument '%s'", - cnt->conf.timelapse_mode); - motion_log(LOG_ERR, 0, "Defaulting to manual timelapse mode"); - conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual"); - } - } + /* If invalid we report in syslog once and continue in manual mode */ + else { + motion_log(LOG_ERR, 0, "Invalid timelapse_mode argument '%s'", + cnt->conf.timelapse_mode); + motion_log(LOG_ERR, 0, "Defaulting to manual timelapse mode"); + conf_cmdparse(&cnt, (char *)"ffmpeg_timelapse_mode",(char *)"manual"); + } + } - /* If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0 - * add a timelapse frame to the timelapse mpeg. - */ - if (cnt->shots == 0 && - time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse) - event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* If ffmpeg timelapse is enabled and time since epoch MOD ffmpeg_timelaps = 0 + * add a timelapse frame to the timelapse mpeg. + */ + if (cnt->shots == 0 && + time_current_frame % cnt->conf.timelapse <= time_last_frame % cnt->conf.timelapse) + event(cnt, EVENT_TIMELAPSE, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); + } - /* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file - * This is an important feature that allows manual roll-over of timelapse file using the http - * remote control via a cron job. - */ - else if (cnt->ffmpeg_timelapse) - event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm); + /* if timelapse mpeg is in progress but conf.timelapse is zero then close timelapse file + * This is an important feature that allows manual roll-over of timelapse file using the http + * remote control via a cron job. + */ + else if (cnt->ffmpeg_timelapse) + event(cnt, EVENT_TIMELAPSEEND, NULL, NULL, NULL, cnt->currenttime_tm); #endif /* HAVE_FFMPEG */ - time_last_frame = time_current_frame; + time_last_frame = time_current_frame; - /***** MOTION LOOP - VIDEO LOOPBACK SECTION *****/ + /***** MOTION LOOP - VIDEO LOOPBACK SECTION *****/ - /* feed last image and motion image to video device pipes and the webcam clients - * In setup mode we send the special setup mode image to both webcam and vloopback pipe - * In normal mode we feed the latest image to vloopback device and we send - * the image to the webcam. We always send the first image in a second to the webcam. - * Other image are sent only when the config option webcam_motion is off - * The result is that with webcam_motion on the webcam stream is normally at the minimal - * 1 frame per second but the minute motion is detected the motion_detected() function - * sends all detected pictures to the webcam except the 1st per second which is already sent. - */ - if (cnt->conf.setup_mode) { - event(cnt, EVENT_IMAGE, cnt->imgs.out, NULL, &cnt->pipe, cnt->currenttime_tm); - event(cnt, EVENT_WEBCAM, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm); - } else { - event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); - if (!cnt->conf.webcam_motion || cnt->shots == 1) - event(cnt, EVENT_WEBCAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); - } + /* feed last image and motion image to video device pipes and the webcam clients + * In setup mode we send the special setup mode image to both webcam and vloopback pipe + * In normal mode we feed the latest image to vloopback device and we send + * the image to the webcam. We always send the first image in a second to the webcam. + * Other image are sent only when the config option webcam_motion is off + * The result is that with webcam_motion on the webcam stream is normally at the minimal + * 1 frame per second but the minute motion is detected the motion_detected() function + * sends all detected pictures to the webcam except the 1st per second which is already sent. + */ + if (cnt->conf.setup_mode) { + event(cnt, EVENT_IMAGE, cnt->imgs.out, NULL, &cnt->pipe, cnt->currenttime_tm); + event(cnt, EVENT_WEBCAM, cnt->imgs.out, NULL, NULL, cnt->currenttime_tm); + } else { + event(cnt, EVENT_IMAGE, cnt->current_image->image, NULL, &cnt->pipe, &cnt->current_image->timestamp_tm); + if (!cnt->conf.webcam_motion || cnt->shots == 1) + event(cnt, EVENT_WEBCAM, cnt->current_image->image, NULL, NULL, &cnt->current_image->timestamp_tm); + } - event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm); + event(cnt, EVENT_IMAGEM, cnt->imgs.out, NULL, &cnt->mpipe, cnt->currenttime_tm); - /***** MOTION LOOP - ONCE PER SECOND PARAMETER UPDATE SECTION *****/ + /***** MOTION LOOP - ONCE PER SECOND PARAMETER UPDATE SECTION *****/ - /* Check for some config parameter changes but only every second */ - if (cnt->shots == 0){ - if (strcasecmp(cnt->conf.output_normal, "on") == 0) - cnt->new_img = NEWIMG_ON; - else if (strcasecmp(cnt->conf.output_normal, "first") == 0) - cnt->new_img = NEWIMG_FIRST; - else if (strcasecmp(cnt->conf.output_normal, "best") == 0) - cnt->new_img = NEWIMG_BEST; - else if (strcasecmp(cnt->conf.output_normal, "center") == 0) - cnt->new_img = NEWIMG_CENTER; - else - cnt->new_img = NEWIMG_OFF; + /* Check for some config parameter changes but only every second */ + if (cnt->shots == 0){ + if (strcasecmp(cnt->conf.output_normal, "on") == 0) + cnt->new_img = NEWIMG_ON; + else if (strcasecmp(cnt->conf.output_normal, "first") == 0) + cnt->new_img = NEWIMG_FIRST; + else if (strcasecmp(cnt->conf.output_normal, "best") == 0) + cnt->new_img = NEWIMG_BEST; + else if (strcasecmp(cnt->conf.output_normal, "center") == 0) + cnt->new_img = NEWIMG_CENTER; + else + cnt->new_img = NEWIMG_OFF; - if (strcasecmp(cnt->conf.locate, "on") == 0) - cnt->locate = LOCATE_ON; - else if (strcasecmp(cnt->conf.locate, "preview") == 0) - cnt->locate = LOCATE_PREVIEW; - else - cnt->locate = LOCATE_OFF; + if (strcasecmp(cnt->conf.locate, "on") == 0) + cnt->locate = LOCATE_ON; + else if (strcasecmp(cnt->conf.locate, "preview") == 0) + cnt->locate = LOCATE_PREVIEW; + else + cnt->locate = LOCATE_OFF; - /* Sanity check for smart_mask_speed, silly value disables smart mask */ - if (cnt->conf.smart_mask_speed < 0 || cnt->conf.smart_mask_speed > 10) - cnt->conf.smart_mask_speed = 0; - /* Has someone changed smart_mask_speed or framerate? */ - if (cnt->conf.smart_mask_speed != cnt->smartmask_speed || smartmask_lastrate != cnt->lastrate){ - if (cnt->conf.smart_mask_speed == 0){ - memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); - memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize); - } - smartmask_lastrate = cnt->lastrate; - cnt->smartmask_speed = cnt->conf.smart_mask_speed; - /* Decay delay - based on smart_mask_speed (framerate independent) - This is always 5*smartmask_speed seconds */ - smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed); - } + /* Sanity check for smart_mask_speed, silly value disables smart mask */ + if (cnt->conf.smart_mask_speed < 0 || cnt->conf.smart_mask_speed > 10) + cnt->conf.smart_mask_speed = 0; + /* Has someone changed smart_mask_speed or framerate? */ + if (cnt->conf.smart_mask_speed != cnt->smartmask_speed || smartmask_lastrate != cnt->lastrate){ + if (cnt->conf.smart_mask_speed == 0){ + memset(cnt->imgs.smartmask, 0, cnt->imgs.motionsize); + memset(cnt->imgs.smartmask_final, 255, cnt->imgs.motionsize); + } + smartmask_lastrate = cnt->lastrate; + cnt->smartmask_speed = cnt->conf.smart_mask_speed; + /* Decay delay - based on smart_mask_speed (framerate independent) + This is always 5*smartmask_speed seconds */ + smartmask_ratio = 5 * cnt->lastrate * (11 - cnt->smartmask_speed); + } #if defined(HAVE_MYSQL) || defined(HAVE_PGSQL) - /* Set the sql mask file according to the SQL config options - * We update it for every frame in case the config was updated - * via remote control. - */ - cnt->sql_mask = cnt->conf.sql_log_image * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) + - cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT + - cnt->conf.sql_log_mpeg * (FTYPE_MPEG + FTYPE_MPEG_MOTION) + - cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE; + /* Set the sql mask file according to the SQL config options + * We update it for every frame in case the config was updated + * via remote control. + */ + cnt->sql_mask = cnt->conf.sql_log_image * (FTYPE_IMAGE + FTYPE_IMAGE_MOTION) + + cnt->conf.sql_log_snapshot * FTYPE_IMAGE_SNAPSHOT + + cnt->conf.sql_log_mpeg * (FTYPE_MPEG + FTYPE_MPEG_MOTION) + + cnt->conf.sql_log_timelapse * FTYPE_MPEG_TIMELAPSE; #endif /* defined(HAVE_MYSQL) || defined(HAVE_PGSQL) */ - } + } - /***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/ + /***** MOTION LOOP - FRAMERATE TIMING AND SLEEPING SECTION *****/ - /* Work out expected frame rate based on config setting which may - have changed from http-control */ - if (cnt->conf.frame_limit) - required_frame_time = 1000000L / cnt->conf.frame_limit; - else - required_frame_time = 0; + /* Work out expected frame rate based on config setting which may + have changed from http-control */ + if (cnt->conf.frame_limit) + required_frame_time = 1000000L / cnt->conf.frame_limit; + else + required_frame_time = 0; - /* Get latest time to calculate time taken to process video data */ - gettimeofday(&tv2, NULL); - elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - timenow; + /* Get latest time to calculate time taken to process video data */ + gettimeofday(&tv2, NULL); + elapsedtime = (tv2.tv_usec + 1000000L * tv2.tv_sec) - timenow; - /* Update history buffer but ignore first pass as timebefore - variable will be inaccurate - */ - if (passflag) - rolling_average_data[rolling_frame] = timenow-timebefore; - else - passflag = 1; + /* Update history buffer but ignore first pass as timebefore + variable will be inaccurate + */ + if (passflag) + rolling_average_data[rolling_frame] = timenow-timebefore; + else + passflag = 1; - rolling_frame++; - if (rolling_frame >= rolling_average_limit) - rolling_frame = 0; + rolling_frame++; + if (rolling_frame >= rolling_average_limit) + rolling_frame = 0; - /* Calculate 10 second average and use deviation in delay calculation */ - rolling_average = 0L; + /* Calculate 10 second average and use deviation in delay calculation */ + rolling_average = 0L; - for (j=0; j < rolling_average_limit; j++) - rolling_average += rolling_average_data[j]; + for (j=0; j < rolling_average_limit; j++) + rolling_average += rolling_average_data[j]; - rolling_average /= rolling_average_limit; - frame_delay = required_frame_time-elapsedtime - (rolling_average - required_frame_time); + rolling_average /= rolling_average_limit; + frame_delay = required_frame_time-elapsedtime - (rolling_average - required_frame_time); - if (frame_delay > 0) { - /* Apply delay to meet frame time */ - if (frame_delay > required_frame_time) - frame_delay = required_frame_time; + if (frame_delay > 0) { + /* Apply delay to meet frame time */ + if (frame_delay > required_frame_time) + frame_delay = required_frame_time; - /* Delay time in nanoseconds for SLEEP */ - delay_time_nsec = frame_delay * 1000; + /* Delay time in nanoseconds for SLEEP */ + delay_time_nsec = frame_delay * 1000; - if (delay_time_nsec > 999999999) - delay_time_nsec = 999999999; + if (delay_time_nsec > 999999999) + delay_time_nsec = 999999999; - /* SLEEP as defined in motion.h A safe sleep using nanosleep */ - SLEEP(0, delay_time_nsec); - } - } + /* SLEEP as defined in motion.h A safe sleep using nanosleep */ + SLEEP(0, delay_time_nsec); + } + } - /* END OF MOTION MAIN LOOP - * If code continues here it is because the thread is exiting or restarting - */ + /* END OF MOTION MAIN LOOP + * If code continues here it is because the thread is exiting or restarting + */ err: - if (rolling_average_data) - free(rolling_average_data); + if (rolling_average_data) + free(rolling_average_data); - cnt->lost_connection = 1; - motion_log(-1, 0, "Thread exiting"); + cnt->lost_connection = 1; + motion_log(-1, 0, "Thread exiting"); - motion_cleanup(cnt); + motion_cleanup(cnt); - pthread_mutex_lock(&global_lock); - threads_running--; - pthread_mutex_unlock(&global_lock); + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); - if (!cnt->restart) - cnt->watchdog=WATCHDOG_OFF; - cnt->running = 0; - cnt->finish = 0; + if (!cnt->restart) + cnt->watchdog=WATCHDOG_OFF; + cnt->running = 0; + cnt->finish = 0; - pthread_exit(NULL); + pthread_exit(NULL); } /** @@ -1867,85 +1916,85 @@ err: */ static void become_daemon(void) { - int i; - FILE *pidf = NULL; - struct sigaction sig_ign_action; + int i; + FILE *pidf = NULL; + struct sigaction sig_ign_action; - /* Setup sig_ign_action */ + /* Setup sig_ign_action */ #ifdef SA_RESTART - sig_ign_action.sa_flags = SA_RESTART; + sig_ign_action.sa_flags = SA_RESTART; #else - sig_ign_action.sa_flags = 0; + sig_ign_action.sa_flags = 0; #endif - sig_ign_action.sa_handler = SIG_IGN; - sigemptyset(&sig_ign_action.sa_mask); + sig_ign_action.sa_handler = SIG_IGN; + sigemptyset(&sig_ign_action.sa_mask); - /* fork */ - if (fork()) { - motion_log(-1, 0, "Motion going to daemon mode"); - exit(0); - } - - /* Create the pid file if defined, if failed exit - * If we fail we report it. If we succeed we postpone the log entry till - * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting - * for an enter. - */ - if (cnt_list[0]->conf.pid_file) { - pidf = fopen(cnt_list[0]->conf.pid_file, "w+"); - - if ( pidf ) { - (void)fprintf(pidf, "%d\n", getpid()); - fclose(pidf); - } else { - motion_log(LOG_ERR, 1, "Exit motion, cannot create process id file (pid file) %s", - cnt_list[0]->conf.pid_file); - exit(0); - } - } + /* fork */ + if (fork()) { + motion_log(-1, 0, "Motion going to daemon mode"); + exit(0); + } + + /* Create the pid file if defined, if failed exit + * If we fail we report it. If we succeed we postpone the log entry till + * later when we have closed stdout. Otherwise Motion hangs in the terminal waiting + * for an enter. + */ + if (cnt_list[0]->conf.pid_file) { + pidf = fopen(cnt_list[0]->conf.pid_file, "w+"); + + if (pidf ) { + (void)fprintf(pidf, "%d\n", getpid()); + fclose(pidf); + } else { + motion_log(LOG_ERR, 1, "Exit motion, cannot create process id file (pid file) %s", + cnt_list[0]->conf.pid_file); + exit(0); + } + } - /* changing dir to root enables people to unmount a disk - without having to stop Motion */ - if (chdir("/")) { - motion_log(LOG_ERR, 1, "Could not change directory"); - } + /* changing dir to root enables people to unmount a disk + without having to stop Motion */ + if (chdir("/")) { + motion_log(LOG_ERR, 1, "Could not change directory"); + } #if (defined(BSD)) - setpgrp(0, getpid()); + setpgrp(0, getpid()); #else - setpgrp(); + setpgrp(); #endif /* BSD */ - - if ((i = open("/dev/tty", O_RDWR)) >= 0) { - ioctl(i, TIOCNOTTY, NULL); - close(i); - } + + if ((i = open("/dev/tty", O_RDWR)) >= 0) { + ioctl(i, TIOCNOTTY, NULL); + close(i); + } - setsid(); - i = open("/dev/null", O_RDONLY); + setsid(); + i = open("/dev/null", O_RDONLY); - if(i != -1) { - dup2(i, STDIN_FILENO); - close(i); - } + if (i != -1) { + dup2(i, STDIN_FILENO); + close(i); + } - i = open("/dev/null", O_WRONLY); + i = open("/dev/null", O_WRONLY); - if(i != -1) { - dup2(i, STDOUT_FILENO); - dup2(i, STDERR_FILENO); - close(i); - } - - /* Now it is safe to add the PID creation to the logs */ - if ( pidf ) - motion_log(LOG_INFO, 0, "Created process id file %s. Process ID is %d", - cnt_list[0]->conf.pid_file, getpid()); - - sigaction(SIGTTOU, &sig_ign_action, NULL); - sigaction(SIGTTIN, &sig_ign_action, NULL); - sigaction(SIGTSTP, &sig_ign_action, NULL); + if (i != -1) { + dup2(i, STDOUT_FILENO); + dup2(i, STDERR_FILENO); + close(i); + } + + /* Now it is safe to add the PID creation to the logs */ + if (pidf ) + motion_log(LOG_INFO, 0, "Created process id file %s. Process ID is %d", + cnt_list[0]->conf.pid_file, getpid()); + + sigaction(SIGTTOU, &sig_ign_action, NULL); + sigaction(SIGTTIN, &sig_ign_action, NULL); + sigaction(SIGTSTP, &sig_ign_action, NULL); } /** @@ -1963,28 +2012,28 @@ static void become_daemon(void) */ static void cntlist_create(int argc, char *argv[]) { - /* cnt_list is an array of pointers to the context structures cnt for each thread. - * First we reserve room for a pointer to thread 0's context structure - * and a NULL pointer which indicates that end of the array of pointers to - * thread context structures. - */ - cnt_list = mymalloc(sizeof(struct context *)*2); + /* cnt_list is an array of pointers to the context structures cnt for each thread. + * First we reserve room for a pointer to thread 0's context structure + * and a NULL pointer which indicates that end of the array of pointers to + * thread context structures. + */ + cnt_list = mymalloc(sizeof(struct context *)*2); - /* Now we reserve room for thread 0's context structure and let cnt_list[0] point to it */ - cnt_list[0] = mymalloc(sizeof(struct context)); + /* Now we reserve room for thread 0's context structure and let cnt_list[0] point to it */ + cnt_list[0] = mymalloc(sizeof(struct context)); - /* Populate context structure with start/default values */ - context_init(cnt_list[0]); + /* Populate context structure with start/default values */ + context_init(cnt_list[0]); - /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */ - cnt_list[1] = NULL; + /* cnt_list[1] pointing to zero indicates no more thread context structures - they get added later */ + cnt_list[1] = NULL; - /* Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads - * the config options from motion.conf, thread config files and the command line. - */ - cnt_list[0]->conf.argv = argv; - cnt_list[0]->conf.argc = argc; - cnt_list = conf_load(cnt_list); + /* Command line arguments are being pointed to from cnt_list[0] and we call conf_load which loads + * the config options from motion.conf, thread config files and the command line. + */ + cnt_list[0]->conf.argv = argv; + cnt_list[0]->conf.argc = argc; + cnt_list = conf_load(cnt_list); } @@ -2001,17 +2050,17 @@ static void cntlist_create(int argc, char *argv[]) */ static void motion_shutdown(void) { - int i = -1; + int i = -1; - motion_remove_pid(); - - while (cnt_list[++i]){ - context_destroy(cnt_list[i]); - } - free(cnt_list); - cnt_list = NULL; + motion_remove_pid(); + + while (cnt_list[++i]){ + context_destroy(cnt_list[i]); + } + free(cnt_list); + cnt_list = NULL; #ifndef WITHOUT_V4L - vid_cleanup(); + vid_cleanup(); #endif } @@ -2032,30 +2081,30 @@ static void motion_shutdown(void) */ static void motion_startup(int daemonize, int argc, char *argv[]) { - /* Initialize our global mutex */ - pthread_mutex_init(&global_lock, NULL); + /* Initialize our global mutex */ + pthread_mutex_init(&global_lock, NULL); - /* Create the list of context structures and load the - * configuration. - */ - cntlist_create(argc, argv); + /* Create the list of context structures and load the + * configuration. + */ + cntlist_create(argc, argv); - motion_log(LOG_INFO, 0, "Motion "VERSION" Started"); + motion_log(LOG_INFO, 0, "Motion "VERSION" Started"); - initialize_chars(); + initialize_chars(); - if (daemonize) { - /* If daemon mode is requested, and we're not going into setup mode, - * become daemon. - */ - if (cnt_list[0]->daemon && cnt_list[0]->conf.setup_mode == 0) { - become_daemon(); - motion_log(LOG_INFO, 0, "Motion running as daemon process"); - } - } + if (daemonize) { + /* If daemon mode is requested, and we're not going into setup mode, + * become daemon. + */ + if (cnt_list[0]->daemon && cnt_list[0]->conf.setup_mode == 0) { + become_daemon(); + motion_log(LOG_INFO, 0, "Motion running as daemon process"); + } + } #ifndef WITHOUT_V4L - vid_init(); + vid_init(); #endif } @@ -2071,29 +2120,29 @@ static void motion_startup(int daemonize, int argc, char *argv[]) static void setup_signals(struct sigaction *sig_handler_action, struct sigaction *sigchild_action) { #ifdef SA_NOCLDWAIT - sigchild_action->sa_flags = SA_NOCLDWAIT; + sigchild_action->sa_flags = SA_NOCLDWAIT; #else - sigchild_action->sa_flags = 0; + sigchild_action->sa_flags = 0; #endif - sigchild_action->sa_handler = sigchild_handler; - sigemptyset(&sigchild_action->sa_mask); + sigchild_action->sa_handler = sigchild_handler; + sigemptyset(&sigchild_action->sa_mask); #ifdef SA_RESTART - sig_handler_action->sa_flags = SA_RESTART; + sig_handler_action->sa_flags = SA_RESTART; #else - sig_handler_action->sa_flags = 0; + sig_handler_action->sa_flags = 0; #endif - sig_handler_action->sa_handler = sig_handler; - sigemptyset(&sig_handler_action->sa_mask); + sig_handler_action->sa_handler = sig_handler; + sigemptyset(&sig_handler_action->sa_mask); - /* Enable automatic zombie reaping */ - sigaction(SIGCHLD, sigchild_action, NULL); - sigaction(SIGPIPE, sigchild_action, NULL); - sigaction(SIGALRM, sig_handler_action, NULL); - sigaction(SIGHUP, sig_handler_action, NULL); - sigaction(SIGINT, sig_handler_action, NULL); - sigaction(SIGQUIT, sig_handler_action, NULL); - sigaction(SIGTERM, sig_handler_action, NULL); - sigaction(SIGUSR1, sig_handler_action, NULL); + /* Enable automatic zombie reaping */ + sigaction(SIGCHLD, sigchild_action, NULL); + sigaction(SIGPIPE, sigchild_action, NULL); + sigaction(SIGALRM, sig_handler_action, NULL); + sigaction(SIGHUP, sig_handler_action, NULL); + sigaction(SIGINT, sig_handler_action, NULL); + sigaction(SIGQUIT, sig_handler_action, NULL); + sigaction(SIGTERM, sig_handler_action, NULL); + sigaction(SIGUSR1, sig_handler_action, NULL); } /** @@ -2110,58 +2159,58 @@ static void setup_signals(struct sigaction *sig_handler_action, struct sigaction */ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr) { - int i; + int i; - /* Check the webcam port number for conflicts. - * First we check for conflict with the control port. - * Second we check for that two threads does not use the same port number - * for the webcam. If a duplicate port is found the webcam feature gets disabled (port =0) - * for this thread and a warning is written to console and syslog. - */ + /* Check the webcam port number for conflicts. + * First we check for conflict with the control port. + * Second we check for that two threads does not use the same port number + * for the webcam. If a duplicate port is found the webcam feature gets disabled (port =0) + * for this thread and a warning is written to console and syslog. + */ - if (cnt->conf.webcam_port != 0) { - /* Compare against the control port. */ - if (cnt_list[0]->conf.control_port == cnt->conf.webcam_port) { - motion_log(LOG_ERR, 0, - "Webcam port number %d for thread %d conflicts with the control port", - cnt->conf.webcam_port, cnt->threadnr); - motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", cnt->threadnr); - cnt->conf.webcam_port = 0; - } + if (cnt->conf.webcam_port != 0) { + /* Compare against the control port. */ + if (cnt_list[0]->conf.control_port == cnt->conf.webcam_port) { + motion_log(LOG_ERR, 0, + "Webcam port number %d for thread %d conflicts with the control port", + cnt->conf.webcam_port, cnt->threadnr); + motion_log(LOG_ERR, 0, "Webcam feature for thread %d is disabled.", cnt->threadnr); + cnt->conf.webcam_port = 0; + } - /* Compare against webcam ports of other threads. */ - for (i = 1; cnt_list[i]; i++) { - if (cnt_list[i] == cnt) - continue; - if (cnt_list[i]->conf.webcam_port == cnt->conf.webcam_port) { - motion_log(LOG_ERR, 0, - "Webcam port number %d for thread %d conflicts with thread %d", - cnt->conf.webcam_port, cnt->threadnr, cnt_list[i]->threadnr); - motion_log(LOG_ERR, 0, - "Webcam feature for thread %d is disabled.", cnt->threadnr); - cnt->conf.webcam_port = 0; - } - } - } + /* Compare against webcam ports of other threads. */ + for (i = 1; cnt_list[i]; i++) { + if (cnt_list[i] == cnt) + continue; + if (cnt_list[i]->conf.webcam_port == cnt->conf.webcam_port) { + motion_log(LOG_ERR, 0, + "Webcam port number %d for thread %d conflicts with thread %d", + cnt->conf.webcam_port, cnt->threadnr, cnt_list[i]->threadnr); + motion_log(LOG_ERR, 0, + "Webcam feature for thread %d is disabled.", cnt->threadnr); + cnt->conf.webcam_port = 0; + } + } + } - /* Update how many threads we have running. This is done within a - * mutex lock to prevent multiple simultaneous updates to - * 'threads_running'. - */ - pthread_mutex_lock(&global_lock); - threads_running++; - pthread_mutex_unlock(&global_lock); + /* Update how many threads we have running. This is done within a + * mutex lock to prevent multiple simultaneous updates to + * 'threads_running'. + */ + pthread_mutex_lock(&global_lock); + threads_running++; + pthread_mutex_unlock(&global_lock); - /* Set a flag that we want this thread running */ - cnt->restart = 1; + /* Set a flag that we want this thread running */ + cnt->restart = 1; - /* Give the thread 30s to start */ - cnt->watchdog = 30; + /* Give the thread 30s to start */ + cnt->watchdog = 30; - /* Create the actual thread. Use 'motion_loop' as the thread - * function. - */ - pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt); + /* Create the actual thread. Use 'motion_loop' as the thread + * function. + */ + pthread_create(&cnt->thread_id, thread_attr, &motion_loop, cnt); } /** @@ -2179,173 +2228,173 @@ static void start_motion_thread(struct context *cnt, pthread_attr_t *thread_attr */ int main (int argc, char **argv) { - int i; - pthread_attr_t thread_attr; - pthread_t thread_id; + int i; + pthread_attr_t thread_attr; + pthread_t thread_id; - /* Setup signals and do some initialization. 1 in the call to - * 'motion_startup' means that Motion will become a daemon if so has been - * requested, and argc and argc are necessary for reading the command - * line options. - */ - struct sigaction sig_handler_action; - struct sigaction sigchild_action; - setup_signals(&sig_handler_action, &sigchild_action); + /* Setup signals and do some initialization. 1 in the call to + * 'motion_startup' means that Motion will become a daemon if so has been + * requested, and argc and argc are necessary for reading the command + * line options. + */ + struct sigaction sig_handler_action; + struct sigaction sigchild_action; + setup_signals(&sig_handler_action, &sigchild_action); - motion_startup(1, argc, argv); + motion_startup(1, argc, argv); #ifdef HAVE_FFMPEG - /* FFMpeg initialization is only performed if FFMpeg support was found - * and not disabled during the configure phase. - */ - ffmpeg_init(); + /* FFMpeg initialization is only performed if FFMpeg support was found + * and not disabled during the configure phase. + */ + ffmpeg_init(); #endif /* HAVE_FFMPEG */ - /* In setup mode, Motion is very communicative towards the user, which - * allows the user to experiment with the config parameters in order to - * optimize motion detection and stuff. - */ - if(cnt_list[0]->conf.setup_mode) - motion_log(-1, 0, "Motion running in setup mode."); + /* In setup mode, Motion is very communicative towards the user, which + * allows the user to experiment with the config parameters in order to + * optimize motion detection and stuff. + */ + if (cnt_list[0]->conf.setup_mode) + motion_log(-1, 0, "Motion running in setup mode."); - /* Create and a thread attribute for the threads we spawn later on. - * PTHREAD_CREATE_DETACHED means to create threads detached, i.e. - * their termination cannot be synchronized through 'pthread_join'. - */ - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); + /* Create and a thread attribute for the threads we spawn later on. + * PTHREAD_CREATE_DETACHED means to create threads detached, i.e. + * their termination cannot be synchronized through 'pthread_join'. + */ + pthread_attr_init(&thread_attr); + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - /* Create the TLS key for thread number. */ - pthread_key_create(&tls_key_threadnr, NULL); + /* Create the TLS key for thread number. */ + pthread_key_create(&tls_key_threadnr, NULL); - do { - if (restart) { - /* Handle the restart situation. Currently the approach is to - * cleanup everything, and then initialize everything again - * (including re-reading the config file(s)). - */ - motion_shutdown(); - restart = 0; /* only one reset for now */ - motion_log(LOG_INFO,0,"motion restarted"); + do { + if (restart) { + /* Handle the restart situation. Currently the approach is to + * cleanup everything, and then initialize everything again + * (including re-reading the config file(s)). + */ + motion_shutdown(); + restart = 0; /* only one reset for now */ + motion_log(LOG_INFO,0,"motion restarted"); #ifndef WITHOUT_V4L - SLEEP(5,0); // maybe some cameras needs less time + SLEEP(5,0); // maybe some cameras needs less time #endif - motion_startup(0, argc, argv); /* 0 = skip daemon init */ - } + motion_startup(0, argc, argv); /* 0 = skip daemon init */ + } - /* Start the motion threads. First 'cnt_list' item is global if 'thread' - * option is used, so start at 1 then and 0 otherwise. - */ - for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) { - /* If i is 0 it means no thread files and we then set the thread number to 1 */ - cnt_list[i]->threadnr = i ? i : 1; + /* Start the motion threads. First 'cnt_list' item is global if 'thread' + * option is used, so start at 1 then and 0 otherwise. + */ + for (i = cnt_list[1] != NULL ? 1 : 0; cnt_list[i]; i++) { + /* If i is 0 it means no thread files and we then set the thread number to 1 */ + cnt_list[i]->threadnr = i ? i : 1; - if ( strcmp(cnt_list[i]->conf_filename,"") ) - motion_log(LOG_INFO, 0, "Thread %d is from %s", cnt_list[i]->threadnr, cnt_list[i]->conf_filename ); + if (strcmp(cnt_list[i]->conf_filename,"") ) + motion_log(LOG_INFO, 0, "Thread %d is from %s", cnt_list[i]->threadnr, cnt_list[i]->conf_filename ); - if (cnt_list[0]->conf.setup_mode) { - motion_log(-1, 0, "Thread %d is device: %s input %d", cnt_list[i]->threadnr, - cnt_list[i]->conf.netcam_url ? cnt_list[i]->conf.netcam_url : cnt_list[i]->conf.video_device, - cnt_list[i]->conf.netcam_url ? -1 : cnt_list[i]->conf.input - ); - } + if (cnt_list[0]->conf.setup_mode) { + motion_log(-1, 0, "Thread %d is device: %s input %d", cnt_list[i]->threadnr, + cnt_list[i]->conf.netcam_url ? cnt_list[i]->conf.netcam_url : cnt_list[i]->conf.video_device, + cnt_list[i]->conf.netcam_url ? -1 : cnt_list[i]->conf.input + ); + } - if (cnt_list[0]->conf.setup_mode) - motion_log(LOG_ERR, 0, "Webcam port %d", cnt_list[i]->conf.webcam_port); + if (cnt_list[0]->conf.setup_mode) + motion_log(LOG_ERR, 0, "Webcam port %d", cnt_list[i]->conf.webcam_port); - start_motion_thread(cnt_list[i], &thread_attr); - } + start_motion_thread(cnt_list[i], &thread_attr); + } - /* Create a thread for the control interface if requested. Create it - * detached and with 'motion_web_control' as the thread function. - */ - if (cnt_list[0]->conf.control_port) - pthread_create(&thread_id, &thread_attr, &motion_web_control, cnt_list); + /* Create a thread for the control interface if requested. Create it + * detached and with 'motion_web_control' as the thread function. + */ + if (cnt_list[0]->conf.control_port) + pthread_create(&thread_id, &thread_attr, &motion_web_control, cnt_list); - if (cnt_list[0]->conf.setup_mode) - motion_log(-1, 0,"Waiting for threads to finish, pid: %d", getpid()); + if (cnt_list[0]->conf.setup_mode) + motion_log(-1, 0,"Waiting for threads to finish, pid: %d", getpid()); - /* Crude way of waiting for all threads to finish - check the thread - * counter (because we cannot do join on the detached threads). - */ - while (1) { - SLEEP(1,0); + /* Crude way of waiting for all threads to finish - check the thread + * counter (because we cannot do join on the detached threads). + */ + while (1) { + SLEEP(1,0); - /* Calculate how many threads runnig or wants to run - * if zero and we want to finish, break out - */ - int motion_threads_running = 0; - for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) { - if (cnt_list[i]->running || cnt_list[i]->restart) - motion_threads_running++; - } + /* Calculate how many threads runnig or wants to run + * if zero and we want to finish, break out + */ + int motion_threads_running = 0; + for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) { + if (cnt_list[i]->running || cnt_list[i]->restart) + motion_threads_running++; + } - if ( ((motion_threads_running == 0 ) && finish ) || - ((motion_threads_running == 0 ) && (threads_running == 0)) ){ - if (debug_level >= CAMERA_DEBUG){ - motion_log(LOG_INFO, 0, "DEBUG-1 threads_running %d motion_threads_running %d , finish %d", - threads_running, motion_threads_running, finish); - } - break; - } + if (((motion_threads_running == 0 ) && finish ) || + ((motion_threads_running == 0 ) && (threads_running == 0)) ){ + if (debug_level >= CAMERA_DEBUG){ + motion_log(LOG_INFO, 0, "DEBUG-1 threads_running %d motion_threads_running %d , finish %d", + threads_running, motion_threads_running, finish); + } + break; + } - for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) { - /* Check if threads wants to be restarted */ - if ( (!cnt_list[i]->running) && (cnt_list[i]->restart) ) { - motion_log(LOG_INFO, 0, "Motion thread %d restart", cnt_list[i]->threadnr); - start_motion_thread(cnt_list[i], &thread_attr); - } - if (cnt_list[i]->watchdog > WATCHDOG_OFF) { - cnt_list[i]->watchdog--; - if (cnt_list[i]->watchdog == 0) { - motion_log(LOG_ERR, 0, "Thread %d - Watchdog timeout, trying to do a graceful restart", - cnt_list[i]->threadnr); - cnt_list[i]->finish = 1; - } - if (cnt_list[i]->watchdog == -60) { - motion_log(LOG_ERR, 0, "Thread %d - Watchdog timeout, did NOT restart graceful," - "killing it!", cnt_list[i]->threadnr); - pthread_cancel(cnt_list[i]->thread_id); - pthread_mutex_lock(&global_lock); - threads_running--; - pthread_mutex_unlock(&global_lock); - motion_cleanup(cnt_list[i]); - cnt_list[i]->running = 0; - cnt_list[i]->finish = 0; - } - } - } + for (i = (cnt_list[1] != NULL ? 1 : 0); cnt_list[i]; i++) { + /* Check if threads wants to be restarted */ + if ((!cnt_list[i]->running) && (cnt_list[i]->restart) ) { + motion_log(LOG_INFO, 0, "Motion thread %d restart", cnt_list[i]->threadnr); + start_motion_thread(cnt_list[i], &thread_attr); + } + if (cnt_list[i]->watchdog > WATCHDOG_OFF) { + cnt_list[i]->watchdog--; + if (cnt_list[i]->watchdog == 0) { + motion_log(LOG_ERR, 0, "Thread %d - Watchdog timeout, trying to do a graceful restart", + cnt_list[i]->threadnr); + cnt_list[i]->finish = 1; + } + if (cnt_list[i]->watchdog == -60) { + motion_log(LOG_ERR, 0, "Thread %d - Watchdog timeout, did NOT restart graceful," + "killing it!", cnt_list[i]->threadnr); + pthread_cancel(cnt_list[i]->thread_id); + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); + motion_cleanup(cnt_list[i]); + cnt_list[i]->running = 0; + cnt_list[i]->finish = 0; + } + } + } - if (debug_level >= CAMERA_DEBUG){ - motion_log(LOG_INFO, 0, "DEBUG-2 threads_running %d motion_threads_running %d , finish %d", - threads_running, motion_threads_running, finish); - } - } - /* Reset end main loop flag */ - finish = 0; + if (debug_level >= CAMERA_DEBUG){ + motion_log(LOG_INFO, 0, "DEBUG-2 threads_running %d motion_threads_running %d , finish %d", + threads_running, motion_threads_running, finish); + } + } + /* Reset end main loop flag */ + finish = 0; - if (cnt_list[0]->conf.setup_mode) - motion_log(LOG_DEBUG, 0, "Threads finished"); + if (cnt_list[0]->conf.setup_mode) + motion_log(LOG_DEBUG, 0, "Threads finished"); - /* Rest for a while if we're supposed to restart. */ - if (restart) - SLEEP(2,0); + /* Rest for a while if we're supposed to restart. */ + if (restart) + SLEEP(2,0); - } while (restart); /* loop if we're supposed to restart */ + } while (restart); /* loop if we're supposed to restart */ - // Be sure that http control exits fine - cnt_list[0]->finish = 1; - SLEEP(1,0); - motion_log(LOG_INFO, 0, "Motion terminating"); + // Be sure that http control exits fine + cnt_list[0]->finish = 1; + SLEEP(1,0); + motion_log(LOG_INFO, 0, "Motion terminating"); - /* Perform final cleanup. */ - pthread_key_delete(tls_key_threadnr); - pthread_attr_destroy(&thread_attr); - pthread_mutex_destroy(&global_lock); - motion_shutdown(); + /* Perform final cleanup. */ + pthread_key_delete(tls_key_threadnr); + pthread_attr_destroy(&thread_attr); + pthread_mutex_destroy(&global_lock); + motion_shutdown(); - return 0; + return 0; } /** @@ -2369,14 +2418,14 @@ int main (int argc, char **argv) */ void * mymalloc(size_t nbytes) { - void *dummy = malloc(nbytes); - if (!dummy) { - motion_log(LOG_EMERG, 1, "Could not allocate %llu bytes of memory!", (unsigned long long)nbytes); - motion_remove_pid(); - exit(1); - } + void *dummy = malloc(nbytes); + if (!dummy) { + motion_log(LOG_EMERG, 1, "Could not allocate %llu bytes of memory!", (unsigned long long)nbytes); + motion_remove_pid(); + exit(1); + } - return dummy; + return dummy; } /** @@ -2397,25 +2446,25 @@ void * mymalloc(size_t nbytes) */ void *myrealloc(void *ptr, size_t size, const char *desc) { - void *dummy = NULL; + void *dummy = NULL; - if (size == 0) { - free(ptr); - motion_log(LOG_WARNING, 0, - "Warning! Function %s tries to resize memoryblock at %p to 0 bytes!", - desc, ptr); - } else { - dummy = realloc(ptr, size); - if (!dummy) { - motion_log(LOG_EMERG, 0, - "Could not resize memory-block at offset %p to %llu bytes (function %s)!", - ptr, (unsigned long long)size, desc); - motion_remove_pid(); - exit(1); - } - } + if (size == 0) { + free(ptr); + motion_log(LOG_WARNING, 0, + "Warning! Function %s tries to resize memoryblock at %p to 0 bytes!", + desc, ptr); + } else { + dummy = realloc(ptr, size); + if (!dummy) { + motion_log(LOG_EMERG, 0, + "Could not resize memory-block at offset %p to %llu bytes (function %s)!", + ptr, (unsigned long long)size, desc); + motion_remove_pid(); + exit(1); + } + } - return dummy; + return dummy; } /** @@ -2435,30 +2484,30 @@ void *myrealloc(void *ptr, size_t size, const char *desc) */ int create_path(const char *path) { - char *start; - mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; + char *start; + mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - if (path[0] == '/') - start = strchr(path + 1, '/'); - else - start = strchr(path, '/'); + if (path[0] == '/') + start = strchr(path + 1, '/'); + else + start = strchr(path, '/'); - while(start) { - char *buffer = strdup(path); - buffer[start-path] = 0x00; + while(start) { + char *buffer = strdup(path); + buffer[start-path] = 0x00; - if (mkdir(buffer, mode) == -1 && errno != EEXIST) { - motion_log(LOG_ERR, 1, "Problem creating directory %s", buffer); - free(buffer); - return -1; - } + if (mkdir(buffer, mode) == -1 && errno != EEXIST) { + motion_log(LOG_ERR, 1, "Problem creating directory %s", buffer); + free(buffer); + return -1; + } - free(buffer); + free(buffer); - start = strchr(start + 1, '/'); - } + start = strchr(start + 1, '/'); + } - return 0; + return 0; } /** @@ -2479,35 +2528,34 @@ int create_path(const char *path) */ FILE * myfopen(const char *path, const char *mode) { - /* first, just try to open the file */ - FILE *dummy = fopen(path, mode); + /* first, just try to open the file */ + FILE *dummy = fopen(path, mode); - /* could not open file... */ - if (!dummy) { - /* path did not exist? */ - if (errno == ENOENT) { - //DEBUG CODE syslog(LOG_DEBUG, "Could not open file %s directly; path did not exist. Creating path & retrying.", path); + /* could not open file... */ + if (!dummy) { + /* path did not exist? */ + if (errno == ENOENT) { - /* create path for file... */ - if (create_path(path) == -1) - return NULL; + /* create path for file... */ + if (create_path(path) == -1) + return NULL; - /* and retry opening the file */ - dummy = fopen(path, mode); - if (dummy) - return dummy; - } + /* and retry opening the file */ + dummy = fopen(path, mode); + if (dummy) + return dummy; + } - /* two possibilities - * 1: there was an other error while trying to open the file for the first time - * 2: could still not open the file after the path was created - */ - motion_log(LOG_ERR, 1, "Error opening file %s with mode %s", path, mode); + /* two possibilities + * 1: there was an other error while trying to open the file for the first time + * 2: could still not open the file after the path was created + */ + motion_log(LOG_ERR, 1, "Error opening file %s with mode %s", path, mode); - return NULL; - } + return NULL; + } - return dummy; + return dummy; } /** @@ -2532,196 +2580,196 @@ FILE * myfopen(const char *path, const char *mode) size_t mystrftime(struct context *cnt, char *s, size_t max, const char *userformat, const struct tm *tm, const char *filename, int sqltype) { - char formatstring[PATH_MAX] = ""; - char tempstring[PATH_MAX] = ""; - char *format, *tempstr; - const char *pos_userformat; + char formatstring[PATH_MAX] = ""; + char tempstring[PATH_MAX] = ""; + char *format, *tempstr; + const char *pos_userformat; - format = formatstring; + format = formatstring; - /* if mystrftime is called with userformat = NULL we return a zero length string */ - if (userformat == NULL) { - *s = '\0'; - return 0; - } + /* if mystrftime is called with userformat = NULL we return a zero length string */ + if (userformat == NULL) { + *s = '\0'; + return 0; + } - for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) { + for (pos_userformat = userformat; *pos_userformat; ++pos_userformat) { - if (*pos_userformat == '%') { - /* Reset 'tempstr' to point to the beginning of 'tempstring', - * otherwise we will eat up tempstring if there are many - * format specifiers. - */ - tempstr = tempstring; - tempstr[0] = '\0'; - switch (*++pos_userformat) { - case '\0': // end of string - --pos_userformat; - break; + if (*pos_userformat == '%') { + /* Reset 'tempstr' to point to the beginning of 'tempstring', + * otherwise we will eat up tempstring if there are many + * format specifiers. + */ + tempstr = tempstring; + tempstr[0] = '\0'; + switch (*++pos_userformat) { + case '\0': // end of string + --pos_userformat; + break; - case 'v': // event - sprintf(tempstr, "%02d", cnt->event_nr); - break; + case 'v': // event + sprintf(tempstr, "%02d", cnt->event_nr); + break; - case 'q': // shots - sprintf(tempstr, "%02d", cnt->current_image->shot); - break; + case 'q': // shots + sprintf(tempstr, "%02d", cnt->current_image->shot); + break; - case 'D': // diffs - sprintf(tempstr, "%d", cnt->current_image->diffs); - break; + case 'D': // diffs + sprintf(tempstr, "%d", cnt->current_image->diffs); + break; - case 'N': // noise - sprintf(tempstr, "%d", cnt->noise); - break; + case 'N': // noise + sprintf(tempstr, "%d", cnt->noise); + break; - case 'i': // motion width - sprintf(tempstr, "%d", cnt->current_image->location.width); - break; + case 'i': // motion width + sprintf(tempstr, "%d", cnt->current_image->location.width); + break; - case 'J': // motion height - sprintf(tempstr, "%d", cnt->current_image->location.height); - break; + case 'J': // motion height + sprintf(tempstr, "%d", cnt->current_image->location.height); + break; - case 'K': // motion center x - sprintf(tempstr, "%d", cnt->current_image->location.x); - break; + case 'K': // motion center x + sprintf(tempstr, "%d", cnt->current_image->location.x); + break; - case 'L': // motion center y - sprintf(tempstr, "%d", cnt->current_image->location.y); - break; + case 'L': // motion center y + sprintf(tempstr, "%d", cnt->current_image->location.y); + break; - case 'o': // threshold - sprintf(tempstr, "%d", cnt->threshold); - break; + case 'o': // threshold + sprintf(tempstr, "%d", cnt->threshold); + break; - case 'Q': // number of labels - sprintf(tempstr, "%d", cnt->current_image->total_labels); - break; - case 't': // thread number - sprintf(tempstr, "%d",(int)(unsigned long) - pthread_getspecific(tls_key_threadnr)); - break; - case 'C': // text_event - if (cnt->text_event_string && cnt->text_event_string[0]) - snprintf(tempstr, PATH_MAX, "%s", cnt->text_event_string); - else - ++pos_userformat; - break; - case 'f': // filename - if (filename) - snprintf(tempstr, PATH_MAX, "%s", filename); - else - ++pos_userformat; - break; - case 'n': // sqltype - if (sqltype) - sprintf(tempstr, "%d", sqltype); - else - ++pos_userformat; - break; - default: // Any other code is copied with the %-sign - *format++ = '%'; - *format++ = *pos_userformat; - continue; - } + case 'Q': // number of labels + sprintf(tempstr, "%d", cnt->current_image->total_labels); + break; + case 't': // thread number + sprintf(tempstr, "%d",(int)(unsigned long) + pthread_getspecific(tls_key_threadnr)); + break; + case 'C': // text_event + if (cnt->text_event_string && cnt->text_event_string[0]) + snprintf(tempstr, PATH_MAX, "%s", cnt->text_event_string); + else + ++pos_userformat; + break; + case 'f': // filename + if (filename) + snprintf(tempstr, PATH_MAX, "%s", filename); + else + ++pos_userformat; + break; + case 'n': // sqltype + if (sqltype) + sprintf(tempstr, "%d", sqltype); + else + ++pos_userformat; + break; + default: // Any other code is copied with the %-sign + *format++ = '%'; + *format++ = *pos_userformat; + continue; + } - /* If a format specifier was found and used, copy the result from - * 'tempstr' to 'format'. - */ - if (tempstr[0]) { - while ((*format = *tempstr++) != '\0') - ++format; - continue; - } - } + /* If a format specifier was found and used, copy the result from + * 'tempstr' to 'format'. + */ + if (tempstr[0]) { + while ((*format = *tempstr++) != '\0') + ++format; + continue; + } + } - /* For any other character than % we just simply copy the character */ - *format++ = *pos_userformat; - } + /* For any other character than % we just simply copy the character */ + *format++ = *pos_userformat; + } - *format = '\0'; - format = formatstring; + *format = '\0'; + format = formatstring; - return strftime(s, max, format, tm); + return strftime(s, max, format, tm); } /** * motion_log * - * This routine is used for printing all informational, debug or error - * messages produced by any of the other motion functions. It always - * produces a message of the form "[n] {message}", and (if the param - * 'errno_flag' is set) follows the message with the associated error - * message from the library. + * This routine is used for printing all informational, debug or error + * messages produced by any of the other motion functions. It always + * produces a message of the form "[n] {message}", and (if the param + * 'errno_flag' is set) follows the message with the associated error + * message from the library. * * Parameters: * - * level logging level for the 'syslog' function - * (-1 implies no syslog message should be produced) - * errno_flag if set, the log message should be followed by the - * error message. - * fmt the format string for producing the message - * ap variable-length argument list + * level logging level for the 'syslog' function + * (-1 implies no syslog message should be produced) + * errno_flag if set, the log message should be followed by the + * error message. + * fmt the format string for producing the message + * ap variable-length argument list * * Returns: - * Nothing + * Nothing */ void motion_log(int level, int errno_flag, const char *fmt, ...) { - int errno_save, n; - char buf[1024]; + int errno_save, n; + char buf[1024]; #if (!defined(BSD)) - char msg_buf[100]; + char msg_buf[100]; #endif - va_list ap; - int threadnr; + va_list ap; + int threadnr; - /* If pthread_getspecific fails (e.g., because the thread's TLS doesn't - * contain anything for thread number, it returns NULL which casts to zero, - * which is nice because that's what we want in that case. - */ - threadnr = (unsigned long)pthread_getspecific(tls_key_threadnr); + /* If pthread_getspecific fails (e.g., because the thread's TLS doesn't + * contain anything for thread number, it returns NULL which casts to zero, + * which is nice because that's what we want in that case. + */ + threadnr = (unsigned long)pthread_getspecific(tls_key_threadnr); - /* - * First we save the current 'error' value. This is required because - * the subsequent calls to vsnprintf could conceivably change it! - */ - errno_save = errno; + /* + * First we save the current 'error' value. This is required because + * the subsequent calls to vsnprintf could conceivably change it! + */ + errno_save = errno; - /* Prefix the message with the thread number */ - n = snprintf(buf, sizeof(buf), "[%d] ", threadnr); + /* Prefix the message with the thread number */ + n = snprintf(buf, sizeof(buf), "[%d] ", threadnr); - /* Next add the user's message */ - va_start(ap, fmt); - n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); + /* Next add the user's message */ + va_start(ap, fmt); + n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); - /* If errno_flag is set, add on the library error message */ - if (errno_flag) { - strcat(buf, ": "); - n += 2; - /* - * this is bad - apparently gcc/libc wants to use the non-standard GNU - * version of strerror_r, which doesn't actually put the message into - * my buffer :-(. I have put in a 'hack' to get around this. - */ + /* If errno_flag is set, add on the library error message */ + if (errno_flag) { + strcat(buf, ": "); + n += 2; + /* + * this is bad - apparently gcc/libc wants to use the non-standard GNU + * version of strerror_r, which doesn't actually put the message into + * my buffer :-(. I have put in a 'hack' to get around this. + */ #if (defined(BSD)) - strerror_r(errno_save, buf + n, sizeof(buf) - n); /* 2 for the ': ' */ + strerror_r(errno_save, buf + n, sizeof(buf) - n); /* 2 for the ': ' */ #else - strcat(buf, strerror_r(errno_save, msg_buf, sizeof(msg_buf))); + strcat(buf, strerror_r(errno_save, msg_buf, sizeof(msg_buf))); #endif - } - /* If 'level' is not negative, send the message to the syslog */ - if (level >= 0) - syslog(level, buf); + } + /* If 'level' is not negative, send the message to the syslog */ + if (level >= 0) + syslog(level, buf); - /* For printing to stderr we need to add a newline */ - strcat(buf, "\n"); - fputs(buf, stderr); - fflush(stderr); + /* For printing to stderr we need to add a newline */ + strcat(buf, "\n"); + fputs(buf, stderr); + fflush(stderr); - /* Clean up the argument list routine */ - va_end(ap); + /* Clean up the argument list routine */ + va_end(ap); } diff --git a/netcam.c b/netcam.c index f39fb5ff..cddd45eb 100644 --- a/netcam.c +++ b/netcam.c @@ -123,19 +123,19 @@ static const char *connect_auth_req = "Authorization: Basic %s\r\n"; */ static char *netcam_url_match(regmatch_t m, const char *input) { - char *match = NULL; - int len; + char *match = NULL; + int len; - if (m.rm_so != -1) { - len = m.rm_eo - m.rm_so; + if (m.rm_so != -1) { + len = m.rm_eo - m.rm_so; - if ((match = (char *) malloc(len + 1)) != NULL) { - strncpy(match, input + m.rm_so, len); - match[len] = '\0'; - } - } + if ((match = (char *) malloc(len + 1)) != NULL) { + strncpy(match, input + m.rm_so, len); + match[len] = '\0'; + } + } - return (match); + return (match); } /** @@ -153,68 +153,68 @@ static char *netcam_url_match(regmatch_t m, const char *input) */ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) { - char *s; - int i; - const char *re = "(http|ftp)://(((.*):(.*))@)?" - "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; - regex_t pattbuf; - regmatch_t matches[10]; + char *s; + int i; + const char *re = "(http|ftp)://(((.*):(.*))@)?" + "([^/:]|[-.a-z0-9]+)(:([0-9]+))?($|(/[^:]*))"; + regex_t pattbuf; + regmatch_t matches[10]; - if( !strncmp( text_url, "file", 4 ) ) - re = "(file)://(((.*):(.*))@)?" - "([^/:]|[-.a-z0-9]*)(:([0-9]*))?($|(/[^:][/-_.a-z0-9]+))"; + if (!strncmp( text_url, "file", 4 ) ) + re = "(file)://(((.*):(.*))@)?" + "([^/:]|[-.a-z0-9]*)(:([0-9]*))?($|(/[^:][/-_.a-z0-9]+))"; - if (debug_level > CAMERA_DEBUG) - motion_log(-1, 0, "Entry netcam_url_parse data %s", text_url ); + if (debug_level > CAMERA_DEBUG) + motion_log(-1, 0, "Entry netcam_url_parse data %s", text_url ); - memset(parse_url, 0, sizeof(struct url_t)); - /* - * regcomp compiles regular expressions into a form that is - * suitable for regexec searches - * regexec matches the URL string against the regular expression - * and returns an array of pointers to strings matching each match - * within (). The results that we need are finally placed in parse_url - */ - if (!regcomp(&pattbuf, re, REG_EXTENDED | REG_ICASE)) { - if (regexec(&pattbuf, text_url, 10, matches, 0) != REG_NOMATCH) { - for (i = 0; i < 10; i++) { - if ((s = netcam_url_match(matches[i], text_url)) != NULL) { - if (debug_level > CAMERA_DEBUG) - motion_log(-1, 0, "Parse case %d data %s", i, s ); - switch (i) { - case 1: - parse_url->service = s; - break; - case 3: - parse_url->userpass = s; - break; - case 6: - parse_url->host = s; - break; - case 8: - parse_url->port = atoi(s); - free(s); - break; - case 9: - parse_url->path = s; - break; - /* other components ignored */ - default: - free(s); - break; - } - } - } - } - } - if ((!parse_url->port) && (parse_url->service)){ - if (!strcmp(parse_url->service, "http")) - parse_url->port = 80; - else if (!strcmp(parse_url->service, "ftp")) - parse_url->port = 21; - } + memset(parse_url, 0, sizeof(struct url_t)); + /* + * regcomp compiles regular expressions into a form that is + * suitable for regexec searches + * regexec matches the URL string against the regular expression + * and returns an array of pointers to strings matching each match + * within (). The results that we need are finally placed in parse_url + */ + if (!regcomp(&pattbuf, re, REG_EXTENDED | REG_ICASE)) { + if (regexec(&pattbuf, text_url, 10, matches, 0) != REG_NOMATCH) { + for (i = 0; i < 10; i++) { + if ((s = netcam_url_match(matches[i], text_url)) != NULL) { + if (debug_level > CAMERA_DEBUG) + motion_log(-1, 0, "Parse case %d data %s", i, s ); + switch (i) { + case 1: + parse_url->service = s; + break; + case 3: + parse_url->userpass = s; + break; + case 6: + parse_url->host = s; + break; + case 8: + parse_url->port = atoi(s); + free(s); + break; + case 9: + parse_url->path = s; + break; + /* other components ignored */ + default: + free(s); + break; + } + } + } + } + } + if ((!parse_url->port) && (parse_url->service)){ + if (!strcmp(parse_url->service, "http")) + parse_url->port = 80; + else if (!strcmp(parse_url->service, "ftp")) + parse_url->port = 21; + } - regfree(&pattbuf); + regfree(&pattbuf); } /** @@ -231,25 +231,25 @@ static void netcam_url_parse(struct url_t *parse_url, const char *text_url) */ static void netcam_url_free(struct url_t *parse_url) { - if (parse_url->service) { - free(parse_url->service); - parse_url->service = NULL; - } + if (parse_url->service) { + free(parse_url->service); + parse_url->service = NULL; + } - if (parse_url->userpass) { - free(parse_url->userpass); - parse_url->userpass = NULL; - } + if (parse_url->userpass) { + free(parse_url->userpass); + parse_url->userpass = NULL; + } - if (parse_url->host) { - free(parse_url->host); - parse_url->host = NULL; - } + if (parse_url->host) { + free(parse_url->host); + parse_url->host = NULL; + } - if (parse_url->path) { - free(parse_url->path); - parse_url->path = NULL; - } + if (parse_url->path) { + free(parse_url->path); + parse_url->path = NULL; + } } /** @@ -267,24 +267,24 @@ static void netcam_url_free(struct url_t *parse_url) */ static void check_quote(char *str) { - int len; - char ch; + int len; + char ch; - ch = *str; + ch = *str; - if ((ch == '"') || (ch == '\'')) { - len = strlen(str) - 1; - if (str[len] == ch) { - memmove(str, str+1, len-1); - str[len-1] = 0; - } - } + if ((ch == '"') || (ch == '\'')) { + len = strlen(str) - 1; + if (str[len] == ch) { + memmove(str, str+1, len-1); + str[len-1] = 0; + } + } } /** * netcam_check_content_length * - * Analyse an HTTP-header line to see if it is a Content-length + * Analyse an HTTP-header line to see if it is a Content-length * * Parameters: * @@ -297,26 +297,26 @@ static void check_quote(char *str) */ static long netcam_check_content_length(char *header) { - long length=-1; /* note this is a long, not an int */ + long length = -1; /* note this is a long, not an int */ - if (!header_process(header, "Content-Length", header_extract_number, &length)) { - /* - * Some netcams deliver some bad-format data, but if - * we were able to recognize the header section and the - * number we might as well try to use it. - */ - if (length > 0) - return length; - return -1; - } + if (!header_process(header, "Content-Length", header_extract_number, &length)) { + /* + * Some netcams deliver some bad-format data, but if + * we were able to recognize the header section and the + * number we might as well try to use it. + */ + if (length > 0) + return length; + return -1; + } - return length; + return length; } /** * netcam_check_keepalive * - * Analyse an HTTP-header line to see if it is a Keep-Alive. + * Analyse an HTTP-header line to see if it is a Keep-Alive. * * Parameters: * @@ -329,23 +329,23 @@ static long netcam_check_content_length(char *header) */ static int netcam_check_keepalive(char *header) { - char *content_type = NULL; + char *content_type = NULL; - if (!header_process(header, "Keep-Alive", http_process_type, &content_type)) - return -1; + if (!header_process(header, "Keep-Alive", http_process_type, &content_type)) + return -1; - /* We do not detect the second field or other case mixes at present. */ + /* We do not detect the second field or other case mixes at present. */ - if (content_type) - free(content_type); + if (content_type) + free(content_type); - return 1; + return 1; } /** * netcam_check_close * - * Analyse an HTTP-header line to see if it is a Connection: close + * Analyse an HTTP-header line to see if it is a Connection: close * * Parameters: * @@ -358,25 +358,25 @@ static int netcam_check_keepalive(char *header) */ static int netcam_check_close(char *header) { - char *type = NULL; - int ret=-1; + char *type = NULL; + int ret = -1; - if (!header_process(header, "Connection", http_process_type, &type)) - return -1; - - if (!strcmp(type, "close")) /* strcmp returns 0 for match */ - ret=1; - - if (type) - free(type); + if (!header_process(header, "Connection", http_process_type, &type)) + return -1; + + if (!strcmp(type, "close")) /* strcmp returns 0 for match */ + ret = 1; + + if (type) + free(type); - return ret; + return ret; } /** * netcam_check_content_type * - * Analyse an HTTP-header line to see if it is a Content-type + * Analyse an HTTP-header line to see if it is a Content-type * * Parameters: * @@ -391,24 +391,24 @@ static int netcam_check_close(char *header) */ static int netcam_check_content_type(char *header) { - char *content_type = NULL; - int ret; + char *content_type = NULL; + int ret; - if (!header_process(header, "Content-type", http_process_type, &content_type)) - return -1; + if (!header_process(header, "Content-type", http_process_type, &content_type)) + return -1; - if (!strcmp(content_type, "image/jpeg")) { - ret = 1; - } else if (!strcmp(content_type, "multipart/x-mixed-replace") || - !strcmp(content_type, "multipart/mixed")) { - ret = 2; - } else - ret = 0; + if (!strcmp(content_type, "image/jpeg")) { + ret = 1; + } else if (!strcmp(content_type, "multipart/x-mixed-replace") || + !strcmp(content_type, "multipart/mixed")) { + ret = 2; + } else + ret = 0; - if (content_type) - free(content_type); + if (content_type) + free(content_type); - return ret; + return ret; } @@ -426,87 +426,87 @@ static int netcam_check_content_type(char *header) */ static int netcam_read_next_header(netcam_context_ptr netcam) { - int retval; - char *header; + int retval; + char *header; - /* - * return if not connected - */ - if (netcam->sock == -1) return -1; - /* - * We are expecting a header which *must* contain a mime-type of - * image/jpeg, and *might* contain a Content-Length. - * - * If this is a "streaming" camera, the header *must* be preceded - * by a "boundary" string. - * - */ - netcam->caps.content_length = 0; - /* - * If this is a "streaming" camera, the stream header must be - * preceded by a "boundary" string - */ - if (netcam->caps.streaming) { - while (1) { - retval = header_get(netcam, &header, HG_NONE); + /* + * return if not connected + */ + if (netcam->sock == -1) return -1; + /* + * We are expecting a header which *must* contain a mime-type of + * image/jpeg, and *might* contain a Content-Length. + * + * If this is a "streaming" camera, the header *must* be preceded + * by a "boundary" string. + * + */ + netcam->caps.content_length = 0; + /* + * If this is a "streaming" camera, the stream header must be + * preceded by a "boundary" string + */ + if (netcam->caps.streaming) { + while (1) { + retval = header_get(netcam, &header, HG_NONE); - if (retval != HG_OK) { - /* Header reported as not-OK, check to see if it's null */ - if (strlen(header) == 0 ) { - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "Error reading image header, streaming mode (1). Null header."); - } else { - /* Header is not null. Output it in case it's a new camera with unknown headers. */ - if (debug_level > CAMERA_INFO) - motion_log(LOG_ERR, 0, "Error reading image header, streaming mode (1). " - "Unknown header '%s'", header ); - } + if (retval != HG_OK) { + /* Header reported as not-OK, check to see if it's null */ + if (strlen(header) == 0) { + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "Error reading image header, streaming mode (1). Null header."); + } else { + /* Header is not null. Output it in case it's a new camera with unknown headers. */ + if (debug_level > CAMERA_INFO) + motion_log(LOG_ERR, 0, "Error reading image header, streaming mode (1). " + "Unknown header '%s'", header ); + } - free(header); - return -1; - } + free(header); + return -1; + } - retval = (strstr(header, netcam->boundary) == NULL); - free(header); + retval = (strstr(header, netcam->boundary) == NULL); + free(header); - if (!retval) - break; - } - } + if (!retval) + break; + } + } - while (1) { - retval = header_get(netcam, &header, HG_NONE); + while (1) { + retval = header_get(netcam, &header, HG_NONE); - if (retval != HG_OK) { - motion_log(LOG_ERR, 0, "Error reading image header (2)"); - free(header); - return -1; - } + if (retval != HG_OK) { + motion_log(LOG_ERR, 0, "Error reading image header (2)"); + free(header); + return -1; + } - if (*header == 0) - break; + if (*header == 0) + break; - if ((retval = netcam_check_content_type(header)) >= 0) { - if (retval != 1) { - motion_log(LOG_ERR, 0, "Header not JPEG"); - free(header); - return -1; - } - } + if ((retval = netcam_check_content_type(header)) >= 0) { + if (retval != 1) { + motion_log(LOG_ERR, 0, "Header not JPEG"); + free(header); + return -1; + } + } - if ((retval = (int) netcam_check_content_length(header)) > 0) { - netcam->caps.content_length = 1; /* set flag */ - netcam->receiving->content_length = (int) retval; - } + if ((retval = (int) netcam_check_content_length(header)) > 0) { + netcam->caps.content_length = 1; /* set flag */ + netcam->receiving->content_length = (int) retval; + } - free(header); - } + free(header); + } - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "Found image header record"); + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "Found image header record"); - free(header); - return 0; + free(header); + return 0; } /** @@ -533,231 +533,235 @@ static int netcam_read_next_header(netcam_context_ptr netcam) */ static int netcam_read_first_header(netcam_context_ptr netcam) { - int retval = -2; /* "Unknown err" */ - int ret; - int firstflag = 1; - int aliveflag = 0; /* If we have seen a Keep-Alive header from cam */ - int closeflag = 0; /* If we have seen a Connection: close header from cam */ - char *header; - char *boundary; - struct context *cnt = netcam->cnt; /* for conf debug_level */ + int retval = -2; /* "Unknown err" */ + int ret; + int firstflag = 1; + int aliveflag = 0; /* If we have seen a Keep-Alive header from cam */ + int closeflag = 0; /* If we have seen a Connection: close header from cam */ + char *header; + char *boundary; + struct context *cnt = netcam->cnt; /* for conf debug_level */ - /* Send the initial command to the camera */ - if (send(netcam->sock, netcam->connect_request, - strlen(netcam->connect_request), 0) < 0) { - motion_log(LOG_ERR, 1, "Error sending 'connect' request"); - return -1; - } + /* Send the initial command to the camera */ + if (send(netcam->sock, netcam->connect_request, + strlen(netcam->connect_request), 0) < 0) { + motion_log(LOG_ERR, 1, "Error sending 'connect' request"); + return -1; + } - /* - * We expect to get back an HTTP header from the camera. - * Successive calls to header_get will return each line - * of the header received. We will continue reading until - * a blank line is received. - * - * As we process the header, we are looking for either of - * header lines Content-type or Content-length. Content-type - * is used to determine whether the camera is "streaming" or - * "non-streaming", and Content-length will be used to determine - * whether future reads of images will be controlled by the - * length specified before the image, or by a boundary string. - * - * The Content-length will only be present "just before" an - * image is sent (if it is present at all). That means that, if - * this is a "streaming" camera, it will not be present in the - * "first header", but will occur later (after a boundary-string). - * For a non-streaming camera, however, there is no boundary-string, - * and the first header is, in fact, the only header. In this case, - * there may be a Content-length. - * - */ - while (1) { /* 'Do forever' */ - ret = header_get(netcam, &header, HG_NONE); + /* + * We expect to get back an HTTP header from the camera. + * Successive calls to header_get will return each line + * of the header received. We will continue reading until + * a blank line is received. + * + * As we process the header, we are looking for either of + * header lines Content-type or Content-length. Content-type + * is used to determine whether the camera is "streaming" or + * "non-streaming", and Content-length will be used to determine + * whether future reads of images will be controlled by the + * length specified before the image, or by a boundary string. + * + * The Content-length will only be present "just before" an + * image is sent (if it is present at all). That means that, if + * this is a "streaming" camera, it will not be present in the + * "first header", but will occur later (after a boundary-string). + * For a non-streaming camera, however, there is no boundary-string, + * and the first header is, in fact, the only header. In this case, + * there may be a Content-length. + * + */ + while (1) { /* 'Do forever' */ + ret = header_get(netcam, &header, HG_NONE); - if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ - motion_log(LOG_DEBUG, 0, "Received first header ('%s')", header); + if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ + motion_log(LOG_DEBUG, 0, "Received first header ('%s')", header); - if (ret != HG_OK) { - if (debug_level > CAMERA_INFO) - motion_log(LOG_ERR, 0, "Error reading first header (%s)", header); - free(header); - return -1; - } - if (firstflag) { - if ((ret = http_result_code(header)) != 200) { - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "HTTP Result code %d", ret); - free(header); - if (netcam->connect_keepalive) { - /* Cannot unset netcam->cnt->conf.netcam_http as it is assigned const */ - /* But we do unset the netcam keepalive flag which was set in netcam_start */ - /* This message is logged as Information as it would be useful to know */ - /* if your netcam often returns bad HTTP result codes */ - netcam->connect_keepalive = 0; - motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag" - "due to apparent closed HTTP connection."); - } - return ret; - } - firstflag = 0; - free(header); - continue; - } - if (*header == 0) /* blank line received */ - break; + if (ret != HG_OK) { + if (debug_level > CAMERA_INFO) + motion_log(LOG_ERR, 0, "Error reading first header (%s)", header); + free(header); + return -1; + } + if (firstflag) { + if ((ret = http_result_code(header)) != 200) { + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "HTTP Result code %d", ret); - /* Check if this line is the content type */ - if ((ret = netcam_check_content_type(header)) >= 0) { - retval = ret; - /* - * We are expecting to find one of three types: - * 'multipart/x-mixed-replace', 'multipart/mixed' - * or 'image/jpeg'. The first two will be received - * from a streaming camera, and the third from a - * camera which provides a single frame only. - */ - switch (ret) { - case 1: /* not streaming */ - if (SETUP) { - if (netcam->connect_keepalive) - motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive set)"); - else - motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive not set)"); - } - netcam->caps.streaming = 0; - break; + free(header); - case 2: /* streaming */ - if (SETUP) - motion_log(LOG_DEBUG, 0, "Streaming camera"); + if (netcam->connect_keepalive) { + /* Cannot unset netcam->cnt->conf.netcam_http as it is assigned const */ + /* But we do unset the netcam keepalive flag which was set in netcam_start */ + /* This message is logged as Information as it would be useful to know */ + /* if your netcam often returns bad HTTP result codes */ + netcam->connect_keepalive = 0; + motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag" + "due to apparent closed HTTP connection."); + } + return ret; + } - netcam->caps.streaming = 1; + firstflag = 0; + free(header); + continue; + } + if (*header == 0) /* blank line received */ + break; - if ((boundary = strstr(header, "boundary="))) { - /* - * on error recovery this - * may already be set - * */ - if (netcam->boundary) - free(netcam->boundary); + /* Check if this line is the content type */ + if ((ret = netcam_check_content_type(header)) >= 0) { + retval = ret; + /* + * We are expecting to find one of three types: + * 'multipart/x-mixed-replace', 'multipart/mixed' + * or 'image/jpeg'. The first two will be received + * from a streaming camera, and the third from a + * camera which provides a single frame only. + */ + switch (ret) { + case 1: /* not streaming */ + if (SETUP) { + if (netcam->connect_keepalive) + motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive set)"); + else + motion_log(LOG_DEBUG, 0, "Non-streaming camera (keep-alive not set)"); + } + netcam->caps.streaming = 0; + break; - netcam->boundary = strdup(boundary + 9); - /* - * HTTP protocol apparently permits the boundary string - * to be quoted (the Lumenera does this, which caused - * trouble) so we need to get rid of any surrounding - * quotes - */ - check_quote(netcam->boundary); - netcam->boundary_length = strlen(netcam->boundary); + case 2: /* streaming */ + if (SETUP) + motion_log(LOG_DEBUG, 0, "Streaming camera"); - if (SETUP) { - motion_log(LOG_DEBUG, 0, "Boundary string [%s]", - netcam->boundary); - } - } - break; + netcam->caps.streaming = 1; - default:{ /* error */ - motion_log(LOG_ERR, 0, "Unrecognized content type"); - free(header); - return -1; - } - } - } else if ((ret = (int) netcam_check_content_length(header)) >= 0) { - if (SETUP) - motion_log(LOG_DEBUG, 0, "Content-length present"); + if ((boundary = strstr(header, "boundary="))) { + /* + * on error recovery this + * may already be set + * */ + if (netcam->boundary) + free(netcam->boundary); - netcam->caps.content_length = 1; /* set flag */ - netcam->receiving->content_length = ret; - } else if (netcam_check_keepalive(header) == TRUE) { - /* Note that we have received a Keep-Alive header, and thus the socket can be left open */ - aliveflag=TRUE; - netcam->keepalive_thisconn = TRUE; - /* This flag will not be set when a Streaming cam is in use, but that */ - /* does not matter as the test below looks at Streaming state also. */ - } else if (netcam_check_close(header) == TRUE) { - /* Note that we have received a Connection: close header */ - closeflag=TRUE; - /* This flag is acted upon below */ - if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ - motion_log(LOG_DEBUG, 0, "Found Conn:close header ('%s')", header); - } - free(header); - } - free(header); + netcam->boundary = strdup(boundary + 9); + /* + * HTTP protocol apparently permits the boundary string + * to be quoted (the Lumenera does this, which caused + * trouble) so we need to get rid of any surrounding + * quotes + */ + check_quote(netcam->boundary); + netcam->boundary_length = strlen(netcam->boundary); - if (!netcam->caps.streaming && netcam->connect_keepalive) { - - /* - * If we are a non-streaming (ie. Jpeg) netcam and keepalive is configured - */ + if (SETUP) + motion_log(LOG_DEBUG, 0, "Boundary string [%s]", + netcam->boundary); + + } + break; - if (aliveflag){ - if (closeflag) { - /* - * If not a streaming cam, and keepalive is set, and the flag shows we - * did not see a Keep-Alive field returned from netcam and a Close field. - * Not quite sure what the correct course of action is here. In for testing. - */ - motion_log(LOG_INFO, 0, "Info: Both 'Connection: Keep-Alive' and 'Connection: close' " - "header received. Motion continues unchanged."); - }else{ - /* aliveflag && !closeflag - * - * If not a streaming cam, and keepalive is set, and the flag shows we - * just got a Keep-Alive field returned from netcam and no Close field. - * No action, as this is the normal case. In debug we print a notification. - */ - - if (debug_level > CAMERA_INFO) - motion_log(LOG_INFO, 0, "Info: Received a Keep-Alive field in this set of headers."); - } - }else{ /* !aliveflag */ - if (!closeflag) { - /* - * If not a streaming cam, and keepalive is set, and the flag shows we - * did not see a Keep-Alive field returned from netcam nor a Close field. - * Not quite sure what the correct course of action is here. In for testing. - */ - motion_log(LOG_INFO, 0, "Info: No 'Connection: Keep-Alive' nor 'Connection: close' " - "header received. Motion continues unchanged."); - }else{ - /* !aliveflag & closeflag - * If not a streaming cam, and keepalive is set, and the flag shows we - * received a 'Connection: close' field returned from netcam. It is not likely - * we will get a Keep-Alive and Close header together - this is picked up by - * the test code above. - * If we receive a Close header, then we want to cease keep-alive for this cam. - * This situation will occur in 2 situations: - * (a) in HTTP 1.1 when the client wants to stop the keep-alive - * (and in this case it would be correct to close connection and then - * make a new one, with keep-alive set again). - * (b) in HTTP 1.0 with keepalive, when the client does not support it. - * In this case we should not attempt to re-start Keep-Alive. - * Due to that, we accept a Connection: close header in HTTP 1.0 & 1.1 modes - * - * To tell between the sitation where a camera has been in Keep-Alive mode and - * is now finishing (and will want to be re-started in Keep-Alive) and the other - * case when a cam does not support it, we have a flag which says if the netcam - * has returned a Keep-Alive flag during this connection. If that's set, we - * set ourselves up to re-connect with Keep-Alive after the socket is closed. - * If it's not set, then we will not try again to use Keep-Alive. - */ - if (!netcam->keepalive_thisconn) { - netcam->connect_keepalive = FALSE; /* No further attempts at keep-alive */ - motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag because 'Connection: close' " - "header received. Netcam does not support Keep-Alive. Motion " - "continues in non-Keep-Alive."); - } else { - netcam->keepalive_timeup = TRUE; /* We will close and re-open keep-alive */ - motion_log(LOG_INFO, 0, "Keep-Alive has reached end of valid period. Motion will close " - "netcam, then resume Keep-Alive with a new socket."); - } - } - } - } - return retval; + default: /* error */ + motion_log(LOG_ERR, 0, "Unrecognized content type"); + free(header); + return -1; + + } + } else if ((ret = (int) netcam_check_content_length(header)) >= 0) { + if (SETUP) + motion_log(LOG_DEBUG, 0, "Content-length present"); + + netcam->caps.content_length = 1; /* set flag */ + netcam->receiving->content_length = ret; + } else if (netcam_check_keepalive(header) == TRUE) { + /* Note that we have received a Keep-Alive header, and thus the socket can be left open */ + aliveflag=TRUE; + netcam->keepalive_thisconn = TRUE; + /* This flag will not be set when a Streaming cam is in use, but that */ + /* does not matter as the test below looks at Streaming state also. */ + } else if (netcam_check_close(header) == TRUE) { + /* Note that we have received a Connection: close header */ + closeflag=TRUE; + /* This flag is acted upon below */ + if (debug_level > CAMERA_INFO) /* Changed criterion and moved up from below to catch headers that cause returns */ + motion_log(LOG_DEBUG, 0, "Found Conn:close header ('%s')", header); + } + free(header); + } + free(header); + + if (!netcam->caps.streaming && netcam->connect_keepalive) { + + /* + * If we are a non-streaming (ie. Jpeg) netcam and keepalive is configured + */ + + if (aliveflag) { + if (closeflag) { + /* + * If not a streaming cam, and keepalive is set, and the flag shows we + * did not see a Keep-Alive field returned from netcam and a Close field. + * Not quite sure what the correct course of action is here. In for testing. + */ + motion_log(LOG_INFO, 0, "Info: Both 'Connection: Keep-Alive' and 'Connection: close' " + "header received. Motion continues unchanged."); + } else { + /* aliveflag && !closeflag + * + * If not a streaming cam, and keepalive is set, and the flag shows we + * just got a Keep-Alive field returned from netcam and no Close field. + * No action, as this is the normal case. In debug we print a notification. + */ + + if (debug_level > CAMERA_INFO) + motion_log(LOG_INFO, 0, "Info: Received a Keep-Alive field in this set of headers."); + } + } else { /* !aliveflag */ + if (!closeflag) { + /* + * If not a streaming cam, and keepalive is set, and the flag shows we + * did not see a Keep-Alive field returned from netcam nor a Close field. + * Not quite sure what the correct course of action is here. In for testing. + */ + motion_log(LOG_INFO, 0, "Info: No 'Connection: Keep-Alive' nor 'Connection: close' " + "header received. Motion continues unchanged."); + } else { + /* !aliveflag & closeflag + * If not a streaming cam, and keepalive is set, and the flag shows we + * received a 'Connection: close' field returned from netcam. It is not likely + * we will get a Keep-Alive and Close header together - this is picked up by + * the test code above. + * If we receive a Close header, then we want to cease keep-alive for this cam. + * This situation will occur in 2 situations: + * (a) in HTTP 1.1 when the client wants to stop the keep-alive + * (and in this case it would be correct to close connection and then + * make a new one, with keep-alive set again). + * (b) in HTTP 1.0 with keepalive, when the client does not support it. + * In this case we should not attempt to re-start Keep-Alive. + * Due to that, we accept a Connection: close header in HTTP 1.0 & 1.1 modes + * + * To tell between the sitation where a camera has been in Keep-Alive mode and + * is now finishing (and will want to be re-started in Keep-Alive) and the other + * case when a cam does not support it, we have a flag which says if the netcam + * has returned a Keep-Alive flag during this connection. If that's set, we + * set ourselves up to re-connect with Keep-Alive after the socket is closed. + * If it's not set, then we will not try again to use Keep-Alive. + */ + if (!netcam->keepalive_thisconn) { + netcam->connect_keepalive = FALSE; /* No further attempts at keep-alive */ + motion_log(LOG_INFO, 0, "Removed netcam Keep-Alive flag because 'Connection: close' " + "header received. Netcam does not support Keep-Alive. Motion " + "continues in non-Keep-Alive."); + } else { + netcam->keepalive_timeup = TRUE; /* We will close and re-open keep-alive */ + motion_log(LOG_INFO, 0, "Keep-Alive has reached end of valid period. Motion will close " + "netcam, then resume Keep-Alive with a new socket."); + } + } + } + } + + return retval; } /** @@ -774,13 +778,12 @@ static int netcam_read_first_header(netcam_context_ptr netcam) */ static void netcam_disconnect(netcam_context_ptr netcam) { + if (netcam->sock > 0) { + if (close(netcam->sock) < 0) + motion_log(LOG_ERR, 1, "netcam_disconnect"); - if (netcam->sock > 0) { - if (close(netcam->sock) < 0) - motion_log(LOG_ERR, 1, "netcam_disconnect"); - - netcam->sock = -1; - } + netcam->sock = -1; + } } /** @@ -802,169 +805,181 @@ static void netcam_disconnect(netcam_context_ptr netcam) */ static int netcam_connect(netcam_context_ptr netcam, int err_flag) { - struct sockaddr_in server; /* for connect */ - struct addrinfo *res; /* for getaddrinfo */ - int ret; - int saveflags; - int back_err; - int optval; - socklen_t optlen=sizeof(optval); - socklen_t len; - fd_set fd_w; - struct timeval selecttime; + struct sockaddr_in server; /* for connect */ + struct addrinfo *res; /* for getaddrinfo */ + int ret; + int saveflags; + int back_err; + int optval; + socklen_t optlen=sizeof(optval); + socklen_t len; + fd_set fd_w; + struct timeval selecttime; - /* Assure any previous connection has been closed - IF we are not in keepalive */ - if (!netcam->connect_keepalive) { - if (debug_level > CAMERA_INFO ) - motion_log(LOG_DEBUG, 0, "netcam_connect, disconnecting netcam since keep-alive not set." ); - netcam_disconnect(netcam); + /* Assure any previous connection has been closed - IF we are not in keepalive */ + if (!netcam->connect_keepalive) { + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect, disconnecting netcam since keep-alive not set." ); + + netcam_disconnect(netcam); - /* create a new socket */ - if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - motion_log(LOG_ERR, 1, "netcam_connect with no keepalive, attempt to create socket failed."); - return -1; - } - if (debug_level > CAMERA_INFO ) - motion_log(LOG_DEBUG, 0, "netcam_connect with no keepalive, new socket created fd %d", netcam->sock); - } else { /* We are in keepalive mode, check for invalid socket */ - if (netcam->sock == -1) { - /* Must be first time, or closed, create a new socket */ - if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - motion_log(LOG_ERR, 1, "netcam_connect with keepalive set, invalid socket." - "This could be the first time. Creating a new one failed."); - return -1; - } - if (debug_level > CAMERA_INFO ) - motion_log(LOG_DEBUG, 0, "netcam_connect with keepalive set, invalid socket." - "This could be first time, created a new one with fd %d", netcam->sock); + /* create a new socket */ + if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + motion_log(LOG_ERR, 1, "netcam_connect with no keepalive, attempt to create socket failed."); + return -1; + } - /* Record that this connection has not yet received a Keep-Alive header */ - netcam->keepalive_thisconn = FALSE; + if (debug_level > CAMERA_INFO ) + motion_log(LOG_DEBUG, 0, "netcam_connect with no keepalive, new socket created fd %d", netcam->sock); - /* Check the socket status for the keepalive option */ - if (getsockopt(netcam->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) { - motion_log(LOG_ERR, 1, "netcam_connect : getsockopt()"); - return -1; - } - if (debug_level > CAMERA_INFO) { - if (optval==1) - motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE is ON"); - else - motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE is OFF"); - } - - /* Set the option active */ - optval = 1; - optlen = sizeof(optval); - if(setsockopt(netcam->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { - motion_log(LOG_ERR, 1, "netcam_connect : setsockopt()"); - return -1; - } - if (debug_level > CAMERA_INFO ) - motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE set on socket."); - } else if (debug_level > CAMERA_INFO ) { - motion_log(LOG_DEBUG, 0, "netcam_connect re-using socket %d since keepalive is set.", netcam->sock); - } - } + } else { /* We are in keepalive mode, check for invalid socket */ + if (netcam->sock == -1) { + /* Must be first time, or closed, create a new socket */ + if ((netcam->sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + motion_log(LOG_ERR, 1, "netcam_connect with keepalive set, invalid socket." + "This could be the first time. Creating a new one failed."); + return -1; + } - /* lookup the hostname given in the netcam URL */ - if ((ret = getaddrinfo(netcam->connect_host, NULL, NULL, &res)) != 0) { - if (!err_flag) - motion_log(LOG_ERR, 0, "getaddrinfo() failed (%s): %s", - netcam->connect_host, gai_strerror(ret)); - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (1)"); - netcam_disconnect(netcam); - return -1; - } + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect with keepalive set, invalid socket." + "This could be first time, created a new one with fd %d", netcam->sock); - /* - * Fill the hostname details into the 'server' structure and - * attempt to connect to the remote server - */ - memset(&server, 0, sizeof(server)); - memcpy(&server, res->ai_addr, sizeof(server)); - freeaddrinfo(res); + /* Record that this connection has not yet received a Keep-Alive header */ + netcam->keepalive_thisconn = FALSE; - server.sin_family = AF_INET; - server.sin_port = htons(netcam->connect_port); + /* Check the socket status for the keepalive option */ + if (getsockopt(netcam->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen) < 0) { + motion_log(LOG_ERR, 1, "netcam_connect : getsockopt()"); + return -1; + } - /* - * We set the socket non-blocking and then use a 'select' - * system call to control the timeout. - */ + if (debug_level > CAMERA_INFO) { + if (optval == 1) + motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE is ON"); + else + motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE is OFF"); + } + + /* Set the option active */ + optval = 1; + optlen = sizeof(optval); - if ((saveflags = fcntl(netcam->sock, F_GETFL, 0)) < 0) { - motion_log(LOG_ERR, 1, "fcntl(1) on socket"); - netcam_disconnect(netcam); - return -1; - } + if (setsockopt(netcam->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { + motion_log(LOG_ERR, 1, "netcam_connect : setsockopt()"); + return -1; + } - /* Set the socket non-blocking */ - if (fcntl(netcam->sock, F_SETFL, saveflags | O_NONBLOCK) < 0) { - motion_log(LOG_ERR, 1, "fcntl(2) on socket"); - netcam_disconnect(netcam); - return -1; - } + if (debug_level > CAMERA_INFO ) + motion_log(LOG_DEBUG, 0, "netcam_connect: SO_KEEPALIVE set on socket."); - /* Now the connect call will return immediately */ - ret = connect(netcam->sock, (struct sockaddr *) &server, - sizeof(server)); - back_err = errno; /* save the errno from connect */ + } else if (debug_level > CAMERA_INFO) { + motion_log(LOG_DEBUG, 0, "netcam_connect re-using socket %d since keepalive is set.", netcam->sock); + } + } - /* If the connect failed with anything except EINPROGRESS, error */ - if ((ret < 0) && (back_err != EINPROGRESS)) { - if (!err_flag) - motion_log(LOG_ERR, 1, "connect() failed (%d)", back_err); - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (4)"); - netcam_disconnect(netcam); - return -1; - } + /* lookup the hostname given in the netcam URL */ + if ((ret = getaddrinfo(netcam->connect_host, NULL, NULL, &res)) != 0) { + if (!err_flag) + motion_log(LOG_ERR, 0, "getaddrinfo() failed (%s): %s", + netcam->connect_host, gai_strerror(ret)); + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (1)"); + netcam_disconnect(netcam); + return -1; + } - /* Now we do a 'select' with timeout to wait for the connect */ - FD_ZERO(&fd_w); - FD_SET(netcam->sock, &fd_w); - selecttime.tv_sec = CONNECT_TIMEOUT; - selecttime.tv_usec = 0; - ret = select(FD_SETSIZE, NULL, &fd_w, NULL, &selecttime); + /* + * Fill the hostname details into the 'server' structure and + * attempt to connect to the remote server + */ + memset(&server, 0, sizeof(server)); + memcpy(&server, res->ai_addr, sizeof(server)); + freeaddrinfo(res); - if (ret == 0) { /* 0 means timeout */ - if (!err_flag) - motion_log(LOG_ERR, 0, "timeout on connect()"); - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (2)"); - netcam_disconnect(netcam); - return -1; - } + server.sin_family = AF_INET; + server.sin_port = htons(netcam->connect_port); - /* - * A +ve value returned from the select (actually, it must be a - * '1' showing 1 fd's changed) shows the select has completed. - * Now we must check the return code from the select. - */ - len = sizeof(ret); + /* + * We set the socket non-blocking and then use a 'select' + * system call to control the timeout. + */ - if (getsockopt(netcam->sock, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - motion_log(LOG_ERR, 0, "getsockopt after connect"); - netcam_disconnect(netcam); - return -1; - } + if ((saveflags = fcntl(netcam->sock, F_GETFL, 0)) < 0) { + motion_log(LOG_ERR, 1, "fcntl(1) on socket"); + netcam_disconnect(netcam); + return -1; + } - /* If the return code is anything except 0, error on connect */ - if (ret) { - if (!err_flag) - motion_log(LOG_ERR, 1, "connect returned error"); - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (3)"); - netcam_disconnect(netcam); - return -1; - } + /* Set the socket non-blocking */ + if (fcntl(netcam->sock, F_SETFL, saveflags | O_NONBLOCK) < 0) { + motion_log(LOG_ERR, 1, "fcntl(2) on socket"); + netcam_disconnect(netcam); + return -1; + } - /* The socket info is stored in the rbuf structure of our context */ - rbuf_initialize(netcam); + /* Now the connect call will return immediately */ + ret = connect(netcam->sock, (struct sockaddr *) &server, + sizeof(server)); + back_err = errno; /* save the errno from connect */ - return 0; /* success */ + /* If the connect failed with anything except EINPROGRESS, error */ + if ((ret < 0) && (back_err != EINPROGRESS)) { + if (!err_flag) + motion_log(LOG_ERR, 1, "connect() failed (%d)", back_err); + + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (4)"); + + netcam_disconnect(netcam); + return -1; + } + + /* Now we do a 'select' with timeout to wait for the connect */ + FD_ZERO(&fd_w); + FD_SET(netcam->sock, &fd_w); + selecttime.tv_sec = CONNECT_TIMEOUT; + selecttime.tv_usec = 0; + ret = select(FD_SETSIZE, NULL, &fd_w, NULL, &selecttime); + + if (ret == 0) { /* 0 means timeout */ + if (!err_flag) + motion_log(LOG_ERR, 0, "timeout on connect()"); + + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (2)"); + + netcam_disconnect(netcam); + return -1; + } + + /* + * A +ve value returned from the select (actually, it must be a + * '1' showing 1 fd's changed) shows the select has completed. + * Now we must check the return code from the select. + */ + len = sizeof(ret); + + if (getsockopt(netcam->sock, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { + motion_log(LOG_ERR, 0, "getsockopt after connect"); + netcam_disconnect(netcam); + return -1; + } + + /* If the return code is anything except 0, error on connect */ + if (ret) { + if (!err_flag) + motion_log(LOG_ERR, 1, "connect returned error"); + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_connect disconnecting netcam (3)"); + netcam_disconnect(netcam); + return -1; + } + + /* The socket info is stored in the rbuf structure of our context */ + rbuf_initialize(netcam); + + return 0; /* success */ } @@ -983,16 +998,16 @@ static int netcam_connect(netcam_context_ptr netcam, int err_flag) */ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) { - if ((buff->size - buff->used) >= numbytes) - return; + if ((buff->size - buff->used) >= numbytes) + return; - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "expanding buffer from %d to %d bytes", - (int) buff->size, (int) buff->size + NETCAM_BUFFSIZE); + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "expanding buffer from %d to %d bytes", + (int) buff->size, (int) buff->size + NETCAM_BUFFSIZE); - buff->ptr = myrealloc(buff->ptr, buff->size + NETCAM_BUFFSIZE, - "netcam_check_buf_size"); - buff->size += NETCAM_BUFFSIZE; + buff->ptr = myrealloc(buff->ptr, buff->size + NETCAM_BUFFSIZE, + "netcam_check_buf_size"); + buff->size += NETCAM_BUFFSIZE; } /** @@ -1003,10 +1018,10 @@ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) * * This routine is called under the four variations of two different * conditions: - * 1) Streaming or non-streaming camera - * Note: Keep-Alive is supported for non-streaming cameras, - * if enabled in the netcam's config structure. - * 2) Header does or does not include Content-Length + * 1) Streaming or non-streaming camera + * Note: Keep-Alive is supported for non-streaming cameras, + * if enabled in the netcam's config structure. + * 2) Header does or does not include Content-Length * Additionally, if it is a streaming camera, there must always be a * boundary-string. * @@ -1020,27 +1035,27 @@ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) * acted upon. * * Our algorithm for this will be as follows: - * 1) If a Content-Length is present, set the variable "remaining" - * to be equal to that value, else set it to a "very large" - * number. - * 2) While there is more data available from the camera: - * a) If there is a "boundary string" specified (from the initial - * header): - * i) If the amount of data in the input buffer is less than - * the length of the boundary string, get more data into - * the input buffer (error if failure). - * ii) If the boundary string is found, check how many - * characters remain in the input buffer before the start - * of the boundary string. If that is less than the - * variable "remaining", reset "remaining" to be equal - * to that number. - * b) Try to copy up to "remaining" characters from the input - * buffer into our destination buffer. - * c) If there are no more characters available from the camera, - * exit this loop, else subtract the number of characters - * actually copied from the variable "remaining". - * 3) If Content-Length was present, and "remaining" is not equal - * to zero, generate a warning message for logging. + * 1) If a Content-Length is present, set the variable "remaining" + * to be equal to that value, else set it to a "very large" + * number. + * 2) While there is more data available from the camera: + * a) If there is a "boundary string" specified (from the initial + * header): + * i) If the amount of data in the input buffer is less than + * the length of the boundary string, get more data into + * the input buffer (error if failure). + * ii) If the boundary string is found, check how many + * characters remain in the input buffer before the start + * of the boundary string. If that is less than the + * variable "remaining", reset "remaining" to be equal + * to that number. + * b) Try to copy up to "remaining" characters from the input + * buffer into our destination buffer. + * c) If there are no more characters available from the camera, + * exit this loop, else subtract the number of characters + * actually copied from the variable "remaining". + * 3) If Content-Length was present, and "remaining" is not equal + * to zero, generate a warning message for logging. * * * Parameters: @@ -1052,246 +1067,246 @@ static void netcam_check_buffsize(netcam_buff_ptr buff, size_t numbytes) */ static int netcam_read_html_jpeg(netcam_context_ptr netcam) { - netcam_buff_ptr buffer; - size_t remaining; /* # characters to read */ - size_t maxflush; /* # chars before boundary */ - size_t rem, rlen, ix; /* working vars */ - int retval; - char *ptr, *bptr, *rptr; - netcam_buff *xchg; - struct timeval curtime; - /* - * Initialisation - set our local pointers to the context - * information - */ - buffer = netcam->receiving; - /* Assure the target buffer is empty */ - buffer->used = 0; - /* Prepare for read loop */ - if (buffer->content_length != 0) - remaining = buffer->content_length; - else - remaining = 999999; + netcam_buff_ptr buffer; + size_t remaining; /* # characters to read */ + size_t maxflush; /* # chars before boundary */ + size_t rem, rlen, ix; /* working vars */ + int retval; + char *ptr, *bptr, *rptr; + netcam_buff *xchg; + struct timeval curtime; + /* + * Initialisation - set our local pointers to the context + * information + */ + buffer = netcam->receiving; + /* Assure the target buffer is empty */ + buffer->used = 0; + /* Prepare for read loop */ + if (buffer->content_length != 0) + remaining = buffer->content_length; + else + remaining = 999999; - /* Now read in the data */ - while (remaining) { - /* Assure data in input buffer */ - if (netcam->response->buffer_left <= 0) { - retval = rbuf_read_bufferful(netcam); + /* Now read in the data */ + while (remaining) { + /* Assure data in input buffer */ + if (netcam->response->buffer_left <= 0) { + retval = rbuf_read_bufferful(netcam); - if (retval <= 0) - break; + if (retval <= 0) + break; - netcam->response->buffer_left = retval; - netcam->response->buffer_pos = netcam->response->buffer; - } + netcam->response->buffer_left = retval; + netcam->response->buffer_pos = netcam->response->buffer; + } - /* If a boundary string is present, take it into account */ - bptr = netcam->boundary; + /* If a boundary string is present, take it into account */ + bptr = netcam->boundary; - if (bptr) { - rptr = netcam->response->buffer_pos; - rlen = netcam->response->buffer_left; + if (bptr) { + rptr = netcam->response->buffer_pos; + rlen = netcam->response->buffer_left; - /* Loop through buffer looking for start of boundary */ - while (1) { - /* - * Logic gets a little complicated here. The - * problem is that we are reading in input - * data in packets, and there is a (small) - * chance that the boundary string could be - * split across successive packets. - * First a quick check if the string *might* - * be in the current buffer. - */ - if (rlen > remaining) - rlen = remaining; + /* Loop through buffer looking for start of boundary */ + while (1) { + /* + * Logic gets a little complicated here. The + * problem is that we are reading in input + * data in packets, and there is a (small) + * chance that the boundary string could be + * split across successive packets. + * First a quick check if the string *might* + * be in the current buffer. + */ + if (rlen > remaining) + rlen = remaining; - if (remaining < netcam->boundary_length) - break; + if (remaining < netcam->boundary_length) + break; - if ((ptr = memchr(rptr, *bptr, rlen)) == NULL) - /* boundary not here (normal path) */ - break; - /* - * At least the first char was found in the - * buffer - check for the rest - */ - rem = rlen - (ptr - rptr); - for (ix = 1; (ix < rem) && (ix < netcam->boundary_length); ix++) { - if (ptr[ix] != bptr[ix]) - break; - } + if ((ptr = memchr(rptr, *bptr, rlen)) == NULL) + /* boundary not here (normal path) */ + break; + /* + * At least the first char was found in the + * buffer - check for the rest + */ + rem = rlen - (ptr - rptr); + for (ix = 1; (ix < rem) && (ix < netcam->boundary_length); ix++) { + if (ptr[ix] != bptr[ix]) + break; + } - if ((ix != netcam->boundary_length) && (ix != rem)) { - /* - * Not pointing at a boundary string - - * step along input - */ - ix = ptr - rptr + 1; - rptr += ix; - rlen -= ix; + if ((ix != netcam->boundary_length) && (ix != rem)) { + /* + * Not pointing at a boundary string - + * step along input + */ + ix = ptr - rptr + 1; + rptr += ix; + rlen -= ix; - if (rlen <= 0) - /* boundary not in buffer - go copy out - */ - break; - /* - * not yet decided - continue - * through input - */ - continue; - } - /* - * If we finish the 'for' with - * ix == boundary_length, that means we found - * the string, and should copy any data which - * precedes it into the target buffer, then - * exit the main loop. - */ - if (ix == netcam->boundary_length) { - if ((ptr - netcam->response->buffer) < (int) remaining) - remaining = ptr - netcam->response->buffer; + if (rlen <= 0) + /* boundary not in buffer - go copy out + */ + break; + /* + * not yet decided - continue + * through input + */ + continue; + } + /* + * If we finish the 'for' with + * ix == boundary_length, that means we found + * the string, and should copy any data which + * precedes it into the target buffer, then + * exit the main loop. + */ + if (ix == netcam->boundary_length) { + if ((ptr - netcam->response->buffer) < (int) remaining) + remaining = ptr - netcam->response->buffer; - /* go copy everything up to boundary */ - break; - } + /* go copy everything up to boundary */ + break; + } - /* - * If not, and ix == rem, that means we reached - * the end of the input buffer in the middle of - * our check, which is the (somewhat messy) - * problem mentioned above. - * - * Assure there is data before potential - * boundary string - */ - if (ptr != netcam->response->buffer) { - /* - * We have a boundary string crossing - * packets :-(. We will copy all the - * data up to the beginning of the - * potential boundary, then re-position - * the (partial) string to the - * beginning and get some more input - * data. First we flush the input - * buffer up to the beginning of the - * (potential) boundary string - */ - ix = ptr - netcam->response->buffer_pos; - netcam_check_buffsize(buffer, ix); - retval = rbuf_flush(netcam, buffer->ptr + buffer->used, ix); - buffer->used += retval; - remaining -= retval; + /* + * If not, and ix == rem, that means we reached + * the end of the input buffer in the middle of + * our check, which is the (somewhat messy) + * problem mentioned above. + * + * Assure there is data before potential + * boundary string + */ + if (ptr != netcam->response->buffer) { + /* + * We have a boundary string crossing + * packets :-(. We will copy all the + * data up to the beginning of the + * potential boundary, then re-position + * the (partial) string to the + * beginning and get some more input + * data. First we flush the input + * buffer up to the beginning of the + * (potential) boundary string + */ + ix = ptr - netcam->response->buffer_pos; + netcam_check_buffsize(buffer, ix); + retval = rbuf_flush(netcam, buffer->ptr + buffer->used, ix); + buffer->used += retval; + remaining -= retval; - /* - * Now move the boundary fragment to - * the head of the input buffer. - * This is really a "hack" - ideally, - * we should have a function within the - * module netcam_wget.c to do this job! - */ + /* + * Now move the boundary fragment to + * the head of the input buffer. + * This is really a "hack" - ideally, + * we should have a function within the + * module netcam_wget.c to do this job! + */ - if (debug_level > CAMERA_INFO) { - motion_log(-1, 0, - "Potential split boundary - " - "%d chars flushed, %d " - "re-positioned", ix, - (int) netcam->response->buffer_left); - } + if (debug_level > CAMERA_INFO) { + motion_log(-1, 0, + "Potential split boundary - " + "%d chars flushed, %d " + "re-positioned", ix, + (int) netcam->response->buffer_left); + } - memmove(netcam->response->buffer, ptr, - netcam->response->buffer_left); - } /* end of boundary split over buffer */ + memmove(netcam->response->buffer, ptr, + netcam->response->buffer_left); + } /* end of boundary split over buffer */ - retval = netcam_recv(netcam, netcam->response->buffer + - netcam->response->buffer_left, - sizeof(netcam->response->buffer) - - netcam->response->buffer_left); + retval = netcam_recv(netcam, netcam->response->buffer + + netcam->response->buffer_left, + sizeof(netcam->response->buffer) - + netcam->response->buffer_left); - if (retval <= 0) { /* this is a fatal error */ - motion_log(LOG_ERR, 1, "recv() fail after boundary string"); - return -1; - } + if (retval <= 0) { /* this is a fatal error */ + motion_log(LOG_ERR, 1, "recv() fail after boundary string"); + return -1; + } - /* Reset the input buffer pointers */ - netcam->response->buffer_left = retval + netcam->response->buffer_left; - netcam->response->buffer_pos = netcam->response->buffer; + /* Reset the input buffer pointers */ + netcam->response->buffer_left = retval + netcam->response->buffer_left; + netcam->response->buffer_pos = netcam->response->buffer; - /* This will cause a 'continue' of the main loop */ - bptr = NULL; + /* This will cause a 'continue' of the main loop */ + bptr = NULL; - /* Return to do the boundary compare from the start */ - break; - } /* end of while(1) input buffer search */ + /* Return to do the boundary compare from the start */ + break; + } /* end of while(1) input buffer search */ - /* !bptr shows we're processing split boundary */ - if (!bptr) - continue; - } /* end of if(bptr) */ + /* !bptr shows we're processing split boundary */ + if (!bptr) + continue; + } /* end of if (bptr) */ - /* boundary string not present, so just write out as much data as possible */ - if (remaining) { - maxflush = MINVAL(netcam->response->buffer_left, remaining); - netcam_check_buffsize(buffer, maxflush); - retval = rbuf_flush(netcam, buffer->ptr + buffer->used, maxflush); - buffer->used += retval; - remaining -= retval; - } - } + /* boundary string not present, so just write out as much data as possible */ + if (remaining) { + maxflush = MINVAL(netcam->response->buffer_left, remaining); + netcam_check_buffsize(buffer, maxflush); + retval = rbuf_flush(netcam, buffer->ptr + buffer->used, maxflush); + buffer->used += retval; + remaining -= retval; + } + } - /* - * read is complete - set the current 'receiving' buffer atomically - * as 'latest', and make the buffer previously in 'latest' become - * the new 'receiving' - */ - if (gettimeofday(&curtime, NULL) < 0) { - motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); - } + /* + * read is complete - set the current 'receiving' buffer atomically + * as 'latest', and make the buffer previously in 'latest' become + * the new 'receiving' + */ + if (gettimeofday(&curtime, NULL) < 0) + motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); + - netcam->receiving->image_time = curtime; + netcam->receiving->image_time = curtime; - /* - * Calculate our "running average" time for this netcam's - * frame transmissions (except for the first time). - * Note that the average frame time is held in microseconds. - */ - if (netcam->last_image.tv_sec) { - netcam->av_frame_time = (9.0 * netcam->av_frame_time + - 1000000.0 * (curtime.tv_sec - netcam->last_image.tv_sec) + - (curtime.tv_usec- netcam->last_image.tv_usec)) / 10.0; + /* + * Calculate our "running average" time for this netcam's + * frame transmissions (except for the first time). + * Note that the average frame time is held in microseconds. + */ + if (netcam->last_image.tv_sec) { + netcam->av_frame_time = (9.0 * netcam->av_frame_time + + 1000000.0 * (curtime.tv_sec - netcam->last_image.tv_sec) + + (curtime.tv_usec- netcam->last_image.tv_usec)) / 10.0; - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); - } - netcam->last_image = curtime; + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); + } + netcam->last_image = curtime; - pthread_mutex_lock(&netcam->mutex); + pthread_mutex_lock(&netcam->mutex); - xchg = netcam->latest; - netcam->latest = netcam->receiving; - netcam->receiving = xchg; - netcam->imgcnt++; - /* - * We have a new frame ready. We send a signal so that - * any thread (e.g. the motion main loop) waiting for the - * next frame to become available may proceed. - */ - pthread_cond_signal(&netcam->pic_ready); + xchg = netcam->latest; + netcam->latest = netcam->receiving; + netcam->receiving = xchg; + netcam->imgcnt++; + /* + * We have a new frame ready. We send a signal so that + * any thread (e.g. the motion main loop) waiting for the + * next frame to become available may proceed. + */ + pthread_cond_signal(&netcam->pic_ready); - pthread_mutex_unlock(&netcam->mutex); + pthread_mutex_unlock(&netcam->mutex); - if (!netcam->caps.streaming) { - if (!netcam->connect_keepalive) { - if (debug_level > CAMERA_INFO ) - motion_log(LOG_DEBUG, 0, "netcam_read_html_jpeg disconnecting netcam since keep-alive not set." ); - netcam_disconnect(netcam); - } else if (debug_level > CAMERA_INFO ) { - motion_log(LOG_DEBUG, 0, "netcam_read_html_jpeg leaving netcam connected." ); - } - } + if (!netcam->caps.streaming) { + if (!netcam->connect_keepalive) { + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "netcam_read_html_jpeg disconnecting netcam since keep-alive not set." ); + netcam_disconnect(netcam); + } else if (debug_level > CAMERA_INFO) { + motion_log(LOG_DEBUG, 0, "netcam_read_html_jpeg leaving netcam connected." ); + } + } - return 0; + return 0; } /** @@ -1304,78 +1319,78 @@ static int netcam_read_html_jpeg(netcam_context_ptr netcam) */ static int netcam_read_ftp_jpeg(netcam_context_ptr netcam) { - netcam_buff_ptr buffer; - int len; - netcam_buff *xchg; - struct timeval curtime; + netcam_buff_ptr buffer; + int len; + netcam_buff *xchg; + struct timeval curtime; - /* Point to our working buffer */ - buffer = netcam->receiving; - buffer->used = 0; + /* Point to our working buffer */ + buffer = netcam->receiving; + buffer->used = 0; - /* Request the image from the remote server */ - if (ftp_get_socket(netcam->ftp) <= 0) { - motion_log(LOG_ERR, 0, "ftp_get_socket failed in netcam_read_jpeg"); - return -1; - } + /* Request the image from the remote server */ + if (ftp_get_socket(netcam->ftp) <= 0) { + motion_log(LOG_ERR, 0, "ftp_get_socket failed in netcam_read_jpeg"); + return -1; + } - /* Now fetch the image using ftp_read. Note this is a blocking call */ - do { - /* Assure there's enough room in the buffer */ - netcam_check_buffsize(buffer, FTP_BUF_SIZE); + /* Now fetch the image using ftp_read. Note this is a blocking call */ + do { + /* Assure there's enough room in the buffer */ + netcam_check_buffsize(buffer, FTP_BUF_SIZE); - /* Do the read */ - if ((len = ftp_read(netcam->ftp, buffer->ptr + buffer->used, FTP_BUF_SIZE)) < 0) - return -1; + /* Do the read */ + if ((len = ftp_read(netcam->ftp, buffer->ptr + buffer->used, FTP_BUF_SIZE)) < 0) + return -1; - buffer->used += len; - } while (len > 0); + buffer->used += len; + } while (len > 0); - if (gettimeofday(&curtime, NULL) < 0) { - motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); - } + if (gettimeofday(&curtime, NULL) < 0) + motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); + - netcam->receiving->image_time = curtime; - /* - * Calculate our "running average" time for this netcam's - * frame transmissions (except for the first time). - * Note that the average frame time is held in microseconds. - */ - if (netcam->last_image.tv_sec) { - netcam->av_frame_time = - ((9.0 * netcam->av_frame_time) + 1000000.0 * - (curtime.tv_sec - netcam->last_image.tv_sec) + - (curtime.tv_usec- netcam->last_image.tv_usec)) - / 10.0; + netcam->receiving->image_time = curtime; + /* + * Calculate our "running average" time for this netcam's + * frame transmissions (except for the first time). + * Note that the average frame time is held in microseconds. + */ + if (netcam->last_image.tv_sec) { + netcam->av_frame_time = + ((9.0 * netcam->av_frame_time) + 1000000.0 * + (curtime.tv_sec - netcam->last_image.tv_sec) + + (curtime.tv_usec- netcam->last_image.tv_usec)) + / 10.0; - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); - } + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); + } - netcam->last_image = curtime; + netcam->last_image = curtime; - /* - * read is complete - set the current 'receiving' buffer atomically - * as 'latest', and make the buffer previously in 'latest' become - * the new 'receiving' - */ - pthread_mutex_lock(&netcam->mutex); + /* + * read is complete - set the current 'receiving' buffer atomically + * as 'latest', and make the buffer previously in 'latest' become + * the new 'receiving' + */ + pthread_mutex_lock(&netcam->mutex); - xchg = netcam->latest; - netcam->latest = netcam->receiving; - netcam->receiving = xchg; - netcam->imgcnt++; + xchg = netcam->latest; + netcam->latest = netcam->receiving; + netcam->receiving = xchg; + netcam->imgcnt++; - /* - * We have a new frame ready. We send a signal so that - * any thread (e.g. the motion main loop) waiting for the - * next frame to become available may proceed. - */ - pthread_cond_signal(&netcam->pic_ready); + /* + * We have a new frame ready. We send a signal so that + * any thread (e.g. the motion main loop) waiting for the + * next frame to become available may proceed. + */ + pthread_cond_signal(&netcam->pic_ready); - pthread_mutex_unlock(&netcam->mutex); + pthread_mutex_unlock(&netcam->mutex); - return 0; + return 0; } @@ -1389,170 +1404,173 @@ static int netcam_read_ftp_jpeg(netcam_context_ptr netcam) */ static int netcam_read_file_jpeg(netcam_context_ptr netcam) { - int loop_counter=0; - if (debug_level > CAMERA_VERBOSE) { - motion_log(-1,0,"Begin %s", __FUNCTION__); - } - netcam_buff_ptr buffer; - int len; - netcam_buff *xchg; - struct timeval curtime; - struct stat statbuf; + int loop_counter=0; - /* Point to our working buffer */ - buffer = netcam->receiving; - buffer->used = 0; + if (debug_level > CAMERA_VERBOSE) + motion_log(-1,0,"Begin %s", __FUNCTION__); + + netcam_buff_ptr buffer; + int len; + netcam_buff *xchg; + struct timeval curtime; + struct stat statbuf; - /*int fstat(int filedes, struct stat *buf);*/ - do { + /* Point to our working buffer */ + buffer = netcam->receiving; + buffer->used = 0; - if( stat( netcam->file->path, &statbuf) ) { - motion_log(-1, 0, "stat(%s) error", netcam->file->path ); - return -1; - } - - if (debug_level > CAMERA_VERBOSE) { - motion_log(-1, 0, "statbuf.st_mtime[%d] != last_st_mtime[%d]", statbuf.st_mtime, netcam->file->last_st_mtime); - } + /*int fstat(int filedes, struct stat *buf);*/ + do { - if( loop_counter>((POLLING_TIMEOUT*1000*1000)/(POLLING_TIME/1000)) ) { //its waits POLLING_TIMEOUT - motion_log(-1, 0, "waiting new file image timeout" ); - return -1; - } + if (stat( netcam->file->path, &statbuf)) { + motion_log(-1, 0, "stat(%s) error", netcam->file->path ); + return -1; + } + + if (debug_level > CAMERA_VERBOSE) { + motion_log(-1, 0, "statbuf.st_mtime[%d] != last_st_mtime[%d]", statbuf.st_mtime, netcam->file->last_st_mtime); + } - if (debug_level > CAMERA_VERBOSE) { - motion_log(-1, 0, "delay waiting new file image "); - } + if (loop_counter>((POLLING_TIMEOUT*1000*1000)/(POLLING_TIME/1000))) { //its waits POLLING_TIMEOUT + motion_log(-1, 0, "waiting new file image timeout" ); + return -1; + } - //SLEEP(netcam->timeout.tv_sec, netcam->timeout.tv_usec*1000 ); //its waits 5seconds - READ_TIMEOUT - SLEEP( 0, POLLING_TIME ); // its waits 500ms - /*return -1;*/ - loop_counter++; + if (debug_level > CAMERA_VERBOSE) { + motion_log(-1, 0, "delay waiting new file image "); + } - } while(statbuf.st_mtime==netcam->file->last_st_mtime); + //SLEEP(netcam->timeout.tv_sec, netcam->timeout.tv_usec*1000 ); //its waits 5seconds - READ_TIMEOUT + SLEEP( 0, POLLING_TIME ); // its waits 500ms + /*return -1;*/ + loop_counter++; - netcam->file->last_st_mtime = statbuf.st_mtime; - if (debug_level > CAMERA_INFO) { - motion_log(LOG_INFO, 0, "processing new file image - st_mtime " - "%d", netcam->file->last_st_mtime ); - } + } while(statbuf.st_mtime==netcam->file->last_st_mtime); - /* Assure there's enough room in the buffer */ - while( buffer->size < (size_t)statbuf.st_size ) { - netcam_check_buffsize(buffer, statbuf.st_size ); - } + netcam->file->last_st_mtime = statbuf.st_mtime; + if (debug_level > CAMERA_INFO) + motion_log(LOG_INFO, 0, "processing new file image - st_mtime " + "%d", netcam->file->last_st_mtime ); + - /* Do the read */ - netcam->file->control_file_desc = open( netcam->file->path, O_RDONLY ); - if( netcam->file->control_file_desc < 0 ) { - motion_log(-1, 0, "open(%s) error:%d", netcam->file->path, netcam->file->control_file_desc ); - return -1; - } + /* Assure there's enough room in the buffer */ + while (buffer->size < (size_t)statbuf.st_size) + netcam_check_buffsize(buffer, statbuf.st_size); + - if ((len = read(netcam->file->control_file_desc, buffer->ptr + buffer->used, statbuf.st_size)) < 0) { - motion_log(-1, 0, "read(%s) error:%d", netcam->file->control_file_desc, len ); - return -1; - } + /* Do the read */ + netcam->file->control_file_desc = open( netcam->file->path, O_RDONLY); - buffer->used += len; + if (netcam->file->control_file_desc < 0) { + motion_log(-1, 0, "open(%s) error:%d", netcam->file->path, netcam->file->control_file_desc); + return -1; + } - close( netcam->file->control_file_desc ); + if ((len = read(netcam->file->control_file_desc, buffer->ptr + buffer->used, statbuf.st_size)) < 0) { + motion_log(-1, 0, "read(%s) error:%d", netcam->file->control_file_desc, len ); + return -1; + } - if (gettimeofday(&curtime, NULL) < 0) { - motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); - } + buffer->used += len; - netcam->receiving->image_time = curtime; - /* - * Calculate our "running average" time for this netcam's - * frame transmissions (except for the first time). - * Note that the average frame time is held in microseconds. - */ - if (netcam->last_image.tv_sec) { - netcam->av_frame_time = - ((9.0 * netcam->av_frame_time) + 1000000.0 * - (curtime.tv_sec - netcam->last_image.tv_sec) + - (curtime.tv_usec- netcam->last_image.tv_usec)) - / 10.0; - - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); - } + close( netcam->file->control_file_desc ); - netcam->last_image = curtime; + if (gettimeofday(&curtime, NULL) < 0) + motion_log(LOG_ERR, 1, "gettimeofday in netcam_read_jpeg"); + - /* - * read is complete - set the current 'receiving' buffer atomically - * as 'latest', and make the buffer previously in 'latest' become - * the new 'receiving' - */ - pthread_mutex_lock(&netcam->mutex); + netcam->receiving->image_time = curtime; + /* + * Calculate our "running average" time for this netcam's + * frame transmissions (except for the first time). + * Note that the average frame time is held in microseconds. + */ + if (netcam->last_image.tv_sec) { + netcam->av_frame_time = + ((9.0 * netcam->av_frame_time) + 1000000.0 * + (curtime.tv_sec - netcam->last_image.tv_sec) + + (curtime.tv_usec- netcam->last_image.tv_usec)) / 10.0; + + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "Calculated frame time %f", netcam->av_frame_time); + } - xchg = netcam->latest; - netcam->latest = netcam->receiving; - netcam->receiving = xchg; - netcam->imgcnt++; + netcam->last_image = curtime; - /* - * We have a new frame ready. We send a signal so that - * any thread (e.g. the motion main loop) waiting for the - * next frame to become available may proceed. - */ - pthread_cond_signal(&netcam->pic_ready); + /* + * read is complete - set the current 'receiving' buffer atomically + * as 'latest', and make the buffer previously in 'latest' become + * the new 'receiving' + */ + pthread_mutex_lock(&netcam->mutex); - pthread_mutex_unlock(&netcam->mutex); + xchg = netcam->latest; + netcam->latest = netcam->receiving; + netcam->receiving = xchg; + netcam->imgcnt++; - if (debug_level > CAMERA_VERBOSE) { - motion_log(-1,0,"End %s", __FUNCTION__); - } - return 0; + /* + * We have a new frame ready. We send a signal so that + * any thread (e.g. the motion main loop) waiting for the + * next frame to become available may proceed. + */ + pthread_cond_signal(&netcam->pic_ready); + + pthread_mutex_unlock(&netcam->mutex); + + if (debug_level > CAMERA_VERBOSE) + motion_log(-1,0,"End %s", __FUNCTION__); + + return 0; } -tfile_context *file_new_context(void) { - tfile_context *ret; +tfile_context *file_new_context(void) +{ + tfile_context *ret; - /* note that mymalloc will exit on any problem */ - ret = mymalloc(sizeof(tfile_context)); - if (!ret) - return ret; + /* note that mymalloc will exit on any problem */ + ret = mymalloc(sizeof(tfile_context)); + if (!ret) + return ret; - memset(ret, 0, sizeof(tfile_context)); - return ret; + memset(ret, 0, sizeof(tfile_context)); + return ret; } void file_free_context(tfile_context* ctxt) { - if (ctxt == NULL) - return; + if (ctxt == NULL) + return; - if (ctxt->path != NULL) - free(ctxt->path); + if (ctxt->path != NULL) + free(ctxt->path); - free(ctxt); + free(ctxt); } -static int netcam_setup_file(netcam_context_ptr netcam, struct url_t *url) { +static int netcam_setup_file(netcam_context_ptr netcam, struct url_t *url) +{ - if ((netcam->file = file_new_context()) == NULL) - return -1; + if ((netcam->file = file_new_context()) == NULL) + return -1; - /* - * We copy the strings out of the url structure into the ftp_context - * structure. By setting url->{string} to NULL we effectively "take - * ownership" of the string away from the URL (i.e. it won't be freed - * when we cleanup the url structure later). - */ - netcam->file->path = url->path; - url->path = NULL; + /* + * We copy the strings out of the url structure into the ftp_context + * structure. By setting url->{string} to NULL we effectively "take + * ownership" of the string away from the URL (i.e. it won't be freed + * when we cleanup the url structure later). + */ + netcam->file->path = url->path; + url->path = NULL; - if (debug_level > CAMERA_INFO) - motion_log(LOG_INFO, 0, "netcam_setup_file: netcam->file->path %s",netcam->file->path); + if (debug_level > CAMERA_INFO) + motion_log(LOG_INFO, 0, "netcam_setup_file: netcam->file->path %s",netcam->file->path); - netcam_url_free(url); + netcam_url_free(url); - netcam->get_image = netcam_read_file_jpeg; + netcam->get_image = netcam_read_file_jpeg; - return 0; + return 0; } /** @@ -1569,431 +1587,437 @@ static int netcam_setup_file(netcam_context_ptr netcam, struct url_t *url) { */ static void *netcam_handler_loop(void *arg) { - int retval; - int open_error = 0; - netcam_context_ptr netcam = arg; - struct context *cnt = netcam->cnt; /* needed for the SETUP macro :-( */ + int retval; + int open_error = 0; + netcam_context_ptr netcam = arg; + struct context *cnt = netcam->cnt; /* needed for the SETUP macro :-( */ - /* Store the corresponding motion thread number in TLS also for this - * thread (necessary for 'motion_log' to function properly). - */ - pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr)); + /* Store the corresponding motion thread number in TLS also for this + * thread (necessary for 'motion_log' to function properly). + */ + pthread_setspecific(tls_key_threadnr, (void *)((unsigned long)cnt->threadnr)); - if (SETUP) - motion_log(LOG_INFO, 0, "Camera handler thread [%d] started", netcam->threadnr); + if (SETUP) + motion_log(LOG_INFO, 0, "Camera handler thread [%d] started", netcam->threadnr); - /* - * The logic of our loop is very simple. If this is a non- - * streaming camera, we re-establish connection with the camera - * and read the header record. If it's a streaming camera, we - * position to the next "boundary string" in the input stream. - * In either case, we then read the following JPEG image into the - * next available buffer, updating the "next" and "latest" indices - * in our netcam * structure. The loop continues until netcam->finish - * or cnt->finish is set. - */ + /* + * The logic of our loop is very simple. If this is a non- + * streaming camera, we re-establish connection with the camera + * and read the header record. If it's a streaming camera, we + * position to the next "boundary string" in the input stream. + * In either case, we then read the following JPEG image into the + * next available buffer, updating the "next" and "latest" indices + * in our netcam * structure. The loop continues until netcam->finish + * or cnt->finish is set. + */ - while (!netcam->finish) { - if (netcam->response) { /* if html input */ - if (!netcam->caps.streaming) { - /* Non-streaming ie. jpeg */ - if (!netcam->connect_keepalive || (netcam->connect_keepalive && netcam->keepalive_timeup)) { - /* If keepalive flag set but time up, time to close this socket */ - if (netcam->connect_keepalive && netcam->keepalive_timeup) { - motion_log(LOG_INFO, 0, "Closing netcam socket as Keep-Alive time is up " - "(camera sent Close field). A reconnect should happen."); - netcam_disconnect(netcam); - netcam->keepalive_timeup = FALSE; - } - /* And the netcam_connect call below will open a new one */ - if (netcam_connect(netcam, open_error) < 0) { - if (!open_error) { /* log first error */ - motion_log(LOG_ERR, 0, - "re-opening camera (non-streaming)"); - open_error = 1; - } - /* need to have a dynamic delay here */ - SLEEP(5,0); - continue; - } - if (open_error) { /* log re-connection */ - motion_log(LOG_ERR, 0, - "camera re-connected"); - open_error = 0; - } - } - /* Send our request and look at the response */ - if ((retval = netcam_read_first_header(netcam)) != 1) { - if (retval > 0) { - motion_log(LOG_ERR, 0, - "Unrecognized image header (%d)", retval); - } else if (retval != -1) { - motion_log(LOG_ERR, 0, - "Error in header (%d)", retval); - } - /* need to have a dynamic delay here */ - continue; - } - } else { /* Streaming */ - if (netcam_read_next_header(netcam) < 0) { - if (netcam_connect(netcam, open_error) < 0) { - if (!open_error) { /* log first error */ - motion_log(LOG_ERR, 0, - "re-opening camera (streaming)"); - open_error = 1; - } - SLEEP(5,0); - continue; - } + while (!netcam->finish) { + if (netcam->response) { /* if html input */ + if (!netcam->caps.streaming) { + /* Non-streaming ie. jpeg */ + if (!netcam->connect_keepalive || (netcam->connect_keepalive && netcam->keepalive_timeup)) { + /* If keepalive flag set but time up, time to close this socket */ + if (netcam->connect_keepalive && netcam->keepalive_timeup) { + motion_log(LOG_INFO, 0, "Closing netcam socket as Keep-Alive time is up " + "(camera sent Close field). A reconnect should happen."); + netcam_disconnect(netcam); + netcam->keepalive_timeup = FALSE; + } - if ((retval = netcam_read_first_header(netcam) != 2)) { - if (retval > 0) { - motion_log(LOG_ERR, 0, - "Unrecognized image header (%d)", - retval); - } else if (retval != -1) { - motion_log(LOG_ERR, 0, - "Error in header (%d)", retval); - } - /* FIXME need some limit */ - continue; - } - } - if (open_error) { /* log re-connection */ - motion_log(LOG_ERR, 0, - "camera re-connected"); - open_error = 0; - } - } - } - if (netcam->get_image(netcam) < 0) { - motion_log(LOG_ERR, 0, "Error getting jpeg image"); - /* if FTP connection, attempt to re-connect to server */ - if (netcam->ftp) { - close(netcam->ftp->control_file_desc); - if (ftp_connect(netcam) < 0) { - motion_log(LOG_ERR, 0, "Trying to re-connect"); - } - } - continue; - } - /* - * FIXME - * Need to check whether the image was received / decoded - * satisfactorily - */ + /* And the netcam_connect call below will open a new one */ + if (netcam_connect(netcam, open_error) < 0) { + if (!open_error) { /* log first error */ + motion_log(LOG_ERR, 0, + "re-opening camera (non-streaming)"); + open_error = 1; + } + /* need to have a dynamic delay here */ + SLEEP(5,0); + continue; + } - /* - * If non-streaming, want to synchronize our thread with the - * motion main-loop. - */ - if (!netcam->caps.streaming) { - pthread_mutex_lock(&netcam->mutex); + if (open_error) { /* log re-connection */ + motion_log(LOG_ERR, 0, + "camera re-connected"); + open_error = 0; + } + } + /* Send our request and look at the response */ + if ((retval = netcam_read_first_header(netcam)) != 1) { + if (retval > 0) { + motion_log(LOG_ERR, 0, + "Unrecognized image header (%d)", retval); + } else if (retval != -1) { + motion_log(LOG_ERR, 0, + "Error in header (%d)", retval); + } + /* need to have a dynamic delay here */ + continue; + } + } else { /* Streaming */ + if (netcam_read_next_header(netcam) < 0) { + if (netcam_connect(netcam, open_error) < 0) { + if (!open_error) { /* log first error */ + motion_log(LOG_ERR, 0, + "re-opening camera (streaming)"); + open_error = 1; + } + SLEEP(5,0); + continue; + } - /* before anything else, check for system shutdown */ - if (netcam->finish) { - pthread_mutex_unlock(&netcam->mutex); - break; - } + if ((retval = netcam_read_first_header(netcam) != 2)) { + if (retval > 0) { + motion_log(LOG_ERR, 0, + "Unrecognized image header (%d)", + retval); + } else if (retval != -1) { + motion_log(LOG_ERR, 0, + "Error in header (%d)", retval); + } + /* FIXME need some limit */ + continue; + } + } + if (open_error) { /* log re-connection */ + motion_log(LOG_ERR, 0, + "camera re-connected"); + open_error = 0; + } + } + } + if (netcam->get_image(netcam) < 0) { + motion_log(LOG_ERR, 0, "Error getting jpeg image"); + /* if FTP connection, attempt to re-connect to server */ + if (netcam->ftp) { + close(netcam->ftp->control_file_desc); + if (ftp_connect(netcam) < 0) + motion_log(LOG_ERR, 0, "Trying to re-connect"); + + } + continue; + } + /* + * FIXME + * Need to check whether the image was received / decoded + * satisfactorily + */ - /* - * If our current loop has finished before the next - * request from the motion main-loop, we do a - * conditional wait (wait for signal). On the other - * hand, if the motion main-loop has already signalled - * us, we just continue. In either event, we clear - * the start_capture flag set by the main loop. - */ - if (!netcam->start_capture) - pthread_cond_wait(&netcam->cap_cond, &netcam->mutex); + /* + * If non-streaming, want to synchronize our thread with the + * motion main-loop. + */ + if (!netcam->caps.streaming) { + pthread_mutex_lock(&netcam->mutex); - netcam->start_capture = 0; + /* before anything else, check for system shutdown */ + if (netcam->finish) { + pthread_mutex_unlock(&netcam->mutex); + break; + } - pthread_mutex_unlock(&netcam->mutex); - } - /* the loop continues forever, or until motion shutdown */ - } + /* + * If our current loop has finished before the next + * request from the motion main-loop, we do a + * conditional wait (wait for signal). On the other + * hand, if the motion main-loop has already signalled + * us, we just continue. In either event, we clear + * the start_capture flag set by the main loop. + */ + if (!netcam->start_capture) + pthread_cond_wait(&netcam->cap_cond, &netcam->mutex); - /* our thread is finished - decrement motion's thread count */ - pthread_mutex_lock(&global_lock); - threads_running--; - pthread_mutex_unlock(&global_lock); + netcam->start_capture = 0; - /* log out a termination message */ - motion_log(LOG_INFO, 0, "netcam camera handler: finish set, exiting"); + pthread_mutex_unlock(&netcam->mutex); + } + /* the loop continues forever, or until motion shutdown */ + } - /* setting netcam->thread_id to zero shows netcam_cleanup we're done */ - netcam->thread_id = 0; + /* our thread is finished - decrement motion's thread count */ + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); - /* signal netcam_cleanup that we're all done */ - pthread_mutex_lock(&netcam->mutex); - pthread_cond_signal(&netcam->exiting); - pthread_mutex_unlock(&netcam->mutex); + /* log out a termination message */ + motion_log(LOG_INFO, 0, "netcam camera handler: finish set, exiting"); - /* Goodbye..... */ - pthread_exit(NULL); + /* setting netcam->thread_id to zero shows netcam_cleanup we're done */ + netcam->thread_id = 0; + + /* signal netcam_cleanup that we're all done */ + pthread_mutex_lock(&netcam->mutex); + pthread_cond_signal(&netcam->exiting); + pthread_mutex_unlock(&netcam->mutex); + + /* Goodbye..... */ + pthread_exit(NULL); } static int netcam_setup_html(netcam_context_ptr netcam, struct url_t *url) { - struct context *cnt = netcam->cnt; - const char *ptr; /* working var */ - char *userpass; /* temp pointer to config value */ - char *encuserpass; /* temp storage for encoded ver */ - char *request_pass = NULL; /* temp storage for base64 conv */ - int ix; + struct context *cnt = netcam->cnt; + const char *ptr; /* working var */ + char *userpass; /* temp pointer to config value */ + char *encuserpass; /* temp storage for encoded ver */ + char *request_pass = NULL; /* temp storage for base64 conv */ + int ix; - /* First the http context structure */ - netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf)); - memset(netcam->response, 0, sizeof(struct rbuf)); + /* First the http context structure */ + netcam->response = (struct rbuf *) mymalloc(sizeof(struct rbuf)); + memset(netcam->response, 0, sizeof(struct rbuf)); - if (debug_level > CAMERA_INFO) - motion_log(LOG_INFO, 0, "netcam_setup_html: Netcam has flags: HTTP1.0: %s HTTP1.1: %s Keep-Alive %s.", - netcam->connect_http_10 ? "1":"0", netcam->connect_http_11 ? "1":"0", - netcam->connect_keepalive ? "ON":"OFF"); + if (debug_level > CAMERA_INFO) + motion_log(LOG_INFO, 0, "netcam_setup_html: Netcam has flags: HTTP1.0: %s HTTP1.1: %s Keep-Alive %s.", + netcam->connect_http_10 ? "1":"0", netcam->connect_http_11 ? "1":"0", + netcam->connect_keepalive ? "ON":"OFF"); - /* - * The network camera may require a username and password. If - * so, the information can come from two different places in the - * motion configuration file. Either it can be present in - * the netcam_userpass, or it can be present as a part of the URL - * for the camera. We assume the first of these has a higher - * relevance. - */ - if (cnt->conf.netcam_userpass) - ptr = cnt->conf.netcam_userpass; - else - ptr = url->userpass; + /* + * The network camera may require a username and password. If + * so, the information can come from two different places in the + * motion configuration file. Either it can be present in + * the netcam_userpass, or it can be present as a part of the URL + * for the camera. We assume the first of these has a higher + * relevance. + */ + if (cnt->conf.netcam_userpass) + ptr = cnt->conf.netcam_userpass; + else + ptr = url->userpass; - /* base64_encode needs up to 3 additional chars */ - if (ptr) { - userpass = mymalloc(strlen(ptr) + 3); - strcpy(userpass, ptr); - } else - userpass = NULL; + /* base64_encode needs up to 3 additional chars */ + if (ptr) { + userpass = mymalloc(strlen(ptr) + 3); + strcpy(userpass, ptr); + } else { + userpass = NULL; + } - /* - * Now we want to create the actual string which will be used to - * connect to the camera. It may or may not contain a username / - * password. We first compose a basic connect message, then check - * if a Keep-Alive header is to be included (or just 'close'), then - * whether a username / password is required and, if so, just - * concatenate it with the request. - * - */ - /* space for final \r\n plus string terminator */ - ix = 3; + /* + * Now we want to create the actual string which will be used to + * connect to the camera. It may or may not contain a username / + * password. We first compose a basic connect message, then check + * if a Keep-Alive header is to be included (or just 'close'), then + * whether a username / password is required and, if so, just + * concatenate it with the request. + * + */ + /* space for final \r\n plus string terminator */ + ix = 3; - /* See if username / password is required */ - if (userpass) { /* if either of the above are non-NULL */ - /* Allocate space for the base64-encoded string */ - encuserpass = mymalloc(BASE64_LENGTH(strlen(userpass)) + 1); - /* Fill in the value */ - base64_encode(userpass, encuserpass, strlen(userpass)); - /* Now create the last part (authorization) of the request */ - request_pass = mymalloc(strlen(connect_auth_req) + - strlen(encuserpass) + 1); - ix += sprintf(request_pass, connect_auth_req, encuserpass); - /* free the working variables */ - free(encuserpass); - } + /* See if username / password is required */ + if (userpass) { /* if either of the above are non-NULL */ + /* Allocate space for the base64-encoded string */ + encuserpass = mymalloc(BASE64_LENGTH(strlen(userpass)) + 1); + /* Fill in the value */ + base64_encode(userpass, encuserpass, strlen(userpass)); + /* Now create the last part (authorization) of the request */ + request_pass = mymalloc(strlen(connect_auth_req) + + strlen(encuserpass) + 1); + ix += sprintf(request_pass, connect_auth_req, encuserpass); + /* free the working variables */ + free(encuserpass); + } - /* - * We are now ready to set up the netcam's "connect request". Most of - * this comes from the (preset) string 'connect_req', but additional - * characters are required if there is a proxy server, or if there is - * a Keep-Alive connection rather than a close connection, or - * a username / password for the camera. The variable 'ix' currently - * has the number of characters required for username/password (which - * could be zero) and for the \r\n and string terminator. We will also - * always need space for the netcam path, and if a proxy is being used - * we also need space for a preceding 'http://{hostname}' for the - * netcam path. - * Note: Keep-Alive (but not HTTP 1.1) is disabled if a proxy URL - * is set, since HTTP 1.0 Keep-alive cannot be transferred through. - */ - if (cnt->conf.netcam_proxy) { - /* - * Allocate space for a working string to contain the path. - * The extra 4 is for "://" and string terminator. - */ - ptr = mymalloc(strlen(url->service) + strlen(url->host) - + strlen(url->path) + 4); - sprintf((char *)ptr, "http://%s%s", url->host, url->path); - netcam->connect_keepalive=0; /* Disable Keepalive if proxy */ - if (debug_level > CAMERA_INFO) - motion_log(LOG_DEBUG, 0, "Removed netcam_keepalive flag due to proxy set." - "Proxy is incompatible with Keep-Alive."); - } else { - /* if no proxy, set as netcam_url path */ - ptr = url->path; - /* - * after generating the connect message the string - * will be freed, so we don't want netcam_url_free - * to free it as well. - */ - url->path = NULL; - } + /* + * We are now ready to set up the netcam's "connect request". Most of + * this comes from the (preset) string 'connect_req', but additional + * characters are required if there is a proxy server, or if there is + * a Keep-Alive connection rather than a close connection, or + * a username / password for the camera. The variable 'ix' currently + * has the number of characters required for username/password (which + * could be zero) and for the \r\n and string terminator. We will also + * always need space for the netcam path, and if a proxy is being used + * we also need space for a preceding 'http://{hostname}' for the + * netcam path. + * Note: Keep-Alive (but not HTTP 1.1) is disabled if a proxy URL + * is set, since HTTP 1.0 Keep-alive cannot be transferred through. + */ + if (cnt->conf.netcam_proxy) { + /* + * Allocate space for a working string to contain the path. + * The extra 4 is for "://" and string terminator. + */ + ptr = mymalloc(strlen(url->service) + strlen(url->host) + + strlen(url->path) + 4); + sprintf((char *)ptr, "http://%s%s", url->host, url->path); + netcam->connect_keepalive=0; /* Disable Keepalive if proxy */ - ix += strlen(ptr); + if (debug_level > CAMERA_INFO) + motion_log(LOG_DEBUG, 0, "Removed netcam_keepalive flag due to proxy set." + "Proxy is incompatible with Keep-Alive."); + } else { + /* if no proxy, set as netcam_url path */ + ptr = url->path; + /* + * after generating the connect message the string + * will be freed, so we don't want netcam_url_free + * to free it as well. + */ + url->path = NULL; + } + + ix += strlen(ptr); /* Now add the required number of characters for the close header * or Keep-Alive header. We test the flag which can be unset if - * there is a problem (rather than the flag in the conf structure - * which is read-only. - */ + * there is a problem (rather than the flag in the conf structure + * which is read-only. + */ - if (netcam->connect_keepalive) { - ix += strlen(connect_req_keepalive); - } else { - ix += strlen(connect_req_close); - } + if (netcam->connect_keepalive) { + ix += strlen(connect_req_keepalive); + } else { + ix += strlen(connect_req_close); + } - /* Point to either the HTTP 1.0 or 1.1 request header set */ - /* If the configuration is anything other than 1.1, use 1.0 */ - /* as a default. This avoids a chance of being left with none */ - if (netcam->connect_http_11==TRUE) - connect_req = connect_req_http11; - else - connect_req = connect_req_http10; + /* Point to either the HTTP 1.0 or 1.1 request header set */ + /* If the configuration is anything other than 1.1, use 1.0 */ + /* as a default. This avoids a chance of being left with none */ + if (netcam->connect_http_11==TRUE) + connect_req = connect_req_http11; + else + connect_req = connect_req_http10; - /* - * Now that we know how much space we need, we can allocate space - * for the connect-request string. - */ - netcam->connect_request = mymalloc(strlen(connect_req) + ix + - strlen(netcam->connect_host)); + /* + * Now that we know how much space we need, we can allocate space + * for the connect-request string. + */ + netcam->connect_request = mymalloc(strlen(connect_req) + ix + + strlen(netcam->connect_host)); - /* Now create the request string with an sprintf */ - sprintf(netcam->connect_request, connect_req, ptr, - netcam->connect_host); + /* Now create the request string with an sprintf */ + sprintf(netcam->connect_request, connect_req, ptr, + netcam->connect_host); - if (netcam->connect_keepalive) { - strcat(netcam->connect_request, connect_req_keepalive); - } else { - strcat(netcam->connect_request, connect_req_close); - } + if (netcam->connect_keepalive) + strcat(netcam->connect_request, connect_req_keepalive); + else + strcat(netcam->connect_request, connect_req_close); + - if (userpass) { - strcat(netcam->connect_request, request_pass); - free(request_pass); - free(userpass); - } + if (userpass) { + strcat(netcam->connect_request, request_pass); + free(request_pass); + free(userpass); + } - /* put on the final CRLF onto the request */ - strcat(netcam->connect_request, "\r\n"); - free((void *)ptr); - netcam_url_free(url); /* Cleanup the url data */ + /* put on the final CRLF onto the request */ + strcat(netcam->connect_request, "\r\n"); + free((void *)ptr); + netcam_url_free(url); /* Cleanup the url data */ - if (debug_level > CAMERA_INFO) { - motion_log(-1, 0, "Camera connect string is ''%s''", netcam->connect_request); - motion_log(-1, 0, "End of camera connect string."); - } + if (debug_level > CAMERA_INFO) { + motion_log(-1, 0, "Camera connect string is ''%s''", netcam->connect_request); + motion_log(-1, 0, "End of camera connect string."); + } - /* - * Our basic initialisation has been completed. Now we will attempt - * to connect with the camera so that we can then get a "header" - * in order to find out what kind of camera we are dealing with, - * as well as what are the picture dimensions. Note that for - * this initial connection, any failure will cause an error - * return from netcam_start (unlike later possible attempts at - * re-connecting, if the network connection is later interrupted). - */ - for (ix = 0; ix < MAX_HEADER_RETRIES; ix++) { - /* - * netcam_connect does an automatic netcam_close, so it's - * safe to include it as part of this loop - * (Not always true now Keep-Alive is implemented) - */ - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "netcam_setup_html: about to try to connect, time #%d", ix ); - if (netcam_connect(netcam, 0) != 0) { - motion_log(LOG_ERR, 0,"Failed to open camera - check your config and that netcamera is online"); + /* + * Our basic initialisation has been completed. Now we will attempt + * to connect with the camera so that we can then get a "header" + * in order to find out what kind of camera we are dealing with, + * as well as what are the picture dimensions. Note that for + * this initial connection, any failure will cause an error + * return from netcam_start (unlike later possible attempts at + * re-connecting, if the network connection is later interrupted). + */ + for (ix = 0; ix < MAX_HEADER_RETRIES; ix++) { + /* + * netcam_connect does an automatic netcam_close, so it's + * safe to include it as part of this loop + * (Not always true now Keep-Alive is implemented) + */ + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "netcam_setup_html: about to try to connect, time #%d", ix); - /* Fatal error on startup */ - ix = MAX_HEADER_RETRIES; - break;; - } + if (netcam_connect(netcam, 0) != 0) { + motion_log(LOG_ERR, 0,"Failed to open camera - check your config and that netcamera is online"); - if (netcam_read_first_header(netcam) >= 0) - break; + /* Fatal error on startup */ + ix = MAX_HEADER_RETRIES; + break;; + } - motion_log(LOG_ERR, 0, "Error reading first header - re-trying"); - } + if (netcam_read_first_header(netcam) >= 0) + break; - if (ix == MAX_HEADER_RETRIES) { - motion_log(LOG_ERR, 0, "Failed to read first camera header - giving up for now"); - return -1; - } + motion_log(LOG_ERR, 0, "Error reading first header - re-trying"); + } - /* - * If this is a streaming camera, we need to position just - * past the boundary string and read the image header - */ - if (netcam->caps.streaming) { - if (netcam_read_next_header(netcam) < 0) { - motion_log(LOG_ERR, 0, - "Failed to read first stream header - giving up for now"); - return -1; - } - } + if (ix == MAX_HEADER_RETRIES) { + motion_log(LOG_ERR, 0, "Failed to read first camera header - giving up for now"); + return -1; + } - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "netcam_setup_html: connected, going on to read image.", ix ); - netcam->get_image = netcam_read_html_jpeg; - return 0; + /* + * If this is a streaming camera, we need to position just + * past the boundary string and read the image header + */ + if (netcam->caps.streaming) { + if (netcam_read_next_header(netcam) < 0) { + motion_log(LOG_ERR, 0, + "Failed to read first stream header - giving up for now"); + return -1; + } + } + + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "netcam_setup_html: connected, going on to read image.", ix ); + + netcam->get_image = netcam_read_html_jpeg; + return 0; } static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) { - struct context *cnt = netcam->cnt; - const char *ptr; + struct context *cnt = netcam->cnt; + const char *ptr; - if ((netcam->ftp = ftp_new_context()) == NULL) - return -1; - /* - * We copy the strings out of the url structure into the ftp_context - * structure. By setting url->{string} to NULL we effectively "take - * ownership" of the string away from the URL (i.e. it won't be freed - * when we cleanup the url structure later). - */ - netcam->ftp->path = url->path; - url->path = NULL; + if ((netcam->ftp = ftp_new_context()) == NULL) + return -1; + /* + * We copy the strings out of the url structure into the ftp_context + * structure. By setting url->{string} to NULL we effectively "take + * ownership" of the string away from the URL (i.e. it won't be freed + * when we cleanup the url structure later). + */ + netcam->ftp->path = url->path; + url->path = NULL; - if (cnt->conf.netcam_userpass != NULL) - ptr = cnt->conf.netcam_userpass; - else { - ptr = url->userpass; /* don't set this one NULL, gets freed */ - } + if (cnt->conf.netcam_userpass != NULL) + ptr = cnt->conf.netcam_userpass; + else + ptr = url->userpass; /* don't set this one NULL, gets freed */ + - if (ptr != NULL) { - char *cptr; + if (ptr != NULL) { + char *cptr; - if ((cptr = strchr(ptr, ':')) == NULL) - netcam->ftp->user = strdup(ptr); - else { - netcam->ftp->user = mymalloc((cptr - ptr)); - memcpy(netcam->ftp->user,ptr,(cptr - ptr)); - netcam->ftp->passwd = strdup(cptr + 1); - } - } + if ((cptr = strchr(ptr, ':')) == NULL) { + netcam->ftp->user = strdup(ptr); + } else { + netcam->ftp->user = mymalloc((cptr - ptr)); + memcpy(netcam->ftp->user,ptr,(cptr - ptr)); + netcam->ftp->passwd = strdup(cptr + 1); + } + } - netcam_url_free(url); + netcam_url_free(url); - /* - * The ftp context should be all ready to attempt a connection with - * the server, so we try .... - */ - if (ftp_connect(netcam) < 0) { - ftp_free_context(netcam->ftp); - return -1; - } + /* + * The ftp context should be all ready to attempt a connection with + * the server, so we try .... + */ + if (ftp_connect(netcam) < 0) { + ftp_free_context(netcam->ftp); + return -1; + } - if (ftp_send_type(netcam->ftp, 'I') < 0) { - motion_log(LOG_ERR, 0, "Error sending TYPE I to ftp server"); - return -1; - } + if (ftp_send_type(netcam->ftp, 'I') < 0) { + motion_log(LOG_ERR, 0, "Error sending TYPE I to ftp server"); + return -1; + } - netcam->get_image = netcam_read_ftp_jpeg; - return 0; + netcam->get_image = netcam_read_ftp_jpeg; + return 0; } /** @@ -2015,20 +2039,19 @@ static int netcam_setup_ftp(netcam_context_ptr netcam, struct url_t *url) { * */ ssize_t netcam_recv(netcam_context_ptr netcam, void *buffptr, size_t buffsize) { - ssize_t retval; - fd_set fd_r; - struct timeval selecttime; + ssize_t retval; + fd_set fd_r; + struct timeval selecttime; - FD_ZERO(&fd_r); - FD_SET(netcam->sock, &fd_r); - selecttime = netcam->timeout; + FD_ZERO(&fd_r); + FD_SET(netcam->sock, &fd_r); + selecttime = netcam->timeout; - retval = select(FD_SETSIZE, &fd_r, NULL, NULL, &selecttime); - if (retval == 0) { /* 0 means timeout */ - return -1; - } - - return recv(netcam->sock, buffptr, buffsize, 0); + retval = select(FD_SETSIZE, &fd_r, NULL, NULL, &selecttime); + if (retval == 0) /* 0 means timeout */ + return -1; + + return recv(netcam->sock, buffptr, buffsize, 0); } /** @@ -2055,132 +2078,130 @@ ssize_t netcam_recv(netcam_context_ptr netcam, void *buffptr, size_t buffsize) { */ void netcam_cleanup(netcam_context_ptr netcam, int init_retry_flag) { - struct timespec waittime; + struct timespec waittime; - if (!netcam) - return; + if (!netcam) + return; - /* - * This 'lock' is just a bit of "defensive" programming. It should - * only be necessary if the routine is being called from different - * threads, but in our Motion design, it should only be called from - * the motion main-loop. - */ - pthread_mutex_lock(&netcam->mutex); + /* + * This 'lock' is just a bit of "defensive" programming. It should + * only be necessary if the routine is being called from different + * threads, but in our Motion design, it should only be called from + * the motion main-loop. + */ + pthread_mutex_lock(&netcam->mutex); - if (netcam->cnt->netcam == NULL) { - return; - } + if (netcam->cnt->netcam == NULL) + return; + + /* + * We set the netcam_context pointer in the motion main-loop context + * to be NULL, so that this routine won't be called a second time + */ + netcam->cnt->netcam = NULL; - /* - * We set the netcam_context pointer in the motion main-loop context - * to be NULL, so that this routine won't be called a second time - */ - netcam->cnt->netcam = NULL; + /* + * Next we set 'finish' in order to get the camera-handler thread + * to stop. + */ + netcam->finish = 1; - /* - * Next we set 'finish' in order to get the camera-handler thread - * to stop. - */ - netcam->finish = 1; + /* + * If the camera is non-streaming, the handler thread could be waiting + * for a signal, so we send it one. If it's actually waiting on the + * condition, it won't actually start yet because we still have + * netcam->mutex locked. + */ - /* - * If the camera is non-streaming, the handler thread could be waiting - * for a signal, so we send it one. If it's actually waiting on the - * condition, it won't actually start yet because we still have - * netcam->mutex locked. - */ + if (!netcam->caps.streaming) + pthread_cond_signal(&netcam->cap_cond); + + /* + * Once the camera-handler gets to the end of it's loop (probably as + * soon as we release netcam->mutex), because netcam->finish has been + * set it will exit it's loop, do anything it needs to do with the + * netcam context, and then send *us* as signal (netcam->exiting). + * Note that when we start our wait on netcam->exiting, our lock on + * netcam->mutex is automatically released, which will allow the + * handler to complete it's loop, notice that 'finish' is set and exit. + * This should always work, but again (defensive programming) we + * use pthread_cond_timedwait and, if our timeout (8 seconds) expires + * we just do the cleanup the handler would normally have done. This + * assures that (even if there is a bug in our code) motion will still + * be able to exit. + * If the init_retry_flag is not set the netcam_cleanup code was + * called while retrying the initial connection to a netcam and then + * there is no camera-handler started yet and thread_running must + * not be decremented. + */ + waittime.tv_sec = time(NULL) + 8; /* Seems that 3 is too small */ + waittime.tv_nsec = 0; - if (!netcam->caps.streaming) { - pthread_cond_signal(&netcam->cap_cond); - } + if (!init_retry_flag && + pthread_cond_timedwait(&netcam->exiting, &netcam->mutex, &waittime) != 0) { + /* + * Although this shouldn't happen, if it *does* happen we will + * log it (just for the programmer's information) + */ + motion_log(-1, 0, "No response from camera " + "handler - it must have already died"); + pthread_mutex_lock(&global_lock); + threads_running--; + pthread_mutex_unlock(&global_lock); + } - /* - * Once the camera-handler gets to the end of it's loop (probably as - * soon as we release netcam->mutex), because netcam->finish has been - * set it will exit it's loop, do anything it needs to do with the - * netcam context, and then send *us* as signal (netcam->exiting). - * Note that when we start our wait on netcam->exiting, our lock on - * netcam->mutex is automatically released, which will allow the - * handler to complete it's loop, notice that 'finish' is set and exit. - * This should always work, but again (defensive programming) we - * use pthread_cond_timedwait and, if our timeout (8 seconds) expires - * we just do the cleanup the handler would normally have done. This - * assures that (even if there is a bug in our code) motion will still - * be able to exit. - * If the init_retry_flag is not set the netcam_cleanup code was - * called while retrying the initial connection to a netcam and then - * there is no camera-handler started yet and thread_running must - * not be decremented. - */ - waittime.tv_sec = time(NULL) + 8; /* Seems that 3 is too small */ - waittime.tv_nsec = 0; + /* we don't need any lock anymore, so release it */ + pthread_mutex_unlock(&netcam->mutex); - if (!init_retry_flag && - pthread_cond_timedwait(&netcam->exiting, &netcam->mutex, &waittime) != 0) { - /* - * Although this shouldn't happen, if it *does* happen we will - * log it (just for the programmer's information) - */ - motion_log(-1, 0, "No response from camera " - "handler - it must have already died"); - pthread_mutex_lock(&global_lock); - threads_running--; - pthread_mutex_unlock(&global_lock); - } + /* and cleanup the rest of the netcam_context structure */ + if (netcam->connect_host != NULL) + free(netcam->connect_host); + - /* we don't need any lock anymore, so release it */ - pthread_mutex_unlock(&netcam->mutex); + if (netcam->connect_request != NULL) + free(netcam->connect_request); + - /* and cleanup the rest of the netcam_context structure */ - if (netcam->connect_host != NULL) { - free(netcam->connect_host); - } + if (netcam->boundary != NULL) + free(netcam->boundary); + - if (netcam->connect_request != NULL) { - free(netcam->connect_request); - } + if (netcam->latest != NULL) { + if (netcam->latest->ptr != NULL) + free(netcam->latest->ptr); + + free(netcam->latest); + } - if (netcam->boundary != NULL) { - free(netcam->boundary); - } + if (netcam->receiving != NULL) { + if (netcam->receiving->ptr != NULL) + free(netcam->receiving->ptr); + + free(netcam->receiving); + } - if (netcam->latest != NULL) { - if (netcam->latest->ptr != NULL) { - free(netcam->latest->ptr); - } - free(netcam->latest); - } + if (netcam->jpegbuf != NULL) { + if (netcam->jpegbuf->ptr != NULL) + free(netcam->jpegbuf->ptr); + + free(netcam->jpegbuf); + } - if (netcam->receiving != NULL) { - if (netcam->receiving->ptr != NULL) { - free(netcam->receiving->ptr); - } - free(netcam->receiving); - } + if (netcam->ftp != NULL) + ftp_free_context(netcam->ftp); + else + netcam_disconnect(netcam); + - if (netcam->jpegbuf != NULL) { - if (netcam->jpegbuf->ptr != NULL) { - free(netcam->jpegbuf->ptr); - } - free(netcam->jpegbuf); - } + if (netcam->response != NULL) + free(netcam->response); + - if (netcam->ftp != NULL) { - ftp_free_context(netcam->ftp); - } else { - netcam_disconnect(netcam); - } - - if (netcam->response != NULL) { - free(netcam->response); - } - - pthread_mutex_destroy(&netcam->mutex); - pthread_cond_destroy(&netcam->cap_cond); - pthread_cond_destroy(&netcam->pic_ready); - pthread_cond_destroy(&netcam->exiting); - free(netcam); + pthread_mutex_destroy(&netcam->mutex); + pthread_cond_destroy(&netcam->cap_cond); + pthread_cond_destroy(&netcam->pic_ready); + pthread_cond_destroy(&netcam->exiting); + free(netcam); } /** @@ -2198,47 +2219,47 @@ void netcam_cleanup(netcam_context_ptr netcam, int init_retry_flag) */ int netcam_next(struct context *cnt, unsigned char *image) { - netcam_context_ptr netcam; + netcam_context_ptr netcam; - /* - * Here we have some more "defensive programming". This check should - * never be true, but if it is just return with a "fatal error". - */ - if ((!cnt) || (!cnt->netcam)) - return NETCAM_FATAL_ERROR; + /* + * Here we have some more "defensive programming". This check should + * never be true, but if it is just return with a "fatal error". + */ + if ((!cnt) || (!cnt->netcam)) + return NETCAM_FATAL_ERROR; - netcam = cnt->netcam; + netcam = cnt->netcam; - if (!netcam->latest->used) { - if (debug_level) { - motion_log(LOG_INFO, 0, "netcam_next called with no data in buffer"); - } - return NETCAM_NOTHING_NEW_ERROR; - } + if (!netcam->latest->used) { + if (debug_level) + motion_log(LOG_INFO, 0, "netcam_next called with no data in buffer"); + + return NETCAM_NOTHING_NEW_ERROR; + } - /* - * If we are controlling a non-streaming camera, we synchronize the - * motion main-loop with the camera-handling thread through a signal, - * together with a flag to say "start your next capture". - */ - if (!netcam->caps.streaming) { - pthread_mutex_lock(&netcam->mutex); - netcam->start_capture = 1; - pthread_cond_signal(&netcam->cap_cond); - pthread_mutex_unlock(&netcam->mutex); - } + /* + * If we are controlling a non-streaming camera, we synchronize the + * motion main-loop with the camera-handling thread through a signal, + * together with a flag to say "start your next capture". + */ + if (!netcam->caps.streaming) { + pthread_mutex_lock(&netcam->mutex); + netcam->start_capture = 1; + pthread_cond_signal(&netcam->cap_cond); + pthread_mutex_unlock(&netcam->mutex); + } - /* - * If an error occurs in the JPEG decompression which follows this, - * jpeglib will return to the code within this 'if'. Basically, our - * approach is to just return a NULL (failed) to the caller (an - * error message has already been produced by the libjpeg routines) - */ - if (setjmp(netcam->setjmp_buffer)) { - return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR; - } - /* If there was no error, process the latest image buffer */ - return netcam_proc_jpeg(netcam, image); + /* + * If an error occurs in the JPEG decompression which follows this, + * jpeglib will return to the code within this 'if'. Basically, our + * approach is to just return a NULL (failed) to the caller (an + * error message has already been produced by the libjpeg routines) + */ + if (setjmp(netcam->setjmp_buffer)) + return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR; + + /* If there was no error, process the latest image buffer */ + return netcam_proc_jpeg(netcam, image); } /** @@ -2259,219 +2280,219 @@ int netcam_next(struct context *cnt, unsigned char *image) int netcam_start(struct context *cnt) { - netcam_context_ptr netcam; /* local pointer to our context */ - pthread_attr_t handler_attribute; /* attributes of our handler thread */ - int retval; /* working var */ - struct url_t url; /* for parsing netcam URL */ + netcam_context_ptr netcam; /* local pointer to our context */ + pthread_attr_t handler_attribute; /* attributes of our handler thread */ + int retval; /* working var */ + struct url_t url; /* for parsing netcam URL */ - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "entered netcam_start()"); + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "entered netcam_start()"); - memset(&url, 0, sizeof(url)); - if (SETUP) - motion_log(LOG_INFO, 0, "Camera thread starting..."); + memset(&url, 0, sizeof(url)); + if (SETUP) + motion_log(LOG_INFO, 0, "Camera thread starting..."); - /* - * Create a new netcam_context for this camera - * and clear all the entries. - */ - cnt->netcam = (struct netcam_context *) - mymalloc(sizeof(struct netcam_context)); - memset(cnt->netcam, 0, sizeof(struct netcam_context)); - netcam = cnt->netcam; /* Just for clarity in remaining code */ - netcam->cnt = cnt; /* Fill in the "parent" info */ + /* + * Create a new netcam_context for this camera + * and clear all the entries. + */ + cnt->netcam = (struct netcam_context *) + mymalloc(sizeof(struct netcam_context)); + memset(cnt->netcam, 0, sizeof(struct netcam_context)); + netcam = cnt->netcam; /* Just for clarity in remaining code */ + netcam->cnt = cnt; /* Fill in the "parent" info */ - /* - * Fill in our new netcam context with all known initial - * values. - */ + /* + * Fill in our new netcam context with all known initial + * values. + */ - /* Our image buffers */ - netcam->receiving = mymalloc(sizeof(netcam_buff)); - memset(netcam->receiving, 0, sizeof(netcam_buff)); - netcam->receiving->ptr = mymalloc(NETCAM_BUFFSIZE); + /* Our image buffers */ + netcam->receiving = mymalloc(sizeof(netcam_buff)); + memset(netcam->receiving, 0, sizeof(netcam_buff)); + netcam->receiving->ptr = mymalloc(NETCAM_BUFFSIZE); - netcam->jpegbuf = mymalloc(sizeof(netcam_buff)); - memset(netcam->jpegbuf, 0, sizeof(netcam_buff)); - netcam->jpegbuf->ptr = mymalloc(NETCAM_BUFFSIZE); + netcam->jpegbuf = mymalloc(sizeof(netcam_buff)); + memset(netcam->jpegbuf, 0, sizeof(netcam_buff)); + netcam->jpegbuf->ptr = mymalloc(NETCAM_BUFFSIZE); - netcam->latest = mymalloc(sizeof(netcam_buff)); - memset(netcam->latest, 0, sizeof(netcam_buff)); - netcam->latest->ptr = mymalloc(NETCAM_BUFFSIZE); - netcam->timeout.tv_sec = READ_TIMEOUT; + netcam->latest = mymalloc(sizeof(netcam_buff)); + memset(netcam->latest, 0, sizeof(netcam_buff)); + netcam->latest->ptr = mymalloc(NETCAM_BUFFSIZE); + netcam->timeout.tv_sec = READ_TIMEOUT; - /* Thread control structures */ - 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); - - /* Initialise the average frame time to the user's value */ - netcam->av_frame_time = 1000000.0 / cnt->conf.frame_limit; + /* Thread control structures */ + 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); + + /* Initialise the average frame time to the user's value */ + netcam->av_frame_time = 1000000.0 / cnt->conf.frame_limit; - /* - * If a proxy has been specified, parse that URL. - */ - if (cnt->conf.netcam_proxy) { - netcam_url_parse(&url, cnt->conf.netcam_proxy); + /* + * If a proxy has been specified, parse that URL. + */ + if (cnt->conf.netcam_proxy) { + netcam_url_parse(&url, cnt->conf.netcam_proxy); - if (!url.host) { - motion_log(LOG_ERR, 0, "Invalid netcam_proxy (%s)", - cnt->conf.netcam_proxy); - netcam_url_free(&url); - return -1; - } + if (!url.host) { + motion_log(LOG_ERR, 0, "Invalid netcam_proxy (%s)", + cnt->conf.netcam_proxy); + netcam_url_free(&url); + return -1; + } - if (url.userpass) { - motion_log(LOG_ERR, 0, "Username/password not allowed on a proxy URL"); - netcam_url_free(&url); - return -1; - } + if (url.userpass) { + motion_log(LOG_ERR, 0, "Username/password not allowed on a proxy URL"); + netcam_url_free(&url); + return -1; + } - /* - * A 'proxy' means that our eventual 'connect' to our - * camera must be sent to the proxy, and that our 'GET' must - * include the full path to the camera host. - */ - netcam->connect_host = url.host; - url.host = NULL; - netcam->connect_port = url.port; - netcam_url_free(&url); /* Finished with proxy */ - } + /* + * A 'proxy' means that our eventual 'connect' to our + * camera must be sent to the proxy, and that our 'GET' must + * include the full path to the camera host. + */ + netcam->connect_host = url.host; + url.host = NULL; + netcam->connect_port = url.port; + netcam_url_free(&url); /* Finished with proxy */ + } - /* - * Parse the URL from the configuration data - */ - netcam_url_parse(&url, cnt->conf.netcam_url); + /* + * Parse the URL from the configuration data + */ + netcam_url_parse(&url, cnt->conf.netcam_url); - if (!url.host) { - motion_log(LOG_ERR, 0, "Invalid netcam_url (%s)", cnt->conf.netcam_url); - netcam_url_free(&url); - return -1; - } + if (!url.host) { + motion_log(LOG_ERR, 0, "Invalid netcam_url (%s)", cnt->conf.netcam_url); + netcam_url_free(&url); + return -1; + } - if (cnt->conf.netcam_proxy == NULL) { - netcam->connect_host = url.host; - url.host = NULL; - netcam->connect_port = url.port; - } + if (cnt->conf.netcam_proxy == NULL) { + netcam->connect_host = url.host; + url.host = NULL; + netcam->connect_port = url.port; + } /* Get HTTP Mode (1.0 default, 1.0 Keep-Alive, 1.1) flag from config - * and report its stata for debug reasons. - * The flags in the conf structure is read only and cannot be - * unset if the Keep-Alive needs to be switched off (ie. netcam does - * not turn out to support it. That is handled by unsetting the flags - * in the context structures (cnt->...) only. - */ + * and report its stata for debug reasons. + * The flags in the conf structure is read only and cannot be + * unset if the Keep-Alive needs to be switched off (ie. netcam does + * not turn out to support it. That is handled by unsetting the flags + * in the context structures (cnt->...) only. + */ - if (!strcmp(cnt->conf.netcam_http,"keep_alive")) { - netcam->connect_http_10 = TRUE; - netcam->connect_http_11 = FALSE; - netcam->connect_keepalive = TRUE; - } else if (!strcmp(cnt->conf.netcam_http,"1.0") || !strcmp(cnt->conf.netcam_http,"1.0")) { - netcam->connect_http_10 = TRUE; - netcam->connect_http_11 = FALSE; - netcam->connect_keepalive = FALSE; - } else if (!strcmp(cnt->conf.netcam_http,"1.1")) { - netcam->connect_http_10 = FALSE; - netcam->connect_http_11 = TRUE; - netcam->connect_keepalive = TRUE; /* HTTP 1.1 has keepalive by default */ - } - if (debug_level > CAMERA_INFO) - motion_log(LOG_INFO, 0, "netcam_start: Netcam_http parameter '%s' converts to flags: HTTP1.0:" - "%s HTTP1.1: %s Keep-Alive %s.", cnt->conf.netcam_http, - netcam->connect_http_10 ? "1":"0", netcam->connect_http_11 ? "1":"0", - netcam->connect_keepalive ? "ON":"OFF"); + if (!strcmp(cnt->conf.netcam_http,"keep_alive")) { + netcam->connect_http_10 = TRUE; + netcam->connect_http_11 = FALSE; + netcam->connect_keepalive = TRUE; + } else if (!strcmp(cnt->conf.netcam_http,"1.0") || !strcmp(cnt->conf.netcam_http,"1.0")) { + netcam->connect_http_10 = TRUE; + netcam->connect_http_11 = FALSE; + netcam->connect_keepalive = FALSE; + } else if (!strcmp(cnt->conf.netcam_http,"1.1")) { + netcam->connect_http_10 = FALSE; + netcam->connect_http_11 = TRUE; + netcam->connect_keepalive = TRUE; /* HTTP 1.1 has keepalive by default */ + } + if (debug_level > CAMERA_INFO) + motion_log(LOG_INFO, 0, "netcam_start: Netcam_http parameter '%s' converts to flags: HTTP1.0:" + "%s HTTP1.1: %s Keep-Alive %s.", cnt->conf.netcam_http, + netcam->connect_http_10 ? "1":"0", netcam->connect_http_11 ? "1":"0", + netcam->connect_keepalive ? "ON":"OFF"); - /* Initialise the netcam socket to -1 to trigger a connection by the keep-alive logic */ - netcam->sock = -1; + /* Initialise the netcam socket to -1 to trigger a connection by the keep-alive logic */ + netcam->sock = -1; - if ((url.service) && (!strcmp(url.service, "http")) ){ - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "netcam_start: now calling netcam_setup_html()"); - retval = netcam_setup_html(netcam, &url); - } else if ((url.service) && (!strcmp(url.service, "ftp")) ){ - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "netcam_start: now calling netcam_setup_ftp"); - retval = netcam_setup_ftp(netcam, &url); - } else if ((url.service) && (!strcmp(url.service, "file")) ){ - if (debug_level > CAMERA_INFO) - motion_log(-1, 0, "netcam_start: now calling netcam_setup_file()"); - retval = netcam_setup_file(netcam, &url); - } else { - motion_log(LOG_ERR, 0, "Invalid netcam service '%s' - " - "must be http or ftp", url.service); - netcam_url_free(&url); - return -1; - } + if ((url.service) && (!strcmp(url.service, "http")) ){ + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "netcam_start: now calling netcam_setup_html()"); + retval = netcam_setup_html(netcam, &url); + } else if ((url.service) && (!strcmp(url.service, "ftp")) ){ + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "netcam_start: now calling netcam_setup_ftp"); + retval = netcam_setup_ftp(netcam, &url); + } else if ((url.service) && (!strcmp(url.service, "file")) ){ + if (debug_level > CAMERA_INFO) + motion_log(-1, 0, "netcam_start: now calling netcam_setup_file()"); + retval = netcam_setup_file(netcam, &url); + } else { + motion_log(LOG_ERR, 0, "Invalid netcam service '%s' - " + "must be http or ftp", url.service); + netcam_url_free(&url); + return -1; + } - if (retval < 0) - return -1; + if (retval < 0) + return -1; - /* - * We expect that, at this point, we should be positioned to read - * the first image available from the camera (directly after the - * applicable header). We want to decode the image in order to get - * the dimensions (width and height). If successful, we will use - * these to set the required image buffer(s) in our netcam_struct. - */ - if ((retval = netcam->get_image(netcam)) != 0) { - motion_log(LOG_ERR, 0, "Failed trying to read first image - retval:%d", retval ); - return -1; - } + /* + * We expect that, at this point, we should be positioned to read + * the first image available from the camera (directly after the + * applicable header). We want to decode the image in order to get + * the dimensions (width and height). If successful, we will use + * these to set the required image buffer(s) in our netcam_struct. + */ + if ((retval = netcam->get_image(netcam)) != 0) { + motion_log(LOG_ERR, 0, "Failed trying to read first image - retval:%d", retval ); + return -1; + } - /* - * If an error occurs in the JPEG decompression which follows this, - * jpeglib will return to the code within this 'if'. If such an error - * occurs during startup, we will just abandon this attempt. - */ - if (setjmp(netcam->setjmp_buffer)) { - motion_log(LOG_ERR, 0, "libjpeg decompression failure " - "on first frame - giving up!"); - return -1; - } + /* + * If an error occurs in the JPEG decompression which follows this, + * jpeglib will return to the code within this 'if'. If such an error + * occurs during startup, we will just abandon this attempt. + */ + if (setjmp(netcam->setjmp_buffer)) { + motion_log(LOG_ERR, 0, "libjpeg decompression failure " + "on first frame - giving up!"); + return -1; + } - netcam->netcam_broken = cnt->conf.netcam_broken; - netcam->JFIF_marker = 0; - netcam_get_dimensions(netcam); + netcam->netcam_broken = cnt->conf.netcam_broken; + netcam->JFIF_marker = 0; + netcam_get_dimensions(netcam); - /* Motion currently requires that image height and width is a - * multiple of 16. So we check for this. - */ - if (netcam->width % 16) { - motion_log(LOG_ERR, 0, "netcam image width (%d) is not modulo 16", - netcam->width); - return -1; - } + /* Motion currently requires that image height and width is a + * multiple of 16. So we check for this. + */ + if (netcam->width % 16) { + motion_log(LOG_ERR, 0, "netcam image width (%d) is not modulo 16", + netcam->width); + return -1; + } - if (netcam->height % 16) { - motion_log(LOG_ERR, 0, "netcam image height (%d) is not modulo 16", - netcam->height); - return -1; - } + if (netcam->height % 16) { + motion_log(LOG_ERR, 0, "netcam image height (%d) is not modulo 16", + netcam->height); + return -1; + } - /* Fill in camera details into context structure */ - cnt->imgs.width = netcam->width; - cnt->imgs.height = netcam->height; - cnt->imgs.size = (netcam->width * netcam->height * 3) / 2; - cnt->imgs.motionsize = netcam->width * netcam->height; - cnt->imgs.type = VIDEO_PALETTE_YUV420P; + /* Fill in camera details into context structure */ + cnt->imgs.width = netcam->width; + cnt->imgs.height = netcam->height; + cnt->imgs.size = (netcam->width * netcam->height * 3) / 2; + cnt->imgs.motionsize = netcam->width * netcam->height; + cnt->imgs.type = VIDEO_PALETTE_YUV420P; - /* - * Everything is now ready - start up the - * "handler thread". - */ - pthread_attr_init(&handler_attribute); - pthread_attr_setdetachstate(&handler_attribute, PTHREAD_CREATE_DETACHED); - pthread_mutex_lock(&global_lock); - netcam->threadnr = ++threads_running; - pthread_mutex_unlock(&global_lock); + /* + * Everything is now ready - start up the + * "handler thread". + */ + pthread_attr_init(&handler_attribute); + pthread_attr_setdetachstate(&handler_attribute, PTHREAD_CREATE_DETACHED); + pthread_mutex_lock(&global_lock); + netcam->threadnr = ++threads_running; + pthread_mutex_unlock(&global_lock); - if ((retval = pthread_create(&netcam->thread_id, &handler_attribute, - &netcam_handler_loop, netcam)) < 0) { - motion_log(LOG_ERR, 1, "Starting camera handler thread [%d]", netcam->threadnr); - return -1; - } + if ((retval = pthread_create(&netcam->thread_id, &handler_attribute, + &netcam_handler_loop, netcam)) < 0) { + motion_log(LOG_ERR, 1, "Starting camera handler thread [%d]", netcam->threadnr); + return -1; + } - return 0; + return 0; } diff --git a/netcam_ftp.c b/netcam_ftp.c index 0bb41596..3c06fed8 100644 --- a/netcam_ftp.c +++ b/netcam_ftp.c @@ -32,15 +32,15 @@ */ ftp_context_pointer ftp_new_context(void) { - ftp_context_pointer ret; + ftp_context_pointer ret; - /* note that mymalloc will exit on any problem */ - ret = mymalloc(sizeof(ftp_context)); + /* note that mymalloc will exit on any problem */ + ret = mymalloc(sizeof(ftp_context)); - memset(ret, 0, sizeof(ftp_context)); - ret->control_file_desc = -1; /* no control connection yet */ - ret->data_file_desc = -1; /* no data connection yet */ - return ret; + memset(ret, 0, sizeof(ftp_context)); + ret->control_file_desc = -1; /* no control connection yet */ + ret->data_file_desc = -1; /* no data connection yet */ + return ret; } /** @@ -57,22 +57,22 @@ ftp_context_pointer ftp_new_context(void) */ void ftp_free_context(ftp_context_pointer ctxt) { - if (ctxt == NULL) - return; + if (ctxt == NULL) + return; - if (ctxt->path != NULL) - free(ctxt->path); + if (ctxt->path != NULL) + free(ctxt->path); - if (ctxt->user) - free(ctxt->user); + if (ctxt->user) + free(ctxt->user); - if (ctxt->passwd) - free(ctxt->passwd); + if (ctxt->passwd) + free(ctxt->passwd); - if (ctxt->control_file_desc >= 0) - close(ctxt->control_file_desc); + if (ctxt->control_file_desc >= 0) + close(ctxt->control_file_desc); - free(ctxt); + free(ctxt); } /** @@ -91,35 +91,36 @@ void ftp_free_context(ftp_context_pointer ctxt) * -XXX for response to be continued */ static int ftp_parse_response(char *buf, int len) { - int val = 0; + int val = 0; - if (len < 3) - return(-1); - if ((*buf >= '0') && (*buf <= '9')) - val = val * 10 + (*buf - '0'); - else - return(0); + if (len < 3) + return(-1); - buf++; + if ((*buf >= '0') && (*buf <= '9')) + val = val * 10 + (*buf - '0'); + else + return(0); - if ((*buf >= '0') && (*buf <= '9')) - val = val * 10 + (*buf - '0'); - else - return(0); + buf++; - buf++; + if ((*buf >= '0') && (*buf <= '9')) + val = val * 10 + (*buf - '0'); + else + return(0); - if ((*buf >= '0') && (*buf <= '9')) - val = val * 10 + (*buf - '0'); - else - return(0); + buf++; - buf++; + if ((*buf >= '0') && (*buf <= '9')) + val = val * 10 + (*buf - '0'); + else + return(0); - if (*buf == '-') - return(-val); + buf++; - return(val); + if (*buf == '-') + return(-val); + + return(val); } /** @@ -134,53 +135,55 @@ static int ftp_parse_response(char *buf, int len) { * Returns the number of bytes read, < 0 indicates an error */ static int ftp_get_more(ftp_context_pointer ctxt) { - int len; - int size; + int len; + int size; - /* Validate that our context structure is valid */ - if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) - return(-1); + /* Validate that our context structure is valid */ + if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) + return(-1); - if ((ctxt->control_buffer_index < 0) || (ctxt->control_buffer_index > FTP_BUF_SIZE)) - return(-1); + if ((ctxt->control_buffer_index < 0) || (ctxt->control_buffer_index > FTP_BUF_SIZE)) + return(-1); - if ((ctxt->control_buffer_used < 0) || (ctxt->control_buffer_used > FTP_BUF_SIZE)) - return(-1); + if ((ctxt->control_buffer_used < 0) || (ctxt->control_buffer_used > FTP_BUF_SIZE)) + return(-1); - if (ctxt->control_buffer_index > ctxt->control_buffer_used) - return(-1); + if (ctxt->control_buffer_index > ctxt->control_buffer_used) + return(-1); - /* - * First pack the control buffer - */ - if (ctxt->control_buffer_index > 0) { - memmove(&ctxt->control_buffer[0], - &ctxt->control_buffer[ctxt->control_buffer_index], - ctxt->control_buffer_used - ctxt->control_buffer_index); - ctxt->control_buffer_used -= ctxt->control_buffer_index; - ctxt->control_buffer_index = 0; - } - size = FTP_BUF_SIZE - ctxt->control_buffer_used; + /* + * First pack the control buffer + */ + if (ctxt->control_buffer_index > 0) { + memmove(&ctxt->control_buffer[0], + &ctxt->control_buffer[ctxt->control_buffer_index], + ctxt->control_buffer_used - ctxt->control_buffer_index); - if (size == 0) { - return(0); - } + ctxt->control_buffer_used -= ctxt->control_buffer_index; + ctxt->control_buffer_index = 0; + } + size = FTP_BUF_SIZE - ctxt->control_buffer_used; - /* - * Read the amount left on the control connection - */ - if ((len = recv(ctxt->control_file_desc, - &ctxt->control_buffer[ctxt->control_buffer_index], - size, 0)) < 0) { - motion_log(LOG_ERR, 1, "recv failed in ftp_get_more"); - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } - ctxt->control_buffer_used += len; - ctxt->control_buffer[ctxt->control_buffer_used] = 0; + if (size == 0) + return(0); + - return(len); + /* + * Read the amount left on the control connection + */ + if ((len = recv(ctxt->control_file_desc, + &ctxt->control_buffer[ctxt->control_buffer_index], + size, 0)) < 0) { + motion_log(LOG_ERR, 1, "recv failed in ftp_get_more"); + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return(-1); + } + + ctxt->control_buffer_used += len; + ctxt->control_buffer[ctxt->control_buffer_used] = 0; + + return len; } /** @@ -195,57 +198,71 @@ static int ftp_get_more(ftp_context_pointer ctxt) { * Returns the code number */ static int ftp_get_response(ftp_context_pointer ctxt) { - char *ptr, *end; - int len; - int res = -1, cur = -1; + char *ptr, *end; + int len; + int res = -1, cur = -1; - if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) - return(-1); + if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) + return(-1); - get_more: - /* - * Assumes everything up to control_buffer[control_buffer_index] has been read - * and analyzed. - */ - len = ftp_get_more(ctxt); - if (len < 0) { - return(-1); - } - if ((ctxt->control_buffer_used == 0) && (len == 0)) { - return(-1); - } - ptr = &ctxt->control_buffer[ctxt->control_buffer_index]; - end = &ctxt->control_buffer[ctxt->control_buffer_used]; + get_more: + /* + * Assumes everything up to control_buffer[control_buffer_index] has been read + * and analyzed. + */ + len = ftp_get_more(ctxt); - while (ptr < end) { - cur = ftp_parse_response(ptr, end - ptr); - if (cur > 0) { - /* - * Successfully scanned the control code, skip - * till the end of the line, but keep the index to be - * able to analyze the result if needed. - */ - res = cur; - ptr += 3; - ctxt->control_buffer_answer = ptr - ctxt->control_buffer; - while ((ptr < end) && (*ptr != '\n')) ptr++; - if (*ptr == '\n') ptr++; - if (*ptr == '\r') ptr++; - break; - } - while ((ptr < end) && (*ptr != '\n')) - ptr++; - if (ptr >= end) { - ctxt->control_buffer_index = ctxt->control_buffer_used; - goto get_more; - } - if (*ptr != '\r') ptr++; - } + if (len < 0) + return -1; + + if ((ctxt->control_buffer_used == 0) && (len == 0)) + return -1; + + ptr = &ctxt->control_buffer[ctxt->control_buffer_index]; + end = &ctxt->control_buffer[ctxt->control_buffer_used]; - if (res < 0) - goto get_more; - ctxt->control_buffer_index = ptr - ctxt->control_buffer; - return(res / 100); + while (ptr < end) { + cur = ftp_parse_response(ptr, end - ptr); + if (cur > 0) { + /* + * Successfully scanned the control code, skip + * till the end of the line, but keep the index to be + * able to analyze the result if needed. + */ + res = cur; + ptr += 3; + ctxt->control_buffer_answer = ptr - ctxt->control_buffer; + + while ((ptr < end) && (*ptr != '\n')) + ptr++; + + if (*ptr == '\n') + ptr++; + + if (*ptr == '\r') + ptr++; + + break; + } + + while ((ptr < end) && (*ptr != '\n')) + ptr++; + + if (ptr >= end) { + ctxt->control_buffer_index = ctxt->control_buffer_used; + goto get_more; + } + + if (*ptr != '\r') + ptr++; + } + + if (res < 0) + goto get_more; + + ctxt->control_buffer_index = ptr - ctxt->control_buffer; + + return(res / 100); } /** @@ -253,22 +270,25 @@ static int ftp_get_response(ftp_context_pointer ctxt) { */ static int ftp_send_user(ftp_context_pointer ctxt) { - char buf[200]; - int len; - int res; + char buf[200]; + int len; + int res; - if (ctxt->user == NULL) - snprintf(buf, sizeof(buf), "USER anonymous\r\n"); - else - snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); - buf[sizeof(buf) - 1] = 0; - len = strlen(buf); - res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_send_user"); - return(res); - } - return(0); + if (ctxt->user == NULL) + snprintf(buf, sizeof(buf), "USER anonymous\r\n"); + else + snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user); + + buf[sizeof(buf) - 1] = 0; + len = strlen(buf); + res = send(ctxt->control_file_desc, buf, len, 0); + + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_send_user"); + return(res); + } + + return 0; } /** @@ -276,22 +296,25 @@ static int ftp_send_user(ftp_context_pointer ctxt) { */ static int ftp_send_passwd(ftp_context_pointer ctxt) { - char buf[200]; - int len; - int res; + char buf[200]; + int len; + int res; - if (ctxt->passwd == NULL) - snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); - else - snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); - buf[sizeof(buf) - 1] = 0; - len = strlen(buf); - res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_send_passwd"); - return(res); - } - return(0); + if (ctxt->passwd == NULL) + snprintf(buf, sizeof(buf), "PASS anonymous@\r\n"); + else + snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); + + buf[sizeof(buf) - 1] = 0; + len = strlen(buf); + res = send(ctxt->control_file_desc, buf, len, 0); + + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_send_passwd"); + return(res); + } + + return 0; } /** @@ -308,20 +331,22 @@ static int ftp_send_passwd(ftp_context_pointer ctxt) { static int ftp_quit(ftp_context_pointer ctxt) { - char buf[200]; - int len, res; + char buf[200]; + int len, res; - if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) - return(-1); + if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) + return -1; - snprintf(buf, sizeof(buf), "QUIT\r\n"); - len = strlen(buf); - res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_quit"); - return(res); - } - return(0); + snprintf(buf, sizeof(buf), "QUIT\r\n"); + len = strlen(buf); + res = send(ctxt->control_file_desc, buf, len, 0); + + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_quit"); + return res; + } + + return 0; } /** @@ -337,125 +362,139 @@ static int ftp_quit(ftp_context_pointer ctxt) { */ int ftp_connect(netcam_context_ptr netcam) { - ftp_context_pointer ctxt; - struct hostent *hp; - int port; - int res; - int addrlen = sizeof (struct sockaddr_in); + ftp_context_pointer ctxt; + struct hostent *hp; + int port; + int res; + int addrlen = sizeof (struct sockaddr_in); - if (netcam == NULL) - return -1; - ctxt = netcam->ftp; - if (ctxt == NULL) - return(-1); - if (netcam->connect_host == NULL) - return(-1); + if (netcam == NULL) + return -1; - /* - * do the blocking DNS query. - */ - port = netcam->connect_port; - if (port == 0) - port = 21; + ctxt = netcam->ftp; - memset (&ctxt->ftp_address, 0, sizeof(ctxt->ftp_address)); + if (ctxt == NULL) + return -1; - hp = gethostbyname (netcam->connect_host); - if (hp == NULL) { - motion_log(LOG_ERR, 1, "gethostbyname failed in ftp_connect"); - return (-1); - } - if ((unsigned int) hp->h_length > - sizeof(((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr)) { - motion_log(LOG_ERR, 1, "gethostbyname address mismatch " - "in ftp_connect"); - return (-1); - } + if (netcam->connect_host == NULL) + return -1; - /* - * Prepare the socket - */ - ((struct sockaddr_in *)&ctxt->ftp_address)->sin_family = AF_INET; - memcpy (&((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr, - hp->h_addr_list[0], hp->h_length); - ((struct sockaddr_in *)&ctxt->ftp_address)->sin_port = - (u_short)htons ((unsigned short)port); - ctxt->control_file_desc = socket (AF_INET, SOCK_STREAM, 0); - addrlen = sizeof (struct sockaddr_in); + /* + * do the blocking DNS query. + */ + port = netcam->connect_port; + + if (port == 0) + port = 21; - if (ctxt->control_file_desc < 0) { - motion_log(LOG_ERR, 1, "socket failed"); - return(-1); - } + memset (&ctxt->ftp_address, 0, sizeof(ctxt->ftp_address)); - /* - * Do the connect. - */ - if (connect(ctxt->control_file_desc, (struct sockaddr *) &ctxt->ftp_address, - addrlen) < 0) { - motion_log(LOG_ERR, 1, "Failed to create a connection"); - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } + hp = gethostbyname (netcam->connect_host); - /* - * Wait for the HELLO from the server. - */ - res = ftp_get_response(ctxt); - if (res != 2) { - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } + if (hp == NULL) { + motion_log(LOG_ERR, 1, "gethostbyname failed in ftp_connect"); + return -1; + } - /* - * Do the authentication - */ - res = ftp_send_user(ctxt); - if (res < 0) { - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } - res = ftp_get_response(ctxt); - switch (res) { - case 2: - return(0); - case 3: - break; - case 1: - case 4: - case 5: - case -1: - default: - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } - res = ftp_send_passwd(ctxt); - if (res < 0) { - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } - res = ftp_get_response(ctxt); - switch (res) { - case 2: - break; - case 3: - motion_log(LOG_ERR, 0, "FTP server asking for ACCT on anonymous"); - case 1: - case 4: - case 5: - case -1: - default: - close(ctxt->control_file_desc); ctxt->control_file_desc = -1; - ctxt->control_file_desc = -1; - return(-1); - } + if ((unsigned int) hp->h_length > + sizeof(((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr)) { + motion_log(LOG_ERR, 1, "gethostbyname address mismatch " + "in ftp_connect"); + return -1; + } - return(0); + /* + * Prepare the socket + */ + ((struct sockaddr_in *)&ctxt->ftp_address)->sin_family = AF_INET; + memcpy (&((struct sockaddr_in *)&ctxt->ftp_address)->sin_addr, + hp->h_addr_list[0], hp->h_length); + + ((struct sockaddr_in *)&ctxt->ftp_address)->sin_port = + (u_short)htons ((unsigned short)port); + ctxt->control_file_desc = socket (AF_INET, SOCK_STREAM, 0); + addrlen = sizeof (struct sockaddr_in); + + if (ctxt->control_file_desc < 0) { + motion_log(LOG_ERR, 1, "socket failed"); + return -1; + } + + /* + * Do the connect. + */ + if (connect(ctxt->control_file_desc, (struct sockaddr *) &ctxt->ftp_address, + addrlen) < 0) { + motion_log(LOG_ERR, 1, "Failed to create a connection"); + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return -1; + } + + /* + * Wait for the HELLO from the server. + */ + res = ftp_get_response(ctxt); + + if (res != 2) { + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return(-1); + } + + /* + * Do the authentication + */ + res = ftp_send_user(ctxt); + if (res < 0) { + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return(-1); + } + + res = ftp_get_response(ctxt); + + switch (res) { + case 2: + return(0); + case 3: + break; + case 1: + case 4: + case 5: + case -1: + default: + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return(-1); + } + + res = ftp_send_passwd(ctxt); + + if (res < 0) { + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return -1; + } + + res = ftp_get_response(ctxt); + + switch (res) { + case 2: + break; + case 3: + motion_log(LOG_ERR, 0, "FTP server asking for ACCT on anonymous"); + case 1: + case 4: + case 5: + case -1: + default: + close(ctxt->control_file_desc); ctxt->control_file_desc = -1; + ctxt->control_file_desc = -1; + return -1; + } + + return 0; } /** @@ -471,152 +510,164 @@ int ftp_connect(netcam_context_ptr netcam) { */ static int ftp_get_connection(ftp_context_pointer ctxt) { - char buf[200], *cur; - int len, i; - int res; - int on; - unsigned char ad[6], *adp, *portp; - unsigned int temp[6]; - struct sockaddr_in data_address; - unsigned int data_address_length; + char buf[200], *cur; + int len, i; + int res; + int on; + unsigned char ad[6], *adp, *portp; + unsigned int temp[6]; + struct sockaddr_in data_address; + unsigned int data_address_length; - if (ctxt == NULL) - return(-1); + if (ctxt == NULL) + return -1; - /* set up a socket for our data address */ - if (ctxt->data_file_desc != -1) - close(ctxt->data_file_desc); - memset (&data_address, 0, sizeof(data_address)); - ctxt->data_file_desc = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (ctxt->data_file_desc < 0) { - motion_log(LOG_ERR, 1, "socket failed"); - return (-1); - } - on = 1; - if (setsockopt(ctxt->data_file_desc, SOL_SOCKET, SO_REUSEADDR, - (char *)&on, sizeof(on)) < 0) { - motion_log(LOG_ERR, 1, "setting socket option SO_REUSEADDR"); - return -1; - } + /* set up a socket for our data address */ + if (ctxt->data_file_desc != -1) + close(ctxt->data_file_desc); + memset (&data_address, 0, sizeof(data_address)); + ctxt->data_file_desc = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (ctxt->data_file_desc < 0) { + motion_log(LOG_ERR, 1, "socket failed"); + return -1; + } - ((struct sockaddr_in *)&data_address)->sin_family = AF_INET; - data_address_length = sizeof (struct sockaddr_in); + on = 1; - if (ctxt->passive) { - /* send PASV command over control channel */ - snprintf (buf, sizeof(buf), "PASV\r\n"); - len = strlen (buf); - res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(res); - } - /* check server's answer */ - res = ftp_get_response(ctxt); - if (res != 2) { - if (res == 5) { - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(-1); - } else { - /* - * retry with an active connection - */ - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - ctxt->passive = 0; - } - } - /* parse the IP address and port supplied by the server */ - cur = &ctxt->control_buffer[ctxt->control_buffer_answer]; - while (((*cur < '0') || (*cur > '9')) && *cur != '\0') - cur++; - if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], - &temp[3], &temp[4], &temp[5]) != 6) { - motion_log(LOG_ERR, 0, "Invalid answer to PASV"); - if (ctxt->data_file_desc != -1) { - close (ctxt->data_file_desc); - ctxt->data_file_desc = -1; - } - return (-1); - } - for (i=0; i<6; i++) - ad[i] = (unsigned char) (temp[i] & 0xff) ; - memcpy (&((struct sockaddr_in *)&data_address)->sin_addr, &ad[0], 4); - memcpy (&((struct sockaddr_in *)&data_address)->sin_port, &ad[4], 2); + if (setsockopt(ctxt->data_file_desc, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) { + motion_log(LOG_ERR, 1, "setting socket option SO_REUSEADDR"); + return -1; + } - /* Now try to connect to the data port */ - if (connect(ctxt->data_file_desc, (struct sockaddr *) &data_address, - data_address_length) < 0) { - motion_log(LOG_ERR, 1, "Failed to create a data connection"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return (-1); - } - } else { - /* - * We want to bind to a port to receive the data. To do this, - * we need the address of our host. One easy way to get it is - * to get the info from the control connection that we have - * with the remote server - */ - getsockname(ctxt->control_file_desc, (struct sockaddr *)&data_address, - &data_address_length); - ((struct sockaddr_in *)&data_address)->sin_port = 0; + ((struct sockaddr_in *)&data_address)->sin_family = AF_INET; + data_address_length = sizeof (struct sockaddr_in); - /* bind to the socket - should give us a unique port */ - if (bind(ctxt->data_file_desc, (struct sockaddr *) &data_address, - data_address_length) < 0) { - motion_log(LOG_ERR, 1, "bind failed"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return (-1); - } + if (ctxt->passive) { + /* send PASV command over control channel */ + snprintf (buf, sizeof(buf), "PASV\r\n"); + len = strlen (buf); + res = send(ctxt->control_file_desc, buf, len, 0); + + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return res; + } - /* we get the port number by reading back in the sockaddr */ - getsockname(ctxt->data_file_desc, (struct sockaddr *)&data_address, - &data_address_length); + /* check server's answer */ + res = ftp_get_response(ctxt); - /* set up a 'listen' on the port to get the server's connection */ - if (listen(ctxt->data_file_desc, 1) < 0) { - motion_log(LOG_ERR, 1, "listen failed"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return (-1); - } + if (res != 2) { + if (res == 5) { + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } else { + /* + * retry with an active connection + */ + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + ctxt->passive = 0; + } + } + /* parse the IP address and port supplied by the server */ + cur = &ctxt->control_buffer[ctxt->control_buffer_answer]; + while (((*cur < '0') || (*cur > '9')) && *cur != '\0') + cur++; - /* now generate the PORT command */ - adp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_addr; - portp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_port; - snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n", - adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff, - portp[0] & 0xff, portp[1] & 0xff); + if (sscanf (cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2], + &temp[3], &temp[4], &temp[5]) != 6) { + motion_log(LOG_ERR, 0, "Invalid answer to PASV"); + + if (ctxt->data_file_desc != -1) { + close (ctxt->data_file_desc); + ctxt->data_file_desc = -1; + } - buf[sizeof(buf) - 1] = 0; - len = strlen(buf); + return -1; + } - /* send the PORT command to the server */ - res = send(ctxt->control_file_desc, buf, len, 0); + for (i=0; i<6; i++) + ad[i] = (unsigned char) (temp[i] & 0xff) ; - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(res); - } + memcpy (&((struct sockaddr_in *)&data_address)->sin_addr, &ad[0], 4); + memcpy (&((struct sockaddr_in *)&data_address)->sin_port, &ad[4], 2); - res = ftp_get_response(ctxt); + /* Now try to connect to the data port */ + if (connect(ctxt->data_file_desc, (struct sockaddr *) &data_address, + data_address_length) < 0) { + motion_log(LOG_ERR, 1, "Failed to create a data connection"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } - if (res != 2) { - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(-1); - } - } + } else { + /* + * We want to bind to a port to receive the data. To do this, + * we need the address of our host. One easy way to get it is + * to get the info from the control connection that we have + * with the remote server + */ + getsockname(ctxt->control_file_desc, (struct sockaddr *)&data_address, + &data_address_length); + ((struct sockaddr_in *)&data_address)->sin_port = 0; - return(ctxt->data_file_desc); + /* bind to the socket - should give us a unique port */ + if (bind(ctxt->data_file_desc, (struct sockaddr *) &data_address, + data_address_length) < 0) { + motion_log(LOG_ERR, 1, "bind failed"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } + + /* we get the port number by reading back in the sockaddr */ + getsockname(ctxt->data_file_desc, (struct sockaddr *)&data_address, + &data_address_length); + + /* set up a 'listen' on the port to get the server's connection */ + if (listen(ctxt->data_file_desc, 1) < 0) { + motion_log(LOG_ERR, 1, "listen failed"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } + + /* now generate the PORT command */ + adp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_addr; + portp = (unsigned char *) &((struct sockaddr_in *)&data_address)->sin_port; + snprintf (buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n", + adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff, + portp[0] & 0xff, portp[1] & 0xff); + + buf[sizeof(buf) - 1] = 0; + len = strlen(buf); + + /* send the PORT command to the server */ + res = send(ctxt->control_file_desc, buf, len, 0); + + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_get_connection"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return res; + } + + res = ftp_get_response(ctxt); + + if (res != 2) { + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } + } + + return ctxt->data_file_desc; } /** @@ -632,45 +683,45 @@ static int ftp_get_connection(ftp_context_pointer ctxt) { */ static int ftp_close_connection(ftp_context_pointer ctxt) { - int res; - fd_set rfd, efd; - struct timeval tv; + int res; + fd_set rfd, efd; + struct timeval tv; - if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) - return(-1); + if ((ctxt == NULL) || (ctxt->control_file_desc < 0)) + return(-1); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; - /* Check for data on the control channel */ - tv.tv_sec = 15; - tv.tv_usec = 0; - FD_ZERO(&rfd); - FD_SET(ctxt->control_file_desc, &rfd); - FD_ZERO(&efd); - FD_SET(ctxt->control_file_desc, &efd); - res = select(ctxt->control_file_desc + 1, &rfd, NULL, &efd, &tv); + /* Check for data on the control channel */ + tv.tv_sec = 15; + tv.tv_usec = 0; + FD_ZERO(&rfd); + FD_SET(ctxt->control_file_desc, &rfd); + FD_ZERO(&efd); + FD_SET(ctxt->control_file_desc, &efd); + res = select(ctxt->control_file_desc + 1, &rfd, NULL, &efd, &tv); - if (res < 0) { - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } + if (res < 0) { + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return -1; + } - if (res == 0) { /* timeout */ - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - } else { /* read the response */ - res = ftp_get_response(ctxt); + if (res == 0) { /* timeout */ + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + } else { /* read the response */ + res = ftp_get_response(ctxt); - if (res != 2) { /* should be positive completion (2) */ - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - return(-1); - } - } + if (res != 2) { /* should be positive completion (2) */ + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + return -1; + } + } - return(0); + return 0; } /** @@ -687,69 +738,69 @@ static int ftp_close_connection(ftp_context_pointer ctxt) { int ftp_get_socket(ftp_context_pointer ctxt) { - char buf[300]; - int res, len; - int acfd; + char buf[300]; + int res, len; + int acfd; - if ((ctxt == NULL) || (ctxt->path == NULL)) - return(-1); + if ((ctxt == NULL) || (ctxt->path == NULL)) + return -1; - /* Set up the data connection */ - ctxt->data_file_desc = ftp_get_connection(ctxt); + /* Set up the data connection */ + ctxt->data_file_desc = ftp_get_connection(ctxt); - if (ctxt->data_file_desc == -1) - return(-1); + if (ctxt->data_file_desc == -1) + return -1; - /* generate a "retrieve" command for the file */ - snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path); - buf[sizeof(buf) - 1] = 0; - len = strlen(buf); + /* generate a "retrieve" command for the file */ + snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path); + buf[sizeof(buf) - 1] = 0; + len = strlen(buf); - /* send it to the server */ - res = send(ctxt->control_file_desc, buf, len, 0); + /* send it to the server */ + res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(res); - } + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return res; + } - /* check the answer */ - res = ftp_get_response(ctxt); + /* check the answer */ + res = ftp_get_response(ctxt); - if (res != 1) { - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(-res); - } + if (res != 1) { + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -res; + } - /* - * if not a passive connection, need to do an accept to get the - * connection from the server - */ - if (!ctxt->passive) { - struct sockaddr_in data_address; - unsigned int data_address_length = sizeof(struct sockaddr_in); + /* + * if not a passive connection, need to do an accept to get the + * connection from the server + */ + if (!ctxt->passive) { + struct sockaddr_in data_address; + unsigned int data_address_length = sizeof(struct sockaddr_in); - if ((acfd = accept(ctxt->data_file_desc, (struct sockaddr *)&data_address, - &data_address_length)) < 0) { - motion_log(LOG_ERR, 1, "accept in ftp_get_socket"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return -1; - } + if ((acfd = accept(ctxt->data_file_desc, (struct sockaddr *)&data_address, + &data_address_length)) < 0) { + motion_log(LOG_ERR, 1, "accept in ftp_get_socket"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -1; + } - close(ctxt->data_file_desc); - ctxt->data_file_desc = acfd; - } + close(ctxt->data_file_desc); + ctxt->data_file_desc = acfd; + } - return(ctxt->data_file_desc); + return ctxt->data_file_desc; } /** * ftp_send_type * -* Send a TYPE (either 'I' or 'A') command to the server +* Send a TYPE (either 'I' or 'A') command to the server * * Parameters * @@ -760,31 +811,31 @@ int ftp_get_socket(ftp_context_pointer ctxt) { * */ int ftp_send_type(ftp_context_pointer ctxt, char type) { - char buf[100], utype; - int len, res; + char buf[100], utype; + int len, res; - utype = toupper(type); - /* Assure transfer will be in "image" mode */ - snprintf(buf, sizeof(buf), "TYPE I\r\n"); - len = strlen(buf); - res = send(ctxt->control_file_desc, buf, len, 0); + utype = toupper(type); + /* Assure transfer will be in "image" mode */ + snprintf(buf, sizeof(buf), "TYPE I\r\n"); + len = strlen(buf); + res = send(ctxt->control_file_desc, buf, len, 0); - if (res < 0) { - motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(res); - } + if (res < 0) { + motion_log(LOG_ERR, 1, "send failed in ftp_get_socket"); + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return res; + } - res = ftp_get_response(ctxt); + res = ftp_get_response(ctxt); - if (res != 2) { - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - return(-res); - } + if (res != 2) { + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + return -res; + } - return 0; + return 0; } /** @@ -803,27 +854,27 @@ int ftp_send_type(ftp_context_pointer ctxt, char type) { * -1 indicates a parameter error. */ int ftp_read(ftp_context_pointer ctxt, void *dest, int len) { - if (ctxt == NULL) - return(-1); + if (ctxt == NULL) + return -1; - if (ctxt->data_file_desc < 0) - return(0); + if (ctxt->data_file_desc < 0) + return 0; - if (dest == NULL) - return(-1); + if (dest == NULL) + return -1; - if (len <= 0) - return(0); + if (len <= 0) + return 0; - len = recv(ctxt->data_file_desc, dest, len, 0); + len = recv(ctxt->data_file_desc, dest, len, 0); - if (len <= 0) { - if (len < 0) - motion_log(LOG_ERR, 1, "recv failed in ftp_read"); - ftp_close_connection(ctxt); - } + if (len <= 0) { + if (len < 0) + motion_log(LOG_ERR, 1, "recv failed in ftp_read"); + ftp_close_connection(ctxt); + } - return(len); + return len; } @@ -839,20 +890,21 @@ int ftp_read(ftp_context_pointer ctxt, void *dest, int len) { * Returns -1 in case of error, 0 otherwise */ int ftp_close(ftp_context_pointer ctxt) { - if (ctxt == NULL) - return(-1); + if (ctxt == NULL) + return -1; - if (ctxt->data_file_desc >= 0) { - close(ctxt->data_file_desc); - ctxt->data_file_desc = -1; - } + if (ctxt->data_file_desc >= 0) { + close(ctxt->data_file_desc); + ctxt->data_file_desc = -1; + } - if (ctxt->control_file_desc >= 0) { - ftp_quit(ctxt); - close(ctxt->control_file_desc); - ctxt->control_file_desc = -1; - } + if (ctxt->control_file_desc >= 0) { + ftp_quit(ctxt); + close(ctxt->control_file_desc); + ctxt->control_file_desc = -1; + } - ftp_free_context(ctxt); - return(0); + ftp_free_context(ctxt); + + return 0; } diff --git a/netcam_wget.c b/netcam_wget.c index 476c1649..834f6f41 100644 --- a/netcam_wget.c +++ b/netcam_wget.c @@ -1,6 +1,6 @@ /* Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002 - Free Software Foundation, Inc. + Free Software Foundation, Inc. Additional Copyright (C) 2004-2005 Christopher Price, Angel Carpintero, and other contributing authors. @@ -38,14 +38,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ definition is not HTTP-specific -- it is virtually indistinguishable from the one given in RFC822 or RFC1036. - message-header = field-name ":" [ field-value ] CRLF + message-header = field-name ":" [ field-value ] CRLF - field-name = token - field-value = *( field-content | LWS ) + field-name = token + field-value = *( field-content | LWS ) - field-content = + field-content = The public functions are header_get() and header_process(), which see. */ @@ -67,84 +67,80 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ int header_get(netcam_context_ptr netcam, char **hdr, enum header_get_flags flags) { - int i; - int bufsize = 80; + int i; + int bufsize = 80; - *hdr = (char *)mymalloc(bufsize); - for (i = 0; 1; i++) { - int res; - /* #### Use DO_REALLOC? */ - if (i > bufsize - 1) - *hdr = (char *)myrealloc(*hdr, (bufsize <<= 1), ""); + *hdr = (char *)mymalloc(bufsize); + for (i = 0; 1; i++) { + int res; + /* #### Use DO_REALLOC? */ + if (i > bufsize - 1) + *hdr = (char *)myrealloc(*hdr, (bufsize <<= 1), ""); - res = RBUF_READCHAR (netcam, *hdr + i); + res = RBUF_READCHAR (netcam, *hdr + i); - if (res == 1) { - if ((*hdr)[i] == '\n') { - if (!((flags & HG_NO_CONTINUATIONS) || i == 0 - || (i == 1 && (*hdr)[0] == '\r'))) { - char next; - /* If the header is non-empty, we need to check if - it continues on to the other line. We do that by - peeking at the next character. */ - res = rbuf_peek(netcam, &next); + if (res == 1) { + if ((*hdr)[i] == '\n') { + if (!((flags & HG_NO_CONTINUATIONS) || i == 0 + || (i == 1 && (*hdr)[0] == '\r'))) { + char next; + /* If the header is non-empty, we need to check if + it continues on to the other line. We do that by + peeking at the next character. */ + res = rbuf_peek(netcam, &next); - if (res == 0) - { - (*hdr)[i] = '\0'; - return HG_EOF; - } - else if (res == -1) - { - (*hdr)[i] = '\0'; - return HG_ERROR; - } - /* If the next character is HT or SP, just continue. */ + if (res == 0) { + (*hdr)[i] = '\0'; + return HG_EOF; + } else if (res == -1) { + (*hdr)[i] = '\0'; + return HG_ERROR; + } + /* If the next character is HT or SP, just continue. */ - if (next == '\t' || next == ' ') - continue; - } + if (next == '\t' || next == ' ') + continue; + } - /* Strip trailing whitespace. (*hdr)[i] is the newline; - decrement I until it points to the last available - whitespace. */ - while (i > 0 && isspace((*hdr)[i - 1])) - --i; - - (*hdr)[i] = '\0'; - break; - } - } else if (res == 0) - { - (*hdr)[i] = '\0'; - return HG_EOF; - } - else - { - (*hdr)[i] = '\0'; - return HG_ERROR; - } - } + /* Strip trailing whitespace. (*hdr)[i] is the newline; + decrement I until it points to the last available + whitespace. */ + while (i > 0 && isspace((*hdr)[i - 1])) + --i; + + (*hdr)[i] = '\0'; + break; + } - return HG_OK; + } else if (res == 0) { + + (*hdr)[i] = '\0'; + return HG_EOF; + } else { + (*hdr)[i] = '\0'; + return HG_ERROR; + } + } + + return HG_OK; } /* Check whether HEADER begins with NAME and, if yes, skip the `:' and the whitespace, and call PROCFUN with the arguments of HEADER's contents (after the `:' and space) and ARG. Otherwise, return 0. */ int header_process (const char *header, const char *name, - int (*procfun)(const char *, void *), - void *arg) + int (*procfun)(const char *, void *), + void *arg) { - /* Check whether HEADER matches NAME. */ - while (*name && (tolower (*name) == tolower (*header))) - ++name, ++header; + /* Check whether HEADER matches NAME. */ + while (*name && (tolower (*name) == tolower (*header))) + ++name, ++header; - if (*name || *header++ != ':') - return 0; - - header += skip_lws (header); - return ((*procfun) (header, arg)); + if (*name || *header++ != ':') + return 0; + + header += skip_lws (header); + return ((*procfun) (header, arg)); } /* Helper functions for use with header_process(). */ @@ -153,34 +149,34 @@ int header_process (const char *header, const char *name, error is encountered, return 0, else 1. */ int header_extract_number(const char *header, void *closure) { - const char *p = header; - long result; + const char *p = header; + long result; - for (result = 0; isdigit (*p); p++) - result = 10 * result + (*p - '0'); + for (result = 0; isdigit (*p); p++) + result = 10 * result + (*p - '0'); - /* Failure if no number present. */ - if (p == header) - return 0; + /* Failure if no number present. */ + if (p == header) + return 0; - /* Skip trailing whitespace. */ - p += skip_lws (p); + /* Skip trailing whitespace. */ + p += skip_lws (p); - /* We return the value, even if a format error follows */ - *(long *)closure = result; + /* We return the value, even if a format error follows */ + *(long *)closure = result; - /* Indicate failure if trailing garbage is present. */ - if (*p) - return 0; + /* Indicate failure if trailing garbage is present. */ + if (*p) + return 0; - return 1; + return 1; } /* Strdup HEADER, and place the pointer to CLOSURE. */ int header_strdup(const char *header, void *closure) { - *(char **)closure = strdup(header); - return 1; + *(char **)closure = strdup(header); + return 1; } @@ -188,148 +184,148 @@ int header_strdup(const char *header, void *closure) characters to skip. */ int skip_lws(const char *string) { - const char *p = string; + const char *p = string; - while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') - ++p; + while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') + ++p; - return p - string; + return p - string; } /* - Encode the string S of length LENGTH to base64 format and place it - to STORE. STORE will be 0-terminated, and must point to a writable - buffer of at least 1+BASE64_LENGTH(length) bytes. + Encode the string S of length LENGTH to base64 format and place it + to STORE. STORE will be 0-terminated, and must point to a writable + buffer of at least 1+BASE64_LENGTH(length) bytes. */ void base64_encode(const char *s, char *store, int length) { - /* Conversion table. */ - static const char tbl[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' - }; - - int i; - unsigned char *p = (unsigned char *)store; + /* Conversion table. */ + static const char tbl[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + }; + + int i; + unsigned char *p = (unsigned char *)store; - /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ - for (i = 0; i < length; i += 3) { - *p++ = tbl[s[0] >> 2]; - *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; - *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; - *p++ = tbl[s[2] & 0x3f]; - s += 3; - } - - /* Pad the result if necessary... */ - if (i == length + 1) - *(p - 1) = '='; - else if (i == length + 2) - *(p - 1) = *(p - 2) = '='; + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ + for (i = 0; i < length; i += 3) { + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; + *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; + *p++ = tbl[s[2] & 0x3f]; + s += 3; + } + + /* Pad the result if necessary... */ + if (i == length + 1) + *(p - 1) = '='; + else if (i == length + 2) + *(p - 1) = *(p - 2) = '='; - /* ...and zero-terminate it. */ - *p = '\0'; + /* ...and zero-terminate it. */ + *p = '\0'; } char *strdupdelim(const char *beg, const char *end) { - char *res = (char *)mymalloc(end - beg + 1); - memcpy (res, beg, end - beg); + char *res = (char *)mymalloc(end - beg + 1); + memcpy (res, beg, end - beg); - res[end - beg] = '\0'; - return res; + res[end - beg] = '\0'; + return res; } int http_process_type(const char *hdr, void *arg) { - char **result = (char **)arg; - /* Locate P on `;' or the terminating zero, whichever comes first. */ - const char *p = strchr (hdr, ';'); + char **result = (char **)arg; + /* Locate P on `;' or the terminating zero, whichever comes first. */ + const char *p = strchr (hdr, ';'); - if (!p) - p = hdr + strlen (hdr); + if (!p) + p = hdr + strlen (hdr); - while (p > hdr && isspace (*(p - 1))) - --p; + while (p > hdr && isspace (*(p - 1))) + --p; - *result = strdupdelim (hdr, p); - return 1; + *result = strdupdelim (hdr, p); + return 1; } /* This is a simple implementation of buffering IO-read functions. */ void rbuf_initialize(netcam_context_ptr netcam) { - netcam->response->buffer_pos = netcam->response->buffer; - netcam->response->buffer_left = 0; + netcam->response->buffer_pos = netcam->response->buffer; + netcam->response->buffer_left = 0; } int rbuf_read_bufferful(netcam_context_ptr netcam) { - return netcam_recv(netcam, netcam->response->buffer, - sizeof (netcam->response->buffer)); + return netcam_recv(netcam, netcam->response->buffer, + sizeof (netcam->response->buffer)); } /* Like rbuf_readchar(), only don't move the buffer position. */ int rbuf_peek(netcam_context_ptr netcam, char *store) { - if (!netcam->response->buffer_left) { - int res; - rbuf_initialize(netcam); - res = netcam_recv (netcam, netcam->response->buffer, - sizeof (netcam->response->buffer)); + if (!netcam->response->buffer_left) { + int res; + rbuf_initialize(netcam); + res = netcam_recv (netcam, netcam->response->buffer, + sizeof (netcam->response->buffer)); - if (res <= 0) - return res; + if (res <= 0) + return res; - netcam->response->buffer_left = res; - } - - *store = *netcam->response->buffer_pos; - return 1; + netcam->response->buffer_left = res; + } + + *store = *netcam->response->buffer_pos; + return 1; } /* - Flush RBUF's buffer to WHERE. Flush MAXSIZE bytes at most. - Returns the number of bytes actually copied. If the buffer is - empty, 0 is returned. + Flush RBUF's buffer to WHERE. Flush MAXSIZE bytes at most. + Returns the number of bytes actually copied. If the buffer is + empty, 0 is returned. */ int rbuf_flush(netcam_context_ptr netcam, char *where, int maxsize) { - if (!netcam->response->buffer_left) - return 0; - else { - int howmuch = MINVAL ((int)netcam->response->buffer_left, maxsize); + if (!netcam->response->buffer_left) { + return 0; + } else { + int howmuch = MINVAL ((int)netcam->response->buffer_left, maxsize); - if (where) - memcpy(where, netcam->response->buffer_pos, howmuch); + if (where) + memcpy(where, netcam->response->buffer_pos, howmuch); - netcam->response->buffer_left -= howmuch; - netcam->response->buffer_pos += howmuch; - return howmuch; - } + netcam->response->buffer_left -= howmuch; + netcam->response->buffer_pos += howmuch; + return howmuch; + } } /* Get the HTTP result code */ int http_result_code(const char *header) { - char *cptr; + char *cptr; - /* assure the header starts out right */ - if (strncmp(header, "HTTP", 4)) - return -1; + /* assure the header starts out right */ + if (strncmp(header, "HTTP", 4)) + return -1; - /* find the space following the HTTP/1.x */ - if ((cptr = strchr(header+4, ' ')) == NULL) - return -1; + /* find the space following the HTTP/1.x */ + if ((cptr = strchr(header+4, ' ')) == NULL) + return -1; - return atoi(cptr + 1); + return atoi(cptr + 1); } diff --git a/picture.c b/picture.c index c175ad45..0cd3dbf9 100644 --- a/picture.c +++ b/picture.c @@ -1,10 +1,10 @@ -/* picture.c +/* picture.c * - * Various funtions for saving/loading pictures. - * Copyright 2002 by Jeroen Vreeken (pe1rxq@amsat.org) - * Portions of this file are Copyright by Lionnel Maugis - * This software is distributed under the GNU public license version 2 - * See also the file 'COPYING'. + * Various funtions for saving/loading pictures. + * Copyright 2002 by Jeroen Vreeken (pe1rxq@amsat.org) + * Portions of this file are Copyright by Lionnel Maugis + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. * */ @@ -19,10 +19,10 @@ * functions used by put_jpeg_grey_memory and put_jpeg_yuv420p_memory */ typedef struct { - struct jpeg_destination_mgr pub; - JOCTET *buf; - size_t bufsize; - size_t jpegsize; + struct jpeg_destination_mgr pub; + JOCTET *buf; + size_t bufsize; + size_t jpegsize; } mem_destination_mgr; typedef mem_destination_mgr *mem_dest_ptr; @@ -30,53 +30,53 @@ typedef mem_destination_mgr *mem_dest_ptr; METHODDEF(void) init_destination(j_compress_ptr cinfo) { - mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; - dest->pub.next_output_byte = dest->buf; - dest->pub.free_in_buffer = dest->bufsize; - dest->jpegsize = 0; + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + dest->pub.next_output_byte = dest->buf; + dest->pub.free_in_buffer = dest->bufsize; + dest->jpegsize = 0; } METHODDEF(boolean) empty_output_buffer(j_compress_ptr cinfo) { - mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; - dest->pub.next_output_byte = dest->buf; - dest->pub.free_in_buffer = dest->bufsize; + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + dest->pub.next_output_byte = dest->buf; + dest->pub.free_in_buffer = dest->bufsize; - return FALSE; - ERREXIT(cinfo, JERR_BUFFER_SIZE); + return FALSE; + ERREXIT(cinfo, JERR_BUFFER_SIZE); } METHODDEF(void) term_destination(j_compress_ptr cinfo) { - mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; - dest->jpegsize = dest->bufsize - dest->pub.free_in_buffer; + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + dest->jpegsize = dest->bufsize - dest->pub.free_in_buffer; } static GLOBAL(void) jpeg_mem_dest(j_compress_ptr cinfo, JOCTET* buf, size_t bufsize) { - mem_dest_ptr dest; + mem_dest_ptr dest; - if (cinfo->dest == NULL) { - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, - sizeof(mem_destination_mgr)); - } + if (cinfo->dest == NULL) { + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + sizeof(mem_destination_mgr)); + } - dest = (mem_dest_ptr) cinfo->dest; + dest = (mem_dest_ptr) cinfo->dest; - dest->pub.init_destination = init_destination; - dest->pub.empty_output_buffer = empty_output_buffer; - dest->pub.term_destination = term_destination; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; - dest->buf = buf; - dest->bufsize = bufsize; - dest->jpegsize = 0; + dest->buf = buf; + dest->bufsize = bufsize; + dest->jpegsize = 0; } static GLOBAL(int) jpeg_mem_size(j_compress_ptr cinfo) { - mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; - return dest->jpegsize; + mem_dest_ptr dest = (mem_dest_ptr) cinfo->dest; + return dest->jpegsize; } @@ -92,61 +92,61 @@ static GLOBAL(int) jpeg_mem_size(j_compress_ptr cinfo) * Returns buffer size of jpeg image */ static int put_jpeg_yuv420p_memory(unsigned char *dest_image, int image_size, - unsigned char *input_image, int width, int height, int quality) + unsigned char *input_image, int width, int height, int quality) { - int i, j, jpeg_image_size; + int i, j, jpeg_image_size; - JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane) - JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5 + JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane) + JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5 - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; - data[0] = y; - data[1] = cb; - data[2] = cr; + data[0] = y; + data[1] = cb; + data[2] = cr; - cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr - - jpeg_create_compress(&cinfo); - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.input_components = 3; - jpeg_set_defaults (&cinfo); + cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr + + jpeg_create_compress(&cinfo); + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; + jpeg_set_defaults (&cinfo); - jpeg_set_colorspace(&cinfo, JCS_YCbCr); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.raw_data_in = TRUE; // supply downsampled data - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; + cinfo.raw_data_in = TRUE; // supply downsampled data + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; - jpeg_set_quality(&cinfo, quality, TRUE); - cinfo.dct_method = JDCT_FASTEST; + jpeg_set_quality(&cinfo, quality, TRUE); + cinfo.dct_method = JDCT_FASTEST; - jpeg_mem_dest(&cinfo, dest_image, image_size); // data written to mem - - jpeg_start_compress (&cinfo, TRUE); + jpeg_mem_dest(&cinfo, dest_image, image_size); // data written to mem + + jpeg_start_compress (&cinfo, TRUE); - for (j = 0; j < height; j += 16) { - for (i = 0; i < 16; i++) { - y[i] = input_image + width*(i+j); - if (i%2 == 0) { - cb[i/2] = input_image + width*height + width/2*((i+j)/2); - cr[i/2] = input_image + width*height + width*height/4 + width/2*((i+j)/2); - } - } - jpeg_write_raw_data(&cinfo, data, 16); - } + for (j = 0; j < height; j += 16) { + for (i = 0; i < 16; i++) { + y[i] = input_image + width * (i + j); + if (i%2 == 0) { + cb[i/2] = input_image + width * height + width / 2 * ((i + j) / 2); + cr[i/2] = input_image + width * height + width * height / 4 + width / 2 * ((i + j) / 2); + } + } + jpeg_write_raw_data(&cinfo, data, 16); + } - jpeg_finish_compress(&cinfo); - jpeg_image_size = jpeg_mem_size(&cinfo); - jpeg_destroy_compress(&cinfo); - - return jpeg_image_size; + jpeg_finish_compress(&cinfo); + jpeg_image_size = jpeg_mem_size(&cinfo); + jpeg_destroy_compress(&cinfo); + + return jpeg_image_size; } /* put_jpeg_grey_memory converts an input image in the grayscale format into a jpeg image @@ -159,40 +159,41 @@ static int put_jpeg_yuv420p_memory(unsigned char *dest_image, int image_size, * - dest_image is a pointer to the jpeg image buffer * Returns buffer size of jpeg image */ -static int put_jpeg_grey_memory(unsigned char *dest_image, int image_size, unsigned char *input_image, int width, int height, int quality) +static int put_jpeg_grey_memory(unsigned char *dest_image, int image_size, + unsigned char *input_image, int width, int height, int quality) { - int y, dest_image_size; - JSAMPROW row_ptr[1]; - struct jpeg_compress_struct cjpeg; - struct jpeg_error_mgr jerr; + int y, dest_image_size; + JSAMPROW row_ptr[1]; + struct jpeg_compress_struct cjpeg; + struct jpeg_error_mgr jerr; - cjpeg.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cjpeg); - cjpeg.image_width = width; - cjpeg.image_height = height; - cjpeg.input_components = 1; /* one colour component */ - cjpeg.in_color_space = JCS_GRAYSCALE; + cjpeg.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cjpeg); + cjpeg.image_width = width; + cjpeg.image_height = height; + cjpeg.input_components = 1; /* one colour component */ + cjpeg.in_color_space = JCS_GRAYSCALE; - jpeg_set_defaults(&cjpeg); + jpeg_set_defaults(&cjpeg); - jpeg_set_quality(&cjpeg, quality, TRUE); - cjpeg.dct_method = JDCT_FASTEST; - jpeg_mem_dest(&cjpeg, dest_image, image_size); // data written to mem + jpeg_set_quality(&cjpeg, quality, TRUE); + cjpeg.dct_method = JDCT_FASTEST; + jpeg_mem_dest(&cjpeg, dest_image, image_size); // data written to mem - jpeg_start_compress (&cjpeg, TRUE); + jpeg_start_compress (&cjpeg, TRUE); - row_ptr[0] = input_image; - - for (y = 0; y < height; y++) { - jpeg_write_scanlines(&cjpeg, row_ptr, 1); - row_ptr[0] += width; - } - - jpeg_finish_compress(&cjpeg); - dest_image_size = jpeg_mem_size(&cjpeg); - jpeg_destroy_compress(&cjpeg); + row_ptr[0] = input_image; + + for (y = 0; y < height; y++) { + jpeg_write_scanlines(&cjpeg, row_ptr, 1); + row_ptr[0] += width; + } + + jpeg_finish_compress(&cjpeg); + dest_image_size = jpeg_mem_size(&cjpeg); + jpeg_destroy_compress(&cjpeg); - return dest_image_size; + return dest_image_size; } /* put_jpeg_yuv420p_file converts an YUV420P coded image to a jpeg image and writes @@ -205,57 +206,58 @@ static int put_jpeg_grey_memory(unsigned char *dest_image, int image_size, unsig * - The jpeg is written directly to the file given by the file pointer fp * Returns nothing */ -static void put_jpeg_yuv420p_file(FILE *fp, unsigned char *image, int width, int height, int quality) +static void put_jpeg_yuv420p_file(FILE *fp, unsigned char *image, int width, + int height, int quality) { - int i,j; + int i,j; - JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane) - JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5 + JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane) + JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5 - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; - data[0] = y; - data[1] = cb; - data[2] = cr; + data[0] = y; + data[1] = cb; + data[2] = cr; - cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr - - jpeg_create_compress(&cinfo); - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.input_components = 3; - jpeg_set_defaults(&cinfo); + cinfo.err = jpeg_std_error(&jerr); // errors get written to stderr + + jpeg_create_compress(&cinfo); + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; + jpeg_set_defaults(&cinfo); - jpeg_set_colorspace(&cinfo, JCS_YCbCr); + jpeg_set_colorspace(&cinfo, JCS_YCbCr); - cinfo.raw_data_in = TRUE; // supply downsampled data - cinfo.comp_info[0].h_samp_factor = 2; - cinfo.comp_info[0].v_samp_factor = 2; - cinfo.comp_info[1].h_samp_factor = 1; - cinfo.comp_info[1].v_samp_factor = 1; - cinfo.comp_info[2].h_samp_factor = 1; - cinfo.comp_info[2].v_samp_factor = 1; + cinfo.raw_data_in = TRUE; // supply downsampled data + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; - jpeg_set_quality(&cinfo, quality, TRUE); - cinfo.dct_method = JDCT_FASTEST; + jpeg_set_quality(&cinfo, quality, TRUE); + cinfo.dct_method = JDCT_FASTEST; - jpeg_stdio_dest(&cinfo, fp); // data written to file - jpeg_start_compress(&cinfo, TRUE); + jpeg_stdio_dest(&cinfo, fp); // data written to file + jpeg_start_compress(&cinfo, TRUE); - for (j = 0; j < height; j += 16) { - for (i = 0; i < 16; i++) { - y[i] = image + width*(i+j); - if (i%2 == 0) { - cb[i/2] = image + width*height + width/2*((i+j)/2); - cr[i/2] = image + width*height + width*height/4 + width/2*((i+j)/2); - } - } - jpeg_write_raw_data(&cinfo, data, 16); - } + for (j = 0; j < height; j += 16) { + for (i = 0; i < 16; i++) { + y[i] = image + width * (i + j); + if (i % 2 == 0) { + cb[i / 2] = image + width * height + width / 2 * ((i + j) / 2); + cr[i / 2] = image + width * height + width * height / 4 + width / 2 * ((i + j) /2); + } + } + jpeg_write_raw_data(&cinfo, data, 16); + } - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); } @@ -271,33 +273,33 @@ static void put_jpeg_yuv420p_file(FILE *fp, unsigned char *image, int width, int */ static void put_jpeg_grey_file(FILE *picture, unsigned char *image, int width, int height, int quality) { - int y; - JSAMPROW row_ptr[1]; - struct jpeg_compress_struct cjpeg; - struct jpeg_error_mgr jerr; + int y; + JSAMPROW row_ptr[1]; + struct jpeg_compress_struct cjpeg; + struct jpeg_error_mgr jerr; - cjpeg.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cjpeg); - cjpeg.image_width = width; - cjpeg.image_height = height; - cjpeg.input_components = 1; /* one colour component */ - cjpeg.in_color_space = JCS_GRAYSCALE; + cjpeg.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cjpeg); + cjpeg.image_width = width; + cjpeg.image_height = height; + cjpeg.input_components = 1; /* one colour component */ + cjpeg.in_color_space = JCS_GRAYSCALE; - jpeg_set_defaults(&cjpeg); + jpeg_set_defaults(&cjpeg); - jpeg_set_quality(&cjpeg, quality, TRUE); - cjpeg.dct_method = JDCT_FASTEST; - jpeg_stdio_dest(&cjpeg, picture); + jpeg_set_quality(&cjpeg, quality, TRUE); + cjpeg.dct_method = JDCT_FASTEST; + jpeg_stdio_dest(&cjpeg, picture); - jpeg_start_compress(&cjpeg, TRUE); + jpeg_start_compress(&cjpeg, TRUE); - row_ptr[0]=image; - for (y = 0; y < height; y++) { - jpeg_write_scanlines(&cjpeg, row_ptr, 1); - row_ptr[0] += width; - } - jpeg_finish_compress(&cjpeg); - jpeg_destroy_compress(&cjpeg); + row_ptr[0]=image; + for (y = 0; y < height; y++) { + jpeg_write_scanlines(&cjpeg, row_ptr, 1); + row_ptr[0] += width; + } + jpeg_finish_compress(&cjpeg); + jpeg_destroy_compress(&cjpeg); } @@ -312,158 +314,158 @@ static void put_jpeg_grey_file(FILE *picture, unsigned char *image, int width, i */ static void put_ppm_bgr24_file(FILE *picture, unsigned char *image, int width, int height) { - int x, y; - unsigned char *l = image; - unsigned char *u = image+width*height; - unsigned char *v = u+(width*height)/4; - int r, g, b; - int warningkiller; - unsigned char rgb[3]; - - /* ppm header - * width height - * maxval - */ - fprintf(picture, "P6\n"); - fprintf(picture, "%d %d\n", width, height); - fprintf(picture, "%d\n", 255); - for (y = 0; y < height; y++) { - - for (x = 0; x < width; x++) { - r = 76283*(((int)*l)-16)+104595*(((int)*u)-128); - g = 76283*(((int)*l)-16)- 53281*(((int)*u)-128)-25625*(((int)*v)-128); - b = 76283*(((int)*l)-16)+132252*(((int)*v)-128); - r = r>>16; - g = g>>16; - b = b>>16; - if (r < 0) - r = 0; - else if (r > 255) - r = 255; - if (g < 0) - g = 0; - else if (g > 255) - g = 255; - if (b < 0) - b = 0; - else if (b > 255) - b = 255; + int x, y; + unsigned char *l = image; + unsigned char *u = image + width * height; + unsigned char *v = u + (width * height) / 4; + int r, g, b; + int warningkiller; + unsigned char rgb[3]; + + /* ppm header + * width height + * maxval + */ + fprintf(picture, "P6\n"); + fprintf(picture, "%d %d\n", width, height); + fprintf(picture, "%d\n", 255); + for (y = 0; y < height; y++) { + + for (x = 0; x < width; x++) { + r = 76283* (((int)*l) - 16) + 104595 * (((int)*u) - 128); + g = 76283* (((int)*l) - 16)- 53281 * (((int)*u) - 128)-25625*(((int)*v)-128); + b = 76283* (((int)*l) - 16) + 132252 * (((int)*v) - 128); + r = r>>16; + g = g>>16; + b = b>>16; + if (r < 0) + r = 0; + else if (r > 255) + r = 255; + if (g < 0) + g = 0; + else if (g > 255) + g = 255; + if (b < 0) + b = 0; + else if (b > 255) + b = 255; - rgb[0] = b; - rgb[1] = g; - rgb[2] = r; + rgb[0] = b; + rgb[1] = g; + rgb[2] = r; - l++; - if (x & 1) { - u++; - v++; - } - /* ppm is rgb not bgr */ - warningkiller = fwrite(rgb, 1, 3, picture); - } - if (y & 1) { - u -= width/2; - v -= width/2; - } - } + l++; + if (x & 1) { + u++; + v++; + } + /* ppm is rgb not bgr */ + warningkiller = fwrite(rgb, 1, 3, picture); + } + if (y & 1) { + u -= width / 2; + v -= width / 2; + } + } } /* copy smartmask as an overlay into motion images and movies */ void overlay_smartmask(struct context *cnt, unsigned char *out) { - int i, x, v, width, height, line; - struct images *imgs = &cnt->imgs; - unsigned char *smartmask = imgs->smartmask_final; - unsigned char *out_y, *out_u, *out_v; - - i = imgs->motionsize; - v = i + ((imgs->motionsize) / 4); - width = imgs->width; - height = imgs->height; + int i, x, v, width, height, line; + struct images *imgs = &cnt->imgs; + unsigned char *smartmask = imgs->smartmask_final; + unsigned char *out_y, *out_u, *out_v; + + i = imgs->motionsize; + v = i + ((imgs->motionsize) / 4); + width = imgs->width; + height = imgs->height; - /* set V to 255 to make smartmask appear red */ - out_v = out + v; - out_u = out + i; - for (i = 0; i < height; i += 2){ - line = i * width; - for (x = 0; x < width; x += 2){ - if (smartmask[line + x] == 0 || - smartmask[line + x + 1] == 0 || - smartmask[line + width + x] == 0 || - smartmask[line + width + x + 1] == 0){ - *out_v = 255; - *out_u = 128; - } - out_v++; - out_u++; - } - } - out_y = out; - /* set colour intensity for smartmask */ - for (i = 0; i < imgs->motionsize; i++){ - if (smartmask[i] == 0) - *out_y = 0; - out_y++; - } + /* set V to 255 to make smartmask appear red */ + out_v = out + v; + out_u = out + i; + for (i = 0; i < height; i += 2){ + line = i * width; + for (x = 0; x < width; x += 2){ + if (smartmask[line + x] == 0 || + smartmask[line + x + 1] == 0 || + smartmask[line + width + x] == 0 || + smartmask[line + width + x + 1] == 0){ + *out_v = 255; + *out_u = 128; + } + out_v++; + out_u++; + } + } + out_y = out; + /* set colour intensity for smartmask */ + for (i = 0; i < imgs->motionsize; i++){ + if (smartmask[i] == 0) + *out_y = 0; + out_y++; + } } /* copy fixed mask as an overlay into motion images and movies */ void overlay_fixed_mask(struct context *cnt, unsigned char *out) { - int i; - struct images *imgs = &cnt->imgs; - unsigned char *motion_img = imgs->out; - unsigned char *mask = imgs->mask; - int pixel; - - /* set y to mask + motion-pixel to keep motion pixels visible on grey background*/ - for (i = 0; i < imgs->motionsize; i++){ - pixel = 255-mask[i]+motion_img[i]; - if (pixel > 255) - *out = 255; - else - *out = pixel; - out++; - } + int i; + struct images *imgs = &cnt->imgs; + unsigned char *motion_img = imgs->out; + unsigned char *mask = imgs->mask; + int pixel; + + /* set y to mask + motion-pixel to keep motion pixels visible on grey background*/ + for (i = 0; i < imgs->motionsize; i++){ + pixel = 255-mask[i]+motion_img[i]; + if (pixel > 255) + *out = 255; + else + *out = pixel; + out++; + } } /* copy largest label as an overlay into motion images and movies */ void overlay_largest_label(struct context *cnt, unsigned char *out) { - int i, x, v, width, height, line; - struct images *imgs = &cnt->imgs; - int *labels = imgs->labels; - unsigned char *out_y, *out_u, *out_v; - - i = imgs->motionsize; - v = i+((imgs->motionsize)/4); - width = imgs->width; - height = imgs->height; + int i, x, v, width, height, line; + struct images *imgs = &cnt->imgs; + int *labels = imgs->labels; + unsigned char *out_y, *out_u, *out_v; + + i = imgs->motionsize; + v = i + ((imgs->motionsize) / 4); + width = imgs->width; + height = imgs->height; - /* set U to 255 to make label appear blue */ - out_u = out+i; - out_v = out+v; - for (i = 0; i < height; i += 2){ - line = i*width; - for (x = 0; x < width; x += 2){ - if (labels[line+x] & 32768 || - labels[line+x+1] & 32768 || - labels[line+width+x] & 32768 || - labels[line+width+x+1] & 32768) { - *out_u = 255; - *out_v = 128; - } - out_u++; - out_v++; - } - } - out_y = out; - /* set intensity for coloured label to have better visibility */ - for (i = 0; i < imgs->motionsize; i++) { - if (*labels++ & 32768) - *out_y = 0; - out_y++; - } + /* set U to 255 to make label appear blue */ + out_u = out + i; + out_v = out + v; + for (i = 0; i < height; i += 2){ + line = i * width; + for (x = 0; x < width; x += 2){ + if (labels[line + x] & 32768 || + labels[line + x + 1] & 32768 || + labels[line + width + x] & 32768 || + labels[line + width + x + 1] & 32768) { + *out_u = 255; + *out_v = 128; + } + out_u++; + out_v++; + } + } + out_y = out; + /* set intensity for coloured label to have better visibility */ + for (i = 0; i < imgs->motionsize; i++) { + if (*labels++ & 32768) + *out_y = 0; + out_y++; + } } /* put_picture_mem is used for the webcam feature. Depending on the image type @@ -481,122 +483,122 @@ void overlay_largest_label(struct context *cnt, unsigned char *out) int put_picture_memory(struct context *cnt, unsigned char* dest_image, int image_size, unsigned char *image, int quality) { - switch (cnt->imgs.type) { - case VIDEO_PALETTE_YUV420P: - return put_jpeg_yuv420p_memory(dest_image, image_size, image, - cnt->imgs.width, cnt->imgs.height, quality); - case VIDEO_PALETTE_GREY: - return put_jpeg_grey_memory(dest_image, image_size, image, - cnt->imgs.width, cnt->imgs.height, quality); - } + switch (cnt->imgs.type) { + case VIDEO_PALETTE_YUV420P: + return put_jpeg_yuv420p_memory(dest_image, image_size, image, + cnt->imgs.width, cnt->imgs.height, quality); + case VIDEO_PALETTE_GREY: + return put_jpeg_grey_memory(dest_image, image_size, image, + cnt->imgs.width, cnt->imgs.height, quality); + } - return 0; + return 0; } void put_picture_fd(struct context *cnt, FILE *picture, unsigned char *image, int quality) { - if (cnt->conf.ppm) { - put_ppm_bgr24_file(picture, image, cnt->imgs.width, cnt->imgs.height); - } else { - switch (cnt->imgs.type) { - case VIDEO_PALETTE_YUV420P: - put_jpeg_yuv420p_file(picture, image, cnt->imgs.width, cnt->imgs.height, quality); - break; - case VIDEO_PALETTE_GREY: - put_jpeg_grey_file(picture, image, cnt->imgs.width, cnt->imgs.height, quality); - break; - } - } + if (cnt->conf.ppm) { + put_ppm_bgr24_file(picture, image, cnt->imgs.width, cnt->imgs.height); + } else { + switch (cnt->imgs.type) { + case VIDEO_PALETTE_YUV420P: + put_jpeg_yuv420p_file(picture, image, cnt->imgs.width, cnt->imgs.height, quality); + break; + case VIDEO_PALETTE_GREY: + put_jpeg_grey_file(picture, image, cnt->imgs.width, cnt->imgs.height, quality); + break; + } + } } void put_picture(struct context *cnt, char *file, unsigned char *image, int ftype) { - FILE *picture; + FILE *picture; - picture = myfopen(file, "w"); - if (!picture) { - /* Report to syslog - suggest solution if the problem is access rights to target dir */ - if (errno == EACCES) { - motion_log(LOG_ERR, 1, - "Can't write picture to file %s - check access rights to target directory", file); - motion_log(LOG_ERR, 1, "Thread is going to finish due to this fatal error"); - cnt->finish = 1; - cnt->restart = 0; - return; - } else { - /* If target dir is temporarily unavailable we may survive */ - motion_log(LOG_ERR, 1, "Can't write picture to file %s", file); - return; - } - } + picture = myfopen(file, "w"); + if (!picture) { + /* Report to syslog - suggest solution if the problem is access rights to target dir */ + if (errno == EACCES) { + motion_log(LOG_ERR, 1, + "Can't write picture to file %s - check access rights to target directory", file); + motion_log(LOG_ERR, 1, "Thread is going to finish due to this fatal error"); + cnt->finish = 1; + cnt->restart = 0; + return; + } else { + /* If target dir is temporarily unavailable we may survive */ + motion_log(LOG_ERR, 1, "Can't write picture to file %s", file); + return; + } + } - put_picture_fd(cnt, picture, image, cnt->conf.quality); - fclose(picture); - event(cnt, EVENT_FILECREATE, NULL, file, (void *)(unsigned long)ftype, NULL); + put_picture_fd(cnt, picture, image, cnt->conf.quality); + fclose(picture); + event(cnt, EVENT_FILECREATE, NULL, file, (void *)(unsigned long)ftype, NULL); } /* Get the pgm file used as fixed mask */ unsigned char *get_pgm(FILE *picture, int width, int height) { - int x = 0 ,y = 0, maxval; - char line[256]; - unsigned char *image; + int x = 0 ,y = 0, maxval; + char line[256]; + unsigned char *image; - line[255]=0; - - if (!fgets(line, 255, picture)) { - motion_log(LOG_ERR, 1, "Could not read from ppm file"); - return NULL; - } - - if (strncmp(line, "P5", 2)) { - motion_log(LOG_ERR, 1, "This is not a ppm file, starts with '%s'", line); - return NULL; - } - - /* skip comment */ - line[0] = '#'; - while (line[0] == '#') - if (!fgets(line, 255, picture)) - return NULL; + line[255]=0; + + if (!fgets(line, 255, picture)) { + motion_log(LOG_ERR, 1, "Could not read from ppm file"); + return NULL; + } + + if (strncmp(line, "P5", 2)) { + motion_log(LOG_ERR, 1, "This is not a ppm file, starts with '%s'", line); + return NULL; + } + + /* skip comment */ + line[0] = '#'; + while (line[0] == '#') + if (!fgets(line, 255, picture)) + return NULL; - /* check size */ - if (sscanf(line, "%d %d", &x, &y) != 2) { - motion_log(LOG_ERR, 1, "Failed reading size in pgm file"); - return NULL; - } - - if (x != width || y != height) { - motion_log(LOG_ERR, 1, "Wrong image size %dx%d should be %dx%d", x, y, width, height); - return NULL; - } + /* check size */ + if (sscanf(line, "%d %d", &x, &y) != 2) { + motion_log(LOG_ERR, 1, "Failed reading size in pgm file"); + return NULL; + } + + if (x != width || y != height) { + motion_log(LOG_ERR, 1, "Wrong image size %dx%d should be %dx%d", x, y, width, height); + return NULL; + } - /* Maximum value */ - line[0] = '#'; - while (line[0] == '#') - if (!fgets(line, 255, picture)) - return NULL; - - if (sscanf(line, "%d", &maxval) != 1) { - motion_log(LOG_ERR, 1, "Failed reading maximum value in pgm file"); - return NULL; - } - - /* read data */ - - image = mymalloc(width * height); - - for (y = 0; y < height; y++) { - if ((int)fread(&image[y * width], 1, width, picture) != width) - motion_log(LOG_ERR, 1, "Failed reading image data from pgm file"); - - for (x = 0; x < width; x++) { - image[y * width + x] = (int)image[y * width + x] * 255 / maxval; - } - } + /* Maximum value */ + line[0] = '#'; + while (line[0] == '#') + if (!fgets(line, 255, picture)) + return NULL; + + if (sscanf(line, "%d", &maxval) != 1) { + motion_log(LOG_ERR, 1, "Failed reading maximum value in pgm file"); + return NULL; + } + + /* read data */ + + image = mymalloc(width * height); + + for (y = 0; y < height; y++) { + if ((int)fread(&image[y * width], 1, width, picture) != width) + motion_log(LOG_ERR, 1, "Failed reading image data from pgm file"); + + for (x = 0; x < width; x++) { + image[y * width + x] = (int)image[y * width + x] * 255 / maxval; + } + } - return image; + return image; } /* If a mask file is asked for but does not exist this function @@ -605,89 +607,91 @@ unsigned char *get_pgm(FILE *picture, int width, int height) */ void put_fixed_mask(struct context *cnt, const char *file) { - FILE *picture; + FILE *picture; - picture = myfopen(file, "w"); - if (!picture) { - /* Report to syslog - suggest solution if the problem is access rights to target dir */ - if (errno == EACCES) { - motion_log(LOG_ERR, 1, - "can't write mask file %s - check access rights to target directory", file); - } else { - /* If target dir is temporarily unavailable we may survive */ - motion_log(LOG_ERR, 1, "can't write mask file %s", file); - } - return; - } - memset(cnt->imgs.out, 255, cnt->imgs.motionsize); /* initialize to unset */ - - /* Write pgm-header */ - fprintf(picture, "P5\n"); - fprintf(picture, "%d %d\n", cnt->conf.width, cnt->conf.height); - fprintf(picture, "%d\n", 255); - - /* write pgm image data at once */ - if ((int)fwrite(cnt->imgs.out, cnt->conf.width, cnt->conf.height, picture) != cnt->conf.height) { - motion_log(LOG_ERR, 1, "Failed writing default mask as pgm file"); - return; - } - - fclose(picture); + picture = myfopen(file, "w"); + + if (!picture) { + /* Report to syslog - suggest solution if the problem is access rights to target dir */ + if (errno == EACCES) { + motion_log(LOG_ERR, 1, + "can't write mask file %s - check access rights to target directory", file); + } else { + /* If target dir is temporarily unavailable we may survive */ + motion_log(LOG_ERR, 1, "can't write mask file %s", file); + } + return; + } - motion_log(LOG_ERR, 0, "Creating empty mask %s",cnt->conf.mask_file); - motion_log(LOG_ERR, 0, "Please edit this file and re-run motion to enable mask feature"); + memset(cnt->imgs.out, 255, cnt->imgs.motionsize); /* initialize to unset */ + + /* Write pgm-header */ + fprintf(picture, "P5\n"); + fprintf(picture, "%d %d\n", cnt->conf.width, cnt->conf.height); + fprintf(picture, "%d\n", 255); + + /* write pgm image data at once */ + if ((int)fwrite(cnt->imgs.out, cnt->conf.width, cnt->conf.height, picture) != cnt->conf.height) { + motion_log(LOG_ERR, 1, "Failed writing default mask as pgm file"); + return; + } + + fclose(picture); + + motion_log(LOG_ERR, 0, "Creating empty mask %s",cnt->conf.mask_file); + motion_log(LOG_ERR, 0, "Please edit this file and re-run motion to enable mask feature"); } /* save preview_shot */ void preview_save(struct context *cnt) { #ifdef HAVE_FFMPEG - int use_jpegpath; - int basename_len; + int use_jpegpath; + int basename_len; #endif /* HAVE_FFMPEG */ - const char *jpegpath; - char previewname[PATH_MAX]; - char filename[PATH_MAX]; - struct image_data *saved_current_image; + const char *jpegpath; + char previewname[PATH_MAX]; + char filename[PATH_MAX]; + struct image_data *saved_current_image; - if (cnt->imgs.preview_image.diffs) { - /* Save current global context */ - saved_current_image = cnt->current_image; - /* Set global context to the image we are processing */ - cnt->current_image = &cnt->imgs.preview_image; + if (cnt->imgs.preview_image.diffs) { + /* Save current global context */ + saved_current_image = cnt->current_image; + /* Set global context to the image we are processing */ + cnt->current_image = &cnt->imgs.preview_image; #ifdef HAVE_FFMPEG - /* Use filename of movie i.o. jpeg_filename when set to 'preview' */ - use_jpegpath = strcmp(cnt->conf.jpegpath, "preview"); - - if (cnt->ffmpeg_new && !use_jpegpath){ - /* Replace avi/mpg with jpg/ppm and keep the rest of the filename */ - basename_len = strlen(cnt->newfilename) - 3; - strncpy(previewname, cnt->newfilename, basename_len); - previewname[basename_len] = '\0'; - strcat(previewname, imageext(cnt)); - put_picture(cnt, previewname, cnt->imgs.preview_image.image , FTYPE_IMAGE); - } else + /* Use filename of movie i.o. jpeg_filename when set to 'preview' */ + use_jpegpath = strcmp(cnt->conf.jpegpath, "preview"); + + if (cnt->ffmpeg_new && !use_jpegpath){ + /* Replace avi/mpg with jpg/ppm and keep the rest of the filename */ + basename_len = strlen(cnt->newfilename) - 3; + strncpy(previewname, cnt->newfilename, basename_len); + previewname[basename_len] = '\0'; + strcat(previewname, imageext(cnt)); + put_picture(cnt, previewname, cnt->imgs.preview_image.image , FTYPE_IMAGE); + } else #endif /* HAVE_FFMPEG */ - { - /* Save best preview-shot also when no movies are recorded or jpegpath - * is used. Filename has to be generated - nothing available to reuse! */ - //printf("preview_shot: different filename or picture only!\n"); + { + /* Save best preview-shot also when no movies are recorded or jpegpath + * is used. Filename has to be generated - nothing available to reuse! */ + //printf("preview_shot: different filename or picture only!\n"); - /* conf.jpegpath would normally be defined but if someone deleted it by control interface - * it is better to revert to the default than fail */ - if (cnt->conf.jpegpath) - jpegpath = cnt->conf.jpegpath; - else - jpegpath = (char *)DEF_JPEGPATH; - - mystrftime(cnt, filename, sizeof(filename), jpegpath, &cnt->imgs.preview_image.timestamp_tm, NULL, 0); - snprintf(previewname, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filename, imageext(cnt)); + /* conf.jpegpath would normally be defined but if someone deleted it by control interface + * it is better to revert to the default than fail */ + if (cnt->conf.jpegpath) + jpegpath = cnt->conf.jpegpath; + else + jpegpath = (char *)DEF_JPEGPATH; + + mystrftime(cnt, filename, sizeof(filename), jpegpath, &cnt->imgs.preview_image.timestamp_tm, NULL, 0); + snprintf(previewname, PATH_MAX, "%s/%s.%s", cnt->conf.filepath, filename, imageext(cnt)); - put_picture(cnt, previewname, cnt->imgs.preview_image.image, FTYPE_IMAGE); - } + put_picture(cnt, previewname, cnt->imgs.preview_image.image, FTYPE_IMAGE); + } - /* restore global context values */ - cnt->current_image = saved_current_image; - } + /* restore global context values */ + cnt->current_image = saved_current_image; + } } diff --git a/rotate.c b/rotate.c index c7889c59..757f403f 100644 --- a/rotate.c +++ b/rotate.c @@ -1,33 +1,33 @@ /* - * rotate.c + * rotate.c * - * Module for handling image rotation. + * Module for handling image rotation. * - * Copyright 2004-2005, Per Jonsson (per@pjd.nu) - * - * This software is distributed under the GNU Public license - * Version 2. See also the file 'COPYING'. + * Copyright 2004-2005, Per Jonsson (per@pjd.nu) + * + * This software is distributed under the GNU Public license + * Version 2. See also the file 'COPYING'. * - * Image rotation is a feature of Motion that can be used when the - * camera is mounted upside-down or on the side. The module only - * supports rotation in multiples of 90 degrees. Using rotation - * increases the Motion CPU usage slightly. + * Image rotation is a feature of Motion that can be used when the + * camera is mounted upside-down or on the side. The module only + * supports rotation in multiples of 90 degrees. Using rotation + * increases the Motion CPU usage slightly. * - * Version history: - * v6 (29-Aug-2005) - simplified the code as Motion now requires - * that width and height are multiples of 16 - * v5 (3-Aug-2005) - cleanup in code comments - * - better adherence to coding standard - * - fix for __bswap_32 macro collision - * - fixed bug where initialization would be - * incomplete for invalid degrees of rotation - * - now uses motion_log for error reporting - * v4 (26-Oct-2004) - new fix for width/height from imgs/conf due to - * earlier misinterpretation - * v3 (11-Oct-2004) - cleanup of width/height from imgs/conf - * v2 (26-Sep-2004) - separation of capture/internal dimensions - * - speed optimization, including bswap - * v1 (28-Aug-2004) - initial version + * Version history: + * v6 (29-Aug-2005) - simplified the code as Motion now requires + * that width and height are multiples of 16 + * v5 (3-Aug-2005) - cleanup in code comments + * - better adherence to coding standard + * - fix for __bswap_32 macro collision + * - fixed bug where initialization would be + * incomplete for invalid degrees of rotation + * - now uses motion_log for error reporting + * v4 (26-Oct-2004) - new fix for width/height from imgs/conf due to + * earlier misinterpretation + * v3 (11-Oct-2004) - cleanup of width/height from imgs/conf + * v2 (26-Sep-2004) - separation of capture/internal dimensions + * - speed optimization, including bswap + * v1 (28-Aug-2004) - initial version */ #include "rotate.h" @@ -36,11 +36,11 @@ * We don't have a 32-bit unsigned integer type, so define it, given * a 32-bit type was found by configure. */ -# ifdef TYPE_32BIT +# ifdef TYPE_32BIT typedef unsigned TYPE_32BIT __uint32; -# else -# error "Failed to find a 32-bit integer type." -# endif +# else +# error "Failed to find a 32-bit integer type." +# endif #endif /*============================================================================= @@ -65,52 +65,52 @@ typedef unsigned TYPE_32BIT __uint32; */ /* Swap bytes in 32 bit value. This is used as a fallback and for constants. */ -#define rot__bswap_constant_32(x) \ - ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ - (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define rot__bswap_constant_32(x) \ + ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) #ifdef __GNUC__ -# if (__GNUC__ >= 2) && (i386 || __i386 || __i386__) +# if (__GNUC__ >= 2) && (i386 || __i386 || __i386__) /* We're on an Intel-compatible platform, so we can use inline Intel assembler * for the swapping. */ -# ifndef HAVE_BSWAP +# ifndef HAVE_BSWAP /* Bswap is not available, we have to use three instructions instead. */ -# define rot__bswap_32(x) \ - (__extension__ \ - ({ register __uint32 __v, __x = (x); \ - if (__builtin_constant_p (__x)) \ - __v = rot__bswap_constant_32 (__x); \ - else \ - __asm__ ("rorw $8, %w0;" \ - "rorl $16, %0;" \ - "rorw $8, %w0" \ - : "=r" (__v) \ - : "0" (__x) \ - : "cc"); \ - __v; })) -# else -# define rot__bswap_32(x) \ - (__extension__ \ - ({ register __uint32 __v, __x = (x); \ - if (__builtin_constant_p (__x)) \ - __v = rot__bswap_constant_32 (__x); \ - else \ - __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); \ - __v; })) -# endif -# else +# define rot__bswap_32(x) \ + (__extension__ \ + ({ register __uint32 __v, __x = (x); \ + if (__builtin_constant_p (__x)) \ + __v = rot__bswap_constant_32 (__x); \ + else \ + __asm__ ("rorw $8, %w0;" \ + "rorl $16, %0;" \ + "rorw $8, %w0" \ + : "=r" (__v) \ + : "0" (__x) \ + : "cc"); \ + __v; })) +# else +# define rot__bswap_32(x) \ + (__extension__ \ + ({ register __uint32 __v, __x = (x); \ + if (__builtin_constant_p (__x)) \ + __v = rot__bswap_constant_32 (__x); \ + else \ + __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); \ + __v; })) +# endif +# else /* Non-Intel platform or too old version of gcc. */ -# define rot__bswap_32(x) \ - (__extension__ \ - ({ register __uint32 __x = (x); \ - rot__bswap_constant_32 (__x); })) -# endif +# define rot__bswap_32(x) \ + (__extension__ \ + ({ register __uint32 __x = (x); \ + rot__bswap_constant_32 (__x); })) +# endif #else /* Not a GNU compiler. */ static inline __uint32 rot__bswap_32(__uint32 __bsx) { - return __bswap_constant_32 (__bsx); + return __bswap_constant_32 (__bsx); } #endif @@ -136,15 +136,15 @@ static inline __uint32 rot__bswap_32(__uint32 __bsx) */ static void reverse_inplace_quad(unsigned char *src, int size) { - __uint32 *nsrc = (__uint32 *)src; /* first quad */ - __uint32 *ndst = (__uint32 *)(src + size - 4); /* last quad */ - register __uint32 tmp; + __uint32 *nsrc = (__uint32 *)src; /* first quad */ + __uint32 *ndst = (__uint32 *)(src + size - 4); /* last quad */ + register __uint32 tmp; - while (nsrc < ndst) { - tmp = swap_bytes(*ndst); - *ndst-- = swap_bytes(*nsrc); - *nsrc++ = tmp; - } + while (nsrc < ndst) { + tmp = swap_bytes(*ndst); + *ndst-- = swap_bytes(*nsrc); + *nsrc++ = tmp; + } } /** @@ -167,17 +167,17 @@ static void reverse_inplace_quad(unsigned char *src, int size) static void rot90cw(unsigned char *src, register unsigned char *dst, int size, int width, int height) { - unsigned char *endp; - register unsigned char *base; - int j; + unsigned char *endp; + register unsigned char *base; + int j; - endp = src + size; - for (base = endp - width; base < endp; base++) { - src = base; - for (j = 0; j < height; j++, src -= width) { - *dst++ = *src; - } - } + endp = src + size; + for (base = endp - width; base < endp; base++) { + src = base; + for (j = 0; j < height; j++, src -= width) + *dst++ = *src; + + } } /** @@ -200,18 +200,18 @@ static void rot90cw(unsigned char *src, register unsigned char *dst, int size, static inline void rot90ccw(unsigned char *src, register unsigned char *dst, int size, int width, int height) { - unsigned char *endp; - register unsigned char *base; - int j; + unsigned char *endp; + register unsigned char *base; + int j; - endp = src + size; - dst = dst + size - 1; - for(base = endp - width; base < endp; base++) { - src = base; - for(j = 0; j < height; j++, src -= width) { - *dst-- = *src; - } - } + endp = src + size; + dst = dst + size - 1; + for(base = endp - width; base < endp; base++) { + src = base; + for(j = 0; j < height; j++, src -= width) + *dst-- = *src; + + } } /** @@ -228,77 +228,77 @@ static inline void rot90ccw(unsigned char *src, register unsigned char *dst, */ void rotate_init(struct context *cnt) { - int size; - - /* Make sure temp_buf isn't freed if it hasn't been allocated. */ - cnt->rotate_data.temp_buf = NULL; + int size; + + /* Make sure temp_buf isn't freed if it hasn't been allocated. */ + cnt->rotate_data.temp_buf = NULL; - /* Assign the value in conf.rotate_deg to rotate_data.degrees. This way, - * we have a value that is safe from changes caused by motion-control. - */ - if((cnt->conf.rotate_deg % 90) > 0) { - motion_log(LOG_ERR, 0, "Config option \"rotate\" not a multiple of 90: %d", - cnt->conf.rotate_deg); - cnt->conf.rotate_deg = 0; /* disable rotation */ - cnt->rotate_data.degrees = 0; /* force return below */ - } else { - cnt->rotate_data.degrees = cnt->conf.rotate_deg % 360; /* range: 0..359 */ - } + /* Assign the value in conf.rotate_deg to rotate_data.degrees. This way, + * we have a value that is safe from changes caused by motion-control. + */ + if ((cnt->conf.rotate_deg % 90) > 0) { + motion_log(LOG_ERR, 0, "Config option \"rotate\" not a multiple of 90: %d", + cnt->conf.rotate_deg); + cnt->conf.rotate_deg = 0; /* disable rotation */ + cnt->rotate_data.degrees = 0; /* force return below */ + } else { + cnt->rotate_data.degrees = cnt->conf.rotate_deg % 360; /* range: 0..359 */ + } - /* Upon entrance to this function, imgs.width and imgs.height contain the - * capture dimensions (as set in the configuration file, or read from a - * netcam source). - * - * If rotating 90 or 270 degrees, the capture dimensions and output dimensions - * are not the same. Capture dimensions will be contained in cap_width and - * cap_height in cnt->rotate_data, while output dimensions will be contained - * in imgs.width and imgs.height. - */ + /* Upon entrance to this function, imgs.width and imgs.height contain the + * capture dimensions (as set in the configuration file, or read from a + * netcam source). + * + * If rotating 90 or 270 degrees, the capture dimensions and output dimensions + * are not the same. Capture dimensions will be contained in cap_width and + * cap_height in cnt->rotate_data, while output dimensions will be contained + * in imgs.width and imgs.height. + */ - /* 1. Transfer capture dimensions into cap_width and cap_height. */ - cnt->rotate_data.cap_width = cnt->imgs.width; - cnt->rotate_data.cap_height = cnt->imgs.height; + /* 1. Transfer capture dimensions into cap_width and cap_height. */ + cnt->rotate_data.cap_width = cnt->imgs.width; + cnt->rotate_data.cap_height = cnt->imgs.height; - if((cnt->rotate_data.degrees == 90) || (cnt->rotate_data.degrees == 270)) { - /* 2. "Swap" imgs.width and imgs.height. */ - cnt->imgs.width = cnt->rotate_data.cap_height; - cnt->imgs.height = cnt->rotate_data.cap_width; - } + if ((cnt->rotate_data.degrees == 90) || (cnt->rotate_data.degrees == 270)) { + /* 2. "Swap" imgs.width and imgs.height. */ + cnt->imgs.width = cnt->rotate_data.cap_height; + cnt->imgs.height = cnt->rotate_data.cap_width; + } - /* If we're not rotating, let's exit once we have setup the capture dimensions - * and output dimensions properly. - */ - if(cnt->rotate_data.degrees == 0) { - return; - } + /* If we're not rotating, let's exit once we have setup the capture dimensions + * and output dimensions properly. + */ + if (cnt->rotate_data.degrees == 0) + return; + - switch(cnt->imgs.type) - { - case VIDEO_PALETTE_YUV420P: - /* For YUV 4:2:0 planar, the memory block used for 90/270 degrees - * rotation needs to be width x height x 1.5 bytes large. - */ - size = cnt->imgs.width * cnt->imgs.height * 3 / 2; - break; - case VIDEO_PALETTE_GREY: - /* For greyscale, the memory block used for 90/270 degrees rotation - * needs to be width x height bytes large. - */ - size = cnt->imgs.width * cnt->imgs.height; - break; - default: - cnt->rotate_data.degrees = 0; - motion_log(LOG_ERR, 0, "Unsupported palette (%d), rotation is disabled", - cnt->imgs.type); - return; - } + switch(cnt->imgs.type) + { + case VIDEO_PALETTE_YUV420P: + /* For YUV 4:2:0 planar, the memory block used for 90/270 degrees + * rotation needs to be width x height x 1.5 bytes large. + */ + size = cnt->imgs.width * cnt->imgs.height * 3 / 2; + break; + case VIDEO_PALETTE_GREY: + /* For greyscale, the memory block used for 90/270 degrees rotation + * needs to be width x height bytes large. + */ + size = cnt->imgs.width * cnt->imgs.height; + break; + default: + cnt->rotate_data.degrees = 0; + motion_log(LOG_ERR, 0, "Unsupported palette (%d), rotation is disabled", + cnt->imgs.type); + return; + } - /* Allocate memory if rotating 90 or 270 degrees, because those rotations - * cannot be performed in-place (they can, but it would be too slow). - */ - if((cnt->rotate_data.degrees == 90) || (cnt->rotate_data.degrees == 270)) { - cnt->rotate_data.temp_buf = mymalloc(size); - } + /* Allocate memory if rotating 90 or 270 degrees, because those rotations + * cannot be performed in-place (they can, but it would be too slow). + */ + if ((cnt->rotate_data.degrees == 90) || (cnt->rotate_data.degrees == 270)) + cnt->rotate_data.temp_buf = mymalloc(size); + } /** @@ -314,9 +314,9 @@ void rotate_init(struct context *cnt) */ void rotate_deinit(struct context *cnt) { - if(cnt->rotate_data.temp_buf) { - free(cnt->rotate_data.temp_buf); - } + if (cnt->rotate_data.temp_buf) + free(cnt->rotate_data.temp_buf); + } /** @@ -337,87 +337,90 @@ void rotate_deinit(struct context *cnt) */ int rotate_map(struct context *cnt, unsigned char *map) { - /* The image format is either YUV 4:2:0 planar, in which case the pixel - * data is divided in three parts: - * Y - width x height bytes - * U - width x height / 4 bytes - * V - as U - * or, it is in greyscale, in which case the pixel data simply consists - * of width x height bytes. - */ - int wh, wh4 = 0, w2 = 0, h2 = 0; /* width*height, width*height/4 etc. */ - int size, deg; - int width, height; + /* The image format is either YUV 4:2:0 planar, in which case the pixel + * data is divided in three parts: + * Y - width x height bytes + * U - width x height / 4 bytes + * V - as U + * or, it is in greyscale, in which case the pixel data simply consists + * of width x height bytes. + */ + int wh, wh4 = 0, w2 = 0, h2 = 0; /* width*height, width*height/4 etc. */ + int size, deg; + int width, height; - deg = cnt->rotate_data.degrees; - width = cnt->rotate_data.cap_width; - height = cnt->rotate_data.cap_height; + deg = cnt->rotate_data.degrees; + width = cnt->rotate_data.cap_width; + height = cnt->rotate_data.cap_height; - /* Pre-calculate some stuff: - * wh - size of the Y plane, or the entire greyscale image - * size - size of the entire memory block - * wh4 - size of the U plane, and the V plane - * w2 - width of the U plane, and the V plane - * h2 - as w2, but height instead - */ - wh = width * height; - if(cnt->imgs.type == VIDEO_PALETTE_YUV420P) { - size = wh * 3 / 2; - wh4 = wh / 4; - w2 = width / 2; - h2 = height / 2; - } - else { /* VIDEO_PALETTE_GREY */ - size = wh; - } + /* Pre-calculate some stuff: + * wh - size of the Y plane, or the entire greyscale image + * size - size of the entire memory block + * wh4 - size of the U plane, and the V plane + * w2 - width of the U plane, and the V plane + * h2 - as w2, but height instead + */ + wh = width * height; + + if (cnt->imgs.type == VIDEO_PALETTE_YUV420P) { + size = wh * 3 / 2; + wh4 = wh / 4; + w2 = width / 2; + h2 = height / 2; + } + else { /* VIDEO_PALETTE_GREY */ + size = wh; + } - switch (deg) { - case 90: - /* first do the Y part */ - rot90cw(map, cnt->rotate_data.temp_buf, wh, width, height); - if(cnt->imgs.type == VIDEO_PALETTE_YUV420P) { - /* then do U and V */ - rot90cw(map + wh, cnt->rotate_data.temp_buf + wh, wh4, w2, h2); - rot90cw(map + wh + wh4, cnt->rotate_data.temp_buf + wh + wh4, - wh4, w2, h2); - } - - /* then copy back from the temp buffer to map */ - memcpy(map, cnt->rotate_data.temp_buf, size); + switch (deg) { + case 90: + /* first do the Y part */ + rot90cw(map, cnt->rotate_data.temp_buf, wh, width, height); - break; - - case 180: - /* 180 degrees is easy - just reverse the data within - * Y, U and V. - */ - reverse_inplace_quad(map, wh); - if(cnt->imgs.type == VIDEO_PALETTE_YUV420P) { - reverse_inplace_quad(map + wh, wh4); - reverse_inplace_quad(map + wh + wh4, wh4); - } - break; + if (cnt->imgs.type == VIDEO_PALETTE_YUV420P) { + /* then do U and V */ + rot90cw(map + wh, cnt->rotate_data.temp_buf + wh, wh4, w2, h2); + rot90cw(map + wh + wh4, cnt->rotate_data.temp_buf + wh + wh4, + wh4, w2, h2); + } + + /* then copy back from the temp buffer to map */ + memcpy(map, cnt->rotate_data.temp_buf, size); - case 270: + break; + + case 180: + /* 180 degrees is easy - just reverse the data within + * Y, U and V. + */ + reverse_inplace_quad(map, wh); - /* first do the Y part */ - rot90ccw(map, cnt->rotate_data.temp_buf, wh, width, height); - if(cnt->imgs.type == VIDEO_PALETTE_YUV420P) { - /* then do U and V */ - rot90ccw(map + wh, cnt->rotate_data.temp_buf + wh, wh4, w2, h2); - rot90ccw(map + wh + wh4, cnt->rotate_data.temp_buf + wh + wh4, - wh4, w2, h2); - } - - /* then copy back from the temp buffer to map */ - memcpy(map, cnt->rotate_data.temp_buf, size); - break; - - default: - /* invalid */ - return -1; - } - - return 0; + if (cnt->imgs.type == VIDEO_PALETTE_YUV420P) { + reverse_inplace_quad(map + wh, wh4); + reverse_inplace_quad(map + wh + wh4, wh4); + } + break; + + case 270: + /* first do the Y part */ + rot90ccw(map, cnt->rotate_data.temp_buf, wh, width, height); + + if (cnt->imgs.type == VIDEO_PALETTE_YUV420P) { + /* then do U and V */ + rot90ccw(map + wh, cnt->rotate_data.temp_buf + wh, wh4, w2, h2); + rot90ccw(map + wh + wh4, cnt->rotate_data.temp_buf + wh + wh4, + wh4, w2, h2); + } + + /* then copy back from the temp buffer to map */ + memcpy(map, cnt->rotate_data.temp_buf, size); + break; + + default: + /* invalid */ + return -1; + } + + return 0; } diff --git a/video.c b/video.c index 273f4889..949b6a29 100644 --- a/video.c +++ b/video.c @@ -1,9 +1,9 @@ -/* video.c +/* video.c * - * Video stream functions for motion. - * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) - * This software is distributed under the GNU public license version 2 - * See also the file 'COPYING'. + * Video stream functions for motion. + * Copyright 2000 by Jeroen Vreeken (pe1rxq@amsat.org) + * This software is distributed under the GNU public license version 2 + * See also the file 'COPYING'. * */ #ifndef WITHOUT_V4L @@ -22,219 +22,221 @@ static void v4l_picture_controls(struct context *cnt, struct video_dev *viddev) { - int dev = viddev->fd; - struct video_picture vid_pic; - int make_change = 0; + int dev = viddev->fd; + struct video_picture vid_pic; + int make_change = 0; - if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) { + if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) { - if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - make_change = 1; - vid_pic.contrast = cnt->conf.contrast * 256; - viddev->contrast = cnt->conf.contrast; - } + make_change = 1; + vid_pic.contrast = cnt->conf.contrast * 256; + viddev->contrast = cnt->conf.contrast; + } - if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) { + if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) { - if (!make_change) { - if (ioctl(dev, VIDIOCGPICT, &vid_pic)==-1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - } + if (!make_change) { + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + } - make_change = 1; - vid_pic.colour = cnt->conf.saturation * 256; - viddev->saturation = cnt->conf.saturation; - } + make_change = 1; + vid_pic.colour = cnt->conf.saturation * 256; + viddev->saturation = cnt->conf.saturation; + } - if (cnt->conf.hue && cnt->conf.hue != viddev->hue) { + if (cnt->conf.hue && cnt->conf.hue != viddev->hue) { - if (!make_change) { - if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - } + if (!make_change) { + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + } - make_change = 1; - vid_pic.hue = cnt->conf.hue * 256; - viddev->hue = cnt->conf.hue; - } - - if (cnt->conf.autobright) { - - if (vid_do_autobright(cnt, viddev)) { - /* If we already read the VIDIOGPICT - we should not do it again */ - if (!make_change) { - if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - } - - vid_pic.brightness = viddev->brightness * 256; - make_change = 1; - } - - } else { - if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) { - if (!make_change) { - if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - } - - make_change = 1; - vid_pic.brightness = cnt->conf.brightness * 256; - viddev->brightness = cnt->conf.brightness; - } - } + make_change = 1; + vid_pic.hue = cnt->conf.hue * 256; + viddev->hue = cnt->conf.hue; + } + + if (cnt->conf.autobright) { + + if (vid_do_autobright(cnt, viddev)) { + /* If we already read the VIDIOGPICT - we should not do it again */ + if (!make_change) { + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + } + + vid_pic.brightness = viddev->brightness * 256; + make_change = 1; + } + + } else { + if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) { + if (!make_change) { + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + } + + make_change = 1; + vid_pic.brightness = cnt->conf.brightness * 256; + viddev->brightness = cnt->conf.brightness; + } + } - if (make_change) { - if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSPICT)"); - } + if (make_change) { + if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSPICT)"); + } } /******************************************************************************************* - Video4linux capture routines + Video4linux capture routines */ unsigned char *v4l_start(struct context *cnt, struct video_dev *viddev, int width, int height, int input, int norm, unsigned long freq, int tuner_number) { - int dev = viddev->fd; - struct video_capability vid_caps; - struct video_channel vid_chnl; - struct video_tuner vid_tuner; - struct video_mbuf vid_buf; - struct video_mmap vid_mmap; - void *map; + int dev = viddev->fd; + struct video_capability vid_caps; + struct video_channel vid_chnl; + struct video_tuner vid_tuner; + struct video_mbuf vid_buf; + struct video_mmap vid_mmap; + void *map; - if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCAP)"); - return (NULL); - } + if (ioctl (dev, VIDIOCGCAP, &vid_caps) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCAP)"); + return (NULL); + } - if (vid_caps.type & VID_TYPE_MONOCHROME) - viddev->v4l_fmt = VIDEO_PALETTE_GREY; + if (vid_caps.type & VID_TYPE_MONOCHROME) + viddev->v4l_fmt = VIDEO_PALETTE_GREY; - if (input != IN_DEFAULT) { - memset(&vid_chnl, 0, sizeof(struct video_channel)); - vid_chnl.channel = input; + if (input != IN_DEFAULT) { + memset(&vid_chnl, 0, sizeof(struct video_channel)); + vid_chnl.channel = input; - if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCHAN)"); - } else { - vid_chnl.channel = input; - vid_chnl.norm = norm; - if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSCHAN)"); - return (NULL); - } - } - } + if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCHAN)"); + } else { + vid_chnl.channel = input; + vid_chnl.norm = norm; + if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSCHAN)"); + return (NULL); + } + } + } - if (freq) { - memset(&vid_tuner, 0, sizeof(struct video_tuner)); - vid_tuner.tuner = tuner_number; - if (ioctl (dev, VIDIOCGTUNER, &vid_tuner) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGTUNER)"); - } else { - if (vid_tuner.flags & VIDEO_TUNER_LOW) { - freq = freq*16; /* steps of 1/16 KHz */ - } else { - freq = (freq*10)/625; - } - if (ioctl(dev, VIDIOCSFREQ, &freq) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSFREQ)"); - return (NULL); - } - if (cnt->conf.setup_mode) - motion_log(-1, 0, "Frequency set"); - } - } + if (freq) { + memset(&vid_tuner, 0, sizeof(struct video_tuner)); + vid_tuner.tuner = tuner_number; + if (ioctl (dev, VIDIOCGTUNER, &vid_tuner) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGTUNER)"); + } else { + if (vid_tuner.flags & VIDEO_TUNER_LOW) { + freq = freq * 16; /* steps of 1/16 KHz */ + } else { + freq = (freq * 10) / 625; + } + if (ioctl(dev, VIDIOCSFREQ, &freq) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSFREQ)"); + return (NULL); + } + if (cnt->conf.setup_mode) + motion_log(-1, 0, "Frequency set"); + } + } - if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { - motion_log(LOG_ERR, 0, "ioctl(VIDIOCGMBUF) - Error device does not support memory map"); - motion_log(LOG_ERR, 0, "V4L capturing using read is deprecated!"); - motion_log(LOG_ERR, 0, "Motion only supports mmap."); - return NULL; - } else { - map = mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); - viddev->size_map = vid_buf.size; - if (vid_buf.frames > 1) { - viddev->v4l_maxbuffer = 2; - viddev->v4l_buffers[0] = map; - viddev->v4l_buffers[1] = (unsigned char *)map + vid_buf.offsets[1]; - } else { - viddev->v4l_buffers[0] = map; - viddev->v4l_maxbuffer = 1; - } + if (ioctl (dev, VIDIOCGMBUF, &vid_buf) == -1) { + motion_log(LOG_ERR, 0, "ioctl(VIDIOCGMBUF) - Error device does not support memory map"); + motion_log(LOG_ERR, 0, "V4L capturing using read is deprecated!"); + motion_log(LOG_ERR, 0, "Motion only supports mmap."); + return NULL; + } else { + map = mmap(0, vid_buf.size, PROT_READ|PROT_WRITE, MAP_SHARED, dev, 0); + viddev->size_map = vid_buf.size; + if (vid_buf.frames > 1) { + viddev->v4l_maxbuffer = 2; + viddev->v4l_buffers[0] = map; + viddev->v4l_buffers[1] = (unsigned char *)map + vid_buf.offsets[1]; + } else { + viddev->v4l_buffers[0] = map; + viddev->v4l_maxbuffer = 1; + } - if (MAP_FAILED == map) { - motion_log(LOG_ERR,1,"MAP_FAILED"); - return (NULL); - } - viddev->v4l_curbuffer = 0; - vid_mmap.format = viddev->v4l_fmt; - vid_mmap.frame = viddev->v4l_curbuffer; - vid_mmap.width = width; - vid_mmap.height = height; - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_DEBUG, 1, "Failed with YUV420P, trying YUV422 palette"); - viddev->v4l_fmt = VIDEO_PALETTE_YUV422; - vid_mmap.format = viddev->v4l_fmt; - /* Try again... */ - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_DEBUG, 1, "Failed with YUV422, trying YUYV palette"); - viddev->v4l_fmt = VIDEO_PALETTE_YUYV; - vid_mmap.format = viddev->v4l_fmt; - - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_DEBUG, 1, "Failed with YUYV, trying RGB24 palette"); - viddev->v4l_fmt = VIDEO_PALETTE_RGB24; - vid_mmap.format = viddev->v4l_fmt; - /* Try again... */ - - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_DEBUG, 1, "Failed with RGB24, trying GREYSCALE palette"); - viddev->v4l_fmt = VIDEO_PALETTE_GREY; - vid_mmap.format = viddev->v4l_fmt; - /* Try one last time... */ - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_ERR, 1, "Failed with all supported palettes " - "- giving up"); - return (NULL); - } - } - } - } - } - } + if (MAP_FAILED == map) { + motion_log(LOG_ERR,1,"MAP_FAILED"); + return (NULL); + } - switch (viddev->v4l_fmt) { - case VIDEO_PALETTE_YUV420P: - viddev->v4l_bufsize = (width*height*3)/2; - motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUV420P palette"); - break; - case VIDEO_PALETTE_YUV422: - viddev->v4l_bufsize = (width*height*2); - motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUV422 palette"); - break; - case VIDEO_PALETTE_YUYV: - viddev->v4l_bufsize = (width*height*2); - motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUYV palette"); - break; - case VIDEO_PALETTE_RGB24: - viddev->v4l_bufsize = (width*height*3); - motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_RGB24 palette"); - break; - case VIDEO_PALETTE_GREY: - viddev->v4l_bufsize = width*height; - motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_GREY palette"); - break; - } - return map; + viddev->v4l_curbuffer = 0; + vid_mmap.format = viddev->v4l_fmt; + vid_mmap.frame = viddev->v4l_curbuffer; + vid_mmap.width = width; + vid_mmap.height = height; + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_DEBUG, 1, "Failed with YUV420P, trying YUV422 palette"); + viddev->v4l_fmt = VIDEO_PALETTE_YUV422; + vid_mmap.format = viddev->v4l_fmt; + /* Try again... */ + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_DEBUG, 1, "Failed with YUV422, trying YUYV palette"); + viddev->v4l_fmt = VIDEO_PALETTE_YUYV; + vid_mmap.format = viddev->v4l_fmt; + + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_DEBUG, 1, "Failed with YUYV, trying RGB24 palette"); + viddev->v4l_fmt = VIDEO_PALETTE_RGB24; + vid_mmap.format = viddev->v4l_fmt; + /* Try again... */ + + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_DEBUG, 1, "Failed with RGB24, trying GREYSCALE palette"); + viddev->v4l_fmt = VIDEO_PALETTE_GREY; + vid_mmap.format = viddev->v4l_fmt; + /* Try one last time... */ + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_ERR, 1, "Failed with all supported palettes " + "- giving up"); + return (NULL); + } + } + } + } + } + } + + switch (viddev->v4l_fmt) { + case VIDEO_PALETTE_YUV420P: + viddev->v4l_bufsize = (width * height * 3) / 2; + motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUV420P palette"); + break; + case VIDEO_PALETTE_YUV422: + viddev->v4l_bufsize = (width * height * 2); + motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUV422 palette"); + break; + case VIDEO_PALETTE_YUYV: + viddev->v4l_bufsize = (width * height * 2); + motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_YUYV palette"); + break; + case VIDEO_PALETTE_RGB24: + viddev->v4l_bufsize = (width * height * 3); + motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_RGB24 palette"); + break; + case VIDEO_PALETTE_GREY: + viddev->v4l_bufsize = width * height; + motion_log(LOG_DEBUG, 0, "Using VIDEO_PALETTE_GREY palette"); + break; + } + + return map; } @@ -256,305 +258,326 @@ unsigned char *v4l_start(struct context *cnt, struct video_dev *viddev, int widt */ int v4l_next(struct video_dev *viddev, unsigned char *map, int width, int height) { - int dev = viddev->fd; - int frame = viddev->v4l_curbuffer; - struct video_mmap vid_mmap; - unsigned char *cap_map; + int dev = viddev->fd; + int frame = viddev->v4l_curbuffer; + struct video_mmap vid_mmap; + unsigned char *cap_map; - sigset_t set, old; + sigset_t set, old; - /* MMAP method is used */ - vid_mmap.format = viddev->v4l_fmt; - vid_mmap.width = width; - vid_mmap.height = height; + /* MMAP method is used */ + vid_mmap.format = viddev->v4l_fmt; + vid_mmap.width = width; + vid_mmap.height = height; - /* Block signals during IOCTL */ - sigemptyset(&set); - sigaddset(&set, SIGCHLD); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGUSR1); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGHUP); - pthread_sigmask (SIG_BLOCK, &set, &old); + /* Block signals during IOCTL */ + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGUSR1); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + pthread_sigmask (SIG_BLOCK, &set, &old); - cap_map = viddev->v4l_buffers[viddev->v4l_curbuffer]; - viddev->v4l_curbuffer++; + cap_map = viddev->v4l_buffers[viddev->v4l_curbuffer]; + viddev->v4l_curbuffer++; - if (viddev->v4l_curbuffer >= viddev->v4l_maxbuffer) - viddev->v4l_curbuffer = 0; + if (viddev->v4l_curbuffer >= viddev->v4l_maxbuffer) + viddev->v4l_curbuffer = 0; - vid_mmap.frame = viddev->v4l_curbuffer; + vid_mmap.frame = viddev->v4l_curbuffer; - if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { - motion_log(LOG_ERR, 1, "mcapture error in proc %d", getpid()); - sigprocmask (SIG_UNBLOCK, &old, NULL); - return V4L_FATAL_ERROR; - } + if (ioctl(dev, VIDIOCMCAPTURE, &vid_mmap) == -1) { + motion_log(LOG_ERR, 1, "mcapture error in proc %d", getpid()); + sigprocmask (SIG_UNBLOCK, &old, NULL); + return V4L_FATAL_ERROR; + } - vid_mmap.frame = frame; + vid_mmap.frame = frame; - if (ioctl(dev, VIDIOCSYNC, &vid_mmap.frame) == -1) { - motion_log(LOG_ERR, 1, "sync error in proc %d", getpid()); - sigprocmask (SIG_UNBLOCK, &old, NULL); - } + if (ioctl(dev, VIDIOCSYNC, &vid_mmap.frame) == -1) { + motion_log(LOG_ERR, 1, "sync error in proc %d", getpid()); + sigprocmask (SIG_UNBLOCK, &old, NULL); + } - pthread_sigmask (SIG_UNBLOCK, &old, NULL); /*undo the signal blocking*/ + pthread_sigmask (SIG_UNBLOCK, &old, NULL); /*undo the signal blocking*/ - switch (viddev->v4l_fmt) { - case VIDEO_PALETTE_RGB24: - conv_rgb24toyuv420p(map, cap_map, width, height); - break; - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_YUV422: - conv_yuv422to420p(map, cap_map, width, height); - break; - default: - memcpy(map, cap_map, viddev->v4l_bufsize); - } + switch (viddev->v4l_fmt) { + case VIDEO_PALETTE_RGB24: + conv_rgb24toyuv420p(map, cap_map, width, height); + break; + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_YUV422: + conv_yuv422to420p(map, cap_map, width, height); + break; + default: + memcpy(map, cap_map, viddev->v4l_bufsize); + } - return 0; + return 0; } -void v4l_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height, int input, - int norm, int skip, unsigned long freq, int tuner_number) +void v4l_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, + int height, int input, int norm, int skip, unsigned long freq, int tuner_number) { - int dev = viddev->fd; - int i; - struct video_channel vid_chnl; - struct video_tuner vid_tuner; - unsigned long frequnits = freq; - - if (input != viddev->input || width != viddev->width || height != viddev->height || - freq != viddev->freq || tuner_number != viddev->tuner_number) { - if (freq) { + int dev = viddev->fd; + int i; + struct video_channel vid_chnl; + struct video_tuner vid_tuner; + unsigned long frequnits = freq; + + if (input != viddev->input || width != viddev->width || height != viddev->height || + freq != viddev->freq || tuner_number != viddev->tuner_number) { + if (freq) { - memset(&vid_tuner, 0, sizeof(struct video_tuner)); + memset(&vid_tuner, 0, sizeof(struct video_tuner)); - vid_tuner.tuner = tuner_number; - if (ioctl (dev, VIDIOCGTUNER, &vid_tuner) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGTUNER)"); - } else { - if (vid_tuner.flags & VIDEO_TUNER_LOW) { - frequnits = freq*16; /* steps of 1/16 KHz */ - } else { - frequnits = (freq*10)/625; - } - if (ioctl(dev, VIDIOCSFREQ, &frequnits) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSFREQ)"); - return; - } - } - } + vid_tuner.tuner = tuner_number; + if (ioctl (dev, VIDIOCGTUNER, &vid_tuner) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGTUNER)"); + } else { + if (vid_tuner.flags & VIDEO_TUNER_LOW) + frequnits = freq * 16; /* steps of 1/16 KHz */ + else + frequnits = (freq * 10) / 625; + - memset(&vid_chnl, 0, sizeof(struct video_channel)); - vid_chnl.channel = input; - - if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCHAN)"); - } else { - vid_chnl.channel = input; - vid_chnl.norm = norm; - if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSCHAN)"); - return; - } - } - v4l_picture_controls(cnt, viddev); - viddev->input = input; - viddev->width = width; - viddev->height = height; - viddev->freq =freq; - viddev->tuner_number = tuner_number; - /* skip a few frames if needed */ - for (i=0; i < skip; i++) - v4l_next(viddev, map, width, height); - } else { - /* No round robin - we only adjust picture controls */ - v4l_picture_controls(cnt, viddev); - } + if (ioctl(dev, VIDIOCSFREQ, &frequnits) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSFREQ)"); + return; + } + } + } + + memset(&vid_chnl, 0, sizeof(struct video_channel)); + vid_chnl.channel = input; + + if (ioctl (dev, VIDIOCGCHAN, &vid_chnl) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGCHAN)"); + } else { + vid_chnl.channel = input; + vid_chnl.norm = norm; + if (ioctl (dev, VIDIOCSCHAN, &vid_chnl) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSCHAN)"); + return; + } + } + v4l_picture_controls(cnt, viddev); + viddev->input = input; + viddev->width = width; + viddev->height = height; + viddev->freq =freq; + viddev->tuner_number = tuner_number; + /* skip a few frames if needed */ + for (i = 0; i < skip; i++) + v4l_next(viddev, map, width, height); + + } else { + /* No round robin - we only adjust picture controls */ + v4l_picture_controls(cnt, viddev); + } } static int v4l_open_vidpipe(void) { - int pipe_fd = -1; - char pipepath[255]; - char buffer[255]; - char *major; - char *minor; - struct utsname uts; + int pipe_fd = -1; + char pipepath[255]; + char buffer[255]; + char *major; + char *minor; + struct utsname uts; - if (uname(&uts) < 0) { - motion_log(LOG_ERR, 1, "Unable to execute uname"); - return -1; - } - major = strtok(uts.release, "."); - minor = strtok(NULL, "."); - if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) { - motion_log(LOG_ERR, 1, "Unable to decipher OS version"); - return -1; - } - if (strcmp(minor, "5") < 0) { - FILE *vloopbacks; - char *loop; - char *input; - char *istatus; - char *output; - char *ostatus; + if (uname(&uts) < 0) { + motion_log(LOG_ERR, 1, "Unable to execute uname"); + return -1; + } + major = strtok(uts.release, "."); + minor = strtok(NULL, "."); + + if ((major == NULL) || (minor == NULL) || (strcmp(major, "2"))) { + motion_log(LOG_ERR, 1, "Unable to decipher OS version"); + return -1; + } - vloopbacks = fopen("/proc/video/vloopback/vloopbacks", "r"); - if (!vloopbacks) { - motion_log(LOG_ERR, 1, "Failed to open '/proc/video/vloopback/vloopbacks'"); - return -1; - } - - /* Read vloopback version*/ - if (!fgets(buffer, 255, vloopbacks)) { - motion_log(LOG_ERR, 1, "Unable to read vloopback version"); - return -1; - } - - fprintf(stderr,"\t%s", buffer); - - /* Read explanation line */ - - if (!fgets(buffer, 255, vloopbacks)) { - motion_log(LOG_ERR, 1, "Unable to read vloopback explanation line"); - return -1; - } - - while (fgets(buffer, 255, vloopbacks)) { - if (strlen(buffer) > 1) { - buffer[strlen(buffer)-1] = 0; - loop=strtok(buffer, "\t"); - input=strtok(NULL, "\t"); - istatus=strtok(NULL, "\t"); - output=strtok(NULL, "\t"); - ostatus=strtok(NULL, "\t"); - if (istatus[0] == '-') { - snprintf(pipepath, 255, "/dev/%s", input); - pipe_fd = open(pipepath, O_RDWR); - if (pipe_fd >= 0) { - motion_log(-1, 0, "\tInput: /dev/%s", input); - motion_log(-1, 0, "\tOutput: /dev/%s", output); - break; - } - } - } - } - fclose(vloopbacks); - } else { - DIR *dir; - struct dirent *dirp; - const char prefix[] = "/sys/class/video4linux/"; - char *ptr, *io; - int fd; - int low = 9999; - int tfd; - int tnum; + if (strcmp(minor, "5") < 0) { + FILE *vloopbacks; + char *loop; + char *input; + char *istatus; + char *output; + char *ostatus; - if ((dir=opendir(prefix)) == NULL) { - motion_log(LOG_ERR, 1, "Failed to open '%s'", prefix); - return -1; - } - while ((dirp=readdir(dir)) != NULL) { - if (!strncmp(dirp->d_name, "video", 5)) { - strncpy(buffer, prefix, 255); - strncat(buffer, dirp->d_name, 255); - strncat(buffer, "/name", 255); - if ((fd = open(buffer, O_RDONLY)) >= 0) { - if ((read(fd, buffer, sizeof(buffer)-1)) < 0) { - close(fd); - continue; - } - ptr = strtok(buffer, " "); - if (strcmp(ptr,"Video")) { - close(fd); - continue; - } - major = strtok(NULL, " "); - minor = strtok(NULL, " "); - io = strtok(NULL, " \n"); - if (strcmp(major, "loopback") || strcmp(io, "input")) { - close(fd); - continue; - } - if ((ptr=strtok(buffer, " ")) == NULL) { - close(fd); - continue; - } - tnum = atoi(minor); - if (tnum < low) { - strcpy(buffer, "/dev/"); - strcat(buffer, dirp->d_name); - if ((tfd=open(buffer, O_RDWR)) >= 0) { - strcpy(pipepath, buffer); - if (pipe_fd >= 0) { - close(pipe_fd); - } - pipe_fd = tfd; - low = tnum; - } - } - close(fd); - } - } - } - closedir(dir); - if (pipe_fd >= 0) - motion_log(-1, 0, "Opened input of %s", pipepath); - } - return pipe_fd; + vloopbacks = fopen("/proc/video/vloopback/vloopbacks", "r"); + + if (!vloopbacks) { + motion_log(LOG_ERR, 1, "Failed to open '/proc/video/vloopback/vloopbacks'"); + return -1; + } + + /* Read vloopback version*/ + if (!fgets(buffer, 255, vloopbacks)) { + motion_log(LOG_ERR, 1, "Unable to read vloopback version"); + return -1; + } + + fprintf(stderr,"\t%s", buffer); + + /* Read explanation line */ + + if (!fgets(buffer, 255, vloopbacks)) { + motion_log(LOG_ERR, 1, "Unable to read vloopback explanation line"); + return -1; + } + + while (fgets(buffer, 255, vloopbacks)) { + if (strlen(buffer) > 1) { + buffer[strlen(buffer)-1] = 0; + loop=strtok(buffer, "\t"); + input=strtok(NULL, "\t"); + istatus=strtok(NULL, "\t"); + output=strtok(NULL, "\t"); + ostatus=strtok(NULL, "\t"); + if (istatus[0] == '-') { + snprintf(pipepath, 255, "/dev/%s", input); + pipe_fd = open(pipepath, O_RDWR); + if (pipe_fd >= 0) { + motion_log(-1, 0, "\tInput: /dev/%s", input); + motion_log(-1, 0, "\tOutput: /dev/%s", output); + break; + } + } + } + } + fclose(vloopbacks); + } else { + DIR *dir; + struct dirent *dirp; + const char prefix[] = "/sys/class/video4linux/"; + char *ptr, *io; + int fd; + int low = 9999; + int tfd; + int tnum; + + if ((dir=opendir(prefix)) == NULL) { + motion_log(LOG_ERR, 1, "Failed to open '%s'", prefix); + return -1; + } + while ((dirp=readdir(dir)) != NULL) { + if (!strncmp(dirp->d_name, "video", 5)) { + strncpy(buffer, prefix, 255); + strncat(buffer, dirp->d_name, 255); + strncat(buffer, "/name", 255); + if ((fd = open(buffer, O_RDONLY)) >= 0) { + if ((read(fd, buffer, sizeof(buffer)-1)) < 0) { + close(fd); + continue; + } + + ptr = strtok(buffer, " "); + + if (strcmp(ptr,"Video")) { + close(fd); + continue; + } + + major = strtok(NULL, " "); + minor = strtok(NULL, " "); + io = strtok(NULL, " \n"); + + if (strcmp(major, "loopback") || strcmp(io, "input")) { + close(fd); + continue; + } + + if ((ptr=strtok(buffer, " ")) == NULL) { + close(fd); + continue; + } + + tnum = atoi(minor); + + if (tnum < low) { + strcpy(buffer, "/dev/"); + strcat(buffer, dirp->d_name); + if ((tfd=open(buffer, O_RDWR)) >= 0) { + strcpy(pipepath, buffer); + + if (pipe_fd >= 0) + close(pipe_fd); + + pipe_fd = tfd; + low = tnum; + } + } + close(fd); + } + } + } + closedir(dir); + + if (pipe_fd >= 0) + motion_log(-1, 0, "Opened input of %s", pipepath); + } + + return pipe_fd; } static int v4l_startpipe(const char *dev_name, int width, int height, int type) { - int dev; - struct video_picture vid_pic; - struct video_window vid_win; + int dev; + struct video_picture vid_pic; + struct video_window vid_win; - if (!strcmp(dev_name, "-")) { - dev = v4l_open_vidpipe(); - } else { - dev = open(dev_name, O_RDWR); - } - if (dev < 0) - return(-1); + if (!strcmp(dev_name, "-")) { + dev = v4l_open_vidpipe(); + } else { + dev = open(dev_name, O_RDWR); + } + if (dev < 0) + return(-1); - if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); - return(-1); - } - vid_pic.palette=type; - if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSPICT)"); - return(-1); - } - if (ioctl(dev, VIDIOCGWIN, &vid_win) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCGWIN)"); - return(-1); - } - vid_win.height = height; - vid_win.width = width; - if (ioctl(dev, VIDIOCSWIN, &vid_win) == -1) { - motion_log(LOG_ERR, 1, "ioctl (VIDIOCSWIN)"); - return(-1); - } - return dev; + if (ioctl(dev, VIDIOCGPICT, &vid_pic) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGPICT)"); + return(-1); + } + + vid_pic.palette=type; + + if (ioctl(dev, VIDIOCSPICT, &vid_pic) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSPICT)"); + return(-1); + } + + if (ioctl(dev, VIDIOCGWIN, &vid_win) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCGWIN)"); + return(-1); + } + + vid_win.height = height; + vid_win.width = width; + + if (ioctl(dev, VIDIOCSWIN, &vid_win) == -1) { + motion_log(LOG_ERR, 1, "ioctl (VIDIOCSWIN)"); + return(-1); + } + + return dev; } static int v4l_putpipe (int dev, unsigned char *image, int size) { - return write(dev, image, size); + return write(dev, image, size); } int vid_startpipe(const char *dev_name, int width, int height, int type) { - return v4l_startpipe( dev_name, width, height, type); + return v4l_startpipe( dev_name, width, height, type); } int vid_putpipe (int dev, unsigned char *image, int size) { - return v4l_putpipe(dev, image, size); + return v4l_putpipe(dev, image, size); } #endif /*WITHOUT_V4L*/ diff --git a/video2.c b/video2.c index aacde456..10b912c7 100644 --- a/video2.c +++ b/video2.c @@ -1,22 +1,22 @@ /* - * video2.c + * video2.c * - * V4L2 interface with basically JPEG decompression support and even more ... - * Copyright 2006 Krzysztof Blaszkowski (kb@sysmikro.com.pl) - * 2007 Angel Carpintero (ack@telefonica.net) + * V4L2 interface with basically JPEG decompression support and even more ... + * Copyright 2006 Krzysztof Blaszkowski (kb@sysmikro.com.pl) + * 2007 Angel Carpintero (ack@telefonica.net) * Supported features and TODO * - preferred palette is JPEG which seems to be very popular for many 640x480 usb cams * - other supported palettes (NOT TESTED) - * V4L2_PIX_FMT_SBGGR8 ( sonix ) - * V4L2_PIX_FMT_SN9C10X ( sonix ) - * V4L2_PIX_FMT_MJPEG, ( tested ) - * V4L2_PIX_FMT_JPEG, ( tested ) - V4L2_PIX_FMT_RGB24, - V4L2_PIX_FMT_UYVY, ( tested ) - V4L2_PIX_FMT_YUV422P, - V4L2_PIX_FMT_YUV420, ( tested ) - V4L2_PIX_FMT_YUYV ( tested ) + * V4L2_PIX_FMT_SBGGR8 ( sonix ) + * V4L2_PIX_FMT_SN9C10X ( sonix ) + * V4L2_PIX_FMT_MJPEG, ( tested ) + * V4L2_PIX_FMT_JPEG, ( tested ) + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_UYVY, ( tested ) + V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_YUV420, ( tested ) + V4L2_PIX_FMT_YUYV ( tested ) * - setting tuner - NOT TESTED * - access to V4L2 device controls is missing. Partially added but requires some improvements likely. @@ -82,819 +82,819 @@ #ifndef V4L2_PIX_FMT_SBGGR8 /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ -#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */ #endif #ifndef V4L2_PIX_FMT_MJPEG -#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ #endif #ifndef V4L2_PIX_FMT_SN9C10X -#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */ +#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */ #endif -#define ZC301_V4L2_CID_DAC_MAGN V4L2_CID_PRIVATE_BASE -#define ZC301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE+1) +#define ZC301_V4L2_CID_DAC_MAGN V4L2_CID_PRIVATE_BASE +#define ZC301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE+1) static const u32 queried_ctrls[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, - V4L2_CID_RED_BALANCE, - V4L2_CID_BLUE_BALANCE, - V4L2_CID_GAMMA, - V4L2_CID_EXPOSURE, - V4L2_CID_AUTOGAIN, - V4L2_CID_GAIN, + V4L2_CID_RED_BALANCE, + V4L2_CID_BLUE_BALANCE, + V4L2_CID_GAMMA, + V4L2_CID_EXPOSURE, + V4L2_CID_AUTOGAIN, + V4L2_CID_GAIN, - ZC301_V4L2_CID_DAC_MAGN, - ZC301_V4L2_CID_GREEN_BALANCE, - 0 + ZC301_V4L2_CID_DAC_MAGN, + ZC301_V4L2_CID_GREEN_BALANCE, + 0 }; typedef struct { - int fd; - char map; - u32 fps; + int fd; + char map; + u32 fps; - struct v4l2_capability cap; - struct v4l2_format fmt; - struct v4l2_requestbuffers req; - struct v4l2_buffer buf; + struct v4l2_capability cap; + struct v4l2_format fmt; + struct v4l2_requestbuffers req; + struct v4l2_buffer buf; - netcam_buff *buffers; + netcam_buff *buffers; - s32 pframe; + s32 pframe; - u32 ctrl_flags; - struct v4l2_queryctrl *controls; + u32 ctrl_flags; + struct v4l2_queryctrl *controls; } src_v4l2_t; static int xioctl(int fd, int request, void *arg) { - int r; + int r; - do - r = ioctl(fd, request, arg); - while (-1 == r && EINTR == errno); + do + r = ioctl(fd, request, arg); + while (-1 == r && EINTR == errno); - return r; + return r; } static int v4l2_get_capability(src_v4l2_t * s) { - if (xioctl(s->fd, VIDIOC_QUERYCAP, &s->cap) < 0) { - motion_log(LOG_ERR, 0, "Not a V4L2 device?"); - return (-1); - } + if (xioctl(s->fd, VIDIOC_QUERYCAP, &s->cap) < 0) { + motion_log(LOG_ERR, 0, "Not a V4L2 device?"); + return (-1); + } - motion_log(LOG_INFO, 0, "cap.driver: \"%s\"", s->cap.driver); - motion_log(LOG_INFO, 0, "cap.card: \"%s\"", s->cap.card); - motion_log(LOG_INFO, 0, "cap.bus_info: \"%s\"", s->cap.bus_info); - motion_log(LOG_INFO, 0, "cap.capabilities=0x%08X", s->cap.capabilities); + motion_log(LOG_INFO, 0, "cap.driver: \"%s\"", s->cap.driver); + motion_log(LOG_INFO, 0, "cap.card: \"%s\"", s->cap.card); + motion_log(LOG_INFO, 0, "cap.bus_info: \"%s\"", s->cap.bus_info); + motion_log(LOG_INFO, 0, "cap.capabilities=0x%08X", s->cap.capabilities); - if (s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) - motion_log(LOG_INFO, 0, "- VIDEO_CAPTURE"); - if (s->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) - motion_log(LOG_INFO, 0, "- VIDEO_OUTPUT"); - if (s->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) - motion_log(LOG_INFO, 0, "- VIDEO_OVERLAY"); - if (s->cap.capabilities & V4L2_CAP_VBI_CAPTURE) - motion_log(LOG_INFO, 0, "- VBI_CAPTURE"); - if (s->cap.capabilities & V4L2_CAP_VBI_OUTPUT) - motion_log(LOG_INFO, 0, "- VBI_OUTPUT"); - if (s->cap.capabilities & V4L2_CAP_RDS_CAPTURE) - motion_log(LOG_INFO, 0, "- RDS_CAPTURE"); - if (s->cap.capabilities & V4L2_CAP_TUNER) - motion_log(LOG_INFO, 0, "- TUNER"); - if (s->cap.capabilities & V4L2_CAP_AUDIO) - motion_log(LOG_INFO, 0, "- AUDIO"); - if (s->cap.capabilities & V4L2_CAP_READWRITE) - motion_log(LOG_INFO, 0, "- READWRITE"); - if (s->cap.capabilities & V4L2_CAP_ASYNCIO) - motion_log(LOG_INFO, 0, "- ASYNCIO"); - if (s->cap.capabilities & V4L2_CAP_STREAMING) - motion_log(LOG_INFO, 0, "- STREAMING"); - if (s->cap.capabilities & V4L2_CAP_TIMEPERFRAME) - motion_log(LOG_INFO, 0, "- TIMEPERFRAME"); + if (s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) + motion_log(LOG_INFO, 0, "- VIDEO_CAPTURE"); + if (s->cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) + motion_log(LOG_INFO, 0, "- VIDEO_OUTPUT"); + if (s->cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) + motion_log(LOG_INFO, 0, "- VIDEO_OVERLAY"); + if (s->cap.capabilities & V4L2_CAP_VBI_CAPTURE) + motion_log(LOG_INFO, 0, "- VBI_CAPTURE"); + if (s->cap.capabilities & V4L2_CAP_VBI_OUTPUT) + motion_log(LOG_INFO, 0, "- VBI_OUTPUT"); + if (s->cap.capabilities & V4L2_CAP_RDS_CAPTURE) + motion_log(LOG_INFO, 0, "- RDS_CAPTURE"); + if (s->cap.capabilities & V4L2_CAP_TUNER) + motion_log(LOG_INFO, 0, "- TUNER"); + if (s->cap.capabilities & V4L2_CAP_AUDIO) + motion_log(LOG_INFO, 0, "- AUDIO"); + if (s->cap.capabilities & V4L2_CAP_READWRITE) + motion_log(LOG_INFO, 0, "- READWRITE"); + if (s->cap.capabilities & V4L2_CAP_ASYNCIO) + motion_log(LOG_INFO, 0, "- ASYNCIO"); + if (s->cap.capabilities & V4L2_CAP_STREAMING) + motion_log(LOG_INFO, 0, "- STREAMING"); + if (s->cap.capabilities & V4L2_CAP_TIMEPERFRAME) + motion_log(LOG_INFO, 0, "- TIMEPERFRAME"); - if (!s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { - motion_log(LOG_ERR, 0, "Device does not support capturing."); - return (-1); - } + if (!s->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) { + motion_log(LOG_ERR, 0, "Device does not support capturing."); + return (-1); + } - return (0); + return (0); } static int v4l2_select_input(src_v4l2_t * s, int in, int norm, unsigned long freq_, int tuner_number ATTRIBUTE_UNUSED) { - struct v4l2_input input; - struct v4l2_standard standard; - v4l2_std_id std_id; + struct v4l2_input input; + struct v4l2_standard standard; + v4l2_std_id std_id; - if (in == 8) - in = 0; + if (in == 8) + in = 0; - /* Set the input. */ - memset (&input, 0, sizeof (input)); - input.index = in; - if (xioctl(s->fd, VIDIOC_ENUMINPUT, &input) == -1) { - motion_log(LOG_ERR, 0, "Unable to query input %d.", in); - motion_log(LOG_ERR, 0, "VIDIOC_ENUMINPUT: %s", strerror(errno)); - return (-1); - } + /* Set the input. */ + memset (&input, 0, sizeof (input)); + input.index = in; + if (xioctl(s->fd, VIDIOC_ENUMINPUT, &input) == -1) { + motion_log(LOG_ERR, 0, "Unable to query input %d.", in); + motion_log(LOG_ERR, 0, "VIDIOC_ENUMINPUT: %s", strerror(errno)); + return (-1); + } - if (debug_level > 5) - motion_log(LOG_INFO, 0, "%s: name = \"%s\", type 0x%08X, status %08x", __FUNCTION__, input.name, - input.type, input.status); + if (debug_level > 5) + motion_log(LOG_INFO, 0, "%s: name = \"%s\", type 0x%08X, status %08x", __FUNCTION__, input.name, + input.type, input.status); - if ((input.type & V4L2_INPUT_TYPE_TUNER) && (debug_level > 5)) - motion_log(LOG_INFO, 0, "- TUNER"); + if ((input.type & V4L2_INPUT_TYPE_TUNER) && (debug_level > 5)) + motion_log(LOG_INFO, 0, "- TUNER"); - if ((input.type & V4L2_INPUT_TYPE_CAMERA) && (debug_level > 5)) - motion_log(LOG_INFO, 0, "- CAMERA"); + if ((input.type & V4L2_INPUT_TYPE_CAMERA) && (debug_level > 5)) + motion_log(LOG_INFO, 0, "- CAMERA"); - if (xioctl(s->fd, VIDIOC_S_INPUT, &in) == -1) { - motion_log(LOG_ERR, 0, "Error selecting input %d", in); - motion_log(LOG_ERR, 0, "VIDIOC_S_INPUT: %s", strerror(errno)); - return (-1); - } + if (xioctl(s->fd, VIDIOC_S_INPUT, &in) == -1) { + motion_log(LOG_ERR, 0, "Error selecting input %d", in); + motion_log(LOG_ERR, 0, "VIDIOC_S_INPUT: %s", strerror(errno)); + return (-1); + } - /* Set video standard usually webcams doesn't support the ioctl or return V4L2_STD_UNKNOWN */ - if (xioctl(s->fd, VIDIOC_G_STD, &std_id) == -1) { - if (debug_level > 5) - motion_log(LOG_INFO, 0, "Device doesn't support VIDIOC_G_STD "); - std_id = 0; // V4L2_STD_UNKNOWN = 0 - } + /* Set video standard usually webcams doesn't support the ioctl or return V4L2_STD_UNKNOWN */ + if (xioctl(s->fd, VIDIOC_G_STD, &std_id) == -1) { + if (debug_level > 5) + motion_log(LOG_INFO, 0, "Device doesn't support VIDIOC_G_STD "); + std_id = 0; // V4L2_STD_UNKNOWN = 0 + } - if (std_id) { - memset(&standard, 0, sizeof(standard)); - standard.index = 0; + if (std_id) { + memset(&standard, 0, sizeof(standard)); + standard.index = 0; - while (xioctl(s->fd, VIDIOC_ENUMSTD, &standard) == 0) { - if ((standard.id & std_id) && (debug_level > 5)) { - motion_log(LOG_INFO, 0, "- video standard %s", standard.name); - } - standard.index++; - } + while (xioctl(s->fd, VIDIOC_ENUMSTD, &standard) == 0) { + if ((standard.id & std_id) && (debug_level > 5)) { + motion_log(LOG_INFO, 0, "- video standard %s", standard.name); + } + standard.index++; + } - switch (norm) { - case 1: - std_id = V4L2_STD_NTSC; - break; - case 2: - std_id = V4L2_STD_SECAM; - break; - default: - std_id = V4L2_STD_PAL; - } + switch (norm) { + case 1: + std_id = V4L2_STD_NTSC; + break; + case 2: + std_id = V4L2_STD_SECAM; + break; + default: + std_id = V4L2_STD_PAL; + } - if (xioctl(s->fd, VIDIOC_S_STD, &std_id) == -1) { - motion_log(LOG_ERR, 0, "Error selecting standard method %d", std_id); - motion_log(LOG_ERR, 0, "VIDIOC_S_STD: %s", strerror(errno)); - } - } + if (xioctl(s->fd, VIDIOC_S_STD, &std_id) == -1) { + motion_log(LOG_ERR, 0, "Error selecting standard method %d", std_id); + motion_log(LOG_ERR, 0, "VIDIOC_S_STD: %s", strerror(errno)); + } + } - /* If this input is attached to a tuner, set the frequency. */ - if (input.type & V4L2_INPUT_TYPE_TUNER) { - struct v4l2_tuner tuner; - struct v4l2_frequency freq; + /* If this input is attached to a tuner, set the frequency. */ + if (input.type & V4L2_INPUT_TYPE_TUNER) { + struct v4l2_tuner tuner; + struct v4l2_frequency freq; - /* Query the tuners capabilities. */ + /* Query the tuners capabilities. */ - memset(&tuner, 0, sizeof(struct v4l2_tuner)); - tuner.index = input.tuner; + memset(&tuner, 0, sizeof(struct v4l2_tuner)); + tuner.index = input.tuner; - if (xioctl(s->fd, VIDIOC_G_TUNER, &tuner) == -1) { - motion_log(LOG_ERR, 0, "VIDIOC_G_TUNER: %s", strerror(errno)); - return (0); - } + if (xioctl(s->fd, VIDIOC_G_TUNER, &tuner) == -1) { + motion_log(LOG_ERR, 0, "VIDIOC_G_TUNER: %s", strerror(errno)); + return (0); + } - /* Set the frequency. */ - memset(&freq, 0, sizeof(struct v4l2_frequency)); - freq.tuner = input.tuner; - freq.type = V4L2_TUNER_ANALOG_TV; - freq.frequency = (freq_ / 1000) * 16; + /* Set the frequency. */ + memset(&freq, 0, sizeof(struct v4l2_frequency)); + freq.tuner = input.tuner; + freq.type = V4L2_TUNER_ANALOG_TV; + freq.frequency = (freq_ / 1000) * 16; - if (xioctl(s->fd, VIDIOC_S_FREQUENCY, &freq) == -1) { - motion_log(LOG_ERR, 0, "VIDIOC_S_FREQUENCY: %s", strerror(errno)); - return (0); - } - } + if (xioctl(s->fd, VIDIOC_S_FREQUENCY, &freq) == -1) { + motion_log(LOG_ERR, 0, "VIDIOC_S_FREQUENCY: %s", strerror(errno)); + return (0); + } + } - return (0); + return (0); } static int v4l2_set_pix_format(struct context *cnt, src_v4l2_t * s, int *width, int *height) { - struct v4l2_fmtdesc fmt; - short int v4l2_pal; + struct v4l2_fmtdesc fmt; + short int v4l2_pal; - static const u32 supported_formats[] = { /* higher index means better chance to be used */ - V4L2_PIX_FMT_SN9C10X, - V4L2_PIX_FMT_SBGGR8, - V4L2_PIX_FMT_MJPEG, - V4L2_PIX_FMT_JPEG, - V4L2_PIX_FMT_RGB24, - V4L2_PIX_FMT_UYVY, - V4L2_PIX_FMT_YUYV, - V4L2_PIX_FMT_YUV422P, - V4L2_PIX_FMT_YUV420, - 0 - }; + static const u32 supported_formats[] = { /* higher index means better chance to be used */ + V4L2_PIX_FMT_SN9C10X, + V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_MJPEG, + V4L2_PIX_FMT_JPEG, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_UYVY, + V4L2_PIX_FMT_YUYV, + V4L2_PIX_FMT_YUV422P, + V4L2_PIX_FMT_YUV420, + 0 + }; - short int index_format = -1; + short int index_format = -1; - memset(&fmt, 0, sizeof(struct v4l2_fmtdesc)); - fmt.index = v4l2_pal = 0; - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + memset(&fmt, 0, sizeof(struct v4l2_fmtdesc)); + fmt.index = v4l2_pal = 0; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - motion_log(LOG_INFO, 0, "Supported palettes:"); - while (xioctl(s->fd, VIDIOC_ENUM_FMT, &fmt) != -1) { - short int i; + motion_log(LOG_INFO, 0, "Supported palettes:"); + while (xioctl(s->fd, VIDIOC_ENUM_FMT, &fmt) != -1) { + short int i; - motion_log(LOG_INFO, 0, "%i: %c%c%c%c (%s)", v4l2_pal, - fmt.pixelformat >> 0, fmt.pixelformat >> 8, - fmt.pixelformat >> 16, fmt.pixelformat >> 24, fmt.description); + motion_log(LOG_INFO, 0, "%i: %c%c%c%c (%s)", v4l2_pal, + fmt.pixelformat >> 0, fmt.pixelformat >> 8, + fmt.pixelformat >> 16, fmt.pixelformat >> 24, fmt.description); - for (i = 0; supported_formats[i]; i++) - if (supported_formats[i] == fmt.pixelformat && i > index_format) { - if (cnt->conf.v4l2_palette == i) { - index_format = cnt->conf.v4l2_palette; - motion_log(LOG_INFO, 0, "Selected palette %c%c%c%c", fmt.pixelformat >> 0, - fmt.pixelformat >> 8, fmt.pixelformat >> 16, fmt.pixelformat >> 24); - i=10; - break; - } - index_format = i; - } + for (i = 0; supported_formats[i]; i++) + if (supported_formats[i] == fmt.pixelformat && i > index_format) { + if (cnt->conf.v4l2_palette == i) { + index_format = cnt->conf.v4l2_palette; + motion_log(LOG_INFO, 0, "Selected palette %c%c%c%c", fmt.pixelformat >> 0, + fmt.pixelformat >> 8, fmt.pixelformat >> 16, fmt.pixelformat >> 24); + i=10; + break; + } + index_format = i; + } - /* Chosen our selected palette, break from while */ - if (index_format == cnt->conf.v4l2_palette && index_format >= 0) - break; + /* Chosen our selected palette, break from while */ + if (index_format == cnt->conf.v4l2_palette && index_format >= 0) + break; - memset(&fmt, 0, sizeof(struct v4l2_fmtdesc)); - fmt.index = ++v4l2_pal; - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } + memset(&fmt, 0, sizeof(struct v4l2_fmtdesc)); + fmt.index = ++v4l2_pal; + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } - if (index_format >= 0) { - - u32 pixformat = supported_formats[index_format]; + if (index_format >= 0) { + + u32 pixformat = supported_formats[index_format]; - memset(&s->fmt, 0, sizeof(struct v4l2_format)); - s->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - s->fmt.fmt.pix.width = *width; - s->fmt.fmt.pix.height = *height; - s->fmt.fmt.pix.pixelformat = pixformat; - s->fmt.fmt.pix.field = V4L2_FIELD_ANY; + memset(&s->fmt, 0, sizeof(struct v4l2_format)); + s->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + s->fmt.fmt.pix.width = *width; + s->fmt.fmt.pix.height = *height; + s->fmt.fmt.pix.pixelformat = pixformat; + s->fmt.fmt.pix.field = V4L2_FIELD_ANY; - if (xioctl(s->fd, VIDIOC_TRY_FMT, &s->fmt) != -1 && s->fmt.fmt.pix.pixelformat == pixformat) { - motion_log(LOG_INFO, 0, "index_format %d Test palette %c%c%c%c (%dx%d)", index_format, pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height); + if (xioctl(s->fd, VIDIOC_TRY_FMT, &s->fmt) != -1 && s->fmt.fmt.pix.pixelformat == pixformat) { + motion_log(LOG_INFO, 0, "index_format %d Test palette %c%c%c%c (%dx%d)", index_format, pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height); - if (s->fmt.fmt.pix.width != (unsigned int) *width - || s->fmt.fmt.pix.height != (unsigned int) *height) { - motion_log(LOG_INFO, 0, "Adjusting resolution from %ix%i to %ix%i.", *width, *height, - s->fmt.fmt.pix.width, s->fmt.fmt.pix.height); - *width = s->fmt.fmt.pix.width; - *height = s->fmt.fmt.pix.height; - } + if (s->fmt.fmt.pix.width != (unsigned int) *width + || s->fmt.fmt.pix.height != (unsigned int) *height) { + motion_log(LOG_INFO, 0, "Adjusting resolution from %ix%i to %ix%i.", *width, *height, + s->fmt.fmt.pix.width, s->fmt.fmt.pix.height); + *width = s->fmt.fmt.pix.width; + *height = s->fmt.fmt.pix.height; + } - if (xioctl(s->fd, VIDIOC_S_FMT, &s->fmt) == -1) { - motion_log(LOG_ERR, 0, "Error setting pixel format."); - motion_log(LOG_ERR, 0, "VIDIOC_S_FMT: %s", strerror(errno)); - return (-1); - } + if (xioctl(s->fd, VIDIOC_S_FMT, &s->fmt) == -1) { + motion_log(LOG_ERR, 0, "Error setting pixel format."); + motion_log(LOG_ERR, 0, "VIDIOC_S_FMT: %s", strerror(errno)); + return (-1); + } - motion_log(LOG_INFO, 0, "Using palette %c%c%c%c (%dx%d) bytesperlines %d sizeimage %d colorspace %08x", pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height, s->fmt.fmt.pix.bytesperline, s->fmt.fmt.pix.sizeimage, s->fmt.fmt. pix.colorspace); + motion_log(LOG_INFO, 0, "Using palette %c%c%c%c (%dx%d) bytesperlines %d sizeimage %d colorspace %08x", pixformat >> 0, pixformat >> 8, pixformat >> 16, pixformat >> 24, *width, *height, s->fmt.fmt.pix.bytesperline, s->fmt.fmt.pix.sizeimage, s->fmt.fmt. pix.colorspace); - /* TODO: Review when it has been tested */ - if (pixformat == V4L2_PIX_FMT_MJPEG) { - struct v4l2_jpegcompression v4l2_jpeg; + /* TODO: Review when it has been tested */ + if (pixformat == V4L2_PIX_FMT_MJPEG) { + struct v4l2_jpegcompression v4l2_jpeg; - if (xioctl(s->fd, VIDIOC_G_JPEGCOMP, &v4l2_jpeg) == -1) { - motion_log(LOG_ERR, 0, "VIDIOC_G_JPEGCOMP not supported but it should"); - } else { - v4l2_jpeg.jpeg_markers |= V4L2_JPEG_MARKER_DHT; - if (xioctl(s->fd, VIDIOC_S_JPEGCOMP, &v4l2_jpeg) == -1) - motion_log(LOG_ERR, 0, "VIDIOC_S_JPEGCOMP %s", strerror(errno)); + if (xioctl(s->fd, VIDIOC_G_JPEGCOMP, &v4l2_jpeg) == -1) { + motion_log(LOG_ERR, 0, "VIDIOC_G_JPEGCOMP not supported but it should"); + } else { + v4l2_jpeg.jpeg_markers |= V4L2_JPEG_MARKER_DHT; + if (xioctl(s->fd, VIDIOC_S_JPEGCOMP, &v4l2_jpeg) == -1) + motion_log(LOG_ERR, 0, "VIDIOC_S_JPEGCOMP %s", strerror(errno)); - } - } - return 0; - } + } + } + return 0; + } - motion_log(LOG_ERR, 0, "VIDIOC_TRY_FMT failed for format %c%c%c%c (%s).", pixformat >> 0, - pixformat >> 8, pixformat >> 16, pixformat >> 24, strerror(errno)); + motion_log(LOG_ERR, 0, "VIDIOC_TRY_FMT failed for format %c%c%c%c (%s).", pixformat >> 0, + pixformat >> 8, pixformat >> 16, pixformat >> 24, strerror(errno)); - return -1; - } + return -1; + } - motion_log(LOG_ERR, 0, "Unable to find a compatible palette format."); - return (-1); + motion_log(LOG_ERR, 0, "Unable to find a compatible palette format."); + return (-1); } #if 0 static void v4l2_set_fps(src_v4l2_t * s){ - struct v4l2_streamparm* setfps; + struct v4l2_streamparm* setfps; - setfps=(struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm)); - memset(setfps, 0, sizeof(struct v4l2_streamparm)); - setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - setfps->parm.capture.timeperframe.numerator=1; - setfps->parm.capture.timeperframe.denominator=s->fps; - if (xioctl(s->fd, VIDIOC_S_PARM, setfps) == -1){ - motion_log(LOG_ERR, 0, "v4l2_set_fps VIDIOC_S_PARM %s",strerror(errno)); - } + setfps=(struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm)); + memset(setfps, 0, sizeof(struct v4l2_streamparm)); + setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + setfps->parm.capture.timeperframe.numerator=1; + setfps->parm.capture.timeperframe.denominator=s->fps; + if (xioctl(s->fd, VIDIOC_S_PARM, setfps) == -1){ + motion_log(LOG_ERR, 0, "v4l2_set_fps VIDIOC_S_PARM %s",strerror(errno)); + } } #endif static int v4l2_set_mmap(src_v4l2_t * s) { - enum v4l2_buf_type type; - u32 b; + enum v4l2_buf_type type; + u32 b; - /* Does the device support streaming? */ - if (!s->cap.capabilities & V4L2_CAP_STREAMING) - return (-1); + /* Does the device support streaming? */ + if (!s->cap.capabilities & V4L2_CAP_STREAMING) + return (-1); - memset(&s->req, 0, sizeof(struct v4l2_requestbuffers)); + memset(&s->req, 0, sizeof(struct v4l2_requestbuffers)); - s->req.count = MMAP_BUFFERS; - s->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - s->req.memory = V4L2_MEMORY_MMAP; + s->req.count = MMAP_BUFFERS; + s->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + s->req.memory = V4L2_MEMORY_MMAP; - if (xioctl(s->fd, VIDIOC_REQBUFS, &s->req) == -1) { - motion_log(LOG_ERR, 1, "Error requesting buffers for memory map."); - motion_log(LOG_ERR, 0, "VIDIOC_REQBUFS: %s", strerror(errno)); - return (-1); - } + if (xioctl(s->fd, VIDIOC_REQBUFS, &s->req) == -1) { + motion_log(LOG_ERR, 1, "Error requesting buffers for memory map."); + motion_log(LOG_ERR, 0, "VIDIOC_REQBUFS: %s", strerror(errno)); + return (-1); + } - motion_log(LOG_DEBUG, 0, "mmap information:"); - motion_log(LOG_DEBUG, 0, "frames=%d", s->req.count); + motion_log(LOG_DEBUG, 0, "mmap information:"); + motion_log(LOG_DEBUG, 0, "frames=%d", s->req.count); - if (s->req.count < MIN_MMAP_BUFFERS) { - motion_log(LOG_ERR, 0, "Insufficient buffer memory."); - return (-1); - } + if (s->req.count < MIN_MMAP_BUFFERS) { + motion_log(LOG_ERR, 0, "Insufficient buffer memory."); + return (-1); + } - s->buffers = calloc(s->req.count, sizeof(netcam_buff)); - if (!s->buffers) { - motion_log(LOG_ERR, 1, "%s: Out of memory.", __FUNCTION__); - return (-1); - } + s->buffers = calloc(s->req.count, sizeof(netcam_buff)); + if (!s->buffers) { + motion_log(LOG_ERR, 1, "%s: Out of memory.", __FUNCTION__); + return (-1); + } - for (b = 0; b < s->req.count; b++) { - struct v4l2_buffer buf; + for (b = 0; b < s->req.count; b++) { + struct v4l2_buffer buf; - memset(&buf, 0, sizeof(struct v4l2_buffer)); + memset(&buf, 0, sizeof(struct v4l2_buffer)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = b; + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = b; - if (xioctl(s->fd, VIDIOC_QUERYBUF, &buf) == -1) { - motion_log(LOG_ERR, 0, "Error querying buffer %i", b); - motion_log(LOG_ERR, 0, "VIDIOC_QUERYBUF: %s", strerror(errno)); - free(s->buffers); - return (-1); - } + if (xioctl(s->fd, VIDIOC_QUERYBUF, &buf) == -1) { + motion_log(LOG_ERR, 0, "Error querying buffer %i", b); + motion_log(LOG_ERR, 0, "VIDIOC_QUERYBUF: %s", strerror(errno)); + free(s->buffers); + return (-1); + } - s->buffers[b].size = buf.length; - s->buffers[b].ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset); + s->buffers[b].size = buf.length; + s->buffers[b].ptr = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, s->fd, buf.m.offset); - if (s->buffers[b].ptr == MAP_FAILED) { - motion_log(LOG_ERR, 0, "Error mapping buffer %i", b); - motion_log(LOG_ERR, 0, "mmap: %s", strerror(errno)); - free(s->buffers); - return (-1); - } + if (s->buffers[b].ptr == MAP_FAILED) { + motion_log(LOG_ERR, 0, "Error mapping buffer %i", b); + motion_log(LOG_ERR, 0, "mmap: %s", strerror(errno)); + free(s->buffers); + return (-1); + } - motion_log(LOG_DEBUG, 0, "%i length=%d", b, buf.length); - } + motion_log(LOG_DEBUG, 0, "%i length=%d", b, buf.length); + } - s->map = -1; + s->map = -1; - for (b = 0; b < s->req.count; b++) { - memset(&s->buf, 0, sizeof(struct v4l2_buffer)); + for (b = 0; b < s->req.count; b++) { + memset(&s->buf, 0, sizeof(struct v4l2_buffer)); - s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - s->buf.memory = V4L2_MEMORY_MMAP; - s->buf.index = b; + s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + s->buf.memory = V4L2_MEMORY_MMAP; + s->buf.index = b; - if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { - motion_log(LOG_ERR, 0, "VIDIOC_QBUF: %s", strerror(errno)); - return (-1); - } - } + if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { + motion_log(LOG_ERR, 0, "VIDIOC_QBUF: %s", strerror(errno)); + return (-1); + } + } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (xioctl(s->fd, VIDIOC_STREAMON, &type) == -1) { - motion_log(LOG_ERR, 0, "Error starting stream."); - motion_log(LOG_ERR, 0, "VIDIOC_STREAMON: %s", strerror(errno)); - return (-1); - } + if (xioctl(s->fd, VIDIOC_STREAMON, &type) == -1) { + motion_log(LOG_ERR, 0, "Error starting stream."); + motion_log(LOG_ERR, 0, "VIDIOC_STREAMON: %s", strerror(errno)); + return (-1); + } - return (0); + return (0); } static int v4l2_scan_controls(src_v4l2_t * s) { - int count, i; - struct v4l2_queryctrl queryctrl; + int count, i; + struct v4l2_queryctrl queryctrl; - memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl)); + memset(&queryctrl, 0, sizeof(struct v4l2_queryctrl)); - for (i = 0, count = 0; queried_ctrls[i]; i++) { - queryctrl.id = queried_ctrls[i]; - if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) - continue; + for (i = 0, count = 0; queried_ctrls[i]; i++) { + queryctrl.id = queried_ctrls[i]; + if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) + continue; - count++; - s->ctrl_flags |= 1 << i; - } + count++; + s->ctrl_flags |= 1 << i; + } - if (count) { - struct v4l2_queryctrl *ctrl = s->controls = calloc(count, sizeof(struct v4l2_queryctrl)); + if (count) { + struct v4l2_queryctrl *ctrl = s->controls = calloc(count, sizeof(struct v4l2_queryctrl)); - if (!ctrl) { - motion_log(LOG_ERR, 0, "%s: Insufficient buffer memory.", __FUNCTION__); - return (-1); - } + if (!ctrl) { + motion_log(LOG_ERR, 0, "%s: Insufficient buffer memory.", __FUNCTION__); + return (-1); + } - for (i = 0; queried_ctrls[i]; i++) { - if (s->ctrl_flags & (1 << i)) { - struct v4l2_control control; + for (i = 0; queried_ctrls[i]; i++) { + if (s->ctrl_flags & (1 << i)) { + struct v4l2_control control; - queryctrl.id = queried_ctrls[i]; - if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) - continue; + queryctrl.id = queried_ctrls[i]; + if (xioctl(s->fd, VIDIOC_QUERYCTRL, &queryctrl)) + continue; - memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl)); + memcpy(ctrl, &queryctrl, sizeof(struct v4l2_queryctrl)); - motion_log(LOG_INFO, 0, "found control 0x%08x, \"%s\", range %d,%d %s", ctrl->id, - ctrl->name, ctrl->minimum, ctrl->maximum, - ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "!DISABLED!" : ""); + motion_log(LOG_INFO, 0, "found control 0x%08x, \"%s\", range %d,%d %s", ctrl->id, + ctrl->name, ctrl->minimum, ctrl->maximum, + ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "!DISABLED!" : ""); - memset (&control, 0, sizeof (control)); - control.id = queried_ctrls[i]; - xioctl(s->fd, VIDIOC_G_CTRL, &control); - motion_log(LOG_INFO, 0, "\t\"%s\", default %d, current %d", ctrl->name, - ctrl->default_value, control.value); + memset (&control, 0, sizeof (control)); + control.id = queried_ctrls[i]; + xioctl(s->fd, VIDIOC_G_CTRL, &control); + motion_log(LOG_INFO, 0, "\t\"%s\", default %d, current %d", ctrl->name, + ctrl->default_value, control.value); - ctrl++; - } - } - } + ctrl++; + } + } + } - return 0; + return 0; } static int v4l2_set_control(src_v4l2_t * s, u32 cid, int value) { - int i, count; + int i, count; - if (!s->controls) - return -1; + if (!s->controls) + return -1; - for (i = 0, count = 0; queried_ctrls[i]; i++) { - if (s->ctrl_flags & (1 << i)) { - if (cid == queried_ctrls[i]) { - struct v4l2_queryctrl *ctrl = s->controls + count; - struct v4l2_control control; - int ret; + for (i = 0, count = 0; queried_ctrls[i]; i++) { + if (s->ctrl_flags & (1 << i)) { + if (cid == queried_ctrls[i]) { + struct v4l2_queryctrl *ctrl = s->controls + count; + struct v4l2_control control; + int ret; - memset (&control, 0, sizeof (control)); - control.id = queried_ctrls[i]; + memset (&control, 0, sizeof (control)); + control.id = queried_ctrls[i]; - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - value = control.value = - (value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum; - ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); - break; + switch (ctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + value = control.value = + (value * (ctrl->maximum - ctrl->minimum) / 256) + ctrl->minimum; + ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); + break; - case V4L2_CTRL_TYPE_BOOLEAN: - value = control.value = value ? 1 : 0; - ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); - break; + case V4L2_CTRL_TYPE_BOOLEAN: + value = control.value = value ? 1 : 0; + ret = xioctl(s->fd, VIDIOC_S_CTRL, &control); + break; - default: - motion_log(LOG_ERR, 0, "%s: control type not supported yet"); - return -1; - } - if (debug_level > 5) - motion_log(LOG_INFO, 0, "setting control \"%s\" to %d (ret %d %s) %s", ctrl->name, - value, ret, ret ? strerror(errno) : "", - ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "Control is DISABLED!" : ""); + default: + motion_log(LOG_ERR, 0, "%s: control type not supported yet"); + return -1; + } + if (debug_level > 5) + motion_log(LOG_INFO, 0, "setting control \"%s\" to %d (ret %d %s) %s", ctrl->name, + value, ret, ret ? strerror(errno) : "", + ctrl->flags & V4L2_CTRL_FLAG_DISABLED ? "Control is DISABLED!" : ""); - return 0; - } - count++; - } - } + return 0; + } + count++; + } + } - return -1; + return -1; } static void v4l2_picture_controls(struct context *cnt, struct video_dev *viddev) { - src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; + src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; - if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) { - viddev->contrast = cnt->conf.contrast; - v4l2_set_control(s, V4L2_CID_CONTRAST, viddev->contrast); - } + if (cnt->conf.contrast && cnt->conf.contrast != viddev->contrast) { + viddev->contrast = cnt->conf.contrast; + v4l2_set_control(s, V4L2_CID_CONTRAST, viddev->contrast); + } - if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) { - viddev->saturation = cnt->conf.saturation; - v4l2_set_control(s, V4L2_CID_SATURATION, viddev->saturation); - } + if (cnt->conf.saturation && cnt->conf.saturation != viddev->saturation) { + viddev->saturation = cnt->conf.saturation; + v4l2_set_control(s, V4L2_CID_SATURATION, viddev->saturation); + } - if (cnt->conf.hue && cnt->conf.hue != viddev->hue) { - viddev->hue = cnt->conf.hue; - v4l2_set_control(s, V4L2_CID_HUE, viddev->hue); - } + if (cnt->conf.hue && cnt->conf.hue != viddev->hue) { + viddev->hue = cnt->conf.hue; + v4l2_set_control(s, V4L2_CID_HUE, viddev->hue); + } - if (cnt->conf.autobright) { - if (vid_do_autobright(cnt, viddev)) { - if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) - v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); - } - } else { - if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) { - viddev->brightness = cnt->conf.brightness; - if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) - v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); - } - } + if (cnt->conf.autobright) { + if (vid_do_autobright(cnt, viddev)) { + if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) + v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); + } + } else { + if (cnt->conf.brightness && cnt->conf.brightness != viddev->brightness) { + viddev->brightness = cnt->conf.brightness; + if (v4l2_set_control(s, V4L2_CID_BRIGHTNESS, viddev->brightness)) + v4l2_set_control(s, V4L2_CID_GAIN, viddev->brightness); + } + } } /* public functions */ unsigned char *v4l2_start(struct context *cnt, struct video_dev *viddev, int width, int height, - int input, int norm, unsigned long freq, int tuner_number) + int input, int norm, unsigned long freq, int tuner_number) { - src_v4l2_t *s; + src_v4l2_t *s; - /* Allocate memory for the state structure. */ - if (!(s = calloc(sizeof(src_v4l2_t), 1))) { - motion_log(LOG_ERR, 0, "%s: Out of memory.", __FUNCTION__); - goto err; - } + /* Allocate memory for the state structure. */ + if (!(s = calloc(sizeof(src_v4l2_t), 1))) { + motion_log(LOG_ERR, 0, "%s: Out of memory.", __FUNCTION__); + goto err; + } - viddev->v4l2_private = s; - s->fd = viddev->fd; - s->fps = cnt->conf.frame_limit; - s->pframe = -1; + viddev->v4l2_private = s; + s->fd = viddev->fd; + s->fps = cnt->conf.frame_limit; + s->pframe = -1; - if (v4l2_get_capability(s)) { - goto err; - } + if (v4l2_get_capability(s)) { + goto err; + } - if (v4l2_select_input(s, input, norm, freq, tuner_number)) { - goto err; - } + if (v4l2_select_input(s, input, norm, freq, tuner_number)) { + goto err; + } - if (v4l2_set_pix_format(cnt ,s, &width, &height)) { - goto err; - } + if (v4l2_set_pix_format(cnt ,s, &width, &height)) { + goto err; + } - if (v4l2_scan_controls(s)) { - goto err; - } + if (v4l2_scan_controls(s)) { + goto err; + } #if 0 - v4l2_set_fps(s); + v4l2_set_fps(s); #endif - if (v4l2_set_mmap(s)) { - goto err; - } + if (v4l2_set_mmap(s)) { + goto err; + } - viddev->size_map = 0; - viddev->v4l_buffers[0] = NULL; - viddev->v4l_maxbuffer = 1; - viddev->v4l_curbuffer = 0; + viddev->size_map = 0; + viddev->v4l_buffers[0] = NULL; + viddev->v4l_maxbuffer = 1; + viddev->v4l_curbuffer = 0; - viddev->v4l_fmt = VIDEO_PALETTE_YUV420P; - viddev->v4l_bufsize = (width * height * 3) / 2; + viddev->v4l_fmt = VIDEO_PALETTE_YUV420P; + viddev->v4l_bufsize = (width * height * 3) / 2; - /* Update width and height with supported values from camera driver */ - viddev->width = width; - viddev->height = height; + /* Update width and height with supported values from camera driver */ + viddev->width = width; + viddev->height = height; - return (void *) 1; + return (void *) 1; err: - if (s) - free(s); - viddev->v4l2_private = NULL; - viddev->v4l2 = 0; - return NULL; + if (s) + free(s); + viddev->v4l2_private = NULL; + viddev->v4l2 = 0; + return NULL; } void v4l2_set_input(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height, - struct config *conf) + struct config *conf) { - int i; - int input = conf->input; - int norm = conf->norm; - int skip = conf->roundrobin_skip; - unsigned long freq = conf->frequency; - int tuner_number = conf->tuner_number; + int i; + int input = conf->input; + int norm = conf->norm; + int skip = conf->roundrobin_skip; + unsigned long freq = conf->frequency; + int tuner_number = conf->tuner_number; - if (input != viddev->input || width != viddev->width || height != viddev->height || - freq != viddev->freq || tuner_number != viddev->tuner_number) { + if (input != viddev->input || width != viddev->width || height != viddev->height || + freq != viddev->freq || tuner_number != viddev->tuner_number) { - struct timeval switchTime; + struct timeval switchTime; - v4l2_select_input((src_v4l2_t *) viddev->v4l2_private, input, norm, freq, tuner_number); + v4l2_select_input((src_v4l2_t *) viddev->v4l2_private, input, norm, freq, tuner_number); - gettimeofday(&switchTime, NULL); + gettimeofday(&switchTime, NULL); - v4l2_picture_controls(cnt, viddev); + v4l2_picture_controls(cnt, viddev); - viddev->input = input; - viddev->width = width; - viddev->height = height; - viddev->freq = freq; - viddev->tuner_number = tuner_number; + viddev->input = input; + viddev->width = width; + viddev->height = height; + viddev->freq = freq; + viddev->tuner_number = tuner_number; - /* Skip all frames captured before switchtime, capture 1 after switchtime */ - { - src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; - unsigned int counter = 0; - if (debug_level > 5) - motion_log(LOG_DEBUG, 0, "set_input_skip_frame switch_time=%ld:%ld", - switchTime.tv_sec, switchTime.tv_usec); + /* Skip all frames captured before switchtime, capture 1 after switchtime */ + { + src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; + unsigned int counter = 0; + if (debug_level > 5) + motion_log(LOG_DEBUG, 0, "set_input_skip_frame switch_time=%ld:%ld", + switchTime.tv_sec, switchTime.tv_usec); - /* Avoid hang using the number of mmap buffers */ - while(counter < s->req.count) - { - counter++; - if (v4l2_next(cnt, viddev, map, width, height)) - break; - if (s->buf.timestamp.tv_sec > switchTime.tv_sec || - (s->buf.timestamp.tv_sec == switchTime.tv_sec && s->buf.timestamp.tv_usec > switchTime.tv_usec)) - break; - if (debug_level > 5) - motion_log(LOG_DEBUG, 0, "got frame before switch timestamp=%ld:%ld", - s->buf.timestamp.tv_sec, s->buf.timestamp.tv_usec); - } - } + /* Avoid hang using the number of mmap buffers */ + while(counter < s->req.count) + { + counter++; + if (v4l2_next(cnt, viddev, map, width, height)) + break; + if (s->buf.timestamp.tv_sec > switchTime.tv_sec || + (s->buf.timestamp.tv_sec == switchTime.tv_sec && s->buf.timestamp.tv_usec > switchTime.tv_usec)) + break; + if (debug_level > 5) + motion_log(LOG_DEBUG, 0, "got frame before switch timestamp=%ld:%ld", + s->buf.timestamp.tv_sec, s->buf.timestamp.tv_usec); + } + } - /* skip a few frames if needed */ - for (i = 1; i < skip; i++) - v4l2_next(cnt, viddev, map, width, height); - } else { - /* No round robin - we only adjust picture controls */ - v4l2_picture_controls(cnt, viddev); - } + /* skip a few frames if needed */ + for (i = 1; i < skip; i++) + v4l2_next(cnt, viddev, map, width, height); + } else { + /* No round robin - we only adjust picture controls */ + v4l2_picture_controls(cnt, viddev); + } } int v4l2_next(struct context *cnt, struct video_dev *viddev, unsigned char *map, int width, int height) { - sigset_t set, old; - src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; + sigset_t set, old; + src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; - if (viddev->v4l_fmt != VIDEO_PALETTE_YUV420P) { - return V4L_FATAL_ERROR; - } + if (viddev->v4l_fmt != VIDEO_PALETTE_YUV420P) { + return V4L_FATAL_ERROR; + } - /* Block signals during IOCTL */ - sigemptyset(&set); - sigaddset(&set, SIGCHLD); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGUSR1); - sigaddset(&set, SIGTERM); - sigaddset(&set, SIGHUP); - pthread_sigmask(SIG_BLOCK, &set, &old); + /* Block signals during IOCTL */ + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIGUSR1); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGHUP); + pthread_sigmask(SIG_BLOCK, &set, &old); - if (s->pframe >= 0) { - if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { - motion_log(LOG_ERR, 0, "%s: VIDIOC_QBUF: %s", __FUNCTION__, strerror(errno)); - return (-1); - } - } + if (s->pframe >= 0) { + if (xioctl(s->fd, VIDIOC_QBUF, &s->buf) == -1) { + motion_log(LOG_ERR, 0, "%s: VIDIOC_QBUF: %s", __FUNCTION__, strerror(errno)); + return (-1); + } + } - memset(&s->buf, 0, sizeof(struct v4l2_buffer)); + memset(&s->buf, 0, sizeof(struct v4l2_buffer)); - s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - s->buf.memory = V4L2_MEMORY_MMAP; + s->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + s->buf.memory = V4L2_MEMORY_MMAP; - if (xioctl(s->fd, VIDIOC_DQBUF, &s->buf) == -1) { + if (xioctl(s->fd, VIDIOC_DQBUF, &s->buf) == -1) { - /* some drivers return EIO when there is no signal, - driver might dequeue an (empty) buffer despite - returning an error, or even stop capturing. - */ - if ( errno == EIO ){ - s->pframe++; - if ((u32)s->pframe >= s->req.count) s->pframe=0; - s->buf.index = s->pframe; + /* some drivers return EIO when there is no signal, + driver might dequeue an (empty) buffer despite + returning an error, or even stop capturing. + */ + if (errno == EIO ){ + s->pframe++; + if ((u32)s->pframe >= s->req.count) s->pframe=0; + s->buf.index = s->pframe; - motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: EIO (s->pframe %d)", __FUNCTION__,s->pframe); + motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: EIO (s->pframe %d)", __FUNCTION__,s->pframe); - return (1); - } + return (1); + } - motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: %s", __FUNCTION__, strerror(errno)); + motion_log(LOG_ERR, 0, "%s: VIDIOC_DQBUF: %s", __FUNCTION__, strerror(errno)); - return (-1); - } + return (-1); + } - s->pframe = s->buf.index; - s->buffers[s->buf.index].used = s->buf.bytesused; - s->buffers[s->buf.index].content_length = s->buf.bytesused; + s->pframe = s->buf.index; + s->buffers[s->buf.index].used = s->buf.bytesused; + s->buffers[s->buf.index].content_length = s->buf.bytesused; - pthread_sigmask(SIG_UNBLOCK, &old, NULL); /*undo the signal blocking */ + pthread_sigmask(SIG_UNBLOCK, &old, NULL); /*undo the signal blocking */ - { - netcam_buff *the_buffer = &s->buffers[s->buf.index]; + { + netcam_buff *the_buffer = &s->buffers[s->buf.index]; - switch (s->fmt.fmt.pix.pixelformat) { - case V4L2_PIX_FMT_RGB24: - conv_rgb24toyuv420p(map, (unsigned char *) the_buffer->ptr, width, height); - return 0; + switch (s->fmt.fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + conv_rgb24toyuv420p(map, (unsigned char *) the_buffer->ptr, width, height); + return 0; - case V4L2_PIX_FMT_UYVY: - conv_uyvyto420p(map, (unsigned char *) the_buffer->ptr, (unsigned)width, (unsigned)height); - return 0; + case V4L2_PIX_FMT_UYVY: + conv_uyvyto420p(map, (unsigned char *) the_buffer->ptr, (unsigned)width, (unsigned)height); + return 0; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YUV422P: - conv_yuv422to420p(map, (unsigned char *) the_buffer->ptr, width, height); - return 0; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YUV422P: + conv_yuv422to420p(map, (unsigned char *) the_buffer->ptr, width, height); + return 0; - case V4L2_PIX_FMT_YUV420: - memcpy(map, the_buffer->ptr, viddev->v4l_bufsize); - return 0; + case V4L2_PIX_FMT_YUV420: + memcpy(map, the_buffer->ptr, viddev->v4l_bufsize); + return 0; - case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_MJPEG: #ifdef MJPEGT - mjpegtoyuv420p(map, (unsigned char *) the_buffer->ptr, width, height, s->buffers[s->buf.index].content_length); - return 0; + mjpegtoyuv420p(map, (unsigned char *) the_buffer->ptr, width, height, s->buffers[s->buf.index].content_length); + return 0; #endif - case V4L2_PIX_FMT_JPEG: - return conv_jpeg2yuv420(cnt, map, the_buffer, width, height); + case V4L2_PIX_FMT_JPEG: + return conv_jpeg2yuv420(cnt, map, the_buffer, width, height); - case V4L2_PIX_FMT_SBGGR8: /* bayer */ - bayer2rgb24(cnt->imgs.common_buffer, (unsigned char *) the_buffer->ptr, width, height); - conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); - return 0; + case V4L2_PIX_FMT_SBGGR8: /* bayer */ + bayer2rgb24(cnt->imgs.common_buffer, (unsigned char *) the_buffer->ptr, width, height); + conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); + return 0; - case V4L2_PIX_FMT_SN9C10X: - sonix_decompress(map, (unsigned char *) the_buffer->ptr, width, height); - bayer2rgb24(cnt->imgs.common_buffer, map, width, height); - conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); - return 0; - } - } + case V4L2_PIX_FMT_SN9C10X: + sonix_decompress(map, (unsigned char *) the_buffer->ptr, width, height); + bayer2rgb24(cnt->imgs.common_buffer, map, width, height); + conv_rgb24toyuv420p(map, cnt->imgs.common_buffer, width, height); + return 0; + } + } - return 1; + return 1; } void v4l2_close(struct video_dev *viddev) { - src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; - enum v4l2_buf_type type; + src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; + enum v4l2_buf_type type; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - xioctl(s->fd, VIDIOC_STREAMOFF, &type); - close(s->fd); - s->fd = -1; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + xioctl(s->fd, VIDIOC_STREAMOFF, &type); + close(s->fd); + s->fd = -1; } void v4l2_cleanup(struct video_dev *viddev) { - src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; + src_v4l2_t *s = (src_v4l2_t *) viddev->v4l2_private; - if (s->buffers) { - unsigned int i; + if (s->buffers) { + unsigned int i; - for (i = 0; i < s->req.count; i++) - munmap(s->buffers[i].ptr, s->buffers[i].size); - free(s->buffers); - s->buffers = NULL; - } + for (i = 0; i < s->req.count; i++) + munmap(s->buffers[i].ptr, s->buffers[i].size); + free(s->buffers); + s->buffers = NULL; + } - if (s->controls) { - free(s->controls); - s->controls = NULL; - } + if (s->controls) { + free(s->controls); + s->controls = NULL; + } - free(s); - viddev->v4l2_private = NULL; + free(s); + viddev->v4l2_private = NULL; } #endif diff --git a/video_common.c b/video_common.c index cd91c78b..44618096 100644 --- a/video_common.c +++ b/video_common.c @@ -2,15 +2,15 @@ * * 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) + * 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'. * */ /* for rotation */ -#include "rotate.h" /* already includes motion.h */ +#include "rotate.h" /* already includes motion.h */ #include "video.h" #ifdef MJPEGT @@ -23,12 +23,12 @@ typedef 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)) +#define CLAMP(x) ((x)<0?0:((x)>255)?255:(x)) typedef struct { - int is_abs; - int len; - int val; + int is_abs; + int len; + int val; } code_table_t; /* @@ -42,55 +42,55 @@ typedef struct { */ static void sonix_decompress_init(code_table_t * table) { - int i; - int is_abs, val, len; + 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; - } + 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; + } } /* @@ -109,74 +109,74 @@ static void sonix_decompress_init(code_table_t * table) */ 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; + 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; + /* 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 - } + 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++) { + bitpos = 0; + for (row = 0; row < height; row++) { - col = 0; + 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; + /* 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; + addr = inp + (bitpos >> 3); + code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); + bitpos += 8; + *outp++ = code; - col += 2; - } + col += 2; + } - while (col < width) { - /* get bitcode from bitstream */ - addr = inp + (bitpos >> 3); - code = (addr[0] << (bitpos & 7)) | (addr[1] >> (8 - (bitpos & 7))); + 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; + /* 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; - } - } + /* 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++; - } - } + /* store pixel */ + *outp++ = CLAMP(val); + col++; + } + } - return 0; + return 0; } /* @@ -189,242 +189,246 @@ int sonix_decompress(unsigned char *outp, unsigned char *inp, int width, int hei void bayer2rgb24(unsigned char *dst, unsigned char *src, long int width, long int height) { - long int i; - unsigned char *rawpt, *scanpt; - long int size; + long int i; + unsigned char *rawpt, *scanpt; + long int size; - rawpt = src; - scanpt = dst; - size = width * height; + 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++; - } + 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; + 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; - } + /* 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; + 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++; - } - } + 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; + 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); + 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++; - } + 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; - } - } + 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; + netcam_context netcam; - if (!buff || !dst) - return 3; + if (!buff || !dst) + return 3; - if (!buff->ptr) - return 2; /* Error decoding MJPEG frame */ + 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; + 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); + 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; - } + if (setjmp(netcam.setjmp_buffer)) + return NETCAM_GENERAL_ERROR | NETCAM_JPEG_CONV_ERROR; + - return netcam_proc_jpeg(&netcam, dst); + 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; + 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])); + 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]); + 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); + 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; loopimgs.image_virgin; /* Or cnt->current_image ? */ + 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; + int make_change = 0; - if (cnt->conf.brightness) - brightness_target = cnt->conf.brightness; - else - brightness_target = 128; + 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); + 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]; - j++; - } - avg = avg / j; + for (i = 0; i < cnt->imgs.motionsize; i += 101) { + avg += image[i]; + j++; + } + avg = avg / j; - /* average is above window - turn down brightness - go for the target */ - if (avg > brightness_window_high) { - step = MIN2((avg - brightness_target) / AUTOBRIGHT_DAMPER + 1, viddev->brightness - AUTOBRIGHT_MIN); - if (viddev->brightness > step + 1 - AUTOBRIGHT_MIN) { - viddev->brightness -= step; - make_change = 1; - } - } else if (avg < brightness_window_low) { - /* average is below window - turn up brightness - go for the target */ - step = MIN2((brightness_target - avg) / AUTOBRIGHT_DAMPER + 1, AUTOBRIGHT_MAX - viddev->brightness); - if (viddev->brightness < AUTOBRIGHT_MAX - step) { - viddev->brightness += step; - make_change = 1; - } - } + /* average is above window - turn down brightness - go for the target */ + if (avg > brightness_window_high) { + step = MIN2((avg - brightness_target) / AUTOBRIGHT_DAMPER + 1, viddev->brightness - AUTOBRIGHT_MIN); + if (viddev->brightness > step + 1 - AUTOBRIGHT_MIN) { + viddev->brightness -= step; + make_change = 1; + } + } else if (avg < brightness_window_low) { + /* average is below window - turn up brightness - go for the target */ + step = MIN2((brightness_target - avg) / AUTOBRIGHT_DAMPER + 1, AUTOBRIGHT_MAX - viddev->brightness); + if (viddev->brightness < AUTOBRIGHT_MAX - step) { + viddev->brightness += step; + make_change = 1; + } + } - return make_change; + return make_change; } /***************************************************************************** - Wrappers calling the actual capture routines + Wrappers calling the actual capture routines *****************************************************************************/ #ifndef WITHOUT_V4L @@ -523,7 +527,7 @@ static struct video_dev *viddevs = NULL; */ void vid_init(void) { - pthread_mutex_init(&vid_mutex, NULL); + pthread_mutex_init(&vid_mutex, NULL); } /** @@ -533,10 +537,10 @@ void vid_init(void) */ void vid_cleanup(void) { - pthread_mutex_destroy(&vid_mutex); + pthread_mutex_destroy(&vid_mutex); } -#endif /* WITHOUT_V4L */ +#endif /* WITHOUT_V4L */ /** * vid_close @@ -546,75 +550,75 @@ void vid_cleanup(void) void vid_close(struct context *cnt) { #ifndef WITHOUT_V4L - struct video_dev *dev = viddevs; - struct video_dev *prev = NULL; + struct video_dev *dev = viddevs; + struct video_dev *prev = NULL; #endif /* WITHOUT_V4L */ - /* Cleanup the netcam part */ - if(cnt->netcam) { - motion_log(LOG_DEBUG, 0, "vid_close: calling netcam_cleanup"); - netcam_cleanup(cnt->netcam, 0); - cnt->netcam = NULL; - return; - } + /* Cleanup the netcam part */ + if (cnt->netcam) { + motion_log(LOG_DEBUG, 0, "vid_close: calling netcam_cleanup"); + netcam_cleanup(cnt->netcam, 0); + cnt->netcam = NULL; + return; + } #ifndef WITHOUT_V4L - /* Cleanup the v4l part */ - pthread_mutex_lock(&vid_mutex); - while (dev) { - if (dev->fd == cnt->video_dev) - break; - prev = dev; - dev = dev->next; - } - pthread_mutex_unlock(&vid_mutex); + /* Cleanup the v4l part */ + pthread_mutex_lock(&vid_mutex); + while (dev) { + if (dev->fd == cnt->video_dev) + break; + prev = dev; + dev = dev->next; + } + pthread_mutex_unlock(&vid_mutex); - /* Set it as closed in thread context */ - cnt->video_dev = -1; + /* Set it as closed in thread context */ + cnt->video_dev = -1; - if (dev == NULL) { - motion_log(LOG_ERR, 0, "vid_close: Unable to find video device"); - return; - } + if (dev == NULL) { + motion_log(LOG_ERR, 0, "vid_close: Unable to find video device"); + return; + } - if( --dev->usage_count == 0) { - motion_log(LOG_INFO, 0, "Closing video device %s", dev->video_device); + if (--dev->usage_count == 0) { + motion_log(LOG_INFO, 0, "Closing video device %s", dev->video_device); #ifdef MOTION_V4L2 - if (dev->v4l2) { - v4l2_close(dev); - v4l2_cleanup(dev); - } else { + if (dev->v4l2) { + v4l2_close(dev); + v4l2_cleanup(dev); + } else { #endif - close(dev->fd); - munmap(viddevs->v4l_buffers[0], viddevs->size_map); - munmap(viddevs->v4l_buffers[1], viddevs->size_map); + close(dev->fd); + munmap(viddevs->v4l_buffers[0], viddevs->size_map); + munmap(viddevs->v4l_buffers[1], viddevs->size_map); #ifdef MOTION_V4L2 - } + } #endif - dev->fd = -1; - pthread_mutex_lock(&vid_mutex); - /* Remove from list */ - if (prev == NULL) - viddevs = dev->next; - else - prev->next = dev->next; - pthread_mutex_unlock(&vid_mutex); + dev->fd = -1; + pthread_mutex_lock(&vid_mutex); + /* Remove from list */ + if (prev == NULL) + viddevs = dev->next; + else + prev->next = dev->next; + pthread_mutex_unlock(&vid_mutex); - pthread_mutexattr_destroy(&dev->attr); - pthread_mutex_destroy(&dev->mutex); - free(dev); - } else { - motion_log(LOG_INFO, 0, "Still %d users of video device %s, so we don't close it now", dev->usage_count, dev->video_device); - /* There is still at least one thread using this device - * If we own it, release it - */ - if (dev->owner == cnt->threadnr) { - dev->frames = 0; - dev->owner = -1; - pthread_mutex_unlock(&dev->mutex); - } - } + pthread_mutexattr_destroy(&dev->attr); + pthread_mutex_destroy(&dev->mutex); + free(dev); + } else { + motion_log(LOG_INFO, 0, "Still %d users of video device %s, so we don't close it now", dev->usage_count, dev->video_device); + /* There is still at least one thread using this device + * If we own it, release it + */ + if (dev->owner == cnt->threadnr) { + dev->frames = 0; + dev->owner = -1; + pthread_mutex_unlock(&dev->mutex); + } + } #endif /* WITHOUT_V4L */ } @@ -645,172 +649,173 @@ void vid_close(struct context *cnt) */ static int vid_v4lx_start(struct context *cnt) { - struct config *conf = &cnt->conf; - int fd = -1; - struct video_dev *dev; + struct config *conf = &cnt->conf; + int fd = -1; + struct video_dev *dev; - int width, height, input, norm, tuner_number; - unsigned long frequency; + int width, height, input, norm, tuner_number; + unsigned long frequency; - /* We use width and height from conf in this function. They will be assigned - * to width and height in imgs here, and cap_width and cap_height in - * rotate_data won't be set until in rotate_init. - * Motion requires that width and height is a multiple of 16 so we check - * for this first. - */ - if (conf->width % 16) { - motion_log(LOG_ERR, 0, "config image width (%d) is not modulo 16", conf->width); - return -1; - } + /* We use width and height from conf in this function. They will be assigned + * to width and height in imgs here, and cap_width and cap_height in + * rotate_data won't be set until in rotate_init. + * Motion requires that width and height is a multiple of 16 so we check + * for this first. + */ + if (conf->width % 16) { + motion_log(LOG_ERR, 0, "config image width (%d) is not modulo 16", conf->width); + return -1; + } - if (conf->height % 16) { - motion_log(LOG_ERR, 0, "config image height (%d) is not modulo 16", conf->height); - return -1; - } + if (conf->height % 16) { + motion_log(LOG_ERR, 0, "config image height (%d) is not modulo 16", conf->height); + return -1; + } - width = conf->width; - height = conf->height; - input = conf->input; - norm = conf->norm; - frequency = conf->frequency; - tuner_number = conf->tuner_number; + width = conf->width; + height = conf->height; + input = conf->input; + norm = conf->norm; + frequency = conf->frequency; + tuner_number = conf->tuner_number; - pthread_mutex_lock(&vid_mutex); + pthread_mutex_lock(&vid_mutex); - /* Transfer width and height from conf to imgs. The imgs values are the ones - * that is used internally in Motion. That way, setting width and height via - * http remote control won't screw things up. - */ - cnt->imgs.width = width; - cnt->imgs.height = height; + /* Transfer width and height from conf to imgs. The imgs values are the ones + * that is used internally in Motion. That way, setting width and height via + * http remote control won't screw things up. + */ + cnt->imgs.width = width; + cnt->imgs.height = height; - /* First we walk through the already discovered video devices to see - * if we have already setup the same device before. If this is the case - * the device is a Round Robin device and we set the basic settings - * and return the file descriptor - */ - dev = viddevs; - while (dev) { - if (!strcmp(conf->video_device, dev->video_device)) { - dev->usage_count++; - cnt->imgs.type = dev->v4l_fmt; - switch (cnt->imgs.type) { - case VIDEO_PALETTE_GREY: - cnt->imgs.motionsize = width * height; - cnt->imgs.size = width * height; - break; - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_YUV422: - cnt->imgs.type = VIDEO_PALETTE_YUV420P; - case VIDEO_PALETTE_YUV420P: - cnt->imgs.motionsize = width * height; - cnt->imgs.size = (width * height * 3) / 2; - break; - } - pthread_mutex_unlock(&vid_mutex); - return dev->fd; - } - dev = dev->next; - } + /* First we walk through the already discovered video devices to see + * if we have already setup the same device before. If this is the case + * the device is a Round Robin device and we set the basic settings + * and return the file descriptor + */ + dev = viddevs; + while (dev) { + if (!strcmp(conf->video_device, dev->video_device)) { + dev->usage_count++; + cnt->imgs.type = dev->v4l_fmt; - dev = mymalloc(sizeof(struct video_dev)); - memset(dev, 0, sizeof(struct video_dev)); + switch (cnt->imgs.type) { + case VIDEO_PALETTE_GREY: + cnt->imgs.motionsize = width * height; + cnt->imgs.size = width * height; + break; + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_YUV422: + cnt->imgs.type = VIDEO_PALETTE_YUV420P; + case VIDEO_PALETTE_YUV420P: + cnt->imgs.motionsize = width * height; + cnt->imgs.size = (width * height * 3) / 2; + break; + } + pthread_mutex_unlock(&vid_mutex); + return dev->fd; + } + dev = dev->next; + } - dev->video_device = conf->video_device; + dev = mymalloc(sizeof(struct video_dev)); + memset(dev, 0, sizeof(struct video_dev)); - fd = open(dev->video_device, O_RDWR); + dev->video_device = conf->video_device; - if (fd < 0) { - motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device); - free(dev); - pthread_mutex_unlock(&vid_mutex); - return -1; - } + fd = open(dev->video_device, O_RDWR); - pthread_mutexattr_init(&dev->attr); - pthread_mutex_init(&dev->mutex, &dev->attr); + if (fd < 0) { + motion_log(LOG_ERR, 1, "Failed to open video device %s", conf->video_device); + free(dev); + pthread_mutex_unlock(&vid_mutex); + return -1; + } - dev->usage_count = 1; - dev->fd = fd; - dev->input = input; - dev->height = height; - dev->width = width; - dev->freq = frequency; - dev->tuner_number = tuner_number; + pthread_mutexattr_init(&dev->attr); + pthread_mutex_init(&dev->mutex, &dev->attr); - /* We set brightness, contrast, saturation and hue = 0 so that they only get - * set if the config is not zero. - */ - dev->brightness = 0; - dev->contrast = 0; - dev->saturation = 0; - dev->hue = 0; - dev->owner = -1; - dev->v4l_fmt = VIDEO_PALETTE_YUV420P; + dev->usage_count = 1; + dev->fd = fd; + dev->input = input; + dev->height = height; + dev->width = width; + dev->freq = frequency; + dev->tuner_number = tuner_number; + + /* We set brightness, contrast, saturation and hue = 0 so that they only get + * set if the config is not zero. + */ + dev->brightness = 0; + dev->contrast = 0; + dev->saturation = 0; + dev->hue = 0; + dev->owner = -1; + dev->v4l_fmt = VIDEO_PALETTE_YUV420P; #ifdef MOTION_V4L2 - /* First lets try V4L2 and if it's not supported V4L1 */ + /* First lets try V4L2 and if it's not supported V4L1 */ - dev->v4l2 = 1; + dev->v4l2 = 1; - if (!v4l2_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { - /* restore width & height before test with v4l - * because could be changed in v4l2_start () - */ - dev->width = width; - dev->height = height; + if (!v4l2_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { + /* restore width & height before test with v4l + * because could be changed in v4l2_start () + */ + dev->width = width; + dev->height = height; #endif - if (!v4l_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { - close(dev->fd); - pthread_mutexattr_destroy(&dev->attr); - pthread_mutex_destroy(&dev->mutex); - free(dev); + if (!v4l_start(cnt, dev, width, height, input, norm, frequency, tuner_number)) { + close(dev->fd); + pthread_mutexattr_destroy(&dev->attr); + pthread_mutex_destroy(&dev->mutex); + free(dev); - pthread_mutex_unlock(&vid_mutex); - return -1; - } + pthread_mutex_unlock(&vid_mutex); + return -1; + } #ifdef MOTION_V4L2 - dev->v4l2 = 0; - } + dev->v4l2 = 0; + } #endif - if (dev->v4l2 == 0) { - motion_log(-1, 0, "Using V4L1"); - } else { - motion_log(-1, 0, "Using V4L2"); - /* Update width & height because could be changed in v4l2_start () */ - width = dev->width; - height = dev->height; - cnt->imgs.width = width; - cnt->imgs.height = height; - } + if (dev->v4l2 == 0) { + motion_log(-1, 0, "Using V4L1"); + } else { + motion_log(-1, 0, "Using V4L2"); + /* Update width & height because could be changed in v4l2_start () */ + width = dev->width; + height = dev->height; + cnt->imgs.width = width; + cnt->imgs.height = height; + } - cnt->imgs.type = dev->v4l_fmt; + cnt->imgs.type = dev->v4l_fmt; - switch (cnt->imgs.type) { - case VIDEO_PALETTE_GREY: - cnt->imgs.size = width * height; - cnt->imgs.motionsize = width * height; - break; - case VIDEO_PALETTE_YUYV: - case VIDEO_PALETTE_RGB24: - case VIDEO_PALETTE_YUV422: - cnt->imgs.type = VIDEO_PALETTE_YUV420P; - case VIDEO_PALETTE_YUV420P: - cnt->imgs.size = (width * height * 3) / 2; - cnt->imgs.motionsize = width * height; - break; - } + switch (cnt->imgs.type) { + case VIDEO_PALETTE_GREY: + cnt->imgs.size = width * height; + cnt->imgs.motionsize = width * height; + break; + case VIDEO_PALETTE_YUYV: + case VIDEO_PALETTE_RGB24: + case VIDEO_PALETTE_YUV422: + cnt->imgs.type = VIDEO_PALETTE_YUV420P; + case VIDEO_PALETTE_YUV420P: + cnt->imgs.size = (width * height * 3) / 2; + cnt->imgs.motionsize = width * height; + break; + } - /* Insert into linked list */ - dev->next = viddevs; - viddevs = dev; + /* Insert into linked list */ + dev->next = viddevs; + viddevs = dev; - pthread_mutex_unlock(&vid_mutex); + pthread_mutex_unlock(&vid_mutex); return fd; } -#endif /*WITHOUT_V4L */ +#endif /*WITHOUT_V4L */ @@ -838,25 +843,25 @@ return fd; int vid_start(struct context *cnt) { - struct config *conf = &cnt->conf; - int dev = -1; + struct config *conf = &cnt->conf; + int dev = -1; - if (conf->netcam_url) { - dev = netcam_start(cnt); - if (dev < 0) { - netcam_cleanup(cnt->netcam, 1); - cnt->netcam = NULL; - } - } + if (conf->netcam_url) { + dev = netcam_start(cnt); + if (dev < 0) { + netcam_cleanup(cnt->netcam, 1); + cnt->netcam = NULL; + } + } #ifdef WITHOUT_V4L - else - motion_log(LOG_ERR, 0,"You must setup netcam_url"); + else + motion_log(LOG_ERR, 0,"You must setup netcam_url"); #else - else - dev = vid_v4lx_start(cnt); -#endif /*WITHOUT_V4L */ + else + dev = vid_v4lx_start(cnt); +#endif /*WITHOUT_V4L */ - return dev; + return dev; } /** @@ -881,69 +886,69 @@ int vid_start(struct context *cnt) */ int vid_next(struct context *cnt, unsigned char *map) { - int ret = -2; - struct config *conf = &cnt->conf; + int ret = -2; + struct config *conf = &cnt->conf; - if (conf->netcam_url) { - if (cnt->video_dev == -1) - return NETCAM_GENERAL_ERROR; + if (conf->netcam_url) { + if (cnt->video_dev == -1) + return NETCAM_GENERAL_ERROR; - return netcam_next(cnt, map); - } + return netcam_next(cnt, map); + } #ifndef WITHOUT_V4L - /* We start a new block so we can make declarations without breaking - * gcc 2.95 or older - */ - { - struct video_dev *dev; - int width, height; + /* We start a new block so we can make declarations without breaking + * gcc 2.95 or older + */ + { + struct video_dev *dev; + int width, height; - /* NOTE: Since this is a capture, we need to use capture dimensions. */ - width = cnt->rotate_data.cap_width; - height = cnt->rotate_data.cap_height; + /* NOTE: Since this is a capture, we need to use capture dimensions. */ + width = cnt->rotate_data.cap_width; + height = cnt->rotate_data.cap_height; - pthread_mutex_lock(&vid_mutex); - dev = viddevs; - while (dev) { - if (dev->fd == cnt->video_dev) - break; - dev = dev->next; - } - pthread_mutex_unlock(&vid_mutex); + pthread_mutex_lock(&vid_mutex); + dev = viddevs; + while (dev) { + if (dev->fd == cnt->video_dev) + break; + dev = dev->next; + } + pthread_mutex_unlock(&vid_mutex); - if (dev == NULL) - return V4L_FATAL_ERROR; + if (dev == NULL) + return V4L_FATAL_ERROR; - if (dev->owner != cnt->threadnr) { - pthread_mutex_lock(&dev->mutex); - dev->owner = cnt->threadnr; - dev->frames = conf->roundrobin_frames; - } + if (dev->owner != cnt->threadnr) { + pthread_mutex_lock(&dev->mutex); + dev->owner = cnt->threadnr; + dev->frames = conf->roundrobin_frames; + } #ifdef MOTION_V4L2 - if (dev->v4l2) { - v4l2_set_input(cnt, dev, map, width, height, conf); + if (dev->v4l2) { + v4l2_set_input(cnt, dev, map, width, height, conf); - ret = v4l2_next(cnt, dev, map, width, height); - } else { + ret = v4l2_next(cnt, dev, map, width, height); + } else { #endif - v4l_set_input(cnt, dev, map, width, height, conf->input, conf->norm, - conf->roundrobin_skip, conf->frequency, conf->tuner_number); + v4l_set_input(cnt, dev, map, width, height, conf->input, conf->norm, + conf->roundrobin_skip, conf->frequency, conf->tuner_number); - ret = v4l_next(dev, map, width, height); + ret = v4l_next(dev, map, width, height); #ifdef MOTION_V4L2 - } + } #endif - if (--dev->frames <= 0) { - dev->owner = -1; - dev->frames = 0; - pthread_mutex_unlock(&dev->mutex); - } + if (--dev->frames <= 0) { + dev->owner = -1; + dev->frames = 0; + pthread_mutex_unlock(&dev->mutex); + } - if (cnt->rotate_data.degrees > 0) { - /* rotate the image as specified */ - rotate_map(cnt, map); - } - } -#endif /*WITHOUT_V4L */ - return ret; + if (cnt->rotate_data.degrees > 0) { + /* rotate the image as specified */ + rotate_map(cnt, map); + } + } +#endif /*WITHOUT_V4L */ + return ret; } diff --git a/webhttpd.c b/webhttpd.c index cfd242bf..b3d17b08 100644 --- a/webhttpd.c +++ b/webhttpd.c @@ -10,7 +10,7 @@ * See also the file 'COPYING'. * */ -#include "webhttpd.h" /* already includes motion.h */ +#include "webhttpd.h" /* already includes motion.h */ #include #include #include @@ -22,218 +22,218 @@ pthread_mutex_t httpd_mutex; int warningkill; // This is a dummy variable use to kill warnings when not checking sscanf and similar functions static const char* ini_template = - "Motion "VERSION"\n" - "\n"; + "Motion "VERSION"\n" + "\n"; static const char *set_template = - "\nMotion "VERSION"\n" - "\n"; + "\nMotion "VERSION"\n" + "\n"; static const char* end_template = - "\n" - "\n"; + "\n" + "\n"; static const char* ok_response = - "HTTP/1.1 200 OK\r\n" - "Server: Motion-httpd/"VERSION"\r\n" - "Connection: close\r\n" - "Max-Age: 0\r\n" - "Expires: 0\r\n" - "Cache-Control: no-cache\r\n" - "Cache-Control: private\r\n" - "Pragma: no-cache\r\n" - "Content-type: text/html\r\n\r\n"; + "HTTP/1.1 200 OK\r\n" + "Server: Motion-httpd/"VERSION"\r\n" + "Connection: close\r\n" + "Max-Age: 0\r\n" + "Expires: 0\r\n" + "Cache-Control: no-cache\r\n" + "Cache-Control: private\r\n" + "Pragma: no-cache\r\n" + "Content-type: text/html\r\n\r\n"; static const char* ok_response_raw = - "HTTP/1.1 200 OK\r\n" - "Server: Motion-httpd/"VERSION"\r\n" - "Connection: close\r\n" - "Max-Age: 0\r\n" - "Expires: 0\r\n" - "Cache-Control: no-cache\r\n" - "Cache-Control: private\r\n" - "Pragma: no-cache\r\n" - "Content-type: text/plain\r\n\r\n"; + "HTTP/1.1 200 OK\r\n" + "Server: Motion-httpd/"VERSION"\r\n" + "Connection: close\r\n" + "Max-Age: 0\r\n" + "Expires: 0\r\n" + "Cache-Control: no-cache\r\n" + "Cache-Control: private\r\n" + "Pragma: no-cache\r\n" + "Content-type: text/plain\r\n\r\n"; static const char* bad_request_response = - "HTTP/1.0 400 Bad Request\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Bad Request

\n" - "

The server did not understand your request.

\n" - "\n" - "\n"; + "HTTP/1.0 400 Bad Request\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Bad Request

\n" + "

The server did not understand your request.

\n" + "\n" + "\n"; static const char* bad_request_response_raw = - "HTTP/1.0 400 Bad Request\r\n" - "Content-type: text/plain\r\n\r\n" - "Bad Request"; + "HTTP/1.0 400 Bad Request\r\n" + "Content-type: text/plain\r\n\r\n" + "Bad Request"; static const char* not_found_response_template = - "HTTP/1.0 404 Not Found\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Not Found

\n" - "

The requested URL was not found on the server.

\n" - "\n" - "\n"; + "HTTP/1.0 404 Not Found\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Not Found

\n" + "

The requested URL was not found on the server.

\n" + "\n" + "\n"; static const char* not_found_response_template_raw = - "HTTP/1.0 404 Not Found\r\n" - "Content-type: text/plain\r\n\r\n" - "Not Found"; + "HTTP/1.0 404 Not Found\r\n" + "Content-type: text/plain\r\n\r\n" + "Not Found"; static const char* not_found_response_valid = - "HTTP/1.0 404 Not Valid\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Not Valid

\n" - "

The requested URL is not valid.

\n" - "\n" - "\n"; + "HTTP/1.0 404 Not Valid\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Not Valid

\n" + "

The requested URL is not valid.

\n" + "\n" + "\n"; static const char* not_found_response_valid_raw = - "HTTP/1.0 404 Not Valid\r\n" - "Content-type: text/plain\r\n\r\n" - "The requested URL is not valid."; + "HTTP/1.0 404 Not Valid\r\n" + "Content-type: text/plain\r\n\r\n" + "The requested URL is not valid."; static const char* not_valid_syntax = - "HTTP/1.0 404 Not Valid Syntax\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Not Valid Syntax

\n" - "\n" - "\n"; + "HTTP/1.0 404 Not Valid Syntax\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Not Valid Syntax

\n" + "\n" + "\n"; static const char* not_valid_syntax_raw = - "HTTP/1.0 404 Not Valid Syntax\r\n" - "Content-type: text/plain\r\n\r\n" - "Not Valid Syntax\n"; + "HTTP/1.0 404 Not Valid Syntax\r\n" + "Content-type: text/plain\r\n\r\n" + "Not Valid Syntax\n"; static const char* not_track = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Tracking Not Enabled

\n"; + "HTTP/1.0 200 OK\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Tracking Not Enabled

\n"; static const char* not_track_raw = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/plain\r\n\r\n" - "Tracking Not Enabled"; + "HTTP/1.0 200 OK\r\n" + "Content-type: text/plain\r\n\r\n" + "Tracking Not Enabled"; static const char* track_error = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Track Error

\n"; + "HTTP/1.0 200 OK\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Track Error

\n"; static const char* track_error_raw = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/plain\r\n\r\n" - "Track Error"; + "HTTP/1.0 200 OK\r\n" + "Content-type: text/plain\r\n\r\n" + "Track Error"; static const char* error_value = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Value Error

\n"; + "HTTP/1.0 200 OK\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Value Error

\n"; static const char* error_value_raw = - "HTTP/1.0 200 OK\r\n" - "Content-type: text/plain\r\n\r\n" - "Value Error"; - + "HTTP/1.0 200 OK\r\n" + "Content-type: text/plain\r\n\r\n" + "Value Error"; + static const char* not_found_response_valid_command = - "HTTP/1.0 404 Not Valid Command\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Not Valid Command

\n" - "

The requested URL is not valid Command.

\n" - "\n" - "\n"; + "HTTP/1.0 404 Not Valid Command\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Not Valid Command

\n" + "

The requested URL is not valid Command.

\n" + "\n" + "\n"; static const char* not_found_response_valid_command_raw = - "HTTP/1.0 404 Not Valid Command\r\n" - "Content-type: text/plain\n\n" - "Not Valid Command\n"; + "HTTP/1.0 404 Not Valid Command\r\n" + "Content-type: text/plain\n\n" + "Not Valid Command\n"; static const char* bad_method_response_template = - "HTTP/1.0 501 Method Not Implemented\r\n" - "Content-type: text/html\r\n\r\n" - "\n" - "\n" - "

Method Not Implemented

\n" - "

The method is not implemented by this server.

\n" - "\n" - "\n"; + "HTTP/1.0 501 Method Not Implemented\r\n" + "Content-type: text/html\r\n\r\n" + "\n" + "\n" + "

Method Not Implemented

\n" + "

The method is not implemented by this server.

\n" + "\n" + "\n"; static const char* bad_method_response_template_raw = - "HTTP/1.0 501 Method Not Implemented\r\n" - "Content-type: text/plain\r\n\r\n" - "Method Not Implemented\n"; + "HTTP/1.0 501 Method Not Implemented\r\n" + "Content-type: text/plain\r\n\r\n" + "Method Not Implemented\n"; static const char *request_auth_response_template= - "HTTP/1.0 401 Authorization Required\r\n" - "WWW-Authenticate: Basic realm=\"Motion Security Access\"\r\n"; + "HTTP/1.0 401 Authorization Required\r\n" + "WWW-Authenticate: Basic realm=\"Motion Security Access\"\r\n"; static void send_template_ini_client(int client_socket, const char* template) { - ssize_t nwrite = 0; - nwrite = write(client_socket, ok_response, strlen (ok_response)); - nwrite += write(client_socket, template, strlen(template)); - if (nwrite != (ssize_t)(strlen(ok_response) + strlen(template))) - motion_log(LOG_ERR, 1, "httpd send_template_ini_client"); + ssize_t nwrite = 0; + nwrite = write(client_socket, ok_response, strlen (ok_response)); + nwrite += write(client_socket, template, strlen(template)); + if (nwrite != (ssize_t)(strlen(ok_response) + strlen(template))) + motion_log(LOG_ERR, 1, "httpd send_template_ini_client"); } static void send_template_ini_client_raw(int client_socket) { - ssize_t nwrite = 0; - nwrite = write(client_socket, ok_response_raw, strlen (ok_response_raw)); - if (nwrite != (ssize_t)strlen(ok_response_raw)) - motion_log(LOG_ERR, 1, "httpd send_template_ini_client_raw"); + ssize_t nwrite = 0; + nwrite = write(client_socket, ok_response_raw, strlen (ok_response_raw)); + if (nwrite != (ssize_t)strlen(ok_response_raw)) + motion_log(LOG_ERR, 1, "httpd send_template_ini_client_raw"); } static void send_template(int client_socket, char *res) { - ssize_t nwrite = 0; - nwrite = write(client_socket, res, strlen(res)); - if ( nwrite != (ssize_t)strlen(res)) - motion_log(LOG_ERR, 1, "httpd send_template failure write"); + ssize_t nwrite = 0; + nwrite = write(client_socket, res, strlen(res)); + if (nwrite != (ssize_t)strlen(res)) + motion_log(LOG_ERR, 1, "httpd send_template failure write"); } static void send_template_raw(int client_socket, char *res) { - ssize_t nwrite = 0; - nwrite = write(client_socket, res, strlen(res)); + ssize_t nwrite = 0; + nwrite = write(client_socket, res, strlen(res)); } static void send_template_end_client(int client_socket) { - ssize_t nwrite = 0; - nwrite = write(client_socket, end_template, strlen(end_template)); + ssize_t nwrite = 0; + nwrite = write(client_socket, end_template, strlen(end_template)); } static void response_client(int client_socket, const char* template, char *back) { - ssize_t nwrite = 0; - nwrite = write(client_socket, template, strlen(template)); - if (back != NULL) { - send_template(client_socket, back); - send_template_end_client(client_socket); - } + ssize_t nwrite = 0; + nwrite = write(client_socket, template, strlen(template)); + if (back != NULL) { + send_template(client_socket, back); + send_template_end_client(client_socket); + } } @@ -249,8 +249,9 @@ static char *replace(const char *str, const char *old, const char *new) count++; /* this is undefined if p - str > PTRDIFF_MAX */ retlen = p - str + strlen(p) + count * (newlen - oldlen); - } else + } else { retlen = strlen(str); + } ret = malloc(retlen + 1); @@ -273,38 +274,36 @@ static char *replace(const char *str, const char *old, const char *new) static void url_decode(char *urlencoded, size_t length) { - char *data=urlencoded; - char *urldecoded=urlencoded; + char *data=urlencoded; + char *urldecoded=urlencoded; - while (length > 0) { - if (*data == '%') { - char c[3]; - int i; - data++; - length--; - c[0] = *data++; - length--; - c[1] = *data; - c[2] = 0; - warningkill = sscanf(c, "%x", &i); - if (i < 128) - *urldecoded++ = (char)i; - else { - *urldecoded++ = '%'; - *urldecoded++ = c[0]; - *urldecoded++ = c[1]; - } - } else if (*data=='+') { - *urldecoded++=' '; - - } - else { - *urldecoded++=*data; - } - data++; - length--; - } - *urldecoded = '\0'; + while (length > 0) { + if (*data == '%') { + char c[3]; + int i; + data++; + length--; + c[0] = *data++; + length--; + c[1] = *data; + c[2] = 0; + warningkill = sscanf(c, "%x", &i); + if (i < 128) + *urldecoded++ = (char)i; + else { + *urldecoded++ = '%'; + *urldecoded++ = c[0]; + *urldecoded++ = c[1]; + } + } else if (*data=='+') { + *urldecoded++=' '; + } else { + *urldecoded++=*data; + } + data++; + length--; + } + *urldecoded = '\0'; } @@ -315,529 +314,532 @@ static void url_decode(char *urlencoded, size_t length) */ static unsigned short int config(char *pointer, char *res, unsigned short int length_uri, - unsigned short int thread, int client_socket, void *userdata) + unsigned short int thread, int client_socket, void *userdata) { - char question; - char command[256] = {'\0'}; - unsigned short int i; - struct context **cnt = userdata; + char question = '\0'; + char command[256] = {'\0'}; + unsigned short int i; + struct context **cnt = userdata; - warningkill = sscanf (pointer, "%255[a-z]%c", command , &question); - if (!strcmp(command,"list")) { - pointer = pointer + 4; - length_uri = length_uri - 4; - if (length_uri == 0) { - const char *value = NULL; - char *retval = NULL; - /*call list*/ - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu\n
    ", thread, thread); - send_template(client_socket, res); + warningkill = sscanf (pointer, "%255[a-z]%c", command , &question); + if (!strcmp(command,"list")) { + pointer = pointer + 4; + length_uri = length_uri - 4; + if (length_uri == 0) { + const char *value = NULL; + char *retval = NULL; + /*call list*/ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

    \nThread %hu\n
      ", thread, thread); + send_template(client_socket, res); - for (i=0; config_params[i].param_name != NULL; i++) { + for (i = 0; config_params[i].param_name != NULL; i++) { - if ((thread != 0) && (config_params[i].main_thread)) - continue; + if ((thread != 0) && (config_params[i].main_thread)) + continue; - value = config_params[i].print(cnt, NULL, i, thread); + value = config_params[i].print(cnt, NULL, i, thread); - if (value == NULL) { - retval=NULL; - - /* Only get the thread value for main thread */ - if (thread == 0) - config_params[i].print(cnt, &retval, i, thread); - - /* thread value*/ - - if (retval) { - - if (!strcmp(retval,"")) { - free(retval); - retval = strdup("No threads"); - } else { - char *temp=retval; - size_t retval_miss = 0; - size_t retval_len = strlen(retval); - unsigned short int ind=0; - char thread_strings[1024]={'\0'}; - - while (retval_miss != retval_len) { - while (*temp != '\n') { - thread_strings[ind++] = *temp; - retval_miss++; - temp++; - } - temp++; - thread_strings[ind++] = '<'; - thread_strings[ind++] = 'b'; - thread_strings[ind++] = 'r'; - thread_strings[ind++] = '>'; - retval_miss++; - } - free(retval); - retval = NULL; - retval = strdup(thread_strings); - } - - sprintf(res, "
    • %s = %s
    • \n", thread, - config_params[i].param_name, config_params[i].param_name, retval); - free(retval); - } else if (thread != 0) { - /* get the value from main thread for the rest of threads */ - value = config_params[i].print(cnt, NULL, i, 0); - - sprintf(res, "
    • %s = %s
    • \n", thread, - config_params[i].param_name, config_params[i].param_name, - value ? value : "(not defined)"); - } else { - sprintf(res, "
    • %s = %s
    • \n", thread, - config_params[i].param_name, config_params[i].param_name, - "(not defined)"); - } - - } else { - sprintf(res, "
    • %s = %s
    • \n",thread, - config_params[i].param_name, config_params[i].param_name, value); - } - send_template(client_socket, res); - } + if (value == NULL) { + retval=NULL; + + /* Only get the thread value for main thread */ + if (thread == 0) + config_params[i].print(cnt, &retval, i, thread); + + /* thread value*/ + + if (retval) { + + if (!strcmp(retval,"")) { + free(retval); + retval = strdup("No threads"); + } else { + char *temp=retval; + size_t retval_miss = 0; + size_t retval_len = strlen(retval); + unsigned short int ind=0; + char thread_strings[1024]={'\0'}; + + while (retval_miss != retval_len) { + while (*temp != '\n') { + thread_strings[ind++] = *temp; + retval_miss++; + temp++; + } + temp++; + thread_strings[ind++] = '<'; + thread_strings[ind++] = 'b'; + thread_strings[ind++] = 'r'; + thread_strings[ind++] = '>'; + retval_miss++; + } + free(retval); + retval = NULL; + retval = strdup(thread_strings); + } + + sprintf(res, "
    • %s = %s
    • \n", thread, + config_params[i].param_name, config_params[i].param_name, retval); + free(retval); + } else if (thread != 0) { + /* get the value from main thread for the rest of threads */ + value = config_params[i].print(cnt, NULL, i, 0); + + sprintf(res, "
    • %s = %s
    • \n", thread, + config_params[i].param_name, config_params[i].param_name, + value ? value : "(not defined)"); + } else { + sprintf(res, "
    • %s = %s
    • \n", thread, + config_params[i].param_name, config_params[i].param_name, + "(not defined)"); + } + + } else { + sprintf(res, "
    • %s = %s
    • \n",thread, + config_params[i].param_name, config_params[i].param_name, value); + } + send_template(client_socket, res); + } - sprintf(res, "
    <– back",thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - for (i=0; config_params[i].param_name != NULL; i++) { - value=config_params[i].print(cnt, NULL, i, thread); - if (value == NULL) - value=config_params[i].print(cnt, NULL, i, 0); - sprintf(res, "%s = %s\n", config_params[i].param_name, value); - send_template_raw(client_socket, res); - } - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"set")) { - /* set?param_name=value */ - pointer = pointer + 3; - length_uri = length_uri - 3; - if ((length_uri != 0) && (question == '?')) { - pointer++; - length_uri--; - warningkill = sscanf(pointer,"%255[-0-9a-z_]%c", command, &question); - /*check command , question == '=' length_uri too*/ - if ((question == '=') && (command[0]!='\0')) { - length_uri = length_uri - strlen(command) - 1; - pointer = pointer + strlen(command) + 1; - /* check if command exists and type of command and not end of URI */ - i=0; - while (config_params[i].param_name != NULL) { - if ((thread != 0) && (config_params[i].main_thread)){ - i++; - continue; - } + sprintf(res, "
<– back",thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + for (i=0; config_params[i].param_name != NULL; i++) { + value=config_params[i].print(cnt, NULL, i, thread); + if (value == NULL) + value=config_params[i].print(cnt, NULL, i, 0); + sprintf(res, "%s = %s\n", config_params[i].param_name, value); + send_template_raw(client_socket, res); + } + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"set")) { + /* set?param_name=value */ + pointer = pointer + 3; + length_uri = length_uri - 3; + if ((length_uri != 0) && (question == '?')) { + pointer++; + length_uri--; + warningkill = sscanf(pointer,"%255[-0-9a-z_]%c", command, &question); + /*check command , question == '=' length_uri too*/ + if ((question == '=') && (command[0]!='\0')) { + length_uri = length_uri - strlen(command) - 1; + pointer = pointer + strlen(command) + 1; + /* check if command exists and type of command and not end of URI */ + i = 0; + while (config_params[i].param_name != NULL) { + if ((thread != 0) && (config_params[i].main_thread)){ + i++; + continue; + } - if (!strcasecmp(command, config_params[i].param_name)) - break; - i++; - } + if (!strcasecmp(command, config_params[i].param_name)) + break; + i++; + } - if (config_params[i].param_name) { - if (length_uri > 0) { - char Value[1024]={'\0'}; - warningkill = sscanf(pointer,"%1023s", Value); - length_uri = length_uri - strlen(Value); - if ( (length_uri == 0) && (strlen(Value) > 0) ) { - /* FIXME need to assure that is a valid value */ - url_decode(Value,strlen(Value)); - conf_cmdparse(cnt + thread, config_params[i].param_name, Value); - if (cnt[0]->conf.control_html_output) { - sprintf(res, - "<– back" - "

\nThread %hu\n" - "
  • %s = %s" - "
Done", - thread, thread, thread,config_params[i].param_name, - config_params[i].param_name, Value); - - send_template_ini_client(client_socket, ini_template); - send_template(client_socket,res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "%s = %s\nDone\n", config_params[i].param_name, Value); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - } - } else { - char *type = NULL; - type = strdup(config_type(&config_params[i])); + if (config_params[i].param_name) { + if (length_uri > 0) { + char Value[1024]={'\0'}; + warningkill = sscanf(pointer,"%1023s", Value); + length_uri = length_uri - strlen(Value); + if ((length_uri == 0) && (strlen(Value) > 0) ) { + /* FIXME need to assure that is a valid value */ + url_decode(Value,strlen(Value)); + conf_cmdparse(cnt + thread, config_params[i].param_name, Value); + if (cnt[0]->conf.control_html_output) { + sprintf(res, + "<– back" + "

\nThread %hu\n" + "
  • %s = %s" + "
Done", + thread, thread, thread,config_params[i].param_name, + config_params[i].param_name, Value); + + send_template_ini_client(client_socket, ini_template); + send_template(client_socket,res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "%s = %s\nDone\n", config_params[i].param_name, Value); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + } + } else { + char *type = NULL; + type = strdup(config_type(&config_params[i])); - if (!strcmp(type,"string")) { - char *value = NULL; - conf_cmdparse(cnt+thread, config_params[i].param_name, value); - free(type); - type = strdup("(null)"); - } else if (!strcmp(type,"int")) { - free(type); - type = strdup("0"); - conf_cmdparse(cnt+thread, config_params[i].param_name, type); - } else if (!strcmp(type,"short")) { - free(type); - type = strdup("0"); - conf_cmdparse(cnt+thread, config_params[i].param_name, type); - } else if (!strcmp(type,"bool")) { - free(type); - type = strdup("off"); - conf_cmdparse(cnt+thread, config_params[i].param_name, type); - } else { - free(type); - type = strdup("unknown"); - } + if (!strcmp(type,"string")) { + char *value = NULL; + conf_cmdparse(cnt+thread, config_params[i].param_name, value); + free(type); + type = strdup("(null)"); + } else if (!strcmp(type,"int")) { + free(type); + type = strdup("0"); + conf_cmdparse(cnt+thread, config_params[i].param_name, type); + } else if (!strcmp(type,"short")) { + free(type); + type = strdup("0"); + conf_cmdparse(cnt+thread, config_params[i].param_name, type); + } else if (!strcmp(type,"bool")) { + free(type); + type = strdup("off"); + conf_cmdparse(cnt+thread, config_params[i].param_name, type); + } else { + free(type); + type = strdup("unknown"); + } - if (cnt[0]->conf.control_html_output) { - sprintf(res, - "<– back

\n" - "Thread %hu\n
  • %s" - "= %s

Done", thread, thread, thread, - config_params[i].param_name, config_params[i].param_name, type); - - send_template_ini_client(client_socket, ini_template); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "%s = %s\nDone\n", config_params[i].param_name,type); - send_template_raw(client_socket, res); - } - free(type); + if (cnt[0]->conf.control_html_output) { + sprintf(res, + "<– back

\n" + "Thread %hu\n
  • %s" + "= %s

Done", thread, thread, thread, + config_params[i].param_name, config_params[i].param_name, type); + + send_template_ini_client(client_socket, ini_template); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "%s = %s\nDone\n", config_params[i].param_name,type); + send_template_raw(client_socket, res); + } + free(type); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - /* Show param_name dialogue only for html output */ - if ( (cnt[0]->conf.control_html_output) && (command[0]!='\0') && - (((length_uri = length_uri - strlen(command)) == 0 )) ) { - i=0; - while (config_params[i].param_name != NULL) { - if ((thread != 0) && (config_params[i].main_thread)){ - i++; - continue; - } + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + /* Show param_name dialogue only for html output */ + if ((cnt[0]->conf.control_html_output) && (command[0]!='\0') && + (((length_uri = length_uri - strlen(command)) == 0 )) ) { + i = 0; + while (config_params[i].param_name != NULL) { + if ((thread != 0) && (config_params[i].main_thread)){ + i++; + continue; + } - if (!strcasecmp(command, config_params[i].param_name)) - break; - i++; - } - /* param_name exists */ - if (config_params[i].param_name) { - const char *value = NULL; - char *text_help = NULL; - char *sharp = NULL; - - value = config_params[i].print(cnt, NULL, i, thread); + if (!strcasecmp(command, config_params[i].param_name)) + break; + i++; + } + /* param_name exists */ + if (config_params[i].param_name) { + const char *value = NULL; + char *text_help = NULL; + char *sharp = NULL; + + value = config_params[i].print(cnt, NULL, i, thread); - sharp = strstr(config_params[i].param_help, "#\n\n#"); - if (sharp == NULL) - sharp = strstr(config_params[i].param_help, "#"); - sharp++; + sharp = strstr(config_params[i].param_help, "#\n\n#"); + if (sharp == NULL) + sharp = strstr(config_params[i].param_help, "#"); + sharp++; - text_help = replace(sharp, "\n#", "
"); - - send_template_ini_client(client_socket, ini_template); - if (!strcmp ("bool",config_type(&config_params[i])) ){ - char option[80] = {'\0'}; - - if ((value == NULL) && (thread != 0)) - value = config_params[i].print(cnt, NULL, i, 0); - - if (!strcmp ("on", value)) - sprintf(option, "\n" - "\n"); - else - sprintf(option, "\n" - "\n"); - - sprintf(res, "<– back

\n" - "Thread %hu\n" - "
\n" - "%s \n" - "    " - "[help]" - "
\n
%s", thread, thread, - config_params[i].param_name, config_params[i].param_name, - option, TWIKI_URL,config_params[i].param_name, text_help); - }else{ - - if (value == NULL){ - if (thread != 0) - /* get the value from main thread for the rest of threads */ - value = config_params[i].print(cnt, NULL, i, 0); - if (value == NULL) value = ""; - } - sprintf(res, "<– back

\n" - "Thread %hu\n
\n" - "%s \n" - "\n" - "    " - "[help]" - "
\n
%s", thread, thread, - config_params[i].param_name, config_params[i].param_name, - value, TWIKI_URL, config_params[i].param_name, text_help); - } + text_help = replace(sharp, "\n#", "
"); + + send_template_ini_client(client_socket, ini_template); + if (!strcmp ("bool",config_type(&config_params[i])) ){ + char option[80] = {'\0'}; + + if ((value == NULL) && (thread != 0)) + value = config_params[i].print(cnt, NULL, i, 0); + + if (!strcmp ("on", value)) + sprintf(option, "\n" + "\n"); + else + sprintf(option, "\n" + "\n"); + + sprintf(res, "<– back

\n" + "Thread %hu\n" + "
\n" + "%s \n" + "    " + "[help]" + "
\n
%s", thread, thread, + config_params[i].param_name, config_params[i].param_name, + option, TWIKI_URL,config_params[i].param_name, text_help); + } else { + + if (value == NULL){ + if (thread != 0) + /* get the value from main thread for the rest of threads */ + value = config_params[i].print(cnt, NULL, i, 0); + if (value == NULL) value = ""; + } + sprintf(res, "<– back

\n" + "Thread %hu\n
\n" + "%s \n" + "\n" + "    " + "[help]" + "
\n
%s", thread, thread, + config_params[i].param_name, config_params[i].param_name, + value, TWIKI_URL, config_params[i].param_name, text_help); + } - send_template(client_socket, res); - send_template_end_client(client_socket); - free(text_help); - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - } else if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, set_template); - sprintf(res, "<– back

\nThread %hu\n" - "
\n\n", thread, thread ); - send_template(client_socket, res); - for (i=0; config_params[i].param_name != NULL; i++) { - if ((thread != 0) && (config_params[i].main_thread)) - continue; - sprintf(res, "\n", - config_params[i].param_name, config_params[i].param_name); - send_template(client_socket, res); - } - sprintf(res, "\n
\n" - "
\n" - "\n" - "\n" - "
\n"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "set needs param_name=value\n"); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"get")) { - /* get?query=param_name */ - pointer = pointer + 3; - length_uri = length_uri - 3; + send_template(client_socket, res); + for (i = 0; config_params[i].param_name != NULL; i++) { + if ((thread != 0) && (config_params[i].main_thread)) + continue; + sprintf(res, "\n", + config_params[i].param_name, config_params[i].param_name); + send_template(client_socket, res); + } + sprintf(res, "\n\n" + "
\n" + "\n" + "\n" + "
\n"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "set needs param_name=value\n"); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"get")) { + /* get?query=param_name */ + pointer = pointer + 3; + length_uri = length_uri - 3; - if ((length_uri > 7) && (question == '?')) { - /* 8 -> query=param_name FIXME minimum length param_name */ - pointer++; - length_uri--; - warningkill = sscanf(pointer,"%255[-0-9a-z]%c", command, &question); + if ((length_uri > 7) && (question == '?')) { + /* 8 -> query=param_name FIXME minimum length param_name */ + pointer++; + length_uri--; + warningkill = sscanf(pointer,"%255[-0-9a-z]%c", command, &question); - if ( (question == '=') && (!strcmp(command,"query")) ) { - pointer = pointer + 6; - length_uri = length_uri - 6; - warningkill = sscanf(pointer, "%255[-0-9a-z_]", command); - /*check if command exist, length_uri too*/ - length_uri = length_uri-strlen(command); + if ((question == '=') && (!strcmp(command,"query")) ) { + pointer = pointer + 6; + length_uri = length_uri - 6; + warningkill = sscanf(pointer, "%255[-0-9a-z_]", command); + /*check if command exist, length_uri too*/ + length_uri = length_uri-strlen(command); - if (length_uri == 0) { - const char *value = NULL; - i=0; - while (config_params[i].param_name != NULL) { - if ((thread != 0) && (config_params[i].main_thread)){ - i++; - continue; - } + if (length_uri == 0) { + const char *value = NULL; + i = 0; + while (config_params[i].param_name != NULL) { + if ((thread != 0) && (config_params[i].main_thread)){ + i++; + continue; + } - if (!strcasecmp(command, config_params[i].param_name)) - break; - i++; - } - /* FIXME bool values or commented values maybe that should be - solved with config_type */ + if (!strcasecmp(command, config_params[i].param_name)) + break; + i++; + } + /* FIXME bool values or commented values maybe that should be + solved with config_type */ - if (config_params[i].param_name) { - const char *type=NULL; - type = config_type(&config_params[i]); - if (!strcmp(type,"unknown")) { - /*error doesn't exists this param_name */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - return 1; - } else { - char *text_help = NULL; - char *sharp = NULL; + if (config_params[i].param_name) { + const char *type=NULL; + type = config_type(&config_params[i]); + if (!strcmp(type,"unknown")) { + /*error doesn't exists this param_name */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + return 1; + } else { + char *text_help = NULL; + char *sharp = NULL; - value = config_params[i].print(cnt, NULL, i, thread); + value = config_params[i].print(cnt, NULL, i, thread); - sharp = strstr(config_params[i].param_help, "#\n\n#"); - if (sharp == NULL) - sharp = strstr(config_params[i].param_help, "#"); - sharp++; + sharp = strstr(config_params[i].param_help, "#\n\n#"); + if (sharp == NULL) + sharp = strstr(config_params[i].param_help, "#"); + sharp++; - text_help = replace(sharp, "\n#", "
"); + text_help = replace(sharp, "\n#", "
"); - if (value == NULL) - value=config_params[i].print(cnt, NULL, i, 0); - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket,ini_template); - sprintf(res, "<– back

\n" - "Thread %hu
\n
%s", - thread, thread, config_params[i].param_name, value, - TWIKI_URL, config_params[i].param_name, text_help); + if (value == NULL) + value=config_params[i].print(cnt, NULL, i, 0); - send_template(client_socket, res); - send_template_end_client(client_socket); + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket,ini_template); + sprintf(res, "<– back

\n" + "Thread %hu
\n
%s", + thread, thread, config_params[i].param_name, value, + TWIKI_URL, config_params[i].param_name, text_help); - free(text_help); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "%s = %s\nDone\n", config_params[i].param_name,value); - send_template_raw(client_socket, res); - } - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - } else if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu
\n" - "
\n" - "\n" - "\n" - "
\n"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "get needs param_name\n"); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - } - } else if (!strcmp(command,"write")) { - pointer = pointer + 5; - length_uri = length_uri - 5; - if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Are you sure? Yes\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - conf_print(cnt); - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hu write\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } + send_template(client_socket, res); + send_template_end_client(client_socket); - } else if (!strcmp(command, "writeyes")) { - pointer = pointer + 8; - length_uri = length_uri - 8; - if (length_uri==0) { - conf_print(cnt); - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu write done !\n", - thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hu write\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) { - response_client(client_socket, not_found_response_valid_command, NULL); - } - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } + free(text_help); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "%s = %s\nDone\n", config_params[i].param_name,value); + send_template_raw(client_socket, res); + } + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + } else if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu
\n" + "
\n" + "\n" + "\n" + "
\n"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "get needs param_name\n"); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + } + } else if (!strcmp(command,"write")) { + pointer = pointer + 5; + length_uri = length_uri - 5; + if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Are you sure? Yes\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + conf_print(cnt); + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hu write\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + + } else if (!strcmp(command, "writeyes")) { + pointer = pointer + 8; + length_uri = length_uri - 8; + if (length_uri == 0) { + conf_print(cnt); + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu write done !\n", + thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hu write\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) { + response_client(client_socket, not_found_response_valid_command, NULL); + } else { + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + + return 1; } @@ -849,175 +851,176 @@ static unsigned short int config(char *pointer, char *res, unsigned short int le */ static unsigned short int action(char *pointer, char *res, unsigned short int length_uri, - unsigned short int thread, int client_socket, void *userdata) + unsigned short int thread, int client_socket, void *userdata) { - /* parse action commands */ - char command[256] = {'\0'}; - struct context **cnt = userdata; - unsigned short int i = 0; + /* parse action commands */ + char command[256] = {'\0'}; + struct context **cnt = userdata; + unsigned short int i = 0; - warningkill = sscanf (pointer, "%255[a-z]" , command); - if (!strcmp(command,"makemovie")) { - pointer = pointer + 9; - length_uri = length_uri - 9; - if (length_uri == 0) { - /*call makemovie*/ + warningkill = sscanf (pointer, "%255[a-z]" , command); + if (!strcmp(command,"makemovie")) { + pointer = pointer + 9; + length_uri = length_uri - 9; + if (length_uri == 0) { + /*call makemovie*/ - if (thread == 0) { - while (cnt[++i]) - cnt[i]->makemovie=1; - } else { - cnt[thread]->makemovie=1; - } + if (thread == 0) { + while (cnt[++i]) + cnt[i]->makemovie = 1; + } else { + cnt[thread]->makemovie = 1; + } - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "makemovie for thread %hu done
\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "makemovie for thread %hu\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket,not_found_response_valid_command,NULL); - else - response_client(client_socket,not_found_response_valid_command_raw,NULL); - } - } else if (!strcmp(command,"snapshot")) { - pointer = pointer + 8; - length_uri = length_uri - 8; - if (length_uri == 0) { - /*call snapshot*/ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "makemovie for thread %hu done
\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "makemovie for thread %hu\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket,not_found_response_valid_command,NULL); + else + response_client(client_socket,not_found_response_valid_command_raw,NULL); + } + } else if (!strcmp(command,"snapshot")) { + pointer = pointer + 8; + length_uri = length_uri - 8; + if (length_uri == 0) { + /*call snapshot*/ - if (thread == 0) { - while (cnt[++i]) - cnt[i]->snapshot=1; - } else { - cnt[thread]->snapshot=1; - } + if (thread == 0) { + while (cnt[++i]) + cnt[i]->snapshot=1; + } else { + cnt[thread]->snapshot=1; + } - cnt[thread]->snapshot = 1; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "snapshot for thread %hu done
\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "snapshot for thread %hu\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command, "restart")) { - pointer = pointer + 7; - length_uri = length_uri - 7; - if (length_uri == 0) { - /*call restart*/ + cnt[thread]->snapshot = 1; + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "snapshot for thread %hu done
\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "snapshot for thread %hu\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command, "restart")) { + pointer = pointer + 7; + length_uri = length_uri - 7; + if (length_uri == 0) { + /*call restart*/ - if (thread == 0) { - motion_log(LOG_DEBUG, 0, "httpd restart"); - kill(getpid(),SIGHUP); - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "restart in progress ... bye
\nHome"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "restart in progress ...\nDone\n"); - send_template_raw(client_socket, res); - } - return 0; // to restart - } else { - motion_log(LOG_DEBUG, 0, "httpd restart thread %d", thread); - if (cnt[thread]->running) { - cnt[thread]->makemovie=1; - cnt[thread]->finish=1; - } - cnt[thread]->restart=1; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "restart for thread %hu done
\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "restart for thread %hu\nDone\n", thread); - send_template_raw(client_socket, res); - } - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket,not_found_response_valid_command,NULL); - else - response_client(client_socket,not_found_response_valid_command_raw,NULL); - } - } else if (!strcmp(command,"quit")) { - pointer = pointer + 4; - length_uri = length_uri - 4; - if (length_uri == 0) { - /*call quit*/ + if (thread == 0) { + motion_log(LOG_DEBUG, 0, "httpd restart"); + kill(getpid(),SIGHUP); + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "restart in progress ... bye
\nHome"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "restart in progress ...\nDone\n"); + send_template_raw(client_socket, res); + } + return 0; // to restart + } else { + motion_log(LOG_DEBUG, 0, "httpd restart thread %d", thread); + if (cnt[thread]->running) { + cnt[thread]->makemovie=1; + cnt[thread]->finish=1; + } + cnt[thread]->restart=1; + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "restart for thread %hu done
\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "restart for thread %hu\nDone\n", thread); + send_template_raw(client_socket, res); + } + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket,not_found_response_valid_command,NULL); + else + response_client(client_socket,not_found_response_valid_command_raw,NULL); + } + } else if (!strcmp(command,"quit")) { + pointer = pointer + 4; + length_uri = length_uri - 4; + if (length_uri == 0) { + /*call quit*/ - if (thread == 0) { - motion_log(LOG_DEBUG, 0, "httpd quit"); - kill(getpid(),SIGQUIT); - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "quit in progress ... bye"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res,"quit in progress ... bye\nDone\n"); - send_template_raw(client_socket, res); - } - return 0; // to quit - } else { - motion_log(LOG_DEBUG, 0, "httpd quit thread %d", thread); - cnt[thread]->restart=0; - cnt[thread]->makemovie=1; - cnt[thread]->finish=1; - cnt[thread]->watchdog=WATCHDOG_OFF; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "quit for thread %hu done
\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "quit for thread %hu\nDone\n", thread); - send_template_raw(client_socket, res); - } - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } + if (thread == 0) { + motion_log(LOG_DEBUG, 0, "httpd quit"); + kill(getpid(),SIGQUIT); + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "quit in progress ... bye"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res,"quit in progress ... bye\nDone\n"); + send_template_raw(client_socket, res); + } + return 0; // to quit - return 1; + } else { + motion_log(LOG_DEBUG, 0, "httpd quit thread %d", thread); + cnt[thread]->restart=0; + cnt[thread]->makemovie=1; + cnt[thread]->finish=1; + cnt[thread]->watchdog=WATCHDOG_OFF; + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "quit for thread %hu done
\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "quit for thread %hu\nDone\n", thread); + send_template_raw(client_socket, res); + } + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + + return 1; } /* @@ -1027,159 +1030,159 @@ static unsigned short int action(char *pointer, char *res, unsigned short int le */ static unsigned short int detection(char *pointer, char *res, unsigned short int length_uri, unsigned short int thread, - int client_socket, void *userdata) + int client_socket, void *userdata) { - char command[256]={'\0'}; - struct context **cnt=userdata; - unsigned short int i = 0; + char command[256]={'\0'}; + struct context **cnt = userdata; + unsigned short int i = 0; - warningkill = sscanf (pointer, "%255[a-z]" , command); - if (!strcmp(command,"status")) { - pointer = pointer + 6; - length_uri = length_uri - 6; - if (length_uri == 0) { - /*call status*/ - - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

Thread %hu" - " Detection status %s\n", thread, thread, - (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - sprintf(res, "Thread %hu Detection status %s\n",thread, - (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE"); - send_template_ini_client_raw(client_socket); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command, "start")) { - pointer = pointer + 5; - length_uri = length_uri - 5; - if (length_uri == 0) { - /*call start*/ + warningkill = sscanf (pointer, "%255[a-z]" , command); + if (!strcmp(command,"status")) { + pointer = pointer + 6; + length_uri = length_uri - 6; + if (length_uri == 0) { + /*call status*/ + + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

Thread %hu" + " Detection status %s\n", thread, thread, + (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + sprintf(res, "Thread %hu Detection status %s\n",thread, + (!cnt[thread]->running)? "NOT RUNNING": (cnt[thread]->pause)? "PAUSE":"ACTIVE"); + send_template_ini_client_raw(client_socket); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command, "start")) { + pointer = pointer + 5; + length_uri = length_uri - 5; + if (length_uri == 0) { + /*call start*/ - if (thread == 0) { - do { - cnt[i]->pause = 0; - } while (cnt[++i]); - } else { - cnt[thread]->pause = 0; - } + if (thread == 0) { + do { + cnt[i]->pause = 0; + } while (cnt[++i]); + } else { + cnt[thread]->pause = 0; + } - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket,ini_template); - sprintf(res, "<– back

\nThread %hu" - " Detection resumed\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hu Detection resumed\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"pause")){ - pointer = pointer + 5; - length_uri = length_uri - 5; - if (length_uri==0) { - /*call pause*/ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket,ini_template); + sprintf(res, "<– back

\nThread %hu" + " Detection resumed\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hu Detection resumed\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"pause")){ + pointer = pointer + 5; + length_uri = length_uri - 5; + if (length_uri == 0) { + /*call pause*/ - if (thread == 0) { - do { - cnt[i]->pause = 1; - } while (cnt[++i]); - } else { - cnt[thread]->pause = 1; - } - - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu" - " Detection paused\n", thread, thread); - send_template(client_socket,res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hu Detection paused\nDone\n", thread); - send_template_raw(client_socket, res); - } - } else { - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"connection")){ - pointer = pointer + 10; - length_uri = length_uri - 10; - if (length_uri==0) { - - /*call connection*/ - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n", thread); - send_template(client_socket,res); - if (thread == 0){ - do{ - sprintf(res, "Thread %hu %s
\n",i, - (!cnt[i]->running)? "NOT RUNNING" : - (cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK); - send_template(client_socket,res); - }while (cnt[++i]); - }else{ - sprintf(res, "Thread %hu %s\n", thread, - (!cnt[thread]->running)? "NOT RUNNING" : - (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK); - send_template(client_socket,res); - } - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - if (thread == 0){ - do{ - sprintf(res, "Thread %hu %s\n", i, - (!cnt[i]->running)? "NOT RUNNING" : + if (thread == 0) { + do { + cnt[i]->pause = 1; + } while (cnt[++i]); + } else { + cnt[thread]->pause = 1; + } + + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu" + " Detection paused\n", thread, thread); + send_template(client_socket,res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hu Detection paused\nDone\n", thread); + send_template_raw(client_socket, res); + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"connection")){ + pointer = pointer + 10; + length_uri = length_uri - 10; + if (length_uri == 0) { + + /*call connection*/ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n", thread); + send_template(client_socket,res); + if (thread == 0) { + do { + sprintf(res, "Thread %hu %s
\n",i, + (!cnt[i]->running)? "NOT RUNNING" : + (cnt[i]->lost_connection)?CONNECTION_KO:CONNECTION_OK); + send_template(client_socket,res); + } while (cnt[++i]); + } else { + sprintf(res, "Thread %hu %s\n", thread, + (!cnt[thread]->running)? "NOT RUNNING" : + (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK); + send_template(client_socket,res); + } + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + if (thread == 0){ + do { + sprintf(res, "Thread %hu %s\n", i, + (!cnt[i]->running)? "NOT RUNNING" : (cnt[i]->lost_connection)? CONNECTION_KO: CONNECTION_OK); - send_template_raw(client_socket, res); - }while (cnt[++i]); - }else{ - sprintf(res, "Thread %hu %s\n", thread, - (!cnt[thread]->running)? "NOT RUNNING" : - (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK); - send_template_raw(client_socket, res); - } - - } - }else{ - /*error*/ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } + send_template_raw(client_socket, res); + } while (cnt[++i]); + } else { + sprintf(res, "Thread %hu %s\n", thread, + (!cnt[thread]->running)? "NOT RUNNING" : + (cnt[thread]->lost_connection)? CONNECTION_KO: CONNECTION_OK); + send_template_raw(client_socket, res); + } + + } + } else { + /*error*/ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } - return 1; + return 1; } @@ -1190,904 +1193,901 @@ static unsigned short int detection(char *pointer, char *res, unsigned short int */ static unsigned short int track(char *pointer, char *res, unsigned short int length_uri, unsigned short int thread, - int client_socket, void *userdata) + int client_socket, void *userdata) { - char question; - char command[256] = {'\0'}; - struct context **cnt = userdata; + char question = '\0'; + char command[256] = {'\0'}; + struct context **cnt = userdata; - warningkill = sscanf(pointer, "%255[a-z]%c", command, &question); - if (!strcmp(command, "set")) { - pointer=pointer+3;length_uri=length_uri-3; - /* FIXME need to check each value */ - /* Relative movement set?pan=0&tilt=0 | set?pan=0 | set?tilt=0*/ - /* Absolute movement set?x=0&y=0 | set?x=0 | set?y=0 */ + warningkill = sscanf(pointer, "%255[a-z]%c", command, &question); + if (!strcmp(command, "set")) { + pointer=pointer+3;length_uri=length_uri-3; + /* FIXME need to check each value */ + /* Relative movement set?pan=0&tilt=0 | set?pan=0 | set?tilt=0*/ + /* Absolute movement set?x=0&y=0 | set?x=0 | set?y=0 */ - if ((question == '?') && (length_uri > 2)) { - char panvalue[12] = {'\0'}, tiltvalue[12] = {'\0'}; - char x_value[12] = {'\0'}, y_value[12] = {'\0'}; - struct context *setcnt; - int pan = 0, tilt = 0, X = 0 , Y = 0; + if ((question == '?') && (length_uri > 2)) { + char panvalue[12] = {'\0'}, tiltvalue[12] = {'\0'}; + char x_value[12] = {'\0'}, y_value[12] = {'\0'}; + struct context *setcnt; + int pan = 0, tilt = 0, X = 0 , Y = 0; - pointer++; - length_uri--; - /* set?pan=value&tilt=value */ - /* set?x=value&y=value */ - /* pan= or x= | tilt= or y= */ + pointer++; + length_uri--; + /* set?pan=value&tilt=value */ + /* set?x=value&y=value */ + /* pan= or x= | tilt= or y= */ - warningkill = sscanf (pointer, "%255[a-z]%c" , command, &question); + warningkill = sscanf (pointer, "%255[a-z]%c" , command, &question); - if (( question != '=' ) || (command[0] == '\0')) { - /* no valid syntax */ - motion_log(LOG_WARNING, 0, "httpd debug race 1"); - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } + if (( question != '=' ) || (command[0] == '\0')) { + /* no valid syntax */ + motion_log(LOG_WARNING, 0, "httpd debug race 1"); + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } - pointer++; - length_uri--; + pointer++; + length_uri--; - /* Check first parameter */ + /* Check first parameter */ - if (!strcmp(command, "pan")) { - pointer = pointer + 3; - length_uri = length_uri - 3; - pan = 1; - if ((warningkill = sscanf(pointer, "%10[-0-9]", panvalue))){ - pointer = pointer + strlen(panvalue); - length_uri = length_uri - strlen(panvalue); - } - } - else if (!strcmp(command, "tilt")) { - pointer = pointer + 4; - length_uri = length_uri - 4; - tilt = 1; - if ((warningkill = sscanf(pointer, "%10[-0-9]", tiltvalue))){ - pointer = pointer + strlen(tiltvalue); - length_uri = length_uri - strlen(tiltvalue); - } - } - else if (!strcmp(command, "x")) { - pointer++; - length_uri--; - X = 1; - if ((warningkill = sscanf(pointer, "%10[-0-9]", x_value))){ - pointer = pointer + strlen(x_value); - length_uri = length_uri - strlen(x_value); - } - } - else if (!strcmp(command, "y")) { - pointer++; - length_uri--; - Y = 1; - if ((warningkill = sscanf (pointer, "%10[-0-9]" , y_value))){ - pointer = pointer + strlen(y_value); - length_uri = length_uri - strlen(y_value); - } - } else { - /* no valid syntax */ - motion_log(LOG_WARNING, 0, "httpd debug race 2"); - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } + if (!strcmp(command, "pan")) { + pointer = pointer + 3; + length_uri = length_uri - 3; + pan = 1; + if ((warningkill = sscanf(pointer, "%10[-0-9]", panvalue))){ + pointer = pointer + strlen(panvalue); + length_uri = length_uri - strlen(panvalue); + } + } + else if (!strcmp(command, "tilt")) { + pointer = pointer + 4; + length_uri = length_uri - 4; + tilt = 1; + if ((warningkill = sscanf(pointer, "%10[-0-9]", tiltvalue))){ + pointer = pointer + strlen(tiltvalue); + length_uri = length_uri - strlen(tiltvalue); + } + } + else if (!strcmp(command, "x")) { + pointer++; + length_uri--; + X = 1; + if ((warningkill = sscanf(pointer, "%10[-0-9]", x_value))){ + pointer = pointer + strlen(x_value); + length_uri = length_uri - strlen(x_value); + } + } + else if (!strcmp(command, "y")) { + pointer++; + length_uri--; + Y = 1; + if ((warningkill = sscanf (pointer, "%10[-0-9]" , y_value))){ + pointer = pointer + strlen(y_value); + length_uri = length_uri - strlen(y_value); + } + } else { + /* no valid syntax */ + motion_log(LOG_WARNING, 0, "httpd debug race 2"); + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } - /* first value check for error */ + /* first value check for error */ - - if ( !warningkill ) { - motion_log(LOG_WARNING, 0, "httpd debug race 3"); - /* error value */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, error_value, NULL); - else - response_client(client_socket, error_value_raw, NULL); - return 1; - } + + if (!warningkill) { + motion_log(LOG_WARNING, 0, "httpd debug race 3"); + /* error value */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, error_value, NULL); + else + response_client(client_socket, error_value_raw, NULL); + return 1; + } - + - /* Only one parameter (pan= ,tilt= ,x= ,y= ) */ - if (length_uri == 0) { - if (pan) { - struct coord cent; - struct context *pancnt; + /* Only one parameter (pan= ,tilt= ,x= ,y= ) */ + if (length_uri == 0) { + if (pan) { + struct coord cent; + struct context *pancnt; - /* move pan */ + /* move pan */ - pancnt = cnt[thread]; - cent.width = pancnt->imgs.width; - cent.height = pancnt->imgs.height; - cent.y = 0; - cent.x = atoi(panvalue); - // Add the number of frame to skip for motion detection - cnt[thread]->moved = track_move(pancnt, pancnt->video_dev, ¢, &pancnt->imgs, 1); - if (cnt[thread]->moved) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track set relative pan=%s
\n", - thread, thread, panvalue); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track set relative pan=%s\nDone\n", panvalue); - send_template_raw(client_socket, res); - } - } else { - /*error in track action*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - } - else - response_client(client_socket, track_error_raw, NULL); - } - } else if (tilt) { - struct coord cent; - struct context *tiltcnt; + pancnt = cnt[thread]; + cent.width = pancnt->imgs.width; + cent.height = pancnt->imgs.height; + cent.y = 0; + cent.x = atoi(panvalue); + // Add the number of frame to skip for motion detection + cnt[thread]->moved = track_move(pancnt, pancnt->video_dev, ¢, &pancnt->imgs, 1); + if (cnt[thread]->moved) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track set relative pan=%s
\n", + thread, thread, panvalue); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track set relative pan=%s\nDone\n", panvalue); + send_template_raw(client_socket, res); + } + } else { + /*error in track action*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } + else + response_client(client_socket, track_error_raw, NULL); + } + } else if (tilt) { + struct coord cent; + struct context *tiltcnt; - /* move tilt */ + /* move tilt */ - tiltcnt = cnt[thread]; - cent.width = tiltcnt->imgs.width; - cent.height = tiltcnt->imgs.height; - cent.x = 0; - cent.y = atoi(tiltvalue); - // Add the number of frame to skip for motion detection - cnt[thread]->moved=track_move(tiltcnt, tiltcnt->video_dev, ¢, &tiltcnt->imgs, 1); - if (cnt[thread]->moved){ - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track set relative tilt=%s\n", - thread, thread, tiltvalue); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track set relative tilt=%s\nDone\n",tiltvalue); - send_template_raw(client_socket, res); - } - } else { - /*error in track action*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - } - else - response_client(client_socket, track_error_raw, NULL); - } - } else if (X){ - /* X */ - setcnt = cnt[thread]; - // 1000 is out of range for pwc - cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), 1000); - if (cnt[thread]->moved) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track set absolute x=%s\n", - thread, thread, x_value); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track set absolute x=%s\nDone\n", x_value); - send_template_raw(client_socket, res); - } - } else { - /*error in track action*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - } - else - response_client(client_socket, track_error_raw, NULL); - } + tiltcnt = cnt[thread]; + cent.width = tiltcnt->imgs.width; + cent.height = tiltcnt->imgs.height; + cent.x = 0; + cent.y = atoi(tiltvalue); + // Add the number of frame to skip for motion detection + cnt[thread]->moved=track_move(tiltcnt, tiltcnt->video_dev, ¢, &tiltcnt->imgs, 1); + if (cnt[thread]->moved){ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track set relative tilt=%s\n", + thread, thread, tiltvalue); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track set relative tilt=%s\nDone\n",tiltvalue); + send_template_raw(client_socket, res); + } + } else { + /*error in track action*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } + else + response_client(client_socket, track_error_raw, NULL); + } + } else if (X) { + /* X */ + setcnt = cnt[thread]; + // 1000 is out of range for pwc + cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), 1000); + if (cnt[thread]->moved) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track set absolute x=%s\n", + thread, thread, x_value); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track set absolute x=%s\nDone\n", x_value); + send_template_raw(client_socket, res); + } + } else { + /*error in track action*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } + else + response_client(client_socket, track_error_raw, NULL); + } - } else { - /* Y */ - setcnt = cnt[thread]; - // 1000 is out of range for pwc - cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, 1000, atoi(y_value)); - if (cnt[thread]->moved) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track set absolute y=%s
\n", - thread, thread, y_value); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track set absolute y=%s\nDone\n", y_value); - send_template_raw(client_socket, res); - } - } else { - /*error in track action*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - } - else - response_client(client_socket, track_error_raw, NULL); - } - } - return 1; - } + } else { + /* Y */ + setcnt = cnt[thread]; + // 1000 is out of range for pwc + cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, 1000, atoi(y_value)); + if (cnt[thread]->moved) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track set absolute y=%s
\n", + thread, thread, y_value); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track set absolute y=%s\nDone\n", y_value); + send_template_raw(client_socket, res); + } + } else { + /*error in track action*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } else { + response_client(client_socket, track_error_raw, NULL); + } + } + } + return 1; + } - /* Check Second parameter */ + /* Check Second parameter */ - warningkill = sscanf (pointer, "%c%255[a-z]" ,&question, command); - if ( ( question != '&' ) || (command[0] == '\0') ){ - motion_log(LOG_WARNING, 0, "httpd debug race 4"); - if ( strstr(pointer,"&")){ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, error_value, NULL); - else - response_client(client_socket, error_value_raw, NULL); - } - /* no valid syntax */ - else{ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - } - return 1; - } + warningkill = sscanf (pointer, "%c%255[a-z]" ,&question, command); + if (( question != '&' ) || (command[0] == '\0') ){ + motion_log(LOG_WARNING, 0, "httpd debug race 4"); + if (strstr(pointer,"&")){ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, error_value, NULL); + else + response_client(client_socket, error_value_raw, NULL); + } else { /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + } + return 1; + } - pointer++; - length_uri--; + pointer++; + length_uri--; - if (!strcmp(command, "pan")){ - pointer = pointer + 3; - length_uri = length_uri - 3; - if ( (pan) || (!tilt) || (X) || (Y) ) { - motion_log(LOG_WARNING, 0, "httpd debug race 5"); - /* no valid syntax */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } - pan=2; - warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, panvalue); - } - else if (!strcmp(command, "tilt")) { - pointer = pointer + 4; - length_uri = length_uri - 4; - if ( (tilt) || (!pan) || (X) || (Y) ) { - /* no valid syntax */ - motion_log(LOG_WARNING, 0, "httpd debug race 6"); - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } - tilt = 2; - warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, tiltvalue); - } - else if (!strcmp(command, "x")) { - pointer++; - length_uri--; - if ( (X) || (!Y) || (pan) || (tilt) ) { - motion_log(LOG_WARNING, 0, "httpd debug race 7"); - - /* no valid syntax */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } - X = 2; - warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, x_value); - } - else if (!strcmp(command, "y")) { - pointer++; - length_uri--; - if ( (Y) || (!X) || (pan) || (tilt) ){ - motion_log(LOG_WARNING, 0, "httpd debug race 8"); - /* no valid syntax */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } - Y = 2; - warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, y_value); - } else { - motion_log(LOG_WARNING, 0, "httpd debug race 9"); - /* no valid syntax */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - } + if (!strcmp(command, "pan")){ + pointer = pointer + 3; + length_uri = length_uri - 3; + if (pan || !tilt || X || Y ) { + motion_log(LOG_WARNING, 0, "httpd debug race 5"); + /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } + pan=2; + warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, panvalue); + } + else if (!strcmp(command, "tilt")) { + pointer = pointer + 4; + length_uri = length_uri - 4; - /* Second value check */ + if (tilt || !pan || X || Y) { + /* no valid syntax */ + motion_log(LOG_WARNING, 0, "httpd debug race 6"); + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } + tilt = 2; + warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, tiltvalue); + } else if (!strcmp(command, "x")) { + pointer++; + length_uri--; + if (X || !Y || pan || tilt) { + motion_log(LOG_WARNING, 0, "httpd debug race 7"); + + /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } + X = 2; + warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, x_value); + } else if (!strcmp(command, "y")) { + pointer++; + length_uri--; + if (Y || !X || pan || tilt){ + motion_log(LOG_WARNING, 0, "httpd debug race 8"); + /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } + Y = 2; + warningkill = sscanf (pointer, "%c%10[-0-9]" ,&question, y_value); + } else { + motion_log(LOG_WARNING, 0, "httpd debug race 9"); + /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } - if ( ( warningkill < 2 ) && (question != '=') ) { - motion_log(LOG_WARNING, 0, "httpd debug race 10"); - /* no valid syntax */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_valid_syntax, NULL); - else - response_client(client_socket, not_valid_syntax_raw, NULL); - return 1; - }else if (( question == '=') && ( warningkill == 1)){ - motion_log(LOG_WARNING, 0, "httpd debug race 11"); - if (cnt[0]->conf.control_html_output) - response_client(client_socket, error_value, NULL); - else - response_client(client_socket, error_value_raw, NULL); - return 1; - } - - - if (pan == 2){ - pointer = pointer + strlen(panvalue) + 1; - length_uri = length_uri - strlen(panvalue) - 1; - } - else if (tilt == 2){ - pointer = pointer + strlen(tiltvalue) + 1; - length_uri = length_uri - strlen(tiltvalue) - 1; - } - else if (X == 2){ - pointer = pointer + strlen(x_value) + 1; - length_uri = length_uri - strlen(x_value) - 1; - } - else{ - pointer = pointer + strlen(y_value) + 1; - length_uri = length_uri - strlen(y_value) - 1; - } - - + /* Second value check */ - if (length_uri != 0) { - motion_log(LOG_WARNING, 0, "httpd debug race 12"); - if (cnt[0]->conf.control_html_output) - response_client(client_socket, error_value, NULL); - else - response_client(client_socket, error_value_raw, NULL); - return 1; - } + if ((warningkill < 2) && (question != '=')) { + motion_log(LOG_WARNING, 0, "httpd debug race 10"); + /* no valid syntax */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_valid_syntax, NULL); + else + response_client(client_socket, not_valid_syntax_raw, NULL); + return 1; + } else if (( question == '=') && ( warningkill == 1)) { + motion_log(LOG_WARNING, 0, "httpd debug race 11"); + if (cnt[0]->conf.control_html_output) + response_client(client_socket, error_value, NULL); + else + response_client(client_socket, error_value_raw, NULL); + return 1; + } + + + if (pan == 2) { + pointer = pointer + strlen(panvalue) + 1; + length_uri = length_uri - strlen(panvalue) - 1; + } else if (tilt == 2) { + pointer = pointer + strlen(tiltvalue) + 1; + length_uri = length_uri - strlen(tiltvalue) - 1; + } else if (X == 2) { + pointer = pointer + strlen(x_value) + 1; + length_uri = length_uri - strlen(x_value) - 1; + } else { + pointer = pointer + strlen(y_value) + 1; + length_uri = length_uri - strlen(y_value) - 1; + } + + + + if (length_uri != 0) { + motion_log(LOG_WARNING, 0, "httpd debug race 12"); + if (cnt[0]->conf.control_html_output) + response_client(client_socket, error_value, NULL); + else + response_client(client_socket, error_value_raw, NULL); + return 1; + } - /* track set absolute ( x , y )*/ + /* track set absolute ( x , y )*/ - if ( X && Y ) { - setcnt = cnt[thread]; - cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), atoi(y_value)); - if (cnt[thread]->moved) { - if (cnt[0]->conf.control_html_output){ - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track absolute set x=%s y=%s
\n", - thread, thread, x_value, y_value); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track absolute set x=%s y=%s\nDone\n", x_value, y_value); - send_template_raw(client_socket, res); - } - } else { - /*error in track action*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - } - else - response_client(client_socket, track_error_raw, NULL); - } - /* track set relative ( pan , tilt )*/ - } else { - struct coord cent; - struct context *relativecnt; + if (X && Y) { + setcnt = cnt[thread]; + cnt[thread]->moved = track_center(setcnt, setcnt->video_dev, 1, atoi(x_value), atoi(y_value)); + if (cnt[thread]->moved) { + if (cnt[0]->conf.control_html_output){ + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track absolute set x=%s y=%s
\n", + thread, thread, x_value, y_value); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track absolute set x=%s y=%s\nDone\n", x_value, y_value); + send_template_raw(client_socket, res); + } + } else { + /*error in track action*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } else { + response_client(client_socket, track_error_raw, NULL); + } + } + /* track set relative ( pan , tilt )*/ + } else { + struct coord cent; + struct context *relativecnt; - /* move pan */ + /* move pan */ - relativecnt = cnt[thread]; - cent.width = relativecnt->imgs.width; - cent.height = relativecnt->imgs.height; - cent.y = 0; - cent.x = atoi(panvalue); - // Add the number of frame to skip for motion detection - cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev, ¢, &relativecnt->imgs, 1); - if (cnt[thread]->moved){ - /* move tilt */ - relativecnt = cnt[thread]; - cent.width = relativecnt->imgs.width; - cent.height = relativecnt->imgs.height; - cent.x = 0; - cent.y = atoi(tiltvalue); - SLEEP(1,0); - cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev, ¢, &relativecnt->imgs, 1); - if (cnt[thread]->moved){ - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
\n" - "track relative pan=%s tilt=%s\n", - thread, thread, panvalue, tiltvalue); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track relative pan=%s tilt=%s\nDone\n", panvalue, tiltvalue); - send_template_raw(client_socket, res); - } - return 1; - } - else{ - /*error in track tilt*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

" - "Thread %hu\n", thread, thread); - response_client(client_socket, track_error, res); - }else response_client(client_socket, track_error_raw, NULL); - } - } + relativecnt = cnt[thread]; + cent.width = relativecnt->imgs.width; + cent.height = relativecnt->imgs.height; + cent.y = 0; + cent.x = atoi(panvalue); + // Add the number of frame to skip for motion detection + cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev, ¢, &relativecnt->imgs, 1); - /*error in track pan*/ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back

Thread %hu\n", - thread, thread); - response_client(client_socket, track_error, res); - } else - response_client(client_socket, track_error_raw, NULL); - } - } else if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu
\n" - "
\n" - "Pan\n" - "Tilt\n" - "\n" - "
\n" - "
\n" - "X\n" - "Y\n" - "\n" - "
\n", thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "set needs a pan/tilt or x/y values\n"); - send_template_raw(client_socket, res); - } - } else { - /* error not valid command */ - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"status")) { - pointer = pointer+6; - length_uri = length_uri-6; - if (length_uri==0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu" - "
track auto %s", thread, thread, - (cnt[thread]->track.active)? "enabled":"disabled"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - sprintf(res, "Thread %hu\n track auto %s\nDone\n",thread, - (cnt[thread]->track.active)? "enabled":"disabled"); - send_template_ini_client_raw(client_socket); - send_template_raw(client_socket, res); - } - } else { - /* error not valid command */ - if (cnt[0]->conf.control_html_output) { - response_client(client_socket, not_found_response_valid_command, NULL); - } - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else if (!strcmp(command,"auto")) { - pointer = pointer + 4; - length_uri = length_uri - 4; - if ((question == '?') && (length_uri > 0)) { - char query[256] = {'\0'}; - pointer++; - length_uri--; - /* value= */ + if (cnt[thread]->moved) { + /* move tilt */ + relativecnt = cnt[thread]; + cent.width = relativecnt->imgs.width; + cent.height = relativecnt->imgs.height; + cent.x = 0; + cent.y = atoi(tiltvalue); + SLEEP(1,0); + cnt[thread]->moved = track_move(relativecnt, relativecnt->video_dev, ¢, &relativecnt->imgs, 1); - warningkill = sscanf (pointer, "%255[a-z]%c",query,&question); - if ((question == '=') && (!strcmp(query,"value")) ) { - pointer = pointer + 6; - length_uri = length_uri - 6; - warningkill = sscanf (pointer, "%255[-0-9a-z]" , command); - if ((command!=NULL) && (strlen(command) > 0)) { - struct context *autocnt; + if (cnt[thread]->moved) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
\n" + "track relative pan=%s tilt=%s\n", + thread, thread, panvalue, tiltvalue); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track relative pan=%s tilt=%s\nDone\n", panvalue, tiltvalue); + send_template_raw(client_socket, res); + } + return 1; + } else { + /*error in track tilt*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

" + "Thread %hu\n", thread, thread); + response_client(client_socket, track_error, res); + } else { + response_client(client_socket, track_error_raw, NULL); + } + } + } - /* auto value=0|1|status*/ + /*error in track pan*/ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back

Thread %hu\n", + thread, thread); + response_client(client_socket, track_error, res); + } else + response_client(client_socket, track_error_raw, NULL); + } + } else if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu
\n" + "
\n" + "Pan\n" + "Tilt\n" + "\n" + "
\n" + "
\n" + "X\n" + "Y\n" + "\n" + "
\n", thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "set needs a pan/tilt or x/y values\n"); + send_template_raw(client_socket, res); + } + } else { + /* error not valid command */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"status")) { + pointer = pointer+6; + length_uri = length_uri-6; + if (length_uri==0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu" + "
track auto %s", thread, thread, + (cnt[thread]->track.active)? "enabled":"disabled"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + sprintf(res, "Thread %hu\n track auto %s\nDone\n",thread, + (cnt[thread]->track.active)? "enabled":"disabled"); + send_template_ini_client_raw(client_socket); + send_template_raw(client_socket, res); + } + } else { + /* error not valid command */ + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else if (!strcmp(command,"auto")) { + pointer = pointer + 4; + length_uri = length_uri - 4; + if ((question == '?') && (length_uri > 0)) { + char query[256] = {'\0'}; + pointer++; + length_uri--; + /* value= */ - if (!strcmp(command,"status")) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu
" - "track auto %s", thread, thread, - (cnt[thread]->track.active)? "enabled":"disabled"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - sprintf(res, "Thread %hu\n track auto %s\nDone\n", thread, - (cnt[thread]->track.active)? "enabled":"disabled"); - send_template_ini_client_raw(client_socket); - send_template_raw(client_socket, res); - } - } else { - int active; - active = atoi(command); - /* CHECK */ - if (active > -1 && active < 2) { - autocnt = cnt[thread]; - autocnt->track.active = active; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

" - "Thread %hu" - "
track auto %s
", thread, thread, - active ? "enabled":"disabled"); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "track auto %s\nDone\n",active ? "enabled":"disabled"); - send_template_raw(client_socket, res); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - else if (length_uri == 0) { + warningkill = sscanf (pointer, "%255[a-z]%c",query,&question); + if ((question == '=') && (!strcmp(query,"value")) ) { + pointer = pointer + 6; + length_uri = length_uri - 6; + warningkill = sscanf (pointer, "%255[-0-9a-z]" , command); + if ((command!=NULL) && (strlen(command) > 0)) { + struct context *autocnt; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\nThread %hu\n" - "
\n" - "
\n",thread, thread, (cnt[thread]->track.active) ? "selected":"", - (cnt[thread]->track.active) ? "selected":"" ); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "auto accepts only 0,1 or status as valid value\n"); - send_template_raw(client_socket, res); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } + /* auto value=0|1|status*/ - return 1; + if (!strcmp(command,"status")) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu
" + "track auto %s", thread, thread, + (cnt[thread]->track.active)? "enabled":"disabled"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + sprintf(res, "Thread %hu\n track auto %s\nDone\n", thread, + (cnt[thread]->track.active)? "enabled":"disabled"); + send_template_ini_client_raw(client_socket); + send_template_raw(client_socket, res); + } + } else { + int active; + active = atoi(command); + /* CHECK */ + if (active > -1 && active < 2) { + autocnt = cnt[thread]; + autocnt->track.active = active; + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

" + "Thread %hu" + "
track auto %s
", thread, thread, + active ? "enabled":"disabled"); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "track auto %s\nDone\n",active ? "enabled":"disabled"); + send_template_raw(client_socket, res); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + else if (length_uri == 0) { + + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\nThread %hu\n" + "
\n" + "
\n",thread, thread, (cnt[thread]->track.active) ? "selected":"", + (cnt[thread]->track.active) ? "selected":"" ); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "auto accepts only 0,1 or status as valid value\n"); + send_template_raw(client_socket, res); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + + return 1; } /* - parses the action requested for motion ( config , action , detection , track ) and call - to action function if needed. + parses the action requested for motion ( config , action , detection , track ) and call + to action function if needed. - return 0 on action restart or quit - return 1 on success + return 0 on action restart or quit + return 1 on success */ static unsigned short int handle_get(int client_socket, const char* url, void *userdata) { - struct context **cnt=userdata; - if (*url == '/' ){ - unsigned short int i = 0; - char *res=NULL; - res = malloc(2048); + struct context **cnt=userdata; - /* get the number of threads */ - while (cnt[++i]); - /* ROOT_URI -> GET / */ - if (! (strcmp (url, "/")) ) { - unsigned short int y; - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket,ini_template); - sprintf(res, "Motion "VERSION" Running [%hu] Threads
\n" - "All
\n", i); - send_template(client_socket, res); - for (y=1; yThread %hu
\n", y, y); - send_template(client_socket, res); - } - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Motion "VERSION" Running [%hu] Threads\n0\n", i); - send_template_raw(client_socket, res); - for (y=1; y GET /2 */ - pointer++; - length_uri--; - warningkill = sscanf (pointer, "%hd%c", &thread, &slash); + /* get the number of threads */ + while (cnt[++i]); + /* ROOT_URI -> GET / */ + if (! (strcmp (url, "/"))) { + unsigned short int y; + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket,ini_template); + sprintf(res, "Motion "VERSION" Running [%hu] Threads
\n" + "All
\n", i); + send_template(client_socket, res); + for (y=1; yThread %hu
\n", y, y); + send_template(client_socket, res); + } + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Motion "VERSION" Running [%hu] Threads\n0\n", i); + send_template_raw(client_socket, res); + for (y=1; y 9){ - pointer = pointer + 2; - length_uri = length_uri - 2; - }else{ - pointer++; - length_uri--; - } - - if (slash == '/') { /* slash found /2/ */ - pointer++; - length_uri--; - } + } else { + char command[256] = {'\0'}; + char slash; + short int thread = -1; + size_t length_uri = 0; + char *pointer = (char *)url; - if (length_uri!=0) { - warningkill = sscanf (pointer, "%255[a-z]%c" , command , &slash); + length_uri = strlen(url); + /* Check for Thread number first -> GET /2 */ + pointer++; + length_uri--; + warningkill = sscanf (pointer, "%hd%c", &thread, &slash); - /* config */ - if (!strcmp(command,"config")) { - pointer = pointer + 6; - length_uri = length_uri - 6; - if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "Thread %hd
\n" - "list
\n" - "write
\n" - "set
\n" - "get
\n", - thread, thread, thread, thread, thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hd\nlist\nwrite\nset\nget\n", thread); - send_template_raw(client_socket, res); - } - } else if ((slash == '/') && (length_uri >= 4)) { - /*call config() */ - pointer++; - length_uri--; - config(pointer, res, length_uri, thread, client_socket, cnt); - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - /* action */ - else if (!strcmp(command,"action")) { - pointer = pointer + 6; - length_uri = length_uri - 6; - /* call action() */ - if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "Thread %hd
\n" - "makemovie
\n" - "snapshot
\n" - "restart
\n" - "quit
\n", - thread,thread,thread,thread,thread,thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hd\nmakemovie\nsnapshot\nrestart\nquit\n", thread); - send_template_raw(client_socket, res); - } - } else if ((slash == '/') && (length_uri > 4)) { - unsigned short int ret = 1; - pointer++; - length_uri--; - ret = action(pointer, res, length_uri, thread, client_socket, cnt); - free(res); - return ret; + if ((thread != -1) && (thread < i)) { + /* thread_number found */ + if (thread > 9) { + pointer = pointer + 2; + length_uri = length_uri - 2; + } else { + pointer++; + length_uri--; + } + + if (slash == '/') { /* slash found /2/ */ + pointer++; + length_uri--; + } - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command,NULL); - else - response_client(client_socket, not_found_response_valid_command_raw,NULL); - } - } - /* detection */ - else if (!strcmp(command,"detection")) { - pointer = pointer + 9; - length_uri = length_uri - 9; - if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "Thread %hd
\n" - "status
\n" - "start
\n" - "pause
\n" - "connection
\n", - thread, thread, thread, thread, thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hd\nstatus\nstart\npause\nconnection\n", thread); - send_template_raw(client_socket, res); - } - } else if ((slash == '/') && (length_uri > 5)) { - pointer++; - length_uri--; - /* call detection() */ - detection(pointer, res, length_uri, thread, client_socket, cnt); - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_valid_command, NULL); - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } - /* track */ - else if (!strcmp(command,"track")) { - pointer = pointer + 5; - length_uri = length_uri - 5; - if (length_uri == 0) { - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket, ini_template); - sprintf(res, "<– back

\n" - "Thread %hd
\n" - "track set pan/tilt
\n" - "track auto
\n" - "track status
\n", - thread, thread, thread, thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hd\nset pan/tilt\nauto\nstatus\n", thread); - send_template_raw(client_socket, res); - } - } - else if ((slash == '/') && (length_uri >= 4)) { - pointer++; - length_uri--; - /* call track() */ - if (cnt[thread]->track.type) { - track(pointer, res, length_uri, thread, client_socket, cnt); - } else { - /* error track not enable */ - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back\n", thread); - response_client(client_socket, not_track,res); - } - else - response_client(client_socket, not_track_raw,NULL); - } - } else { - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back\n", thread); - response_client(client_socket, not_found_response_valid_command, res); - } - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back\n", thread); - response_client(client_socket, not_found_response_valid_command, res); - } - else - response_client(client_socket, not_found_response_valid_command_raw, NULL); - } - } else { - /* /thread_number/ requested */ - if (cnt[0]->conf.control_html_output) { - send_template_ini_client(client_socket,ini_template); - sprintf(res, "<– back

\nThread %hd
\n" - "config
\n" - "action
\n" - "detection
\n" - "track
\n", - thread, thread, thread, thread, thread); - send_template(client_socket, res); - send_template_end_client(client_socket); - } else { - send_template_ini_client_raw(client_socket); - sprintf(res, "Thread %hd\nconfig\naction\ndetection\ntrack\n", thread); - send_template_raw(client_socket, res); - } - } - } else { - if (cnt[0]->conf.control_html_output) { - sprintf(res, "<– back\n"); - response_client(client_socket, not_found_response_valid, res); - } - else - response_client(client_socket, not_found_response_valid_raw, NULL); - } - } - free(res); - } else { - if (cnt[0]->conf.control_html_output) - response_client(client_socket, not_found_response_template,NULL); - else - response_client(client_socket, not_found_response_template_raw,NULL); - } + if (length_uri != 0) { + warningkill = sscanf (pointer, "%255[a-z]%c" , command , &slash); - return 1; + /* config */ + if (!strcmp(command,"config")) { + pointer = pointer + 6; + length_uri = length_uri - 6; + if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "Thread %hd
\n" + "list
\n" + "write
\n" + "set
\n" + "get
\n", + thread, thread, thread, thread, thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hd\nlist\nwrite\nset\nget\n", thread); + send_template_raw(client_socket, res); + } + } else if ((slash == '/') && (length_uri >= 4)) { + /*call config() */ + pointer++; + length_uri--; + config(pointer, res, length_uri, thread, client_socket, cnt); + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + /* action */ + else if (!strcmp(command,"action")) { + pointer = pointer + 6; + length_uri = length_uri - 6; + /* call action() */ + if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "Thread %hd
\n" + "makemovie
\n" + "snapshot
\n" + "restart
\n" + "quit
\n", + thread,thread,thread,thread,thread,thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hd\nmakemovie\nsnapshot\nrestart\nquit\n", thread); + send_template_raw(client_socket, res); + } + } else if ((slash == '/') && (length_uri > 4)) { + unsigned short int ret = 1; + pointer++; + length_uri--; + ret = action(pointer, res, length_uri, thread, client_socket, cnt); + free(res); + return ret; + + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command,NULL); + else + response_client(client_socket, not_found_response_valid_command_raw,NULL); + } + } + /* detection */ + else if (!strcmp(command,"detection")) { + pointer = pointer + 9; + length_uri = length_uri - 9; + if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "Thread %hd
\n" + "status
\n" + "start
\n" + "pause
\n" + "connection
\n", + thread, thread, thread, thread, thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hd\nstatus\nstart\npause\nconnection\n", thread); + send_template_raw(client_socket, res); + } + } else if ((slash == '/') && (length_uri > 5)) { + pointer++; + length_uri--; + /* call detection() */ + detection(pointer, res, length_uri, thread, client_socket, cnt); + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_valid_command, NULL); + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } + /* track */ + else if (!strcmp(command,"track")) { + pointer = pointer + 5; + length_uri = length_uri - 5; + if (length_uri == 0) { + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket, ini_template); + sprintf(res, "<– back

\n" + "Thread %hd
\n" + "track set pan/tilt
\n" + "track auto
\n" + "track status
\n", + thread, thread, thread, thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hd\nset pan/tilt\nauto\nstatus\n", thread); + send_template_raw(client_socket, res); + } + } + else if ((slash == '/') && (length_uri >= 4)) { + pointer++; + length_uri--; + /* call track() */ + if (cnt[thread]->track.type) { + track(pointer, res, length_uri, thread, client_socket, cnt); + } else { + /* error track not enable */ + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back\n", thread); + response_client(client_socket, not_track,res); + } + else + response_client(client_socket, not_track_raw,NULL); + } + } else { + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back\n", thread); + response_client(client_socket, not_found_response_valid_command, res); + } + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back\n", thread); + response_client(client_socket, not_found_response_valid_command, res); + } + else + response_client(client_socket, not_found_response_valid_command_raw, NULL); + } + } else { + /* /thread_number/ requested */ + if (cnt[0]->conf.control_html_output) { + send_template_ini_client(client_socket,ini_template); + sprintf(res, "<– back

\nThread %hd
\n" + "config
\n" + "action
\n" + "detection
\n" + "track
\n", + thread, thread, thread, thread, thread); + send_template(client_socket, res); + send_template_end_client(client_socket); + } else { + send_template_ini_client_raw(client_socket); + sprintf(res, "Thread %hd\nconfig\naction\ndetection\ntrack\n", thread); + send_template_raw(client_socket, res); + } + } + } else { + if (cnt[0]->conf.control_html_output) { + sprintf(res, "<– back\n"); + response_client(client_socket, not_found_response_valid, res); + } else { + response_client(client_socket, not_found_response_valid_raw, NULL); + } + } + } + free(res); + } else { + if (cnt[0]->conf.control_html_output) + response_client(client_socket, not_found_response_template,NULL); + else + response_client(client_socket, not_found_response_template_raw,NULL); + } + + return 1; } @@ -2101,136 +2101,127 @@ static unsigned short int handle_get(int client_socket, const char* url, void *u static unsigned short int read_client(int client_socket, void *userdata, char *auth) { - unsigned short int alive = 1; - unsigned short int ret = 1; - char buffer[1024] = {'\0'}; - unsigned short int length = 1023; - struct context **cnt = userdata; + unsigned short int alive = 1; + unsigned short int ret = 1; + char buffer[1024] = {'\0'}; + unsigned short int length = 1023; + struct context **cnt = userdata; - /* lock the mutex */ - pthread_mutex_lock(&httpd_mutex); + /* lock the mutex */ + pthread_mutex_lock(&httpd_mutex); - while (alive) - { - ssize_t nread = 0, readb = -1; + while (alive) { + ssize_t nread = 0, readb = -1; - nread = read (client_socket, buffer, length); + nread = read (client_socket, buffer, length); - if (nread <= 0) { - motion_log(LOG_ERR, 1, "httpd First read"); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } - else { - char method[10]={'\0'}; - char url[512]={'\0'}; - char protocol[10]={'\0'}; - char *authentication=NULL; + if (nread <= 0) { + motion_log(LOG_ERR, 1, "httpd First read"); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } else { + char method[10]={'\0'}; + char url[512]={'\0'}; + char protocol[10]={'\0'}; + char *authentication=NULL; - buffer[nread] = '\0'; + buffer[nread] = '\0'; - warningkill = sscanf (buffer, "%9s %511s %9s", method, url, protocol); + warningkill = sscanf (buffer, "%9s %511s %9s", method, url, protocol); - while ((strstr (buffer, "\r\n\r\n") == NULL) && (readb != 0) && (nread < length)){ - readb = read (client_socket, buffer+nread, sizeof (buffer) - nread); + while ((strstr (buffer, "\r\n\r\n") == NULL) && (readb != 0) && (nread < length)) { + readb = read (client_socket, buffer+nread, sizeof (buffer) - nread); - if (readb == -1){ - nread = -1; - break; - } + if (readb == -1) { + nread = -1; + break; + } - nread +=readb; - - if (nread > length) { - motion_log(LOG_ERR, 1, "httpd End buffer reached waiting for buffer ending"); - break; - } - buffer[nread] = '\0'; - } + nread +=readb; + + if (nread > length) { + motion_log(LOG_ERR, 1, "httpd End buffer reached waiting for buffer ending"); + break; + } + buffer[nread] = '\0'; + } - /* Make sure the last read didn't fail. If it did, there's a - problem with the connection, so give up. */ - if (nread == -1) { - motion_log(LOG_ERR, 1, "httpd READ"); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } - alive = 0; + /* Make sure the last read didn't fail. If it did, there's a + problem with the connection, so give up. */ + if (nread == -1) { + motion_log(LOG_ERR, 1, "httpd READ"); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } + alive = 0; - /* Check Protocol */ - if (strcmp (protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) { - /* We don't understand this protocol. Report a bad response. */ - if (cnt[0]->conf.control_html_output) - warningkill = write (client_socket, bad_request_response, sizeof (bad_request_response)); - else - warningkill = write (client_socket, bad_request_response_raw, sizeof (bad_request_response_raw)); + /* Check Protocol */ + if (strcmp (protocol, "HTTP/1.0") && strcmp (protocol, "HTTP/1.1")) { + /* We don't understand this protocol. Report a bad response. */ + if (cnt[0]->conf.control_html_output) + warningkill = write (client_socket, bad_request_response, sizeof (bad_request_response)); + else + warningkill = write (client_socket, bad_request_response_raw, sizeof (bad_request_response_raw)); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } + pthread_mutex_unlock(&httpd_mutex); + return 1; + } - if (strcmp (method, "GET")) { - /* This server only implements the GET method. If client - uses other method, report the failure. */ - char response[1024]; - if (cnt[0]->conf.control_html_output) - snprintf (response, sizeof (response),bad_method_response_template, method); - else - snprintf (response, sizeof (response),bad_method_response_template_raw, method); - warningkill = write (client_socket, response, strlen (response)); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } + if (strcmp (method, "GET")) { + /* This server only implements the GET method. If client + uses other method, report the failure. */ + char response[1024]; + if (cnt[0]->conf.control_html_output) + snprintf (response, sizeof (response),bad_method_response_template, method); + else + snprintf (response, sizeof (response),bad_method_response_template_raw, method); + warningkill = write (client_socket, response, strlen (response)); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } - if ( auth != NULL) { - if ( (authentication = strstr(buffer,"Basic")) ) { - char *end_auth = NULL; - authentication = authentication + 6; + if (auth != NULL) { + if ((authentication = strstr(buffer,"Basic")) ) { + char *end_auth = NULL; + authentication = authentication + 6; - if ( (end_auth = strstr(authentication,"\r\n")) ) { - authentication[end_auth - authentication] = '\0'; - } else { - char response[1024]; - snprintf (response, sizeof (response),request_auth_response_template, method); - warningkill = write (client_socket, response, strlen (response)); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } + if ((end_auth = strstr(authentication,"\r\n")) ) { + authentication[end_auth - authentication] = '\0'; + } else { + char response[1024]; + snprintf (response, sizeof (response),request_auth_response_template, method); + warningkill = write (client_socket, response, strlen (response)); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } - // Don't allow to change control_authentication from http control - // If it has to be allowed reenable check_authentication() - /*if ( !check_authentication(auth, authentication, - strlen(cnt[0]->conf.control_authentication), - cnt[0]->conf.control_authentication)) { - */ + if (strcmp(auth, authentication)) { + char response[1024]={'\0'}; + snprintf(response, sizeof (response), request_auth_response_template, method); + warningkill = write (client_socket, response, strlen (response)); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } else { + ret = handle_get (client_socket, url, cnt); + /* A valid auth request. Process it. */ + } + } else { + // Request Authorization + char response[1024]={'\0'}; + snprintf (response, sizeof (response),request_auth_response_template, method); + warningkill = write (client_socket, response, strlen (response)); + pthread_mutex_unlock(&httpd_mutex); + return 1; + } + } else { + ret = handle_get(client_socket, url, cnt); + /* A valid request. Process it. */ + } + } + } + pthread_mutex_unlock(&httpd_mutex); - if (strcmp(auth, authentication)){ - char response[1024]={'\0'}; - snprintf(response, sizeof (response), request_auth_response_template, method); - warningkill = write (client_socket, response, strlen (response)); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } else { - ret = handle_get (client_socket, url, cnt); - /* A valid auth request. Process it. */ - } - } else { - // Request Authorization - char response[1024]={'\0'}; - snprintf (response, sizeof (response),request_auth_response_template, method); - warningkill = write (client_socket, response, strlen (response)); - pthread_mutex_unlock(&httpd_mutex); - return 1; - } - } else { - ret = handle_get(client_socket, url, cnt); - /* A valid request. Process it. */ - } - } - } - pthread_mutex_unlock(&httpd_mutex); - - return ret; + return ret; } @@ -2239,31 +2230,31 @@ static unsigned short int read_client(int client_socket, void *userdata, char *a This function waits timeout seconds for listen socket. Returns : - -1 if the timeout expires or on accept error. - curfd (client socket) on accept success. + -1 if the timeout expires or on accept error. + curfd (client socket) on accept success. */ static int acceptnonblocking(int serverfd, int timeout) { - int curfd; - socklen_t namelen = sizeof(struct sockaddr_in); - struct sockaddr_in client; - struct timeval tm; - fd_set fds; + int curfd; + socklen_t namelen = sizeof(struct sockaddr_in); + struct sockaddr_in client; + struct timeval tm; + fd_set fds; - tm.tv_sec = timeout; /* Timeout in seconds */ - tm.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(serverfd,&fds); - - if( select (serverfd + 1, &fds, NULL, NULL, &tm) > 0){ - if(FD_ISSET(serverfd, &fds)) { - if((curfd = accept(serverfd, (struct sockaddr*)&client, &namelen))>0) - return(curfd); - } - } + tm.tv_sec = timeout; /* Timeout in seconds */ + tm.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(serverfd,&fds); + + if (select (serverfd + 1, &fds, NULL, NULL, &tm) > 0) { + if (FD_ISSET(serverfd, &fds)) { + if ((curfd = accept(serverfd, (struct sockaddr*)&client, &namelen)) > 0) + return(curfd); + } + } - return -1; + return -1; } @@ -2273,105 +2264,106 @@ static int acceptnonblocking(int serverfd, int timeout) void httpd_run(struct context **cnt) { - int sd, client_socket_fd, val = 1; - unsigned short int client_sent_quit_message = 1, closehttpd = 0; - struct sockaddr_in servAddr; - struct sigaction act; - char *authentication = NULL; + int sd, client_socket_fd, val = 1; + unsigned short int client_sent_quit_message = 1, closehttpd = 0; + struct sockaddr_in servAddr; + struct sigaction act; + char *authentication = NULL; - /* Initialize the mutex */ - pthread_mutex_init(&httpd_mutex, NULL); + /* Initialize the mutex */ + pthread_mutex_init(&httpd_mutex, NULL); - /* set signal handlers TO IGNORE */ - memset(&act,0,sizeof(act)); - sigemptyset(&act.sa_mask); - act.sa_handler = SIG_IGN; - sigaction(SIGPIPE,&act,NULL); - sigaction(SIGCHLD,&act,NULL); + /* set signal handlers TO IGNORE */ + memset(&act,0,sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE,&act,NULL); + sigaction(SIGCHLD,&act,NULL); - /* create socket */ - sd = socket(AF_INET, SOCK_STREAM, 0); + /* create socket */ + sd = socket(AF_INET, SOCK_STREAM, 0); - if (sd<0) { - motion_log(LOG_ERR, 1, "httpd socket"); - pthread_mutex_destroy(&httpd_mutex); - return; - } + if (sd < 0) { + motion_log(LOG_ERR, 1, "httpd socket"); + pthread_mutex_destroy(&httpd_mutex); + return; + } - /* bind server port */ - servAddr.sin_family = AF_INET; - if (cnt[0]->conf.control_localhost) - servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - else - servAddr.sin_addr.s_addr = htonl(INADDR_ANY); - servAddr.sin_port = htons(cnt[0]->conf.control_port); + /* bind server port */ + servAddr.sin_family = AF_INET; + if (cnt[0]->conf.control_localhost) + servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + else + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(cnt[0]->conf.control_port); - /* Reuse Address */ - - setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof( int ) ) ; + /* Reuse Address */ + + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) ; - if (bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr))<0) { - motion_log(LOG_ERR, 1, "httpd bind()"); - close(sd); - pthread_mutex_destroy(&httpd_mutex); - return; - } + if (bind(sd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0) { + motion_log(LOG_ERR, 1, "httpd bind()"); + close(sd); + pthread_mutex_destroy(&httpd_mutex); + return; + } - if (listen(sd,5) == -1){ - motion_log(LOG_ERR, 1, "httpd listen()"); - close(sd); - pthread_mutex_destroy(&httpd_mutex); - return; - } + if (listen(sd,5) == -1) { + motion_log(LOG_ERR, 1, "httpd listen()"); + close(sd); + pthread_mutex_destroy(&httpd_mutex); + return; + } - motion_log(LOG_DEBUG, 0, "motion-httpd/"VERSION" running, accepting connections"); - motion_log(LOG_DEBUG, 0, "motion-httpd: waiting for data on port TCP %d", cnt[0]->conf.control_port); + motion_log(LOG_DEBUG, 0, "motion-httpd/"VERSION" running, accepting connections"); + motion_log(LOG_DEBUG, 0, "motion-httpd: waiting for data on port TCP %d", cnt[0]->conf.control_port); - if (cnt[0]->conf.control_authentication != NULL ) { - char *userpass = NULL; - size_t auth_size = strlen(cnt[0]->conf.control_authentication); + if (cnt[0]->conf.control_authentication != NULL) { + char *userpass = NULL; + size_t auth_size = strlen(cnt[0]->conf.control_authentication); - authentication = (char *) mymalloc(BASE64_LENGTH(auth_size) + 1); - userpass = mymalloc(auth_size + 4); - /* base64_encode can read 3 bytes after the end of the string, initialize it */ - memset(userpass, 0, auth_size + 4); - strcpy(userpass, cnt[0]->conf.control_authentication); - base64_encode(userpass, authentication, auth_size); - free(userpass); - } + authentication = (char *) mymalloc(BASE64_LENGTH(auth_size) + 1); + userpass = mymalloc(auth_size + 4); + /* base64_encode can read 3 bytes after the end of the string, initialize it */ + memset(userpass, 0, auth_size + 4); + strcpy(userpass, cnt[0]->conf.control_authentication); + base64_encode(userpass, authentication, auth_size); + free(userpass); + } - while ((client_sent_quit_message) && (!closehttpd)) { + while ((client_sent_quit_message) && (!closehttpd)) { - client_socket_fd = acceptnonblocking(sd, 1); + client_socket_fd = acceptnonblocking(sd, 1); - if (client_socket_fd<0) { - if ((!cnt[0]) || (cnt[0]->finish)){ - motion_log(-1, 0, "httpd - Finishing"); - closehttpd = 1; - } - } else { - /* Get the Client request */ - client_sent_quit_message = read_client (client_socket_fd, cnt, authentication); - motion_log(-1, 0, "httpd - Read from client"); + if (client_socket_fd < 0) { + if ((!cnt[0]) || (cnt[0]->finish)){ + motion_log(-1, 0, "httpd - Finishing"); + closehttpd = 1; + } + } else { + /* Get the Client request */ + client_sent_quit_message = read_client (client_socket_fd, cnt, authentication); + motion_log(-1, 0, "httpd - Read from client"); - /* Close Connection */ - if (client_socket_fd) - close(client_socket_fd); - } + /* Close Connection */ + if (client_socket_fd) + close(client_socket_fd); + } - } + } - if (authentication != NULL) free(authentication); - close(sd); - motion_log(LOG_DEBUG, 0, "httpd Closing"); - pthread_mutex_destroy(&httpd_mutex); + if (authentication != NULL) + free(authentication); + close(sd); + motion_log(LOG_DEBUG, 0, "httpd Closing"); + pthread_mutex_destroy(&httpd_mutex); } void *motion_web_control(void *arg) { - struct context **cnt=arg; - httpd_run(cnt); - motion_log(LOG_DEBUG, 0, "httpd thread exit"); - pthread_exit(NULL); + struct context **cnt=arg; + httpd_run(cnt); + motion_log(LOG_DEBUG, 0, "httpd thread exit"); + pthread_exit(NULL); }