Index: motion/conf.c =================================================================== --- motion/conf.c (revision 444) +++ motion/conf.c (working copy) @@ -1623,7 +1623,7 @@ motion_log(LOG_INFO, 0, "%s: Writing config file to %s", __FUNCTION__, cnt[thread]->conf_filename); - conffile = myfopen(cnt[thread]->conf_filename, "w"); + conffile = myfopen(cnt[thread]->conf_filename, "w", 0); if (!conffile) continue; @@ -1666,7 +1666,7 @@ } fprintf(conffile, "\n"); - fclose(conffile); + myfclose(conffile); conffile = NULL; } } Index: motion/motion.c =================================================================== --- motion/motion.c (revision 444) +++ motion/motion.c (working copy) @@ -381,7 +381,7 @@ } if (ptr_logfile) - fclose(ptr_logfile); + myfclose(ptr_logfile); } @@ -2145,16 +2145,16 @@ * for an enter. */ if (cnt_list[0]->conf.pid_file) { - pidf = myfopen(cnt_list[0]->conf.pid_file, "w+"); + pidf = myfopen(cnt_list[0]->conf.pid_file, "w+", 0); if (pidf) { (void)fprintf(pidf, "%d\n", getpid()); - fclose(pidf); + myfclose(pidf); } else { motion_log(LOG_ERR, 1, "%s: Exit motion, cannot create process id file (pid file) %s", __FUNCTION__, cnt_list[0]->conf.pid_file); if (ptr_logfile) - fclose(ptr_logfile); + myfclose(ptr_logfile); exit(0); } } @@ -2740,6 +2740,13 @@ return 0; } +#define MYBUFCOUNT 32 +struct MyBuffer { + FILE* fh; + char* buffer; + size_t bufsize; +} buffers[MYBUFCOUNT]; + /** * myfopen * @@ -2747,17 +2754,25 @@ * (which is: path does not exist), the path is created and then things are * tried again. This is faster then trying to create that path over and over * again. If someone removes the path after it was created, myfopen will - * recreate the path automatically. + * recreate the path automatically. If the bufsize is set to > 0, we will + * allocate (or re-use) write buffers to use instead of the default ones. + * This gives us much higher throughput in many cases. * * Parameters: * * path - path to the file to open * mode - open mode + * bufsize - size of write buffers, 0 == OS default * * Returns: the file stream object */ -FILE * myfopen(const char *path, const char *mode) +FILE * myfopen(const char *path, const char *mode, size_t bufsize) { + static int bufferInit = 0; + if (!bufferInit) { + bufferInit = 1; + memset(buffers, 0x00, sizeof(buffers)); + } /* first, just try to open the file */ FILE *dummy = fopen(path, mode); @@ -2772,23 +2787,87 @@ /* and retry opening the file */ dummy = fopen(path, mode); - if (dummy) - return dummy; } + } + + if (dummy) { + if (bufsize > 0) { + int i = 0; + for (i = 0; i < MYBUFCOUNT; i++) { + int first = -1; + if (!buffers[i].fh) { + if (first == -1) + first = i; + if (buffers[i].buffer == NULL || + buffers[i].bufsize >= bufsize || + (i == (MYBUFCOUNT - 1) && first >= 0)) { + if (buffers[i].buffer == NULL) { + /* We are allocating a new buffer */ + buffers[i].fh = dummy; + buffers[i].buffer = mymalloc(bufsize); + buffers[i].bufsize = bufsize; + } + else if (buffers[i].bufsize >= bufsize) { + /* We are using an old buffer */ + buffers[i].fh = dummy; + } + else { + /* We are reusing an old buffer, but it is too + * small, realloc it */ + i = first; + buffers[i].fh = dummy; + buffers[i].buffer = myrealloc(buffers[i].buffer, + bufsize, "myfopen"); + buffers[i].bufsize = bufsize; + } + if (buffers[i].buffer == NULL) { + /* our allocation failed, so just use the default + * OS buffers */ + buffers[i].fh = NULL; + buffers[i].bufsize = 0; + } + else { + setvbuf(buffers[i].fh, buffers[i].buffer, + _IOFBF, buffers[i].bufsize); + } + break; + } + } + } + } + } else { /* two possibilities - * 1: there was an other error while trying to open the file for the first time + * 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, "%s: Error opening file %s with mode %s", __FUNCTION__, path, mode); - - return NULL; } return dummy; } +int myfclose(FILE* fh) +{ + int i = 0; + int rval = fclose(fh); + for (i = 0; i < MYBUFCOUNT; i++) { + if (buffers[i].fh == fh) { + buffers[i].fh = NULL; +#if 0 /* Don't free the buffers for now, reuse them instead */ + if (buffers[i].buffer) + free(buffers[i].buffer); + buffers[i].buffer = NULL; + buffers[i].bufsize = 0; +#endif + break; + } + } + return rval; +} + /** * mystrftime * Index: motion/motion.h =================================================================== --- motion/motion.h (revision 444) +++ motion/motion.h (working copy) @@ -191,6 +191,8 @@ #define UPDATE_REF_FRAME 1 #define RESET_REF_FRAME 2 +#define BUFSIZE_1MEG (1024 * 1024) + /* Forward declaration, used in track.h */ struct images; @@ -421,7 +423,8 @@ int http_bindsock(int, int); void * mymalloc(size_t); void * myrealloc(void *, size_t, const char *); -FILE * myfopen(const char *, const char *); +FILE * myfopen(const char *, const char *, size_t); +int myfclose(FILE *); size_t mystrftime(struct context *, char *, size_t, const char *, const struct tm *, const char *, int); int create_path(const char *); #endif /* _INCLUDE_MOTION_H */ Index: motion/event.c =================================================================== --- motion/event.c (revision 444) +++ motion/event.c (working copy) @@ -398,7 +398,7 @@ snprintf(cnt->extpipefilename, PATH_MAX - 4, "%s/%s", cnt->conf.filepath, stamp); /* Open a dummy file to check if path is correct */ - fd_dummy = myfopen(cnt->extpipefilename, "w"); + fd_dummy = myfopen(cnt->extpipefilename, "w", 0); /* TODO: trigger some warning instead of only log an error message */ if (fd_dummy == NULL) { @@ -414,7 +414,7 @@ } - fclose(fd_dummy); + myfclose(fd_dummy); unlink(cnt->extpipefilename); mystrftime(cnt, stamp, sizeof(stamp), cnt->conf.extpipe, currenttime_tm, cnt->extpipefilename, 0); Index: motion/ffmpeg.c =================================================================== --- motion/ffmpeg.c (revision 444) +++ motion/ffmpeg.c (working copy) @@ -76,7 +76,9 @@ static int file_open_append(URLContext *h, const char *filename, int flags) { const char *colon; - int access_flags, fd; + const char *mode; + FILE *fh; + size_t bufsize = 0; /* Skip past the protocol part of filename. */ colon = strchr(filename, ':'); @@ -86,18 +88,20 @@ if (flags & URL_RDWR) { - access_flags = O_CREAT | O_APPEND | O_RDWR; + mode = "ab+"; + bufsize = BUFSIZE_1MEG; } else if (flags & URL_WRONLY) { - access_flags = O_CREAT | O_APPEND | O_WRONLY; + mode = "ab"; + bufsize = BUFSIZE_1MEG; } else { - access_flags = O_RDONLY; + mode = "rb"; } - fd = open(filename, access_flags, 0666); - if (fd < 0) + fh = myfopen(filename, mode, bufsize); + if (fh == NULL) return AVERROR(ENOENT); - h->priv_data = (void *)(size_t)fd; + h->priv_data = (void *)fh; return 0; } @@ -131,49 +135,52 @@ static int file_open(URLContext *h, const char *filename, int flags) { - int access_flags, fd; - + const char *mode; + FILE *fh; + size_t bufsize = 0; + av_strstart(filename, "file:", &filename); if (flags & URL_RDWR) { - access_flags = O_CREAT | O_TRUNC | O_RDWR; + mode = "wb+"; + bufsize = BUFSIZE_1MEG; } else if (flags & URL_WRONLY) { - access_flags = O_CREAT | O_TRUNC | O_WRONLY; + mode = "wb"; + bufsize = BUFSIZE_1MEG; } else { - access_flags = O_RDONLY; + mode = "rb"; } -#ifdef O_BINARY - access_flags |= O_BINARY; -#endif - fd = open(filename, access_flags, 0666); - if (fd < 0) + fh = myfopen(filename, mode, bufsize); + if (fh == NULL) return AVERROR(ENOENT); - h->priv_data = (void *)(size_t)fd; + h->priv_data = (void *)fh; 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); + FILE *fh = (FILE *)h->priv_data; + return fread(buf, 1, size, fh); } static int file_write(URLContext *h, unsigned char *buf, int size) { - int fd = (size_t)h->priv_data; - return write(fd, buf, size); + FILE *fh = (FILE *)h->priv_data; + return fwrite(buf, 1, size, fh); } static int64_t file_seek(URLContext *h, int64_t pos, int whence) { - int fd = (size_t)h->priv_data; - return lseek(fd, pos, whence); + FILE *fh = (FILE *)h->priv_data; + if (fseek(fh, pos, whence)) + return -1; + return ftell(fh); } static int file_close(URLContext *h) { - int fd = (size_t)h->priv_data; - return close(fd); + FILE *fh = (FILE *)h->priv_data; + return myfclose(fh); } URLProtocol file_protocol = { Index: motion/logger.c =================================================================== --- motion/logger.c (revision 444) +++ motion/logger.c (working copy) @@ -33,7 +33,7 @@ */ FILE * set_logfile(const char *logfile_name) { - return logfile = myfopen(logfile_name, "a"); + return logfile = myfopen(logfile_name, "a", 0); } Index: motion/picture.c =================================================================== --- motion/picture.c (revision 444) +++ motion/picture.c (working copy) @@ -521,7 +521,7 @@ { FILE *picture; - picture = myfopen(file, "w"); + picture = myfopen(file, "w", BUFSIZE_1MEG); if (!picture) { /* Report to syslog - suggest solution if the problem is access rights to target dir */ if (errno == EACCES) { @@ -540,7 +540,7 @@ } put_picture_fd(cnt, picture, image, cnt->conf.quality); - fclose(picture); + myfclose(picture); event(cnt, EVENT_FILECREATE, NULL, file, (void *)(unsigned long)ftype, NULL); } @@ -617,7 +617,7 @@ { FILE *picture; - picture = myfopen(file, "w"); + picture = myfopen(file, "w", BUFSIZE_1MEG); if (!picture) { /* Report to syslog - suggest solution if the problem is access rights to target dir */ if (errno == EACCES) { @@ -643,7 +643,7 @@ return; } - fclose(picture); + myfclose(picture); motion_log(LOG_ERR, 0, "%s: Creating empty mask %s\nPlease edit this file and " "re-run motion to enable mask feature", __FUNCTION__, cnt->conf.mask_file);