| /**************************************************************************** |
| * drivers/video/v4l2_cap.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <debug.h> |
| #include <stdio.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <poll.h> |
| |
| #include <nuttx/mutex.h> |
| #include <nuttx/video/v4l2_cap.h> |
| #include <nuttx/video/video.h> |
| |
| #include "video_framebuff.h" |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| #define MAX_CAPTURE_FMT (2) |
| #define CAPTURE_FMT_MAIN (0) |
| #define CAPTURE_FMT_SUB (1) |
| |
| #define REMAINING_CAPNUM_INFINITY (-1) |
| |
| /**************************************************************************** |
| * Private Types |
| ****************************************************************************/ |
| |
| enum capture_state_e |
| { |
| CAPTURE_STATE_STREAMOFF = 0, /* Capture trigger event is not received */ |
| CAPTURE_STATE_STREAMON = 1, /* Capture trigger event is received, |
| * but capture is not operated. |
| */ |
| CAPTURE_STATE_CAPTURE = 2, /* On capture */ |
| }; |
| |
| enum capture_state_cause_e |
| { |
| CAUSE_CAPTURE_STOP = 0, /* Stop capture event for capture stream */ |
| CAUSE_CAPTURE_START = 1, /* Start capture event for capture stream */ |
| CAUSE_CAPTURE_DQBUF = 2, /* DQBUF timing for video stream */ |
| CAUSE_STILL_STOP = 3, /* Stop capture event for still stream */ |
| CAUSE_STILL_START = 4, /* Start capture event for still stream */ |
| }; |
| |
| enum capture_waitend_cause_e |
| { |
| WAITEND_CAUSE_CAPTUREDONE = 0, |
| WAITEND_CAUSE_DQCANCEL = 1, |
| WAITEND_CAUSE_STILLSTOP = 2, |
| }; |
| |
| struct video_format_s |
| { |
| uint16_t width; |
| uint16_t height; |
| uint32_t pixelformat; |
| }; |
| |
| typedef struct video_format_s video_format_t; |
| |
| struct capture_wait_capture_s |
| { |
| sem_t dqbuf_wait_flg; |
| |
| /* Save container which capture is done */ |
| |
| FAR vbuf_container_t *done_container; |
| enum capture_waitend_cause_e waitend_cause; |
| }; |
| |
| typedef struct capture_wait_capture_s capture_wait_capture_t; |
| |
| struct capture_type_inf_s |
| { |
| mutex_t lock_state; |
| enum capture_state_e state; |
| int32_t remaining_capnum; |
| capture_wait_capture_t wait_capture; |
| uint8_t nr_fmt; |
| video_format_t fmt[MAX_CAPTURE_FMT]; |
| struct v4l2_rect clip; |
| struct v4l2_fract frame_interval; |
| video_framebuff_t bufinf; |
| FAR uint8_t *bufheap; /* for V4L2_MEMORY_MMAP buffers */ |
| FAR struct pollfd *fds; |
| uint32_t seqnum; |
| }; |
| |
| typedef struct capture_type_inf_s capture_type_inf_t; |
| |
| struct capture_scene_params_s |
| { |
| uint8_t mode; /* enum v4l2_scene_mode */ |
| |
| int32_t brightness; |
| int32_t contrast; |
| int32_t saturation; |
| int32_t hue; |
| bool awb; |
| int32_t red; |
| int32_t blue; |
| int32_t gamma; |
| uint32_t gamma_curve_sz; |
| uint8_t *gamma_curve; |
| int32_t ev; |
| bool hflip_video; |
| bool vflip_video; |
| bool hflip_still; |
| bool vflip_still; |
| int32_t sharpness; |
| enum v4l2_colorfx colorfx; |
| bool auto_brightness; |
| int32_t rotate; |
| enum v4l2_exposure_auto_type ae; |
| int32_t exposure_time; |
| int32_t focus; |
| bool af; |
| int32_t zoom; |
| int32_t iris; |
| enum v4l2_auto_n_preset_white_balance wb; |
| int32_t wdr; |
| bool stabilization; |
| enum v4l2_iso_sensitivity_auto_type iso_auto; |
| int32_t iso; |
| enum v4l2_exposure_metering meter; |
| int32_t spot_pos; |
| int32_t threea_lock; |
| enum v4l2_flash_led_mode led; |
| int32_t jpeg_quality; |
| }; |
| |
| typedef struct capture_scene_params_s capture_scene_params_t; |
| |
| struct capture_parameter_name_s |
| { |
| uint32_t id; |
| const char *name; |
| }; |
| |
| typedef struct capture_parameter_name_s capture_parameter_name_t; |
| |
| struct capture_mng_s |
| { |
| struct v4l2_s v4l2; |
| |
| /* Parameter of capture_initialize() */ |
| |
| mutex_t lock_open_num; |
| uint8_t open_num; |
| capture_type_inf_t capture_inf; |
| capture_type_inf_t still_inf; |
| FAR struct imgdata_s *imgdata; |
| FAR struct imgsensor_s *imgsensor; |
| enum v4l2_scene_mode capture_scene_mode; |
| uint8_t capture_scence_num; |
| FAR capture_scene_params_t *capture_scene_param[V4L2_SCENE_MODE_MAX]; |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| bool unlinked; |
| #endif |
| }; |
| |
| typedef struct capture_mng_s capture_mng_t; |
| |
| /**************************************************************************** |
| * Private Function Prototypes |
| ****************************************************************************/ |
| |
| static FAR capture_type_inf_t * |
| get_capture_type_inf(FAR capture_mng_t *cmng, uint8_t type); |
| static enum capture_state_e |
| estimate_next_capture_state(FAR capture_mng_t *cmng, |
| enum capture_state_cause_e cause); |
| static void change_capture_state(FAR capture_mng_t *cmng, |
| enum capture_state_e next_state); |
| static bool is_taking_still_picture(FAR capture_mng_t *cmng); |
| static bool is_bufsize_sufficient(FAR capture_mng_t *cmng, uint32_t bufsize); |
| static void cleanup_resources(FAR capture_mng_t *cmng); |
| static bool is_sem_waited(FAR sem_t *sem); |
| static int save_scene_param(FAR capture_mng_t *cmng, |
| enum v4l2_scene_mode mode, |
| uint32_t id, |
| FAR struct v4l2_ext_control *control); |
| static int complete_capture(uint8_t err_code, uint32_t datasize, |
| FAR const struct timeval *ts, |
| FAR void *arg); |
| static int validate_frame_setting(FAR capture_mng_t *cmng, |
| enum v4l2_buf_type type, |
| uint8_t nr_fmt, |
| FAR video_format_t *vfmt, |
| FAR struct v4l2_rect *clip, |
| FAR struct v4l2_fract *interval); |
| static size_t get_bufsize(FAR video_format_t *vf); |
| |
| /* ioctl function for each cmds of ioctl */ |
| |
| static int capture_querycap(FAR struct file *filep, |
| FAR struct v4l2_capability *cap); |
| static int capture_g_input(FAR int *num); |
| static int capture_enum_input(FAR struct file *filep, |
| FAR struct v4l2_input *input); |
| static int capture_reqbufs(FAR struct file *filep, |
| FAR struct v4l2_requestbuffers *reqbufs); |
| static int capture_querybuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf); |
| static int capture_qbuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf); |
| static int capture_dqbuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf); |
| static int capture_cancel_dqbuf(FAR struct file *filep, |
| enum v4l2_buf_type type); |
| static int capture_g_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt); |
| static int capture_s_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt); |
| static int capture_try_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt); |
| static int capture_g_parm(FAR struct file *filep, |
| FAR struct v4l2_streamparm *parm); |
| static int capture_s_parm(FAR struct file *filep, |
| FAR struct v4l2_streamparm *parm); |
| static int capture_streamon(FAR struct file *filep, |
| FAR enum v4l2_buf_type *type); |
| static int capture_streamoff(FAR struct file *filep, |
| FAR enum v4l2_buf_type *type); |
| static int capture_do_halfpush(FAR struct file *filep, |
| bool enable); |
| static int capture_takepict_start(FAR struct file *filep, |
| int32_t capture_num); |
| static int capture_takepict_stop(FAR struct file *filep, |
| bool halfpush); |
| static int capture_s_selection(FAR struct file *filep, |
| FAR struct v4l2_selection *clip); |
| static int capture_g_selection(FAR struct file *filep, |
| FAR struct v4l2_selection *clip); |
| static int capture_queryctrl(FAR struct file *filep, |
| FAR struct v4l2_queryctrl *ctrl); |
| static int capture_query_ext_ctrl(FAR struct file *filep, |
| FAR struct v4l2_query_ext_ctrl *ctrl); |
| static int capture_querymenu(FAR struct file *filep, |
| FAR struct v4l2_querymenu *menu); |
| static int capture_g_ctrl(FAR struct file *filep, |
| FAR struct v4l2_control *ctrl); |
| static int capture_s_ctrl(FAR struct file *filep, |
| FAR struct v4l2_control *ctrl); |
| static int capture_g_ext_ctrls(FAR struct file *filep, |
| FAR struct v4l2_ext_controls *ctrls); |
| static int capture_s_ext_ctrls(FAR struct file *filep, |
| FAR struct v4l2_ext_controls *ctrls); |
| static int capture_query_ext_ctrl_scene(FAR struct file *filep, |
| FAR struct v4s_query_ext_ctrl_scene *ctrl); |
| static int capture_querymenu_scene(FAR struct file *filep, |
| FAR struct v4s_querymenu_scene *menu); |
| static int capture_g_ext_ctrls_scene(FAR struct file *filep, |
| FAR struct v4s_ext_controls_scene *ctrls); |
| static int capture_s_ext_ctrls_scene(FAR struct file *filep, |
| FAR struct v4s_ext_controls_scene *ctrls); |
| static int capture_enum_fmt(FAR struct file *filep, |
| FAR struct v4l2_fmtdesc *f); |
| static int capture_enum_frminterval(FAR struct file *filep, |
| FAR struct v4l2_frmivalenum *f); |
| static int capture_enum_frmsize(FAR struct file *filep, |
| FAR struct v4l2_frmsizeenum *f); |
| |
| /* File operations function */ |
| |
| static int capture_open(FAR struct file *filep); |
| static int capture_close(FAR struct file *filep); |
| static int capture_mmap(FAR struct file *filep, |
| FAR struct mm_map_entry_s *map); |
| static int capture_poll(FAR struct file *filep, |
| FAR struct pollfd *fds, bool setup); |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| static int capture_unlink(FAR struct inode *inode); |
| #endif |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| static const struct v4l2_ops_s g_capture_vops = |
| { |
| capture_querycap, /* querycap */ |
| capture_g_input, /* g_input */ |
| capture_enum_input, /* enum_input */ |
| capture_reqbufs, /* reqbufs */ |
| capture_querybuf, /* querybuf */ |
| capture_qbuf, /* qbuf */ |
| capture_dqbuf, /* dqbuf */ |
| capture_cancel_dqbuf, /* cancel_dqbuf */ |
| capture_g_fmt, /* g_fmt */ |
| capture_s_fmt, /* s_fmt */ |
| capture_try_fmt, /* try_fmt */ |
| capture_g_parm, /* g_parm */ |
| capture_s_parm, /* s_parm */ |
| capture_streamon, /* streamon */ |
| capture_streamoff, /* streamoff */ |
| capture_do_halfpush, /* do_halfpush */ |
| capture_takepict_start, /* takepict_start */ |
| capture_takepict_stop, /* takepict_stop */ |
| capture_s_selection, /* s_selection */ |
| capture_g_selection, /* g_selection */ |
| capture_queryctrl, /* queryctrl */ |
| capture_query_ext_ctrl, /* query_ext_ctrl */ |
| capture_querymenu, /* querymenu */ |
| capture_g_ctrl, /* g_ctrl */ |
| capture_s_ctrl, /* s_ctrl */ |
| capture_g_ext_ctrls, /* g_ext_ctrls */ |
| capture_s_ext_ctrls, /* s_ext_ctrls */ |
| capture_query_ext_ctrl_scene, /* query_ext_ctrl_scene */ |
| capture_querymenu_scene, /* querymenu_scene */ |
| capture_g_ext_ctrls_scene, /* g_ext_ctrls_scene */ |
| capture_s_ext_ctrls_scene, /* s_ext_ctrls_scene */ |
| capture_enum_fmt, /* enum_fmt */ |
| capture_enum_frminterval, /* enum_frminterval */ |
| capture_enum_frmsize /* enum_frmsize */ |
| }; |
| |
| static const struct file_operations g_capture_fops = |
| { |
| capture_open, /* open */ |
| capture_close, /* close */ |
| NULL, /* read */ |
| NULL, /* write */ |
| NULL, /* seek */ |
| NULL, /* ioctl */ |
| capture_mmap, /* mmap */ |
| NULL, /* truncate */ |
| capture_poll, /* poll */ |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| capture_unlink, /* unlink */ |
| #endif |
| }; |
| |
| static const capture_parameter_name_t g_capture_parameter_name[] = |
| { |
| { |
| IMGSENSOR_ID_BRIGHTNESS, "Brightness" |
| }, |
| |
| { |
| IMGSENSOR_ID_CONTRAST, "Contrast" |
| }, |
| |
| { |
| IMGSENSOR_ID_SATURATION, "Saturation" |
| }, |
| |
| { |
| IMGSENSOR_ID_HUE, "Hue" |
| }, |
| |
| { |
| IMGSENSOR_ID_AUTO_WHITE_BALANCE, "Automatic white balance" |
| }, |
| |
| { |
| IMGSENSOR_ID_RED_BALANCE, "Red balance" |
| }, |
| |
| { |
| IMGSENSOR_ID_BLUE_BALANCE, "Blue balance" |
| }, |
| |
| { |
| IMGSENSOR_ID_GAMMA, "Gamma value" |
| }, |
| |
| { |
| IMGSENSOR_ID_GAMMA_CURVE, "Gamma adjustment(curve)" |
| }, |
| |
| { |
| IMGSENSOR_ID_EXPOSURE, "Exposure value" |
| }, |
| |
| { |
| IMGSENSOR_ID_HFLIP_VIDEO, "Mirror horizontally(VIDEO)" |
| }, |
| |
| { |
| IMGSENSOR_ID_VFLIP_VIDEO, "Mirror vertically(VIDEO)" |
| }, |
| |
| { |
| IMGSENSOR_ID_HFLIP_STILL, "Mirror horizontally(STILL)" |
| }, |
| |
| { |
| IMGSENSOR_ID_VFLIP_STILL, "Mirror vertically(STILL)" |
| }, |
| |
| { |
| IMGSENSOR_ID_SHARPNESS, "Sharpness" |
| }, |
| |
| { |
| IMGSENSOR_ID_COLOR_KILLER, "Color killer" |
| }, |
| |
| { |
| IMGSENSOR_ID_COLORFX, "Color effect" |
| }, |
| |
| { |
| IMGSENSOR_ID_AUTOBRIGHTNESS, "Auto brightness" |
| }, |
| |
| { |
| IMGSENSOR_ID_ROTATE, "Rotate" |
| }, |
| |
| { |
| IMGSENSOR_ID_EXPOSURE_AUTO, "Auto Exposure" |
| }, |
| |
| { |
| IMGSENSOR_ID_EXPOSURE_ABSOLUTE, "Exposure time(100 usec)" |
| }, |
| |
| { |
| IMGSENSOR_ID_FOCUS_ABSOLUTE, "Focus(absolute value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_FOCUS_RELATIVE, "Focus(relative value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_FOCUS_AUTO, "Continuous Auto Focus" |
| }, |
| |
| { |
| IMGSENSOR_ID_ZOOM_ABSOLUTE, "Zoom(absolute value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_ZOOM_RELATIVE, "Zoom(relative value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_ZOOM_CONTINUOUS, "Continuous zoom" |
| }, |
| |
| { |
| IMGSENSOR_ID_IRIS_ABSOLUTE, "Iris(absolute value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_IRIS_RELATIVE, "Iris(relative value)" |
| }, |
| |
| { |
| IMGSENSOR_ID_AUTO_N_PRESET_WB, "Preset white balance" |
| }, |
| |
| { |
| IMGSENSOR_ID_WIDE_DYNAMIC_RANGE, "Wide dynamic range" |
| }, |
| |
| { |
| IMGSENSOR_ID_IMG_STABILIZATION, "Image stabilization" |
| }, |
| |
| { |
| IMGSENSOR_ID_ISO_SENSITIVITY, "ISO sensitivity" |
| }, |
| |
| { |
| IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, "Automatic ISO sensitivity" |
| }, |
| |
| { |
| IMGSENSOR_ID_EXPOSURE_METERING, "Photometry" |
| }, |
| |
| { |
| IMGSENSOR_ID_SPOT_POSITION, "Spot position" |
| }, |
| |
| { |
| IMGSENSOR_ID_3A_LOCK, "Lock AWB/AE" |
| }, |
| |
| { |
| IMGSENSOR_ID_AUTO_FOCUS_START, "Start single Auto Focus" |
| }, |
| |
| { |
| IMGSENSOR_ID_AUTO_FOCUS_STOP, "Stop single Auto Focus" |
| }, |
| |
| { |
| IMGSENSOR_ID_3A_PARAMETER, "3A parameter" |
| }, |
| |
| { |
| IMGSENSOR_ID_3A_STATUS, "3A status" |
| }, |
| |
| { |
| IMGSENSOR_ID_FLASH_LED_MODE, "LED mode" |
| }, |
| |
| { |
| IMGSENSOR_ID_JPEG_QUALITY, "JPEG compression quality" |
| } |
| }; |
| |
| static FAR struct imgsensor_s **g_capture_registered_sensor = NULL; |
| static size_t g_capture_registered_sensor_num; |
| static FAR struct imgdata_s *g_capture_data = NULL; |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| static FAR capture_type_inf_t * |
| get_capture_type_inf(FAR capture_mng_t *cmng, uint8_t type) |
| { |
| FAR capture_type_inf_t *type_inf; |
| |
| switch (type) |
| { |
| case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
| type_inf = &cmng->capture_inf; |
| break; |
| |
| case V4L2_BUF_TYPE_STILL_CAPTURE: |
| type_inf = &cmng->still_inf; |
| break; |
| |
| default: /* Error case */ |
| type_inf = NULL; |
| break; |
| } |
| |
| return type_inf; |
| } |
| |
| static enum capture_state_e |
| estimate_next_capture_state(FAR capture_mng_t *cmng, |
| enum capture_state_cause_e cause) |
| { |
| enum capture_state_e current_state = cmng->capture_inf.state; |
| |
| switch (cause) |
| { |
| case CAUSE_CAPTURE_STOP: |
| return CAPTURE_STATE_STREAMOFF; |
| |
| case CAUSE_CAPTURE_START: |
| if (is_taking_still_picture(cmng)) |
| { |
| return CAPTURE_STATE_STREAMON; |
| } |
| else |
| { |
| return CAPTURE_STATE_CAPTURE; |
| } |
| |
| case CAUSE_STILL_STOP: |
| if (current_state == CAPTURE_STATE_STREAMON) |
| { |
| return CAPTURE_STATE_CAPTURE; |
| } |
| else |
| { |
| return current_state; |
| } |
| |
| case CAUSE_STILL_START: |
| if (current_state == CAPTURE_STATE_CAPTURE) |
| { |
| return CAPTURE_STATE_STREAMON; |
| } |
| else |
| { |
| return current_state; |
| } |
| |
| case CAUSE_CAPTURE_DQBUF: |
| if (current_state == CAPTURE_STATE_STREAMON && |
| !is_taking_still_picture(cmng)) |
| { |
| return CAPTURE_STATE_CAPTURE; |
| } |
| else |
| { |
| return current_state; |
| } |
| |
| default: |
| return current_state; |
| } |
| } |
| |
| static void convert_to_imgdatafmt(FAR video_format_t *video, |
| FAR imgdata_format_t *data) |
| { |
| ASSERT(video && data); |
| |
| data->width = video->width; |
| data->height = video->height; |
| switch (video->pixelformat) |
| { |
| case V4L2_PIX_FMT_NV12: |
| data->pixelformat = IMGDATA_PIX_FMT_NV12; |
| break; |
| |
| case V4L2_PIX_FMT_YUV420: |
| data->pixelformat = IMGDATA_PIX_FMT_YUV420P; |
| break; |
| |
| case V4L2_PIX_FMT_YUYV: |
| data->pixelformat = IMGDATA_PIX_FMT_YUYV; |
| break; |
| |
| case V4L2_PIX_FMT_UYVY: |
| data->pixelformat = IMGDATA_PIX_FMT_UYVY; |
| break; |
| |
| case V4L2_PIX_FMT_RGB565: |
| data->pixelformat = IMGDATA_PIX_FMT_RGB565; |
| break; |
| |
| case V4L2_PIX_FMT_JPEG: |
| data->pixelformat = IMGDATA_PIX_FMT_JPEG; |
| break; |
| |
| default: /* V4L2_PIX_FMT_JPEG_WITH_SUBIMG */ |
| data->pixelformat = IMGDATA_PIX_FMT_JPEG_WITH_SUBIMG; |
| break; |
| } |
| } |
| |
| static void convert_to_imgsensorfmt(FAR video_format_t *video, |
| FAR imgsensor_format_t *sensor) |
| { |
| ASSERT(video && sensor); |
| |
| sensor->width = video->width; |
| sensor->height = video->height; |
| switch (video->pixelformat) |
| { |
| case V4L2_PIX_FMT_NV12: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_NV12; |
| break; |
| |
| case V4L2_PIX_FMT_YUV420: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_YUV420P; |
| break; |
| |
| case V4L2_PIX_FMT_YUYV: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_YUYV; |
| break; |
| |
| case V4L2_PIX_FMT_UYVY: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_UYVY; |
| break; |
| |
| case V4L2_PIX_FMT_RGB565: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_RGB565; |
| break; |
| |
| case V4L2_PIX_FMT_JPEG: |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_JPEG; |
| break; |
| |
| default: /* V4L2_PIX_FMT_JPEG_WITH_SUBIMG */ |
| sensor->pixelformat = IMGSENSOR_PIX_FMT_JPEG_WITH_SUBIMG; |
| break; |
| } |
| } |
| |
| static void convert_to_imgdatainterval(FAR struct v4l2_fract *video, |
| FAR imgdata_interval_t *data) |
| { |
| ASSERT(video && data); |
| |
| data->numerator = video->numerator; |
| data->denominator = video->denominator; |
| } |
| |
| static void convert_to_imgsensorinterval(FAR struct v4l2_fract *video, |
| FAR imgsensor_interval_t *sensor) |
| { |
| ASSERT(video && sensor); |
| |
| sensor->numerator = video->numerator; |
| sensor->denominator = video->denominator; |
| } |
| |
| static bool is_clipped(FAR struct v4l2_rect *clip) |
| { |
| bool ret = false; |
| |
| if (clip) |
| { |
| if (clip->left != 0 || clip->top != 0 || |
| clip->width != 0 || clip->height != 0) |
| { |
| ret = true; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static void get_clipped_format(uint8_t nr_fmt, |
| FAR video_format_t *fmt, |
| FAR struct v4l2_rect *clip, |
| FAR video_format_t *c_fmt) |
| { |
| DEBUGASSERT(fmt && c_fmt); |
| |
| if (is_clipped(clip)) |
| { |
| c_fmt[CAPTURE_FMT_MAIN].width = clip->width; |
| c_fmt[CAPTURE_FMT_MAIN].height = clip->height; |
| c_fmt[CAPTURE_FMT_MAIN].pixelformat = |
| fmt[CAPTURE_FMT_MAIN].pixelformat; |
| |
| if (nr_fmt > 1) |
| { |
| /* Clipped size of thumbnail is |
| * small as ratio of main size and thumbnail size. |
| */ |
| |
| memcpy(&c_fmt[CAPTURE_FMT_SUB], |
| &fmt[CAPTURE_FMT_SUB], |
| sizeof(video_format_t)); |
| |
| c_fmt[CAPTURE_FMT_SUB].width = |
| (uint32_t)c_fmt[CAPTURE_FMT_SUB].width * |
| clip->width / fmt[CAPTURE_FMT_MAIN].width; |
| |
| c_fmt[CAPTURE_FMT_SUB].height = |
| (uint32_t)c_fmt[CAPTURE_FMT_SUB].height * |
| clip->height / fmt[CAPTURE_FMT_MAIN].height; |
| } |
| } |
| else |
| { |
| memcpy(c_fmt, fmt, nr_fmt * sizeof(video_format_t)); |
| } |
| } |
| |
| static int start_capture(FAR struct capture_mng_s *cmng, |
| enum v4l2_buf_type type, |
| uint8_t nr_fmt, |
| FAR video_format_t *fmt, |
| FAR struct v4l2_rect *clip, |
| FAR struct v4l2_fract *interval, |
| uintptr_t bufaddr, uint32_t bufsize) |
| { |
| video_format_t c_fmt[MAX_CAPTURE_FMT]; |
| imgdata_format_t df[MAX_CAPTURE_FMT]; |
| imgsensor_format_t sf[MAX_CAPTURE_FMT]; |
| imgdata_interval_t di; |
| imgsensor_interval_t si; |
| |
| ASSERT(fmt && interval && cmng->imgsensor && cmng->imgdata); |
| |
| get_clipped_format(nr_fmt, fmt, clip, c_fmt); |
| |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_MAIN], &df[IMGDATA_FMT_MAIN]); |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_SUB], &df[IMGDATA_FMT_SUB]); |
| convert_to_imgdatainterval(interval, &di); |
| convert_to_imgsensorfmt(&fmt[CAPTURE_FMT_MAIN], &sf[IMGSENSOR_FMT_MAIN]); |
| convert_to_imgsensorfmt(&fmt[CAPTURE_FMT_SUB], &sf[IMGSENSOR_FMT_SUB]); |
| convert_to_imgsensorinterval(interval, &si); |
| |
| IMGDATA_SET_BUF(cmng->imgdata, |
| nr_fmt, df, (FAR uint8_t *)bufaddr, bufsize); |
| IMGDATA_START_CAPTURE(cmng->imgdata, |
| nr_fmt, df, &di, complete_capture, cmng); |
| IMGSENSOR_START_CAPTURE(cmng->imgsensor, |
| type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? |
| IMGSENSOR_STREAM_TYPE_VIDEO : IMGSENSOR_STREAM_TYPE_STILL, |
| nr_fmt, sf, &si); |
| return OK; |
| } |
| |
| static void stop_capture(FAR struct capture_mng_s *cmng, |
| enum v4l2_buf_type type) |
| { |
| ASSERT(cmng->imgsensor && cmng->imgdata); |
| |
| IMGDATA_STOP_CAPTURE(cmng->imgdata); |
| IMGSENSOR_STOP_CAPTURE(cmng->imgsensor, |
| type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? |
| IMGSENSOR_STREAM_TYPE_VIDEO : IMGSENSOR_STREAM_TYPE_STILL); |
| } |
| |
| static void change_capture_state(FAR capture_mng_t *cmng, |
| enum capture_state_e next_state) |
| { |
| enum capture_state_e current_state = cmng->capture_inf.state; |
| enum capture_state_e updated_next_state = next_state; |
| |
| if (current_state != CAPTURE_STATE_CAPTURE && |
| next_state == CAPTURE_STATE_CAPTURE) |
| { |
| FAR vbuf_container_t *container = |
| video_framebuff_get_vacant_container(&cmng->capture_inf.bufinf); |
| if (container != NULL) |
| { |
| cmng->capture_inf.seqnum = 0; |
| start_capture(cmng, |
| V4L2_BUF_TYPE_VIDEO_CAPTURE, |
| cmng->capture_inf.nr_fmt, |
| cmng->capture_inf.fmt, |
| &cmng->capture_inf.clip, |
| &cmng->capture_inf.frame_interval, |
| container->buf.m.userptr, |
| container->buf.length); |
| } |
| else |
| { |
| updated_next_state = CAPTURE_STATE_STREAMON; |
| } |
| } |
| else if (current_state == CAPTURE_STATE_CAPTURE && |
| next_state != CAPTURE_STATE_CAPTURE) |
| { |
| stop_capture(cmng, V4L2_BUF_TYPE_VIDEO_CAPTURE); |
| } |
| |
| cmng->capture_inf.state = updated_next_state; |
| } |
| |
| static bool is_taking_still_picture(FAR capture_mng_t *cmng) |
| { |
| return cmng->still_inf.state == CAPTURE_STATE_STREAMON || |
| cmng->still_inf.state == CAPTURE_STATE_CAPTURE; |
| } |
| |
| static bool is_bufsize_sufficient(FAR capture_mng_t *cmng, uint32_t bufsize) |
| { |
| /* Depend on format, frame size, and JPEG compression quality */ |
| |
| return true; |
| } |
| |
| static void initialize_frame_setting(FAR struct imgsensor_s *imgsensor, |
| FAR uint8_t *nr_fmt, |
| FAR video_format_t *fmt, |
| FAR struct v4l2_fract *interval) |
| { |
| ASSERT(nr_fmt && fmt && interval); |
| |
| /* Initial setting : QVGA YUV4:2:2 15FPS */ |
| |
| *nr_fmt = 1; |
| if (imgsensor && imgsensor->frmsizes) |
| { |
| if (imgsensor->frmsizes[0].type == V4L2_FRMSIZE_TYPE_DISCRETE) |
| { |
| fmt[CAPTURE_FMT_MAIN].width = |
| imgsensor->frmsizes[0].discrete.width; |
| fmt[CAPTURE_FMT_MAIN].height = |
| imgsensor->frmsizes[0].discrete.height; |
| } |
| else |
| { |
| fmt[CAPTURE_FMT_MAIN].width = |
| imgsensor->frmsizes[0].stepwise.min_width; |
| fmt[CAPTURE_FMT_MAIN].height = |
| imgsensor->frmsizes[0].stepwise.min_height; |
| } |
| } |
| else |
| { |
| fmt[CAPTURE_FMT_MAIN].width = VIDEO_HSIZE_QVGA; |
| fmt[CAPTURE_FMT_MAIN].height = VIDEO_VSIZE_QVGA; |
| } |
| |
| if (imgsensor && imgsensor->fmtdescs) |
| { |
| fmt[CAPTURE_FMT_MAIN].pixelformat = imgsensor->fmtdescs[0].pixelformat; |
| } |
| else |
| { |
| fmt[CAPTURE_FMT_MAIN].pixelformat = V4L2_PIX_FMT_UYVY; |
| } |
| |
| if (imgsensor && imgsensor->frmintervals) |
| { |
| if (imgsensor->frmintervals[0].type == V4L2_FRMIVAL_TYPE_DISCRETE) |
| { |
| interval->denominator = |
| imgsensor->frmintervals[0].discrete.denominator; |
| interval->numerator = |
| imgsensor->frmintervals[0].discrete.numerator; |
| } |
| else |
| { |
| interval->denominator = |
| imgsensor->frmintervals[0].stepwise.min.denominator; |
| interval->numerator = |
| imgsensor->frmintervals[0].stepwise.min.numerator; |
| } |
| } |
| else |
| { |
| interval->denominator = 15; |
| interval->numerator = 1; |
| } |
| } |
| |
| static void initialize_streamresources(FAR capture_type_inf_t *type_inf, |
| FAR capture_mng_t *cmng) |
| { |
| memset(type_inf, 0, sizeof(capture_type_inf_t)); |
| type_inf->remaining_capnum = REMAINING_CAPNUM_INFINITY; |
| nxmutex_init(&type_inf->lock_state); |
| nxsem_init(&type_inf->wait_capture.dqbuf_wait_flg, 0, 0); |
| initialize_frame_setting(cmng->imgsensor, &type_inf->nr_fmt, |
| type_inf->fmt, |
| &type_inf->frame_interval); |
| video_framebuff_init(&type_inf->bufinf); |
| } |
| |
| static int32_t get_default_value(FAR capture_mng_t *cmng, uint32_t id) |
| { |
| imgsensor_supported_value_t value; |
| int ret; |
| |
| if (cmng->imgsensor == NULL) |
| { |
| /* Don't care(unsupported parameter) */ |
| |
| return 0; |
| } |
| |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, id, &value); |
| if (ret != OK) |
| { |
| /* Don't care(unsupported parameter) */ |
| |
| return 0; |
| } |
| |
| switch (value.type) |
| { |
| case IMGSENSOR_CTRL_TYPE_INTEGER_MENU: |
| return value.u.discrete.default_value; |
| |
| case IMGSENSOR_CTRL_TYPE_U8: |
| case IMGSENSOR_CTRL_TYPE_U16: |
| case IMGSENSOR_CTRL_TYPE_U32: |
| |
| /* Don't care */ |
| |
| return 0; |
| |
| default: |
| return value.u.range.default_value; |
| } |
| } |
| |
| static int32_t initialize_scene_gamma(FAR capture_mng_t *cmng, |
| FAR uint8_t **gamma) |
| { |
| imgsensor_supported_value_t sup_val; |
| imgsensor_value_t val; |
| int32_t sz; |
| int ret; |
| |
| *gamma = NULL; |
| |
| ASSERT(cmng->imgsensor); |
| |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, |
| IMGSENSOR_ID_GAMMA_CURVE, &sup_val); |
| if (ret != OK) |
| { |
| /* Unsupported parameter */ |
| |
| return 0; |
| } |
| |
| switch (sup_val.type) |
| { |
| case IMGSENSOR_CTRL_TYPE_U8: |
| sz = sup_val.u.elems.nr_elems * sizeof(uint8_t); |
| if (sz / sizeof(uint8_t) != sup_val.u.elems.nr_elems) |
| { |
| /* Multiplication overflow */ |
| |
| return 0; |
| } |
| |
| break; |
| |
| case IMGSENSOR_CTRL_TYPE_U16: |
| sz = sup_val.u.elems.nr_elems * sizeof(uint16_t); |
| if (sz / sizeof(uint16_t) != sup_val.u.elems.nr_elems) |
| { |
| /* Multiplication overflow */ |
| |
| return 0; |
| } |
| |
| break; |
| |
| default: /* IMGSENSOR_CTRL_TYPE_U32 */ |
| sz = sup_val.u.elems.nr_elems * sizeof(uint32_t); |
| if (sz / sizeof(uint32_t) != sup_val.u.elems.nr_elems) |
| { |
| /* Multiplication overflow */ |
| |
| return 0; |
| } |
| |
| break; |
| } |
| |
| *gamma = kmm_malloc(sz); |
| val.p_u8 = (FAR uint8_t *)*gamma; |
| IMGSENSOR_GET_VALUE(cmng->imgsensor, IMGSENSOR_ID_GAMMA_CURVE, sz, &val); |
| return sz; |
| } |
| |
| static int initialize_scene_parameter(FAR capture_mng_t *cmng, |
| enum v4l2_scene_mode mode, |
| FAR capture_scene_params_t **vsp) |
| { |
| FAR capture_scene_params_t *sp = |
| kmm_malloc(sizeof(capture_scene_params_t)); |
| |
| if (!sp) |
| { |
| return -ENOMEM; |
| } |
| |
| sp->mode = mode; |
| sp->brightness = get_default_value(cmng, IMGSENSOR_ID_BRIGHTNESS); |
| sp->contrast = get_default_value(cmng, IMGSENSOR_ID_CONTRAST); |
| sp->saturation = get_default_value(cmng, IMGSENSOR_ID_SATURATION); |
| sp->hue = get_default_value(cmng, IMGSENSOR_ID_HUE); |
| sp->awb = get_default_value(cmng, |
| IMGSENSOR_ID_AUTO_WHITE_BALANCE); |
| sp->red = get_default_value(cmng, IMGSENSOR_ID_RED_BALANCE); |
| sp->blue = get_default_value(cmng, IMGSENSOR_ID_BLUE_BALANCE); |
| sp->gamma = get_default_value(cmng, IMGSENSOR_ID_GAMMA); |
| sp->gamma_curve_sz = initialize_scene_gamma(cmng, &sp->gamma_curve); |
| sp->ev = get_default_value(cmng, IMGSENSOR_ID_EXPOSURE); |
| sp->hflip_video = get_default_value(cmng, IMGSENSOR_ID_HFLIP_VIDEO); |
| sp->vflip_video = get_default_value(cmng, IMGSENSOR_ID_VFLIP_VIDEO); |
| sp->hflip_still = get_default_value(cmng, IMGSENSOR_ID_HFLIP_STILL); |
| sp->vflip_still = get_default_value(cmng, IMGSENSOR_ID_VFLIP_STILL); |
| sp->sharpness = get_default_value(cmng, IMGSENSOR_ID_SHARPNESS); |
| sp->colorfx = get_default_value(cmng, IMGSENSOR_ID_COLORFX); |
| sp->auto_brightness = get_default_value(cmng, IMGSENSOR_ID_AUTOBRIGHTNESS); |
| sp->rotate = get_default_value(cmng, IMGSENSOR_ID_ROTATE); |
| sp->ae = get_default_value(cmng, IMGSENSOR_ID_EXPOSURE_AUTO); |
| sp->exposure_time = get_default_value(cmng, |
| IMGSENSOR_ID_EXPOSURE_ABSOLUTE); |
| sp->focus = get_default_value(cmng, IMGSENSOR_ID_FOCUS_ABSOLUTE); |
| sp->af = get_default_value(cmng, IMGSENSOR_ID_FOCUS_AUTO); |
| sp->zoom = get_default_value(cmng, IMGSENSOR_ID_ZOOM_ABSOLUTE); |
| sp->iris = get_default_value(cmng, IMGSENSOR_ID_IRIS_ABSOLUTE); |
| sp->wb = get_default_value(cmng, |
| IMGSENSOR_ID_AUTO_N_PRESET_WB); |
| sp->wdr = get_default_value(cmng, |
| IMGSENSOR_ID_WIDE_DYNAMIC_RANGE); |
| sp->stabilization = get_default_value(cmng, |
| IMGSENSOR_ID_IMG_STABILIZATION); |
| sp->iso_auto = get_default_value(cmng, |
| IMGSENSOR_ID_ISO_SENSITIVITY_AUTO); |
| sp->iso = get_default_value(cmng, |
| IMGSENSOR_ID_ISO_SENSITIVITY); |
| sp->meter = get_default_value(cmng, |
| IMGSENSOR_ID_EXPOSURE_METERING); |
| sp->threea_lock = get_default_value(cmng, IMGSENSOR_ID_3A_LOCK); |
| sp->led = get_default_value(cmng, IMGSENSOR_ID_FLASH_LED_MODE); |
| sp->jpeg_quality = get_default_value(cmng, IMGSENSOR_ID_JPEG_QUALITY); |
| |
| *vsp = sp; |
| |
| return OK; |
| } |
| |
| static void initialize_scenes_parameter(FAR capture_mng_t *cmng) |
| { |
| memset(cmng->capture_scene_param, |
| 0, sizeof(cmng->capture_scene_param)); |
| |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_NONE, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #ifdef CONFIG_VIDEO_SCENE_BACKLIGHT |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_BACKLIGHT, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_BACKLIGHT */ |
| #ifdef CONFIG_VIDEO_SCENE_BEACHSNOW |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_BEACH_SNOW, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_BEACHSNOW */ |
| #ifdef CONFIG_VIDEO_SCENE_CANDLELIGHT |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_CANDLE_LIGHT, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_CANDLELIGHT */ |
| #ifdef CONFIG_VIDEO_SCENE_DAWNDUSK |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_DAWN_DUSK, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_DAWNDUSK */ |
| #ifdef CONFIG_VIDEO_SCENE_FALLCOLORS |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_FALL_COLORS, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_FALLCOLORS */ |
| #ifdef CONFIG_VIDEO_SCENE_FIREWORKS |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_FIREWORKS, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_FIREWORKS */ |
| #ifdef CONFIG_VIDEO_SCENE_LANDSCAPE |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_LANDSCAPE, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_LANDSCAPE */ |
| #ifdef CONFIG_VIDEO_SCENE_NIGHT |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_NIGHT, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_NIGHT */ |
| #ifdef CONFIG_VIDEO_SCENE_PARTYINDOOR |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_PARTY_INDOOR, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_PARTYINDOOR */ |
| #ifdef CONFIG_VIDEO_SCENE_PORTRAIT |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_PORTRAIT, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_PORTRAIT */ |
| #ifdef CONFIG_VIDEO_SCENE_SPORTS |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_SPORTS, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_SPORTS */ |
| #ifdef CONFIG_VIDEO_SCENE_SUNSET |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_SUNSET, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_SUNSET */ |
| #ifdef CONFIG_VIDEO_SCENE_TEXT |
| initialize_scene_parameter(cmng, V4L2_SCENE_MODE_TEXT, |
| &cmng->capture_scene_param[cmng->capture_scence_num++]); |
| #endif /* CONFIG_VIDEO_SCENE_TEXT */ |
| } |
| |
| static void initialize_resources(FAR capture_mng_t *cmng) |
| { |
| initialize_streamresources(&cmng->capture_inf, cmng); |
| initialize_streamresources(&cmng->still_inf, cmng); |
| initialize_scenes_parameter(cmng); |
| } |
| |
| static void cleanup_streamresources(FAR capture_type_inf_t *type_inf, |
| FAR capture_mng_t *cmng) |
| { |
| video_framebuff_uninit(&type_inf->bufinf); |
| nxsem_destroy(&type_inf->wait_capture.dqbuf_wait_flg); |
| nxmutex_destroy(&type_inf->lock_state); |
| if (type_inf->bufheap != NULL) |
| { |
| if (cmng->imgdata->ops->free) |
| { |
| cmng->imgdata->ops->free(cmng->imgdata, type_inf->bufheap); |
| } |
| else |
| { |
| kumm_free(type_inf->bufheap); |
| } |
| |
| type_inf->bufheap = NULL; |
| } |
| } |
| |
| static void cleanup_scene_parameter(FAR capture_scene_params_t **vsp) |
| { |
| FAR capture_scene_params_t *sp = *vsp; |
| ASSERT(sp); |
| |
| if (sp->gamma_curve != NULL) |
| { |
| kmm_free(sp->gamma_curve); |
| sp->gamma_curve = NULL; |
| sp->gamma_curve_sz = 0; |
| } |
| |
| kmm_free(sp); |
| *vsp = NULL; |
| } |
| |
| static void cleanup_scenes_parameter(FAR capture_mng_t *cmng) |
| { |
| int i; |
| |
| for (i = 0; i < cmng->capture_scence_num; i++) |
| { |
| cleanup_scene_parameter(&cmng->capture_scene_param[i]); |
| } |
| |
| cmng->capture_scence_num = 0; |
| } |
| |
| static void cleanup_resources(FAR capture_mng_t *cmng) |
| { |
| /* If in capture, stop */ |
| |
| if (cmng->capture_inf.state == CAPTURE_STATE_CAPTURE) |
| { |
| stop_capture(cmng, V4L2_BUF_TYPE_VIDEO_CAPTURE); |
| } |
| |
| if (cmng->still_inf.state == CAPTURE_STATE_CAPTURE) |
| { |
| stop_capture(cmng, V4L2_BUF_TYPE_STILL_CAPTURE); |
| } |
| |
| /* Clean up resource */ |
| |
| cleanup_streamresources(&cmng->capture_inf, cmng); |
| cleanup_streamresources(&cmng->still_inf, cmng); |
| cleanup_scenes_parameter(cmng); |
| } |
| |
| static bool is_sem_waited(FAR sem_t *sem) |
| { |
| int semcount; |
| |
| return nxsem_get_value(sem, &semcount) == OK && semcount < 0; |
| } |
| |
| static int validate_frame_setting(FAR capture_mng_t *cmng, |
| enum v4l2_buf_type type, |
| uint8_t nr_fmt, |
| FAR video_format_t *vfmt, |
| FAR struct v4l2_rect *clip, |
| FAR struct v4l2_fract *interval) |
| { |
| video_format_t c_fmt[MAX_CAPTURE_FMT]; |
| imgdata_format_t df[MAX_CAPTURE_FMT]; |
| imgsensor_format_t sf[MAX_CAPTURE_FMT]; |
| imgdata_interval_t di; |
| imgsensor_interval_t si; |
| int ret; |
| |
| ASSERT(vfmt && interval && cmng->imgsensor && cmng->imgdata); |
| |
| /* Return OK only in case both image data driver and |
| * image sensor driver support. |
| */ |
| |
| get_clipped_format(nr_fmt, vfmt, clip, c_fmt); |
| |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_MAIN], &df[IMGDATA_FMT_MAIN]); |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_SUB], &df[IMGDATA_FMT_SUB]); |
| convert_to_imgdatainterval(interval, &di); |
| convert_to_imgsensorfmt(&vfmt[CAPTURE_FMT_MAIN], &sf[IMGSENSOR_FMT_MAIN]); |
| convert_to_imgsensorfmt(&vfmt[CAPTURE_FMT_SUB], &sf[IMGSENSOR_FMT_SUB]); |
| convert_to_imgsensorinterval(interval, &si); |
| |
| ret = IMGSENSOR_VALIDATE_FRAME_SETTING(cmng->imgsensor, |
| type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? |
| IMGSENSOR_STREAM_TYPE_VIDEO : IMGSENSOR_STREAM_TYPE_STILL, |
| nr_fmt, sf, &si); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| return IMGDATA_VALIDATE_FRAME_SETTING(cmng->imgdata, nr_fmt, df, &di); |
| } |
| |
| static size_t get_bufsize(FAR video_format_t *vf) |
| { |
| size_t ret = vf->width * vf->height; |
| |
| switch (vf->pixelformat) |
| { |
| case V4L2_PIX_FMT_NV12: |
| case V4L2_PIX_FMT_YUV420: |
| return ret * 3 / 2; |
| case V4L2_PIX_FMT_YUYV: |
| case V4L2_PIX_FMT_UYVY: |
| case V4L2_PIX_FMT_RGB565: |
| case V4L2_PIX_FMT_JPEG: |
| default: |
| return ret * 2; |
| } |
| } |
| |
| static size_t get_heapsize(FAR capture_type_inf_t *type_inf) |
| { |
| return type_inf->bufinf.container_size * |
| get_bufsize(&type_inf->fmt[CAPTURE_FMT_MAIN]); |
| } |
| |
| static bool validate_clip_range(int32_t pos, uint32_t c_sz, uint16_t frm_sz) |
| { |
| return pos >= 0 && c_sz <= frm_sz && pos + c_sz <= frm_sz; |
| } |
| |
| static bool validate_clip_setting(FAR struct v4l2_rect *clip, |
| FAR video_format_t *fmt) |
| { |
| DEBUGASSERT(clip && fmt); |
| |
| /* Not permit the setting which do not fit inside frame size. */ |
| |
| return validate_clip_range(clip->left, clip->width, fmt->width) && |
| validate_clip_range(clip->top, clip->height, fmt->height); |
| } |
| |
| static void set_parameter_name(uint32_t id, FAR char *name) |
| { |
| int size = |
| sizeof(g_capture_parameter_name) / sizeof(capture_parameter_name_t); |
| int cnt; |
| |
| for (cnt = 0; cnt < size; cnt++) |
| { |
| if (g_capture_parameter_name[cnt].id == id) |
| { |
| break; |
| } |
| } |
| |
| ASSERT(cnt < size); |
| |
| /* copy size = 32 is due to V4L2 specification. */ |
| |
| strlcpy(name, g_capture_parameter_name[cnt].name, 32); |
| } |
| |
| static int set_intvalue(FAR struct capture_mng_s *cmng, |
| uint32_t id, int32_t value32) |
| { |
| imgsensor_value_t value; |
| |
| ASSERT(cmng->imgsensor); |
| |
| value.value32 = value32; |
| return IMGSENSOR_SET_VALUE(cmng->imgsensor, id, sizeof(int32_t), value); |
| } |
| |
| static int set_pvalue(FAR struct capture_mng_s *cmng, |
| uint32_t id, int size, void *pval) |
| { |
| imgsensor_value_t value; |
| |
| ASSERT(cmng->imgsensor); |
| |
| value.p_u8 = (FAR uint8_t *)pval; |
| return IMGSENSOR_SET_VALUE(cmng->imgsensor, id, size, value); |
| } |
| |
| static capture_scene_params_t *search_scene_param(FAR capture_mng_t *cmng, |
| enum v4l2_scene_mode mode) |
| { |
| int i; |
| |
| for (i = 0; i < cmng->capture_scence_num; i++) |
| { |
| if (cmng->capture_scene_param[i]->mode == mode) |
| { |
| return cmng->capture_scene_param[i]; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static int reflect_scene_parameter(FAR capture_mng_t *cmng, |
| enum v4l2_scene_mode mode) |
| { |
| capture_scene_params_t *sp; |
| |
| sp = search_scene_param(cmng, mode); |
| if (sp == NULL) |
| { |
| /* Unsupported scene mode */ |
| |
| return -EINVAL; |
| } |
| |
| set_intvalue(cmng, IMGSENSOR_ID_BRIGHTNESS, sp->brightness); |
| set_intvalue(cmng, IMGSENSOR_ID_CONTRAST, sp->contrast); |
| set_intvalue(cmng, IMGSENSOR_ID_SATURATION, sp->saturation); |
| set_intvalue(cmng, IMGSENSOR_ID_HUE , sp->hue); |
| set_intvalue(cmng, IMGSENSOR_ID_AUTO_WHITE_BALANCE, sp->awb); |
| set_intvalue(cmng, IMGSENSOR_ID_RED_BALANCE , sp->red); |
| set_intvalue(cmng, IMGSENSOR_ID_BLUE_BALANCE, sp->blue); |
| set_intvalue(cmng, IMGSENSOR_ID_GAMMA, sp->gamma); |
| set_pvalue(cmng, IMGSENSOR_ID_GAMMA_CURVE, |
| sp->gamma_curve_sz, sp->gamma_curve); |
| set_intvalue(cmng, IMGSENSOR_ID_EXPOSURE, sp->ev); |
| set_intvalue(cmng, IMGSENSOR_ID_HFLIP_VIDEO, sp->hflip_video); |
| set_intvalue(cmng, IMGSENSOR_ID_VFLIP_VIDEO, sp->vflip_video); |
| set_intvalue(cmng, IMGSENSOR_ID_HFLIP_STILL, sp->hflip_still); |
| set_intvalue(cmng, IMGSENSOR_ID_VFLIP_STILL, sp->vflip_still); |
| set_intvalue(cmng, IMGSENSOR_ID_SHARPNESS, sp->sharpness); |
| set_intvalue(cmng, IMGSENSOR_ID_COLORFX, sp->colorfx); |
| set_intvalue(cmng, IMGSENSOR_ID_AUTOBRIGHTNESS, sp->auto_brightness); |
| set_intvalue(cmng, IMGSENSOR_ID_ROTATE, sp->rotate); |
| set_intvalue(cmng, IMGSENSOR_ID_EXPOSURE_AUTO, sp->ae); |
| if (sp->ae == V4L2_EXPOSURE_MANUAL || |
| sp->ae == V4L2_EXPOSURE_SHUTTER_PRIORITY) |
| { |
| set_intvalue(cmng, IMGSENSOR_ID_EXPOSURE_ABSOLUTE, sp->exposure_time); |
| } |
| |
| set_intvalue(cmng, IMGSENSOR_ID_FOCUS_ABSOLUTE, sp->focus); |
| set_intvalue(cmng, IMGSENSOR_ID_FOCUS_AUTO, sp->af); |
| set_intvalue(cmng, IMGSENSOR_ID_ZOOM_ABSOLUTE, sp->zoom); |
| if (sp->ae == V4L2_EXPOSURE_MANUAL || |
| sp->ae == V4L2_EXPOSURE_APERTURE_PRIORITY) |
| { |
| set_intvalue(cmng, IMGSENSOR_ID_IRIS_ABSOLUTE, sp->iris); |
| } |
| |
| set_intvalue(cmng, IMGSENSOR_ID_AUTO_N_PRESET_WB, sp->wb); |
| set_intvalue(cmng, IMGSENSOR_ID_WIDE_DYNAMIC_RANGE, sp->wdr); |
| set_intvalue(cmng, IMGSENSOR_ID_IMG_STABILIZATION, sp->stabilization); |
| set_intvalue(cmng, IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, sp->iso_auto); |
| if (sp->iso_auto == V4L2_ISO_SENSITIVITY_MANUAL) |
| { |
| set_intvalue(cmng, IMGSENSOR_ID_ISO_SENSITIVITY, sp->iso); |
| } |
| |
| set_intvalue(cmng, IMGSENSOR_ID_EXPOSURE_METERING, sp->meter); |
| set_intvalue(cmng, IMGSENSOR_ID_3A_LOCK, sp->threea_lock); |
| set_intvalue(cmng, IMGSENSOR_ID_FLASH_LED_MODE, sp->led); |
| set_intvalue(cmng, IMGSENSOR_ID_JPEG_QUALITY, sp->jpeg_quality); |
| |
| cmng->capture_scene_mode = mode; |
| return OK; |
| } |
| |
| static int read_scene_param(FAR struct capture_mng_s *cmng, |
| enum v4l2_scene_mode mode, |
| uint32_t id, |
| FAR struct v4l2_ext_control *control) |
| { |
| imgsensor_supported_value_t value; |
| capture_scene_params_t *sp; |
| int ret = OK; |
| |
| ASSERT(cmng->imgsensor); |
| |
| if (control == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| sp = search_scene_param(cmng, mode); |
| if (sp == NULL) |
| { |
| /* Unsupported scene mode */ |
| |
| return -EINVAL; |
| } |
| |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, id, &value); |
| if (ret < 0) |
| { |
| /* Unsupported camera parameter */ |
| |
| return ret; |
| } |
| |
| switch (id) |
| { |
| case IMGSENSOR_ID_BRIGHTNESS: |
| control->value = sp->brightness; |
| break; |
| |
| case IMGSENSOR_ID_CONTRAST: |
| control->value = sp->contrast; |
| break; |
| |
| case IMGSENSOR_ID_SATURATION: |
| control->value = sp->saturation; |
| break; |
| |
| case IMGSENSOR_ID_HUE: |
| control->value = sp->hue; |
| break; |
| |
| case IMGSENSOR_ID_AUTO_WHITE_BALANCE: |
| control->value = sp->awb; |
| break; |
| |
| case IMGSENSOR_ID_RED_BALANCE: |
| control->value = sp->red; |
| break; |
| |
| case IMGSENSOR_ID_BLUE_BALANCE: |
| control->value = sp->blue; |
| break; |
| |
| case IMGSENSOR_ID_GAMMA: |
| control->value = sp->gamma; |
| break; |
| |
| case IMGSENSOR_ID_GAMMA_CURVE: |
| memcpy(control->p_u8, |
| sp->gamma_curve, |
| sp->gamma_curve_sz); |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE: |
| control->value = sp->ev; |
| break; |
| |
| case IMGSENSOR_ID_HFLIP_VIDEO: |
| control->value = sp->hflip_video; |
| break; |
| |
| case IMGSENSOR_ID_VFLIP_VIDEO: |
| control->value = sp->vflip_video; |
| break; |
| |
| case IMGSENSOR_ID_HFLIP_STILL: |
| control->value = sp->hflip_still; |
| break; |
| |
| case IMGSENSOR_ID_VFLIP_STILL: |
| control->value = sp->vflip_still; |
| break; |
| |
| case IMGSENSOR_ID_SHARPNESS: |
| control->value = sp->sharpness; |
| break; |
| |
| case IMGSENSOR_ID_COLOR_KILLER: |
| control->value = sp->colorfx == V4L2_COLORFX_BW; |
| break; |
| |
| case IMGSENSOR_ID_COLORFX: |
| control->value = sp->colorfx; |
| break; |
| |
| case IMGSENSOR_ID_AUTOBRIGHTNESS: |
| control->value = sp->auto_brightness; |
| break; |
| |
| case IMGSENSOR_ID_ROTATE: |
| control->value = sp->rotate; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_AUTO: |
| control->value = sp->ae; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_ABSOLUTE: |
| control->value = sp->exposure_time; |
| break; |
| |
| case IMGSENSOR_ID_FOCUS_ABSOLUTE: |
| control->value = sp->focus; |
| break; |
| |
| case IMGSENSOR_ID_FOCUS_AUTO: |
| control->value = sp->af; |
| break; |
| |
| case IMGSENSOR_ID_ZOOM_ABSOLUTE: |
| control->value = sp->zoom; |
| break; |
| |
| case IMGSENSOR_ID_IRIS_ABSOLUTE: |
| control->value = sp->iris; |
| break; |
| |
| case IMGSENSOR_ID_AUTO_N_PRESET_WB: |
| control->value = sp->wb; |
| break; |
| |
| case IMGSENSOR_ID_WIDE_DYNAMIC_RANGE: |
| control->value = sp->wdr; |
| break; |
| |
| case IMGSENSOR_ID_IMG_STABILIZATION: |
| control->value = sp->stabilization; |
| break; |
| |
| case IMGSENSOR_ID_ISO_SENSITIVITY: |
| control->value = sp->iso; |
| break; |
| |
| case IMGSENSOR_ID_ISO_SENSITIVITY_AUTO: |
| control->value = sp->iso_auto; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_METERING: |
| control->value = sp->meter; |
| break; |
| |
| case IMGSENSOR_ID_SPOT_POSITION: |
| control->value = sp->spot_pos; |
| break; |
| |
| case IMGSENSOR_ID_3A_LOCK: |
| control->value = sp->threea_lock; |
| break; |
| |
| case IMGSENSOR_ID_FLASH_LED_MODE: |
| control->value = sp->led; |
| break; |
| |
| case IMGSENSOR_ID_JPEG_QUALITY: |
| control->value = sp->jpeg_quality; |
| break; |
| |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| static int check_range(int64_t value, |
| int64_t min, |
| int64_t max, |
| uint64_t step) |
| { |
| if (value < min || value > max || |
| (value - min) % step != 0) |
| { |
| return -EINVAL; |
| } |
| |
| return OK; |
| } |
| |
| static int save_scene_param(FAR capture_mng_t *cmng, |
| enum v4l2_scene_mode mode, |
| uint32_t id, |
| FAR struct v4l2_ext_control *control) |
| { |
| imgsensor_supported_value_t value; |
| FAR imgsensor_capability_range_t *range = &value.u.range; |
| FAR imgsensor_capability_discrete_t *disc = &value.u.discrete; |
| FAR imgsensor_capability_elems_t *elem = &value.u.elems; |
| FAR capture_scene_params_t *sp; |
| int ret; |
| int i; |
| |
| ASSERT(cmng->imgsensor); |
| |
| sp = search_scene_param(cmng, mode); |
| if (sp == NULL) |
| { |
| /* Unsupported scene mode */ |
| |
| return -EINVAL; |
| } |
| |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, id, &value); |
| if (ret < 0) |
| { |
| /* Unsupported camera parameter */ |
| |
| return ret; |
| } |
| |
| switch (value.type) |
| { |
| case IMGSENSOR_CTRL_TYPE_INTEGER_MENU: |
| for (i = 0; i < disc->nr_values; i++) |
| { |
| if (control->value == disc->values[i]) |
| { |
| break; |
| } |
| } |
| |
| if (i >= disc->nr_values) |
| { |
| return -EINVAL; |
| } |
| |
| break; |
| |
| case IMGSENSOR_CTRL_TYPE_U8: |
| if (control->size < elem->nr_elems * sizeof(uint8_t)) |
| { |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < elem->nr_elems; i++) |
| { |
| ret = check_range(control->p_u8[i], |
| elem->minimum, |
| elem->maximum, |
| elem->step); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| } |
| |
| break; |
| |
| case IMGSENSOR_CTRL_TYPE_U16: |
| if (control->size < elem->nr_elems * sizeof(uint16_t)) |
| { |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < elem->nr_elems; i++) |
| { |
| ret = check_range(control->p_u16[i], |
| elem->minimum, |
| elem->maximum, |
| elem->step); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| } |
| |
| break; |
| |
| case IMGSENSOR_CTRL_TYPE_U32: |
| if (control->size < elem->nr_elems * sizeof(uint32_t)) |
| { |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < elem->nr_elems; i++) |
| { |
| ret = check_range(control->p_u32[i], |
| elem->minimum, |
| elem->maximum, |
| elem->step); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| } |
| |
| break; |
| |
| default: |
| ret = check_range(control->value, |
| range->minimum, |
| range->maximum, |
| range->step); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| break; |
| } |
| |
| switch (id) |
| { |
| case IMGSENSOR_ID_BRIGHTNESS: |
| sp->brightness = control->value; |
| break; |
| |
| case IMGSENSOR_ID_CONTRAST: |
| sp->contrast = control->value; |
| break; |
| |
| case IMGSENSOR_ID_SATURATION: |
| sp->saturation = control->value; |
| break; |
| |
| case IMGSENSOR_ID_HUE: |
| sp->hue = control->value; |
| break; |
| |
| case IMGSENSOR_ID_AUTO_WHITE_BALANCE: |
| sp->awb = control->value; |
| break; |
| |
| case IMGSENSOR_ID_RED_BALANCE: |
| sp->red = control->value; |
| break; |
| |
| case IMGSENSOR_ID_BLUE_BALANCE: |
| sp->blue = control->value; |
| break; |
| |
| case IMGSENSOR_ID_GAMMA: |
| sp->gamma = control->value; |
| break; |
| |
| case IMGSENSOR_ID_GAMMA_CURVE: |
| memcpy(sp->gamma_curve, |
| control->p_u8, |
| sp->gamma_curve_sz); |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE: |
| sp->ev = control->value; |
| break; |
| |
| case IMGSENSOR_ID_HFLIP_VIDEO: |
| sp->hflip_video = control->value; |
| break; |
| |
| case IMGSENSOR_ID_VFLIP_VIDEO: |
| sp->vflip_video = control->value; |
| break; |
| |
| case IMGSENSOR_ID_HFLIP_STILL: |
| sp->hflip_still = control->value; |
| break; |
| |
| case IMGSENSOR_ID_VFLIP_STILL: |
| sp->vflip_still = control->value; |
| break; |
| |
| case IMGSENSOR_ID_SHARPNESS: |
| sp->sharpness = control->value; |
| break; |
| |
| case IMGSENSOR_ID_COLOR_KILLER: |
| sp->colorfx = control->value ? V4L2_COLORFX_BW : V4L2_COLORFX_NONE; |
| break; |
| |
| case IMGSENSOR_ID_COLORFX: |
| sp->colorfx = control->value; |
| break; |
| |
| case IMGSENSOR_ID_AUTOBRIGHTNESS: |
| sp->auto_brightness = control->value; |
| break; |
| |
| case IMGSENSOR_ID_ROTATE: |
| sp->rotate = control->value; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_AUTO: |
| sp->ae = control->value; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_ABSOLUTE: |
| sp->exposure_time = control->value; |
| break; |
| |
| case IMGSENSOR_ID_FOCUS_ABSOLUTE: |
| sp->focus = control->value; |
| break; |
| |
| case IMGSENSOR_ID_FOCUS_AUTO: |
| sp->af = control->value; |
| break; |
| |
| case IMGSENSOR_ID_ZOOM_ABSOLUTE: |
| sp->zoom = control->value; |
| break; |
| |
| case IMGSENSOR_ID_IRIS_ABSOLUTE: |
| sp->iris = control->value; |
| break; |
| |
| case IMGSENSOR_ID_AUTO_N_PRESET_WB: |
| sp->wb = control->value; |
| break; |
| |
| case IMGSENSOR_ID_WIDE_DYNAMIC_RANGE: |
| sp->wdr = control->value; |
| break; |
| |
| case IMGSENSOR_ID_IMG_STABILIZATION: |
| sp->stabilization = control->value; |
| break; |
| |
| case IMGSENSOR_ID_ISO_SENSITIVITY: |
| sp->iso = control->value; |
| break; |
| |
| case IMGSENSOR_ID_ISO_SENSITIVITY_AUTO: |
| sp->iso_auto = control->value; |
| break; |
| |
| case IMGSENSOR_ID_EXPOSURE_METERING: |
| sp->meter = control->value; |
| break; |
| |
| case IMGSENSOR_ID_SPOT_POSITION: |
| sp->spot_pos = control->value; |
| break; |
| |
| case IMGSENSOR_ID_3A_LOCK: |
| sp->threea_lock = control->value; |
| break; |
| |
| case IMGSENSOR_ID_FLASH_LED_MODE: |
| sp->led = control->value; |
| break; |
| |
| case IMGSENSOR_ID_JPEG_QUALITY: |
| sp->jpeg_quality = control->value; |
| break; |
| |
| default: |
| return -EINVAL; |
| } |
| |
| return OK; |
| } |
| |
| /* Callback function which device driver call when capture has done. */ |
| |
| static int complete_capture(uint8_t err_code, |
| uint32_t datasize, |
| FAR const struct timeval *ts, |
| FAR void *arg) |
| { |
| FAR capture_mng_t *cmng = (FAR capture_mng_t *)arg; |
| FAR capture_type_inf_t *type_inf; |
| FAR vbuf_container_t *container = NULL; |
| enum v4l2_buf_type buf_type; |
| irqstate_t flags; |
| imgdata_format_t df[MAX_CAPTURE_FMT]; |
| video_format_t c_fmt[MAX_CAPTURE_FMT]; |
| |
| flags = enter_critical_section(); |
| |
| buf_type = cmng->still_inf.state == CAPTURE_STATE_CAPTURE ? |
| V4L2_BUF_TYPE_STILL_CAPTURE : V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| type_inf = get_capture_type_inf(cmng, buf_type); |
| if (type_inf == NULL) |
| { |
| leave_critical_section(flags); |
| return -EINVAL; |
| } |
| |
| poll_notify(&type_inf->fds, 1, POLLIN); |
| |
| if (err_code == 0) |
| { |
| type_inf->bufinf.vbuf_next->buf.flags = 0; |
| if (type_inf->remaining_capnum > 0) |
| { |
| type_inf->remaining_capnum--; |
| } |
| } |
| else |
| { |
| type_inf->bufinf.vbuf_next->buf.flags = V4L2_BUF_FLAG_ERROR; |
| } |
| |
| type_inf->bufinf.vbuf_next->buf.bytesused = datasize; |
| if (ts != NULL) |
| { |
| type_inf->bufinf.vbuf_next->buf.timestamp = *ts; |
| } |
| |
| video_framebuff_capture_done(&type_inf->bufinf); |
| |
| if (is_sem_waited(&type_inf->wait_capture.dqbuf_wait_flg)) |
| { |
| /* If waiting capture in DQBUF, |
| * get/save container and unlock wait |
| */ |
| |
| type_inf->wait_capture.done_container = |
| video_framebuff_pop_curr_container(&type_inf->bufinf); |
| type_inf->wait_capture.waitend_cause = WAITEND_CAUSE_CAPTUREDONE; |
| nxsem_post(&type_inf->wait_capture.dqbuf_wait_flg); |
| } |
| |
| if (type_inf->remaining_capnum == 0) |
| { |
| stop_capture(cmng, buf_type); |
| type_inf->state = CAPTURE_STATE_STREAMOFF; |
| |
| /* If stop still stream, notify it to video stream */ |
| |
| if (buf_type == V4L2_BUF_TYPE_STILL_CAPTURE && |
| is_sem_waited(&cmng->capture_inf.wait_capture.dqbuf_wait_flg)) |
| { |
| cmng->capture_inf.wait_capture.waitend_cause = |
| WAITEND_CAUSE_STILLSTOP; |
| nxsem_post(&cmng->capture_inf.wait_capture.dqbuf_wait_flg); |
| } |
| } |
| else |
| { |
| container = video_framebuff_get_vacant_container(&type_inf->bufinf); |
| if (container == NULL) |
| { |
| stop_capture(cmng, buf_type); |
| type_inf->state = CAPTURE_STATE_STREAMON; |
| } |
| else |
| { |
| get_clipped_format(type_inf->nr_fmt, |
| type_inf->fmt, |
| &type_inf->clip, |
| c_fmt); |
| |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_MAIN], |
| &df[IMGDATA_FMT_MAIN]); |
| convert_to_imgdatafmt(&c_fmt[CAPTURE_FMT_SUB], |
| &df[IMGDATA_FMT_SUB]); |
| |
| IMGDATA_SET_BUF(cmng->imgdata, |
| type_inf->nr_fmt, |
| df, |
| (FAR uint8_t *)container->buf.m.userptr, |
| container->buf.length); |
| container->buf.sequence = type_inf->seqnum++; |
| } |
| } |
| |
| leave_critical_section(flags); |
| return OK; |
| } |
| |
| static FAR struct imgsensor_s * |
| get_connected_imgsensor(FAR struct imgsensor_s **sensors, |
| size_t sensor_num) |
| { |
| FAR struct imgsensor_s *sensor = NULL; |
| int i; |
| |
| for (i = 0; i < sensor_num; i++) |
| { |
| if (sensors[i] && |
| IMGSENSOR_IS_AVAILABLE(sensors[i])) |
| { |
| sensor = sensors[i]; |
| break; |
| } |
| } |
| |
| return sensor; |
| } |
| |
| /**************************************************************************** |
| * Ioctl Functions |
| ****************************************************************************/ |
| |
| static int capture_querycap(FAR struct file *filep, |
| FAR struct v4l2_capability *cap) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR const char *name; |
| |
| if (cmng == NULL || cap == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| name = IMGSENSOR_GET_DRIVER_NAME(cmng->imgsensor); |
| if (name == NULL) |
| { |
| return -ENOTTY; |
| } |
| |
| memset(cap, 0, sizeof(struct v4l2_capability)); |
| |
| /* cap->driver needs to be NULL-terminated. */ |
| |
| strlcpy((FAR char *)cap->driver, name, sizeof(cap->driver)); |
| cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
| |
| return OK; |
| } |
| |
| static int capture_g_input(FAR int *num) |
| { |
| *num = 0; |
| return OK; |
| } |
| |
| static int capture_enum_input(FAR struct file *filep, |
| FAR struct v4l2_input *input) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR const char *name; |
| |
| if (cmng == NULL || input->index > 0) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| name = IMGSENSOR_GET_DRIVER_NAME(cmng->imgsensor); |
| if (name == NULL) |
| { |
| return -ENOTTY; |
| } |
| |
| memset(input, 0, sizeof(struct v4l2_input)); |
| strlcpy((FAR char *)input->name, name, sizeof(input->name)); |
| input->type = V4L2_INPUT_TYPE_CAMERA; |
| |
| return OK; |
| } |
| |
| static int capture_reqbufs(FAR struct file *filep, |
| FAR struct v4l2_requestbuffers *reqbufs) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| struct imgdata_s *imgdata = cmng->imgdata; |
| |
| irqstate_t flags; |
| int ret = OK; |
| |
| if (cmng == NULL || reqbufs == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, reqbufs->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| flags = enter_critical_section(); |
| |
| if (type_inf->state == CAPTURE_STATE_CAPTURE) |
| { |
| /* In capture, REQBUFS is not permitted */ |
| |
| ret = -EPERM; |
| } |
| else |
| { |
| if (reqbufs->count > V4L2_REQBUFS_COUNT_MAX) |
| { |
| reqbufs->count = V4L2_REQBUFS_COUNT_MAX; |
| } |
| |
| video_framebuff_change_mode(&type_inf->bufinf, reqbufs->mode); |
| ret = video_framebuff_realloc_container(&type_inf->bufinf, |
| reqbufs->count); |
| if (ret == OK && reqbufs->memory == V4L2_MEMORY_MMAP) |
| { |
| if (type_inf->bufheap != NULL) |
| { |
| if (imgdata->ops->free) |
| { |
| imgdata->ops->free(imgdata, type_inf->bufheap); |
| } |
| else |
| { |
| kumm_free(type_inf->bufheap); |
| } |
| } |
| |
| if (imgdata->ops->alloc) |
| { |
| type_inf->bufheap = imgdata->ops->alloc(imgdata, 32, |
| reqbufs->count * |
| get_bufsize(&type_inf->fmt[CAPTURE_FMT_MAIN])); |
| } |
| else |
| { |
| type_inf->bufheap = kumm_memalign(32, reqbufs->count * |
| get_bufsize(&type_inf->fmt[CAPTURE_FMT_MAIN])); |
| } |
| |
| if (type_inf->bufheap == NULL) |
| { |
| ret = -ENOMEM; |
| } |
| } |
| } |
| |
| leave_critical_section(flags); |
| return ret; |
| } |
| |
| static int capture_querybuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| |
| if (cmng == NULL || buf == NULL || buf->memory != V4L2_MEMORY_MMAP) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, buf->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (buf->index >= type_inf->bufinf.container_size) |
| { |
| return -EINVAL; |
| } |
| |
| buf->length = get_bufsize(&type_inf->fmt[CAPTURE_FMT_MAIN]); |
| buf->m.offset = buf->length * buf->index; |
| |
| return OK; |
| } |
| |
| static int capture_qbuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| FAR vbuf_container_t *container; |
| enum capture_state_e next_capture_state; |
| irqstate_t flags; |
| |
| if (cmng == NULL || buf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, buf->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (!is_bufsize_sufficient(cmng, buf->length)) |
| { |
| return -EINVAL; |
| } |
| |
| container = video_framebuff_get_container(&type_inf->bufinf); |
| if (container == NULL) |
| { |
| return -ENOMEM; |
| } |
| |
| memcpy(&container->buf, buf, sizeof(struct v4l2_buffer)); |
| if (buf->memory == V4L2_MEMORY_MMAP) |
| { |
| /* only use userptr inside the container */ |
| |
| container->buf.length = get_bufsize(&type_inf->fmt[CAPTURE_FMT_MAIN]); |
| container->buf.m.userptr = (unsigned long)(type_inf->bufheap + |
| container->buf.length * buf->index); |
| } |
| |
| video_framebuff_queue_container(&type_inf->bufinf, container); |
| |
| nxmutex_lock(&type_inf->lock_state); |
| flags = enter_critical_section(); |
| if (type_inf->state == CAPTURE_STATE_STREAMON) |
| { |
| leave_critical_section(flags); |
| |
| if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| { |
| nxmutex_lock(&cmng->still_inf.lock_state); |
| next_capture_state = |
| estimate_next_capture_state(cmng, CAUSE_CAPTURE_START); |
| change_capture_state(cmng, next_capture_state); |
| nxmutex_unlock(&cmng->still_inf.lock_state); |
| } |
| else |
| { |
| container = |
| video_framebuff_get_vacant_container(&type_inf->bufinf); |
| if (container != NULL) |
| { |
| type_inf->seqnum = 0; |
| start_capture(cmng, |
| buf->type, |
| type_inf->nr_fmt, |
| type_inf->fmt, |
| &type_inf->clip, |
| &type_inf->frame_interval, |
| container->buf.m.userptr, |
| container->buf.length); |
| type_inf->state = CAPTURE_STATE_CAPTURE; |
| } |
| } |
| } |
| else |
| { |
| leave_critical_section(flags); |
| } |
| |
| nxmutex_unlock(&type_inf->lock_state); |
| return OK; |
| } |
| |
| static int capture_dqbuf(FAR struct file *filep, |
| FAR struct v4l2_buffer *buf) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| FAR vbuf_container_t *container; |
| FAR sem_t *dqbuf_wait_flg; |
| enum capture_state_e next_capture_state; |
| irqstate_t flags; |
| |
| if (cmng == NULL || buf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, buf->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| container = video_framebuff_dq_valid_container(&type_inf->bufinf); |
| if (container == NULL) |
| { |
| if (filep->f_oflags & O_NONBLOCK) |
| { |
| return -EAGAIN; |
| } |
| |
| /* Not yet done capture. Wait done */ |
| |
| dqbuf_wait_flg = &type_inf->wait_capture.dqbuf_wait_flg; |
| |
| /* Loop until semaphore is unlocked by capture done or DQCANCEL */ |
| |
| do |
| { |
| if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| { |
| /* If start capture condition is satisfied, start capture */ |
| |
| flags = enter_critical_section(); |
| next_capture_state = |
| estimate_next_capture_state(cmng, CAUSE_CAPTURE_DQBUF); |
| change_capture_state(cmng, next_capture_state); |
| leave_critical_section(flags); |
| } |
| |
| nxsem_wait_uninterruptible(dqbuf_wait_flg); |
| } |
| while (type_inf->wait_capture.waitend_cause == |
| WAITEND_CAUSE_STILLSTOP); |
| |
| container = type_inf->wait_capture.done_container; |
| if (container == NULL) |
| { |
| /* Waking up without captured data means abort. |
| * Therefore, Check cause. |
| */ |
| |
| if (type_inf->wait_capture.waitend_cause == WAITEND_CAUSE_DQCANCEL) |
| { |
| return -ECANCELED; |
| } |
| } |
| |
| type_inf->wait_capture.done_container = NULL; |
| } |
| |
| memcpy(buf, &container->buf, sizeof(struct v4l2_buffer)); |
| video_framebuff_free_container(&type_inf->bufinf, container); |
| |
| return OK; |
| } |
| |
| static int capture_cancel_dqbuf(FAR struct file *filep, |
| enum v4l2_buf_type type) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (!is_sem_waited(&type_inf->wait_capture.dqbuf_wait_flg)) |
| { |
| /* In not waiting DQBUF case, return OK */ |
| |
| return OK; |
| } |
| |
| type_inf->wait_capture.waitend_cause = WAITEND_CAUSE_DQCANCEL; |
| |
| /* If capture is done before nxsem_post, cause is overwritten */ |
| |
| return nxsem_post(&type_inf->wait_capture.dqbuf_wait_flg); |
| } |
| |
| static int capture_g_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, fmt->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| memset(&fmt->fmt, 0, sizeof(fmt->fmt)); |
| fmt->fmt.pix.width = type_inf->fmt[CAPTURE_FMT_MAIN].width; |
| fmt->fmt.pix.height = type_inf->fmt[CAPTURE_FMT_MAIN].height; |
| fmt->fmt.pix.pixelformat = type_inf->fmt[CAPTURE_FMT_MAIN].pixelformat; |
| |
| return OK; |
| } |
| |
| static int capture_s_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| int ret; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ret = capture_try_fmt(filep, fmt); |
| if (ret != 0) |
| { |
| return ret; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, fmt->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (type_inf->state != CAPTURE_STATE_STREAMOFF) |
| { |
| return -EBUSY; |
| } |
| |
| switch (fmt->fmt.pix.pixelformat) |
| { |
| case V4L2_PIX_FMT_SUBIMG_UYVY: |
| case V4L2_PIX_FMT_SUBIMG_RGB565: |
| if (type_inf->fmt[CAPTURE_FMT_MAIN].pixelformat != |
| V4L2_PIX_FMT_JPEG_WITH_SUBIMG) |
| { |
| return -EPERM; |
| } |
| |
| type_inf->fmt[CAPTURE_FMT_SUB].width = fmt->fmt.pix.width; |
| type_inf->fmt[CAPTURE_FMT_SUB].height = fmt->fmt.pix.height; |
| type_inf->fmt[CAPTURE_FMT_SUB].pixelformat = |
| fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_SUBIMG_UYVY ? |
| V4L2_PIX_FMT_UYVY : V4L2_PIX_FMT_RGB565; |
| type_inf->nr_fmt = 2; |
| break; |
| |
| default: |
| type_inf->fmt[CAPTURE_FMT_MAIN].width = fmt->fmt.pix.width; |
| type_inf->fmt[CAPTURE_FMT_MAIN].height = fmt->fmt.pix.height; |
| type_inf->fmt[CAPTURE_FMT_MAIN].pixelformat = |
| fmt->fmt.pix.pixelformat; |
| type_inf->nr_fmt = 1; |
| break; |
| } |
| |
| return OK; |
| } |
| |
| static int capture_try_fmt(FAR struct file *filep, |
| FAR struct v4l2_format *fmt) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| video_format_t vf[MAX_CAPTURE_FMT]; |
| uint8_t nr_fmt; |
| |
| if (cmng == NULL || fmt == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor && cmng->imgdata); |
| |
| type_inf = get_capture_type_inf(cmng, fmt->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| switch (fmt->fmt.pix.pixelformat) |
| { |
| case V4L2_PIX_FMT_SUBIMG_UYVY: |
| case V4L2_PIX_FMT_SUBIMG_RGB565: |
| if (type_inf->fmt[CAPTURE_FMT_MAIN].pixelformat != |
| V4L2_PIX_FMT_JPEG_WITH_SUBIMG) |
| { |
| return -EPERM; |
| } |
| |
| /* Validate both main image and subimage. */ |
| |
| nr_fmt = 2; |
| memcpy(&vf[CAPTURE_FMT_MAIN], |
| &type_inf->fmt[CAPTURE_FMT_MAIN], |
| sizeof(video_format_t)); |
| vf[CAPTURE_FMT_SUB].width = fmt->fmt.pix.width; |
| vf[CAPTURE_FMT_SUB].height = fmt->fmt.pix.height; |
| vf[CAPTURE_FMT_SUB].pixelformat = |
| fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_SUBIMG_UYVY ? |
| V4L2_PIX_FMT_UYVY : V4L2_PIX_FMT_RGB565; |
| break; |
| case V4L2_PIX_FMT_NV12: |
| case V4L2_PIX_FMT_YUV420: |
| case V4L2_PIX_FMT_YUYV: |
| case V4L2_PIX_FMT_UYVY: |
| case V4L2_PIX_FMT_RGB565: |
| case V4L2_PIX_FMT_JPEG: |
| case V4L2_PIX_FMT_JPEG_WITH_SUBIMG: |
| nr_fmt = 1; |
| vf[CAPTURE_FMT_MAIN].width = fmt->fmt.pix.width; |
| vf[CAPTURE_FMT_MAIN].height = fmt->fmt.pix.height; |
| vf[CAPTURE_FMT_MAIN].pixelformat = fmt->fmt.pix.pixelformat; |
| break; |
| |
| default: |
| return -EINVAL; |
| } |
| |
| return validate_frame_setting(cmng, |
| fmt->type, |
| nr_fmt, |
| vf, |
| &type_inf->clip, |
| &type_inf->frame_interval); |
| } |
| |
| static int capture_g_parm(FAR struct file *filep, |
| FAR struct v4l2_streamparm *parm) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| int ret = -EINVAL; |
| |
| if (cmng == NULL || parm == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| DEBUGASSERT(cmng->imgsensor); |
| |
| type_inf = get_capture_type_inf(cmng, parm->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| memset(&parm->parm, 0, sizeof(parm->parm)); |
| |
| if (type_inf->state == CAPTURE_STATE_CAPTURE) |
| { |
| /* If capture is started and lower driver has the get_frame_interval(), |
| * query lower driver. |
| */ |
| |
| ret = IMGSENSOR_GET_FRAME_INTERVAL(cmng->imgsensor, parm->type, |
| (imgsensor_interval_t *)&parm->parm.capture.timeperframe); |
| } |
| |
| if (ret != OK) |
| { |
| /* In no capture state or error case, return stored value. */ |
| |
| memcpy(&parm->parm.capture.timeperframe, |
| &type_inf->frame_interval, |
| sizeof(struct v4l2_fract)); |
| } |
| |
| parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
| return OK; |
| } |
| |
| static int capture_s_parm(FAR struct file *filep, |
| FAR struct v4l2_streamparm *parm) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| int ret; |
| |
| if (cmng == NULL || parm == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor && cmng->imgdata); |
| |
| type_inf = get_capture_type_inf(cmng, parm->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (type_inf->state != CAPTURE_STATE_STREAMOFF) |
| { |
| return -EBUSY; |
| } |
| |
| ret = validate_frame_setting(cmng, |
| parm->type, |
| type_inf->nr_fmt, |
| type_inf->fmt, |
| &type_inf->clip, |
| &parm->parm.capture.timeperframe); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| memcpy(&type_inf->frame_interval, |
| &parm->parm.capture.timeperframe, |
| sizeof(struct v4l2_fract)); |
| |
| return ret; |
| } |
| |
| static int capture_streamon(FAR struct file *filep, |
| FAR enum v4l2_buf_type *type) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| enum capture_state_e next_capture_state; |
| int ret = OK; |
| |
| if (cmng == NULL || type == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, *type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| { |
| /* No procedure for VIDIOC_STREAMON(STILL_CAPTURE) */ |
| |
| return OK; |
| } |
| |
| nxmutex_lock(&type_inf->lock_state); |
| |
| if (type_inf->state != CAPTURE_STATE_STREAMOFF) |
| { |
| ret = -EPERM; |
| } |
| else |
| { |
| next_capture_state = |
| estimate_next_capture_state(cmng, CAUSE_CAPTURE_START); |
| change_capture_state(cmng, next_capture_state); |
| } |
| |
| nxmutex_unlock(&type_inf->lock_state); |
| return ret; |
| } |
| |
| static int capture_streamoff(FAR struct file *filep, |
| FAR enum v4l2_buf_type *type) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| enum capture_state_e next_capture_state; |
| irqstate_t flags; |
| int ret = OK; |
| |
| if (cmng == NULL || type == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, *type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| { |
| /* No procedure for VIDIOC_STREAMOFF(STILL_CAPTURE) */ |
| |
| return OK; |
| } |
| |
| flags = enter_critical_section(); |
| |
| if (type_inf->state == CAPTURE_STATE_STREAMOFF) |
| { |
| ret = -EPERM; |
| } |
| else |
| { |
| next_capture_state = |
| estimate_next_capture_state(cmng, CAUSE_CAPTURE_STOP); |
| change_capture_state(cmng, next_capture_state); |
| } |
| |
| leave_critical_section(flags); |
| |
| return ret; |
| } |
| |
| static int capture_do_halfpush(FAR struct file *filep, bool enable) |
| { |
| struct v4l2_ext_controls ext_controls; |
| struct v4l2_ext_control control[2]; |
| |
| /* Replace to VIDIOC_S_EXT_CTRLS format */ |
| |
| control[0].id = V4L2_CID_3A_LOCK; |
| control[0].value = enable ? |
| V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE : 0; |
| control[1].id = V4L2_CID_AUTO_FOCUS_START; |
| control[1].value = enable ? true : false; |
| |
| ext_controls.ctrl_class = V4L2_CTRL_CLASS_CAMERA; |
| ext_controls.count = 2; |
| ext_controls.controls = control; |
| |
| /* Execute VIDIOC_S_EXT_CTRLS */ |
| |
| return capture_s_ext_ctrls(filep, &ext_controls); |
| } |
| |
| static int capture_takepict_start(FAR struct file *filep, |
| int32_t capture_num) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| enum capture_state_e next_capture_state; |
| FAR vbuf_container_t *container; |
| irqstate_t flags; |
| int ret = OK; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| nxmutex_lock(&cmng->still_inf.lock_state); |
| |
| if (cmng->still_inf.state != CAPTURE_STATE_STREAMOFF) |
| { |
| ret = -EPERM; |
| } |
| else |
| { |
| if (capture_num > 0) |
| { |
| cmng->still_inf.remaining_capnum = capture_num; |
| } |
| else |
| { |
| cmng->still_inf.remaining_capnum = REMAINING_CAPNUM_INFINITY; |
| } |
| |
| /* Control video stream prior to still stream */ |
| |
| flags = enter_critical_section(); |
| |
| next_capture_state = estimate_next_capture_state(cmng, |
| CAUSE_STILL_START); |
| change_capture_state(cmng, next_capture_state); |
| |
| leave_critical_section(flags); |
| |
| container = |
| video_framebuff_get_vacant_container(&cmng->still_inf.bufinf); |
| if (container != NULL) |
| { |
| /* Start still stream capture */ |
| |
| start_capture(cmng, |
| V4L2_BUF_TYPE_STILL_CAPTURE, |
| cmng->still_inf.nr_fmt, |
| cmng->still_inf.fmt, |
| &cmng->still_inf.clip, |
| &cmng->still_inf.frame_interval, |
| container->buf.m.userptr, |
| container->buf.length); |
| |
| cmng->still_inf.state = CAPTURE_STATE_CAPTURE; |
| } |
| else |
| { |
| cmng->still_inf.state = CAPTURE_STATE_STREAMON; |
| } |
| } |
| |
| nxmutex_unlock(&cmng->still_inf.lock_state); |
| return ret; |
| } |
| |
| static int capture_takepict_stop(FAR struct file *filep, |
| bool halfpush) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| enum capture_state_e next_capture_state; |
| irqstate_t flags; |
| int ret = OK; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| nxmutex_lock(&cmng->still_inf.lock_state); |
| |
| if (cmng->still_inf.state == CAPTURE_STATE_STREAMOFF && |
| cmng->still_inf.remaining_capnum == REMAINING_CAPNUM_INFINITY) |
| { |
| ret = -EPERM; |
| } |
| else |
| { |
| flags = enter_critical_section(); |
| if (cmng->still_inf.state == CAPTURE_STATE_CAPTURE) |
| { |
| stop_capture(cmng, V4L2_BUF_TYPE_STILL_CAPTURE); |
| } |
| |
| leave_critical_section(flags); |
| |
| cmng->still_inf.state = CAPTURE_STATE_STREAMOFF; |
| cmng->still_inf.remaining_capnum = REMAINING_CAPNUM_INFINITY; |
| |
| /* Control video stream */ |
| |
| nxmutex_lock(&cmng->capture_inf.lock_state); |
| next_capture_state = estimate_next_capture_state(cmng, |
| CAUSE_STILL_STOP); |
| change_capture_state(cmng, next_capture_state); |
| nxmutex_unlock(&cmng->capture_inf.lock_state); |
| } |
| |
| nxmutex_unlock(&cmng->still_inf.lock_state); |
| return ret; |
| } |
| |
| static int capture_s_selection(FAR struct file *filep, |
| FAR struct v4l2_selection *clip) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| uint32_t p_u32[IMGSENSOR_CLIP_NELEM]; |
| imgsensor_value_t val; |
| int32_t id; |
| int ret; |
| |
| if (cmng == NULL || clip == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| type_inf = get_capture_type_inf(cmng, clip->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (type_inf->state != CAPTURE_STATE_STREAMOFF) |
| { |
| return -EBUSY; |
| } |
| |
| if (!validate_clip_setting(&clip->r, type_inf->fmt)) |
| { |
| return -EINVAL; |
| } |
| |
| ret = validate_frame_setting(cmng, |
| clip->type, |
| type_inf->nr_fmt, |
| type_inf->fmt, |
| &clip->r, |
| &type_inf->frame_interval); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| id = clip->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? |
| IMGSENSOR_ID_CLIP_VIDEO : IMGSENSOR_ID_CLIP_STILL; |
| |
| p_u32[IMGSENSOR_CLIP_INDEX_LEFT] = clip->r.left; |
| p_u32[IMGSENSOR_CLIP_INDEX_TOP] = clip->r.top; |
| p_u32[IMGSENSOR_CLIP_INDEX_WIDTH] = clip->r.width; |
| p_u32[IMGSENSOR_CLIP_INDEX_HEIGHT] = clip->r.height; |
| |
| val.p_u32 = p_u32; |
| ret = IMGSENSOR_SET_VALUE(cmng->imgsensor, id, sizeof(p_u32), val); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| memcpy(&type_inf->clip, &clip->r, sizeof(struct v4l2_rect)); |
| return ret; |
| } |
| |
| static int capture_g_selection(FAR struct file *filep, |
| FAR struct v4l2_selection *clip) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| |
| if (cmng == NULL || clip == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = get_capture_type_inf(cmng, clip->type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| memcpy(&clip->r, &type_inf->clip, sizeof(struct v4l2_rect)); |
| return OK; |
| } |
| |
| static int capture_queryctrl(FAR struct file *filep, |
| FAR struct v4l2_queryctrl *ctrl) |
| { |
| struct v4l2_query_ext_ctrl ext_ctrl; |
| int ret; |
| |
| if (ctrl == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| /* Replace to VIDIOC_QUERY_EXT_CTRL format */ |
| |
| ext_ctrl.ctrl_class = ctrl->ctrl_class; |
| ext_ctrl.id = ctrl->id; |
| |
| ret = capture_query_ext_ctrl(filep, &ext_ctrl); |
| if (ret != OK) |
| { |
| return ret; |
| } |
| |
| if (ext_ctrl.type == V4L2_CTRL_TYPE_INTEGER64 || |
| ext_ctrl.type == V4L2_CTRL_TYPE_U8 || |
| ext_ctrl.type == V4L2_CTRL_TYPE_U16 || |
| ext_ctrl.type == V4L2_CTRL_TYPE_U32) |
| { |
| /* Unsupported type in VIDIOC_QUERYCTRL */ |
| |
| return -EINVAL; |
| } |
| |
| /* Replace gotten value to VIDIOC_QUERYCTRL */ |
| |
| ctrl->type = ext_ctrl.type; |
| ctrl->minimum = ext_ctrl.minimum; |
| ctrl->maximum = ext_ctrl.maximum; |
| ctrl->step = ext_ctrl.step; |
| ctrl->default_value = ext_ctrl.default_value; |
| ctrl->flags = ext_ctrl.flags; |
| strlcpy(ctrl->name, ext_ctrl.name, sizeof(ctrl->name)); |
| |
| return OK; |
| } |
| |
| static int capture_query_ext_ctrl(FAR struct file *filep, |
| FAR struct v4l2_query_ext_ctrl *attr) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| imgsensor_supported_value_t value; |
| imgsensor_capability_range_t *range = &value.u.range; |
| imgsensor_capability_discrete_t *disc = &value.u.discrete; |
| imgsensor_capability_elems_t *elem = &value.u.elems; |
| int ret; |
| |
| if (cmng == NULL || attr == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| attr->flags = 0; |
| attr->elem_size = 0; |
| attr->elems = 1; |
| attr->nr_of_dims = 0; |
| memset(attr->dims, 0, sizeof(attr->dims)); |
| |
| if (attr->id == V4L2_CID_SCENE_MODE) |
| { |
| /* Scene mode is processed in only video driver. */ |
| |
| attr->type = V4L2_CTRL_TYPE_INTEGER_MENU; |
| attr->minimum = 0; |
| attr->maximum = cmng->capture_scence_num - 1; |
| attr->step = 1; |
| attr->default_value = 0; |
| attr->flags = 0; |
| strlcpy(attr->name, "Scene Mode", 32); |
| } |
| else |
| { |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, attr->id, &value); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| attr->type = value.type; |
| attr->flags = 0; |
| |
| switch (value.type) |
| { |
| case IMGSENSOR_CTRL_TYPE_INTEGER_MENU: |
| attr->minimum = 0; |
| attr->maximum = disc->nr_values - 1; |
| attr->step = 1; |
| attr->default_value = disc->default_value; |
| break; |
| |
| case IMGSENSOR_CTRL_TYPE_U8: |
| case IMGSENSOR_CTRL_TYPE_U16: |
| case IMGSENSOR_CTRL_TYPE_U32: |
| attr->minimum = elem->minimum; |
| attr->maximum = elem->maximum; |
| attr->step = elem->step; |
| attr->elems = elem->nr_elems; |
| break; |
| |
| default: |
| attr->minimum = range->minimum; |
| attr->maximum = range->maximum; |
| attr->step = range->step; |
| attr->default_value = range->default_value; |
| break; |
| } |
| |
| set_parameter_name(attr->id, attr->name); |
| } |
| |
| return OK; |
| } |
| |
| static int capture_querymenu(FAR struct file *filep, |
| FAR struct v4l2_querymenu *menu) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| imgsensor_supported_value_t value; |
| int ret; |
| |
| if (cmng == NULL || menu == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| if (menu->id == V4L2_CID_SCENE_MODE) |
| { |
| /* Scene mode is processed in only video driver. */ |
| |
| if (menu->index > cmng->capture_scence_num - 1) |
| { |
| return -EINVAL; |
| } |
| |
| menu->value = cmng->capture_scene_param[menu->index]->mode; |
| } |
| else |
| { |
| ret = IMGSENSOR_GET_SUPPORTED_VALUE(cmng->imgsensor, |
| menu->id, |
| &value); |
| if (ret < 0) |
| { |
| return ret; |
| } |
| |
| if (value.type != IMGSENSOR_CTRL_TYPE_INTEGER_MENU) |
| { |
| /* VIDIOC_QUERYMENU is used only for |
| * IMGSENSOR_CTRL_TYPE_INTEGER_MENU. |
| */ |
| |
| return -EINVAL; |
| } |
| |
| if (menu->index >= value.u.discrete.nr_values) |
| { |
| return -EINVAL; |
| } |
| |
| menu->value = value.u.discrete.values[menu->index]; |
| } |
| |
| return OK; |
| } |
| |
| static int capture_g_ctrl(FAR struct file *filep, |
| FAR struct v4l2_control *ctrl) |
| { |
| struct v4l2_ext_controls ext_controls; |
| struct v4l2_ext_control control; |
| int ret; |
| |
| if (ctrl == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| memset(&ext_controls, 0, sizeof(struct v4l2_ext_controls)); |
| memset(&control, 0, sizeof(struct v4l2_ext_control)); |
| |
| /* Replace to VIDIOC_G_EXT_CTRLS format */ |
| |
| control.id = ctrl->id; |
| |
| ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER; |
| ext_controls.count = 1; |
| ext_controls.controls = &control; |
| |
| /* Execute VIDIOC_G_EXT_CTRLS */ |
| |
| ret = capture_g_ext_ctrls(filep, &ext_controls); |
| if (ret == OK) |
| { |
| /* Replace gotten value to VIDIOC_G_CTRL parameter */ |
| |
| ctrl->value = control.value; |
| } |
| |
| return ret; |
| } |
| |
| static int capture_s_ctrl(FAR struct file *filep, |
| FAR struct v4l2_control *ctrl) |
| { |
| struct v4l2_ext_controls ext_controls; |
| struct v4l2_ext_control control; |
| |
| if (ctrl == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| /* Replace to VIDIOC_S_EXT_CTRLS format */ |
| |
| control.id = ctrl->id; |
| control.value = ctrl->value; |
| |
| ext_controls.ctrl_class = V4L2_CTRL_CLASS_USER; |
| ext_controls.count = 1; |
| ext_controls.controls = &control; |
| |
| /* Execute VIDIOC_S_EXT_CTRLS */ |
| |
| return capture_s_ext_ctrls(filep, &ext_controls); |
| } |
| |
| static int capture_g_ext_ctrls(FAR struct file *filep, |
| FAR struct v4l2_ext_controls *ctrls) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR struct v4l2_ext_control *control; |
| int ret = OK; |
| int cnt; |
| |
| if (cmng == NULL || ctrls == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| for (cnt = 0, control = ctrls->controls; |
| cnt < ctrls->count; |
| cnt++, control++) |
| { |
| if (control->id == V4L2_CID_SCENE_MODE) |
| { |
| control->value = cmng->capture_scene_mode; |
| } |
| else |
| { |
| ret = IMGSENSOR_GET_VALUE(cmng->imgsensor, |
| control->id, |
| control->size, |
| (imgsensor_value_t *)&control->value64); |
| if (ret < 0) |
| { |
| /* Set cnt in that error occurred */ |
| |
| ctrls->error_idx = cnt; |
| return ret; |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int capture_s_ext_ctrls(FAR struct file *filep, |
| FAR struct v4l2_ext_controls *ctrls) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR struct v4l2_ext_control *control; |
| int ret = OK; |
| int cnt; |
| |
| if (cmng == NULL || ctrls == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| ASSERT(cmng->imgsensor); |
| |
| for (cnt = 0, control = ctrls->controls; |
| cnt < ctrls->count; |
| cnt++, control++) |
| { |
| if (control->id == V4L2_CID_SCENE_MODE) |
| { |
| ret = reflect_scene_parameter(cmng, control->value); |
| } |
| else |
| { |
| ret = IMGSENSOR_SET_VALUE(cmng->imgsensor, |
| control->id, |
| control->size, |
| (imgsensor_value_t)control->value64); |
| if (ret == 0) |
| { |
| if (cmng->capture_scene_mode == V4L2_SCENE_MODE_NONE) |
| { |
| save_scene_param(cmng, V4L2_SCENE_MODE_NONE, |
| control->id, |
| control); |
| } |
| } |
| } |
| |
| if (ret < 0) |
| { |
| /* Set cnt in that error occurred */ |
| |
| ctrls->error_idx = cnt; |
| return ret; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int capture_query_ext_ctrl_scene(FAR struct file *filep, |
| FAR struct v4s_query_ext_ctrl_scene *attr) |
| { |
| if (attr == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| return capture_query_ext_ctrl(filep, &attr->control); |
| } |
| |
| static int capture_querymenu_scene(FAR struct file *filep, |
| FAR struct v4s_querymenu_scene *menu) |
| { |
| if (menu == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| return capture_querymenu(filep, &menu->menu); |
| } |
| |
| static int capture_s_ext_ctrls_scene(FAR struct file *filep, |
| FAR struct v4s_ext_controls_scene *ctrls) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR struct v4l2_ext_control *control; |
| int ret = OK; |
| int cnt; |
| |
| if (cmng == NULL || ctrls == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| for (cnt = 0, control = ctrls->control.controls; |
| cnt < ctrls->control.count; |
| cnt++, control++) |
| { |
| ret = save_scene_param(cmng, ctrls->mode, control->id, control); |
| if (ret != OK) |
| { |
| ctrls->control.error_idx = cnt; |
| return ret; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int capture_g_ext_ctrls_scene(FAR struct file *filep, |
| FAR struct v4s_ext_controls_scene *ctrls) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR struct v4l2_ext_control *control; |
| int ret = OK; |
| int cnt; |
| |
| if (cmng == NULL || ctrls == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| for (cnt = 0, control = ctrls->control.controls; |
| cnt < ctrls->control.count; |
| cnt++, control++) |
| { |
| ret = read_scene_param(cmng, ctrls->mode, |
| control->id, |
| control); |
| if (ret != OK) |
| { |
| ctrls->control.error_idx = cnt; |
| return ret; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static int capture_enum_fmt(FAR struct file *filep, |
| FAR struct v4l2_fmtdesc *f) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| |
| if (cmng == NULL || f == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (cmng->imgsensor && cmng->imgsensor->fmtdescs) |
| { |
| if (f->index > cmng->imgsensor->fmtdescs_num) |
| { |
| return -EINVAL; |
| } |
| else |
| { |
| f->pixelformat = cmng->imgsensor->fmtdescs[f->index].pixelformat; |
| strlcpy(f->description, |
| cmng->imgsensor->fmtdescs[f->index].description, |
| sizeof(f->description)); |
| } |
| } |
| else |
| { |
| if (f->index > 0) |
| { |
| return -EINVAL; |
| } |
| |
| f->pixelformat = V4L2_PIX_FMT_UYVY; |
| } |
| |
| return 0; |
| } |
| |
| static int capture_enum_frmsize(FAR struct file *filep, |
| FAR struct v4l2_frmsizeenum *f) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| |
| if (cmng == NULL || f == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (cmng->imgsensor && cmng->imgsensor->frmsizes) |
| { |
| if (f->index > cmng->imgsensor->frmsizes_num) |
| { |
| return -EINVAL; |
| } |
| else |
| { |
| f->type = cmng->imgsensor->frmsizes[f->index].type; |
| if (f->type == V4L2_FRMSIZE_TYPE_DISCRETE) |
| { |
| f->discrete = cmng->imgsensor->frmsizes[f->index].discrete; |
| } |
| else |
| { |
| f->stepwise = cmng->imgsensor->frmsizes[f->index].stepwise; |
| } |
| } |
| } |
| else |
| { |
| if (f->index > 0) |
| { |
| return -EINVAL; |
| } |
| |
| f->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
| f->discrete.width = VIDEO_HSIZE_QVGA; |
| f->discrete.height = VIDEO_VSIZE_QVGA; |
| } |
| |
| return 0; |
| } |
| |
| static int capture_enum_frminterval(FAR struct file *filep, |
| FAR struct v4l2_frmivalenum *f) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| |
| if (cmng == NULL || f == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| if (cmng->imgsensor && cmng->imgsensor->frmintervals) |
| { |
| if (f->index > cmng->imgsensor->frmintervals_num) |
| { |
| return -EINVAL; |
| } |
| else |
| { |
| f->type = cmng->imgsensor->frmintervals[f->index].type; |
| if (f->type == V4L2_FRMIVAL_TYPE_DISCRETE) |
| { |
| f->discrete = cmng->imgsensor->frmintervals[f->index].discrete; |
| } |
| else |
| { |
| f->stepwise = cmng->imgsensor->frmintervals[f->index].stepwise; |
| } |
| } |
| } |
| else |
| { |
| if (f->index > 0) |
| { |
| return -EINVAL; |
| } |
| |
| f->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
| f->discrete.denominator = 15; |
| f->discrete.numerator = 1; |
| } |
| |
| return 0; |
| } |
| |
| /**************************************************************************** |
| * File Opterations Functions |
| ****************************************************************************/ |
| |
| static int capture_open(FAR struct file *filep) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| int ret = OK; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| nxmutex_lock(&cmng->lock_open_num); |
| if (cmng->open_num == 0) |
| { |
| /* Only in first execution, open device */ |
| |
| ret = IMGSENSOR_INIT(cmng->imgsensor); |
| if (ret == OK) |
| { |
| ret = IMGDATA_INIT(cmng->imgdata); |
| if (ret == OK) |
| { |
| initialize_resources(cmng); |
| } |
| } |
| else |
| { |
| ret = -ENODEV; |
| } |
| } |
| |
| /* In second or later execution, ret is initial value(=OK) */ |
| |
| if (ret == OK) |
| { |
| cmng->open_num++; |
| } |
| |
| nxmutex_unlock(&cmng->lock_open_num); |
| return ret; |
| } |
| |
| static int capture_close(FAR struct file *filep) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| nxmutex_lock(&cmng->lock_open_num); |
| |
| if (--cmng->open_num == 0) |
| { |
| cleanup_resources(cmng); |
| IMGSENSOR_UNINIT(cmng->imgsensor); |
| IMGDATA_UNINIT(cmng->imgdata); |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| if (cmng->unlinked) |
| { |
| nxmutex_unlock(&cmng->lock_open_num); |
| nxmutex_destroy(&cmng->lock_open_num); |
| kmm_free(cmng); |
| inode->i_private = NULL; |
| return OK; |
| } |
| |
| #endif |
| } |
| |
| nxmutex_unlock(&cmng->lock_open_num); |
| return OK; |
| } |
| |
| static int capture_mmap(FAR struct file *filep, |
| FAR struct mm_map_entry_s *map) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| size_t heapsize; |
| int ret = -EINVAL; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| type_inf = &cmng->capture_inf; |
| heapsize = get_heapsize(type_inf); |
| |
| if (map->offset >= 0 && map->offset < heapsize && |
| map->length && map->offset + map->length <= heapsize) |
| { |
| map->vaddr = type_inf->bufheap + map->offset; |
| ret = OK; |
| } |
| |
| return ret; |
| } |
| |
| static int capture_poll(FAR struct file *filep, |
| FAR struct pollfd *fds, bool setup) |
| { |
| FAR struct inode *inode = filep->f_inode; |
| FAR capture_mng_t *cmng = inode->i_private; |
| FAR capture_type_inf_t *type_inf; |
| enum v4l2_buf_type buf_type; |
| irqstate_t flags; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| buf_type = cmng->still_inf.state == CAPTURE_STATE_CAPTURE ? |
| V4L2_BUF_TYPE_STILL_CAPTURE : V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| type_inf = get_capture_type_inf(cmng, buf_type); |
| if (type_inf == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| flags = enter_critical_section(); |
| |
| if (setup) |
| { |
| if (type_inf->fds == NULL) |
| { |
| type_inf->fds = fds; |
| fds->priv = &type_inf->fds; |
| if (!video_framebuff_is_empty(&type_inf->bufinf)) |
| { |
| poll_notify(&fds, 1, POLLIN); |
| } |
| } |
| else |
| { |
| leave_critical_section(flags); |
| return -EBUSY; |
| } |
| } |
| else if (fds->priv) |
| { |
| type_inf->fds = NULL; |
| fds->priv = NULL; |
| } |
| |
| leave_critical_section(flags); |
| |
| return OK; |
| } |
| |
| #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS |
| static int capture_unlink(FAR struct inode *inode) |
| { |
| FAR capture_mng_t *cmng = inode->i_private; |
| |
| if (cmng == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| nxmutex_lock(&cmng->lock_open_num); |
| if (cmng->open_num == 0) |
| { |
| nxmutex_unlock(&cmng->lock_open_num); |
| nxmutex_destroy(&cmng->lock_open_num); |
| kmm_free(cmng); |
| inode->i_private = NULL; |
| } |
| else |
| { |
| cmng->unlinked = true; |
| nxmutex_unlock(&cmng->lock_open_num); |
| } |
| |
| nxmutex_destroy(&cmng->lock_open_num); |
| |
| return OK; |
| } |
| #endif |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| int capture_initialize(FAR const char *devpath) |
| { |
| return capture_register(devpath, |
| g_capture_data, |
| g_capture_registered_sensor, |
| g_capture_registered_sensor_num); |
| } |
| |
| int capture_uninitialize(FAR const char *devpath) |
| { |
| return capture_unregister(devpath); |
| } |
| |
| int capture_register(FAR const char *devpath, |
| FAR struct imgdata_s *data, |
| FAR struct imgsensor_s **sensors, |
| size_t sensor_num) |
| { |
| FAR capture_mng_t *cmng; |
| int ret; |
| |
| /* Input devpath Error Check */ |
| |
| if (devpath == NULL || data == NULL) |
| { |
| return -EINVAL; |
| } |
| |
| /* Initialize capture device structure */ |
| |
| cmng = kmm_zalloc(sizeof(capture_mng_t)); |
| if (cmng == NULL) |
| { |
| verr("Failed to allocate instance\n"); |
| return -ENOMEM; |
| } |
| |
| cmng->v4l2.vops = &g_capture_vops; |
| cmng->v4l2.fops = &g_capture_fops; |
| |
| cmng->imgdata = data; |
| cmng->imgsensor = get_connected_imgsensor(sensors, sensor_num); |
| if (cmng->imgsensor == NULL) |
| { |
| kmm_free(cmng); |
| return -EINVAL; |
| } |
| |
| /* Initialize mutex */ |
| |
| nxmutex_init(&cmng->lock_open_num); |
| |
| /* Register the character driver */ |
| |
| ret = video_register(devpath, (FAR struct v4l2_s *)cmng); |
| if (ret < 0) |
| { |
| verr("Failed to register driver: %d\n", ret); |
| nxmutex_destroy(&cmng->lock_open_num); |
| kmm_free(cmng); |
| return ret; |
| } |
| |
| return OK; |
| } |
| |
| int capture_unregister(FAR const char *devpath) |
| { |
| return unregister_driver(devpath); |
| } |
| |
| int imgsensor_register(FAR struct imgsensor_s *sensor) |
| { |
| FAR struct imgsensor_s **new_addr; |
| int ret = -ENOMEM; |
| |
| new_addr = kmm_realloc(g_capture_registered_sensor, sizeof(sensor) * |
| (g_capture_registered_sensor_num + 1)); |
| if (new_addr != NULL) |
| { |
| new_addr[g_capture_registered_sensor_num++] = sensor; |
| g_capture_registered_sensor = new_addr; |
| ret = OK; |
| } |
| |
| return ret; |
| } |
| |
| void imgdata_register(FAR struct imgdata_s *data) |
| { |
| g_capture_data = data; |
| } |