static int ambitv_cycle_next_program() { int ret = 0; if (!conf.ambitv_on) { ambitv_log(ambitv_log_info, LOGNAME "not cycling program, because state is paused.\n"); return 0; } conf.cur_prog = (conf.cur_prog + 1) % ambitv_num_programs; ret = ambitv_program_run(ambitv_programs[conf.cur_prog]); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to switch to program '%s', aborting...\n", ambitv_programs[conf.cur_prog]->name); } else { ambitv_log(ambitv_log_info, LOGNAME "switched to program '%s'.\n", ambitv_programs[conf.cur_prog]->name); } return ret; }
static void ambitv_mood_light_processor_print_configuration(struct ambitv_processor_component* component) { struct ambitv_mood_light_processor* mood = (struct ambitv_mood_light_processor*) component->priv; ambitv_log(ambitv_log_info, "\tspeed: %.1f\n", mood->step * 1000.0); ambitv_log(ambitv_log_info, "\tmode: %d\n", mood->mode); }
static int ambitv_v4l2_grab_capture_loop_iteration(struct ambitv_source_component* grabber) { int ret = 0; fd_set fds; struct timeval tv; struct v4l2_grab* grab_priv = (struct v4l2_grab*)grabber->priv; if (NULL == grab_priv) return -1; FD_ZERO(&fds); FD_SET(grab_priv->fd, &fds); tv.tv_sec = 2; tv.tv_usec = 0; ret = select(grab_priv->fd+1, &fds, NULL, NULL, &tv); if (ret < 0) { if (EINTR == errno) ret = 0; ambitv_log(ambitv_log_error, LOGNAME "failed to select() a frame: %d (%s).\n", errno, strerror(errno)); } else if (0 == ret) { ambitv_log(ambitv_log_error, LOGNAME "select() timed out.\n"); } if (ret > 0) { ret = ambitv_v4l2_grab_read_frame(grab_priv); } return ret; }
static int ambitv_v4l2_grab_open_device(struct v4l2_grab* grabber) { int ret = 0; struct stat st; ret = stat(grabber->device_name, &st); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to stat '%s' : %d (%s).\n", grabber->device_name, errno, strerror(errno)); return ret; } if (!S_ISCHR(st.st_mode)) { ambitv_log(ambitv_log_error, LOGNAME "'%s' is not a device.\n", grabber->device_name); return -ENODEV; } grabber->fd = open(grabber->device_name, O_RDWR | O_NONBLOCK, 0); if (grabber->fd < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to open '%s': %d (%s).\n", grabber->device_name, errno, strerror(errno)); ret = -errno; } return ret; }
static int ambitv_v4l2_grab_start_streaming(struct v4l2_grab* grabber) { int i, ret; enum v4l2_buf_type type; for (i=0; i < grabber->num_buffers; i++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ret = xioctl(grabber->fd, VIDIOC_QBUF, &buf); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to enqueue a video buffer.\n"); return -EINVAL; } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = xioctl(grabber->fd, VIDIOC_STREAMON, &type); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to start video streaming: %d (%s).\n", errno, strerror(errno)); return -EINVAL; } return 0; }
static int ambitv_edge_color_processor_configure(struct ambitv_edge_processor_priv* edge, int argc, char** argv) { int c, ret = 0; static struct option lopts[] = { { "box-width", required_argument, 0, '0' }, { "box-height", required_argument, 0, '1' }, { NULL, 0, 0, 0 } }; optind = 0; while (1) { c = getopt_long(argc, argv, "", lopts, NULL); if (c < 0) break; switch (c) { case '0': case '1': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf > 0) { edge->boxsize[c-'0'] = (int)nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind-2], optarg); ret = -1; goto errReturn; } } break; } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous argument '%s'.\n", argv[optind]); ret = -1; } errReturn: return ret; }
static int ambitv_program_configure(struct ambitv_program* program, int argc, char** argv) { int c, ret = 0; static struct option lopts[] = { { "activate", required_argument, 0, 'a' }, { NULL, 0, 0, 0 } }; optind = 0; while (1) { c = getopt_long(argc, argv, "", lopts, NULL); if (c < 0) break; switch (c) { case 'a': { if ('&' != optarg[0]) { ambitv_log(ambitv_log_error, LOGNAME "component name is not prefixed with '&': '%s'.\n", optarg); goto errReturn; } ret = ambitv_program_append_component_with_name(program, &optarg[1]); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to find component with name '%s'.\n", optarg); goto errReturn; } break; } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous argument '%s'.\n", argv[optind]); ret = -1; } errReturn: return ret; }
int ambitv_v4l2_grab_stop(struct ambitv_source_component* grabber) { int ret = 0; struct v4l2_grab* grab_priv = (struct v4l2_grab*)grabber->priv; if (NULL == grab_priv) return -1; if (grab_priv->fd < 0) { ambitv_log(ambitv_log_warn, LOGNAME "grabber is not running and can't be stopped.\n"); return -1; } ret = ambitv_v4l2_grab_stop_streaming(grab_priv); if (ret < 0) goto fail_return; ret = ambitv_v4l2_grab_uninit_device(grab_priv); if (ret < 0) goto fail_return; ret = ambitv_v4l2_grab_close_device(grab_priv); fail_return: return ret; }
static void ambitv_audio_processor_print_configuration(struct ambitv_processor_component* component) { struct ambitv_audio_processor_priv* audio = (struct ambitv_audio_processor_priv*) component->priv; ambitv_log(ambitv_log_info, "\ttype : %d\n" "\tsensitivity: %d\n" "\tsmoothing : %d\n" "\tlevelcolor : %02X%02X%02X\n" "\tlinear : %d\n", audio->type, audio->sensitivity, audio->smoothing, audio->lcolor.r, audio->lcolor.g, audio->lcolor.b, audio->linear); }
static void ambitv_edge_color_processor_print_configuration(struct ambitv_processor_component* component) { struct ambitv_edge_processor_priv* edge = (struct ambitv_edge_processor_priv*)component->priv; ambitv_log(ambitv_log_info, "\tbox-width: %d\n" "\tbox-height: %d\n", edge->boxsize[0], edge->boxsize[1] ); }
static int ambitv_v4l2_grab_init_device(struct v4l2_grab* grabber) { int ret; struct v4l2_capability cap; struct v4l2_format vid_fmt; ret = xioctl(grabber->fd, VIDIOC_QUERYCAP, &cap); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "'%s' is no v4l2 device.\n", grabber->device_name); return ret; } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { ambitv_log(ambitv_log_error, LOGNAME "'%s' is not a video capture device.\n", grabber->device_name); return -ENODEV; } if (!(cap.capabilities & V4L2_CAP_STREAMING)) { ambitv_log(ambitv_log_error, LOGNAME "'%s' does not support streaming i/o.\n", grabber->device_name); return -ENODEV; } memset(&vid_fmt, 0, sizeof(vid_fmt)); vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = xioctl(grabber->fd, VIDIOC_G_FMT, &vid_fmt); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to determine video format of '%s'.\n", grabber->device_name); return -EINVAL; } vid_fmt.fmt.pix.width = 720; vid_fmt.fmt.pix.height = 576; ret = xioctl(grabber->fd, VIDIOC_S_FMT, &vid_fmt); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to set video format of '%s'.\n", grabber->device_name); return -EINVAL; } grabber->width = vid_fmt.fmt.pix.width; grabber->height = vid_fmt.fmt.pix.height; grabber->bytesperline = vid_fmt.fmt.pix.bytesperline; grabber->fmt = v4l2_to_ambitv_video_format(vid_fmt.fmt.pix.pixelformat); ambitv_log(ambitv_log_info, LOGNAME "video format: %ux%u (%s).\n", vid_fmt.fmt.pix.width, vid_fmt.fmt.pix.height, v4l2_string_from_fourcc(vid_fmt.fmt.pix.pixelformat)); return ambitv_v4l2_grab_init_mmap(grabber); }
static int ambitv_toggle_paused() { int ret = 0; conf.ambitv_on = !conf.ambitv_on; if (conf.ambitv_on) { ret = ambitv_program_run(ambitv_programs[conf.cur_prog]); if (ret < 0) ambitv_log(ambitv_log_error, LOGNAME "failed to start program '%s'.\n", ambitv_programs[conf.cur_prog]->name); } else { ret = ambitv_program_stop_current(); if (ret < 0) ambitv_log(ambitv_log_error, LOGNAME "failed to stop program '%s'.\n", ambitv_programs[conf.cur_prog]->name); } ambitv_log(ambitv_log_info, LOGNAME "now: %s\n", conf.ambitv_on ? "running" : "paused"); return ret; }
int ambitv_program_enable(struct ambitv_program* program) { int i; for (i=0; i<ambitv_num_programs; i++) if (0 == strcmp(program->name, ambitv_programs[i]->name)) { ambitv_log(ambitv_log_error, LOGNAME "a program with name '%s' is already registered.\n", program->name); return -1; } ambitv_num_programs = ambitv_util_append_ptr_to_list( (void***)&ambitv_programs, ambitv_num_programs, &ambitv_len_programs, program ); ambitv_log(ambitv_log_info, LOGNAME "registered program '%s'.\n", program->name); return 0; }
static int ambitv_v4l2_grab_stop_streaming(struct v4l2_grab* grabber) { int ret; enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = xioctl(grabber->fd, VIDIOC_STREAMOFF, &type); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to stop video streaming: %d (%s).\n", errno, strerror(errno)); ret = -errno; } return ret; }
static int ambitv_v4l2_grab_uninit_device(struct v4l2_grab* grabber) { unsigned int i; int ret; struct vid_buffer* buffers = (struct vid_buffer*)grabber->buffers; for (i=0; i < grabber->num_buffers; i++) { ret = munmap(buffers[i].start, buffers[i].length); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to unmap buffer: %d (%s).\n", errno, strerror(errno)); return -errno; } } ambitv_v4l2_grab_free_buffers(grabber); return 0; }
static int ambitv_program_append_component_with_name(struct ambitv_program* program, const char* name) { int ret = -1; void* component = ambitv_component_find_by_name(name); if (NULL != component) { program->num_components = ambitv_util_append_ptr_to_list( &program->components, program->num_components, &program->len_components, component ); ambitv_log(ambitv_log_info, LOGNAME "'%s': appended component '%s'.\n", program->name, name); ret = 0; } return ret; }
static void ambitv_v4l2_grab_print_configuration(struct ambitv_source_component* component) { struct v4l2_grab* grab_priv = (struct v4l2_grab*)component->priv; ambitv_log(ambitv_log_info, "\tdevice name: %s\n" "\tbuffers: %d\n" "\tcrop-top: %d\n" "\tcrop-right: %d\n" "\tcrop-bottom: %d\n" "\tcrop-left: %d\n" "\tauto-crop luma threshold: %d\n", grab_priv->device_name, grab_priv->req_buffers, grab_priv->crop[0], grab_priv->crop[1], grab_priv->crop[2], grab_priv->crop[3], grab_priv->auto_crop_luminance ); }
int ambitv_v4l2_grab_start(struct ambitv_source_component* grabber) { int ret = 0; struct v4l2_grab* grab_priv = (struct v4l2_grab*)grabber->priv; if (NULL == grab_priv) return -1; if (grab_priv->fd > -1) { ambitv_log(ambitv_log_warn, LOGNAME "grabber is already running.\n"); return -1; } ret = ambitv_v4l2_grab_open_device(grab_priv); if (ret < 0) goto fail_open; ret = ambitv_v4l2_grab_init_device(grab_priv); if (ret < 0) goto fail_init; ret = ambitv_v4l2_grab_start_streaming(grab_priv); if (ret < 0) goto fail_streaming; return ret; fail_streaming: ambitv_v4l2_grab_uninit_device(grab_priv); fail_init: ambitv_v4l2_grab_close_device(grab_priv); fail_open: return ret; }
static int ambitv_mood_light_processor_configure(struct ambitv_processor_component* mood, int argc, char** argv) { int c, ret = 0; struct ambitv_mood_light_processor* mood_priv = (struct ambitv_mood_light_processor*) mood->priv; if (NULL == mood_priv) return -1; static struct option lopts[] = { { "speed", required_argument, 0, 's' }, { "mode", required_argument, 0, 'm' }, { NULL, 0, 0, 0 } }; while (1) { c = getopt_long(argc, argv, "", lopts, NULL); if (c < 0) break; switch (c) { case 's': { if (NULL != optarg) { char* eptr = NULL; double nbuf = strtod(optarg, &eptr); if ('\0' == *eptr && nbuf > 0) { mood_priv->step = nbuf / 1000.0; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); return -1; } } break; } case 'm': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf >= 0) { mood_priv->mode = nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); return -1; } } break; } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous configuration argument: '%s'.\n", argv[optind]); ret = -1; } return ret; }
static int ambitv_runloop() { int ret = 0; unsigned char c = 0; fd_set fds, ex_fds; struct timeval tv; FD_ZERO(&fds); FD_ZERO(&ex_fds); FD_SET(STDIN_FILENO, &fds); if (conf.gpio_fd >= 0) FD_SET(conf.gpio_fd, &ex_fds); tv.tv_sec = 0; tv.tv_usec = 500000; ret = select(MAX(STDIN_FILENO, conf.gpio_fd)+1, &fds, NULL, &ex_fds, &tv); if (ret < 0) { if (EINTR != errno && EWOULDBLOCK != errno) { ambitv_log(ambitv_log_error, LOGNAME "error during select(): %d (%s)\n", errno, strerror(errno)); ret = 0; } goto finishLoop; } if (FD_ISSET(STDIN_FILENO, &fds)) { ret = read(STDIN_FILENO, &c, 1); if (ret < 0) { if (EINTR != errno && EWOULDBLOCK != errno) { ambitv_log(ambitv_log_error, LOGNAME "error during read() on stdin: %d (%s)\n", errno, strerror(errno)); } else ret = 0; goto finishLoop; } else if (0 == ret) goto finishLoop; switch (c) { case 0x20: { // space ret = ambitv_cycle_next_program(); if (ret < 0) goto finishLoop; break; } case 't': { ret = ambitv_toggle_paused(); if (ret < 0) goto finishLoop; break; } default: break; } } if (conf.gpio_fd >= 0 && FD_ISSET(conf.gpio_fd, &ex_fds)) { char buf[16]; ret = read(conf.gpio_fd, buf, sizeof(*buf)); lseek(conf.gpio_fd, 0, SEEK_SET); if (ret < 0) { if (EINTR != errno && EWOULDBLOCK != errno) { ambitv_log(ambitv_log_error, LOGNAME "failed to read from gpio %d.\n", conf.gpio_idx); ret = -1; } else ret = 0; goto finishLoop; } else if (0 == ret) goto finishLoop; if ('0' == buf[0]) { struct timeval now; (void)gettimeofday(&now, NULL); if (0 != conf.last_button_press.tv_sec) { long millis = ambitv_millis_between(&now, &conf.last_button_press); if (millis <= BUTTON_MILLIS && BUTTON_MILLIS_HYST <= millis) conf.button_cnt++; } else conf.button_cnt++; memcpy(&conf.last_button_press, &now, sizeof(struct timeval)); } } if (conf.button_cnt > 0) { struct timeval now; (void)gettimeofday(&now, NULL); if (0 != conf.last_button_press.tv_sec) { long millis = ambitv_millis_between(&now, &conf.last_button_press); if (millis > BUTTON_MILLIS) { if (conf.button_cnt > 1) { ret = ambitv_cycle_next_program(); } else { ret = ambitv_toggle_paused(); } conf.button_cnt = 0; memset(&conf.last_button_press, 0, sizeof(struct timeval)); } } } finishLoop: return ret; }
static int ambitv_v4l2_grab_configure(struct ambitv_source_component* grabber, int argc, char** argv) { int c, ret = 0; struct v4l2_grab* grab_priv = (struct v4l2_grab*)grabber->priv; if (NULL == grab_priv) return -1; static struct option lopts[] = { { "video-device", required_argument, 0, 'd' }, { "buffers", required_argument, 0, 'b' }, { "crop-top", required_argument, 0, '0' }, { "crop-right", required_argument, 0, '1' }, { "crop-bottom", required_argument, 0, '2' }, { "crop-left", required_argument, 0, '3' }, { "autocrop-luminance-threshold", required_argument, 0, 'a' }, { NULL, 0, 0, 0 } }; while (1) { c = getopt_long(argc, argv, "", lopts, NULL); if (c < 0) break; switch (c) { case 'd': { if (NULL != optarg) { if (NULL != grab_priv->device_name) free(grab_priv->device_name); grab_priv->device_name = strdup(optarg); } break; } case 'b': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr) { grab_priv->req_buffers = (int)nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind-2], optarg); return -1; } } break; } case '0': case '1': case '2': case '3': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf >= 0) { grab_priv->crop[c-'0'] = (int)nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind-2], optarg); return -1; } } break; } case 'a': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr) { grab_priv->auto_crop_luminance = (int)nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind-2], optarg); return -1; } } break; } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous configuration argument: '%s'.\n", argv[optind]); ret = -1; } return ret; }
static int ambitv_main_configure(int argc, char** argv) { int c, ret = 0; static struct option lopts[] = { { "button-gpio", required_argument, 0, 'b' }, { "file", required_argument, 0, 'f' }, { "help", no_argument, 0, 'h' }, { "program", required_argument, 0, 'p' }, { NULL, 0, 0, 0 } }; while (1) { c = getopt_long(argc, argv, "b:f:hp:", lopts, NULL); if (c < 0) break; switch (c) { case 'f': { if (NULL != optarg) { conf.config_path = strdup(optarg); } break; } case 'b': case 'p': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf > 0) { if ('b' == c) conf.gpio_idx = (int)nbuf; else if ('p' == c) conf.program_idx = (int)nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind-2], optarg); ambitv_usage(argv[0]); return -1; } } break; } case 'h': { ambitv_usage(argv[0]); exit(0); } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous configuration argument: '%s'.\n", argv[optind]); ambitv_usage(argv[0]); ret = -1; } return ret; }
int main(int argc, char** argv) { int ret = 0, i; struct ambitv_conf_parser* parser; struct termios tt; unsigned long tt_orig; signal(SIGINT, ambitv_signal_handler); signal(SIGTERM, ambitv_signal_handler); printf( "\n" "*********************************************************\n" "* ambi-tv: diy ambient lighting for your screen or tv *\n" "* (c) @gkaindl *\n" "*********************************************************\n" "\n" ); conf.program_idx = 0; conf.gpio_idx = -1; conf.config_path = DEFAULT_CONFIG_PATH; conf.ambitv_on = 1; conf.gpio_fd = -1; conf.running = 1; ret = ambitv_main_configure(argc, argv); if (ret < 0) return -1; parser = ambitv_conf_parser_create(); parser->f_handle_block = ambitv_handle_config_block; ret = ambitv_conf_parser_read_config_file(parser, conf.config_path); ambitv_conf_parser_free(parser); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to parse configuration file, aborting...\n"); ambitv_usage(argv[0]); return -1; } if (ambitv_num_programs <= 0) { ambitv_log(ambitv_log_error, LOGNAME "no programs available, aborting...\n"); return -1; } ambitv_log(ambitv_log_info, LOGNAME "configuration finished, %d programs available.\n", ambitv_num_programs); for (i=0; i<ambitv_num_programs; i++) ambitv_log(ambitv_log_info, "\t%s\n", ambitv_programs[i]->name); if (conf.gpio_idx >= 0) { conf.gpio_fd = ambitv_gpio_open_button_irq(conf.gpio_idx); if (conf.gpio_fd < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to prepare gpio %d, aborting...\n", conf.gpio_idx); return -1; } else { ambitv_log(ambitv_log_info, LOGNAME "using gpio %d as physical button.\n", conf.gpio_idx); } } tcgetattr(STDIN_FILENO, &tt); tt_orig = tt.c_lflag; tt.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &tt); if (conf.program_idx >= ambitv_num_programs) { ambitv_log(ambitv_log_error, LOGNAME "program at index %d requested, but only %d programs available. aborting...\n", conf.program_idx, ambitv_num_programs); goto errReturn; } conf.cur_prog = conf.program_idx; ret = ambitv_program_run(ambitv_programs[conf.cur_prog]); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to start initial program '%s', aborting...\n", ambitv_programs[conf.cur_prog]->name); goto errReturn; } ambitv_log(ambitv_log_info, LOGNAME "started initial program '%s'.\n", ambitv_programs[conf.cur_prog]->name); fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK); ambitv_log(ambitv_log_info, LOGNAME "************* start-up complete\n" "\tpress <space> to cycle between programs.\n" "\tpress 't' to toggle pause.\n"); if (conf.gpio_idx >= 0) { ambitv_log(ambitv_log_info, "\tphysical (gpio) button: click to pause/resume, double-click to cycle between programs.\n"); } while (conf.running && ambitv_runloop() >= 0); ret = ambitv_program_stop_current(); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to stop program '%s' before exiting.\n", ambitv_programs[conf.cur_prog]->name); goto errReturn; } errReturn: tt.c_lflag = tt_orig; tcsetattr(STDIN_FILENO, TCSANOW, &tt); if (conf.gpio_fd >= 0) ambitv_gpio_close_button_irq(conf.gpio_fd, conf.gpio_idx); return ret; }
static int ambitv_v4l2_grab_read_frame(struct v4l2_grab* grabber) { struct v4l2_buffer buf; int ret, ewidth, eheight, ebpl, auto_crop[4] = {0,0,0,0}; unsigned char* eframe; struct vid_buffer* buffers = (struct vid_buffer*)grabber->buffers; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; ret = xioctl(grabber->fd, VIDIOC_DQBUF, &buf); if (ret < 0) { switch (errno) { case EIO: case EAGAIN: return 0; default: ambitv_log(ambitv_log_error, LOGNAME "failed to dequeue a frame: %d (%s).\n", errno, strerror(errno)); return -errno; } } if (buf.index >= grabber->num_buffers) { ambitv_log(ambitv_log_error, LOGNAME "buffer index is out of expected range.\n"); return -EINVAL; } if (grabber->auto_crop_luminance >= 0 && ambitv_video_fmt_detect_crop_for_frame( &auto_crop[0], grabber->auto_crop_luminance, buffers[buf.index].start, grabber->width, grabber->height, grabber->bytesperline, grabber->fmt) < 0) memset(auto_crop, 0, sizeof(int) * 4); // apply crop switch (grabber->fmt) { case ambitv_video_format_yuyv: { int cx = (grabber->crop[3] & ~1) + auto_crop[3], cy = grabber->crop[0] + auto_crop[0]; ebpl = grabber->bytesperline ? grabber->bytesperline : 2*grabber->width; eframe = buffers[buf.index].start + cy * ebpl + cx * 2; ewidth = grabber->width - grabber->crop[1] - grabber->crop[3] - auto_crop[1] - auto_crop[3]; eheight = grabber->height - grabber->crop[0] - grabber->crop[2] - auto_crop[0] - auto_crop[2]; break; } default: { eframe = NULL; ewidth = 0; eheight = 0; ebpl = 0; break; } } ambitv_source_component_distribute_to_active_processors( grabber->source_component, eframe, ewidth, eheight, ebpl, grabber->fmt ); ret = xioctl(grabber->fd, VIDIOC_QBUF, &buf); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to enqueue a frame: %d (%s).\n", errno, strerror(errno)); } return ret; }
static int ambitv_v4l2_grab_init_mmap(struct v4l2_grab* grabber) { int ret; struct v4l2_requestbuffers req; memset(&req, 0, sizeof(req)); req.count = grabber->req_buffers; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; ret = xioctl(grabber->fd, VIDIOC_REQBUFS, &req); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to set up memory mapping for '%s'.\n", grabber->device_name); return -ENODEV; } if (req.count < 2) { ambitv_log(ambitv_log_error, LOGNAME "insufficient buffer memory for '%s'.\n", grabber->device_name); return -ENOMEM; } grabber->buffers = calloc(req.count, sizeof(struct vid_buffer)); if (NULL == grabber->buffers) { ambitv_log(ambitv_log_error, LOGNAME "failed to allocate buffer memory.\n"); return -ENOMEM; } struct vid_buffer* buffers = (struct vid_buffer*)grabber->buffers; for (grabber->num_buffers = 0; grabber->num_buffers < req.count; grabber->num_buffers++) { struct v4l2_buffer buf; memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = grabber->num_buffers; ret = xioctl(grabber->fd, VIDIOC_QUERYBUF, &buf); if (ret < 0) { ambitv_log(ambitv_log_error, LOGNAME "failed to query video buffer.\n"); goto fail_buf; } buffers[grabber->num_buffers].length = buf.length; buffers[grabber->num_buffers].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, grabber->fd, buf.m.offset); if (MAP_FAILED == buffers[grabber->num_buffers].start) { ambitv_log(ambitv_log_error, LOGNAME "failed to set up mmap().\n"); goto fail_buf; } } return 0; fail_buf: ambitv_v4l2_grab_free_buffers(grabber); return -ENODEV; }
int ambitv_parse_led_string(const char* str, int** out_ptr, int* out_len) { int a, b, c, ilen = 0, idx = 0, skip = 0, *s = &a; int* list = NULL; a = b = 0; while (1) { c = *str++; switch (c) { case 'X': case 'x': { if (&b == s) { ambitv_log(ambitv_log_error, LOGNAME "unexpected '%c'.\n", c); goto errReturn; } skip = 1; break; } case '-': { if (&a == s && !skip) { s = &b; } else { ambitv_log(ambitv_log_error, LOGNAME "unexpected '%c'.\n", c); goto errReturn; } break; } case '\0': case '\n': case ',': { if (skip) { while (a--) idx = ambitv_util_append_ptr_to_list((void***) &list, idx, &ilen, (void*) -1); } else { int l = a, r = a + 1, ss = 1; if (&b == s) { ss = (l > b) ? -1 : 1; r = b + ss; } do { idx = ambitv_util_append_ptr_to_list((void***) &list, idx, &ilen, (void*) l); l += ss; } while (l != r); } skip = a = b = 0; s = &a; break; } default: { if (skip || c < '0' || c > '9') { ambitv_log(ambitv_log_error, LOGNAME "unexpected character '%c'.\n", c); goto errReturn; } *s = *s * 10 + (c - '0'); break; } } if (c == '\0' || c == '\n') break; } *out_ptr = list; *out_len = idx; return 0; errReturn: return -1; }
static int ambitv_audio_processor_configure(struct ambitv_audio_processor_priv* audio, int argc, char** argv) { int c, ret = 0; static struct option lopts[] = { { "atype", required_argument, 0, 't' }, { "sensitivity", required_argument, 0, 's' }, { "smoothing", required_argument, 0, 'S' }, { "linear", required_argument, 0, 'e' }, { "levelcolor", required_argument, 0, 'l' }, { NULL, 0, 0, 0 } }; optind = 0; while (1) { c = getopt_long(argc, argv, "", lopts, NULL); if (c < 0) break; switch (c) { case 's': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf > 0) { audio->sensitivity = (int) nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); ret = -1; goto errReturn; } } break; } case 'S': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf >= 0 && nbuf < 8) { audio->smoothing = (int) nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); ret = -1; goto errReturn; } } break; case 't': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf >= 0 && nbuf < ATYPE_NUMATYPES) { audio->type = (int) nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); ret = -1; goto errReturn; } } break; } case 'e': { if (NULL != optarg) { char* eptr = NULL; long nbuf = strtol(optarg, &eptr, 10); if ('\0' == *eptr && nbuf >= 0 && nbuf < 2) { audio->linear = (int) nbuf; } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); ret = -1; goto errReturn; } } break; } case 'l': { if (NULL != optarg) { if ((sscanf(optarg, "%2X%2X%2X", &audio->lcolor.r, &audio->lcolor.g, &audio->lcolor.b) == 3)) { audio->avgcolor = !(audio->lcolor.r || audio->lcolor.g || audio->lcolor.b); } else { ambitv_log(ambitv_log_error, LOGNAME "invalid argument for '%s': '%s'.\n", argv[optind - 2], optarg); ret = -1; goto errReturn; } } break; } } default: break; } } if (optind < argc) { ambitv_log(ambitv_log_error, LOGNAME "extraneous argument '%s'.\n", argv[optind]); ret = -1; } errReturn: return ret; }