diff --git a/src/io_pipeline.c b/src/io_pipeline.c index 9b07728..2da32fc 100644 --- a/src/io_pipeline.c +++ b/src/io_pipeline.c @@ -83,21 +83,24 @@ update_process_pipeline() .device_rotation = state_io.device_rotation, .gain.control = state_io.gain.control, + .gain.auto_control = state_io.gain.auto_control, .gain.value = state_io.gain.value, .gain.max = state_io.gain.max, .gain.manual = state_io.gain.manual, .exposure.control = state_io.exposure.control, + .exposure.auto_control = state_io.exposure.auto_control, .exposure.value = state_io.exposure.value, .exposure.max = state_io.exposure.max, .exposure.manual = state_io.exposure.manual, .focus.control = state_io.focus.control, + .focus.auto_control = state_io.focus.auto_control, .focus.value = state_io.focus.value, .focus.max = state_io.focus.max, .focus.manual = state_io.focus.manual, - .balance = {balance_red, 1.0f, balance_blue}, + .balance = { balance_red, 1.0f, balance_blue }, }; struct mp_process_pipeline_state pipeline_state = { @@ -359,6 +362,9 @@ init_controls() 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.focus.auto_control = V4L2_CID_FOCUS_AUTO; + } else { + state_io.focus.auto_control = 0; } state_io.can_af_trigger = mp_camera_query_control( @@ -383,8 +389,14 @@ init_controls() state_io.gain.value = 0; } - state_io.gain.manual = - mp_camera_control_get_bool(state_io.camera, V4L2_CID_AUTOGAIN) == 0; + if (mp_camera_query_control(state_io.camera, V4L2_CID_AUTOGAIN, &control)) { + state_io.gain.auto_control = V4L2_CID_AUTOGAIN; + state_io.gain.manual = + mp_camera_control_get_bool(state_io.camera, + V4L2_CID_AUTOGAIN) == 0; + } else { + state_io.gain.auto_control = 0; + } if (mp_camera_query_control(state_io.camera, V4L2_CID_EXPOSURE, &control)) { state_io.exposure.control = V4L2_CID_EXPOSURE; @@ -396,10 +408,16 @@ init_controls() state_io.exposure.control = 0; } - 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_EXPOSURE_AUTO, &control)) { + state_io.exposure.auto_control = V4L2_CID_EXPOSURE_AUTO; + state_io.exposure.manual = + mp_camera_control_get_int32(state_io.camera, + V4L2_CID_EXPOSURE_AUTO) == + V4L2_EXPOSURE_MANUAL; + } else { + state_io.exposure.auto_control = 0; + } if (mp_camera_query_control( state_io.camera, V4L2_CID_RED_BALANCE, &control)) { @@ -422,9 +440,9 @@ init_controls() * State transfer from Main -> IO */ static void -update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) +update_state(MPPipeline *pipeline, const mp_state_io *new_state) { - if (state_io.camera != state->camera) { + if (state_io.camera != new_state->camera) { if (state_io.camera != NULL) { mp_process_pipeline_sync(); mp_camera_stop_capture(mpcamera); @@ -436,7 +454,7 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) capture_source = NULL; } - state_io.camera = state->camera; + state_io.camera = new_state->camera; if (state_io.camera) { libmegapixels_open(state_io.camera); mpcamera = mp_camera_new(state_io.camera); @@ -495,29 +513,39 @@ update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) init_controls(); } } - state_io.configuration = state->configuration; - state_io.burst_length = state->burst_length; - state_io.preview_width = state->preview_width; - state_io.preview_height = state->preview_height; - state_io.device_rotation = state->device_rotation; + state_io.configuration = new_state->configuration; + state_io.burst_length = new_state->burst_length; + state_io.preview_width = new_state->preview_width; + state_io.preview_height = new_state->preview_height; + state_io.device_rotation = new_state->device_rotation; if (state_io.camera) { - state_io.gain.manual_req = state->gain_is_manual; - state_io.gain.value_req = state->gain; - state_io.exposure.manual_req = state->exposure_is_manual; - state_io.exposure.value_req = state->exposure; + state_io.gain.value = new_state->gain.value; + state_io.gain.value_req = new_state->gain.value_req; + state_io.gain.manual = new_state->gain.manual; + state_io.gain.manual_req = new_state->gain.manual_req; - state_io.flash_enabled = state->flash_enabled; + state_io.exposure.value = new_state->exposure.value; + state_io.exposure.value_req = new_state->exposure.value_req; + state_io.exposure.manual = new_state->exposure.manual; + state_io.exposure.manual_req = new_state->exposure.manual_req; + + state_io.focus.value = new_state->focus.value; + state_io.focus.value_req = new_state->focus.value_req; + state_io.focus.manual = new_state->focus.manual; + state_io.focus.manual_req = new_state->focus.manual_req; + + state_io.flash_enabled = new_state->flash_enabled; } update_process_pipeline(); } void -mp_io_pipeline_update_state(const struct mp_io_pipeline_state *state) +mp_io_pipeline_update_state(const mp_state_io *state) { mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, state, - sizeof(struct mp_io_pipeline_state)); + sizeof(mp_state_io)); } diff --git a/src/io_pipeline.h b/src/io_pipeline.h index 0842535..575b800 100644 --- a/src/io_pipeline.h +++ b/src/io_pipeline.h @@ -1,29 +1,10 @@ #pragma once +#include "state.h" #include #include #include -struct mp_io_pipeline_state { - libmegapixels_camera *camera; - libmegapixels_devconfig *configuration; - - int burst_length; - - int preview_width; - int preview_height; - - int device_rotation; - - bool gain_is_manual; - int gain; - - bool exposure_is_manual; - int exposure; - - bool flash_enabled; -}; - void mp_io_pipeline_start(); void mp_io_pipeline_stop(); @@ -32,4 +13,4 @@ void mp_io_pipeline_capture(); void mp_io_pipeline_release_buffer(uint32_t buffer_index); -void mp_io_pipeline_update_state(const struct mp_io_pipeline_state *state); +void mp_io_pipeline_update_state(const mp_state_io *state); diff --git a/src/main.c b/src/main.c index 9d67181..9f04b40 100644 --- a/src/main.c +++ b/src/main.c @@ -100,37 +100,70 @@ check_window_active() static void update_io_pipeline() { - struct mp_io_pipeline_state io_state = { + mp_state_io new_state = { .camera = state.camera, .configuration = state.configuration, .burst_length = state.burst_length, .preview_width = state.preview_width, .preview_height = state.preview_height, .device_rotation = state.device_rotation, - .gain_is_manual = state.gain_is_manual, - .gain = state.gain, - .exposure_is_manual = state.exposure_is_manual, - .exposure = state.exposure, - .flash_enabled = state.flash_enabled, + + .gain.control = state.gain.control, + .gain.auto_control = state.gain.auto_control, + .gain.value = state.gain.value, + .gain.value_req = state.gain.value_req, + .gain.max = state.gain.max, + .gain.manual = state.gain.manual, + .gain.manual_req = state.gain.manual_req, + + .exposure.control = state.exposure.control, + .exposure.auto_control = state.exposure.auto_control, + .exposure.value = state.exposure.value, + .exposure.value_req = state.exposure.value_req, + .exposure.max = state.exposure.max, + .exposure.manual = state.exposure.manual, + .exposure.manual_req = state.exposure.manual_req, + + .focus.control = state.focus.control, + .focus.auto_control = state.focus.auto_control, + .focus.value = state.focus.value, + .focus.value_req = state.focus.value_req, + .focus.max = state.focus.max, + .focus.manual = state.focus.manual, + .focus.manual_req = state.focus.manual_req, }; - mp_io_pipeline_update_state(&io_state); + mp_io_pipeline_update_state(&new_state); // Make the right settings available for the camera 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); + gtk_widget_set_visible(iso_button, state.gain.control != 0); + gtk_widget_set_visible(shutter_button, state.exposure.control != 0); } +/* + * State transfer from Process -> Main + */ static bool update_state(const mp_state_main *new_state) { if (state.camera == new_state->camera) { - state.gain_is_manual = new_state->gain_is_manual; - state.gain = new_state->gain; - state.gain_max = new_state->gain_max; + state.gain.control = new_state->gain.control; + state.gain.auto_control = new_state->gain.auto_control; + state.gain.value = new_state->gain.value; + state.gain.max = new_state->gain.max; + state.gain.manual = new_state->gain.manual; - state.exposure_is_manual = new_state->exposure_is_manual; - state.exposure = new_state->exposure; + state.exposure.control = new_state->exposure.control; + state.exposure.auto_control = new_state->exposure.auto_control; + state.exposure.value = new_state->exposure.value; + state.exposure.max = new_state->exposure.max; + state.exposure.manual = new_state->exposure.manual; + + state.focus.control = new_state->focus.control; + state.focus.auto_control = new_state->focus.auto_control; + state.focus.value = new_state->focus.value; + state.focus.max = new_state->focus.max; + state.focus.manual = new_state->focus.manual; state.has_auto_focus_continuous = new_state->has_auto_focus_continuous; @@ -140,10 +173,6 @@ update_state(const mp_state_main *new_state) state.preview_buffer_width = new_state->preview_buffer_width; 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; } @@ -785,8 +814,8 @@ open_controls(GtkWidget *parent, static void set_gain(double value) { - if (state.gain != (int)value) { - state.gain = (int)value; + if (state.gain.value != (int)value) { + state.gain.value_req = (int)value; update_io_pipeline(); } } @@ -794,8 +823,8 @@ set_gain(double value) static void set_gain_auto(bool is_auto) { - if (state.gain_is_manual != !is_auto) { - state.gain_is_manual = !is_auto; + if (state.gain.manual != !is_auto) { + state.gain.manual_req = !is_auto; update_io_pipeline(); } } @@ -806,9 +835,9 @@ open_iso_controls(GtkWidget *button, gpointer user_data) open_controls(button, "ISO", 0, - state.gain_max, - state.gain, - !state.gain_is_manual, + state.gain.max, + state.gain.value, + !state.gain.manual, set_gain, set_gain_auto); } @@ -816,21 +845,18 @@ open_iso_controls(GtkWidget *button, gpointer user_data) static void set_shutter(double value) { - // TODO: Implement shutter in libmegapixels - /* - int new_exposure = (int)(value / 360.0 * camera->capture_mode.height); - if (new_exposure != exposure) { - exposure = new_exposure; + int new_exposure = (int)(value / 360.0 * state.camera->current_mode->height); + if (new_exposure != state.exposure.value) { + state.exposure.value_req = new_exposure; update_io_pipeline(); } - */ } static void set_shutter_auto(bool is_auto) { - if (state.exposure_is_manual != !is_auto) { - state.exposure_is_manual = !is_auto; + if (state.exposure.manual != !is_auto) { + state.exposure.manual_req = !is_auto; update_io_pipeline(); } } @@ -838,12 +864,14 @@ set_shutter_auto(bool is_auto) static void open_shutter_controls(GtkWidget *button, gpointer user_data) { + float value = + ((float)state.exposure.value / (float)state.exposure.max) * 360.0f; open_controls(button, "Shutter", 1.0, 360.0, - state.exposure, - !state.exposure_is_manual, + value, + !state.exposure.manual, set_shutter, set_shutter_auto); } diff --git a/src/process_pipeline.c b/src/process_pipeline.c index e498f56..aa375e3 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -460,7 +460,7 @@ process_image_for_preview(const uint8_t *image) mp_process_pipeline_buffer_ref(output_buffer); mp_main_set_preview(output_buffer); - if (!state_proc.exposure.manual) { + if (!state_proc.exposure.manual && state_proc.exposure.auto_control == 0) { int width = output_buffer_width / 3; int height = output_buffer_height / 3; uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1); @@ -473,9 +473,6 @@ process_image_for_preview(const uint8_t *image) center); libmegapixels_aaa_software_statistics( center, width, height, &state_proc.stats); - printf("STAT: %d %d\n", - state_proc.stats.exposure, - state_proc.stats.whitebalance); } // Create a thumbnail from the preview for the last capture @@ -961,16 +958,19 @@ update_state(MPPipeline *pipeline, const mp_state_proc *new_state) state_proc.camera = new_state->camera; state_proc.gain.control = new_state->gain.control; + state_proc.gain.auto_control = new_state->gain.auto_control; state_proc.gain.value = new_state->gain.value; state_proc.gain.max = new_state->gain.max; state_proc.gain.manual = new_state->gain.manual; state_proc.exposure.control = new_state->exposure.control; + state_proc.exposure.auto_control = new_state->exposure.auto_control; state_proc.exposure.value = new_state->exposure.value; state_proc.exposure.max = new_state->exposure.max; state_proc.exposure.manual = new_state->exposure.manual; state_proc.focus.control = new_state->focus.control; + state_proc.focus.auto_control = new_state->focus.auto_control; state_proc.focus.value = new_state->focus.value; state_proc.focus.max = new_state->focus.max; state_proc.focus.manual = new_state->focus.manual; @@ -1010,19 +1010,29 @@ update_state(MPPipeline *pipeline, const mp_state_proc *new_state) mp_state_main new_main = { .camera = pr_camera, - .gain_is_manual = new_state->gain.manual, - .gain = state_proc.gain.value, - .gain_max = state_proc.gain.max, - .exposure_is_manual = state_proc.exposure.manual, - .exposure = state_proc.exposure.value, .has_auto_focus_continuous = false, .has_auto_focus_start = false, .preview_buffer_width = output_buffer_width, .preview_buffer_height = output_buffer_height, - .control_gain = new_state->gain.control != 0, - .control_exposure = state_proc.exposure.control != 0, - .control_focus = state_proc.focus.control != 0, .control_flash = false, + + .gain.control = state_proc.gain.control, + .gain.auto_control = state_proc.gain.auto_control, + .gain.value = state_proc.gain.value, + .gain.max = state_proc.gain.max, + .gain.manual = state_proc.gain.manual, + + .exposure.control = state_proc.exposure.control, + .exposure.auto_control = state_proc.exposure.auto_control, + .exposure.value = state_proc.exposure.value, + .exposure.max = state_proc.exposure.max, + .exposure.manual = state_proc.exposure.manual, + + .focus.control = state_proc.focus.control, + .focus.auto_control = state_proc.focus.auto_control, + .focus.value = state_proc.focus.value, + .focus.max = state_proc.focus.max, + .focus.manual = state_proc.focus.manual, }; mp_main_update_state(&new_main); } diff --git a/src/state.h b/src/state.h index eec4908..9d4d1a2 100644 --- a/src/state.h +++ b/src/state.h @@ -2,9 +2,20 @@ #include #include +typedef struct cstate { + uint32_t control; + int32_t value; + int32_t value_req; + int32_t max; + bool manual; + bool manual_req; + uint32_t auto_control; +} controlstate; + typedef struct state_main { libmegapixels_devconfig *configuration; libmegapixels_camera *camera; + libmegapixels_aaa_stats stats; // Size of the preview widget int preview_width; @@ -19,38 +30,22 @@ typedef struct state_main { int burst_length; // Control state - bool control_gain; - bool control_exposure; bool control_flash; - bool control_focus; - - bool gain_is_manual; - int gain; - int gain_max; - - bool exposure_is_manual; - int exposure; - bool flash_enabled; + controlstate gain; + controlstate exposure; + controlstate focus; bool has_auto_focus_continuous; bool has_auto_focus_start; } 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_devconfig *configuration; libmegapixels_camera *camera; libmegapixels_mode *mode_capture; libmegapixels_mode *mode_preview; + libmegapixels_aaa_stats stats; int burst_length; int captures_remaining;