Index: webcam.c =================================================================== --- webcam.c (revisión: 292) +++ webcam.c (copia de trabajo) @@ -17,9 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include "picture.h" -/* picture.h already includes motion.h and this one webcam.h */ #include #include #include @@ -28,9 +26,6 @@ #include #include - - - /* This function sets up a TCP/IP socket for incoming requests. It is called only during * initialisation of Motion from the function webcam_init * The function sets up a a socket on the port number given by _port_. @@ -92,7 +87,14 @@ 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 * to be sent (either because there isn't any, or because the clients @@ -148,12 +150,10 @@ */ 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; client->nr++; @@ -194,14 +194,44 @@ } /* end while (client) */ } -/* Routine to create a new "tmpbuffer", which is a common - * object used by all clients connected to a single camera - */ -static struct webcam_buffer *webcam_tmpbuffer(int size) + +/* for debugging only */ +typedef struct { volatile int counter; } atomic_t; +static __inline__ void atomic_inc(atomic_t *v) { - struct webcam_buffer *tmpbuffer=mymalloc(sizeof(struct webcam_buffer)); - tmpbuffer->ref=0; - tmpbuffer->ptr=mymalloc(size); + __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. + * Get an unused webcam_tmpbuffer or create a new one + */ +static struct webcam_buffer *webcam_tmpbuffer(struct webcam *list, int 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; } @@ -222,11 +252,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; @@ -235,7 +266,7 @@ if (new->next) new->next->prev=new; - list->next=new; + list->next=new; } @@ -258,10 +289,8 @@ } } - if (tmpbuffer->ref<=0) { - free(tmpbuffer->ptr); - free(tmpbuffer); - } + if (tmpbuffer->ref<=0) + webcam_tmpbuffer_unuse(list, tmpbuffer); } @@ -291,6 +320,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; } @@ -301,6 +331,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"); @@ -313,7 +344,7 @@ while (next) { list=next; next=list->next; - + if (list->tmpbuffer) { free(list->tmpbuffer->ptr); free(list->tmpbuffer); @@ -322,6 +353,21 @@ close(list->socket); free(list); } + + tmpbuffer=cnt->webcam.tmpbuffer; + + while (tmpbuffer) { + if (tmpbuffer != cnt->webcam.tmpbuffer->next) + tmpbuffer=cnt->webcam.tmpbuffer->next; + else tmpbuffer = NULL; + + if (cnt->webcam.tmpbuffer->ptr) + free(cnt->webcam.tmpbuffer->ptr); + free(cnt->webcam.tmpbuffer); + cnt->webcam.tmpbuffer = NULL; + } + + } /* webcam_put is the starting point of the webcam loop. It is called from @@ -378,12 +424,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) { Index: webcam.h =================================================================== --- webcam.h (revisión: 292) +++ webcam.h (copia de trabajo) @@ -25,6 +25,8 @@ unsigned char *ptr; int ref; long size; + long buffersize; + struct webcam_buffer *next; }; struct webcam { Index: conf.c =================================================================== --- conf.c (revisión: 292) +++ conf.c (copia de trabajo) @@ -73,6 +73,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,