|
@@ -39,6 +39,7 @@ static int output_buffer_width = -1;
|
|
static int output_buffer_height = -1;
|
|
static int output_buffer_height = -1;
|
|
|
|
|
|
static bool flash_enabled;
|
|
static bool flash_enabled;
|
|
|
|
+static int framecounter = 0;
|
|
|
|
|
|
static char capture_fname[255];
|
|
static char capture_fname[255];
|
|
|
|
|
|
@@ -154,6 +155,10 @@ setup(MPPipeline *pipeline, const void *data)
|
|
libdng_init();
|
|
libdng_init();
|
|
settings = g_settings_new(APP_ID);
|
|
settings = g_settings_new(APP_ID);
|
|
prctl(PR_SET_NAME, "megapixels-pr", NULL, NULL, NULL);
|
|
prctl(PR_SET_NAME, "megapixels-pr", NULL, NULL, NULL);
|
|
|
|
+
|
|
|
|
+ state_proc.mode_balance = AAA_BY_POST;
|
|
|
|
+ state_proc.mode_exposure = AAA_BY_V4L2_CONTROLS;
|
|
|
|
+ state_proc.mode_focus = AAA_DISABLED;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
void
|
|
@@ -340,6 +345,122 @@ clamp_float(float value, float min, float max)
|
|
return value;
|
|
return value;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+clamp_control(controlstate *control)
|
|
|
|
+{
|
|
|
|
+ if (control->value_req > control->max) {
|
|
|
|
+ control->value_req = control->max;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+process_aaa()
|
|
|
|
+{
|
|
|
|
+ bool auto_exposure =
|
|
|
|
+ !state_proc.exposure.manual && state_proc.exposure.auto_control == 0;
|
|
|
|
+ bool auto_focus =
|
|
|
|
+ !state_proc.focus.manual && state_proc.focus.auto_control == 0;
|
|
|
|
+ bool auto_balance = TRUE;
|
|
|
|
+ if (!auto_exposure && !auto_focus && !auto_balance) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int width = output_buffer_width;
|
|
|
|
+ int height = output_buffer_height / 3;
|
|
|
|
+ uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1);
|
|
|
|
+ glReadPixels(0, height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, center);
|
|
|
|
+
|
|
|
|
+ libmegapixels_aaa_set_matrix(&state_proc.stats,
|
|
|
|
+ state_proc.calibration.color_matrix_1,
|
|
|
|
+ state_proc.calibration.color_matrix_2);
|
|
|
|
+ libmegapixels_aaa_software_statistics(
|
|
|
|
+ &state_proc.stats, center, width, height);
|
|
|
|
+
|
|
|
|
+ state_proc.blacklevel -= (float)state_proc.stats.blacklevel * 0.001f;
|
|
|
|
+ state_proc.blacklevel = clamp_float(state_proc.blacklevel, 0.0f, 0.07f);
|
|
|
|
+
|
|
|
|
+ if (auto_exposure) {
|
|
|
|
+ int direction = state_proc.stats.exposure;
|
|
|
|
+ int step = 0;
|
|
|
|
+ if (direction > 0) {
|
|
|
|
+ // Preview is too dark
|
|
|
|
+
|
|
|
|
+ // Try raising the exposure time first
|
|
|
|
+ if (state_proc.exposure.value < state_proc.exposure.max) {
|
|
|
|
+ step = state_proc.exposure.value / 4;
|
|
|
|
+ step = step < 4 ? 4 : step;
|
|
|
|
+ state_proc.exposure.value_req =
|
|
|
|
+ state_proc.exposure.value +
|
|
|
|
+ (step * direction);
|
|
|
|
+ printf("Expose + %d\n",
|
|
|
|
+ state_proc.exposure.value_req);
|
|
|
|
+ } else {
|
|
|
|
+ // Raise sensor gain if exposure limit is hit
|
|
|
|
+ step = state_proc.gain.value / 4;
|
|
|
|
+ step = step < 4 ? 4 : step;
|
|
|
|
+ state_proc.gain.value_req =
|
|
|
|
+ state_proc.gain.value + (step * direction);
|
|
|
|
+ printf("Gain + %d\n", state_proc.gain.value_req);
|
|
|
|
+ }
|
|
|
|
+ } else if (direction < 0) {
|
|
|
|
+ // Preview is too bright
|
|
|
|
+
|
|
|
|
+ // Lower the sensor gain first to have less noise
|
|
|
|
+ if (state_proc.gain.value > 0) {
|
|
|
|
+ step = state_proc.gain.value / 4;
|
|
|
|
+ state_proc.gain.value_req =
|
|
|
|
+ state_proc.gain.value + (step * direction);
|
|
|
|
+ printf("Gain - %d\n", state_proc.gain.value_req);
|
|
|
|
+ } else {
|
|
|
|
+ // Shorten the exposure time to go even darker
|
|
|
|
+ step = state_proc.exposure.value / 4;
|
|
|
|
+ state_proc.exposure.value_req =
|
|
|
|
+ state_proc.exposure.value +
|
|
|
|
+ (step * direction);
|
|
|
|
+ printf("Expose - %d\n",
|
|
|
|
+ state_proc.exposure.value_req);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clamp_control(&state_proc.gain);
|
|
|
|
+ clamp_control(&state_proc.exposure);
|
|
|
|
+ mp_io_pipeline_set_control_int32(state_proc.gain.control,
|
|
|
|
+ state_proc.gain.value_req);
|
|
|
|
+ mp_io_pipeline_set_control_int32(state_proc.exposure.control,
|
|
|
|
+ state_proc.exposure.value_req);
|
|
|
|
+ state_proc.gain.value = state_proc.gain.value_req;
|
|
|
|
+ state_proc.exposure.value = state_proc.exposure.value_req;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (auto_balance) {
|
|
|
|
+ float r = state_proc.stats.avg_r;
|
|
|
|
+ float g = state_proc.stats.avg_g;
|
|
|
|
+ float b = state_proc.stats.avg_b;
|
|
|
|
+
|
|
|
|
+ // Revert the current gains set on the preview
|
|
|
|
+ b /= state_proc.red;
|
|
|
|
+ b /= state_proc.blue;
|
|
|
|
+
|
|
|
|
+ float t = 2.0f;
|
|
|
|
+ if (r < t && g < t && b < t) {
|
|
|
|
+ // Don't try to AWB on very dark frames
|
|
|
|
+ } else {
|
|
|
|
+ // Calculate the new R/B gains based on the average color of
|
|
|
|
+ // the frame
|
|
|
|
+ float new_r = g / clamp_float(r, 1.0f, 999.0f);
|
|
|
|
+ float new_b = g / clamp_float(b, 1.0f, 999.0f);
|
|
|
|
+
|
|
|
|
+ state_proc.red = clamp_float(new_r, 0.01f, 4.0f);
|
|
|
|
+ state_proc.blue = clamp_float(new_b, 0.01f, 4.0f);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ gles2_debayer_set_shading(gles2_debayer,
|
|
|
|
+ state_proc.red,
|
|
|
|
+ state_proc.blue,
|
|
|
|
+ state_proc.blacklevel);
|
|
|
|
+}
|
|
|
|
+
|
|
static GdkTexture *
|
|
static GdkTexture *
|
|
process_image_for_preview(const uint8_t *image)
|
|
process_image_for_preview(const uint8_t *image)
|
|
{
|
|
{
|
|
@@ -412,48 +533,9 @@ process_image_for_preview(const uint8_t *image)
|
|
mp_process_pipeline_buffer_ref(output_buffer);
|
|
mp_process_pipeline_buffer_ref(output_buffer);
|
|
mp_main_set_preview(output_buffer);
|
|
mp_main_set_preview(output_buffer);
|
|
|
|
|
|
- if (!state_proc.exposure.manual && state_proc.exposure.auto_control == 0) {
|
|
|
|
- int width = output_buffer_width;
|
|
|
|
- int height = output_buffer_height / 3;
|
|
|
|
- uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1);
|
|
|
|
- glReadPixels(
|
|
|
|
- 0, height, width, height, GL_RGBA, GL_UNSIGNED_BYTE, center);
|
|
|
|
-
|
|
|
|
- libmegapixels_aaa_set_matrix(&state_proc.stats,
|
|
|
|
- state_proc.calibration.color_matrix_1,
|
|
|
|
- state_proc.calibration.color_matrix_2);
|
|
|
|
- libmegapixels_aaa_software_statistics(
|
|
|
|
- &state_proc.stats, center, width, height);
|
|
|
|
-
|
|
|
|
- state_proc.blacklevel -= (float)state_proc.stats.blacklevel * 0.001f;
|
|
|
|
- state_proc.blacklevel =
|
|
|
|
- clamp_float(state_proc.blacklevel, 0.0f, 0.07f);
|
|
|
|
-
|
|
|
|
- float r = state_proc.stats.avg_r;
|
|
|
|
- float g = state_proc.stats.avg_g;
|
|
|
|
- float b = state_proc.stats.avg_b;
|
|
|
|
-
|
|
|
|
- // Revert the current gains set on the preview
|
|
|
|
- b /= state_proc.red;
|
|
|
|
- b /= state_proc.blue;
|
|
|
|
-
|
|
|
|
- float t = 2.0f;
|
|
|
|
- if (r < t && g < t && b < t) {
|
|
|
|
- // Don't try to AWB on very dark frames
|
|
|
|
- } else {
|
|
|
|
- // Calculate the new R/B gains based on the average color of
|
|
|
|
- // the frame
|
|
|
|
- float new_r = g / clamp_float(r, 1.0f, 999.0f);
|
|
|
|
- float new_b = g / clamp_float(b, 1.0f, 999.0f);
|
|
|
|
-
|
|
|
|
- state_proc.red = clamp_float(new_r, 0.01f, 4.0f);
|
|
|
|
- state_proc.blue = clamp_float(new_b, 0.01f, 4.0f);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- gles2_debayer_set_shading(gles2_debayer,
|
|
|
|
- state_proc.red,
|
|
|
|
- state_proc.blue,
|
|
|
|
- state_proc.blacklevel);
|
|
|
|
|
|
+ if (framecounter++ == 2) {
|
|
|
|
+ framecounter = 0;
|
|
|
|
+ process_aaa();
|
|
}
|
|
}
|
|
|
|
|
|
// Create a thumbnail from the preview for the last capture
|
|
// Create a thumbnail from the preview for the last capture
|
|
@@ -1022,12 +1104,14 @@ update_state(MPPipeline *pipeline, const mp_state_proc *new_state)
|
|
.gain.control = state_proc.gain.control,
|
|
.gain.control = state_proc.gain.control,
|
|
.gain.auto_control = state_proc.gain.auto_control,
|
|
.gain.auto_control = state_proc.gain.auto_control,
|
|
.gain.value = state_proc.gain.value,
|
|
.gain.value = state_proc.gain.value,
|
|
|
|
+ .gain.value_req = state_proc.gain.value_req,
|
|
.gain.max = state_proc.gain.max,
|
|
.gain.max = state_proc.gain.max,
|
|
.gain.manual = state_proc.gain.manual,
|
|
.gain.manual = state_proc.gain.manual,
|
|
|
|
|
|
.exposure.control = state_proc.exposure.control,
|
|
.exposure.control = state_proc.exposure.control,
|
|
.exposure.auto_control = state_proc.exposure.auto_control,
|
|
.exposure.auto_control = state_proc.exposure.auto_control,
|
|
.exposure.value = state_proc.exposure.value,
|
|
.exposure.value = state_proc.exposure.value,
|
|
|
|
+ .exposure.value_req = state_proc.exposure.value_req,
|
|
.exposure.max = state_proc.exposure.max,
|
|
.exposure.max = state_proc.exposure.max,
|
|
.exposure.manual = state_proc.exposure.manual,
|
|
.exposure.manual = state_proc.exposure.manual,
|
|
|
|
|