Refactor controls

This commit is contained in:
Martijn Braam
2023-07-20 16:20:23 +02:00
parent c4969cec6c
commit d51a2fb263
6 changed files with 273 additions and 206 deletions

View File

@@ -82,6 +82,7 @@ set_source_files_properties(
) )
add_dependencies(megapixels-gtk dummy-resource) add_dependencies(megapixels-gtk dummy-resource)
target_link_libraries(megapixels-gtk target_link_libraries(megapixels-gtk
m
${GTK4_LIBRARIES} ${GTK4_LIBRARIES}
${FEEDBACK_LIBRARIES} ${FEEDBACK_LIBRARIES}
${TIFF_LIBRARIES} ${TIFF_LIBRARIES}

View File

@@ -4,6 +4,7 @@
#include "flash.h" #include "flash.h"
#include "pipeline.h" #include "pipeline.h"
#include "process_pipeline.h" #include "process_pipeline.h"
#include "state.h"
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
@@ -13,36 +14,10 @@
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
libmegapixels_camera *io_camera = NULL; mp_state_io state_io;
libmegapixels_mode *mode_capture = NULL;
libmegapixels_mode *mode_preview = NULL;
MPCamera *mpcamera = NULL; MPCamera *mpcamera = NULL;
static bool just_switched_mode = false;
static int blank_frame_count = 0;
static int burst_length;
static int captures_remaining = 0;
static int preview_width;
static int preview_height;
static int device_rotation;
struct control_state {
bool gain_is_manual;
int gain;
bool exposure_is_manual;
int exposure;
};
static struct control_state desired_controls = {};
static struct control_state current_controls = {};
static bool flash_enabled = false;
static bool want_focus = false;
static MPPipeline *pipeline; static MPPipeline *pipeline;
static GSource *capture_source; static GSource *capture_source;
@@ -57,9 +32,7 @@ void
mp_io_pipeline_start() mp_io_pipeline_start()
{ {
mp_process_pipeline_start(); mp_process_pipeline_start();
pipeline = mp_pipeline_new(); pipeline = mp_pipeline_new();
mp_pipeline_invoke(pipeline, setup, NULL, 0); mp_pipeline_invoke(pipeline, setup, NULL, 0);
} }
@@ -69,57 +42,59 @@ mp_io_pipeline_stop()
if (capture_source) { if (capture_source) {
g_source_destroy(capture_source); g_source_destroy(capture_source);
} }
mp_pipeline_free(pipeline); mp_pipeline_free(pipeline);
mp_process_pipeline_stop(); mp_process_pipeline_stop();
} }
/*
* Update state from IO -> Process
*/
static void static void
update_process_pipeline() update_process_pipeline()
{ {
// Grab the latest control values // Grab the latest control values
if (!current_controls.gain_is_manual) { if (!state_io.gain.manual && state_io.gain.control) {
// current_controls.gain = state_io.gain.value = mp_camera_control_get_int32(
// mp_camera_control_get_int32(info->camera, state_io.camera, state_io.gain.control);
// info->gain_ctrl);
} }
if (!current_controls.exposure_is_manual) {
// current_controls.exposure = if (!state_io.exposure.manual && state_io.exposure.control) {
// mp_camera_control_get_int32(info->camera, state_io.exposure.value = mp_camera_control_get_int32(
// V4L2_CID_EXPOSURE); state_io.camera, state_io.exposure.control);
} }
MPControl control; MPControl control;
float balance_red = 1.0f; float balance_red = 1.0f;
float balance_blue = 1.0f; float balance_blue = 1.0f;
/* if (state_io.red.control && state_io.blue.control) {
if (mp_camera_query_control(info->camera, V4L2_CID_RED_BALANCE, &control)) { int red = mp_camera_control_get_int32(state_io.camera,
int red = mp_camera_control_get_int32(info->camera, state_io.red.control);
V4L2_CID_RED_BALANCE); int blue = mp_camera_control_get_int32(state_io.camera,
int blue = mp_camera_control_get_int32(info->camera, state_io.blue.control);
V4L2_CID_BLUE_BALANCE); balance_red = (float)red / (float)state_io.red.max;
balance_red = (float)red / (float)control.max; balance_blue = (float)blue / (float)state_io.blue.max;
balance_blue = (float)blue / (float)control.max;
} }
*/
struct mp_process_pipeline_state pipeline_state = { struct mp_process_pipeline_state pipeline_state = {
.camera = io_camera, .camera = state_io.camera,
.burst_length = burst_length, .burst_length = state_io.burst_length,
.preview_width = preview_width, .preview_width = state_io.preview_width,
.preview_height = preview_height, .preview_height = state_io.preview_height,
.device_rotation = device_rotation, .device_rotation = state_io.device_rotation,
.gain_is_manual = current_controls.gain_is_manual, .gain_is_manual = state_io.gain.manual,
.gain = current_controls.gain, .gain = state_io.gain.value,
.gain_max = 1, // TODO: Fix .gain_max = state_io.gain.max,
.balance_red = balance_red, .balance_red = balance_red,
.balance_blue = balance_blue, .balance_blue = balance_blue,
.exposure_is_manual = current_controls.exposure_is_manual, .exposure_is_manual = state_io.exposure.manual,
.exposure = current_controls.exposure, .exposure = state_io.exposure.value,
.has_auto_focus_continuous = false, // TODO: fix .has_auto_focus_continuous = state_io.focus.control != 0,
.has_auto_focus_start = false, // TODO: fix .has_auto_focus_start = state_io.can_af_trigger,
.flash_enabled = flash_enabled, .flash_enabled = state_io.flash_enabled,
.control_gain = state_io.gain.control != 0,
.control_exposure = state_io.exposure.control != 0,
.control_focus = state_io.focus.control != 0,
.control_flash = true,
}; };
mp_process_pipeline_update_state(&pipeline_state); mp_process_pipeline_update_state(&pipeline_state);
} }
@@ -127,7 +102,7 @@ update_process_pipeline()
static void static void
focus(MPPipeline *pipeline, const void *data) focus(MPPipeline *pipeline, const void *data)
{ {
want_focus = true; state_io.trigger_af = true;
} }
void void
@@ -139,32 +114,30 @@ mp_io_pipeline_focus()
static void static void
capture(MPPipeline *pipeline, const void *data) capture(MPPipeline *pipeline, const void *data)
{ {
uint32_t gain;
float gain_norm; float gain_norm;
// Disable the autogain/exposure while taking the burst // Disable the autogain/exposure while taking the burst
/* TODO: Fix mp_camera_control_set_int32(state_io.camera, V4L2_CID_AUTOGAIN, 0);
mp_camera_control_set_int32(info->camera, V4L2_CID_AUTOGAIN, 0);
mp_camera_control_set_int32( mp_camera_control_set_int32(
info->camera, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL); state_io.camera, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL);
*/
// Get current gain to calculate a burst length; // Get current gain to calculate a burst length;
// with low gain there's 3, with the max automatic gain of the ov5640 // with low gain there's 3, with the max automatic gain of the ov5640
// the value seems to be 248 which creates a 5 frame burst // the value seems to be 248 which creates a 5 frame burst
// for manual gain you can go up to 11 frames // for manual gain you can go up to 11 frames
gain = mp_camera_control_get_int32(io_camera, V4L2_CID_GAIN); state_io.gain.value =
// gain_norm = (float)gain / (float)mpcamera.gain_max; mp_camera_control_get_int32(state_io.camera, V4L2_CID_GAIN);
// burst_length = (int)fmax(sqrt(gain_norm) * 10, 2) + 1; gain_norm = (float)state_io.gain.value / (float)state_io.gain.max;
burst_length = MIN(1, burst_length); state_io.burst_length = (int)fmax(sqrtf(gain_norm) * 10, 2) + 1;
captures_remaining = burst_length; state_io.burst_length = MIN(1, state_io.burst_length);
state_io.captures_remaining = state_io.burst_length;
// Change camera mode for capturing // Change camera mode for capturing
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(mpcamera); mp_camera_stop_capture(mpcamera);
struct v4l2_format format = {0}; struct v4l2_format format = { 0 };
libmegapixels_select_mode(io_camera, mode_capture, &format); libmegapixels_select_mode(state_io.camera, state_io.mode_capture, &format);
just_switched_mode = true; state_io.flush_pipeline = true;
mp_camera_start_capture(mpcamera); mp_camera_start_capture(mpcamera);
@@ -211,59 +184,58 @@ start_focus()
!mp_camera_check_task_complete(mpcamera, focus_continuous_task)) !mp_camera_check_task_complete(mpcamera, focus_continuous_task))
return; return;
/* TODO: implement if (state_io.focus.control) {
if (mpcamera.has_auto_focus_continuous) {
focus_continuous_task = mp_camera_control_set_bool_bg( focus_continuous_task = mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_FOCUS_AUTO, 1); state_io.camera, state_io.focus.control, 1);
} else if (info->has_auto_focus_start) { } else if (state_io.can_af_trigger) {
start_focus_task = mp_camera_control_set_bool_bg( start_focus_task = mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_AUTO_FOCUS_START, 1); state_io.camera, V4L2_CID_AUTO_FOCUS_START, 1);
} }
*/
} }
static void static void
update_controls() update_controls()
{ {
// Don't update controls while capturing // Don't update controls while capturing
if (captures_remaining > 0) { if (state_io.captures_remaining > 0) {
return; return;
} }
/* TODO: implement
if (want_focus) { if (state_io.trigger_af) {
start_focus(mpcamera); state_io.trigger_af = false;
want_focus = false; start_focus();
} }
if (current_controls.gain_is_manual != desired_controls.gain_is_manual) { if (state_io.gain.manual != state_io.gain.manual_req) {
mp_camera_control_set_bool_bg(info->camera, mp_camera_control_set_bool_bg(state_io.camera,
V4L2_CID_AUTOGAIN, V4L2_CID_AUTOGAIN,
!desired_controls.gain_is_manual); !state_io.gain.manual_req);
state_io.gain.manual = state_io.gain.manual_req;
} }
if (desired_controls.gain_is_manual && if (state_io.gain.manual && state_io.gain.value != state_io.gain.value_req) {
current_controls.gain != desired_controls.gain) { mp_camera_control_set_int32_bg(state_io.camera,
mp_camera_control_set_int32_bg( state_io.gain.control,
info->camera, info->gain_ctrl, desired_controls.gain); state_io.gain.value_req);
state_io.gain.value = state_io.gain.value_req;
} }
if (current_controls.exposure_is_manual != if (state_io.exposure.manual != state_io.exposure.manual_req) {
desired_controls.exposure_is_manual) { mp_camera_control_set_bool_bg(state_io.camera,
mp_camera_control_set_int32_bg(info->camera, V4L2_CID_EXPOSURE_AUTO,
V4L2_CID_EXPOSURE_AUTO, state_io.exposure.manual_req ?
desired_controls.exposure_is_manual ? V4L2_EXPOSURE_MANUAL :
V4L2_EXPOSURE_MANUAL : V4L2_EXPOSURE_AUTO);
V4L2_EXPOSURE_AUTO); state_io.exposure.manual = state_io.exposure.manual_req;
} }
if (desired_controls.exposure_is_manual && if (state_io.exposure.manual &&
current_controls.exposure != desired_controls.exposure) { state_io.exposure.value != state_io.exposure.value_req) {
mp_camera_control_set_int32_bg( mp_camera_control_set_int32_bg(state_io.camera,
info->camera, V4L2_CID_EXPOSURE, desired_controls.exposure); state_io.exposure.control,
state_io.exposure.value_req);
state_io.exposure.value = state_io.exposure.value_req;
} }
current_controls = desired_controls;
*/
} }
static void static void
@@ -274,11 +246,12 @@ on_frame(MPBuffer buffer, void *_data)
// When the mode is switched while capturing we get a couple blank frames, // When the mode is switched while capturing we get a couple blank frames,
// presumably from buffers made ready during the switch. Ignore these. // presumably from buffers made ready during the switch. Ignore these.
if (just_switched_mode) { if (state_io.flush_pipeline) {
if (blank_frame_count < 20) { if (state_io.blank_frame_count < 20) {
// Only check a 10x10 area // Only check a 10x10 area
size_t test_size = MIN(10, io_camera->current_mode->width) * size_t test_size =
MIN(10, io_camera->current_mode->height); MIN(10, state_io.camera->current_mode->width) *
MIN(10, state_io.camera->current_mode->height);
bool image_is_blank = true; bool image_is_blank = true;
for (size_t i = 0; i < test_size; ++i) { for (size_t i = 0; i < test_size; ++i) {
@@ -288,45 +261,44 @@ on_frame(MPBuffer buffer, void *_data)
} }
if (image_is_blank) { if (image_is_blank) {
++blank_frame_count; ++state_io.blank_frame_count;
return; return;
} }
} else { } else {
printf("Blank image limit reached, resulting capture may be blank\n"); printf("Blank image limit reached, resulting capture may be blank\n");
} }
just_switched_mode = false; state_io.flush_pipeline = false;
blank_frame_count = 0; state_io.blank_frame_count = 0;
} }
// Send the image off for processing // Send the image off for processing
mp_process_pipeline_process_image(buffer); mp_process_pipeline_process_image(buffer);
if (captures_remaining > 0) { if (state_io.captures_remaining > 0) {
--captures_remaining; --state_io.captures_remaining;
if (captures_remaining == 0) { if (state_io.captures_remaining == 0) {
// Restore the auto exposure and gain if needed // Restore the auto exposure and gain if needed
if (!current_controls.exposure_is_manual) { if (!state_io.exposure.manual) {
mp_camera_control_set_int32_bg( mp_camera_control_set_int32_bg(
io_camera, state_io.camera,
V4L2_CID_EXPOSURE_AUTO, V4L2_CID_EXPOSURE_AUTO,
V4L2_EXPOSURE_AUTO); V4L2_EXPOSURE_AUTO);
} }
/* TODO: implement if (!state_io.gain.manual) {
if (!current_controls.gain_is_manual) {
mp_camera_control_set_bool_bg( mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_AUTOGAIN, true); state_io.camera, V4L2_CID_AUTOGAIN, true);
} }
*/
// Go back to preview mode // Go back to preview mode
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(mpcamera); mp_camera_stop_capture(mpcamera);
struct v4l2_format format = {0}; struct v4l2_format format = { 0 };
libmegapixels_select_mode(io_camera, mode_preview, &format); libmegapixels_select_mode(
just_switched_mode = true; state_io.camera, state_io.mode_preview, &format);
state_io.flush_pipeline = true;
mp_camera_start_capture(mpcamera); mp_camera_start_capture(mpcamera);
@@ -342,20 +314,82 @@ on_frame(MPBuffer buffer, void *_data)
} }
} }
static void
init_controls()
{
if (mp_camera_query_control(
state_io.camera, V4L2_CID_FOCUS_ABSOLUTE, NULL)) {
// TODO: Set focus state
state_io.focus.control = V4L2_CID_FOCUS_ABSOLUTE;
} else {
state_io.focus.control = 0;
}
if (mp_camera_query_control(state_io.camera, V4L2_CID_FOCUS_AUTO, NULL)) {
mp_camera_control_set_bool_bg(
state_io.camera, V4L2_CID_FOCUS_AUTO, true);
}
state_io.can_af_trigger = mp_camera_query_control(
state_io.camera, V4L2_CID_AUTO_FOCUS_START, NULL);
MPControl control;
if (mp_camera_query_control(state_io.camera, V4L2_CID_GAIN, &control)) {
state_io.gain.control = V4L2_CID_GAIN;
state_io.gain.max = control.max;
} else if (mp_camera_query_control(
state_io.camera, V4L2_CID_ANALOGUE_GAIN, &control)) {
state_io.gain.control = V4L2_CID_ANALOGUE_GAIN;
state_io.gain.max = control.max;
} else {
state_io.gain.max = 0;
state_io.gain.control = 0;
}
if (state_io.gain.control) {
state_io.gain.value = mp_camera_control_get_int32(
state_io.camera, state_io.gain.control);
} else {
state_io.gain.value = 0;
}
state_io.gain.manual =
mp_camera_control_get_bool(state_io.camera, V4L2_CID_AUTOGAIN) == 0;
state_io.exposure.value =
mp_camera_control_get_int32(state_io.camera, V4L2_CID_EXPOSURE);
state_io.exposure.manual =
mp_camera_control_get_int32(state_io.camera,
V4L2_CID_EXPOSURE_AUTO) ==
V4L2_EXPOSURE_MANUAL;
if (mp_camera_query_control(
state_io.camera, V4L2_CID_RED_BALANCE, &control)) {
state_io.red.control = V4L2_CID_RED_BALANCE;
state_io.red.max = control.max;
} else {
state_io.red.control = 0;
}
if (mp_camera_query_control(
state_io.camera, V4L2_CID_BLUE_BALANCE, &control)) {
state_io.blue.control = V4L2_CID_BLUE_BALANCE;
state_io.blue.max = control.max;
} else {
state_io.blue.control = 0;
}
}
/*
* State transfer from Main -> IO
*/
static void static void
update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state)
{ {
// Make sure the state isn't updated more than it needs to be by checking if (state_io.camera != state->camera) {
// whether this state change actually changes anything. if (state_io.camera != NULL) {
bool has_changed = false;
if (io_camera != state->camera) {
has_changed = true;
if (io_camera != NULL) {
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(mpcamera); mp_camera_stop_capture(mpcamera);
libmegapixels_close(io_camera); libmegapixels_close(state_io.camera);
} }
if (capture_source) { if (capture_source) {
@@ -363,90 +397,68 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state)
capture_source = NULL; capture_source = NULL;
} }
io_camera = state->camera; state_io.camera = state->camera;
if (io_camera) { if (state_io.camera) {
libmegapixels_open(io_camera); libmegapixels_open(state_io.camera);
mpcamera = mp_camera_new(io_camera); mpcamera = mp_camera_new(state_io.camera);
mode_preview = NULL; state_io.mode_preview = NULL;
mode_capture = NULL; state_io.mode_capture = NULL;
for (int m = 0; m < io_camera->num_modes; m++) { for (int m = 0; m < state_io.camera->num_modes; m++) {
if (io_camera->modes[m]->rate > 29) { if (state_io.camera->modes[m]->rate > 29) {
mode_preview = io_camera->modes[m]; state_io.mode_preview =
state_io.camera->modes[m];
break; break;
} }
} }
long area = 0; long area = 0;
for (int m = 0; m < io_camera->num_modes; m++) { for (int m = 0; m < state_io.camera->num_modes; m++) {
long this_pixels = io_camera->modes[m]->width * long this_pixels = state_io.camera->modes[m]->width *
io_camera->modes[m]->height; state_io.camera->modes[m]->height;
if (this_pixels > area) { if (this_pixels > area) {
area = this_pixels; area = this_pixels;
mode_capture = io_camera->modes[m]; state_io.mode_capture =
state_io.camera->modes[m];
} }
} }
if (mode_preview == NULL && mode_capture != NULL) { if (state_io.mode_preview == NULL &&
// If no fast preview mode is available, make do with state_io.mode_capture != NULL) {
// slow modes. // If no fast preview mode is available, make due
mode_preview = mode_capture; // with slow modes.
state_io.mode_preview = state_io.mode_capture;
} }
if (mode_preview != NULL) { if (state_io.mode_preview != NULL) {
if (io_camera->video_fd == 0) { if (state_io.camera->video_fd == 0) {
libmegapixels_open(io_camera); libmegapixels_open(state_io.camera);
} }
struct v4l2_format format = {0}; struct v4l2_format format = { 0 };
libmegapixels_select_mode(io_camera, mode_preview, &format); libmegapixels_select_mode(state_io.camera,
state_io.mode_preview,
&format);
} }
mp_camera_start_capture(mpcamera); mp_camera_start_capture(mpcamera);
capture_source = mp_pipeline_add_capture_source( capture_source = mp_pipeline_add_capture_source(
pipeline, mpcamera, on_frame, NULL); pipeline, mpcamera, on_frame, NULL);
current_controls.gain_is_manual = init_controls();
mp_camera_control_get_bool(io_camera,
V4L2_CID_AUTOGAIN) == 0;
// current_controls.gain =
// mp_camera_control_get_int32(camera,
// info->gain_ctrl);
// current_controls.exposure_is_manual =
// mp_camera_control_get_int32(
// info->camera, V4L2_CID_EXPOSURE_AUTO) ==
// V4L2_EXPOSURE_MANUAL;
// current_controls.exposure = mp_camera_control_get_int32(
// info->camera, V4L2_CID_EXPOSURE);
} }
} }
has_changed = has_changed || burst_length != state->burst_length || state_io.burst_length = state->burst_length;
preview_width != state->preview_width || state_io.preview_width = state->preview_width;
preview_height != state->preview_height || state_io.preview_height = state->preview_height;
device_rotation != state->device_rotation; state_io.device_rotation = state->device_rotation;
burst_length = state->burst_length; if (state_io.camera) {
preview_width = state->preview_width; state_io.gain.manual_req = state->gain_is_manual;
preview_height = state->preview_height; state_io.gain.value_req = state->gain;
device_rotation = state->device_rotation; state_io.exposure.manual_req = state->exposure_is_manual;
state_io.exposure.value_req = state->exposure;
if (io_camera) { state_io.flash_enabled = state->flash_enabled;
struct control_state previous_desired = desired_controls;
desired_controls.gain_is_manual = state->gain_is_manual;
desired_controls.gain = state->gain;
desired_controls.exposure_is_manual = state->exposure_is_manual;
desired_controls.exposure = state->exposure;
has_changed = has_changed ||
memcmp(&previous_desired,
&desired_controls,
sizeof(struct control_state)) != 0 ||
flash_enabled != state->flash_enabled;
flash_enabled = state->flash_enabled;
} }
assert(has_changed);
update_process_pipeline(); update_process_pipeline();
} }

