From ba09044961948d93db7aa166f2829d46e81e875a Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 14 Feb 2014 17:12:08 +0000 Subject: [PATCH 173/174] V4L2: Initial pass at scene modes. Only supports exposure mode and metering modes. Signed-off-by: Dave Stevenson --- drivers/media/platform/bcm2835/bcm2835-camera.h | 10 +- drivers/media/platform/bcm2835/controls.c | 225 ++++++++++++++++++++---- 2 files changed, 199 insertions(+), 36 deletions(-) --- a/drivers/media/platform/bcm2835/bcm2835-camera.h +++ b/drivers/media/platform/bcm2835/bcm2835-camera.h @@ -15,7 +15,7 @@ * core driver device */ -#define V4L2_CTRL_COUNT 24 /* number of v4l controls */ +#define V4L2_CTRL_COUNT 25 /* number of v4l controls */ enum { MMAL_COMPONENT_CAMERA = 0, @@ -45,11 +45,15 @@ struct bm2835_mmal_dev { /* controls */ struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT]; + enum v4l2_scene_mode scene_mode; struct mmal_colourfx colourfx; int hflip; int vflip; - enum mmal_parameter_exposuremode exposure_mode; - enum v4l2_exposure_auto_type exposure_mode_v4l2; + enum mmal_parameter_exposuremode exposure_mode_user; + enum v4l2_exposure_auto_type exposure_mode_v4l2_user; + /* active exposure mode may differ if selected via a scene mode */ + enum mmal_parameter_exposuremode exposure_mode_active; + enum mmal_parameter_exposuremeteringmode metering_mode; unsigned int manual_shutter_speed; bool exp_auto_priority; --- a/drivers/media/platform/bcm2835/controls.c +++ b/drivers/media/platform/bcm2835/controls.c @@ -145,6 +145,25 @@ static const struct v4l2_to_mmal_effects 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} } }; +struct v4l2_mmal_scene_config { + enum v4l2_scene_mode v4l2_scene; + enum mmal_parameter_exposuremode exposure_mode; + enum mmal_parameter_exposuremeteringmode metering_mode; +}; + +static const struct v4l2_mmal_scene_config scene_configs[] = { + /* V4L2_SCENE_MODE_NONE automatically added */ + { + V4L2_SCENE_MODE_NIGHT, + MMAL_PARAM_EXPOSUREMODE_NIGHT, + MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE + }, + { + V4L2_SCENE_MODE_SPORTS, + MMAL_PARAM_EXPOSUREMODE_SPORTS, + MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE + }, +}; /* control handlers*/ @@ -296,7 +315,7 @@ static int ctrl_set_exposure(struct bm28 struct v4l2_ctrl *ctrl, const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) { - enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode; + enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user; u32 shutter_speed = 0; struct vchiq_mmal_port *control; int ret = 0; @@ -317,31 +336,32 @@ static int ctrl_set_exposure(struct bm28 case V4L2_EXPOSURE_MANUAL: exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF; break; - - case V4L2_EXPOSURE_SHUTTER_PRIORITY: - exp_mode = MMAL_PARAM_EXPOSUREMODE_SPORTS; - break; - - case V4L2_EXPOSURE_APERTURE_PRIORITY: - exp_mode = MMAL_PARAM_EXPOSUREMODE_NIGHT; - break; - } - dev->exposure_mode = exp_mode; - dev->exposure_mode_v4l2 = ctrl->val; + dev->exposure_mode_user = exp_mode; + dev->exposure_mode_v4l2_user = ctrl->val; } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) { dev->exp_auto_priority = ctrl->val; } - if (dev->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF) - shutter_speed = dev->manual_shutter_speed; + if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { + if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF) + shutter_speed = dev->manual_shutter_speed; - ret = vchiq_mmal_port_parameter_set(dev->instance, control, - MMAL_PARAMETER_SHUTTER_SPEED, - &shutter_speed, sizeof(shutter_speed)); - ret += vchiq_mmal_port_parameter_set(dev->instance, control, - MMAL_PARAMETER_EXPOSURE_MODE, - &exp_mode, sizeof(u32)); + ret = vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_SHUTTER_SPEED, + &shutter_speed, + sizeof(shutter_speed)); + ret += vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_EXPOSURE_MODE, + &exp_mode, + sizeof(u32)); + dev->exposure_mode_active = exp_mode; + } + /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should + * always apply irrespective of scene mode. + */ ret += set_framerate_params(dev); return ret; @@ -351,35 +371,38 @@ static int ctrl_set_metering_mode(struct struct v4l2_ctrl *ctrl, const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) { - u32 u32_value; - struct vchiq_mmal_port *control; - - control = &dev->component[MMAL_COMPONENT_CAMERA]->control; - switch (ctrl->val) { case V4L2_EXPOSURE_METERING_AVERAGE: - u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; + dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE; break; case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: - u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; + dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT; break; case V4L2_EXPOSURE_METERING_SPOT: - u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; + dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT; break; /* todo matrix weighting not added to Linux API till 3.9 case V4L2_EXPOSURE_METERING_MATRIX: - u32_value = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; + dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX; break; */ } - return vchiq_mmal_port_parameter_set(dev->instance, control, + if (dev->scene_mode == V4L2_SCENE_MODE_NONE) { + struct vchiq_mmal_port *control; + u32 u32_value = dev->metering_mode; + + control = &dev->component[MMAL_COMPONENT_CAMERA]->control; + + return vchiq_mmal_port_parameter_set(dev->instance, control, mmal_ctrl->mmal_id, &u32_value, sizeof(u32_value)); + } else + return 0; } static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev, @@ -738,6 +761,113 @@ static int ctrl_set_video_encode_profile return ret; } +static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev, + struct v4l2_ctrl *ctrl, + const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl) +{ + int ret = 0; + int shutter_speed; + struct vchiq_mmal_port *control; + + v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, + "scene mode selected %d, was %d\n", ctrl->val, + dev->scene_mode); + control = &dev->component[MMAL_COMPONENT_CAMERA]->control; + + if (ctrl->val == dev->scene_mode) + return 0; + + if (ctrl->val == V4L2_SCENE_MODE_NONE) { + /* Restore all user selections */ + dev->scene_mode = V4L2_SCENE_MODE_NONE; + + if (dev->exposure_mode_user == MMAL_PARAM_EXPOSUREMODE_OFF) + shutter_speed = dev->manual_shutter_speed; + else + shutter_speed = 0; + + v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev, + "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n", + __func__, shutter_speed, dev->exposure_mode_user, + dev->metering_mode); + ret = vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_SHUTTER_SPEED, + &shutter_speed, + sizeof(shutter_speed)); + ret += vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_EXPOSURE_MODE, + &dev->exposure_mode_user, + sizeof(u32)); + dev->exposure_mode_active = dev->exposure_mode_user; + ret += vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_EXP_METERING_MODE, + &dev->metering_mode, + sizeof(u32)); + ret += set_framerate_params(dev); + } else { + /* Set up scene mode */ + int i; + const struct v4l2_mmal_scene_config *scene = NULL; + int shutter_speed; + enum mmal_parameter_exposuremode exposure_mode; + enum mmal_parameter_exposuremeteringmode metering_mode; + + for (i = 0; i < ARRAY_SIZE(scene_configs); i++) { + if (scene_configs[i].v4l2_scene == + ctrl->val) { + scene = &scene_configs[i]; + break; + } + } + if (i >= ARRAY_SIZE(scene_configs)) + return -EINVAL; + + /* Set all the values */ + dev->scene_mode = ctrl->val; + + if (scene->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF) + shutter_speed = dev->manual_shutter_speed; + else + shutter_speed = 0; + exposure_mode = scene->exposure_mode; + metering_mode = scene->metering_mode; + + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n", + __func__, shutter_speed, exposure_mode, metering_mode); + + ret = vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_SHUTTER_SPEED, + &shutter_speed, + sizeof(shutter_speed)); + ret += vchiq_mmal_port_parameter_set(dev->instance, + control, + MMAL_PARAMETER_EXPOSURE_MODE, + &exposure_mode, + sizeof(u32)); + dev->exposure_mode_active = exposure_mode; + ret += vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_EXPOSURE_MODE, + &exposure_mode, + sizeof(u32)); + ret += vchiq_mmal_port_parameter_set(dev->instance, control, + MMAL_PARAMETER_EXP_METERING_MODE, + &metering_mode, + sizeof(u32)); + ret += set_framerate_params(dev); + } + if (ret) { + v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, + "%s: Setting scene to %d, ret=%d\n", + __func__, ctrl->val, ret); + ret = -EINVAL; + } + return 0; +} + static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) { struct bm2835_mmal_dev *dev = @@ -973,6 +1103,15 @@ static const struct bm2835_mmal_v4l2_ctr &ctrl_set_video_encode_profile_level, false }, + { + V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU, + -1, /* Min is computed at runtime */ + V4L2_SCENE_MODE_TEXT, + V4L2_SCENE_MODE_NONE, 1, NULL, + MMAL_PARAMETER_PROFILE, + &ctrl_set_scene_mode, + false + }, }; int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) @@ -1000,8 +1139,7 @@ int set_framerate_params(struct bm2835_m struct mmal_parameter_fps_range fps_range; int ret; - if ((dev->exposure_mode_v4l2 == V4L2_EXPOSURE_AUTO || - dev->exposure_mode_v4l2 == V4L2_EXPOSURE_APERTURE_PRIORITY) && + if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) && (dev->exp_auto_priority)) { /* Variable FPS. Define min FPS as 1fps. * Max as max defined FPS. @@ -1049,6 +1187,7 @@ int set_framerate_params(struct bm2835_m return ret; } + int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev, struct v4l2_ctrl_handler *hdl) { @@ -1068,10 +1207,30 @@ int bm2835_mmal_init_controls(struct bm2 break; case MMAL_CONTROL_TYPE_STD_MENU: + { + int mask = ctrl->min; + + if (ctrl->id == V4L2_CID_SCENE_MODE) { + /* Special handling to work out the mask + * value based on the scene_configs array + * at runtime. Reduces the chance of + * mismatches. + */ + int i; + mask = 1<ctrls[c] = v4l2_ctrl_new_std_menu(hdl, &bm2835_mmal_ctrl_ops, ctrl->id, - ctrl->max, ctrl->min, ctrl->def); + ctrl->max, mask, ctrl->def); break; + } case MMAL_CONTROL_TYPE_INT_MENU: dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,