e542ef9175
Add new control id V4L2_CID_EXPOSURE_METERING_SPOT_POSITION to support spot position setting in spot exposure metering.
3449 lines
89 KiB
C
3449 lines
89 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/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)
|
|
|
|
#define VIDEO_SCENE_MAX (sizeof(g_video_scene_parameter) / \
|
|
sizeof(video_scene_params_t))
|
|
|
|
#define VIDEO_ID(x, y) (((x) << 16) | (y))
|
|
|
|
/****************************************************************************
|
|
* 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_mng_s
|
|
{
|
|
FAR char *devpath; /* Parameter of video_initialize() */
|
|
mutex_t lock_open_num;
|
|
uint8_t open_num;
|
|
video_type_inf_t video_inf;
|
|
video_type_inf_t still_inf;
|
|
};
|
|
|
|
typedef struct video_mng_s video_mng_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;
|
|
|
|
/****************************************************************************
|
|
* 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);
|
|
|
|
/* 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(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);
|
|
static int validate_frame_setting(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 struct v4l2_capability *cap);
|
|
static int video_g_input(FAR int *num);
|
|
static int video_enum_input(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 struct v4l2_queryctrl *ctrl);
|
|
static int video_query_ext_ctrl(FAR struct v4l2_query_ext_ctrl *ctrl);
|
|
static int video_querymenu(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 struct v4s_query_ext_ctrl_scene
|
|
*ctrl);
|
|
static int video_querymenu_scene(FAR struct v4s_querymenu_scene *menu);
|
|
static int video_g_ext_ctrls_scene(FAR struct v4s_ext_controls_scene *ctrls);
|
|
static int video_s_ext_ctrls_scene(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 */
|
|
};
|
|
|
|
static bool g_video_initialized = false;
|
|
|
|
static enum v4l2_scene_mode g_video_scene_mode = V4L2_SCENE_MODE_NONE;
|
|
static video_scene_params_t g_video_scene_parameter[] =
|
|
{
|
|
{
|
|
V4L2_SCENE_MODE_NONE
|
|
},
|
|
#ifdef CONFIG_VIDEO_SCENE_BACKLIGHT
|
|
{
|
|
V4L2_SCENE_MODE_BACKLIGHT
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_BACKLIGHT */
|
|
#ifdef CONFIG_VIDEO_SCENE_BEACHSNOW
|
|
{
|
|
V4L2_SCENE_MODE_BEACH_SNOW
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_BEACHSNOW */
|
|
#ifdef CONFIG_VIDEO_SCENE_CANDLELIGHT
|
|
{
|
|
V4L2_SCENE_MODE_CANDLE_LIGHT
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_CANDLELIGHT */
|
|
#ifdef CONFIG_VIDEO_SCENE_DAWNDUSK
|
|
{
|
|
V4L2_SCENE_MODE_DAWN_DUSK
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_DAWNDUSK */
|
|
#ifdef CONFIG_VIDEO_SCENE_FALLCOLORS
|
|
{
|
|
V4L2_SCENE_MODE_FALL_COLORS,
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_FALLCOLORS */
|
|
#ifdef CONFIG_VIDEO_SCENE_FIREWORKS
|
|
{
|
|
V4L2_SCENE_MODE_FIREWORKS
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_FIREWORKS */
|
|
#ifdef CONFIG_VIDEO_SCENE_LANDSCAPE
|
|
{
|
|
V4L2_SCENE_MODE_LANDSCAPE
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_LANDSCAPE */
|
|
#ifdef CONFIG_VIDEO_SCENE_NIGHT
|
|
{
|
|
V4L2_SCENE_MODE_NIGHT
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_NIGHT */
|
|
#ifdef CONFIG_VIDEO_SCENE_PARTYINDOOR
|
|
{
|
|
V4L2_SCENE_MODE_PARTY_INDOOR
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_PARTYINDOOR */
|
|
#ifdef CONFIG_VIDEO_SCENE_PORTRAIT
|
|
{
|
|
V4L2_SCENE_MODE_PORTRAIT
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_PORTRAIT */
|
|
#ifdef CONFIG_VIDEO_SCENE_SPORTS
|
|
{
|
|
V4L2_SCENE_MODE_SPORTS
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_SPORTS */
|
|
#ifdef CONFIG_VIDEO_SCENE_SUNSET
|
|
{
|
|
V4L2_SCENE_MODE_SUNSET
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_SUNSET */
|
|
#ifdef CONFIG_VIDEO_SCENE_TEXT
|
|
{
|
|
V4L2_SCENE_MODE_TEXT
|
|
},
|
|
#endif /* CONFIG_VIDEO_SCENE_TEXT */
|
|
};
|
|
|
|
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 void *g_video_handler;
|
|
static FAR struct imgsensor_s **g_video_registered_sensor;
|
|
static int g_video_registered_sensor_num;
|
|
static FAR struct imgsensor_s *g_video_sensor;
|
|
static FAR struct imgdata_s *g_video_data;
|
|
|
|
/****************************************************************************
|
|
* 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_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_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(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 && g_video_sensor && g_video_data);
|
|
|
|
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);
|
|
|
|
IMGSENSOR_START_CAPTURE(g_video_sensor,
|
|
type == V4L2_BUF_TYPE_VIDEO_CAPTURE ?
|
|
IMGSENSOR_STREAM_TYPE_VIDEO : IMGSENSOR_STREAM_TYPE_STILL,
|
|
nr_fmt, sf, &si);
|
|
IMGDATA_START_CAPTURE(g_video_data,
|
|
nr_fmt, df, &di, video_complete_capture);
|
|
IMGDATA_SET_BUF(g_video_data, (FAR uint8_t *)bufaddr, bufsize);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static void stop_capture(enum v4l2_buf_type type)
|
|
{
|
|
ASSERT(g_video_sensor && g_video_data);
|
|
|
|
IMGDATA_STOP_CAPTURE(g_video_data);
|
|
IMGSENSOR_STOP_CAPTURE(g_video_sensor,
|
|
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(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(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(uint32_t id)
|
|
{
|
|
imgsensor_supported_value_t value;
|
|
int ret;
|
|
|
|
if (g_video_sensor == NULL)
|
|
{
|
|
/* Don't care(unsupported parameter) */
|
|
|
|
return 0;
|
|
}
|
|
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor, 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(uint8_t **gamma)
|
|
{
|
|
imgsensor_supported_value_t sup_val;
|
|
imgsensor_value_t val;
|
|
int32_t sz;
|
|
int ret;
|
|
|
|
*gamma = NULL;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor,
|
|
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(g_video_sensor, IMGSENSOR_ID_GAMMA_CURVE, sz, &val);
|
|
return sz;
|
|
}
|
|
|
|
static void initialize_scene_parameter(video_scene_params_t *sp)
|
|
{
|
|
ASSERT(sp);
|
|
|
|
sp->brightness = get_default_value(IMGSENSOR_ID_BRIGHTNESS);
|
|
sp->contrast = get_default_value(IMGSENSOR_ID_CONTRAST);
|
|
sp->saturation = get_default_value(IMGSENSOR_ID_SATURATION);
|
|
sp->hue = get_default_value(IMGSENSOR_ID_HUE);
|
|
sp->awb = get_default_value(IMGSENSOR_ID_AUTO_WHITE_BALANCE);
|
|
sp->red = get_default_value(IMGSENSOR_ID_RED_BALANCE);
|
|
sp->blue = get_default_value(IMGSENSOR_ID_BLUE_BALANCE);
|
|
sp->gamma = get_default_value(IMGSENSOR_ID_GAMMA);
|
|
sp->gamma_curve_sz = initialize_scene_gamma(&sp->gamma_curve);
|
|
sp->ev = get_default_value(IMGSENSOR_ID_EXPOSURE);
|
|
sp->hflip_video = get_default_value(IMGSENSOR_ID_HFLIP_VIDEO);
|
|
sp->vflip_video = get_default_value(IMGSENSOR_ID_VFLIP_VIDEO);
|
|
sp->hflip_still = get_default_value(IMGSENSOR_ID_HFLIP_STILL);
|
|
sp->vflip_still = get_default_value(IMGSENSOR_ID_VFLIP_STILL);
|
|
sp->sharpness = get_default_value(IMGSENSOR_ID_SHARPNESS);
|
|
sp->colorfx = get_default_value(IMGSENSOR_ID_COLORFX);
|
|
sp->auto_brightness = get_default_value(IMGSENSOR_ID_AUTOBRIGHTNESS);
|
|
sp->rotate = get_default_value(IMGSENSOR_ID_ROTATE);
|
|
sp->ae = get_default_value(IMGSENSOR_ID_EXPOSURE_AUTO);
|
|
sp->exposure_time = get_default_value(IMGSENSOR_ID_EXPOSURE_ABSOLUTE);
|
|
sp->focus = get_default_value(IMGSENSOR_ID_FOCUS_ABSOLUTE);
|
|
sp->af = get_default_value(IMGSENSOR_ID_FOCUS_AUTO);
|
|
sp->zoom = get_default_value(IMGSENSOR_ID_ZOOM_ABSOLUTE);
|
|
sp->iris = get_default_value(IMGSENSOR_ID_IRIS_ABSOLUTE);
|
|
sp->wb = get_default_value(IMGSENSOR_ID_AUTO_N_PRESET_WB);
|
|
sp->wdr = get_default_value(IMGSENSOR_ID_WIDE_DYNAMIC_RANGE);
|
|
sp->stabilization = get_default_value(IMGSENSOR_ID_IMG_STABILIZATION);
|
|
sp->iso_auto = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY_AUTO);
|
|
sp->iso = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY);
|
|
sp->meter = get_default_value(IMGSENSOR_ID_EXPOSURE_METERING);
|
|
sp->spot_pos = get_default_value(IMGSENSOR_ID_SPOT_POSITION);
|
|
sp->threea_lock = get_default_value(IMGSENSOR_ID_3A_LOCK);
|
|
sp->led = get_default_value(IMGSENSOR_ID_FLASH_LED_MODE);
|
|
sp->jpeg_quality = get_default_value(IMGSENSOR_ID_JPEG_QUALITY);
|
|
}
|
|
|
|
static void initialize_scenes_parameter(void)
|
|
{
|
|
video_scene_params_t *sp = &g_video_scene_parameter[0];
|
|
int i;
|
|
|
|
for (i = 0; i < VIDEO_SCENE_MAX; i++)
|
|
{
|
|
initialize_scene_parameter(sp++);
|
|
}
|
|
}
|
|
|
|
static void initialize_resources(FAR video_mng_t *vmng)
|
|
{
|
|
initialize_streamresources(&vmng->video_inf);
|
|
initialize_streamresources(&vmng->still_inf);
|
|
initialize_scenes_parameter();
|
|
}
|
|
|
|
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(video_scene_params_t *sp)
|
|
{
|
|
ASSERT(sp);
|
|
|
|
if (sp->gamma_curve != NULL)
|
|
{
|
|
kmm_free(sp->gamma_curve);
|
|
sp->gamma_curve = NULL;
|
|
sp->gamma_curve_sz = 0;
|
|
}
|
|
}
|
|
|
|
static void cleanup_scenes_parameter(void)
|
|
{
|
|
video_scene_params_t *sp = &g_video_scene_parameter[0];
|
|
int i;
|
|
|
|
for (i = 0; i < VIDEO_SCENE_MAX; i++)
|
|
{
|
|
cleanup_scene_parameter(sp++);
|
|
}
|
|
}
|
|
|
|
static void cleanup_resources(FAR video_mng_t *vmng)
|
|
{
|
|
/* If in capture, stop */
|
|
|
|
if (vmng->video_inf.state == VIDEO_STATE_CAPTURE)
|
|
{
|
|
stop_capture(V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
|
}
|
|
|
|
if (vmng->still_inf.state == VIDEO_STATE_CAPTURE)
|
|
{
|
|
stop_capture(V4L2_BUF_TYPE_STILL_CAPTURE);
|
|
}
|
|
|
|
/* Clean up resource */
|
|
|
|
cleanup_streamresources(&vmng->video_inf);
|
|
cleanup_streamresources(&vmng->still_inf);
|
|
cleanup_scenes_parameter();
|
|
}
|
|
|
|
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(void)
|
|
{
|
|
FAR struct imgsensor_s *sensor = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < g_video_registered_sensor_num; i++)
|
|
{
|
|
if (g_video_registered_sensor[i] &&
|
|
IMGSENSOR_IS_AVAILABLE(g_video_registered_sensor[i]))
|
|
{
|
|
sensor = g_video_registered_sensor[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sensor;
|
|
}
|
|
|
|
static int video_open(FAR struct file *filep)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR video_mng_t *priv = (FAR video_mng_t *)inode->i_private;
|
|
int ret = OK;
|
|
|
|
nxmutex_lock(&priv->lock_open_num);
|
|
if (priv->open_num == 0)
|
|
{
|
|
/* Only in first execution, open device */
|
|
|
|
g_video_sensor = get_connected_imgsensor();
|
|
if (g_video_sensor != NULL)
|
|
{
|
|
ret = IMGSENSOR_INIT(g_video_sensor);
|
|
if (ret == OK)
|
|
{
|
|
ret = IMGDATA_INIT(g_video_data);
|
|
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 = (FAR video_mng_t *)inode->i_private;
|
|
|
|
nxmutex_lock(&priv->lock_open_num);
|
|
if (priv->open_num == 0)
|
|
{
|
|
nxmutex_unlock(&priv->lock_open_num);
|
|
return OK;
|
|
}
|
|
|
|
if (--priv->open_num == 0)
|
|
{
|
|
cleanup_resources(priv);
|
|
IMGSENSOR_UNINIT(g_video_sensor);
|
|
IMGDATA_UNINIT(g_video_data);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static int video_querycap(FAR struct v4l2_capability *cap)
|
|
{
|
|
FAR const char *name;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
if (cap == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
name = IMGSENSOR_GET_DRIVER_NAME(g_video_sensor);
|
|
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 struct v4l2_input *input)
|
|
{
|
|
FAR const char *name;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
if (input->index > 0)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
name = IMGSENSOR_GET_DRIVER_NAME(g_video_sensor);
|
|
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(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(g_video_sensor && vmng);
|
|
|
|
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(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(g_video_sensor, 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(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 && g_video_sensor && g_video_data);
|
|
|
|
/* 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(g_video_sensor,
|
|
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(g_video_data, 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_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 && g_video_sensor && g_video_data);
|
|
|
|
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_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(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(g_video_sensor && g_video_data);
|
|
|
|
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(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 && g_video_sensor);
|
|
|
|
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(g_video_sensor, 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(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(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 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(&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 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(g_video_sensor);
|
|
|
|
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->ctrl_class == V4L2_CTRL_CLASS_CAMERA &&
|
|
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 = VIDEO_SCENE_MAX - 1;
|
|
attr->step = 1;
|
|
attr->default_value = 0;
|
|
strlcpy(attr->name, "Scene Mode", 32);
|
|
}
|
|
else
|
|
{
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor,
|
|
VIDEO_ID(attr->ctrl_class, attr->id),
|
|
&value);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
attr->type = value.type;
|
|
|
|
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(VIDEO_ID(attr->ctrl_class, attr->id),
|
|
attr->name);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int video_querymenu(FAR struct v4l2_querymenu *menu)
|
|
{
|
|
imgsensor_supported_value_t value;
|
|
int ret;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
if (menu == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (menu->ctrl_class == V4L2_CTRL_CLASS_CAMERA &&
|
|
menu->id == V4L2_CID_SCENE_MODE)
|
|
{
|
|
/* Scene mode is processed in only video driver. */
|
|
|
|
if (menu->index > VIDEO_SCENE_MAX - 1)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
menu->value = g_video_scene_parameter[menu->index].mode;
|
|
}
|
|
else
|
|
{
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor,
|
|
VIDEO_ID(menu->ctrl_class, 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;
|
|
|
|
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(g_video_sensor);
|
|
|
|
if (priv == NULL || ctrls == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (cnt = 0, control = ctrls->controls;
|
|
cnt < ctrls->count;
|
|
cnt++, control++)
|
|
{
|
|
ret = IMGSENSOR_GET_VALUE(g_video_sensor,
|
|
VIDEO_ID(ctrls->ctrl_class, 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(uint32_t id, int32_t value32)
|
|
{
|
|
imgsensor_value_t value;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
value.value32 = value32;
|
|
return IMGSENSOR_SET_VALUE(g_video_sensor, id, sizeof(int32_t), value);
|
|
}
|
|
|
|
static int set_pvalue(uint32_t id, int size, void *pval)
|
|
{
|
|
imgsensor_value_t value;
|
|
|
|
ASSERT(g_video_sensor);
|
|
|
|
value.p_u8 = (FAR uint8_t *)pval;
|
|
return IMGSENSOR_SET_VALUE(g_video_sensor, id, size, value);
|
|
}
|
|
|
|
static video_scene_params_t *search_scene_param(enum v4l2_scene_mode mode)
|
|
{
|
|
video_scene_params_t *sp = &g_video_scene_parameter[0];
|
|
int i;
|
|
|
|
for (i = 0; i < VIDEO_SCENE_MAX; i++, sp++)
|
|
{
|
|
if (sp->mode == mode)
|
|
{
|
|
return sp;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int reflect_scene_parameter(enum v4l2_scene_mode mode)
|
|
{
|
|
video_scene_params_t *sp;
|
|
|
|
sp = search_scene_param(mode);
|
|
if (sp == NULL)
|
|
{
|
|
/* Unsupported scene mode */
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
set_intvalue(IMGSENSOR_ID_BRIGHTNESS, sp->brightness);
|
|
set_intvalue(IMGSENSOR_ID_CONTRAST, sp->contrast);
|
|
set_intvalue(IMGSENSOR_ID_SATURATION, sp->saturation);
|
|
set_intvalue(IMGSENSOR_ID_HUE , sp->hue);
|
|
set_intvalue(IMGSENSOR_ID_AUTO_WHITE_BALANCE, sp->awb);
|
|
set_intvalue(IMGSENSOR_ID_RED_BALANCE , sp->red);
|
|
set_intvalue(IMGSENSOR_ID_BLUE_BALANCE, sp->blue);
|
|
set_intvalue(IMGSENSOR_ID_GAMMA, sp->gamma);
|
|
set_pvalue(IMGSENSOR_ID_GAMMA_CURVE, sp->gamma_curve_sz, sp->gamma_curve);
|
|
set_intvalue(IMGSENSOR_ID_EXPOSURE, sp->ev);
|
|
set_intvalue(IMGSENSOR_ID_HFLIP_VIDEO, sp->hflip_video);
|
|
set_intvalue(IMGSENSOR_ID_VFLIP_VIDEO, sp->vflip_video);
|
|
set_intvalue(IMGSENSOR_ID_HFLIP_STILL, sp->hflip_still);
|
|
set_intvalue(IMGSENSOR_ID_VFLIP_STILL, sp->vflip_still);
|
|
set_intvalue(IMGSENSOR_ID_SHARPNESS, sp->sharpness);
|
|
set_intvalue(IMGSENSOR_ID_COLORFX, sp->colorfx);
|
|
set_intvalue(IMGSENSOR_ID_AUTOBRIGHTNESS, sp->auto_brightness);
|
|
set_intvalue(IMGSENSOR_ID_ROTATE, sp->rotate);
|
|
set_intvalue(IMGSENSOR_ID_EXPOSURE_AUTO, sp->ae);
|
|
if (sp->ae == V4L2_EXPOSURE_MANUAL ||
|
|
sp->ae == V4L2_EXPOSURE_SHUTTER_PRIORITY)
|
|
{
|
|
set_intvalue(IMGSENSOR_ID_EXPOSURE_ABSOLUTE, sp->exposure_time);
|
|
}
|
|
|
|
set_intvalue(IMGSENSOR_ID_FOCUS_ABSOLUTE, sp->focus);
|
|
set_intvalue(IMGSENSOR_ID_FOCUS_AUTO, sp->af);
|
|
set_intvalue(IMGSENSOR_ID_ZOOM_ABSOLUTE, sp->zoom);
|
|
if (sp->ae == V4L2_EXPOSURE_MANUAL ||
|
|
sp->ae == V4L2_EXPOSURE_APERTURE_PRIORITY)
|
|
{
|
|
set_intvalue(IMGSENSOR_ID_IRIS_ABSOLUTE, sp->iris);
|
|
}
|
|
|
|
set_intvalue(IMGSENSOR_ID_AUTO_N_PRESET_WB, sp->wb);
|
|
set_intvalue(IMGSENSOR_ID_WIDE_DYNAMIC_RANGE, sp->wdr);
|
|
set_intvalue(IMGSENSOR_ID_IMG_STABILIZATION, sp->stabilization);
|
|
set_intvalue(IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, sp->iso_auto);
|
|
if (sp->iso_auto == V4L2_ISO_SENSITIVITY_MANUAL)
|
|
{
|
|
set_intvalue(IMGSENSOR_ID_ISO_SENSITIVITY, sp->iso);
|
|
}
|
|
|
|
set_intvalue(IMGSENSOR_ID_EXPOSURE_METERING, sp->meter);
|
|
set_intvalue(IMGSENSOR_ID_SPOT_POSITION, sp->spot_pos);
|
|
set_intvalue(IMGSENSOR_ID_3A_LOCK, sp->threea_lock);
|
|
set_intvalue(IMGSENSOR_ID_FLASH_LED_MODE, sp->led);
|
|
set_intvalue(IMGSENSOR_ID_JPEG_QUALITY, sp->jpeg_quality);
|
|
|
|
g_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(g_video_sensor);
|
|
|
|
if (priv == NULL || ctrls == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (cnt = 0, control = ctrls->controls;
|
|
cnt < ctrls->count;
|
|
cnt++, control++)
|
|
{
|
|
if (ctrls->ctrl_class == V4L2_CTRL_CLASS_CAMERA &&
|
|
control->id == V4L2_CID_SCENE_MODE)
|
|
{
|
|
ret = reflect_scene_parameter(control->value);
|
|
}
|
|
else
|
|
{
|
|
ret = IMGSENSOR_SET_VALUE(g_video_sensor,
|
|
VIDEO_ID(ctrls->ctrl_class, control->id),
|
|
control->size,
|
|
(imgsensor_value_t)control->value64);
|
|
if (ret == 0)
|
|
{
|
|
if (g_video_scene_mode == V4L2_SCENE_MODE_NONE)
|
|
{
|
|
save_scene_param(V4L2_SCENE_MODE_NONE,
|
|
VIDEO_ID(ctrls->ctrl_class, 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 struct v4s_query_ext_ctrl_scene *attr)
|
|
{
|
|
if (attr == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
return video_query_ext_ctrl(&attr->control);
|
|
}
|
|
|
|
static int video_querymenu_scene(FAR struct v4s_querymenu_scene *menu)
|
|
{
|
|
if (menu == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
return video_querymenu(&menu->menu);
|
|
}
|
|
|
|
static int read_scene_param(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(g_video_sensor);
|
|
|
|
if (control == NULL)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
sp = search_scene_param(mode);
|
|
if (sp == NULL)
|
|
{
|
|
/* Unsupported scene mode */
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor, 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 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(ctrls->mode,
|
|
VIDEO_ID(ctrls->control.ctrl_class, 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(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(g_video_sensor);
|
|
|
|
sp = search_scene_param(mode);
|
|
if (sp == NULL)
|
|
{
|
|
/* Unsupported scene mode */
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = IMGSENSOR_GET_SUPPORTED_VALUE(g_video_sensor, 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 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(ctrls->mode,
|
|
VIDEO_ID(ctrls->control.ctrl_class, 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 = (FAR video_mng_t *)inode->i_private;
|
|
int ret = OK;
|
|
|
|
switch (cmd)
|
|
{
|
|
case VIDIOC_QUERYCAP:
|
|
ret = video_querycap((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((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((FAR struct v4l2_queryctrl *)arg);
|
|
break;
|
|
|
|
case VIDIOC_QUERY_EXT_CTRL:
|
|
ret = video_query_ext_ctrl((FAR struct v4l2_query_ext_ctrl *)arg);
|
|
break;
|
|
|
|
case VIDIOC_QUERYMENU:
|
|
ret = video_querymenu((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(
|
|
(FAR struct v4s_query_ext_ctrl_scene *)arg);
|
|
break;
|
|
|
|
case V4SIOC_QUERYMENU_SCENE:
|
|
ret = video_querymenu_scene((FAR struct v4s_querymenu_scene *)arg);
|
|
break;
|
|
|
|
case V4SIOC_G_EXT_CTRLS_SCENE:
|
|
ret = video_g_ext_ctrls_scene(
|
|
(FAR struct v4s_ext_controls_scene *)arg);
|
|
break;
|
|
|
|
case V4SIOC_S_EXT_CTRLS_SCENE:
|
|
ret = video_s_ext_ctrls_scene(
|
|
(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 = (FAR video_mng_t *)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 = (FAR video_mng_t *)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(&type_inf->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;
|
|
}
|
|
|
|
static FAR void *video_register(FAR const char *devpath)
|
|
{
|
|
FAR video_mng_t *priv;
|
|
size_t allocsize;
|
|
int ret;
|
|
|
|
/* Input devpath Error Check */
|
|
|
|
if (devpath == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
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 NULL;
|
|
}
|
|
|
|
/* Initialize video device structure */
|
|
|
|
priv = (FAR video_mng_t *)kmm_zalloc(sizeof(video_mng_t));
|
|
if (priv == NULL)
|
|
{
|
|
verr("Failed to allocate instance\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* Save device path */
|
|
|
|
priv->devpath = (FAR char *)kmm_malloc(allocsize + 1);
|
|
if (priv->devpath == NULL)
|
|
{
|
|
kmm_free(priv);
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(priv->devpath, devpath, allocsize);
|
|
priv->devpath[allocsize] = '\0';
|
|
|
|
/* 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 NULL;
|
|
}
|
|
|
|
return priv;
|
|
}
|
|
|
|
static int video_unregister(FAR video_mng_t *priv)
|
|
{
|
|
int ret = OK;
|
|
|
|
if (priv == NULL)
|
|
{
|
|
ret = -ENODEV;
|
|
}
|
|
else
|
|
{
|
|
nxmutex_destroy(&priv->lock_open_num);
|
|
unregister_driver(priv->devpath);
|
|
|
|
kmm_free(priv->devpath);
|
|
kmm_free(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* 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 video_mng_t *vmng = (FAR video_mng_t *)g_video_handler;
|
|
FAR video_type_inf_t *type_inf;
|
|
FAR vbuf_container_t *container = NULL;
|
|
enum v4l2_buf_type buf_type;
|
|
irqstate_t flags;
|
|
|
|
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(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(buf_type);
|
|
type_inf->state = VIDEO_STATE_STREAMON;
|
|
}
|
|
else
|
|
{
|
|
IMGDATA_SET_BUF(g_video_data,
|
|
(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)
|
|
{
|
|
if (g_video_initialized)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
g_video_handler = video_register(devpath);
|
|
g_video_initialized = true;
|
|
|
|
return OK;
|
|
}
|
|
|
|
int video_uninitialize(void)
|
|
{
|
|
if (!g_video_initialized)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
video_unregister(g_video_handler);
|
|
g_video_initialized = false;
|
|
|
|
return OK;
|
|
}
|
|
|
|
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;
|
|
}
|