diff --git a/Makefile.am b/Makefile.am index b1a12cd..b806e9f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign subdir-objects -Wall bin_PROGRAMS = forge -forge_SOURCES = src/main.c src/args.c src/forge.c src/file.c src/window.c src/shaders.c src/timer.c src/string.c src/config_file.c src/rand.c src/video.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c +forge_SOURCES = src/main.c src/args.c src/forge.c src/file.c src/window.c src/shaders.c src/timer.c src/string.c src/config_file.c src/rand.c src/video.c src/shared.c $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/hashmap.c/hashmap.c $(top_srcdir)/log.c/src/log.c forge_CFLAGS = -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays -fno-exceptions -fopenmp -I$(top_srcdir)/include -DGLFW_INCLUDE_NONE -DGLFW_EXPOSE_NATIVE_EGL -DGLFW_NATIVE_INCLUDE_NONE -DLOG_USE_COLOR forge_LDADD = -lm -lGL -lglfw -include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h src/constants.h src/window.h src/shaders.h src/timer.h src/string.h src/config_file.h src/rand.h src/video.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h \ No newline at end of file +include_HEADERS = src/main.h src/args.h src/config.h src/types.h src/forge.h src/file.h src/constants.h src/window.h src/shaders.h src/timer.h src/string.h src/config_file.h src/rand.h src/video.h src/shared.h $(top_srcdir)/include/glad/gl.h $(top_srcdir)/include/glad/egl.h $(top_srcdir)/include/linmath.h $(top_srcdir)/include/hashmap.h $(top_srcdir)/include/log.h \ No newline at end of file diff --git a/Makefile.dev b/Makefile.dev index 67aa4ef..7093aad 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -25,7 +25,7 @@ build: .PHONY: run run: build - ./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=240 --hot-reload + ./build/$(TARGET) $(TEST_ARGS) --monitor-only --internal-size=480 --video-size=240 --hot-reload .PHONY: demo demo: build diff --git a/README.md b/README.md index 208c4f0..35531c0 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,8 @@ make -f Makefile.dev release-arch - [x] Shader based format mapping - [x] Video mapping config file - [x] Get first video size matching internal size - - [x] other internal size for video + - [x] Other internal size for video + - [x] Pass input fps into shaders for debug - [ ] Clean code and fix things - [x] Monitor screen - [x] 2nd window diff --git a/config/shaders.cfg b/config/shaders.cfg index 61a9e77..15289e9 100644 --- a/config/shaders.cfg +++ b/config/shaders.cfg @@ -5,6 +5,8 @@ UNIFORM_DEMO=iDemo UNIFORM_RESOLUTION=iResolution UNIFORM_TEX_RESOLUTION=iTexResolution UNIFORM_IN_RESOLUTION_PREFIX=iInputResolution +UNIFORM_IN_FORMAT_PREFIX=iInputFormat +UNIFORM_IN_FPS_PREFIX=iInputFPS UNIFORM_SEED_PREFIX=seed UNIFORM_STATE_PREFIX=state UNIFORM_TEX_PREFIX=tex diff --git a/shaders/frag0.glsl b/shaders/frag0.glsl index 0217d9b..7202895 100644 --- a/shaders/frag0.glsl +++ b/shaders/frag0.glsl @@ -11,6 +11,10 @@ uniform float iTempo; uniform int iFPS; uniform vec2 iResolution; uniform vec2 iTexResolution; +uniform vec2 iInputResolution1; +uniform vec2 iInputResolution2; +uniform int iInputFPS1; +uniform int iInputFPS2; uniform int iDemo; uniform int seed1; @@ -1310,12 +1314,26 @@ subroutine(src_stage_sub) vec4 src_16(vec2 vUV, int seed) f += selected_fx == 4 ? h_rect(uv2, vec2(-2, -3.2), vec2(1, 0), 0.1) : 0; // show inputs / feedback - f += selected_srca == 5 ? rect(uv2, vec2(-8, 2), vec2(2, 0.1)) : 0; - f += selected_srca == 10 ? rect(uv2, vec2(-7, 2), vec2(1, 0.1)) + rect(uv2, vec2(-8, 0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-9, -1), vec2(1, 0.1)) : 0; - f += (selected_srca == 0 || selected_srca % 5 != 0 && selected_srca >= 8) ? rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 4), vec2(7, 0.1)) + rect(uv2, vec2(-7, 3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, 2), vec2(0.1, 2.1)) : 0; - f += selected_srcb == 5 ? rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-7, -0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-8.5, 1), vec2(1.5, 0.1)) : 0; - f += selected_srcb == 10 ? rect(uv2, vec2(-8, -2), vec2(2, 0.1)) : 0; - f += (selected_srcb == 0 || selected_srcb % 5 != 0 && selected_srcb >= 8) ? rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -4), vec2(7, 0.1)) + rect(uv2, vec2(-7, -3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, -2), vec2(0.1, 2.1)) : 0; + float line_a_a = rect(uv2, vec2(-8, 2), vec2(2, 0.1)); + float line_a_b = rect(uv2, vec2(-7, 2), vec2(1, 0.1)) + rect(uv2, vec2(-8, 0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-9, -1), vec2(1, 0.1)); + float line_a_f = rect(uv2, vec2(-6.5, 2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, 4), vec2(7, 0.1)) + rect(uv2, vec2(-7, 3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, 2), vec2(0.1, 2.1)); + if (selected_srca == 5) { + f += iInputResolution1.x > 0 ? line_a_a : line_a_f; + } else if (selected_srca == 10) { + f += iInputResolution2.x > 0 ? line_a_b : line_a_f; + } else if (selected_srca == 0 || selected_srca >= 8) { + f += line_a_f; + } + float line_b_a = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(-7, -0.5), vec2(0.1, 1.6)) + rect(uv2, vec2(-8.5, 1), vec2(1.5, 0.1)); + float line_b_b = rect(uv2, vec2(-8, -2), vec2(2, 0.1)); + float line_b_f = rect(uv2, vec2(-6.5, -2), vec2(0.5, 0.1)) + rect(uv2, vec2(0, -4), vec2(7, 0.1)) + rect(uv2, vec2(-7, -3), vec2(0.1, 1.1)) + rect(uv2, vec2(7, -2), vec2(0.1, 2.1)); + if (selected_srcb == 5) { + f += iInputResolution1.x > 0 ? line_b_a : line_b_f; + } else if (selected_srcb == 10) { + f += iInputResolution2.x > 0 ? line_b_b : line_b_f; + } else if (selected_srcb == 0 || selected_srcb >= 8) { + f += line_b_f; + } // show page f += char_at(uv2, vec2(-9.2, -4.3), hex_chars[page]); @@ -1338,24 +1356,34 @@ subroutine(src_stage_sub) vec4 src_16(vec2 vUV, int seed) f += write_int(uv3, vec2(x - 4,13), iFPS, 3); v = min(1, iFPS/60.0); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); - f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); + f += rect(uv3, vec2(x + 4 * v - 3.5, 12), vec2(4 * v, 0.4)); x = 0; f += write_5(uv3, vec2(x,13), texts[1]); f += write_int(uv3, vec2(x - 4,13), int(iTempo), 3); v = modTime(1); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); - f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); + f += rect(uv3, vec2(x + 4 * v - 3.5, 12), vec2(4 * v, 0.4)); x = 15; f += write_5(uv3, vec2(x,13), texts[2]); f += write_int(uv3, vec2(x - 6,13), int(iTime), 5); v = fract(iTime); f += h_rect(uv3, vec2(x, 12), vec2(4, 0.5), 0.2); - f += rect(uv3, vec2(x + 4 * v - 4, 12), vec2(4 * v, 0.4)); + f += rect(uv3, vec2(x + 4 * v - 3.5, 12), vec2(4 * v, 0.4)); f += write_5(uv3, vec2(-2,-15), iDemo > 0 ? texts[3] : texts[4]); + if (iInputResolution1.x > 0) { + f += write_5(uv3, vec2(-23.5,5.5), texts[0]); + f += write_int(uv3, vec2(-27,5.5), iInputFPS1, 3); + } + + if (iInputResolution2.x > 0) { + f += write_5(uv3, vec2(-23.5,-9.5), texts[0]); + f += write_int(uv3, vec2(-27,-9.5), iInputFPS2, 3); + } + return vec4(f); } @@ -1924,7 +1952,7 @@ subroutine(mix_stage_sub) vec4 mix_16(vec2 vUV, sampler2D ta, sampler2D tb, int const mat3x3 yuv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}}; -const float YUYV_FOURCC = 1448695129.0; +const int YUYV_FOURCC = 1448695129; vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) { float w = base_width - 1; diff --git a/shaders/frag1.glsl b/shaders/frag1.glsl index 8be51ea..9f62239 100644 --- a/shaders/frag1.glsl +++ b/shaders/frag1.glsl @@ -6,12 +6,12 @@ in vec2 vUV; out vec4 fragColor; -uniform vec3 iInputResolution1; +uniform int iInputFormat1; void main() { - if (iInputResolution1.z == YUYV_FOURCC) { + if (iInputFormat1 == YUYV_FOURCC) { fragColor = yuyvTex(tex1, vUV, int(iInputResolution1.x)); } else { - fragColor = vec4(0, 0, 0, 1); + fragColor = texture(tex0, vUV); } } \ No newline at end of file diff --git a/shaders/frag2.glsl b/shaders/frag2.glsl index 7fb44ff..db7701e 100644 --- a/shaders/frag2.glsl +++ b/shaders/frag2.glsl @@ -6,12 +6,12 @@ in vec2 vUV; out vec4 fragColor; -uniform vec3 iInputResolution2; +uniform int iInputFormat2; void main() { - if (iInputResolution2.z == YUYV_FOURCC) { + if (iInputFormat2 == YUYV_FOURCC) { fragColor = yuyvTex(tex2, vUV, int(iInputResolution2.x)); } else { - fragColor = vec4(0, 0, 0, 1); + fragColor = texture(tex0, vUV); } } \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 8267ec2..61d4a6d 100644 --- a/src/forge.c +++ b/src/forge.c @@ -10,6 +10,7 @@ #include "forge.h" #include "rand.h" #include "shaders.h" +#include "shared.h" #include "timer.h" #include "types.h" #include "video.h" @@ -24,15 +25,19 @@ static File *fragment_shaders; static File common_shader_code; static Timer timer; static ConfigFile shader_config; -static bool stop; +static SharedBool *stop; + +static void compute_fps() { + unsigned int i; -static unsigned int compute_fps() { double fps; char title[100]; if (timer_inc(&timer)) { fps = timer_reset(&timer); + log_trace("(main) %.2ffps", fps); + if (window_output != NULL) { sprintf(title, PACKAGE " " VERSION " - %.0ffps", fps); window_update_title(window_output, title); @@ -42,9 +47,15 @@ static unsigned int compute_fps() { sprintf(title, PACKAGE " " VERSION " (monitor) - %.0ffps", fps); window_update_title(window_monitor, title); } + + context.fps = (unsigned int)round(fps); } - return (unsigned int)round(fps); + for (i = 0; i < program.in_count; i++) { + if (!inputs[i].error) { + context.input_fps[i] = inputs[i].fps->value; + } + } } static void randomize_context_state() { @@ -79,6 +90,8 @@ static void init_context(Parameters params) { (unsigned int *)calloc(program.in_count, sizeof(unsigned int)); context.input_formats = (unsigned int *)calloc(program.in_count, sizeof(unsigned int)); + context.input_fps = + (unsigned int *)calloc(program.in_count, sizeof(unsigned int)); for (i = 0; i < program.in_count; i++) { if (!inputs[i].error) { @@ -95,6 +108,7 @@ static void free_context() { free(context.input_widths); free(context.input_heights); free(context.input_formats); + free(context.input_fps); } static void hot_reload() { @@ -175,7 +189,7 @@ static void start_video_captures(unsigned int video_count) { for (i = 0; i < video_count; i++) { if (!inputs[i].error) { - video_background_read(&inputs[i], &stop); + video_background_read(&inputs[i], stop); } } } @@ -195,7 +209,7 @@ static void free_video_captures(unsigned int video_count) { static void error_callback(int error, const char *description) { log_error("[GLFW] %d: %s", error, description); window_terminate(); - stop = true; + stop->value = true; exit(EXIT_FAILURE); } @@ -219,7 +233,7 @@ static void loop(bool hr) { hot_reload(); } - context.fps = compute_fps(); + compute_fps(); context.time = window_get_time(); @@ -245,7 +259,7 @@ static void loop(bool hr) { void forge_run(Parameters params) { unsigned int frag_count; - stop = false; + stop = shared_init_bool("/" PACKAGE "_stop", false); shader_config = config_file_read(params.frag_config_path, false); @@ -253,12 +267,12 @@ void forge_run(Parameters params) { init_files(params.frag_path, frag_count); + init_inputs(params.video_in, params.video_in_count, params.video_size); + window_startup(error_callback); context.internal_height = params.internal_size; - init_inputs(params.video_in, params.video_in_count, params.video_size); - if (params.output) { window_output = window_init(PACKAGE " " VERSION, params.output_screen, params.windowed, NULL, key_callback); @@ -303,7 +317,7 @@ void forge_run(Parameters params) { loop(params.hot_reload); } - stop = true; + stop->value = true; wait(NULL); diff --git a/src/shaders.c b/src/shaders.c index f01e253..cd2d7a4 100644 --- a/src/shaders.c +++ b/src/shaders.c @@ -272,13 +272,28 @@ static void init_single_program(ShaderProgram *program, unsigned int i, prefix = config_file_get_str(shader_config, "UNIFORM_IN_RESOLUTION_PREFIX", "iInputResolution"); - for (j = 0; j < program->in_count; j++) { sprintf(name, "%s%d", prefix, j + 1); program->iinres_locations[i * program->in_count + j] = glGetUniformLocation(program->programs[i], name); } + prefix = config_file_get_str(shader_config, "UNIFORM_IN_FORMAT_PREFIX", + "iInputFormat"); + for (j = 0; j < program->in_count; j++) { + sprintf(name, "%s%d", prefix, j + 1); + program->iinfmt_locations[i * program->in_count + j] = + glGetUniformLocation(program->programs[i], name); + } + + prefix = + config_file_get_str(shader_config, "UNIFORM_IN_FPS_PREFIX", "iInputFPS"); + for (j = 0; j < program->in_count; j++) { + sprintf(name, "%s%d", prefix, j + 1); + program->iinfps_locations[i * program->in_count + j] = + glGetUniformLocation(program->programs[i], name); + } + prefix = config_file_get_str(shader_config, "UNIFORM_SEED_PREFIX", "seed"); for (j = 0; j < program->frag_count; j++) { sprintf(name, "%s%d", prefix, j + 1); @@ -335,6 +350,10 @@ static void init_programs(ShaderProgram *program, ConfigFile shader_config) { program->itexres_locations = malloc(program->frag_count * sizeof(GLuint)); program->iinres_locations = malloc(program->frag_count * program->in_count * sizeof(GLuint)); + program->iinfmt_locations = + malloc(program->frag_count * program->in_count * sizeof(GLuint)); + program->iinfps_locations = + malloc(program->frag_count * program->in_count * sizeof(GLuint)); program->idemo_locations = malloc(program->frag_count * sizeof(GLuint)); program->iseed_locations = malloc(program->frag_count * program->frag_count * sizeof(GLuint)); @@ -435,8 +454,7 @@ static void use_program(ShaderProgram program, int i, bool output, Context context) { unsigned int j, k; GLuint *subroutines; - vec2 resolution, tex_resolution; - vec3 in_resolution; + vec2 resolution, tex_resolution, in_resolution; resolution[0] = (float)context.width; resolution[1] = (float)context.height; @@ -474,10 +492,13 @@ static void use_program(ShaderProgram program, int i, bool output, for (j = 0; j < program.in_count; j++) { in_resolution[0] = context.input_widths[j]; in_resolution[1] = context.input_heights[j]; - in_resolution[2] = context.input_formats[j]; - glUniform3fv(program.iinres_locations[i * program.in_count + j], 1, + glUniform2fv(program.iinres_locations[i * program.in_count + j], 1, (const GLfloat *)&in_resolution); + glUniform1i(program.iinfmt_locations[i * program.in_count + j], + (const GLint)context.input_formats[j]); + glUniform1i(program.iinfps_locations[i * program.in_count + j], + (const GLint)context.input_fps[j]); } // set seeds uniforms diff --git a/src/shared.c b/src/shared.c new file mode 100644 index 0000000..c63519d --- /dev/null +++ b/src/shared.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include + +#include "shared.h" +#include "types.h" + +static void *open_shared(const char *key, size_t size, int *fd) { + *fd = shm_open(key, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + ftruncate(*fd, size); + + return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0); +} + +static void close_shared(void *shared, size_t size, int fd) { + munmap(shared, size); + close(fd); +} + +SharedUint *shared_init_uint(const char *key, unsigned int initial_value) { + int shared_fd; + SharedUint *shared; + + shared = open_shared(key, sizeof(SharedUint), &shared_fd); + + shared->fd = shared_fd; + shared->value = initial_value; + + return shared; +} + +void shared_close_uint(SharedUint *shared) { + close_shared(shared, sizeof(SharedUint), shared->fd); +} + +SharedBool *shared_init_bool(const char *key, bool initial_value) { + int shared_fd; + SharedBool *shared; + + shared = open_shared(key, sizeof(SharedBool), &shared_fd); + + shared->fd = shared_fd; + shared->value = initial_value; + + return shared; +} + +void shared_close_bool(SharedBool *shared) { + close_shared(shared, sizeof(SharedBool), shared->fd); +} diff --git a/src/shared.h b/src/shared.h new file mode 100644 index 0000000..7db1945 --- /dev/null +++ b/src/shared.h @@ -0,0 +1,12 @@ +#include "types.h" + +#ifndef SHARED_H +#define SHARED_H + +SharedUint *shared_init_uint(const char *key, unsigned int initial_value); +void shared_close_uint(SharedUint *shared); + +SharedBool *shared_init_bool(const char *key, bool initial_value); +void shared_close_bool(SharedBool *shared); + +#endif /* SHARED_H */ \ No newline at end of file diff --git a/src/types.h b/src/types.h index ae60597..5e0516b 100644 --- a/src/types.h +++ b/src/types.h @@ -13,6 +13,16 @@ #ifndef TYPES_H #define TYPES_H +typedef struct SharedUint { + int fd; + unsigned int value; +} SharedUint; + +typedef struct SharedBool { + int fd; + bool value; +} SharedBool; + typedef struct Parameters { bool hot_reload; bool output; @@ -70,6 +80,8 @@ typedef struct ShaderProgram { GLuint *ires_locations; GLuint *itexres_locations; GLuint *iinres_locations; + GLuint *iinfmt_locations; + GLuint *iinfps_locations; GLuint *idemo_locations; GLuint *iseed_locations; GLuint *istate_locations; @@ -95,6 +107,7 @@ typedef struct VideoCapture { unsigned int height; unsigned int pixelformat; unsigned int bytesperline; + SharedUint *fps; bool output; struct v4l2_buffer buf; EGLImageKHR dma_image; @@ -117,6 +130,7 @@ typedef struct Context { unsigned int *input_widths; unsigned int *input_heights; unsigned int *input_formats; + unsigned int *input_fps; } Context; typedef struct Timer { diff --git a/src/video.c b/src/video.c index 9ff07d5..42845f1 100644 --- a/src/video.c +++ b/src/video.c @@ -3,10 +3,14 @@ #include #include #include +#include #include #include #include +#include "config.h" +#include "rand.h" +#include "shared.h" #include "timer.h" #include "types.h" #include "video.h" @@ -266,6 +270,14 @@ static void create_image_buffer(VideoCapture *video_capture) { ioctl(video_capture->fd, VIDIOC_QBUF, &video_capture->buf); } +static void create_shared_data(VideoCapture *video_capture) { + char name[256]; + + sprintf(name, "/" PACKAGE "_fps_%d", rand_uint(1000000)); + + video_capture->fps = shared_init_uint(name, 0); +} + static void close_stream(VideoCapture video_capture) { ioctl(video_capture.fd, VIDIOC_STREAMOFF, &buf_type); } @@ -305,6 +317,8 @@ VideoCapture video_init(char *name, unsigned int preferred_height) { create_image_buffer(&video_capture); + create_shared_data(&video_capture); + return video_capture; } @@ -326,9 +340,11 @@ static bool read_video(VideoCapture *video_capture) { return true; } -void video_background_read(VideoCapture *video_capture, bool *stop) { +void video_background_read(VideoCapture *video_capture, SharedBool *stop) { pid_t pid; Timer timer; + double fps; + pid = fork(); if (pid < 0) { log_error("Could not create subprocess"); @@ -341,21 +357,30 @@ void video_background_read(VideoCapture *video_capture, bool *stop) { pid); timer = timer_init(30); - while (!*stop && read_video(video_capture)) { + while (!stop->value && read_video(video_capture)) { // repeat infinitely if (timer_inc(&timer)) { - log_trace("(%s) %.2ffps", video_capture->name, timer_reset(&timer)); + fps = timer_reset(&timer); + + video_capture->fps->value = (unsigned int)round(fps); + log_trace("(%s) %.2ffps", video_capture->name, fps); } } - log_info("%s background acquisition stopped (pid: %d)", video_capture->name, - pid); + if (stop->value) { + log_info("%s background acquisition stopped by main thread (pid: %d)", + video_capture->name, pid); + } else { + log_info("%s background acquisition stopped after error (pid: %d)", + video_capture->name, pid); + } window_terminate(); - exit(EXIT_SUCCESS); + exit(stop->value ? EXIT_SUCCESS : EXIT_FAILURE); } void video_free(VideoCapture video_capture) { if (!video_capture.error) { close_stream(video_capture); + shared_close_uint(video_capture.fps); } if (video_capture.exp_fd != -1) { close(video_capture.exp_fd); diff --git a/src/video.h b/src/video.h index a9acde7..67296a5 100644 --- a/src/video.h +++ b/src/video.h @@ -5,7 +5,7 @@ VideoCapture video_init(char *name, unsigned int preferred_height); -void video_background_read(VideoCapture *video_capture, bool *stop); +void video_background_read(VideoCapture *video_capture, SharedBool *stop); void video_free(VideoCapture video_capture);