/* zero all the stats structures */ void stats_zero(void) { int dir, fd; unsigned i; char *fname; unsigned counters[STATS_END]; x_asprintf(&fname, "%s/stats", cache_dir); unlink(fname); free(fname); for (dir=0;dir<=0xF;dir++) { x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir); fd = safe_open(fname); if (fd == -1) { free(fname); continue; } memset(counters, 0, sizeof(counters)); lock_fd(fd); stats_read_fd(fd, counters); for (i=0;stats_info[i].message;i++) { if (!(stats_info[i].flags & FLAG_NOZERO)) { counters[stats_info[i].stat] = 0; } } write_stats(fd, counters); close(fd); free(fname); } }
int sleep_period(sleep_handler_t *sleep_handler, double *freq) { handler_t *handler=(handler_t *)sleep_handler; struct timeval current_time; struct timeval diff; struct timeval sleep_time_tv; struct timespec sleep_time_ts; // lets take current time if(gettimeofday(¤t_time, NULL)) { free(handler->errstr); x_asprintf(&handler->errstr, "Error calling gettimeofday(): %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 2; } // lets calculate diff if(timeval_subtract(&diff, ¤t_time, &handler->last_call_time)) { free(handler->errstr); x_asprintf(&handler->errstr, "Your system clock is running backwards!\n"); handler->last_call_time.tv_sec=current_time.tv_sec; handler->last_call_time.tv_usec=current_time.tv_usec; return 2; } // and sleep time if(timeval_subtract(&sleep_time_tv, &handler->period, &diff)) { double period; // negative, we've got a delay; lets calculate it period=(double)diff.tv_sec; period+=((double)diff.tv_usec)/1e6; *freq=1/period; if(gettimeofday(&handler->last_call_time, NULL)) { free(handler->errstr); x_asprintf(&handler->errstr, "Error calling gettimeofday(): %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); free(handler); return 2; } return 1; } else { // here, just sleep sleep_time_ts.tv_sec=sleep_time_tv.tv_sec; sleep_time_ts.tv_nsec=(long)(sleep_time_tv.tv_usec*1e3); errno=0; if(nanosleep(&sleep_time_ts, NULL)) { free(handler->errstr); x_asprintf(&handler->errstr, "Error calling nanosleep(): %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); } if(gettimeofday(&handler->last_call_time, NULL)) { free(handler->errstr); x_asprintf(&handler->errstr, "Error calling gettimeofday(): %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); free(handler); return 2; } } return 0; }
log_handler_t *log_create_handler(int verbose_level, int motion, const char *path, char **errstr) { handler_t *handler; char buffer[256]; // allocate handler handler=(handler_t *)x_malloc(sizeof(handler_t)); // set level handler->level=verbose_level; // motion handler->motion=motion; // open stream if(path==NULL) handler->stream=stdout; else { errno=0; handler->stream=fopen(path, "a"); if(handler->stream==NULL) { x_asprintf(errstr, "Error opening log file '%s': %s", path, strerror_r(errno, buffer, 256)); return NULL; } } return (log_handler_t *)handler; }
/* sum and display the total stats for all cache dirs */ void stats_summary(void) { int dir, i; unsigned counters[STATS_END]; memset(counters, 0, sizeof(counters)); /* add up the stats in each directory */ for (dir=-1;dir<=0xF;dir++) { char *fname; if (dir == -1) { x_asprintf(&fname, "%s/stats", cache_dir); } else { x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir); } stats_read(fname, counters); free(fname); /* oh what a nasty hack ... */ if (dir == -1) { counters[STATS_MAXSIZE] = 0; } } printf("cache directory %s\n", cache_dir); /* and display them */ for (i=0;stats_info[i].message;i++) { enum stats stat = stats_info[i].stat; if (counters[stat] == 0 && !(stats_info[i].flags & FLAG_ALWAYS)) { continue; } printf("%s ", stats_info[i].message); if (stats_info[i].fn) { stats_info[i].fn(counters[stat]); printf("\n"); } else { printf("%8u\n", counters[stat]); } } }
/* set the per directory limits */ int stats_set_limits(long maxfiles, long maxsize) { int dir; unsigned counters[STATS_END]; if (maxfiles != -1) { maxfiles /= 16; } if (maxsize != -1) { maxsize /= 16; } if (create_dir(cache_dir) != 0) { return 1; } /* set the limits in each directory */ for (dir=0;dir<=0xF;dir++) { char *fname, *cdir; int fd; x_asprintf(&cdir, "%s/%1x", cache_dir, dir); if (create_dir(cdir) != 0) { return 1; } x_asprintf(&fname, "%s/stats", cdir); free(cdir); memset(counters, 0, sizeof(counters)); fd = safe_open(fname); if (fd != -1) { lock_fd(fd); stats_read_fd(fd, counters); if (maxfiles != -1) { counters[STATS_MAXFILES] = maxfiles; } if (maxsize != -1) { counters[STATS_MAXSIZE] = maxsize; } write_stats(fd, counters); close(fd); } free(fname); } return 0; }
/* update the stats counter for this compile */ static void stats_update_size(enum stats stat, size_t size, size_t numfiles) { int fd; unsigned counters[STATS_END]; int need_cleanup = 0; if (getenv("CCACHE_NOSTATS")) return; if (!stats_file) { if (!cache_dir) return; x_asprintf(&stats_file, "%s/stats", cache_dir); } /* open safely to try to prevent symlink races */ fd = safe_open(stats_file); /* still can't get it? don't bother ... */ if (fd == -1) return; memset(counters, 0, sizeof(counters)); if (lock_fd(fd) != 0) { close(fd); return; } /* read in the old stats */ stats_read_fd(fd, counters); /* update them */ counters[stat]++; /* on a cache miss we up the file count and size */ if (stat == STATS_TOCACHE) { counters[STATS_NUMFILES] += numfiles; counters[STATS_TOTALSIZE] += size; } /* and write them out */ write_stats(fd, counters); close(fd); /* we might need to cleanup if the cache has now got too big */ if (counters[STATS_MAXFILES] != 0 && counters[STATS_NUMFILES] > counters[STATS_MAXFILES]) { need_cleanup = 1; } if (counters[STATS_MAXSIZE] != 0 && counters[STATS_TOTALSIZE] > counters[STATS_MAXSIZE]) { need_cleanup = 1; } if (need_cleanup) { char *p = dirname(stats_file); cleanup_dir(p, counters[STATS_MAXFILES], counters[STATS_MAXSIZE], numfiles); free(p); } }
/* copy a file - used when hard links don't work the copy is done via a temporary file and atomic rename */ int copy_file(const char *src, const char *dest) { int fd1, fd2; char buf[10240]; int n; char *tmp_name; mode_t mask; x_asprintf(&tmp_name, "%s.XXXXXX", dest); fd1 = open(src, O_RDONLY); if (fd1 == -1) { free(tmp_name); return -1; } fd2 = mkstemp(tmp_name); if (fd2 == -1) { close(fd1); free(tmp_name); return -1; } while ((n = read(fd1, buf, sizeof(buf))) > 0) { if (write(fd2, buf, n) != n) { close(fd2); close(fd1); unlink(tmp_name); free(tmp_name); return -1; } } close(fd1); /* get perms right on the tmp file */ mask = umask(0); fchmod(fd2, 0666 & ~mask); umask(mask); /* the close can fail on NFS if out of space */ if (close(fd2) == -1) { unlink(tmp_name); free(tmp_name); return -1; } unlink(dest); if (rename(tmp_name, dest) == -1) { unlink(tmp_name); free(tmp_name); return -1; } free(tmp_name); return 0; }
/* find an executable by name in $PATH. Exclude any that are links to exclude_name */ char *find_executable(const char *name, const char *exclude_name) { char *path; char *tok; struct stat st1, st2; if (*name == '/') { return x_strdup(name); } path = getenv("F90CACHE_PATH"); if (!path) { path = getenv("PATH"); } if (!path) { fc_log("no PATH variable!?\n"); return NULL; } path = x_strdup(path); /* search the path looking for the first compiler of the right name that isn't us */ for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) { char *fname; x_asprintf(&fname, "%s/%s", tok, name); /* look for a normal executable file */ if (access(fname, X_OK) == 0 && lstat(fname, &st1) == 0 && stat(fname, &st2) == 0 && S_ISREG(st2.st_mode)) { /* if its a symlink then ensure it doesn't point at something called exclude_name */ if (S_ISLNK(st1.st_mode)) { char *buf = x_realpath(fname); if (buf) { char *p = str_basename(buf); if (strcmp(p, exclude_name) == 0) { /* its a link to "f90cache" ! */ free(p); free(buf); continue; } free(buf); free(p); } } /* found it! */ free(path); return fname; } free(fname); } return NULL; }
int main(int argc, char *argv[]) { char *p; cache_dir = getenv("CCACHE_DIR"); if (!cache_dir) { x_asprintf(&cache_dir, "%s/.ccache", get_home_directory()); } temp_dir = getenv("CCACHE_TEMPDIR"); if (!temp_dir) { temp_dir = cache_dir; } cache_logfile = getenv("CCACHE_LOGFILE"); setup_uncached_err(); /* the user might have set CCACHE_UMASK */ p = getenv("CCACHE_UMASK"); if (p) { mode_t mask; errno = 0; mask = strtol(p, NULL, 8); if (errno == 0) { umask(mask); } } /* check if we are being invoked as "ccache" */ if (strlen(argv[0]) >= strlen(MYNAME) && strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) { if (argc < 2) { usage(); exit(1); } /* if the first argument isn't an option, then assume we are being passed a compiler name and options */ if (argv[1][0] == '-') { return ccache_main(argc, argv); } } /* make sure the cache dir exists */ if (create_dir(cache_dir) != 0) { fprintf(stderr,"ccache: failed to create %s (%s)\n", cache_dir, strerror(errno)); exit(1); } ccache(argc, argv); return 1; }
/* cleanup in all cache subdirs */ void cleanup_all(const char *dir) { unsigned counters[STATS_END]; char *dname, *sfile; int i; for (i = 0; i <= 0xF; i++) { x_asprintf(&dname, "%s/%1x", dir, i); x_asprintf(&sfile, "%s/%1x/stats", dir, i); memset(counters, 0, sizeof(counters)); stats_read(sfile, counters); cleanup_dir(dname, counters[STATS_MAXFILES], counters[STATS_MAXSIZE]); free(dname); free(sfile); } }
static void delete_sibling_file(const char *base, const char *extension) { struct stat st; char *path; x_asprintf(&path, "%s%s", base, extension); if (lstat(path, &st) == 0) { delete_file(path, file_size(&st) / 1024); } else if (errno != ENOENT) { cc_log("Failed to stat %s (%s)", path, strerror(errno)); } free(path); }
int v4l_start_cap(v4l_handler_t *v4l_handler, v4l_cam_ident_t v4l_cam_ident) { handler_t *handler=(handler_t *)v4l_handler; int b; // no double call if(handler->buffer_pos!=-1) { free(handler->errstr); x_asprintf(&handler->errstr, "v4l_start_cap() should be called only once.\n"); return 1; } // Switch camera if(v4l_set_cam(handler, v4l_cam_ident)) return 1; handler->vid_mmap.width=handler->v4l_cam_par[v4l_cam_ident].width; handler->vid_mmap.height=handler->v4l_cam_par[v4l_cam_ident].height; handler->vid_mmap.format=handler->v4l_cam_par[v4l_cam_ident].palette; // start capture to buffer for(b=0;b<handler->vid_mbuf.frames;b++) { handler->vid_mmap.frame=b; errno=0; if(ioctl(handler->fd, VIDIOCMCAPTURE, &handler->vid_mmap)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to start capture: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } // if more than one camera, lets stop at the first frame if(handler->n_cam) break; } handler->buffer_pos=0; // set last camera handler->camera_last=v4l_cam_ident; return 0; }
int evid_init(char **errstr) { // XviD global initialization xvid_gbl_init_t xvid_gbl_init; memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init)); xvid_gbl_init.version=XVID_VERSION; xvid_gbl_init.debug=0; xvid_gbl_init.cpu_flags=0; if(xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL)) { x_asprintf(errstr, "%s", "Error initializing XviD core.\n"); return 1; } return 0; }
int log_destroy_handler(log_handler_t *log_handler, char **errstr) { handler_t *handler=(handler_t *)log_handler; char buffer[256]; errno=0; if(EOF==fclose(handler->stream)) { x_asprintf(errstr, "Error closing log file: %s", strerror_r(errno, buffer, 256)); return 1; } free(handler); return 0; }
/* wipe all cached files in all subdirs */ void wipe_all(const char *dir) { char *dname; int i; for (i = 0; i <= 0xF; i++) { x_asprintf(&dname, "%s/%1x", dir, i); traverse(dir, wipe_fn); free(dname); } /* and fix the counters */ cleanup_all(dir); }
/* Make a copy of stderr that will not be cached, so things like distcc can send networking errors to it. */ static void setup_uncached_err(void) { char *buf; int uncached_fd; uncached_fd = dup(2); if (uncached_fd == -1) { cc_log("dup(2) failed\n"); failed(); } /* leak a pointer to the environment */ x_asprintf(&buf, "UNCACHED_ERR_FD=%d", uncached_fd); if (putenv(buf) == -1) { cc_log("putenv failed\n"); failed(); } }
sleep_handler_t *sleep_create_handler(double freq, char **errstr) { handler_t *handler; handler=(handler_t *)x_malloc(sizeof(handler_t)); handler->period.tv_sec=(long)(1/freq); handler->period.tv_usec=(long)((long)((1/freq)*1e6)-(long)(1/freq)*1e6); handler->errstr=NULL; errno=0; if(gettimeofday(&handler->last_call_time, NULL)) { x_asprintf(errstr, "Error calling gettimeofday(): %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); free(handler); return NULL; } return (sleep_handler_t *)handler; }
int evid_destroy_handler(evid_handler_t *evid_handler, char **errstr) { handler_t *handler=(handler_t *)evid_handler; free(handler->filename); // avilib if(AVI_close(handler->avilib.avi)) { x_asprintf(errstr, "Error closing AVI file: %s.\n", AVI_strerror()); return 1; } // xvid if(xvid_encore(handler->xvid.handle, XVID_ENC_DESTROY, NULL, NULL)) { (*errstr)=NULL; return 1; } // free bitstream free(handler->xvid.bitstream); // free handle free(handler); return 0; }
/* set the per directory sizes */ void stats_set_sizes(const char *dir, size_t num_files, size_t total_size) { int fd; unsigned counters[STATS_END]; char *stats_file; create_dir(dir); x_asprintf(&stats_file, "%s/stats", dir); memset(counters, 0, sizeof(counters)); fd = safe_open(stats_file); if (fd != -1) { lock_fd(fd); stats_read_fd(fd, counters); counters[STATS_NUMFILES] = num_files; counters[STATS_TOTALSIZE] = total_size; write_stats(fd, counters); close(fd); } free(stats_file); }
/* revsusive directory traversal - used for cleanup fn() is called on all files/dirs in the tree */ void traverse(const char *dir, void (*fn)(const char *, struct stat *)) { DIR *d; struct dirent *de; d = opendir(dir); if (!d) return; while ((de = readdir(d))) { char *fname; struct stat st; if (strcmp(de->d_name,".") == 0) continue; if (strcmp(de->d_name,"..") == 0) continue; if (strlen(de->d_name) == 0) continue; x_asprintf(&fname, "%s/%s", dir, de->d_name); if (lstat(fname, &st)) { if (errno != ENOENT) { perror(fname); } free(fname); continue; } if (S_ISDIR(st.st_mode)) { traverse(fname, fn); } fn(fname, &st); free(fname); } closedir(d); }
/** * xlog_record_va: * @log_level: The log level of the message to write. * @module_name: The name of the module this message applies to. * @where: Where the log was generated (e.g., the file name, line number, etc). * @format: The printf() format of the message to write. * Note that a trailing newline is added if none is present. * @ap: The vararg list of arguments. * * Write a log message. **/ static void xlog_record_va(xlog_level_t log_level, const char *module_name, const char *where, const char *format, va_list ap) { const char *preamble_lead; const char *process_name_lead; char *buf_payload_ptr = NULL, *buf_preamble_ptr = NULL; char *buf_output_ptr = NULL; int buf_output_size; size_t i; #ifdef SIGPIPE sig_t sigpipe_handler; #endif if (! start_flag) { if (! init_flag) fprintf(stderr, "Logging must be initialized first by xlog_init()\n"); if (! start_flag) fprintf(stderr, "Logging must be started first by xlog_start()\n"); abort(); } if ((xlog_output_file_count == 0) && (xlog_output_func_count == 0)) return; if (XLOG_LEVEL_MAX <= log_level) return; /* Invalid log level */ if (! xlog_level_enabled[log_level]) return; /* The log level is disabled */ #ifdef SIGPIPE sigpipe_handler = signal(SIGPIPE, SIG_IGN); #endif preamble_lead = (preamble_string) ? preamble_string : ""; process_name_lead = (process_name_string) ? process_name_string : ""; /* Special case for the pre-amble level */ if (log_level == XLOG_LEVEL_RTRMGR_ONLY_NO_PREAMBLE) { x_asprintf(&buf_preamble_ptr, ""); } else { /* * Prepare the preamble string to write. * XXX: we need to prepare it once, otherwise the time may be * different when we write to more than one outputs. */ switch (xlog_verbose_level[log_level]) { case XLOG_VERBOSE_LOW: /* The minimum log information */ x_asprintf(&buf_preamble_ptr, "[ %s %s %s %s ] ", xlog_localtime2string(), xlog_level_names[log_level], process_name_lead, module_name); break; case XLOG_VERBOSE_MEDIUM: /* Add preamble string if non-NULL */ x_asprintf(&buf_preamble_ptr, "[ %s %s %s %s %s ] ", xlog_localtime2string(), preamble_lead, xlog_level_names[log_level], process_name_lead, module_name); break; case XLOG_VERBOSE_HIGH: /* Most verbose */ default: x_asprintf(&buf_preamble_ptr, "[ %s %s %s %s:%d %s %s ] ", xlog_localtime2string(), preamble_lead, xlog_level_names[log_level], process_name_lead, (int)pid, module_name, where); break; } } /* * Prepare the payload string to write */ x_vasprintf(&buf_payload_ptr, format, ap); if ((buf_preamble_ptr == NULL) && ((buf_payload_ptr == NULL) || buf_payload_ptr[0] == '\0')) goto cleanup_label; /* * Prepare the output string to write. * XXX: here we explicitly add the '\n' at the end of the * output string, because the XLOG message format implies it. */ buf_output_size = x_asprintf(&buf_output_ptr, "%s%s\n", buf_preamble_ptr, buf_payload_ptr); if ((buf_output_ptr == NULL) || (buf_output_ptr[0] == '\0') || (buf_output_size < 0)) { goto cleanup_label; } /* Remove our '\n' from the end if the payload itself already has one */ if (buf_output_size >= 2) { char n1, n2; n1 = buf_output_ptr[buf_output_size - 2]; n2 = buf_output_ptr[buf_output_size - 1]; if ((n1 == '\n') && (n2 == '\n')) buf_output_ptr[buf_output_size - 1] = '\0'; } /* * Write to the file descriptors */ for (i = 0; i < xlog_output_file_count; ) { FILE *fp = xlog_outputs_file[i]; if (xlog_write(fp, "%s", buf_output_ptr) || xlog_flush(fp)) { xlog_remove_output(fp); continue; } i++; } /* * Write to the functions */ for (i = 0; i < xlog_output_func_count; ) { xlog_output_func_t func = xlog_outputs_func[i]; void *obj = xlog_outputs_obj[i]; if (func(obj, log_level, buf_output_ptr) < 0) { xlog_remove_output_func(func, obj); continue; } i++; } cleanup_label: /* * Cleanup */ if (buf_preamble_ptr) free(buf_preamble_ptr); if (buf_payload_ptr) free(buf_payload_ptr); if (buf_output_ptr) free(buf_output_ptr); #ifdef SIGPIPE signal(SIGPIPE, sigpipe_handler); #endif }
/* run the real compiler and put the result in cache */ static void to_cache(ARGS *args) { char *path_stderr; char *tmp_stdout, *tmp_stderr, *tmp_hashname; struct stat st1, st2; int status; x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string()); x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string()); x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", temp_dir, tmp_string()); args_add(args, "-o"); args_add(args, tmp_hashname); /* Turn off DEPENDENCIES_OUTPUT when running cc1, because * otherwise it will emit a line like * * tmp.stdout.vexed.732.o: /home/mbp/.ccache/tmp.stdout.vexed.732.i * * unsetenv() is on BSD and Linux but not portable. */ putenv("DEPENDENCIES_OUTPUT"); if (getenv("CCACHE_CPP2")) { args_add(args, input_file); } else { args_add(args, i_tmpfile); } status = execute(args->argv, tmp_stdout, tmp_stderr); args_pop(args, 3); if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) { cc_log("compiler produced stdout for %s\n", output_file); stats_update(STATS_STDOUT); unlink(tmp_stdout); unlink(tmp_stderr); unlink(tmp_hashname); failed(); } unlink(tmp_stdout); if (status != 0) { int fd; cc_log("compile of %s gave status = %d\n", output_file, status); stats_update(STATS_STATUS); fd = open(tmp_stderr, O_RDONLY | O_BINARY); if (fd != -1) { if (strcmp(output_file, "/dev/null") == 0 || rename(tmp_hashname, output_file) == 0 || errno == ENOENT) { if (cpp_stderr) { /* we might have some stderr from cpp */ int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY); if (fd2 != -1) { copy_fd(fd2, 2); close(fd2); unlink(cpp_stderr); cpp_stderr = NULL; } } /* we can use a quick method of getting the failed output */ copy_fd(fd, 2); close(fd); unlink(tmp_stderr); if (i_tmpfile && !direct_i_file) { unlink(i_tmpfile); } exit(status); } } unlink(tmp_stderr); unlink(tmp_hashname); failed(); } x_asprintf(&path_stderr, "%s.stderr", hashname); if (stat(tmp_stderr, &st1) != 0 || stat(tmp_hashname, &st2) != 0 || rename(tmp_hashname, hashname) != 0 || rename(tmp_stderr, path_stderr) != 0) { cc_log("failed to rename tmp files - %s\n", strerror(errno)); stats_update(STATS_ERROR); failed(); } cc_log("Placed %s into cache\n", output_file); stats_tocache(file_size(&st1) + file_size(&st2)); free(tmp_hashname); free(tmp_stderr); free(tmp_stdout); free(path_stderr); }
int v4l_sync_frame(v4l_handler_t *v4l_handler, v4l_cam_ident_t v4l_cam_ident_next, pixel_t *frame) { handler_t *handler=(handler_t *)v4l_handler; int old_pos=handler->buffer_pos; int h, m, f; // sync current frame errno=0; if(ioctl(handler->fd, VIDIOCSYNC, &handler->buffer_pos)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to sync frame: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } // if more than one camera and buffer avaliable, we start next capture if(handler->n_cam&&handler->vid_mbuf.frames>1) { // Switch camera if(v4l_set_cam(handler, v4l_cam_ident_next)) return 1; handler->buffer_pos=handler->buffer_pos?0:1; handler->vid_mmap.frame=handler->buffer_pos; errno=0; if(ioctl(handler->fd, VIDIOCMCAPTURE, &handler->vid_mmap)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to start capture: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } } // crop frame if(frame!=NULL) { m=handler->v4l_cam_par[handler->camera_last].width*handler->v4l_cam_par[handler->camera_last].window_y*PALETTE_DEPTH; f=0; for(h=0; h<handler->v4l_cam_par[handler->camera_last].frame_par.height;h++) { // copy line m+=handler->v4l_cam_par[handler->camera_last].window_x*PALETTE_DEPTH; memcpy(&frame[f], &handler->map[m+handler->vid_mbuf.offsets[old_pos]], (size_t)handler->v4l_cam_par[handler->camera_last].frame_par.width*PALETTE_DEPTH); m+=(handler->v4l_cam_par[handler->camera_last].width-handler->v4l_cam_par[handler->camera_last].window_x)*PALETTE_DEPTH; f+=handler->v4l_cam_par[handler->camera_last].frame_par.width*PALETTE_DEPTH; } } // if we had not enought buffer, start next capture now if(handler->n_cam) { if(handler->vid_mbuf.frames<=1) { // Switch camera if(v4l_set_cam(handler, v4l_cam_ident_next)) return 1; // start capture handler->vid_mmap.frame=handler->buffer_pos; errno=0; if(ioctl(handler->fd, VIDIOCMCAPTURE, &handler->vid_mmap)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to start capture: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } } // if only one camera } else { handler->vid_mmap.frame=handler->buffer_pos; errno=0; if(ioctl(handler->fd, VIDIOCMCAPTURE, &handler->vid_mmap)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to start capture: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } handler->buffer_pos=handler->buffer_pos==handler->vid_mbuf.frames-1?0:handler->buffer_pos+1; } // set last cam handler->camera_last=v4l_cam_ident_next; return 0; }
/* find the hash for a command. The hash includes all argument lists, plus the output from running the compiler with -E */ static void find_hash(ARGS *args) { int i; char *path_stdout, *path_stderr; char *hash_dir; char *s; struct stat st; int status; int nlevels = 2; char *input_base; char *tmp; if ((s = getenv("CCACHE_NLEVELS"))) { nlevels = atoi(s); if (nlevels < 1) nlevels = 1; if (nlevels > 8) nlevels = 8; } hash_start(); /* when we are doing the unifying tricks we need to include the input file name in the hash to get the warnings right */ if (enable_unify) { hash_string(input_file); } /* we have to hash the extension, as a .i file isn't treated the same by the compiler as a .ii file */ hash_string(i_extension); /* first the arguments */ for (i=1;i<args->argc;i++) { /* some arguments don't contribute to the hash. The theory is that these arguments will change the output of -E if they are going to have any effect at all, or they only affect linking */ if (i < args->argc-1) { if (strcmp(args->argv[i], "-I") == 0 || strcmp(args->argv[i], "-include") == 0 || strcmp(args->argv[i], "-L") == 0 || strcmp(args->argv[i], "-D") == 0 || strcmp(args->argv[i], "-idirafter") == 0 || strcmp(args->argv[i], "-isystem") == 0) { i++; continue; } } if (strncmp(args->argv[i], "-I", 2) == 0 || strncmp(args->argv[i], "-L", 2) == 0 || strncmp(args->argv[i], "-D", 2) == 0 || strncmp(args->argv[i], "-idirafter", 10) == 0 || strncmp(args->argv[i], "-isystem", 8) == 0) { continue; } if (strncmp(args->argv[i], "--specs=", 8) == 0 && stat(args->argv[i]+8, &st) == 0) { /* if given a explicit specs file, then hash that file, but don't include the path to it in the hash */ hash_file(args->argv[i]+8); continue; } /* all other arguments are included in the hash */ hash_string(args->argv[i]); } /* the compiler driver size and date. This is a simple minded way to try and detect compiler upgrades. It is not 100% reliable */ if (stat(args->argv[0], &st) != 0) { cc_log("Couldn't stat the compiler!? (argv[0]='%s')\n", args->argv[0]); stats_update(STATS_COMPILER); failed(); } /* also include the hash of the compiler name - as some compilers use hard links and behave differently depending on the real name */ if (st.st_nlink > 1) { hash_string(str_basename(args->argv[0])); } hash_int(st.st_size); hash_int(st.st_mtime); /* possibly hash the current working directory */ if (getenv("CCACHE_HASHDIR")) { char *cwd = gnu_getcwd(); if (cwd) { hash_string(cwd); free(cwd); } } /* ~/hello.c -> tmp.hello.123.i limit the basename to 10 characters in order to cope with filesystem with small maximum filename length limits */ input_base = str_basename(input_file); tmp = strchr(input_base, '.'); if (tmp != NULL) { *tmp = 0; } if (strlen(input_base) > 10) { input_base[10] = 0; } /* now the run */ x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", temp_dir, input_base, tmp_string(), i_extension); x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", temp_dir, tmp_string()); if (!direct_i_file) { /* run cpp on the input file to obtain the .i */ args_add(args, "-E"); args_add(args, input_file); status = execute(args->argv, path_stdout, path_stderr); args_pop(args, 2); } else { /* we are compiling a .i or .ii file - that means we can skip the cpp stage and directly form the correct i_tmpfile */ path_stdout = input_file; if (create_empty_file(path_stderr) != 0) { stats_update(STATS_ERROR); cc_log("failed to create empty stderr file\n"); failed(); } status = 0; } if (status != 0) { if (!direct_i_file) { unlink(path_stdout); } unlink(path_stderr); cc_log("the preprocessor gave %d\n", status); stats_update(STATS_PREPROCESSOR); failed(); } /* if the compilation is with -g then we have to include the whole of the preprocessor output, which means we are sensitive to line number information. Otherwise we can discard line number info, which makes us less sensitive to reformatting changes Note! I have now disabled the unification code by default as it gives the wrong line numbers for warnings. Pity. */ if (!enable_unify) { hash_file(path_stdout); } else { if (unify_hash(path_stdout) != 0) { stats_update(STATS_ERROR); failed(); } } hash_file(path_stderr); i_tmpfile = path_stdout; if (!getenv("CCACHE_CPP2")) { /* if we are using the CPP trick then we need to remember this stderr data and output it just before the main stderr from the compiler pass */ cpp_stderr = path_stderr; } else { unlink(path_stderr); free(path_stderr); } /* we use a N level subdir for the cache path to reduce the impact on filesystems which are slow for large directories */ s = hash_result(); x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]); x_asprintf(&stats_file, "%s/stats", hash_dir); for (i=1; i<nlevels; i++) { char *p; if (create_dir(hash_dir) != 0) { cc_log("failed to create %s\n", hash_dir); failed(); } x_asprintf(&p, "%s/%c", hash_dir, s[i]); free(hash_dir); hash_dir = p; } if (create_dir(hash_dir) != 0) { cc_log("failed to create %s\n", hash_dir); failed(); } x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels); free(hash_dir); }
int v4l_init_dev(v4l_handler_t *v4l_handler) { handler_t *handler=(handler_t *)v4l_handler; int i; struct video_capability v4l_cap; // open video device file descriptor errno=0; handler->fd=open(handler->v4l_dev, O_RDWR); if(handler->fd==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Error opening device: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } // check if card can capture // get capabilities errno=0; if(ioctl(handler->fd, VIDIOCGCAP, &v4l_cap)==-1) { free(handler->errstr); x_asprintf(&handler->errstr,"Capability query failed: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } // check capture if(!(v4l_cap.type&VID_TYPE_CAPTURE)) { free(handler->errstr); x_asprintf(&handler->errstr, "This card is not capable of capturing frames. You can only use it to watch TV!\n"); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } // check palette && frame size for(i=0;i<=handler->n_cam;i++) { // palette if(v4l_cap.type&VID_TYPE_MONOCHROME||handler->v4l_cam_par[i].gray) { if(!handler->v4l_cam_par[i].gray) free(handler->errstr); x_asprintf(&handler->errstr, "Asked for colored capture on camera %d, but device is monochrome!\n", i); } handler->v4l_cam_par[i].palette=VIDEO_PALETTE_YUV422; // frame size if(handler->v4l_cam_par[i].width>v4l_cap.maxwidth ||handler->v4l_cam_par[i].width<v4l_cap.minwidth ||handler->v4l_cam_par[i].height>v4l_cap.maxheight ||handler->v4l_cam_par[i].height<v4l_cap.minheight) { free(handler->errstr); x_asprintf(&handler->errstr, "Asked frame size (%dx%d) on camera %d is out of range device support (%dx%d - %dx%d).\n", handler->v4l_cam_par[i].width, handler->v4l_cam_par[i].height, i, v4l_cap.minwidth, v4l_cap.minheight, v4l_cap.maxwidth, v4l_cap.maxheight); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } // camera settings if(v4l_set_cam(handler, i)) { errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } if(v4l_check_cam_settings(handler, i)) { errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } } // map device if(ioctl(handler->fd, VIDIOCGMBUF, &handler->vid_mbuf)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Device do not support mmap() interface to capture images. You might have an obsolete board/driver.\n"); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } if(handler->vid_mbuf.frames<1) { free(handler->errstr); x_asprintf(&handler->errstr, "Device do not support at least 1 frame in buffer!\n"); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } if((handler->map=(char *)mmap(0, handler->vid_mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, handler->fd, 0))==MAP_FAILED) { free(handler->errstr); x_asprintf(&handler->errstr, "mmap() failed!\n"); errno=0; if(close(handler->fd)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to close file '%s': %s\n", handler->v4l_dev,strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH) ); } return 1; } handler->buffer_pos=-1; return 0; }
// Check v4l camera settings int v4l_check_cam_settings(v4l_handler_t *v4l_handler, v4l_cam_ident_t v4l_cam_ident) { handler_t *handler=(handler_t *)v4l_handler; struct video_channel v4l_chan; struct video_tuner v4l_tun; struct video_picture v4l_pict; unsigned long freq; /* video source */ // get settings memset(&v4l_chan, 0, sizeof(struct video_channel)); v4l_chan.channel=handler->v4l_cam_par[v4l_cam_ident].channel; errno=0; if(ioctl(handler->fd, VIDIOCGCHAN, &v4l_chan)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to get video source parameters.\n"); return 1; } // check if(v4l_chan.channel!=handler->v4l_cam_par[v4l_cam_ident].channel) { free(handler->errstr); x_asprintf(&handler->errstr, "Card did not changed channel: requested %d, got %d.\n", handler->v4l_cam_par[v4l_cam_ident].channel, v4l_chan.channel); return 1; } if(v4l_chan.norm!=handler->v4l_cam_par[v4l_cam_ident].norm) { free(handler->errstr); x_asprintf(&handler->errstr, "Card did not changed norm: requested %d, got %d.\n", handler->v4l_cam_par[v4l_cam_ident].norm, v4l_chan.norm); return 1; } /* tuner */ if(handler->v4l_cam_par[v4l_cam_ident].tuner!=-1) { // check if channel has a tuner if(v4l_chan.tuners<1) { free(handler->errstr); x_asprintf(&handler->errstr, "Request to set tuner for this channel, but channel do not have a tuner.\n"); return 1; } // check if channel has asked tuner number if(handler->v4l_cam_par[v4l_cam_ident].tuner>=v4l_chan.tuners) { free(handler->errstr); x_asprintf(&handler->errstr, "Request to set tuner number %d for this channel, but channel do not have such tuner.\n", handler->v4l_cam_par[v4l_cam_ident].tuner); return 1; } // get settings errno=0; if(ioctl(handler->fd, VIDIOCGTUNER, &v4l_tun)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to get tuner information: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } // check settings if(v4l_tun.tuner!=handler->v4l_cam_par[v4l_cam_ident].tuner) { free(handler->errstr); x_asprintf(&handler->errstr, "Card did switch to specified tuner: requested %d, got %d.\n", handler->v4l_cam_par[v4l_cam_ident].tuner, v4l_tun.tuner ); return 1; } if(v4l_tun.mode!=handler->v4l_cam_par[v4l_cam_ident].mode) { free(handler->errstr); x_asprintf(&handler->errstr, "Tuner %d did not switch to requested mode: requested %d, got %d.\n", handler->v4l_cam_par[v4l_cam_ident].tuner, handler->v4l_cam_par[v4l_cam_ident].tuner, v4l_tun.tuner ); return 1; } /* frequency switch */ if(handler->v4l_cam_par[v4l_cam_ident].freq) { // no frequency tuning allowed if(v4l_tun.rangehigh>v4l_tun.rangelow) { free(handler->errstr); x_asprintf(&handler->errstr, "Asked to tune frequency, but v4l driver says board's highest tunable frequency is lower than board's lowest tunable frequency. Probably this tuner do not support frequency tuning.\n"); return 1; } // frequency out of range if(handler->v4l_cam_par[v4l_cam_ident].freq<v4l_tun.rangelow||handler->v4l_cam_par[v4l_cam_ident].freq>v4l_tun.rangehigh) { free(handler->errstr); x_asprintf(&handler->errstr, "Frequency out of range: requested %ld, range is %ld to %ld.\n", handler->v4l_cam_par[v4l_cam_ident].freq, v4l_tun.rangelow, v4l_tun.rangehigh); return 1; } // get frequency errno=0; if(ioctl(handler->fd, VIDIOCGFREQ, &freq)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to get frequency: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } // check setting if(freq!=handler->v4l_cam_par[v4l_cam_ident].freq) { free(handler->errstr); x_asprintf(&handler->errstr, "Tuner %d did not switch frequency: requested %ld, got %ld.\n", handler->v4l_cam_par[v4l_cam_ident].tuner, handler->v4l_cam_par[v4l_cam_ident].freq, freq); return 1; } } } /* Image proprieties */ // get settings errno=0; if(ioctl(handler->fd, VIDIOCGPICT, &v4l_pict)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to get image proprieties.\n"); return 1; } // check settings if(v4l_pict.brightness!=handler->v4l_cam_par[v4l_cam_ident].brightness) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set brightness: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].brightness, v4l_pict.brightness); return 1; } if(v4l_pict.hue!=handler->v4l_cam_par[v4l_cam_ident].hue) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set hue: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].hue, v4l_pict.hue); return 1; } if(v4l_pict.colour!=handler->v4l_cam_par[v4l_cam_ident].colour) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set colour: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].colour, v4l_pict.colour); return 1; } if(v4l_pict.contrast!=handler->v4l_cam_par[v4l_cam_ident].contrast) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set contrast: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].contrast, v4l_pict.contrast); return 1; } if(v4l_pict.whiteness!=handler->v4l_cam_par[v4l_cam_ident].whiteness) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set whiteness: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].whiteness, v4l_pict.whiteness); return 1; } // check strange value for depth if(v4l_pict.depth!=PALETTE_DEPTH*8) { free(handler->errstr); x_asprintf(&handler->errstr, "Unexpected value in capture depth variable: %hd. Internal error, contact the author.\n", v4l_pict.depth); return 1; } // palette if(handler->v4l_cam_par[v4l_cam_ident].palette!=v4l_pict.palette) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set palette: requested %hd, got %hd.\n", handler->v4l_cam_par[v4l_cam_ident].palette, v4l_pict.palette); return 1; } return 0; }
// Set v4l capture to specifyed camera int v4l_set_cam(v4l_handler_t *v4l_handler, v4l_cam_ident_t v4l_cam_ident) { handler_t *handler=(handler_t *)v4l_handler; struct video_channel v4l_chan; struct video_tuner v4l_tun; struct video_picture v4l_pict; if(handler->camera_last!=v4l_cam_ident) { if(v4l_cam_ident>handler->n_cam||v4l_cam_ident<0) { free(handler->errstr); x_asprintf(&handler->errstr, "Requested camera %d not configured!\n", v4l_cam_ident); return 1; } handler->camera_last=v4l_cam_ident; /* video source */ memset(&v4l_chan, 0, sizeof(struct video_channel)); v4l_chan.channel=handler->v4l_cam_par[v4l_cam_ident].channel; switch(handler->v4l_cam_par[v4l_cam_ident].norm) { case 0: v4l_chan.norm=VIDEO_MODE_PAL; break; case 1: v4l_chan.norm=VIDEO_MODE_NTSC; break; case 2: v4l_chan.norm=VIDEO_MODE_SECAM; break; case 3: v4l_chan.norm=VIDEO_MODE_AUTO; break; default: return 3; } // set input errno=0; if(ioctl(handler->fd, VIDIOCSCHAN, &v4l_chan)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to change to channel %d: %s\n", handler->v4l_cam_par[v4l_cam_ident].channel, strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } /* tuner */ if(handler->v4l_cam_par[v4l_cam_ident].tuner!=-1) { // set tunner v4l_tun.tuner=handler->v4l_cam_par[v4l_cam_ident].tuner; v4l_tun.mode=handler->v4l_cam_par[v4l_cam_ident].mode; errno=0; if(ioctl(handler->fd, VIDIOCSTUNER, &v4l_tun)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to change/set tuner: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } /* frequency switch */ if(handler->v4l_cam_par[v4l_cam_ident].freq) { // set frequency errno=0; if(ioctl(handler->fd, VIDIOCSFREQ, &handler->v4l_cam_par[v4l_cam_ident].freq)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to set frequency: %s\n", strerror_r(errno, handler->errbuf, MAX_ERROR_MSG_LENGTH)); return 1; } } } /* Image proprieties */ v4l_pict.brightness=handler->v4l_cam_par[v4l_cam_ident].brightness; v4l_pict.hue=handler->v4l_cam_par[v4l_cam_ident].hue; v4l_pict.colour=handler->v4l_cam_par[v4l_cam_ident].colour; v4l_pict.contrast=handler->v4l_cam_par[v4l_cam_ident].contrast; v4l_pict.whiteness=handler->v4l_cam_par[v4l_cam_ident].whiteness; // do not know about this, but keep 0 to make it work... v4l_pict.depth=PALETTE_DEPTH*8; v4l_pict.palette=handler->v4l_cam_par[v4l_cam_ident].palette; // set things errno=0; if(ioctl(handler->fd, VIDIOCSPICT, &v4l_pict)==-1) { free(handler->errstr); x_asprintf(&handler->errstr, "Fail to change image proprieties.\n"); return 1; } } return 0; }
/* try to return the compile result from cache. If we can return from cache then this function exits with the correct status code, otherwise it returns */ static void from_cache(int first) { int fd_stderr, fd_cpp_stderr; char *stderr_file; int ret; struct stat st; x_asprintf(&stderr_file, "%s.stderr", hashname); fd_stderr = open(stderr_file, O_RDONLY | O_BINARY); if (fd_stderr == -1) { /* it isn't in cache ... */ free(stderr_file); return; } /* make sure the output is there too */ if (stat(hashname, &st) != 0) { close(fd_stderr); unlink(stderr_file); free(stderr_file); return; } /* the user might be disabling cache hits */ if (first && getenv("CCACHE_RECACHE")) { close(fd_stderr); unlink(stderr_file); free(stderr_file); return; } utime(stderr_file, NULL); if (strcmp(output_file, "/dev/null") == 0) { ret = 0; } else { unlink(output_file); if (getenv("CCACHE_HARDLINK")) { ret = link(hashname, output_file); } else { ret = copy_file(hashname, output_file); } } /* the hash file might have been deleted by some external process */ if (ret == -1 && errno == ENOENT) { cc_log("hashfile missing for %s\n", output_file); stats_update(STATS_MISSING); close(fd_stderr); unlink(stderr_file); return; } free(stderr_file); if (ret == -1) { ret = copy_file(hashname, output_file); if (ret == -1) { cc_log("failed to copy %s -> %s (%s)\n", hashname, output_file, strerror(errno)); stats_update(STATS_ERROR); failed(); } } if (ret == 0) { /* update the mtime on the file so that make doesn't get confused */ utime(output_file, NULL); } /* get rid of the intermediate preprocessor file */ if (i_tmpfile) { if (!direct_i_file) { unlink(i_tmpfile); } free(i_tmpfile); i_tmpfile = NULL; } /* send the cpp stderr, if applicable */ fd_cpp_stderr = open(cpp_stderr, O_RDONLY | O_BINARY); if (fd_cpp_stderr != -1) { copy_fd(fd_cpp_stderr, 2); close(fd_cpp_stderr); unlink(cpp_stderr); free(cpp_stderr); cpp_stderr = NULL; } /* send the stderr */ copy_fd(fd_stderr, 2); close(fd_stderr); /* and exit with the right status code */ if (first) { cc_log("got cached result for %s\n", output_file); stats_update(STATS_CACHED); } exit(0); }
evid_handler_t *evid_create_handler(frame_par_t *frame_par, evid_xvidpar_t *evid_xvidpar, double framerate, char *filename, char **errstr) { xvid_enc_create_t xvid_enc_create; handler_t *handler; handler=(handler_t *)x_malloc(sizeof(handler_t)); // frame_par memcpy(&(handler->frame_par), frame_par, sizeof(frame_par_t)); // xvid_par memcpy(&(handler->evid_xvidpar), evid_xvidpar, sizeof(evid_xvidpar_t)); // sets file name handler->filename=(char *)x_malloc(strlen(filename)+1); strcpy(handler->filename, filename); // avilib if((handler->avilib.avi=AVI_open_output_file(filename))==NULL) { x_asprintf(errstr, "%s.\n", AVI_strerror()); free(handler); return NULL; } AVI_set_video(handler->avilib.avi, frame_par->width, frame_par->height, framerate, "xvid"); AVI_set_audio(handler->avilib.avi, 0, 44100, 16, WAVE_FORMAT_UNKNOWN); // xvid encoder memset(&xvid_enc_create, 0, sizeof(xvid_enc_create)); xvid_enc_create.profile=XVID_PROFILE_S_L0; // XVID_PROFILE_AS_L4; // do not know abot this... xvid_enc_create.version=XVID_VERSION; xvid_enc_create.width=frame_par->width; xvid_enc_create.height=frame_par->height; xvid_enc_create.num_zones=0; xvid_enc_create.zones=NULL; xvid_enc_create.num_plugins=0; xvid_enc_create.plugins=NULL; xvid_enc_create.num_threads=0; xvid_enc_create.max_bframes=0; xvid_enc_create.global=0; xvid_enc_create.global|=XVID_GLOBAL_CLOSED_GOP; xvid_enc_create.fincr=1000; xvid_enc_create.fbase=(int)(framerate*1000); xvid_enc_create.max_key_interval=(int)(framerate*10); xvid_enc_create.frame_drop_ratio=0; xvid_enc_create.bquant_ratio=150; xvid_enc_create.bquant_offset=100; xvid_enc_create.min_quant[0]=2; xvid_enc_create.max_quant[0]=31; if(xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL)) { x_asprintf(errstr, "Error initializing XviD encore.\n"); if(AVI_close(handler->avilib.avi)) { free((*errstr)); x_asprintf(errstr, "Error initializing XviD encore / Error closing AVI file: %s.\n", AVI_strerror()); } unlink(filename); // no error checking here free(handler); return NULL; } handler->xvid.handle=xvid_enc_create.handle; // bitstream handler->xvid.bitstream=x_malloc((size_t)(handler->frame_par.width*handler->frame_par.height*PALETTE_DEPTH)); // errstr handler->errstr=NULL; return (evid_handler_t *)handler; }
int evid_enc_frame(evid_handler_t *evid_handler, pixel_t *frame) { xvid_enc_frame_t xvid_enc_frame; handler_t *handler=(handler_t *)evid_handler; static const int vop_presets[] = { 0, 0, XVID_VOP_HALFPEL, XVID_VOP_HALFPEL | XVID_VOP_INTER4V, XVID_VOP_HALFPEL | XVID_VOP_INTER4V, XVID_VOP_HALFPEL | XVID_VOP_INTER4V | XVID_VOP_TRELLISQUANT, XVID_VOP_HALFPEL | XVID_VOP_INTER4V | XVID_VOP_TRELLISQUANT | XVID_VOP_HQACPRED, }; static const int motion_presets[] = { 0, XVID_ME_ADVANCEDDIAMOND16, XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16, XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8, XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP, XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP, XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16 | XVID_ME_ADVANCEDDIAMOND8 | XVID_ME_HALFPELREFINE8 | XVID_ME_EXTSEARCH8 | XVID_ME_CHROMA_PVOP | XVID_ME_CHROMA_BVOP, }; int frame_size; // XviD memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame)); xvid_enc_frame.version=XVID_VERSION; xvid_enc_frame.vol_flags=0; xvid_enc_frame.vol_flags|=XVID_VOL_INTERLACING; xvid_enc_frame.quant_intra_matrix=NULL; xvid_enc_frame.quant_inter_matrix=NULL; xvid_enc_frame.par=XVID_PAR_11_VGA; xvid_enc_frame.par_width=1; xvid_enc_frame.par_height=1; xvid_enc_frame.fincr=0; xvid_enc_frame.vop_flags=vop_presets[handler->evid_xvidpar.quality]; if(handler->evid_xvidpar.gray) xvid_enc_frame.vop_flags|=XVID_VOP_GREYSCALE; xvid_enc_frame.motion=motion_presets[handler->evid_xvidpar.quality]; xvid_enc_frame.input.csp=XVID_CSP_YUY2; xvid_enc_frame.input.plane[0]=frame; xvid_enc_frame.input.stride[0]=handler->frame_par.width*PALETTE_DEPTH; xvid_enc_frame.type=XVID_TYPE_AUTO; xvid_enc_frame.quant=handler->evid_xvidpar.quant; xvid_enc_frame.bitstream=handler->xvid.bitstream; xvid_enc_frame.length=-1; frame_size=xvid_encore(handler->xvid.handle, XVID_ENC_ENCODE, &xvid_enc_frame, NULL); // avilib if(AVI_write_frame(handler->avilib.avi, (char *)handler->xvid.bitstream, (long)frame_size, ((xvid_enc_frame.out_flags&XVID_KEYFRAME)?1:0))) { free(handler->errstr); switch(AVI_errno) { case AVI_ERR_SIZELIM: return 1; break; default: x_asprintf(&handler->errstr, "Error writing encoded frame to AVI file: %s.\n", AVI_strerror()); break; } return 1; } // update header if(AVI_make_header(handler->avilib.avi)) { free(handler->errstr); x_asprintf(&handler->errstr, "Error writing encoded frame to AVI file: %s.\n", AVI_strerror()); return 1; } return 0; }