diff --git a/README.md b/README.md index 2581c98..9043124 100644 --- a/README.md +++ b/README.md @@ -174,9 +174,9 @@ These are configurable in the [`forge_project.cfg`](#forge_projectcfg). ### CLI arguments ```txt -forge steel-dev +forge steel-VERSION -usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf] +usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vb=COUNT] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf] Fusion Of Real-time Generative Effects. @@ -196,6 +196,7 @@ options: -nar, --no-auto-random do not randomize state (default) -arc, --auto-random-cycle auto random cycle length (default: 4) -vi, --video-in path to video capture device (multiple allowed) + -vb, --video-buffers number of video buffers to use (default: 2) -vs, --video-size video capture desired height (default: internal texture height) -vr, --video-reconnect auto-reconnect video (default) -nvr, --no-video-reconnect do not auto-reconnect video diff --git a/default/forge_project.cfg b/default/forge_project.cfg index 8574ea4..1836c2a 100644 --- a/default/forge_project.cfg +++ b/default/forge_project.cfg @@ -51,8 +51,6 @@ UNIFORM_STATE_PREFIX=iState UNIFORM_ACTIVE_PREFIX=iActive # Input X format raw integer value UNIFORM_IN_FORMAT_PREFIX=iInputFormat -# Input X should use swap texture or not (0/1) -UNIFORM_IN_SWAP_PREFIX=iInputSwap # --- uniform vec2 --- @@ -106,9 +104,6 @@ IN_COUNT=2 # To which texture will be bound video device X IN_1_OUT=1 IN_2_OUT=2 -# To which texture will be bound swap buffers (for double-buffering) -IN_1_SWAP_OUT=3 -IN_2_SWAP_OUT=4 # === FRAGMENT SHADERS # Fragment shaders will be read from the CLI directory as "fragX.glsl" diff --git a/src/args.c b/src/args.c index 08a7a2f..857d923 100644 --- a/src/args.c +++ b/src/args.c @@ -32,6 +32,7 @@ static void print_help(int status_code) { #ifdef VIDEO_IN "[-vi=FILE] " "[-vs=SIZE] " + "[-vb=COUNT] " "[-vr / -nvr] " #endif /* VIDEO_IN */ "[-is=SIZE] " @@ -63,6 +64,8 @@ static void print_help(int status_code) { #ifdef VIDEO_IN " -vi, --video-in path to video capture device (multiple " "allowed)\n" + " -vb, --video-buffers number of video buffers to use (default: " + "2)\n" " -vs, --video-size video capture desired height (default: " "internal texture height)\n" " -vr, --video-reconnect auto-reconnect video (default)\n" @@ -134,9 +137,12 @@ void args_parse(Parameters *params, int argc, char **argv) { params->demo = false; params->auto_random = false; params->auto_random_cycle = 4; +#ifdef VIDEO_IN params->video_in.length = 0; + params->video_buffers = 2; params->video_size = 0; params->video_reconnect = true; +#endif /* VIDEO_IN */ params->internal_size = 720; params->load_state = true; params->save_state = true; @@ -184,38 +190,6 @@ void args_parse(Parameters *params, int argc, char **argv) { if (params->auto_random_cycle == 0) { invalid_value(arg, value); } - } else if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) { -#ifdef VIDEO_IN - if (params->video_in.length == MAX_VIDEO) { - log_error("maximum video input reached"); - exit(EXIT_FAILURE); - } - strlcpy(params->video_in.values[params->video_in.length++], value, - STR_LEN); -#else - invalid_arg(arg); -#endif /* VIDEO_IN */ - } else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) { -#ifdef VIDEO_IN - params->video_size = parse_uint(arg, value); - if (params->video_size == 0) { - invalid_value(arg, value); - } -#else - invalid_arg(arg); -#endif /* VIDEO_IN */ - } else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) { -#ifdef VIDEO_IN - params->video_reconnect = true; -#else - invalid_arg(arg); -#endif /* VIDEO_IN */ - } else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) { -#ifdef VIDEO_IN - params->video_reconnect = false; -#else - invalid_arg(arg); -#endif /* VIDEO_IN */ } else if (is_arg(arg, "-is") || is_arg(arg, "--internal-size")) { params->internal_size = parse_uint(arg, value); if (params->internal_size == 0) { @@ -238,7 +212,34 @@ void args_parse(Parameters *params, int argc, char **argv) { } else if (is_arg(arg, "-tf") || is_arg(arg, "--trace-fps")) { params->trace_fps = true; } else { +#ifdef VIDEO_IN + if (is_arg(arg, "-vi") || is_arg(arg, "--video-in")) { + if (params->video_in.length == MAX_VIDEO) { + log_error("maximum video input reached"); + exit(EXIT_FAILURE); + } + strlcpy(params->video_in.values[params->video_in.length++], value, + STR_LEN); + } else if (is_arg(arg, "-vb") || is_arg(arg, "--video-buffers")) { + params->video_buffers = parse_uint(arg, value); + if (params->video_buffers == 0) { + invalid_value(arg, value); + } + } else if (is_arg(arg, "-vs") || is_arg(arg, "--video-size")) { + params->video_size = parse_uint(arg, value); + if (params->video_size == 0) { + invalid_value(arg, value); + } + } else if (is_arg(arg, "-vr") || is_arg(arg, "--video-reconnect")) { + params->video_reconnect = true; + } else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) { + params->video_reconnect = false; + } else { + invalid_arg(arg); + } +#else invalid_arg(arg); +#endif /* VIDEO_IN */ } } @@ -247,8 +248,9 @@ void args_parse(Parameters *params, int argc, char **argv) { log_error("monitor screen cannot be the same as output screen"); exit(EXIT_FAILURE); } - +#ifdef VIDEO_IN if (params->video_size == 0) { params->video_size = params->internal_size; } +#endif /* VIDEO_IN */ } diff --git a/src/forge.c b/src/forge.c index c07e96b..9188698 100644 --- a/src/forge.c +++ b/src/forge.c @@ -70,7 +70,7 @@ static void init_context() { memset(context.input_resolutions, 0, sizeof(context.input_resolutions)); memset(context.input_formats, 0, sizeof(context.input_formats)); memset(context.input_fps, 0, sizeof(context.input_fps)); - memset(context.input_swap, 0, sizeof(context.input_swap)); + memset(context.input_index, 0, sizeof(context.input_index)); #endif /* VIDEO_IN */ } @@ -85,7 +85,7 @@ static void init_inputs() { for (unsigned int i = 0; i < init_params.video_in.length; i++) { video_init(&video_captures.values[i], init_params.video_in.values[i], - init_params.video_size); + init_params.video_size, init_params.video_buffers); if (!video_captures.values[i].error) { context.input_resolutions[i][0] = video_captures.values[i].width; @@ -121,7 +121,7 @@ background_reconnect_video_captures(__attribute__((unused)) void *args) { if (video_captures.values[i].disconnected) { video_free(&video_captures.values[i]); video_init(&video_captures.values[i], init_params.video_in.values[i], - init_params.video_size); + init_params.video_size, init_params.video_buffers); if (!video_captures.values[i].error) { context.input_resolutions[i][0] = video_captures.values[i].width; @@ -292,7 +292,8 @@ static bool init(const Parameters *params) { } #ifdef VIDEO_IN - shaders_link_inputs(&program, &project, &video_captures); + shaders_link_inputs(&program, &project, &video_captures, + init_params.video_buffers); #endif /* VIDEO_IN */ if (program.error) { diff --git a/src/shaders.c b/src/shaders.c index db67f90..56cf986 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -191,18 +191,20 @@ static void rebind_textures(const ShaderProgram *program) { #ifdef VIDEO_IN static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, unsigned int input_index, - unsigned int texture_index, bool swap, - bool reload) { + unsigned int sub_index, bool reload) { + unsigned int texture_index = + program->tex_count + input_index * program->sub_video_count + sub_index; + if (reload) { glDeleteTextures(1, program->textures + texture_index); if (check_glerror(program, "link_input_to_texture/glDeleteTextures")) { return false; } + } - glGenTextures(1, program->textures + texture_index); - if (check_glerror(program, "link_input_to_texture/glGenTextures")) { - return false; - } + glGenTextures(1, program->textures + texture_index); + if (check_glerror(program, "link_input_to_texture/glGenTextures")) { + return false; } EGLImageKHR dma_image; @@ -217,7 +219,7 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, EGL_LINUX_DRM_FOURCC_EXT, input->pixelformat, EGL_DMA_BUF_PLANE0_FD_EXT, - swap ? input->exp_fd_swap : input->exp_fd, + input->exp_fd[sub_index], EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, @@ -230,11 +232,8 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, return false; } - if (swap) { - program->dma_images_swap[input_index] = dma_image; - } else { - program->dma_images[input_index] = dma_image; - } + program->dma_images[input_index * program->sub_video_count + sub_index] = + dma_image; glActiveTexture(GL_TEXTURE0 + texture_index); if (check_glerror(program, "link_input_to_texture/glActiveTexture")) { @@ -259,33 +258,35 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input, return false; } - log_info("Texture %d linked to %s", texture_index, input->name); + log_info("Texture %d linked to %s[%d]", texture_index, input->name, + sub_index); return true; } static bool init_input(ShaderProgram *program, const ConfigFile *config, - VideoCaptureArray *inputs, unsigned int i, bool reload) { + VideoCaptureArray *inputs, unsigned int input_index, + bool reload) { unsigned int tex_i; + unsigned int sub_index; char name[STR_LEN]; - if (i < inputs->length && !inputs->values[i].error) { - snprintf(name, STR_LEN, "IN_%d_OUT", i + 1); + if (input_index < inputs->length && input_index < program->in_count && + !inputs->values[input_index].error) { + snprintf(name, STR_LEN, "IN_%d_OUT", input_index + 1); tex_i = config_file_get_int(config, name, 0); - if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, false, - reload)) { - return false; - } - if (inputs->values[i].with_swap) { - snprintf(name, STR_LEN, "IN_%d_SWAP_OUT", i + 1); - tex_i = config_file_get_int(config, name, 0); - if (!link_input_to_texture(program, &inputs->values[i], i, tex_i, true, - reload)) { + for (sub_index = 0; sub_index < inputs->values[input_index].buf_count; + sub_index++) { + if (!link_input_to_texture(program, &inputs->values[input_index], + input_index, sub_index, reload)) { return false; } } + program->input_tex_map[input_index] = tex_i; + program->tex_map[tex_i] = + program->tex_count + input_index * program->sub_video_count; } else { - log_warn("Cannot link input %d", i + 1); + log_warn("Cannot link input %d", input_index + 1); } return true; } @@ -535,13 +536,6 @@ static bool init_single_program(ShaderProgram *program, unsigned int i, glGetUniformLocation(program->programs[i], name); } - prefix = config_file_get_str(config, "UNIFORM_IN_SWAP_PREFIX", "iInputSwap"); - for (unsigned int j = 0; j < program->in_count; j++) { - snprintf(name, STR_LEN, "%s%d", prefix, j + 1); - program->iinswap_locations[i * program->in_count + j] = - glGetUniformLocation(program->programs[i], name); - } - prefix = config_file_get_str(config, "UNIFORM_SEED_PREFIX", "iSeed"); for (unsigned int j = 0; j < program->frag_count; j++) { snprintf(name, STR_LEN, "%s%d", prefix, j + 1); @@ -650,8 +644,7 @@ static void update_viewport(ShaderProgram *program, const Context *context) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, context->tex_resolution[0], context->tex_resolution[1], 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - check_glerror_ro( - "update_viewport/glTexImage2D"); // TODO dont remap input textures + check_glerror_ro("update_viewport/glTexImage2D"); } program->last_resolution[0] = context->resolution[0]; program->last_resolution[1] = context->resolution[1]; @@ -736,8 +729,6 @@ static void use_program(const ShaderProgram *program, int i, bool output, context->input_formats[j]); write_uniform_1i(program->iinfps_locations[i * program->in_count + j], context->input_fps[j]); - write_uniform_1i(program->iinswap_locations[i * program->in_count + j], - context->input_swap[j] ? 1 : 0); } #endif /* VIDEO_IN */ @@ -781,10 +772,9 @@ static void use_program(const ShaderProgram *program, int i, bool output, } // set GL_TEXTURE(X) to uniform sampler2D texX - // TODO perform input swap here for (unsigned int j = 0; j < program->tex_count; j++) { write_uniform_1i(program->textures_locations[i * program->tex_count + j], - j); + program->tex_map[j]); } // draw output @@ -793,11 +783,16 @@ static void use_program(const ShaderProgram *program, int i, bool output, void shaders_init(ShaderProgram *program, const Project *project, const Context *context, bool rebind) { + unsigned int i; if (!rebind) { program->error = false; program->last_resolution[0] = context->resolution[0]; program->last_resolution[1] = context->resolution[1]; program->tex_count = config_file_get_int(&project->config, "TEX_COUNT", 9); + memset(program->tex_map, 0, sizeof(program->tex_map)); + for (i = 0; i < program->tex_count; i++) { + program->tex_map[i] = i; + } program->frag_count = project->frag_count; program->frag_output_index = config_file_get_int(&project->config, "FRAG_OUTPUT", 1) - 1; @@ -812,7 +807,7 @@ void shaders_init(ShaderProgram *program, const Project *project, #ifdef VIDEO_IN memset(program->dma_images, 0, sizeof(program->dma_images)); - memset(program->dma_images_swap, 0, sizeof(program->dma_images_swap)); + memset(program->input_tex_map, 0, sizeof(program->input_tex_map)); #endif /* VIDEO_IN */ if (!init_gl(program)) { @@ -848,31 +843,50 @@ void shaders_init(ShaderProgram *program, const Project *project, #ifdef VIDEO_IN void shaders_relink_input(ShaderProgram *program, const Project *project, - VideoCaptureArray *inputs, unsigned int i) { - // shaders_free_input(program, i); - init_input(program, &project->config, inputs, i, true); + VideoCaptureArray *inputs, unsigned int input_index) { + shaders_free_input(program, input_index); + init_input(program, &project->config, inputs, input_index, true); } void shaders_link_inputs(ShaderProgram *program, const Project *project, - VideoCaptureArray *inputs) { - for (unsigned int i = 0; i < program->in_count; i++) { + VideoCaptureArray *inputs, unsigned int buffer_count) { + unsigned int i; + program->sub_video_count = buffer_count; + for (i = 0; i < program->in_count; i++) { init_input(program, &project->config, inputs, i, false); } } void shaders_free_input(ShaderProgram *program, unsigned int input_index) { - if (program->dma_images[input_index] != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(program->egl_display, program->dma_images[input_index]); - program->dma_images[input_index] = EGL_NO_IMAGE_KHR; - } - if (program->dma_images_swap[input_index] != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(program->egl_display, - program->dma_images_swap[input_index]); - program->dma_images_swap[input_index] = EGL_NO_IMAGE_KHR; + unsigned int sub_index; + for (sub_index = 0; sub_index < program->sub_video_count; sub_index++) { + if (program->dma_images[input_index * program->sub_video_count + + sub_index] != EGL_NO_IMAGE_KHR) { + eglDestroyImageKHR( + program->egl_display, + program + ->dma_images[input_index * program->sub_video_count + sub_index]); + program->dma_images[input_index * program->sub_video_count + sub_index] = + EGL_NO_IMAGE_KHR; + } } check_eglerror_ro("shaders_free_input/eglDestroyImageKHR"); } +static void update_inputs_tex_map(ShaderProgram *program, + const Context *context) { + unsigned int i; + unsigned int tex_i; + for (i = 0; i < program->in_count; i++) { + if (context->input_formats[i] != 0) { + tex_i = program->input_tex_map[i]; + program->tex_map[tex_i] = program->tex_count + + i * program->sub_video_count + + context->input_index[i]; + } + } +} + #endif /* VIDEO_IN */ void shaders_update(ShaderProgram *program, const File *fragment_shader, @@ -887,6 +901,10 @@ void shaders_update(ShaderProgram *program, const File *fragment_shader, void shaders_compute(ShaderProgram *program, const Context *context, bool monitor, bool output_only) { +#ifdef VIDEO_IN + update_inputs_tex_map(program, context); +#endif /* VIDEO_IN */ + if (!output_only) { glBindVertexArray(program->vertex_array[0]); @@ -923,6 +941,12 @@ void shaders_free(const ShaderProgram *program) { glDeleteTextures(program->tex_count, program->textures); check_glerror_ro("shaders_free/glDeleteTextures"); +#ifdef VIDEO_IN + glDeleteTextures(program->in_count * program->sub_video_count, + program->textures + program->tex_count); + check_glerror_ro("shaders_free/glDeleteTextures"); +#endif + glDeleteBuffers(1, &program->vertex_buffer); check_glerror_ro("shaders_free/glDeleteBuffers"); } diff --git a/src/shaders.h b/src/shaders.h index a983fe6..f0e8520 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -12,7 +12,7 @@ void shaders_relink_input(ShaderProgram *program, const Project *project, VideoCaptureArray *inputs, unsigned int i); void shaders_link_inputs(ShaderProgram *program, const Project *project, - VideoCaptureArray *inputs); + VideoCaptureArray *inputs, unsigned int buffer_count); void shaders_free_input(ShaderProgram *program, unsigned int input_index); diff --git a/src/types.h b/src/types.h index e0657ee..225ff64 100644 --- a/src/types.h +++ b/src/types.h @@ -45,10 +45,13 @@ typedef struct Parameters { bool demo; bool auto_random; unsigned int auto_random_cycle; +#ifdef VIDEO_IN StringArray video_in; + unsigned int video_buffers; unsigned int video_size; - unsigned int internal_size; bool video_reconnect; +#endif /* VIDEO_IN */ + unsigned int internal_size; bool load_state; bool save_state; bool midi_reconnect; @@ -85,6 +88,7 @@ typedef struct ShaderProgram { GLuint vertex_array[2]; unsigned int tex_count; + unsigned int tex_map[ARRAY_SIZE]; GLuint textures[ARRAY_SIZE]; unsigned int frag_count; @@ -105,7 +109,6 @@ typedef struct ShaderProgram { GLuint iinres_locations[ARRAY_SIZE]; GLuint iinfmt_locations[ARRAY_SIZE]; GLuint iinfps_locations[ARRAY_SIZE]; - GLuint iinswap_locations[ARRAY_SIZE]; GLuint idemo_locations[ARRAY_SIZE]; GLuint iautorand_locations[ARRAY_SIZE]; GLuint iautorandcycle_locations[ARRAY_SIZE]; @@ -130,9 +133,10 @@ typedef struct ShaderProgram { unsigned int in_count; #ifdef VIDEO_IN + unsigned int sub_video_count; + unsigned int input_tex_map[MAX_VIDEO]; EGLDisplay egl_display; EGLImageKHR dma_images[MAX_VIDEO]; - EGLImageKHR dma_images_swap[MAX_VIDEO]; #endif /* VIDEO_IN */ } ShaderProgram; @@ -163,7 +167,7 @@ typedef struct Context { vec2 input_resolutions[MAX_VIDEO]; unsigned int input_formats[MAX_VIDEO]; unsigned int input_fps[MAX_VIDEO]; - bool input_swap[MAX_VIDEO]; + unsigned int input_index[MAX_VIDEO]; #endif /* VIDEO_IN */ double time; Tempo tempo; @@ -190,17 +194,15 @@ typedef struct VideoCapture { _Atomic bool error; _Atomic bool disconnected; _Atomic bool needs_reload; - bool with_swap; - _Atomic bool swap; + unsigned int buf_count; + unsigned int buf_index; int fd; - int exp_fd; - int exp_fd_swap; + int exp_fd[ARRAY_SIZE]; unsigned int width; unsigned int height; unsigned int pixelformat; unsigned int bytesperline; - struct v4l2_buffer buf; - struct v4l2_buffer buf_swap; + struct v4l2_buffer buf[ARRAY_SIZE]; } VideoCapture; typedef struct VideoCaptureArray { diff --git a/src/video.c b/src/video.c index 4587ea8..dee9c5a 100644 --- a/src/video.c +++ b/src/video.c @@ -192,14 +192,15 @@ static bool set_format(VideoCapture *video_capture) { return true; } -static bool request_buffers(VideoCapture *video_capture) { +static bool request_buffers(VideoCapture *video_capture, + unsigned int buffer_count) { struct v4l2_requestbuffers reqbuf; memset(&reqbuf, 0, sizeof(reqbuf)); reqbuf.type = buf_type; reqbuf.memory = V4L2_MEMORY_MMAP; - reqbuf.count = 2; // TODO buffer array with count from parameters + reqbuf.count = buffer_count; if (ioctl(video_capture->fd, VIDIOC_REQBUFS, &reqbuf) == -1) { ioctl_error(video_capture, "VIDIOC_REQBUFS", @@ -209,7 +210,7 @@ static bool request_buffers(VideoCapture *video_capture) { log_info("(%s) V4L2 Buffer Count: %d", video_capture->name, reqbuf.count); - video_capture->with_swap = reqbuf.count > 1; + video_capture->buf_count = reqbuf.count; return true; } @@ -239,16 +240,15 @@ static bool export_buffer(VideoCapture *video_capture, int *fd, } static bool export_buffers(VideoCapture *video_capture) { - bool result; + unsigned int i; - result = export_buffer(video_capture, &video_capture->exp_fd, 0); - - if (result && video_capture->with_swap) { - result = - result && export_buffer(video_capture, &video_capture->exp_fd_swap, 1); + for (i = 0; i < video_capture->buf_count; i++) { + if (!export_buffer(video_capture, &video_capture->exp_fd[i], i)) { + return false; + } } - return result; + return true; } static bool open_stream(VideoCapture *video_capture) { @@ -274,10 +274,10 @@ static void create_image_buffer(const VideoCapture *video_capture, } static void create_image_buffers(VideoCapture *video_capture) { - create_image_buffer(video_capture, &video_capture->buf, 0); + unsigned int i; - if (video_capture->with_swap) { - create_image_buffer(video_capture, &video_capture->buf_swap, 1); + for (i = 0; i < video_capture->buf_count; i++) { + create_image_buffer(video_capture, &video_capture->buf[i], i); } } @@ -286,31 +286,26 @@ static void close_stream(const VideoCapture *video_capture) { } static unsigned int read_video(VideoCapture *video_capture) { - unsigned int result; struct v4l2_capability cap; - result = 0; + if (ioctl(video_capture->fd, VIDIOC_DQBUF, + &video_capture->buf[video_capture->buf_index]) != -1) { + ioctl(video_capture->fd, VIDIOC_QBUF, + &video_capture->buf[video_capture->buf_index]); + video_capture->buf_index = + (video_capture->buf_index + 1) % video_capture->buf_count; + return true; + } - if ((video_capture->swap || !video_capture->with_swap) && - ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf) != -1) { - ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf); - - result = 1; - } else if (!video_capture->swap && video_capture->with_swap && - ioctl(video_capture->fd, VIDIOC_DQBUF, &video_capture->buf_swap) != - -1) { - ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf_swap); - - result = 2; - } else if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) { + if (ioctl(video_capture->fd, VIDIOC_QUERYCAP, &cap) == -1) { video_capture->error = true; } - return result; + return false; } void video_init(VideoCapture *video_capture, const char *name, - unsigned int preferred_height) { + unsigned int preferred_height, unsigned int buffer_count) { open_device(video_capture, name); if (video_capture->error) { @@ -329,7 +324,7 @@ void video_init(VideoCapture *video_capture, const char *name, return; } - if (!request_buffers(video_capture)) { + if (!request_buffers(video_capture, buffer_count)) { return; } @@ -352,14 +347,15 @@ void *video_background_read(void *args) { bool trace_fps = process_args->trace_fps; Timer timer; double fps; - unsigned int video_result; + bool result; log_info("(%s) background acquisition started", video_capture->name); timer_init(&timer, 30); while (!context->stop && !video_capture->error) { - video_result = read_video(video_capture); - if (video_result > 0 && timer_inc(&timer)) { + result = read_video(video_capture); + + if (result && timer_inc(&timer)) { fps = timer_reset(&timer); context->input_fps[input_index] = (unsigned int)round(fps); @@ -367,9 +363,9 @@ void *video_background_read(void *args) { log_trace("(%s) %.2ffps", video_capture->name, fps); } } - if (video_result > 0) { - context->input_swap[input_index] = video_capture->swap = - video_result == 2; + + if (result) { + context->input_index[input_index] = video_capture->buf_index; } } if (context->stop) { @@ -385,13 +381,14 @@ void *video_background_read(void *args) { } void video_free(const VideoCapture *video_capture) { + unsigned int i; + close_stream(video_capture); - if (video_capture->exp_fd != -1) { - close(video_capture->exp_fd); - } - if (video_capture->exp_fd_swap != -1) { - close(video_capture->exp_fd_swap); + + for (i = 0; i < video_capture->buf_count; i++) { + close(video_capture->exp_fd[i]); } + if (video_capture->fd != -1) { close(video_capture->fd); } diff --git a/src/video.h b/src/video.h index b9e6bbd..6581b95 100644 --- a/src/video.h +++ b/src/video.h @@ -6,7 +6,7 @@ #ifdef VIDEO_IN void video_init(VideoCapture *video_capture, const char *name, - unsigned int preferred_height); + unsigned int preferred_height, unsigned int buffer_count); void *video_background_read(void *args);