diff -Naur motion-20060711-051001_orig/conf.c motion-20060711-051001/conf.c --- motion-20060711-051001_orig/conf.c 2006-07-11 05:10:02.000000000 +0200 +++ motion-20060711-051001/conf.c 2006-07-12 07:18:31.000000000 +0200 @@ -76,6 +76,7 @@ ffmpeg_cap_motion: 0, ffmpeg_bps: DEF_FFMPEG_BPS, ffmpeg_vbr: DEF_FFMPEG_VBR, + ffmpeg_deinterlace: 0, ffmpeg_video_codec: DEF_FFMPEG_CODEC, webcam_port: 0, webcam_quality: 50, diff -Naur motion-20060711-051001_orig/webcam.c motion-20060711-051001/webcam.c --- motion-20060711-051001_orig/webcam.c 2006-07-12 07:58:40.000000000 +0200 +++ motion-20060711-051001/webcam.c 2006-07-12 15:16:46.000000000 +0200 @@ -92,6 +92,12 @@ return -1; } +/* Put webcam_tmpbuffer to reuse onto list of unused webcam_tmpbuffers */ +static void webcam_tmpbuffer_unuse(struct webcam *list, struct webcam_buffer *tmpbuffer) +{ + tmpbuffer->next=list->tmpbuffer; + list->tmpbuffer=tmpbuffer; +} /* Webcam flush sends any outstanding data to all connected clients. * It continuously goes through the client list until no data is able @@ -159,11 +165,9 @@ */ if ( (client->filepos >= client->tmpbuffer->size) || (written < 0 && errno!=EAGAIN)) { - /* If no other clients need this buffer, free it */ - if (--client->tmpbuffer->ref <= 0) { - free(client->tmpbuffer->ptr); - free(client->tmpbuffer); - } + /* If no other clients need this buffer, unuse it */ + if (--client->tmpbuffer->ref <= 0) + webcam_tmpbuffer_unuse(list, client->tmpbuffer); /* Mark this client's buffer as empty */ client->tmpbuffer=NULL; @@ -205,19 +209,45 @@ } /* end while (client) */ } +/* for debugging only */ +typedef struct { volatile int counter; } atomic_t; +static __inline__ void atomic_inc(atomic_t *v) +{ + __asm__ __volatile__( + "incl %0" + :"=m" (v->counter) + :"m" (v->counter)); +} + /* Routine to create a new "tmpbuffer", which is a common - * object used by all clients connected to a single camera + * object used by all clients connected to a single camera. + * Get an unused webcam_tmpbuffer or create a new one */ -static struct webcam_buffer *webcam_tmpbuffer(int size) +static struct webcam_buffer *webcam_tmpbuffer(struct webcam *list, int size) { - struct webcam_buffer *tmpbuffer=mymalloc(sizeof(struct webcam_buffer)); - tmpbuffer->ref=0; - tmpbuffer->ptr=mymalloc(size); - + static atomic_t numwebcambuffer={0}; + struct webcam_buffer *tmpbuffer; + + tmpbuffer=list->tmpbuffer; + if (tmpbuffer) { + list->tmpbuffer=tmpbuffer->next; + if (size > tmpbuffer->buffersize) { + tmpbuffer->ptr=myrealloc(tmpbuffer->ptr,size,"webcam_tmpbuffer"); + motion_log(LOG_INFO, 0, "webcambuffer realloc (size from %d to %d)", tmpbuffer->buffersize, size); + tmpbuffer->buffersize=size; + } + } else { + tmpbuffer=mymalloc(sizeof(struct webcam_buffer)); + tmpbuffer->ref=0; + tmpbuffer->ptr=mymalloc(size); + tmpbuffer->buffersize=size; + tmpbuffer->next = NULL; + atomic_inc(&numwebcambuffer); + motion_log(LOG_INFO, 0, "webcambuffer new (count %d size %d)", numwebcambuffer,size); + } return tmpbuffer; } - static void webcam_add_client(struct webcam *list, int sc) { struct webcam *new = mymalloc(sizeof(struct webcam)); @@ -233,11 +263,12 @@ memset(new, 0, sizeof(struct webcam)); new->socket=sc; - if ((new->tmpbuffer = webcam_tmpbuffer(sizeof(header))) == NULL) { + if ((new->tmpbuffer = webcam_tmpbuffer(list, sizeof(header))) == NULL) { motion_log(LOG_ERR, 1, "Error creating tmpbuffer in webcam_add_client"); } else { memcpy(new->tmpbuffer->ptr, header, sizeof(header)-1); new->tmpbuffer->size = sizeof(header)-1; + new->tmpbuffer->ref++; } new->prev=list; @@ -269,10 +300,8 @@ } } - if (tmpbuffer->ref<=0) { - free(tmpbuffer->ptr); - free(tmpbuffer); - } + if (tmpbuffer->ref<=0) + webcam_tmpbuffer_unuse(list, tmpbuffer); } @@ -338,6 +367,7 @@ cnt->webcam.socket=http_bindsock(cnt->conf.webcam_port, cnt->conf.webcam_localhost); cnt->webcam.next=NULL; cnt->webcam.prev=NULL; + cnt->webcam.tmpbuffer=NULL; return cnt->webcam.socket; } @@ -348,6 +378,7 @@ { struct webcam *list; struct webcam *next = cnt->webcam.next; + struct webcam_buffer *tmpbuffer; if (cnt->conf.setup_mode) motion_log(-1, 0, "Closing webcam listen socket"); @@ -369,6 +400,13 @@ close(list->socket); free(list); } + tmpbuffer=cnt->webcam.tmpbuffer; + while (tmpbuffer) { + tmpbuffer=cnt->webcam.tmpbuffer->next; + + free(cnt->webcam.tmpbuffer->ptr); + free(cnt->webcam.tmpbuffer); + } #ifdef HAVE_FFMPEG avcodec_close(cnt->webcam.codec_context); av_free(cnt->webcam.codec_context); @@ -432,12 +470,12 @@ /* Check if any clients have available buffers */ if (webcam_check_write(&cnt->webcam)) { - /* yes - create a new tmpbuffer for current image. + /* yes - get a tmpbuffer for current image. * Note that this should create a buffer which is *much* larger * than necessary, but it is difficult to estimate the * minimum size actually required. */ - tmpbuffer = webcam_tmpbuffer(cnt->imgs.size); + tmpbuffer = webcam_tmpbuffer(&cnt->webcam, cnt->imgs.size); /* check if allocation went ok */ if (tmpbuffer) { diff -Naur motion-20060711-051001_orig/webcam.h motion-20060711-051001/webcam.h --- motion-20060711-051001_orig/webcam.h 2006-07-12 07:55:10.000000000 +0200 +++ motion-20060711-051001/webcam.h 2006-07-12 07:18:36.000000000 +0200 @@ -29,6 +29,8 @@ unsigned char *ptr; int ref; long size; + long buffersize; + struct webcam_buffer *next; }; struct webcam {