|
@@ -374,6 +374,95 @@ clamp_control(controlstate *control)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int focus;
|
|
|
+static int focus_phase;
|
|
|
+
|
|
|
+static void auto_focus_start(void)
|
|
|
+{
|
|
|
+ focus_phase = 0;
|
|
|
+ focus = 0;
|
|
|
+}
|
|
|
+
|
|
|
+struct focus_stats {
|
|
|
+ unsigned long long sharp;
|
|
|
+};
|
|
|
+
|
|
|
+#define PH_SWEEP 5
|
|
|
+#define PH_DONE 6
|
|
|
+
|
|
|
+static void auto_focus_step(const struct focus_stats *stats)
|
|
|
+{
|
|
|
+ static uint64_t best_sharp, best_focus;
|
|
|
+ static const bool debug = true;
|
|
|
+
|
|
|
+ if (debug) printf("Phase %d, sharp %d best %d ", focus_phase, (int)(stats->sharp / 10000), (int)(best_sharp/ 10000));
|
|
|
+ if (focus_phase >= PH_DONE) {
|
|
|
+ focus_phase++;
|
|
|
+ if (stats->sharp < (best_sharp * 6) / 10) {
|
|
|
+ if (debug) printf("Lost, restart.\n");
|
|
|
+ auto_focus_start();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (debug) printf("Idle @ %d.\n", focus);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (focus_phase < PH_SWEEP) {
|
|
|
+ best_sharp = 0;
|
|
|
+ focus = 200;
|
|
|
+ focus_phase ++;
|
|
|
+ best_focus = 0;
|
|
|
+ if (debug) printf("...prepare\n");
|
|
|
+ goto set;
|
|
|
+ }
|
|
|
+ if (stats->sharp > best_sharp) {
|
|
|
+ if (debug) printf("Still improving, focus %d\n", focus);
|
|
|
+ best_focus = focus;
|
|
|
+ best_sharp = stats->sharp;
|
|
|
+ focus += 10;
|
|
|
+ goto set;
|
|
|
+ }
|
|
|
+ if (stats->sharp < (best_sharp * 8) / 10) {
|
|
|
+ if (debug) printf("AF done?\n");
|
|
|
+ focus = best_focus - 10;
|
|
|
+ focus_phase = PH_DONE;
|
|
|
+ goto set;
|
|
|
+ }
|
|
|
+ if (focus > 1023) {
|
|
|
+ if (debug) printf("Finished range\n");
|
|
|
+ focus = best_focus - 10;
|
|
|
+ focus_phase = PH_DONE;
|
|
|
+ goto set;
|
|
|
+ }
|
|
|
+ if (debug) printf("Not improving\n");
|
|
|
+ focus += 10;
|
|
|
+ set:
|
|
|
+ state_proc.focus.value_req = focus;
|
|
|
+ clamp_control(&state_proc.focus);
|
|
|
+ mp_io_pipeline_set_control_int32(&state_proc.focus.control,
|
|
|
+ state_proc.focus.value_req);
|
|
|
+ state_proc.focus.value = state_proc.focus.value_req;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+focus_stats(struct focus_stats *stats, const unsigned int *frame, const int width,
|
|
|
+ const int height)
|
|
|
+{
|
|
|
+ unsigned long long sharp = 0;
|
|
|
+ unsigned int last_y = 0;
|
|
|
+
|
|
|
+ for (ssize_t p = 0; p < width * height; p++) {
|
|
|
+ unsigned int r = (frame[p] >> 0) & 0xff;
|
|
|
+ unsigned int g = (frame[p] >> 8) & 0xff;
|
|
|
+ unsigned int b = (frame[p] >> 16) & 0xff;
|
|
|
+ unsigned int y = (r + g + b) / 3;
|
|
|
+
|
|
|
+ sharp += (y-last_y) * (y-last_y);
|
|
|
+
|
|
|
+ last_y = y;
|
|
|
+ }
|
|
|
+ stats->sharp = sharp;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
process_aaa()
|
|
|
{
|
|
@@ -400,6 +489,12 @@ process_aaa()
|
|
|
state_proc.blacklevel -= (float)state_proc.stats.blacklevel * 0.001f;
|
|
|
state_proc.blacklevel = clamp_float(state_proc.blacklevel, 0.0f, 0.07f);
|
|
|
|
|
|
+ if (auto_focus) {
|
|
|
+ struct focus_stats stats;
|
|
|
+ focus_stats(&stats, center, width, height);
|
|
|
+ auto_focus_step(&stats);
|
|
|
+ }
|
|
|
+
|
|
|
if (auto_exposure) {
|
|
|
int direction = state_proc.stats.exposure;
|
|
|
int step = 0;
|