d499ac9d58
Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
3820 lines
101 KiB
C
3820 lines
101 KiB
C
/****************************************************************************
|
|
* 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;
|
|
FAR 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;
|
|
FAR 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)
|
|
{
|
|
uint32_t width = vf->width;
|
|
uint32_t height = vf->height;
|
|
size_t ret = width * 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;
|
|
irqstate_t flags;
|
|
int ret = OK;
|
|
|
|
if (cmng == NULL || reqbufs == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
imgdata = cmng->imgdata;
|
|
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.
|
|
*/
|
|
|
|
DEBUGASSERT(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;
|
|
uint32_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);
|
|
}
|
|
|
|
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;
|
|
}
|