refactor: specify number of video input buffers
Clang Lint CI / lint-no-video (push) Successful in 1m5s
Clang Build CI / run-no-video (push) Successful in 1m5s
Clang Build CI / run-video (push) Successful in 1m5s
Clang Build CI / build-release (push) Successful in 2m24s
Clang Lint CI / lint-video (push) Successful in 2m22s
Clang Lint CI / lint-no-video (push) Successful in 1m5s
Clang Build CI / run-no-video (push) Successful in 1m5s
Clang Build CI / run-video (push) Successful in 1m5s
Clang Build CI / build-release (push) Successful in 2m24s
Clang Lint CI / lint-video (push) Successful in 2m22s
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
+35
-33
@@ -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 */
|
||||
}
|
||||
|
||||
+5
-4
@@ -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) {
|
||||
|
||||
+77
-53
@@ -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");
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
+12
-10
@@ -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 {
|
||||
|
||||
+38
-41
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user