nuttx/drivers/video/video.c
SPRESENSE 75a0a08a4d drivers/video: Modify control id definition
Modify control id definition to avoid duplication even if
the control ids belong to the same control class.
Also, not refer to control class in driver.
2024-03-11 15:44:39 +01:00

3520 lines
94 KiB
C

/****************************************************************************
* drivers/video/video.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 <nuttx/config.h>
#include <debug.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/video/video.h>
#include <nuttx/video/imgsensor.h>
#include <nuttx/video/imgdata.h>
#include "video_framebuff.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define MAX_VIDEO_FILE_PATH (32)
#define MAX_VIDEO_FMT (2)
#define VIDEO_FMT_MAIN (0)
#define VIDEO_FMT_SUB (1)
#define VIDEO_REMAINING_CAPNUM_INFINITY (-1)
/****************************************************************************
* Private Types
****************************************************************************/
enum video_state_e
{
VIDEO_STATE_STREAMOFF = 0, /* Capture trigger event is not received */
VIDEO_STATE_STREAMON = 1, /* Capture trigger event is received,
* but capture is not operated.
*/
VIDEO_STATE_CAPTURE = 2, /* On capture */
};
enum video_state_transition_cause
{
CAUSE_VIDEO_STOP = 0, /* Stop capture event for video stream */
CAUSE_VIDEO_START = 1, /* Start capture event for video stream */
CAUSE_VIDEO_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 video_waitend_cause_e
{
VIDEO_WAITEND_CAUSE_CAPTUREDONE = 0,
VIDEO_WAITEND_CAUSE_DQCANCEL = 1,
VIDEO_WAITEND_CAUSE_STILLSTOP = 2,
};
struct video_wait_capture_s
{
sem_t dqbuf_wait_flg;
/* Save container which capture is done */
FAR vbuf_container_t *done_container;
enum video_waitend_cause_e waitend_cause;
};
typedef struct video_wait_capture_s video_wait_capture_t;
struct video_format_s
{
uint16_t width;
uint16_t height;
uint32_t pixelformat;
};
typedef struct video_format_s video_format_t;
struct video_type_inf_s
{
mutex_t lock_state;
enum video_state_e state;
int32_t remaining_capnum;
video_wait_capture_t wait_capture;
uint8_t nr_fmt;
video_format_t fmt[MAX_VIDEO_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 video_type_inf_s video_type_inf_t;
struct video_scene_params_s
{
uint8_t mode; /* enum v4l2_scene_mode */
int32_t brightness;
int32_t contrast;
int32_t saturation;
int32_t hue;
bool awb;
int32_t red;
int32_t blue;
int32_t gamma;
uint32_t gamma_curve_sz;
uint8_t *gamma_curve;
int32_t ev;
bool hflip_video;
bool vflip_video;
bool hflip_still;
bool vflip_still;
int32_t sharpness;
enum v4l2_colorfx colorfx;
bool auto_brightness;
int32_t rotate;
enum v4l2_exposure_auto_type ae;
int32_t exposure_time;
int32_t focus;
bool af;
int32_t zoom;
int32_t iris;
enum v4l2_auto_n_preset_white_balance wb;
int32_t wdr;
bool stabilization;
enum v4l2_iso_sensitivity_auto_type iso_auto;
int32_t iso;
enum v4l2_exposure_metering meter;
int32_t spot_pos;
int32_t threea_lock;
enum v4l2_flash_led_mode led;
int32_t jpeg_quality;
};
typedef struct video_scene_params_s video_scene_params_t;
struct video_parameter_name_s
{
uint32_t id;
const char *name;
};
typedef struct video_parameter_name_s video_parameter_name_t;
struct video_mng_s
{
/* Parameter of video_initialize() */
FAR char *devpath;
mutex_t lock_open_num;
uint8_t open_num;
video_type_inf_t video_inf;
video_type_inf_t still_inf;
FAR struct imgdata_s *imgdata;
FAR struct imgsensor_s *imgsensor;
enum v4l2_scene_mode video_scene_mode;
uint8_t video_scence_num;
FAR video_scene_params_t *video_scene_param[V4L2_SCENE_MODE_MAX];
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
bool unlinked;
#endif
};
typedef struct video_mng_s video_mng_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Character driver methods. */
static int video_open(FAR struct file *filep);
static int video_close(FAR struct file *filep);
static ssize_t video_read(FAR struct file *filep,
FAR char *buffer, size_t buflen);
static ssize_t video_write(FAR struct file *filep,
FAR const char *buffer, size_t buflen);
static int video_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
static int video_mmap(FAR struct file *filep,
FAR struct mm_map_entry_s *map);
static int video_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int video_unlink(FAR struct inode *inode);
#endif
/* Common function */
static FAR video_type_inf_t *
get_video_type_inf(FAR video_mng_t *vmng, uint8_t type);
static enum video_state_e
estimate_next_video_state(FAR video_mng_t *vmng,
enum video_state_transition_cause cause);
static void change_video_state(FAR video_mng_t *vmng,
enum video_state_e next_state);
static bool is_taking_still_picture(FAR video_mng_t *vmng);
static bool is_bufsize_sufficient(FAR video_mng_t *vmng, uint32_t bufsize);
static void cleanup_resources(FAR video_mng_t *vmng);
static bool is_sem_waited(FAR sem_t *sem);
static int save_scene_param(FAR video_mng_t *vmng,
enum v4l2_scene_mode mode,
uint32_t id,
struct v4l2_ext_control *control);
static int video_complete_capture(uint8_t err_code, uint32_t datasize,
FAR const struct timeval *ts,
FAR void *arg);
static int validate_frame_setting(FAR video_mng_t *vmng,
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);
/* Internal function for each cmds of ioctl */
static int video_querycap(FAR video_mng_t *vmng,
FAR struct v4l2_capability *cap);
static int video_g_input(FAR int *num);
static int video_enum_input(FAR video_mng_t *vmng,
FAR struct v4l2_input *input);
static int video_reqbufs(FAR struct video_mng_s *vmng,
FAR struct v4l2_requestbuffers *reqbufs);
static int video_qbuf(FAR struct video_mng_s *vmng,
FAR struct v4l2_buffer *buf);
static int video_dqbuf(FAR struct video_mng_s *vmng,
FAR struct v4l2_buffer *buf,
int oflags);
static int video_cancel_dqbuf(FAR struct video_mng_s *vmng,
enum v4l2_buf_type type);
static int video_g_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *fmt);
static int video_s_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *fmt);
static int video_try_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *v4l2);
static int video_g_parm(FAR struct video_mng_s *priv,
FAR struct v4l2_streamparm *parm);
static int video_s_parm(FAR struct video_mng_s *priv,
FAR struct v4l2_streamparm *parm);
static int video_streamon(FAR struct video_mng_s *vmng,
FAR enum v4l2_buf_type *type);
static int video_streamoff(FAR struct video_mng_s *vmng,
FAR enum v4l2_buf_type *type);
static int video_do_halfpush(FAR struct video_mng_s *priv,
bool enable);
static int video_takepict_start(FAR struct video_mng_s *vmng,
int32_t capture_num);
static int video_takepict_stop(FAR struct video_mng_s *vmng,
bool halfpush);
static int video_queryctrl(FAR video_mng_t *vmng,
FAR struct v4l2_queryctrl *ctrl);
static int video_query_ext_ctrl(FAR video_mng_t *vmng,
FAR struct v4l2_query_ext_ctrl *ctrl);
static int video_querymenu(FAR video_mng_t *vmng,
FAR struct v4l2_querymenu *menu);
static int video_g_ctrl(FAR struct video_mng_s *priv,
FAR struct v4l2_control *ctrl);
static int video_s_ctrl(FAR struct video_mng_s *priv,
FAR struct v4l2_control *ctrl);
static int video_g_ext_ctrls(FAR struct video_mng_s *priv,
FAR struct v4l2_ext_controls *ctrls);
static int video_s_ext_ctrls(FAR struct video_mng_s *priv,
FAR struct v4l2_ext_controls *ctrls);
static int video_query_ext_ctrl_scene(FAR video_mng_t *vmng,
FAR struct v4s_query_ext_ctrl_scene *ctrl);
static int video_querymenu_scene(FAR video_mng_t *vmng,
FAR struct v4s_querymenu_scene *menu);
static int video_g_ext_ctrls_scene(FAR video_mng_t *vmng,
FAR struct v4s_ext_controls_scene *ctrls);
static int video_s_ext_ctrls_scene(FAR video_mng_t *vmng,
FAR struct v4s_ext_controls_scene *ctrls);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_video_fops =
{
video_open, /* open */
video_close, /* close */
video_read, /* read */
video_write, /* write */
NULL, /* seek */
video_ioctl, /* ioctl */
video_mmap, /* mmap */
NULL, /* truncate */
video_poll, /* poll */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
video_unlink, /* unlink */
#endif
};
static const video_parameter_name_t g_video_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_video_registered_sensor = NULL;
static size_t g_video_registered_sensor_num;
static FAR struct imgdata_s *g_video_data = NULL;
/****************************************************************************
* Private Functions
****************************************************************************/
static FAR video_type_inf_t *
get_video_type_inf(FAR video_mng_t *vmng, uint8_t type)
{
FAR video_type_inf_t *type_inf;
switch (type)
{
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
type_inf = &vmng->video_inf;
break;
case V4L2_BUF_TYPE_STILL_CAPTURE:
type_inf = &vmng->still_inf;
break;
default: /* Error case */
type_inf = NULL;
break;
}
return type_inf;
}
static enum video_state_e
estimate_next_video_state(FAR video_mng_t *vmng,
enum video_state_transition_cause cause)
{
enum video_state_e current_state = vmng->video_inf.state;
switch (cause)
{
case CAUSE_VIDEO_STOP:
return VIDEO_STATE_STREAMOFF;
case CAUSE_VIDEO_START:
if (is_taking_still_picture(vmng))
{
return VIDEO_STATE_STREAMON;
}
else
{
return VIDEO_STATE_CAPTURE;
}
case CAUSE_STILL_STOP:
if (current_state == VIDEO_STATE_STREAMON)
{
return VIDEO_STATE_CAPTURE;
}
else
{
return current_state;
}
case CAUSE_STILL_START:
if (current_state == VIDEO_STATE_CAPTURE)
{
return VIDEO_STATE_STREAMON;
}
else
{
return current_state;
}
case CAUSE_VIDEO_DQBUF:
if (current_state == VIDEO_STATE_STREAMON &&
!is_taking_still_picture(vmng))
{
return VIDEO_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[VIDEO_FMT_MAIN].width = clip->width;
c_fmt[VIDEO_FMT_MAIN].height = clip->height;
c_fmt[VIDEO_FMT_MAIN].pixelformat = fmt[VIDEO_FMT_MAIN].pixelformat;
if (nr_fmt > 1)
{
/* Clipped size of thumbnail is
* small as ratio of main size and thumbnal size.
*/
memcpy(&c_fmt[VIDEO_FMT_SUB],
&fmt[VIDEO_FMT_SUB],
sizeof(video_format_t));
c_fmt[VIDEO_FMT_SUB].width =
(uint32_t)c_fmt[VIDEO_FMT_SUB].width *
clip->width / fmt[VIDEO_FMT_MAIN].width;
c_fmt[VIDEO_FMT_SUB].height =
(uint32_t)c_fmt[VIDEO_FMT_SUB].height *
clip->height / fmt[VIDEO_FMT_MAIN].height;
}
}
else
{
memcpy(c_fmt, fmt, nr_fmt * sizeof(video_format_t));
}
}
static int start_capture(FAR video_mng_t *vmng,
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_VIDEO_FMT];
imgdata_format_t df[MAX_VIDEO_FMT];
imgsensor_format_t sf[MAX_VIDEO_FMT];
imgdata_interval_t di;
imgsensor_interval_t si;
ASSERT(fmt && interval && vmng->imgsensor && vmng->imgdata);
get_clipped_format(nr_fmt, fmt, clip, c_fmt);
convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_MAIN], &df[IMGDATA_FMT_MAIN]);
convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_SUB], &df[IMGDATA_FMT_SUB]);
convert_to_imgdatainterval(interval, &di);
convert_to_imgsensorfmt(&fmt[VIDEO_FMT_MAIN], &sf[IMGSENSOR_FMT_MAIN]);
convert_to_imgsensorfmt(&fmt[VIDEO_FMT_SUB], &sf[IMGSENSOR_FMT_SUB]);
convert_to_imgsensorinterval(interval, &si);
IMGDATA_SET_BUF(vmng->imgdata,
nr_fmt, df, (FAR uint8_t *)bufaddr, bufsize);
IMGDATA_START_CAPTURE(vmng->imgdata,
nr_fmt, df, &di, video_complete_capture, vmng);
IMGSENSOR_START_CAPTURE(vmng->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 video_mng_t *vmng, enum v4l2_buf_type type)
{
ASSERT(vmng->imgsensor && vmng->imgdata);
IMGDATA_STOP_CAPTURE(vmng->imgdata);
IMGSENSOR_STOP_CAPTURE(vmng->imgsensor,
type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
IMGSENSOR_STREAM_TYPE_VIDEO : IMGSENSOR_STREAM_TYPE_STILL);
}
static void change_video_state(FAR video_mng_t *vmng,
enum video_state_e next_state)
{
enum video_state_e current_state = vmng->video_inf.state;
enum video_state_e updated_next_state = next_state;
if (current_state != VIDEO_STATE_CAPTURE &&
next_state == VIDEO_STATE_CAPTURE)
{
FAR vbuf_container_t *container =
video_framebuff_get_vacant_container(&vmng->video_inf.bufinf);
if (container != NULL)
{
vmng->video_inf.seqnum = 0;
start_capture(vmng,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
vmng->video_inf.nr_fmt,
vmng->video_inf.fmt,
&vmng->video_inf.clip,
&vmng->video_inf.frame_interval,
container->buf.m.userptr,
container->buf.length);
}
else
{
updated_next_state = VIDEO_STATE_STREAMON;
}
}
else if (current_state == VIDEO_STATE_CAPTURE &&
next_state != VIDEO_STATE_CAPTURE)
{
stop_capture(vmng, V4L2_BUF_TYPE_VIDEO_CAPTURE);
}
vmng->video_inf.state = updated_next_state;
}
static bool is_taking_still_picture(FAR video_mng_t *vmng)
{
return vmng->still_inf.state == VIDEO_STATE_STREAMON ||
vmng->still_inf.state == VIDEO_STATE_CAPTURE;
}
static bool is_bufsize_sufficient(FAR video_mng_t *vmng, uint32_t bufsize)
{
/* Depend on format, frame size, and JPEG compression quality */
return true;
}
static void initialize_frame_setting(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;
fmt[VIDEO_FMT_MAIN].width = VIDEO_HSIZE_QVGA;
fmt[VIDEO_FMT_MAIN].height = VIDEO_VSIZE_QVGA;
fmt[VIDEO_FMT_MAIN].pixelformat = V4L2_PIX_FMT_UYVY;
interval->denominator = 15;
interval->numerator = 1;
}
static void initialize_streamresources(FAR video_type_inf_t *type_inf)
{
memset(type_inf, 0, sizeof(video_type_inf_t));
type_inf->remaining_capnum = VIDEO_REMAINING_CAPNUM_INFINITY;
nxmutex_init(&type_inf->lock_state);
nxsem_init(&type_inf->wait_capture.dqbuf_wait_flg, 0, 0);
initialize_frame_setting(&type_inf->nr_fmt,
type_inf->fmt,
&type_inf->frame_interval);
video_framebuff_init(&type_inf->bufinf);
}
static int32_t get_default_value(FAR video_mng_t *vmng, uint32_t id)
{
imgsensor_supported_value_t value;
int ret;
if (vmng->imgsensor == NULL)
{
/* Don't care(unsupported parameter) */
return 0;
}
ret = IMGSENSOR_GET_SUPPORTED_VALUE(vmng->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 video_mng_t *vmng, uint8_t **gamma)
{
imgsensor_supported_value_t sup_val;
imgsensor_value_t val;
int32_t sz;
int ret;
*gamma = NULL;
ASSERT(vmng->imgsensor);
ret = IMGSENSOR_GET_SUPPORTED_VALUE(vmng->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(vmng->imgsensor, IMGSENSOR_ID_GAMMA_CURVE, sz, &val);
return sz;
}
static int initialize_scene_parameter(FAR video_mng_t *vmng,
enum v4l2_scene_mode mode,
video_scene_params_t **vsp)
{
FAR video_scene_params_t *sp = kmm_malloc(sizeof(video_scene_params_t));
if (!sp)
{
return -ENOMEM;
}
sp->brightness = get_default_value(vmng, IMGSENSOR_ID_BRIGHTNESS);
sp->contrast = get_default_value(vmng, IMGSENSOR_ID_CONTRAST);
sp->saturation = get_default_value(vmng, IMGSENSOR_ID_SATURATION);
sp->hue = get_default_value(vmng, IMGSENSOR_ID_HUE);
sp->awb = get_default_value(vmng,
IMGSENSOR_ID_AUTO_WHITE_BALANCE);
sp->red = get_default_value(vmng, IMGSENSOR_ID_RED_BALANCE);
sp->blue = get_default_value(vmng, IMGSENSOR_ID_BLUE_BALANCE);
sp->gamma = get_default_value(vmng, IMGSENSOR_ID_GAMMA);
sp->gamma_curve_sz = initialize_scene_gamma(vmng, &sp->gamma_curve);
sp->ev = get_default_value(vmng, IMGSENSOR_ID_EXPOSURE);
sp->hflip_video = get_default_value(vmng, IMGSENSOR_ID_HFLIP_VIDEO);
sp->vflip_video = get_default_value(vmng, IMGSENSOR_ID_VFLIP_VIDEO);
sp->hflip_still = get_default_value(vmng, IMGSENSOR_ID_HFLIP_STILL);
sp->vflip_still = get_default_value(vmng, IMGSENSOR_ID_VFLIP_STILL);
sp->sharpness = get_default_value(vmng, IMGSENSOR_ID_SHARPNESS);
sp->colorfx = get_default_value(vmng, IMGSENSOR_ID_COLORFX);
sp->auto_brightness = get_default_value(vmng, IMGSENSOR_ID_AUTOBRIGHTNESS);
sp->rotate = get_default_value(vmng, IMGSENSOR_ID_ROTATE);
sp->ae = get_default_value(vmng, IMGSENSOR_ID_EXPOSURE_AUTO);
sp->exposure_time = get_default_value(vmng,
IMGSENSOR_ID_EXPOSURE_ABSOLUTE);
sp->focus = get_default_value(vmng, IMGSENSOR_ID_FOCUS_ABSOLUTE);
sp->af = get_default_value(vmng, IMGSENSOR_ID_FOCUS_AUTO);
sp->zoom = get_default_value(vmng, IMGSENSOR_ID_ZOOM_ABSOLUTE);
sp->iris = get_default_value(vmng, IMGSENSOR_ID_IRIS_ABSOLUTE);
sp->wb = get_default_value(vmng,
IMGSENSOR_ID_AUTO_N_PRESET_WB);
sp->wdr = get_default_value(vmng,
IMGSENSOR_ID_WIDE_DYNAMIC_RANGE);
sp->stabilization = get_default_value(vmng,
IMGSENSOR_ID_IMG_STABILIZATION);
sp->iso_auto = get_default_value(vmng,
IMGSENSOR_ID_ISO_SENSITIVITY_AUTO);
sp->iso = get_default_value(vmng,
IMGSENSOR_ID_ISO_SENSITIVITY);
sp->meter = get_default_value(vmng,
IMGSENSOR_ID_EXPOSURE_METERING);
sp->threea_lock = get_default_value(vmng, IMGSENSOR_ID_3A_LOCK);
sp->led = get_default_value(vmng, IMGSENSOR_ID_FLASH_LED_MODE);
sp->jpeg_quality = get_default_value(vmng, IMGSENSOR_ID_JPEG_QUALITY);
*vsp = sp;
return OK;
}
static void initialize_scenes_parameter(FAR video_mng_t *vmng)
{
memset(vmng->video_scene_param,
0, sizeof(vmng->video_scene_param));
initialize_scene_parameter(vmng, V4L2_SCENE_MODE_NONE,
&vmng->video_scene_param[vmng->video_scence_num++]);
#ifdef CONFIG_VIDEO_SCENE_BACKLIGHT
initialize_scene_parameter(vmng, V4L2_SCENE_MODE_BACKLIGHT,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_BACKLIGHT */
#ifdef CONFIG_VIDEO_SCENE_BEACHSNOW
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_BEACHSNOW,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_BEACHSNOW */
#ifdef CONFIG_VIDEO_SCENE_CANDLELIGHT
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_CANDLELIGHT,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_CANDLELIGHT */
#ifdef CONFIG_VIDEO_SCENE_DAWNDUSK
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_DAWNDUSK,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_DAWNDUSK */
#ifdef CONFIG_VIDEO_SCENE_FALLCOLORS
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_FALLCOLORS,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_FALLCOLORS */
#ifdef CONFIG_VIDEO_SCENE_FIREWORKS
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_FIREWORKS,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_FIREWORKS */
#ifdef CONFIG_VIDEO_SCENE_LANDSCAPE
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_LANDSCAPE,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_LANDSCAPE */
#ifdef CONFIG_VIDEO_SCENE_NIGHT
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_NIGHT,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_NIGHT */
#ifdef CONFIG_VIDEO_SCENE_PARTYINDOOR
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_PARTYINDOOR,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_PARTYINDOOR */
#ifdef CONFIG_VIDEO_SCENE_PORTRAIT
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_PORTRAIT,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_PORTRAIT */
#ifdef CONFIG_VIDEO_SCENE_SPORTS
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_SPORTS,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_SPORTS */
#ifdef CONFIG_VIDEO_SCENE_SUNSET
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_SUNSET,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_SUNSET */
#ifdef CONFIG_VIDEO_SCENE_TEXT
initialize_scene_parameter(vmng, CONFIG_VIDEO_SCENE_TEXT,
&vmng->video_scene_param[vmng->video_scence_num++]);
#endif /* CONFIG_VIDEO_SCENE_TEXT */
}
static void initialize_resources(FAR video_mng_t *vmng)
{
initialize_streamresources(&vmng->video_inf);
initialize_streamresources(&vmng->still_inf);
initialize_scenes_parameter(vmng);
}
static void cleanup_streamresources(FAR video_type_inf_t *type_inf)
{
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)
{
kumm_free(type_inf->bufheap);
type_inf->bufheap = NULL;
}
}
static void cleanup_scene_parameter(FAR video_scene_params_t **vsp)
{
FAR video_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 video_mng_t *vmng)
{
int i;
for (i = 0; i < vmng->video_scence_num; i++)
{
cleanup_scene_parameter(&vmng->video_scene_param[i]);
}
vmng->video_scence_num = 0;
}
static void cleanup_resources(FAR video_mng_t *vmng)
{
/* If in capture, stop */
if (vmng->video_inf.state == VIDEO_STATE_CAPTURE)
{
stop_capture(vmng, V4L2_BUF_TYPE_VIDEO_CAPTURE);
}
if (vmng->still_inf.state == VIDEO_STATE_CAPTURE)
{
stop_capture(vmng, V4L2_BUF_TYPE_STILL_CAPTURE);
}
/* Clean up resource */
cleanup_streamresources(&vmng->video_inf);
cleanup_streamresources(&vmng->still_inf);
cleanup_scenes_parameter(vmng);
}
static bool is_sem_waited(FAR sem_t *sem)
{
int semcount;
return nxsem_get_value(sem, &semcount) == OK && semcount < 0;
}
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;
}
static int video_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR video_mng_t *priv = inode->i_private;
int ret = OK;
nxmutex_lock(&priv->lock_open_num);
if (priv->open_num == 0)
{
/* Only in first execution, open device */
ret = IMGSENSOR_INIT(priv->imgsensor);
if (ret == OK)
{
ret = IMGDATA_INIT(priv->imgdata);
if (ret == OK)
{
initialize_resources(priv);
}
}
else
{
ret = -ENODEV;
}
}
/* In second or later execution, ret is initial value(=OK) */
if (ret == OK)
{
priv->open_num++;
}
nxmutex_unlock(&priv->lock_open_num);
return ret;
}
static int video_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR video_mng_t *priv = inode->i_private;
nxmutex_lock(&priv->lock_open_num);
if (--priv->open_num == 0)
{
cleanup_resources(priv);
IMGSENSOR_UNINIT(priv->imgsensor);
IMGDATA_UNINIT(priv->imgdata);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
if (priv->unlinked)
{
nxmutex_unlock(&priv->lock_open_num);
nxmutex_destroy(&priv->lock_open_num);
kmm_free(priv->devpath);
kmm_free(priv);
inode->i_private = NULL;
return OK;
}
#endif
}
nxmutex_unlock(&priv->lock_open_num);
return OK;
}
static ssize_t video_read(FAR struct file *filep,
FAR char *buffer, size_t buflen)
{
return -ENOTSUP;
}
static ssize_t video_write(FAR struct file *filep,
FAR const char *buffer, size_t buflen)
{
return -ENOTSUP;
}
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int video_unlink(FAR struct inode *inode)
{
FAR video_mng_t *priv = inode->i_private;
nxmutex_lock(&priv->lock_open_num);
if (priv->open_num == 0)
{
nxmutex_unlock(&priv->lock_open_num);
nxmutex_destroy(&priv->lock_open_num);
kmm_free(priv->devpath);
kmm_free(priv);
inode->i_private = NULL;
}
else
{
priv->unlinked = true;
nxmutex_unlock(&priv->lock_open_num);
}
return OK;
}
#endif
static int video_querycap(FAR video_mng_t *vmng,
FAR struct v4l2_capability *cap)
{
FAR const char *name;
ASSERT(vmng->imgsensor);
if (cap == NULL)
{
return -EINVAL;
}
name = IMGSENSOR_GET_DRIVER_NAME(vmng->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 video_g_input(FAR int *num)
{
*num = 0;
return OK;
}
static int video_enum_input(FAR video_mng_t *vmng,
FAR struct v4l2_input *input)
{
FAR const char *name;
ASSERT(vmng->imgsensor);
if (input->index > 0)
{
return -EINVAL;
}
name = IMGSENSOR_GET_DRIVER_NAME(vmng->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 video_reqbufs(FAR struct video_mng_s *vmng,
FAR struct v4l2_requestbuffers *reqbufs)
{
FAR video_type_inf_t *type_inf;
irqstate_t flags;
int ret = OK;
if (vmng == NULL || reqbufs == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, reqbufs->type);
if (type_inf == NULL)
{
return -EINVAL;
}
flags = enter_critical_section();
if (type_inf->state == VIDEO_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)
{
kumm_free(type_inf->bufheap);
}
type_inf->bufheap = kumm_memalign(32,
reqbufs->count * get_bufsize(&type_inf->fmt[VIDEO_FMT_MAIN]));
if (type_inf->bufheap == NULL)
{
ret = -ENOMEM;
}
}
}
leave_critical_section(flags);
return ret;
}
static int video_querybuf(FAR struct video_mng_s *vmng,
FAR struct v4l2_buffer *buf)
{
FAR video_type_inf_t *type_inf;
if (vmng == NULL || buf == NULL || buf->memory != V4L2_MEMORY_MMAP)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, 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[VIDEO_FMT_MAIN]);
buf->m.offset = buf->length * buf->index;
return OK;
}
static int video_qbuf(FAR struct video_mng_s *vmng,
FAR struct v4l2_buffer *buf)
{
FAR video_type_inf_t *type_inf;
FAR vbuf_container_t *container;
enum video_state_e next_video_state;
irqstate_t flags;
if (vmng == NULL || buf == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, buf->type);
if (type_inf == NULL)
{
return -EINVAL;
}
if (!is_bufsize_sufficient(vmng, 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[VIDEO_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 == VIDEO_STATE_STREAMON)
{
leave_critical_section(flags);
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
{
nxmutex_lock(&vmng->still_inf.lock_state);
next_video_state =
estimate_next_video_state(vmng, CAUSE_VIDEO_START);
change_video_state(vmng, next_video_state);
nxmutex_unlock(&vmng->still_inf.lock_state);
}
else
{
container =
video_framebuff_get_vacant_container(&type_inf->bufinf);
if (container != NULL)
{
type_inf->seqnum = 0;
start_capture(vmng,
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 = VIDEO_STATE_CAPTURE;
}
}
}
else
{
leave_critical_section(flags);
}
nxmutex_unlock(&type_inf->lock_state);
return OK;
}
static int video_dqbuf(FAR struct video_mng_s *vmng,
FAR struct v4l2_buffer *buf,
int oflags)
{
irqstate_t flags;
FAR video_type_inf_t *type_inf;
FAR vbuf_container_t *container;
FAR sem_t *dqbuf_wait_flg;
enum video_state_e next_video_state;
if (vmng == NULL || buf == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, buf->type);
if (type_inf == NULL)
{
return -EINVAL;
}
container = video_framebuff_dq_valid_container(&type_inf->bufinf);
if (container == NULL)
{
if (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_video_state =
estimate_next_video_state(vmng, CAUSE_VIDEO_DQBUF);
change_video_state(vmng, next_video_state);
leave_critical_section(flags);
}
nxsem_wait_uninterruptible(dqbuf_wait_flg);
}
while (type_inf->wait_capture.waitend_cause ==
VIDEO_WAITEND_CAUSE_STILLSTOP);
container = type_inf->wait_capture.done_container;
if (container == NULL)
{
/* Waking up without captured data means abort.
* Therefore, Check cause.
*/
if (type_inf->wait_capture.waitend_cause ==
VIDEO_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 video_cancel_dqbuf(FAR struct video_mng_s *vmng,
enum v4l2_buf_type type)
{
FAR video_type_inf_t *type_inf;
type_inf = get_video_type_inf(vmng, 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 = VIDEO_WAITEND_CAUSE_DQCANCEL;
/* If capture is done before nxsem_post, cause is overwritten */
return nxsem_post(&type_inf->wait_capture.dqbuf_wait_flg);
}
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 int video_s_selection(FAR struct video_mng_s *vmng,
FAR struct v4l2_selection *clip)
{
FAR video_type_inf_t *type_inf;
uint32_t p_u32[IMGSENSOR_CLIP_NELEM];
imgsensor_value_t val;
int32_t id;
int ret;
ASSERT(vmng && vmng->imgsensor);
if (clip == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, clip->type);
if (type_inf == NULL)
{
return -EINVAL;
}
if (type_inf->state != VIDEO_STATE_STREAMOFF)
{
return -EBUSY;
}
if (!validate_clip_setting(&clip->r, type_inf->fmt))
{
return -EINVAL;
}
ret = validate_frame_setting(vmng,
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(vmng->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 video_g_selection(FAR struct video_mng_s *vmng,
FAR struct v4l2_selection *clip)
{
FAR video_type_inf_t *type_inf;
ASSERT(vmng);
if (clip == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, clip->type);
if (type_inf == NULL)
{
return -EINVAL;
}
memcpy(&clip->r, &type_inf->clip, sizeof(struct v4l2_rect));
return OK;
}
static int validate_frame_setting(FAR video_mng_t *vmng,
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_VIDEO_FMT];
imgdata_format_t df[MAX_VIDEO_FMT];
imgsensor_format_t sf[MAX_VIDEO_FMT];
imgdata_interval_t di;
imgsensor_interval_t si;
int ret;
ASSERT(vfmt && interval && vmng->imgsensor && vmng->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[VIDEO_FMT_MAIN], &df[IMGDATA_FMT_MAIN]);
convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_SUB], &df[IMGDATA_FMT_SUB]);
convert_to_imgdatainterval(interval, &di);
convert_to_imgsensorfmt(&vfmt[VIDEO_FMT_MAIN], &sf[IMGSENSOR_FMT_MAIN]);
convert_to_imgsensorfmt(&vfmt[VIDEO_FMT_SUB], &sf[IMGSENSOR_FMT_SUB]);
convert_to_imgsensorinterval(interval, &si);
ret = IMGSENSOR_VALIDATE_FRAME_SETTING(vmng->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(vmng->imgdata, nr_fmt, df, &di);
}
static size_t get_bufsize(FAR video_format_t *vf)
{
size_t ret = vf->width * vf->height;
switch (vf->pixelformat)
{
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_YUV420:
return ret * 3 / 2;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_JPEG:
default:
return ret * 2;
}
}
static size_t get_heapsize(FAR video_type_inf_t *type_inf)
{
return type_inf->bufinf.container_size *
get_bufsize(&type_inf->fmt[VIDEO_FMT_MAIN]);
}
static int video_try_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *v4l2)
{
FAR video_type_inf_t *type_inf;
video_format_t vf[MAX_VIDEO_FMT];
uint8_t nr_fmt;
ASSERT(priv && priv->imgsensor && priv->imgdata);
if (v4l2 == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(priv, v4l2->type);
if (type_inf == NULL)
{
return -EINVAL;
}
switch (v4l2->fmt.pix.pixelformat)
{
case V4L2_PIX_FMT_SUBIMG_UYVY:
case V4L2_PIX_FMT_SUBIMG_RGB565:
if (type_inf->fmt[VIDEO_FMT_MAIN].pixelformat !=
V4L2_PIX_FMT_JPEG_WITH_SUBIMG)
{
return -EPERM;
}
/* Validate both main image and subimage. */
nr_fmt = 2;
memcpy(&vf[VIDEO_FMT_MAIN],
&type_inf->fmt[VIDEO_FMT_MAIN],
sizeof(video_format_t));
vf[VIDEO_FMT_SUB].width = v4l2->fmt.pix.width;
vf[VIDEO_FMT_SUB].height = v4l2->fmt.pix.height;
vf[VIDEO_FMT_SUB].pixelformat =
v4l2->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[VIDEO_FMT_MAIN].width = v4l2->fmt.pix.width;
vf[VIDEO_FMT_MAIN].height = v4l2->fmt.pix.height;
vf[VIDEO_FMT_MAIN].pixelformat = v4l2->fmt.pix.pixelformat;
break;
default:
return -EINVAL;
}
return validate_frame_setting(priv,
v4l2->type,
nr_fmt,
vf,
&type_inf->clip,
&type_inf->frame_interval);
}
static int video_g_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *fmt)
{
FAR video_type_inf_t *type_inf;
type_inf = get_video_type_inf(priv, fmt->type);
if (type_inf == NULL)
{
return -EINVAL;
}
memset(&fmt->fmt, 0, sizeof(fmt->fmt));
fmt->fmt.pix.width = type_inf->fmt[VIDEO_FMT_MAIN].width;
fmt->fmt.pix.height = type_inf->fmt[VIDEO_FMT_MAIN].height;
fmt->fmt.pix.pixelformat = type_inf->fmt[VIDEO_FMT_MAIN].pixelformat;
return OK;
}
static int video_s_fmt(FAR struct video_mng_s *priv,
FAR struct v4l2_format *fmt)
{
FAR video_type_inf_t *type_inf;
int ret;
ret = video_try_fmt(priv, fmt);
if (ret != 0)
{
return ret;
}
type_inf = get_video_type_inf(priv, fmt->type);
if (type_inf == NULL)
{
return -EINVAL;
}
if (type_inf->state != VIDEO_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[VIDEO_FMT_MAIN].pixelformat !=
V4L2_PIX_FMT_JPEG_WITH_SUBIMG)
{
return -EPERM;
}
type_inf->fmt[VIDEO_FMT_SUB].width = fmt->fmt.pix.width;
type_inf->fmt[VIDEO_FMT_SUB].height = fmt->fmt.pix.height;
type_inf->fmt[VIDEO_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[VIDEO_FMT_MAIN].width = fmt->fmt.pix.width;
type_inf->fmt[VIDEO_FMT_MAIN].height = fmt->fmt.pix.height;
type_inf->fmt[VIDEO_FMT_MAIN].pixelformat = fmt->fmt.pix.pixelformat;
type_inf->nr_fmt = 1;
break;
}
return OK;
}
static int video_s_parm(FAR struct video_mng_s *priv,
FAR struct v4l2_streamparm *parm)
{
FAR video_type_inf_t *type_inf;
int ret;
ASSERT(priv->imgsensor && priv->imgdata);
type_inf = get_video_type_inf(priv, parm->type);
if (type_inf == NULL)
{
return -EINVAL;
}
if (type_inf->state != VIDEO_STATE_STREAMOFF)
{
return -EBUSY;
}
ret = validate_frame_setting(priv,
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 video_g_parm(FAR struct video_mng_s *vmng,
FAR struct v4l2_streamparm *parm)
{
FAR video_type_inf_t *type_inf;
int ret = -EINVAL;
DEBUGASSERT(vmng && vmng->imgsensor);
type_inf = get_video_type_inf(vmng, parm->type);
if (type_inf == NULL)
{
return -EINVAL;
}
memset(&parm->parm, 0, sizeof(parm->parm));
if (type_inf->state == VIDEO_STATE_CAPTURE)
{
/* If capture is started and lower driver has the get_frame_interval(),
* query lower driver.
*/
ret = IMGSENSOR_GET_FRAME_INTERVAL(vmng->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 video_streamon(FAR struct video_mng_s *vmng,
FAR enum v4l2_buf_type *type)
{
FAR video_type_inf_t *type_inf;
enum video_state_e next_video_state;
int ret = OK;
if (vmng == NULL || type == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, *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 != VIDEO_STATE_STREAMOFF)
{
ret = -EPERM;
}
else
{
next_video_state =
estimate_next_video_state(vmng, CAUSE_VIDEO_START);
change_video_state(vmng, next_video_state);
}
nxmutex_unlock(&type_inf->lock_state);
return ret;
}
static int video_streamoff(FAR struct video_mng_s *vmng,
FAR enum v4l2_buf_type *type)
{
FAR video_type_inf_t *type_inf;
enum video_state_e next_video_state;
irqstate_t flags;
int ret = OK;
if (vmng == NULL || type == NULL)
{
return -EINVAL;
}
type_inf = get_video_type_inf(vmng, *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 == VIDEO_STATE_STREAMOFF)
{
ret = -EPERM;
}
else
{
next_video_state =
estimate_next_video_state(vmng, CAUSE_VIDEO_STOP);
change_video_state(vmng, next_video_state);
}
leave_critical_section(flags);
return ret;
}
static int video_do_halfpush(FAR struct video_mng_s *priv, 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 video_s_ext_ctrls(priv, &ext_controls);
}
static int video_takepict_start(FAR struct video_mng_s *vmng,
int32_t capture_num)
{
enum video_state_e next_video_state;
FAR vbuf_container_t *container;
irqstate_t flags;
int ret = OK;
if (vmng == NULL)
{
return -EINVAL;
}
nxmutex_lock(&vmng->still_inf.lock_state);
if (vmng->still_inf.state != VIDEO_STATE_STREAMOFF)
{
ret = -EPERM;
}
else
{
if (capture_num > 0)
{
vmng->still_inf.remaining_capnum = capture_num;
}
else
{
vmng->still_inf.remaining_capnum = VIDEO_REMAINING_CAPNUM_INFINITY;
}
/* Control video stream prior to still stream */
flags = enter_critical_section();
next_video_state = estimate_next_video_state(vmng,
CAUSE_STILL_START);
change_video_state(vmng, next_video_state);
leave_critical_section(flags);
container =
video_framebuff_get_vacant_container(&vmng->still_inf.bufinf);
if (container != NULL)
{
/* Start still stream capture */
start_capture(vmng,
V4L2_BUF_TYPE_STILL_CAPTURE,
vmng->still_inf.nr_fmt,
vmng->still_inf.fmt,
&vmng->still_inf.clip,
&vmng->still_inf.frame_interval,
container->buf.m.userptr,
container->buf.length);
vmng->still_inf.state = VIDEO_STATE_CAPTURE;
}
else
{
vmng->still_inf.state = VIDEO_STATE_STREAMON;
}
}
nxmutex_unlock(&vmng->still_inf.lock_state);
return ret;
}
static int video_takepict_stop(FAR struct video_mng_s *vmng, bool halfpush)
{
enum video_state_e next_video_state;
irqstate_t flags;
int ret = OK;
if (vmng == NULL)
{
return -EINVAL;
}
nxmutex_lock(&vmng->still_inf.lock_state);
if (vmng->still_inf.state == VIDEO_STATE_STREAMOFF &&
vmng->still_inf.remaining_capnum == VIDEO_REMAINING_CAPNUM_INFINITY)
{
ret = -EPERM;
}
else
{
flags = enter_critical_section();
if (vmng->still_inf.state == VIDEO_STATE_CAPTURE)
{
stop_capture(vmng, V4L2_BUF_TYPE_STILL_CAPTURE);
}
leave_critical_section(flags);
vmng->still_inf.state = VIDEO_STATE_STREAMOFF;
vmng->still_inf.remaining_capnum = VIDEO_REMAINING_CAPNUM_INFINITY;
/* Control video stream */
nxmutex_lock(&vmng->video_inf.lock_state);
next_video_state = estimate_next_video_state(vmng,
CAUSE_STILL_STOP);
change_video_state(vmng, next_video_state);
nxmutex_unlock(&vmng->video_inf.lock_state);
}
nxmutex_unlock(&vmng->still_inf.lock_state);
return ret;
}
static int video_queryctrl(FAR video_mng_t *vmng,
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 = video_query_ext_ctrl(vmng, &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 void set_parameter_name(uint32_t id, char *name)
{
int size =
sizeof(g_video_parameter_name) / sizeof(video_parameter_name_t);
int cnt;
for (cnt = 0; cnt < size; cnt++)
{
if (g_video_parameter_name[cnt].id == id)
{
break;
}
}
ASSERT(cnt < size);
/* copy size = 32 is due to V4L2 specification. */
strlcpy(name, g_video_parameter_name[cnt].name, 32);
}
static int video_query_ext_ctrl(FAR struct video_mng_s *vmng,
FAR struct v4l2_query_ext_ctrl *attr)
{
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;
ASSERT(vmng->imgsensor);
if (attr == NULL)
{
return -EINVAL;
}
attr->flags = 0;
attr->elem_size = 0;
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 = vmng->video_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(vmng->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 video_querymenu(FAR video_mng_t *vmng,
FAR struct v4l2_querymenu *menu)
{
imgsensor_supported_value_t value;
int ret;
ASSERT(vmng->imgsensor);
if (menu == NULL)
{
return -EINVAL;
}
if (menu->id == V4L2_CID_SCENE_MODE)
{
/* Scene mode is processed in only video driver. */
if (menu->index > vmng->video_scence_num - 1)
{
return -EINVAL;
}
menu->value = vmng->video_scene_param[menu->index]->mode;
}
else
{
ret = IMGSENSOR_GET_SUPPORTED_VALUE(vmng->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 video_g_ctrl(FAR struct video_mng_s *priv,
FAR struct v4l2_control *ctrl)
{
struct v4l2_ext_controls ext_controls;
struct v4l2_ext_control control;
int ret;
memset(&ext_controls, 0, sizeof(struct v4l2_ext_controls));
memset(&control, 0, sizeof(struct v4l2_ext_control));
if (ctrl == NULL)
{
return -EINVAL;
}
/* 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 = video_g_ext_ctrls(priv, &ext_controls);
if (ret == OK)
{
/* Replace gotten value to VIDIOC_G_CTRL parameter */
ctrl->value = control.value;
}
return ret;
}
static int video_s_ctrl(FAR struct video_mng_s *priv,
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 video_s_ext_ctrls(priv, &ext_controls);
}
static int video_g_ext_ctrls(FAR struct video_mng_s *priv,
FAR struct v4l2_ext_controls *ctrls)
{
FAR struct v4l2_ext_control *control;
int ret = OK;
int cnt;
ASSERT(priv->imgsensor);
if (priv == NULL || ctrls == NULL)
{
return -EINVAL;
}
for (cnt = 0, control = ctrls->controls;
cnt < ctrls->count;
cnt++, control++)
{
ret = IMGSENSOR_GET_VALUE(priv->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 set_intvalue(FAR video_mng_t *vmng,
uint32_t id, int32_t value32)
{
imgsensor_value_t value;
ASSERT(vmng->imgsensor);
value.value32 = value32;
return IMGSENSOR_SET_VALUE(vmng->imgsensor, id, sizeof(int32_t), value);
}
static int set_pvalue(FAR video_mng_t *vmng,
uint32_t id, int size, void *pval)
{
imgsensor_value_t value;
ASSERT(vmng->imgsensor);
value.p_u8 = (FAR uint8_t *)pval;
return IMGSENSOR_SET_VALUE(vmng->imgsensor, id, size, value);
}
static video_scene_params_t *search_scene_param(FAR video_mng_t *vmng,
enum v4l2_scene_mode mode)
{
int i;
for (i = 0; i < vmng->video_scence_num; i++)
{
if (vmng->video_scene_param[i]->mode == mode)
{
return vmng->video_scene_param[i];
}
}
return NULL;
}
static int reflect_scene_parameter(FAR video_mng_t *vmng,
enum v4l2_scene_mode mode)
{
video_scene_params_t *sp;
sp = search_scene_param(vmng, mode);
if (sp == NULL)
{
/* Unsupported scene mode */
return -EINVAL;
}
set_intvalue(vmng, IMGSENSOR_ID_BRIGHTNESS, sp->brightness);
set_intvalue(vmng, IMGSENSOR_ID_CONTRAST, sp->contrast);
set_intvalue(vmng, IMGSENSOR_ID_SATURATION, sp->saturation);
set_intvalue(vmng, IMGSENSOR_ID_HUE , sp->hue);
set_intvalue(vmng, IMGSENSOR_ID_AUTO_WHITE_BALANCE, sp->awb);
set_intvalue(vmng, IMGSENSOR_ID_RED_BALANCE , sp->red);
set_intvalue(vmng, IMGSENSOR_ID_BLUE_BALANCE, sp->blue);
set_intvalue(vmng, IMGSENSOR_ID_GAMMA, sp->gamma);
set_pvalue(vmng, IMGSENSOR_ID_GAMMA_CURVE,
sp->gamma_curve_sz, sp->gamma_curve);
set_intvalue(vmng, IMGSENSOR_ID_EXPOSURE, sp->ev);
set_intvalue(vmng, IMGSENSOR_ID_HFLIP_VIDEO, sp->hflip_video);
set_intvalue(vmng, IMGSENSOR_ID_VFLIP_VIDEO, sp->vflip_video);
set_intvalue(vmng, IMGSENSOR_ID_HFLIP_STILL, sp->hflip_still);
set_intvalue(vmng, IMGSENSOR_ID_VFLIP_STILL, sp->vflip_still);
set_intvalue(vmng, IMGSENSOR_ID_SHARPNESS, sp->sharpness);
set_intvalue(vmng, IMGSENSOR_ID_COLORFX, sp->colorfx);
set_intvalue(vmng, IMGSENSOR_ID_AUTOBRIGHTNESS, sp->auto_brightness);
set_intvalue(vmng, IMGSENSOR_ID_ROTATE, sp->rotate);
set_intvalue(vmng, IMGSENSOR_ID_EXPOSURE_AUTO, sp->ae);
if (sp->ae == V4L2_EXPOSURE_MANUAL ||
sp->ae == V4L2_EXPOSURE_SHUTTER_PRIORITY)
{
set_intvalue(vmng, IMGSENSOR_ID_EXPOSURE_ABSOLUTE, sp->exposure_time);
}
set_intvalue(vmng, IMGSENSOR_ID_FOCUS_ABSOLUTE, sp->focus);
set_intvalue(vmng, IMGSENSOR_ID_FOCUS_AUTO, sp->af);
set_intvalue(vmng, IMGSENSOR_ID_ZOOM_ABSOLUTE, sp->zoom);
if (sp->ae == V4L2_EXPOSURE_MANUAL ||
sp->ae == V4L2_EXPOSURE_APERTURE_PRIORITY)
{
set_intvalue(vmng, IMGSENSOR_ID_IRIS_ABSOLUTE, sp->iris);
}
set_intvalue(vmng, IMGSENSOR_ID_AUTO_N_PRESET_WB, sp->wb);
set_intvalue(vmng, IMGSENSOR_ID_WIDE_DYNAMIC_RANGE, sp->wdr);
set_intvalue(vmng, IMGSENSOR_ID_IMG_STABILIZATION, sp->stabilization);
set_intvalue(vmng, IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, sp->iso_auto);
if (sp->iso_auto == V4L2_ISO_SENSITIVITY_MANUAL)
{
set_intvalue(vmng, IMGSENSOR_ID_ISO_SENSITIVITY, sp->iso);
}
set_intvalue(vmng, IMGSENSOR_ID_EXPOSURE_METERING, sp->meter);
set_intvalue(vmng, IMGSENSOR_ID_3A_LOCK, sp->threea_lock);
set_intvalue(vmng, IMGSENSOR_ID_FLASH_LED_MODE, sp->led);
set_intvalue(vmng, IMGSENSOR_ID_JPEG_QUALITY, sp->jpeg_quality);
vmng->video_scene_mode = mode;
return OK;
}
static int video_s_ext_ctrls(FAR struct video_mng_s *priv,
FAR struct v4l2_ext_controls *ctrls)
{
FAR struct v4l2_ext_control *control;
int ret = OK;
int cnt;
ASSERT(priv->imgsensor);
if (priv == NULL || ctrls == NULL)
{
return -EINVAL;
}
for (cnt = 0, control = ctrls->controls;
cnt < ctrls->count;
cnt++, control++)
{
if (control->id == V4L2_CID_SCENE_MODE)
{
ret = reflect_scene_parameter(priv, control->value);
}
else
{
ret = IMGSENSOR_SET_VALUE(priv->imgsensor,
control->id,
control->size,
(imgsensor_value_t)control->value64);
if (ret == 0)
{
if (priv->video_scene_mode == V4L2_SCENE_MODE_NONE)
{
save_scene_param(priv, 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 video_query_ext_ctrl_scene(FAR video_mng_t *vmng,
FAR struct v4s_query_ext_ctrl_scene *attr)
{
if (attr == NULL)
{
return -EINVAL;
}
return video_query_ext_ctrl(vmng, &attr->control);
}
static int video_querymenu_scene(FAR video_mng_t *vmng,
FAR struct v4s_querymenu_scene *menu)
{
if (menu == NULL)
{
return -EINVAL;
}
return video_querymenu(vmng, &menu->menu);
}
static int read_scene_param(FAR struct video_mng_s *vmng,
enum v4l2_scene_mode mode,
uint32_t id,
struct v4l2_ext_control *control)
{
imgsensor_supported_value_t value;
video_scene_params_t *sp;
int ret = OK;
ASSERT(vmng->imgsensor);
if (control == NULL)
{
return -EINVAL;
}
sp = search_scene_param(vmng, mode);
if (sp == NULL)
{
/* Unsupported scene mode */
return -EINVAL;
}
ret = IMGSENSOR_GET_SUPPORTED_VALUE(vmng->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 video_g_ext_ctrls_scene(FAR video_mng_t *vmng,
FAR struct v4s_ext_controls_scene *ctrls)
{
FAR struct v4l2_ext_control *control;
int ret = OK;
int cnt;
if (ctrls == NULL)
{
return -EINVAL;
}
for (cnt = 0, control = ctrls->control.controls;
cnt < ctrls->control.count;
cnt++, control++)
{
ret = read_scene_param(vmng, ctrls->mode,
control->id,
control);
if (ret != OK)
{
ctrls->control.error_idx = cnt;
return ret;
}
}
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 video_mng_t *vmng,
enum v4l2_scene_mode mode,
uint32_t id,
struct v4l2_ext_control *control)
{
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;
video_scene_params_t *sp;
int ret;
int i;
ASSERT(vmng->imgsensor);
sp = search_scene_param(vmng, mode);
if (sp == NULL)
{
/* Unsupported scene mode */
return -EINVAL;
}
ret = IMGSENSOR_GET_SUPPORTED_VALUE(vmng->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;
}
static int video_s_ext_ctrls_scene(FAR struct video_mng_s *vmng,
FAR struct v4s_ext_controls_scene *ctrls)
{
FAR struct v4l2_ext_control *control;
int ret = OK;
int cnt;
if (ctrls == NULL)
{
return -EINVAL;
}
for (cnt = 0, control = ctrls->control.controls;
cnt < ctrls->control.count;
cnt++, control++)
{
ret = save_scene_param(vmng, ctrls->mode, control->id, control);
if (ret != OK)
{
ctrls->control.error_idx = cnt;
return ret;
}
}
return ret;
}
/****************************************************************************
* Name: video_ioctl
*
* Description:
* Standard character driver ioctl method.
*
****************************************************************************/
static int video_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR video_mng_t *priv = inode->i_private;
int ret = OK;
switch (cmd)
{
case VIDIOC_QUERYCAP:
ret = video_querycap(priv, (FAR struct v4l2_capability *)arg);
break;
case VIDIOC_G_INPUT:
ret = video_g_input((FAR int *)arg);
break;
case VIDIOC_ENUMINPUT:
ret = video_enum_input(priv, (FAR struct v4l2_input *)arg);
break;
case VIDIOC_REQBUFS:
ret = video_reqbufs(priv, (FAR struct v4l2_requestbuffers *)arg);
break;
case VIDIOC_QUERYBUF:
ret = video_querybuf(priv, (FAR struct v4l2_buffer *)arg);
break;
case VIDIOC_QBUF:
ret = video_qbuf(priv, (FAR struct v4l2_buffer *)arg);
break;
case VIDIOC_DQBUF:
ret = video_dqbuf(priv, (FAR struct v4l2_buffer *)arg,
filep->f_oflags);
break;
case VIDIOC_CANCEL_DQBUF:
ret = video_cancel_dqbuf(priv, (FAR enum v4l2_buf_type)arg);
break;
case VIDIOC_STREAMON:
ret = video_streamon(priv, (FAR enum v4l2_buf_type *)arg);
break;
case VIDIOC_STREAMOFF:
ret = video_streamoff(priv, (FAR enum v4l2_buf_type *)arg);
break;
case VIDIOC_DO_HALFPUSH:
ret = video_do_halfpush(priv, arg);
break;
case VIDIOC_TAKEPICT_START:
ret = video_takepict_start(priv, (int32_t)arg);
break;
case VIDIOC_TAKEPICT_STOP:
ret = video_takepict_stop(priv, arg);
break;
case VIDIOC_S_SELECTION:
ret = video_s_selection(priv, (FAR struct v4l2_selection *)arg);
break;
case VIDIOC_G_SELECTION:
ret = video_g_selection(priv, (FAR struct v4l2_selection *)arg);
break;
case VIDIOC_TRY_FMT:
ret = video_try_fmt(priv, (FAR struct v4l2_format *)arg);
break;
case VIDIOC_G_FMT:
ret = video_g_fmt(priv, (FAR struct v4l2_format *)arg);
break;
case VIDIOC_S_FMT:
ret = video_s_fmt(priv, (FAR struct v4l2_format *)arg);
break;
case VIDIOC_S_PARM:
ret = video_s_parm(priv, (FAR struct v4l2_streamparm *)arg);
break;
case VIDIOC_G_PARM:
ret = video_g_parm(priv, (FAR struct v4l2_streamparm *)arg);
break;
case VIDIOC_QUERYCTRL:
ret = video_queryctrl(priv, (FAR struct v4l2_queryctrl *)arg);
break;
case VIDIOC_QUERY_EXT_CTRL:
ret = video_query_ext_ctrl(priv,
(FAR struct v4l2_query_ext_ctrl *)arg);
break;
case VIDIOC_QUERYMENU:
ret = video_querymenu(priv, (FAR struct v4l2_querymenu *)arg);
break;
case VIDIOC_G_CTRL:
ret = video_g_ctrl(priv, (FAR struct v4l2_control *)arg);
break;
case VIDIOC_S_CTRL:
ret = video_s_ctrl(priv, (FAR struct v4l2_control *)arg);
break;
case VIDIOC_G_EXT_CTRLS:
ret = video_g_ext_ctrls(priv, (FAR struct v4l2_ext_controls *)arg);
break;
case VIDIOC_S_EXT_CTRLS:
ret = video_s_ext_ctrls(priv, (FAR struct v4l2_ext_controls *)arg);
break;
case VIDIOC_G_STD:
ret = -ENODATA;
break;
case VIDIOC_S_STD:
ret = -EINVAL;
break;
case V4SIOC_QUERY_EXT_CTRL_SCENE:
ret = video_query_ext_ctrl_scene(priv,
(FAR struct v4s_query_ext_ctrl_scene *)arg);
break;
case V4SIOC_QUERYMENU_SCENE:
ret = video_querymenu_scene(priv,
(FAR struct v4s_querymenu_scene *)arg);
break;
case V4SIOC_G_EXT_CTRLS_SCENE:
ret = video_g_ext_ctrls_scene(priv,
(FAR struct v4s_ext_controls_scene *)arg);
break;
case V4SIOC_S_EXT_CTRLS_SCENE:
ret = video_s_ext_ctrls_scene(priv,
(FAR struct v4s_ext_controls_scene *)arg);
break;
default:
verr("Unrecognized cmd: %d\n", cmd);
ret = - ENOTTY;
break;
}
return ret;
}
static int video_mmap(FAR struct file *filep, FAR struct mm_map_entry_s *map)
{
FAR struct inode *inode = filep->f_inode;
FAR video_mng_t *priv = inode->i_private;
FAR video_type_inf_t *type_inf = &priv->video_inf;
size_t heapsize = get_heapsize(type_inf);
int ret = -EINVAL;
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 video_poll(FAR struct file *filep, struct pollfd *fds, bool setup)
{
FAR struct inode *inode = filep->f_inode;
FAR video_mng_t *priv = inode->i_private;
FAR video_type_inf_t *type_inf;
enum v4l2_buf_type buf_type;
irqstate_t flags;
buf_type = priv->still_inf.state == VIDEO_STATE_CAPTURE ?
V4L2_BUF_TYPE_STILL_CAPTURE : V4L2_BUF_TYPE_VIDEO_CAPTURE;
type_inf = get_video_type_inf(priv, 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;
}
/* Callback function which device driver call when capture has done. */
static int video_complete_capture(uint8_t err_code, uint32_t datasize,
FAR const struct timeval *ts,
FAR void *arg)
{
FAR video_mng_t *vmng = (FAR video_mng_t *)arg;
FAR video_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_VIDEO_FMT];
video_format_t c_fmt[MAX_VIDEO_FMT];
flags = enter_critical_section();
buf_type = vmng->still_inf.state == VIDEO_STATE_CAPTURE ?
V4L2_BUF_TYPE_STILL_CAPTURE : V4L2_BUF_TYPE_VIDEO_CAPTURE;
type_inf = get_video_type_inf(vmng, 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_curr->buf.flags = 0;
if (type_inf->remaining_capnum > 0)
{
type_inf->remaining_capnum--;
}
}
else
{
type_inf->bufinf.vbuf_curr->buf.flags = V4L2_BUF_FLAG_ERROR;
}
type_inf->bufinf.vbuf_curr->buf.bytesused = datasize;
if (ts != NULL)
{
type_inf->bufinf.vbuf_curr->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 =
VIDEO_WAITEND_CAUSE_CAPTUREDONE;
nxsem_post(&type_inf->wait_capture.dqbuf_wait_flg);
}
if (type_inf->remaining_capnum == 0)
{
stop_capture(vmng, buf_type);
type_inf->state = VIDEO_STATE_STREAMOFF;
/* If stop still stream, notify it to video stream */
if (buf_type == V4L2_BUF_TYPE_STILL_CAPTURE &&
is_sem_waited(&vmng->video_inf.wait_capture.dqbuf_wait_flg))
{
vmng->video_inf.wait_capture.waitend_cause =
VIDEO_WAITEND_CAUSE_STILLSTOP;
nxsem_post(&vmng->video_inf.wait_capture.dqbuf_wait_flg);
}
}
else
{
container = video_framebuff_get_vacant_container(&type_inf->bufinf);
if (container == NULL)
{
stop_capture(vmng, buf_type);
type_inf->state = VIDEO_STATE_STREAMON;
}
else
{
get_clipped_format(type_inf->nr_fmt,
type_inf->fmt,
&type_inf->clip,
c_fmt);
convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_MAIN],
&df[IMGDATA_FMT_MAIN]);
convert_to_imgdatafmt(&c_fmt[VIDEO_FMT_SUB], &df[IMGDATA_FMT_SUB]);
IMGDATA_SET_BUF(vmng->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;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int video_initialize(FAR const char *devpath)
{
return video_register(devpath,
g_video_data,
g_video_registered_sensor,
g_video_registered_sensor_num);
}
int video_uninitialize(FAR const char *devpath)
{
return video_unregister(devpath);
}
int video_register(FAR const char *devpath,
FAR struct imgdata_s *data,
FAR struct imgsensor_s **sensors,
size_t sensor_num)
{
FAR video_mng_t *priv;
size_t allocsize;
int ret;
/* Input devpath Error Check */
if (devpath == NULL || data == NULL)
{
return -EINVAL;
}
allocsize = strnlen(devpath, MAX_VIDEO_FILE_PATH - 1/* Space for '\0' */);
if (allocsize < 2 ||
devpath[0] != '/' ||
(allocsize == MAX_VIDEO_FILE_PATH - 1 &&
devpath[MAX_VIDEO_FILE_PATH] != '\0'))
{
return -EINVAL;
}
/* Initialize video device structure */
priv = kmm_zalloc(sizeof(video_mng_t));
if (priv == NULL)
{
verr("Failed to allocate instance\n");
return -ENOMEM;
}
priv->imgsensor = get_connected_imgsensor(sensors, sensor_num);
if (priv->imgsensor == NULL)
{
kmm_free(priv);
return -EINVAL;
}
/* Save device path */
priv->devpath = kmm_malloc(allocsize + 1);
if (priv->devpath == NULL)
{
kmm_free(priv);
return -ENOMEM;
}
memcpy(priv->devpath, devpath, allocsize);
priv->devpath[allocsize] = '\0';
priv->imgdata = data;
/* Initialize mutex */
nxmutex_init(&priv->lock_open_num);
/* Register the character driver */
ret = register_driver(priv->devpath, &g_video_fops, 0666, priv);
if (ret < 0)
{
verr("Failed to register driver: %d\n", ret);
nxmutex_destroy(&priv->lock_open_num);
kmm_free(priv->devpath);
kmm_free(priv);
return ret;
}
return OK;
}
int video_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_video_registered_sensor, sizeof(sensor) *
(g_video_registered_sensor_num + 1));
if (new_addr != NULL)
{
new_addr[g_video_registered_sensor_num++] = sensor;
g_video_registered_sensor = new_addr;
ret = OK;
}
return ret;
}
void imgdata_register(FAR struct imgdata_s *data)
{
g_video_data = data;
}