View File

@@ -48,8 +48,6 @@ RENDERDOC_API_1_1_2 *rdoc_api = NULL;
mp_state_main state; mp_state_main state;
static bool camera_is_initialized = false;
static MPProcessPipelineBuffer *current_preview_buffer = NULL; static MPProcessPipelineBuffer *current_preview_buffer = NULL;
static char last_path[260] = ""; static char last_path[260] = "";
@@ -65,7 +63,11 @@ GtkWidget *process_spinner;
GtkWidget *scanned_codes; GtkWidget *scanned_codes;
GtkWidget *preview_top_box; GtkWidget *preview_top_box;
GtkWidget *preview_bottom_box; GtkWidget *preview_bottom_box;
GtkWidget *flash_button; GtkWidget *flash_button;
GtkWidget *iso_button;
GtkWidget *shutter_button;
LfbEvent *capture_event; LfbEvent *capture_event;
GSettings *settings; GSettings *settings;
@@ -106,16 +108,14 @@ update_io_pipeline()
mp_io_pipeline_update_state(&io_state); mp_io_pipeline_update_state(&io_state);
// Make the right settings available for the camera // Make the right settings available for the camera
gtk_widget_set_visible(flash_button, state.flash_enabled); gtk_widget_set_visible(flash_button, state.control_flash);
gtk_widget_set_visible(iso_button, state.control_gain);
gtk_widget_set_visible(shutter_button, state.control_exposure);
} }
static bool static bool
update_state(const mp_state_main *new_state) update_state(const mp_state_main *new_state)
{ {
if (!camera_is_initialized) {
camera_is_initialized = true;
}
if (state.camera == new_state->camera) { if (state.camera == new_state->camera) {
state.gain_is_manual = new_state->gain_is_manual; state.gain_is_manual = new_state->gain_is_manual;
state.gain = new_state->gain; state.gain = new_state->gain;
@@ -131,6 +131,11 @@ update_state(const mp_state_main *new_state)
state.preview_buffer_width = new_state->preview_buffer_width; state.preview_buffer_width = new_state->preview_buffer_width;
state.preview_buffer_height = new_state->preview_buffer_height; state.preview_buffer_height = new_state->preview_buffer_height;
state.control_gain = new_state->control_gain;
state.control_exposure = new_state->control_exposure;
state.control_focus = new_state->control_focus;
state.control_flash = new_state->control_flash;
return false; return false;
} }
@@ -1121,9 +1126,9 @@ activate(GtkApplication *app, gpointer data)
"/org/postmarketos/Megapixels/camera.ui"); "/org/postmarketos/Megapixels/camera.ui");
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
GtkWidget *iso_button = iso_button =
GTK_WIDGET(gtk_builder_get_object(builder, "iso-controls-button")); GTK_WIDGET(gtk_builder_get_object(builder, "iso-controls-button"));
GtkWidget *shutter_button = GTK_WIDGET( shutter_button = GTK_WIDGET(
gtk_builder_get_object(builder, "shutter-controls-button")); gtk_builder_get_object(builder, "shutter-controls-button"));
flash_button = flash_button =
GTK_WIDGET(gtk_builder_get_object(builder, "flash-controls-button")); GTK_WIDGET(gtk_builder_get_object(builder, "flash-controls-button"));

