Skip to content

Commit

Permalink
Add support for autofocus
Browse files Browse the repository at this point in the history
  • Loading branch information
iizukanao committed Jan 30, 2023
1 parent aae533b commit 1dcad16
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
41 changes: 41 additions & 0 deletions libpicam/picam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,37 @@ int Picam::camera_set_sharpness() {
return 0;
}

int Picam::camera_set_autofocus_mode(char *mode) {
if (camera_->controls().count(&libcamera::controls::AfMode) == 0) {
// When we try to set the AF Mode on a camera that does not support AF, libcamera crashes.
log_debug("skipping autofocus because it is not supported by the camera\n");
return 0;
}

libcamera::controls::AfModeEnum af_mode = libcamera::controls::AfModeContinuous;
for (unsigned int i = 0; i < sizeof(video_autofocus_mode_options) / sizeof(video_autofocus_mode_option); i++) {
if (strcmp(video_autofocus_mode_options[i].name, mode) == 0) {
af_mode = video_autofocus_mode_options[i].af_mode;
break;
}
}
log_debug("camera_set_autofocus_mode: %s\n", mode);
controls_.set(libcamera::controls::AfMode, af_mode);
return 0;
}

int Picam::camera_set_lens_position() {
if (this->option->video_lens_position != -1.0f) {
if (camera_->controls().count(&libcamera::controls::LensPosition) == 0) {
log_debug("skipping lens position because it is not supported by the camera\n");
return 0;
}
log_debug("camera_set_lens_position: %f\n", this->option->video_lens_position);
controls_.set(libcamera::controls::LensPosition, this->option->video_lens_position);
}
return 0;
}