View File

@@ -1083,6 +1083,10 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state
.has_auto_focus_start = state->has_auto_focus_start, .has_auto_focus_start = state->has_auto_focus_start,
.preview_buffer_width = output_buffer_width, .preview_buffer_width = output_buffer_width,
.preview_buffer_height = output_buffer_height, .preview_buffer_height = output_buffer_height,
.control_gain = state->control_gain,
.control_exposure = state->control_exposure,
.control_focus = state->control_focus,
.control_flash = state->control_flash,
}; };
mp_main_update_state(&new_state); mp_main_update_state(&new_state);
} }

View File

@@ -29,6 +29,11 @@ struct mp_process_pipeline_state {
bool has_auto_focus_start; bool has_auto_focus_start;
bool flash_enabled; bool flash_enabled;
bool control_gain;
bool control_exposure;
bool control_flash;
bool control_focus;
}; };
bool mp_process_find_processor(char *script); bool mp_process_find_processor(char *script);

View File

@@ -19,6 +19,11 @@ typedef struct state_main {
int burst_length; int burst_length;
// Control state // Control state
bool control_gain;
bool control_exposure;
bool control_flash;
bool control_focus;
bool gain_is_manual; bool gain_is_manual;
int gain; int gain;
int gain_max; int gain_max;
@@ -31,3 +36,38 @@ typedef struct state_main {
bool has_auto_focus_continuous; bool has_auto_focus_continuous;
bool has_auto_focus_start; bool has_auto_focus_start;
} mp_state_main; } mp_state_main;
typedef struct cstate {
uint32_t control;
int32_t value;
int32_t value_req;
int32_t max;
bool manual;
bool manual_req;
} controlstate;
typedef struct state_io {
libmegapixels_camera *camera;
libmegapixels_mode *mode_capture;
libmegapixels_mode *mode_preview;
int burst_length;
int captures_remaining;
bool flush_pipeline;
int blank_frame_count;
// Control state
controlstate gain;
controlstate exposure;
controlstate focus;
controlstate red;
controlstate blue;
bool can_af_trigger;
bool trigger_af;
bool flash_enabled;
// State passed through to the process pipeline
int preview_width;
int preview_height;
int device_rotation;
} mp_state_io;