/**
* Reads a file and returns the contents.
* file_contents argument will be set to the pointer to the
Expand Down Expand Up @@ -2098,6 +2129,16 @@ void Picam::StartCamera()
exit(EXIT_FAILURE);
}

// Auto focus mode
if (this->camera_set_autofocus_mode(this->option->video_autofocus_mode) != 0) {
exit(EXIT_FAILURE);
}

// Lens position for manual focus mode
if (this->camera_set_lens_position() != 0) {
exit(EXIT_FAILURE);
}

if (camera_->start(&controls_))
throw std::runtime_error("failed to start camera");
controls_.clear();
Expand Down
2 changes: 2 additions & 0 deletions libpicam/picam.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ class Picam {
int camera_set_contrast();
int camera_set_saturation();
int camera_set_sharpness();
int camera_set_autofocus_mode(char *mode);
int camera_set_lens_position();

// >>> libcamera_app.hpp
template <typename T>
Expand Down
50 changes: 46 additions & 4 deletions picam_option/picam_option.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ void PicamOption::print_usage() {
// log_info(" --blank[=0xAARRGGBB] Set the video background color to black (or optional ARGB value)\n");
log_info(" --query Query camera capabilities then exit\n");
// log_info(" --mode Specify the camera sensor mode (values depend on the camera hardware)\n");
log_info(" [autofocus] (available on Camera Module 3)\n");
log_info(" --autofocus-mode <mode> AF (autofocus) algorithm. <mode> is one of:\n");
log_info(" continuous: Continuous autofocus (default)\n");
log_info(" manual: Manual mode\n");
log_info(" --lens-position <num> Move lens to the reciprocal of the focal distance in\n");
log_info(" meters, also known as diopters. Implies \"--autofocus-mode manual\".\n");
log_info(" To focus on objects 2m away, use 0.5 (1m / 0.5 = 2m).\n");
log_info(" To focus on objects 25cm away, use 4 (1m / 4 = 0.25m).\n");
log_info(" Use 0 for maximum focus distance.\n");
log_info(" [timestamp] (may be a bit heavy on Raspberry Pi 1)\n");
log_info(" --time Enable timestamp\n");
log_info(" --timeformat <spec> Timestamp format (see \"man strftime\" for spec)\n");
Expand Down Expand Up @@ -278,6 +287,8 @@ int PicamOption::parse(int argc, char **argv) {
{ "contrast", required_argument, NULL, 0 },
{ "saturation", required_argument, NULL, 0 },
{ "sharpness", required_argument, NULL, 0 },
{ "autofocus-mode", required_argument, NULL, 0 },
{ "lens-position", required_argument, NULL, 0 },
{ 0, 0, 0, 0 },
};
int option_index = 0;
Expand Down Expand Up @@ -984,38 +995,67 @@ int PicamOption::parse(int argc, char **argv) {
} else if (strcmp(long_options[option_index].name, "help") == 0) {
this->show_help = true;
return 0;
} else if (strcmp(long_options[option_index].name, "brightness") == 0) {
} else if (strcmp(long_options[option_index].name, "brightness") == 0) {
char *end;
double value = strtod(optarg, &end);
if (end == optarg || *end != '\0' || errno == ERANGE) { // parse error
log_fatal("error: invalid --brightness: %s\n", optarg);
return EXIT_FAILURE;
}
video_brightness = value;
} else if (strcmp(long_options[option_index].name, "contrast") == 0) {
} else if (strcmp(long_options[option_index].name, "contrast") == 0) {
char *end;
double value = strtod(optarg, &end);
if (end == optarg || *end != '\0' || errno == ERANGE) { // parse error
log_fatal("error: invalid --contrast: %s\n", optarg);
return EXIT_FAILURE;
}
video_contrast = value;
} else if (strcmp(long_options[option_index].name, "saturation") == 0) {
} else if (strcmp(long_options[option_index].name, "saturation") == 0) {
char *end;
double value = strtod(optarg, &end);
if (end == optarg || *end != '\0' || errno == ERANGE) { // parse error
log_fatal("error: invalid --saturation: %s\n", optarg);
return EXIT_FAILURE;
}
video_saturation = value;
}else if (strcmp(long_options[option_index].name, "sharpness") == 0) {
} else if (strcmp(long_options[option_index].name, "sharpness") == 0) {
char *end;
double value = strtod(optarg, &end);
if (end == optarg || *end != '\0' || errno == ERANGE) { // parse error
log_fatal("error: invalid --sharpness: %s\n", optarg);
return EXIT_FAILURE;
}
video_sharpness = value;
} else if (strcmp(long_options[option_index].name, "autofocus-mode") == 0) {
strncpy(video_autofocus_mode, optarg, sizeof(video_autofocus_mode) - 1);
video_autofocus_mode[sizeof(video_autofocus_mode) - 1] = '\0';
int matched = 0;
unsigned int i;
for (i = 0; i < sizeof(video_autofocus_mode_options) / sizeof(video_autofocus_mode_option); i++) {
if (strcmp(video_autofocus_mode_options[i].name, video_autofocus_mode) == 0) {
matched = 1;
break;
}
}
if (!matched) {
log_fatal("error: invalid autofocus-mode: %s\n", optarg);
return EXIT_FAILURE;
}
} else if (strcmp(long_options[option_index].name, "lens-position") == 0) {
char *end;
double value = strtod(optarg, &end);
if (end == optarg || *end != '\0' || errno == ERANGE) { // parse error
log_fatal("error: invalid --lens-position: %s\n", optarg);
return EXIT_FAILURE;
}
if (value < 0.0f) {
log_fatal("error: --lens-position must be greater than or equal to 0");
return EXIT_FAILURE;
}
video_lens_position = value;
strncpy(video_autofocus_mode, "manual", sizeof(video_autofocus_mode) - 1);
video_autofocus_mode[sizeof(video_autofocus_mode) - 1] = '\0';
}
break;
case 'w':
Expand Down Expand Up @@ -1205,6 +1245,8 @@ int PicamOption::parse(int argc, char **argv) {
log_debug("video_contrast=%d\n", video_contrast);
log_debug("video_saturation=%d\n", video_saturation);
log_debug("video_sharpness=%d\n", video_sharpness);
log_debug("video_autofocus_mode=%s\n", video_autofocus_mode);
log_debug("video_lens_position=%f\n", video_lens_position);
log_debug("alsa_dev=%s\n", alsa_dev);
log_debug("audio_channels=%d\n", audio_channels);
log_debug("audio_sample_rate=%d\n", audio_sample_rate);
Expand Down
15 changes: 15 additions & 0 deletions picam_option/picam_option.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ const video_avc_level_option video_avc_level_options[] = {
// Level >= 5.0 is not supported by the encoder
};

typedef struct video_autofocus_mode_option {
const char *name;
libcamera::controls::AfModeEnum af_mode;
} video_autofocus_mode_option;
const video_autofocus_mode_option video_autofocus_mode_options[] = {
{ "manual", libcamera::controls::AfModeManual },
{ "continuous", libcamera::controls::AfModeContinuous },
};

class PicamOption
{
public:
Expand Down Expand Up @@ -188,6 +197,12 @@ class PicamOption
// 0.0 means no sharpening
float video_sharpness = 0.0f;

// The default is to initiate autofocus at any moment
char video_autofocus_mode[11] = "continuous";

// -1.0f means lens position is not specified.
float video_lens_position = -1.0f;

char state_dir[256] = "state";
char hooks_dir[256] = "hooks";
float audio_volume_multiply = 1.0f;
Expand Down

0 comments on commit 1dcad16

Please sign in to comment.