diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d75b92d35a..c5becf6480 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -22,6 +22,12 @@ config FB_OVERLAY_BLIT depends on FB_OVERLAY default n +config VIDEO_STREAM + bool "Video Stream Support" + default n + ---help--- + Enable video Stream support + config VIDEO_MAX7456 bool "Maxim 7456 Monochrome OSD" default n diff --git a/drivers/video/Make.defs b/drivers/video/Make.defs index 206c6a9af1..82ac7ee049 100644 --- a/drivers/video/Make.defs +++ b/drivers/video/Make.defs @@ -41,6 +41,10 @@ ifeq ($(CONFIG_VIDEO_FB),y) CSRCS += fb.c endif +ifeq ($(CONFIG_VIDEO_STREAM),y) + CSRCS += video.c video_framebuff.c +endif + # These video drivers depend on I2C support ifeq ($(CONFIG_I2C),y) diff --git a/drivers/video/video.c b/drivers/video/video.c new file mode 100644 index 0000000000..f8e1845b39 --- /dev/null +++ b/drivers/video/video.c @@ -0,0 +1,1609 @@ +/**************************************************************************** + * drivers/video/video.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "video_framebuff.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define video_printf(format, ...) _info(format, ##__VA_ARGS__) + +#define MAX_VIDEO_FILE_PATH (32) + +#define VIDEO_TRUE (1) +#define VIDEO_FALSE (0) + +#define VIDEO_REMAINING_CAPNUM_INFINITY (-1) + +/* Debug option */ + +#ifdef CONFIG_DEBUG_VIDEO_ERROR +#define videoerr(format, ...) _err(format, ##__VA_ARGS__) +#else +#define videoerr(x...) +#endif + +#ifdef CONFIG_DEBUG_VIDEO_WARN +#define videowarn(format, ...) _warn(format, ##__VA_ARGS__) +#else +#define videowarn(x...) +#endif + +#ifdef CONFIG_DEBUG_VIDEO_INFO +#define videoinfo(format, ...) _info(format, ##__VA_ARGS__) +#else +#define videoinfo(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum video_state_e +{ + VIDEO_STATE_STREAMOFF = 0, /* DMA trigger event is not received */ + VIDEO_STATE_STREAMON = 1, /* DMA trigger event is received, + * but DMA is not operated. + */ + VIDEO_STATE_DMA = 2, /* On DMA */ +}; + +enum video_state_transition_cause +{ + CAUSE_VIDEO_STOP = 0, /* Stop DMA event for video stream */ + CAUSE_VIDEO_START = 1, /* Start DMA event for video stream */ + CAUSE_VIDEO_DQBUF = 2, /* DQBUF timing for video stream */ + CAUSE_STILL_STOP = 3, /* Stop DMA event for still stream */ + CAUSE_STILL_START = 4, /* Start DMA event for still stream */ +}; + +enum video_waitend_cause_e +{ + VIDEO_WAITEND_CAUSE_DMADONE = 0, + VIDEO_WAITEND_CAUSE_DQCANCEL = 1, + VIDEO_WAITEND_CAUSE_STILLSTOP = 2, +}; + +struct video_wait_dma_s +{ + FAR sem_t dqbuf_wait_flg; + FAR vbuf_container_t *done_container; /* Save container which dma done */ + enum video_waitend_cause_e waitend_cause; +}; + +typedef struct video_wait_dma_s video_wait_dma_t; + +struct video_type_inf_s +{ + sem_t lock_state; + enum video_state_e state; + int32_t remaining_capnum; + video_wait_dma_t wait_dma; + video_framebuff_t bufinf; +}; + +typedef struct video_type_inf_s video_type_inf_t; + +struct video_mng_s +{ + FAR char *devpath; /* parameter of video_initialize() */ + sem_t lock_open_num; + uint8_t open_num; + FAR struct pollfd *poll_wait; /* poll(setup) information */ + video_type_inf_t video_inf; + video_type_inf_t still_inf; +}; + +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 int video_ioctl(FAR struct file *filep, int cmd, unsigned long arg); +static int video_poll(FAR struct file *filep, + FAR struct pollfd *fds, + bool setup); + +/* Common function */ + +static int video_lock(FAR sem_t *sem); +static int video_unlock(FAR sem_t *sem); +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); + +/* internal function for each cmds of ioctl */ + +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); +static int video_cancel_dqbuf(FAR struct video_mng_s *vmng, + enum v4l2_buf_type type); +static int video_enum_fmt(FAR struct v4l2_fmtdesc *fmt); +static int video_enum_framesizes(FAR struct v4l2_frmsizeenum *frmsize); +static int video_s_fmt(FAR struct video_mng_s *priv, + FAR struct v4l2_format *fmt); +static int video_enum_frameintervals(FAR struct v4l2_frmivalenum *frmival); +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(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); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_video_fops = +{ + video_open, /* open */ + video_close, /* close */ + 0, /* read */ + 0, /* write */ + 0, /* seek */ + video_ioctl, /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + video_poll, /* poll */ +#endif + 0 /* unlink */ +}; + +static FAR const struct video_devops_s *g_video_devops; + +static bool is_initialized = false; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static int video_lock(FAR sem_t *sem) +{ + int ret; + int l_errno; + + if (sem == NULL) + { + return -EINVAL; + } + + while (1) + { + ret = sem_wait(sem); + if (ret == ERROR) + { + l_errno = errno; + if (l_errno == EINTR) + { + continue; + } + + videoerr("sem_wait() failed:%d\n", l_errno); + } + + break; + } + + return ret; +} + +static int video_unlock(FAR sem_t *sem) +{ + if (sem == NULL) + { + return -EINVAL; + } + + sem_post(sem); + + return OK; +} + +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_DMA; + } + + case CAUSE_STILL_STOP: + if (current_state == VIDEO_STATE_STREAMON) + { + return VIDEO_STATE_DMA; + } + else + { + return current_state; + } + + case CAUSE_STILL_START: + if (current_state == VIDEO_STATE_DMA) + { + 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_DMA; + } + else + { + return current_state; + } + + default: + return current_state; + } +} + +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; + FAR vbuf_container_t *dma_container; + + if ((current_state != VIDEO_STATE_DMA) && + (next_state == VIDEO_STATE_DMA)) + { + dma_container = + video_framebuff_get_dma_container(&vmng->video_inf.bufinf); + if (dma_container) + { + g_video_devops->set_buftype(V4L2_BUF_TYPE_VIDEO_CAPTURE); + g_video_devops->set_buf(dma_container->buf.m.userptr, + dma_container->buf.length); + } + else + { + updated_next_state = VIDEO_STATE_STREAMON; + } + } + else + { + if ((current_state == VIDEO_STATE_DMA) && + (next_state != VIDEO_STATE_DMA)) + { + g_video_devops->cancel_dma(); + } + } + + vmng->video_inf.state = updated_next_state; + + return; +} + +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_DMA)); +} + +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_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; + sem_init(&type_inf->lock_state, 0, 1); + sem_init(&type_inf->wait_dma.dqbuf_wait_flg, 0, 0); + video_framebuff_init(&type_inf->bufinf); + + return; +} + +static void initialize_resources(FAR video_mng_t *vmng) +{ + initialize_streamresources(&vmng->video_inf); + initialize_streamresources(&vmng->still_inf); + + return; +} + +static void cleanup_streamresources(FAR video_type_inf_t *type_inf) +{ + video_framebuff_uninit(&type_inf->bufinf); + sem_destroy(&type_inf->wait_dma.dqbuf_wait_flg); + sem_destroy(&type_inf->lock_state); + memset(type_inf, 0, sizeof(video_type_inf_t)); + type_inf->remaining_capnum = VIDEO_REMAINING_CAPNUM_INFINITY; + + return; +} + +static void cleanup_resources(FAR video_mng_t *vmng) +{ + /* clean up resource */ + + if ((vmng->video_inf.state == VIDEO_STATE_DMA) || + (vmng->still_inf.state == VIDEO_STATE_DMA)) + { + /* If in DMA, stop */ + + g_video_devops->cancel_dma(); + } + + cleanup_streamresources(&vmng->video_inf); + cleanup_streamresources(&vmng->still_inf); + + return; +} + +static bool is_sem_waited(FAR sem_t *sem) +{ + int ret; + int semcount; + + ret = sem_getvalue(sem, &semcount); + if ((ret == OK) && (semcount < 0)) + { + return true; + } + else + { + return false; + } +} + +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; + + video_lock(&priv->lock_open_num); + if (priv->open_num == 0) + { + /* Only in first execution, open device */ + + ret = g_video_devops->open(priv); + if (ret == OK) + { + initialize_resources(priv); + } + } + + /* In second or later execution, ret is initial value(=OK) */ + + if (ret == OK) + { + priv->open_num++; + } + video_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; + int ret = ERROR; + + video_lock(&priv->lock_open_num); + if (priv->open_num == 0) + { + return OK; + } + + priv->open_num--; + + if (priv->open_num == 0) + { + cleanup_resources(priv); + g_video_devops->close(); + } + video_unlock(&priv->lock_open_num); + + return ret; +} + +static int video_reqbufs(FAR struct video_mng_s *vmng, + FAR struct v4l2_requestbuffers *reqbufs) +{ + int ret = OK; + FAR video_type_inf_t *type_inf; + irqstate_t flags; + + 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_DMA) + { + /* In DMA, REQBUFS is not permitted */ + + ret = -EPERM; + } + else + { + video_framebuff_change_mode(&type_inf->bufinf, reqbufs->mode); + + ret = video_framebuff_realloc_container(&type_inf->bufinf, + reqbufs->count); + } + + leave_critical_section(flags); + + return ret; +} + +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)); + video_framebuff_queue_container(&type_inf->bufinf, container); + + video_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) + { + video_lock(&vmng->still_inf.lock_state); + next_video_state = estimate_next_video_state + (vmng, CAUSE_VIDEO_START); + change_video_state(vmng, next_video_state); + video_unlock(&vmng->still_inf.lock_state); + } + else + { + container = video_framebuff_get_dma_container(&type_inf->bufinf); + if (container) + { + g_video_devops->set_buftype(buf->type); + g_video_devops->set_buf(container->buf.m.userptr, + container->buf.length); + type_inf->state = VIDEO_STATE_DMA; + } + } + } + else + { + leave_critical_section(flags); + } + + video_unlock(&type_inf->lock_state); + + return OK; +} + +static int video_dqbuf(FAR struct video_mng_s *vmng, + FAR struct v4l2_buffer *buf) +{ + irqstate_t flags; + FAR video_type_inf_t *type_inf; + FAR vbuf_container_t *container; + 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) + { + /* Not yet done DMA. Wait done */ + + dqbuf_wait_flg = &type_inf->wait_dma.dqbuf_wait_flg; + + /* Loop until semaphore is unlocked by DMA done or DQCANCEL */ + + do + { + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + { + /* If start DMA condition is satisfied, start DMA */ + + 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); + } + + sem_wait(dqbuf_wait_flg); + } + while (type_inf->wait_dma.waitend_cause == + VIDEO_WAITEND_CAUSE_STILLSTOP); + + container = type_inf->wait_dma.done_container; + + if (!container) + { + /* Waking up without DMA data means abort. + * Therefore, Check cause. + */ + + if (type_inf->wait_dma.waitend_cause + == VIDEO_WAITEND_CAUSE_DQCANCEL) + { + return -ECANCELED; + } + } + + type_inf->wait_dma.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_dma.dqbuf_wait_flg)) + { + /* In not waiting DQBUF case, return OK */ + + return OK; + } + + type_inf->wait_dma.waitend_cause = VIDEO_WAITEND_CAUSE_DQCANCEL; + + /* If DMA is done before sem_post, cause is overwritten */ + + sem_post(&type_inf->wait_dma.dqbuf_wait_flg); + + return OK; +} + +static int video_enum_fmt(FAR struct v4l2_fmtdesc *fmt) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->get_range_of_fmt == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->get_range_of_fmt(fmt); + + return ret; +} + +static int video_enum_framesizes(FAR struct v4l2_frmsizeenum *frmsize) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->get_range_of_framesize == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->get_range_of_framesize(frmsize); + + return ret; +} + +static int video_try_fmt(FAR struct v4l2_format *fmt) +{ + int ret; + + if ((g_video_devops == NULL) || (g_video_devops->try_format == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->try_format(fmt); + + return ret; +} + +static int video_s_fmt(FAR struct video_mng_s *priv, + FAR struct v4l2_format *fmt) +{ + int ret; + + if ((g_video_devops == NULL) || (g_video_devops->set_format == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->set_format(fmt); + + return ret; +} + +static int video_enum_frameintervals(FAR struct v4l2_frmivalenum *frmival) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->get_range_of_frameinterval == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->get_range_of_frameinterval(frmival); + + return ret; +} + +static int video_s_parm(FAR struct video_mng_s *priv, + FAR struct v4l2_streamparm *parm) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->set_frameinterval == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->set_frameinterval(parm); + + return ret; +} + +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; + } + + video_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); + } + + video_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(bool enable) +{ + if ((g_video_devops == NULL) || (g_video_devops->do_halfpush == NULL)) + { + return -EINVAL; + } + + return g_video_devops->do_halfpush(enable); +} + +static int video_takepict_start(FAR struct video_mng_s *vmng, + int32_t capture_num) +{ + irqstate_t flags; + enum video_state_e next_video_state; + FAR vbuf_container_t *dma_container; + int ret = OK; + + if (vmng == NULL) + { + return -EINVAL; + } + + video_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); + + dma_container = video_framebuff_get_dma_container + (&vmng->still_inf.bufinf); + if (dma_container) + { + /* Start video stream DMA */ + + g_video_devops->set_buftype(V4L2_BUF_TYPE_STILL_CAPTURE); + g_video_devops->set_buf(dma_container->buf.m.userptr, + dma_container->buf.length); + vmng->still_inf.state = VIDEO_STATE_DMA; + } + else + { + vmng->still_inf.state = VIDEO_STATE_STREAMON; + } + } + + video_unlock(&vmng->still_inf.lock_state); + + return ret; +} + +static int video_takepict_stop(FAR struct video_mng_s *vmng, bool halfpush) +{ + int ret = OK; + irqstate_t flags; + enum video_state_e next_video_state; + + if (vmng == NULL) + { + return -EINVAL; + } + + video_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_DMA) + { + g_video_devops->cancel_dma(); + } + leave_critical_section(flags); + + vmng->still_inf.state = VIDEO_STATE_STREAMOFF; + vmng->still_inf.remaining_capnum = VIDEO_REMAINING_CAPNUM_INFINITY; + + /* Control video stream */ + + video_lock(&vmng->video_inf.lock_state); + next_video_state = estimate_next_video_state(vmng, + CAUSE_STILL_STOP); + change_video_state(vmng, next_video_state); + video_unlock(&vmng->video_inf.lock_state); + } + + video_unlock(&vmng->still_inf.lock_state); + + return ret; +} + +static int video_queryctrl(FAR struct v4l2_queryctrl *ctrl) +{ + int ret; + struct v4l2_query_ext_ctrl ext_ctrl; + + 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; + strncpy(ctrl->name, ext_ctrl.name, sizeof(ctrl->name)); + + return OK; +} + +static int video_query_ext_ctrl(FAR struct v4l2_query_ext_ctrl *ctrl) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->get_range_of_ctrlvalue == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->get_range_of_ctrlvalue(ctrl); + + return ret; +} + +static int video_querymenu(FAR struct v4l2_querymenu *menu) +{ + int ret; + + if ((g_video_devops == NULL) || + (g_video_devops->get_menu_of_ctrlvalue == NULL)) + { + return -EINVAL; + } + + ret = g_video_devops->get_menu_of_ctrlvalue(menu); + + return ret; +} + +static int video_g_ctrl(FAR struct video_mng_s *priv, + FAR struct v4l2_control *ctrl) +{ + int ret; + struct v4l2_ext_controls ext_controls; + struct v4l2_ext_control 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) +{ + int ret; + 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 */ + + ret = video_s_ext_ctrls(priv, &ext_controls); + + return ret; +} + +static int video_g_ext_ctrls(FAR struct video_mng_s *priv, + FAR struct v4l2_ext_controls *ctrls) +{ + int ret = OK; + int cnt; + FAR struct v4l2_ext_control *control; + + if ((priv == NULL) || (ctrls == NULL)) + { + return -EINVAL; + } + + for (cnt = 0, control = ctrls->controls; + cnt < ctrls->count; + cnt++, control++) + { + ret = g_video_devops->get_ctrlvalue(ctrls->ctrl_class, control); + + if (ret < 0) + { + /* Set cnt in that error occured */ + + ctrls->error_idx = cnt; + return ret; + } + } + + return ret; +} + +static int video_s_ext_ctrls(FAR struct video_mng_s *priv, + FAR struct v4l2_ext_controls *ctrls) +{ + int ret; + int cnt; + FAR struct v4l2_ext_control *control; + + if ((priv == NULL) || (ctrls == NULL)) + { + return -EINVAL; + } + + for (cnt = 0, control = ctrls->controls; + cnt < ctrls->count; + cnt++, control++) + { + ret = g_video_devops->set_ctrlvalue(ctrls->ctrl_class, control); + + if (ret < 0) + { + /* Set cnt in that error occured */ + + ctrls->error_idx = cnt; + return ret; + } + } + + ret = g_video_devops->refresh(); + if (ret < 0) + { + ctrls->error_idx = cnt; + } + + 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_REQBUFS: + ret = video_reqbufs(priv, (FAR struct v4l2_requestbuffers *)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); + + 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(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_ENUM_FMT: + ret = video_enum_fmt((FAR struct v4l2_fmtdesc *)arg); + + break; + + case VIDIOC_ENUM_FRAMESIZES: + ret = video_enum_framesizes((FAR struct v4l2_frmsizeenum *)arg); + + break; + + case VIDIOC_TRY_FMT: + ret = video_try_fmt((FAR struct v4l2_format *)arg); + + break; + + case VIDIOC_S_FMT: + ret = video_s_fmt(priv, (FAR struct v4l2_format *)arg); + + break; + + case VIDIOC_ENUM_FRAMEINTERVALS: + ret = video_enum_frameintervals((FAR struct v4l2_frmivalenum *)arg); + + break; + + case VIDIOC_S_PARM: + ret = video_s_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; + + default: + videoerr("Unrecognized cmd: %d\n", cmd); + ret = - ENOTTY; + break; + } + + return ret; +} + +static int video_poll_setup(FAR struct video_mng_s *priv, + FAR struct pollfd *fds) +{ + if ((fds->events & POLLIN) == 0) + { + return -EDEADLK; + } + + /* TODO: If data exists, get and sem_post If no data, wait dma */ + + return OK; +} + +static int video_poll_teardown(FAR struct video_mng_s *priv, + FAR struct pollfd *fds) +{ + /* TODO: Delete poll wait information */ + + return OK; +} + +static int video_poll(FAR struct file *filep, + FAR struct pollfd *fds, + bool setup) +{ + FAR struct inode *inode = filep->f_inode; + FAR video_mng_t *priv = inode->i_private; + + if (setup) + { + return video_poll_setup(priv, fds); + } + else + { + return video_poll_teardown(priv, fds); + } + + return OK; +} + +static FAR void *video_register(FAR const char *devpath) +{ + FAR video_mng_t *priv; + int ret; + size_t allocsize; + + /* Input devpath Error Check */ + + if (!devpath) + { + 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_malloc(sizeof(video_mng_t)); + if (!priv) + { + videoerr("Failed to allocate instance\n"); + return NULL; + } + + memset(priv, 0, sizeof(video_mng_t)); + + /* Save device path */ + + priv->devpath = (FAR char *)kmm_malloc(allocsize + 1); + if (!priv->devpath) + { + kmm_free(priv); + return NULL; + } + memcpy(priv->devpath, devpath, allocsize); + priv->devpath[allocsize] = '\0'; + + /* Initialize semaphore */ + + sem_init(&priv->lock_open_num, 0, 1); + + /* Register the character driver */ + + ret = register_driver(priv->devpath, &g_video_fops, 0666, priv); + if (ret < 0) + { + videoerr("Failed to register driver: %d\n", ret); + kmm_free(priv->devpath); + kmm_free(priv); + return NULL; + } + + return (FAR void *)priv; +} + +static int video_unregister(FAR video_mng_t *v_mgr) +{ + int ret = OK; + + if (!v_mgr) + { + ret = -ENODEV; + } + else + { + sem_destroy(&v_mgr->lock_open_num); + + unregister_driver((const char *)v_mgr->devpath); + + kmm_free(v_mgr->devpath); + kmm_free(v_mgr); + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +static FAR void *video_handler; + +int video_initialize(FAR const char *devpath) +{ + if (is_initialized) + { + return OK; + } + + video_handler = video_register(devpath); + + is_initialized = true; + + return OK; +} + +int video_uninitialize(void) +{ + if (is_initialized) + { + return OK; + } + video_unregister(video_handler); + + is_initialized = false; + + return OK; +} + +int video_common_notify_dma_done(uint8_t err_code, + uint32_t buf_type, + uint32_t datasize, + FAR void *priv) +{ + FAR video_mng_t *vmng = (FAR video_mng_t *)priv; + FAR video_type_inf_t *type_inf; + FAR vbuf_container_t *container = NULL; + + type_inf = get_video_type_inf(vmng, buf_type); + if (type_inf == NULL) + { + return -EINVAL; + } + + if (err_code == 0) + { + type_inf->bufinf.vbuf_dma->buf.flags = 0; + if (type_inf->remaining_capnum > 0) + { + type_inf->remaining_capnum--; + } + } + else + { + type_inf->bufinf.vbuf_dma->buf.flags = V4L2_BUF_FLAG_ERROR; + } + + type_inf->bufinf.vbuf_dma->buf.bytesused = datasize; + video_framebuff_dma_done(&type_inf->bufinf); + + if (is_sem_waited(&type_inf->wait_dma.dqbuf_wait_flg)) + { + /* If waiting DMA done in DQBUF, + * get/save container and unlock wait + */ + + type_inf->wait_dma.done_container + = video_framebuff_pop_curr_container(&type_inf->bufinf); + type_inf->wait_dma.waitend_cause + = VIDEO_WAITEND_CAUSE_DMADONE; + sem_post(&type_inf->wait_dma.dqbuf_wait_flg); + + /* TODO: in poll wait, unlock wait */ + } + + if (type_inf->remaining_capnum == 0) + { + g_video_devops->cancel_dma(); + 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_dma.dqbuf_wait_flg)) + { + vmng->video_inf.wait_dma.waitend_cause + = VIDEO_WAITEND_CAUSE_STILLSTOP; + sem_post(&vmng->video_inf.wait_dma.dqbuf_wait_flg); + } + } + else + { + container = video_framebuff_get_dma_container(&type_inf->bufinf); + if (!container) + { + g_video_devops->cancel_dma(); + type_inf->state = VIDEO_STATE_STREAMON; + } + else + { + g_video_devops->set_buf(container->buf.m.userptr, + container->buf.length); + } + } + + return OK; +} diff --git a/drivers/video/video_framebuff.c b/drivers/video/video_framebuff.c new file mode 100644 index 0000000000..440efd4f57 --- /dev/null +++ b/drivers/video/video_framebuff.c @@ -0,0 +1,299 @@ +/**************************************************************************** + * drivers/video/video_framebuff.c + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include "video_framebuff.h" + +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static void init_buf_chain(video_framebuff_t *fbuf) +{ + int i; + vbuf_container_t *tmp; + + fbuf->vbuf_empty = fbuf->vbuf_alloced; + fbuf->vbuf_next_dma = NULL; + fbuf->vbuf_dma = NULL; + fbuf->vbuf_top = NULL; + fbuf->vbuf_tail = NULL; + + tmp = fbuf->vbuf_alloced; + for (i = 0; i < fbuf->container_size - 1; i++) + { + tmp->next = &tmp[1]; + tmp++; + } +} + +static void cleanup_container(video_framebuff_t *fbuf) +{ + if (fbuf->vbuf_alloced) + { + memset(fbuf->vbuf_alloced, + 0, + sizeof(vbuf_container_t)*fbuf->container_size); + init_buf_chain(fbuf); + } +} + +static inline int is_last_one(video_framebuff_t *fbuf) +{ + return fbuf->vbuf_top == fbuf->vbuf_tail ? 1 : 0; +} + +static inline vbuf_container_t *dequeue_vbuf_unsafe(video_framebuff_t *fbuf) +{ + vbuf_container_t *ret = fbuf->vbuf_top; + if (is_last_one(fbuf)) + { + fbuf->vbuf_top = NULL; + fbuf->vbuf_tail = NULL; + fbuf->vbuf_next_dma = NULL; + } + else + { + if (fbuf->mode == V4L2_BUF_MODE_RING) + { + fbuf->vbuf_tail->next = fbuf->vbuf_top->next; + } + fbuf->vbuf_top = fbuf->vbuf_top->next; + } + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ +void video_framebuff_init(video_framebuff_t *fbuf) +{ + fbuf->mode = V4L2_BUF_MODE_RING; + fbuf->vbuf_empty = NULL; + fbuf->vbuf_top = NULL; + fbuf->vbuf_tail = NULL; + fbuf->vbuf_next_dma = NULL; + + sem_init(&fbuf->lock_empty, 0, 1); +} + +void video_framebuff_uninit(video_framebuff_t *fbuf) +{ + video_framebuff_realloc_container(fbuf, 0); + sem_destroy(&fbuf->lock_empty); +} + +int video_framebuff_realloc_container(video_framebuff_t *fbuf, int sz) +{ + if (sz > V4L2_REQBUFS_COUNT_MAX) + { + return -EINVAL; + } + + if (fbuf->vbuf_alloced == NULL || fbuf->container_size != sz) + { + if (fbuf->container_size != sz) + { + if (fbuf->vbuf_alloced != NULL) + { + kmm_free(fbuf->vbuf_alloced); + } + fbuf->vbuf_alloced = NULL; + fbuf->container_size = 0; + } + if (sz > 0) + { + fbuf->vbuf_alloced + = (vbuf_container_t *)kmm_malloc(sizeof(vbuf_container_t)*sz); + if (fbuf->vbuf_alloced == NULL) + { + return -ENOMEM; + } + } + fbuf->container_size = sz; + } + + cleanup_container(fbuf); + + return OK; +} + +vbuf_container_t *video_framebuff_get_container(video_framebuff_t *fbuf) +{ + vbuf_container_t *ret; + + sem_wait(&fbuf->lock_empty); + ret = fbuf->vbuf_empty; + if (ret) + { + fbuf->vbuf_empty = ret->next; + ret->next = NULL; + } + sem_post(&fbuf->lock_empty); + + return ret; +} + +void video_framebuff_free_container(video_framebuff_t *fbuf, + vbuf_container_t *cnt) +{ + sem_wait(&fbuf->lock_empty); + cnt->next = fbuf->vbuf_empty; + fbuf->vbuf_empty = cnt; + sem_post(&fbuf->lock_empty); +} + +void video_framebuff_queue_container(video_framebuff_t *fbuf, + vbuf_container_t *tgt) +{ + irqstate_t flags; + + flags = enter_critical_section(); + if (fbuf->vbuf_top) + { + fbuf->vbuf_tail->next = tgt; + fbuf->vbuf_tail = tgt; + if (fbuf->vbuf_next_dma == NULL) + { + fbuf->vbuf_next_dma = tgt; + } + } + else + { + fbuf->vbuf_top = fbuf->vbuf_tail = tgt; + fbuf->vbuf_next_dma = tgt; + } + + if (fbuf->mode == V4L2_BUF_MODE_RING) + { + fbuf->vbuf_tail->next = fbuf->vbuf_top; + } + else /* Case of V4L2_BUF_MODE_FIFO */ + { + fbuf->vbuf_tail->next = NULL; + } + leave_critical_section(flags); +} + +vbuf_container_t *video_framebuff_dq_valid_container(video_framebuff_t *fbuf) +{ + irqstate_t flags; + vbuf_container_t *ret = NULL; + + flags = enter_critical_section(); + if (fbuf->vbuf_top != NULL && fbuf->vbuf_top != fbuf->vbuf_next_dma) + { + ret = dequeue_vbuf_unsafe(fbuf); + } + leave_critical_section(flags); + + return ret; +} + +vbuf_container_t *video_framebuff_get_dma_container(video_framebuff_t *fbuf) +{ + irqstate_t flags; + vbuf_container_t *ret; + + flags = enter_critical_section(); + ret = fbuf->vbuf_dma = fbuf->vbuf_next_dma; + leave_critical_section(flags); + + return ret; +} + +void video_framebuff_dma_done(video_framebuff_t *fbuf) +{ + fbuf->vbuf_dma = NULL; + if (fbuf->vbuf_next_dma) + { + fbuf->vbuf_next_dma = fbuf->vbuf_next_dma->next; + if (fbuf->vbuf_next_dma == fbuf->vbuf_top) /* RING mode case. */ + { + fbuf->vbuf_top = fbuf->vbuf_top->next; + fbuf->vbuf_tail = fbuf->vbuf_tail->next; + } + } +} + +void video_framebuff_change_mode(video_framebuff_t *fbuf, + enum v4l2_buf_mode mode) +{ + irqstate_t flags; + + flags = enter_critical_section(); + if (fbuf->mode != mode) + { + if (fbuf->vbuf_tail) + { + if (mode == V4L2_BUF_MODE_RING) + { + fbuf->vbuf_tail->next = fbuf->vbuf_top; + fbuf->vbuf_next_dma = fbuf->vbuf_top; + } + else + { + fbuf->vbuf_tail->next = NULL; + fbuf->vbuf_next_dma = fbuf->vbuf_top; + } + } + fbuf->mode = mode; + } + leave_critical_section(flags); +} + +vbuf_container_t *video_framebuff_pop_curr_container(video_framebuff_t *fbuf) +{ + irqstate_t flags; + vbuf_container_t *ret = NULL; + + flags = enter_critical_section(); + if (fbuf->vbuf_top != NULL) + { + ret = dequeue_vbuf_unsafe(fbuf); + } + + leave_critical_section(flags); + + return ret; +} diff --git a/drivers/video/video_framebuff.h b/drivers/video/video_framebuff.h new file mode 100644 index 0000000000..51699553b5 --- /dev/null +++ b/drivers/video/video_framebuff.h @@ -0,0 +1,90 @@ +/**************************************************************************** + * drivers/video/video_framebuff.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __VIDEO_VIDEO_FRAMEBUFF_H__ +#define __VIDEO_VIDEO_FRAMEBUFF_H__ + +#include +#include + +struct vbuf_container_s +{ + struct v4l2_buffer buf; /* Buffer information */ + struct vbuf_container_s *next; /* pointer to next buffer */ +}; + +typedef struct vbuf_container_s vbuf_container_t; + +struct video_framebuff_s +{ + enum v4l2_buf_mode mode; + sem_t lock_empty; + int container_size; + vbuf_container_t *vbuf_alloced; + vbuf_container_t *vbuf_empty; + vbuf_container_t *vbuf_top; + vbuf_container_t *vbuf_tail; + vbuf_container_t *vbuf_dma; + vbuf_container_t *vbuf_next_dma; +}; + +typedef struct video_framebuff_s video_framebuff_t; + +/* Buffer access interface. */ + +void video_framebuff_init + (video_framebuff_t *fbuf); +void video_framebuff_uninit + (video_framebuff_t *fbuf); +int video_framebuff_realloc_container + (video_framebuff_t *fbuf, int sz); +vbuf_container_t *video_framebuff_get_container + (video_framebuff_t *fbuf); +void video_framebuff_free_container + (video_framebuff_t *fbuf, vbuf_container_t *cnt); +void video_framebuff_queue_container + (video_framebuff_t *fbuf, vbuf_container_t *tgt); +vbuf_container_t *video_framebuff_dq_valid_container + (video_framebuff_t *fbuf); +vbuf_container_t *video_framebuff_get_dma_container + (video_framebuff_t *fbuf); +vbuf_container_t *video_framebuff_pop_curr_container + (video_framebuff_t *fbuf); +void video_framebuff_dma_done + (video_framebuff_t *fbuf); +void video_framebuff_change_mode + (video_framebuff_t *fbuf, enum v4l2_buf_mode mode); + +#endif // __VIDEO_VIDEO_FRAMEBUFF_H__ diff --git a/include/nuttx/video/video.h b/include/nuttx/video/video.h new file mode 100644 index 0000000000..2123112c4a --- /dev/null +++ b/include/nuttx/video/video.h @@ -0,0 +1,646 @@ +/**************************************************************************** + * modules/include/video/video.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_VIDEO_H +#define __INCLUDE_NUTTX_VIDEO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "video_controls.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define _VIDIOCBASE (0x1000) + +#define _VIDIOC(nr) _IOC(_VIDIOCBASE,nr) + +/* Enumerate the formats supported by device */ + +#define VIDIOC_ENUM_FMT _VIDIOC(0x0001) + +/* Enumerate the framesizes supported by device */ + +#define VIDIOC_ENUM_FRAMESIZES _VIDIOC(0x0002) + +/* Enumerate the frameintervals supported by device */ + +#define VIDIOC_ENUM_FRAMEINTERVALS _VIDIOC(0x0003) + +/* Try format */ + +#define VIDIOC_TRY_FMT _VIDIOC(0x0004) + +/* Set the data format. */ + +#define VIDIOC_S_FMT _VIDIOC(0x0005) + +/* Set the frame interval. */ + +#define VIDIOC_S_PARM _VIDIOC(0x0006) + +/* Initiate user pointer I/O */ + +#define VIDIOC_REQBUFS _VIDIOC(0x0007) + +/* Enqueue an empty buffer */ + +#define VIDIOC_QBUF _VIDIOC(0x0008) + +/* Dequeue a filled buffer */ + +#define VIDIOC_DQBUF _VIDIOC(0x0009) + +/* Start streaming */ + +#define VIDIOC_STREAMON _VIDIOC(0x000A) + +/* Stop streaming */ + +#define VIDIOC_STREAMOFF _VIDIOC(0x000B) + +/* Do halfpush */ + +#define VIDIOC_DO_HALFPUSH _VIDIOC(0x000C) + +/* Start taking picture + * + * Type is int32_t, not address pointer.\n + * 0 or negative value means continuing until VIDIOC_TAKEPICT_STOP. \n + * Positive value(to be supported) means continuing + * up to a specified number of times or until VIDIOC_TAKEPICT_STOP. + */ + +#define VIDIOC_TAKEPICT_START _VIDIOC(0x000D) + +/* Stop taking picture */ + +#define VIDIOC_TAKEPICT_STOP _VIDIOC(0x000E) + +/* Query control */ + +#define VIDIOC_QUERYCTRL _VIDIOC(0x000F) + +/* Query control */ + +#define VIDIOC_QUERY_EXT_CTRL _VIDIOC(0x0010) + +/* Query menu */ + +#define VIDIOC_QUERYMENU _VIDIOC(0x0011) + +/* Get current control value. + * This request is a special case of VIDIOC_G_EXT_CTRLS. + * Address pointing to struct #v4l2_control + */ + +#define VIDIOC_G_CTRL _VIDIOC(0x0012) + +/* Set control value. + * This request is a special case of VIDIOC_S_EXT_CTRLS. + * Address pointing to struct #v4l2_control + */ + +#define VIDIOC_S_CTRL _VIDIOC(0x0013) + +/* Get current control value + * Address pointing to struct #v4l2_ext_controls + */ + +#define VIDIOC_G_EXT_CTRLS _VIDIOC(0x0014) + +/* Set control value + * Address pointing to struct #v4l2_ext_controls + */ + +#define VIDIOC_S_EXT_CTRLS _VIDIOC(0x0015) + +/* Cancel DQBUF + * enum #v4l2_buf_type + */ + +#define VIDIOC_CANCEL_DQBUF _VIDIOC(0x0016) + +#define VIDEO_HSIZE_QVGA (320) /* QVGA horizontal size */ +#define VIDEO_VSIZE_QVGA (240) /* QVGA vertical size */ +#define VIDEO_HSIZE_VGA (640) /* VGA horizontal size */ +#define VIDEO_VSIZE_VGA (480) /* VGA vertical size */ +#define VIDEO_HSIZE_QUADVGA (1280) /* QUADVGA horizontal size */ +#define VIDEO_VSIZE_QUADVGA (960) /* QUADVGA vertical size */ +#define VIDEO_HSIZE_HD (1280) /* HD horizontal size */ +#define VIDEO_VSIZE_HD (720) /* HD vertical size */ +#define VIDEO_HSIZE_FULLHD (1920) /* FULLHD horizontal size */ +#define VIDEO_VSIZE_FULLHD (1080) /* FULLHD vertical size */ +#define VIDEO_HSIZE_5M (2560) /* 5M horizontal size */ +#define VIDEO_VSIZE_5M (1920) /* 5M vertical size */ +#define VIDEO_HSIZE_3M (2048) /* 3M horizontal size */ +#define VIDEO_VSIZE_3M (1536) /* 3M vertical size */ + +/* Four-character-code (FOURCC) */ + +#define v4l2_fourcc(a, b, c, d)\ + ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ + ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) +#define v4l2_fourcc_be(a, b, c, d) (v4l2_fourcc(a, b, c, d) | (1 << 31)) + +/* YUV 4:2:2 */ + +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') + +/* RGB565 */ + +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') + +/* JFIF JPEG */ + +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') + +/* JPEG + sub image */ + +#define V4L2_PIX_FMT_JPEG_WITH_SUBIMG v4l2_fourcc('J', 'S', 'U', 'B') + +/* MAX length of v4l2_fmtdesc description string */ + +#define V4L2_FMT_DSC_MAX (32) + +/* MAX length of v4l2_query_ext_ctrl dims array */ + +#define V4L2_CTRL_MAX_DIMS (4) + +/* MAX value of VIDIOC_REQBUFS count parameter */ + +#define V4L2_REQBUFS_COUNT_MAX (256) + +/* Buffer error flag */ + +#define V4L2_BUF_FLAG_ERROR (0x0001) + +/**************************************************************************** + * Public Types + ****************************************************************************/ +/* Buffer type. + * Currently, support only V4L2_BUF_TYPE_VIDEO_CAPTURE and + * V4L2_BUF_TYPE_STILL_CAPTURE. + */ + +enum v4l2_buf_type +{ + V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, /* single-planar video capture stream */ + V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, /* single-planar video output stream */ + V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, /* video overlay */ + V4L2_BUF_TYPE_VBI_CAPTURE = 4, /* raw VBI capture stream */ + V4L2_BUF_TYPE_VBI_OUTPUT = 5, /* raw VBI output stream */ + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, /* sliced VBI capture stream */ + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, /* sliced VBI output stream */ + V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, /* video output overlay */ + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, /* multi-planar video capture stream */ + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, /* multi-planar video output stream */ + V4L2_BUF_TYPE_SDR_CAPTURE = 11, /* Software Defined Radio capture stream */ + V4L2_BUF_TYPE_SDR_OUTPUT = 12, /* Software Defined Radio output stream */ + V4L2_BUF_TYPE_META_CAPTURE = 13, /* metadata capture */ + V4L2_BUF_TYPE_PRIVATE = 0x80, /* Deprecated, do not use */ + V4L2_BUF_TYPE_STILL_CAPTURE = 0x81 /* single-planar still capture stream */ +}; + +/* Memory I/O method. Currently, support only V4L2_MEMORY_USERPTR. */ + +enum v4l2_memory +{ + V4L2_MEMORY_MMAP = 1, /* memory mapping I/O */ + V4L2_MEMORY_USERPTR = 2, /* user pointer I/O */ + V4L2_MEMORY_OVERLAY = 3, /* overlay I/O */ + V4L2_MEMORY_DMABUF = 4, /* DMA shared buffer I/O */ +}; + +/* Field order. Currently, support only V4L2_FIELD_ANY */ + +enum v4l2_field +{ + V4L2_FIELD_ANY = 0, /* driver can choose from none, */ + V4L2_FIELD_NONE = 1, /* this device has no fields ... */ + V4L2_FIELD_TOP = 2, /* top field only */ + V4L2_FIELD_BOTTOM = 3, /* bottom field only */ + V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ + V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one */ + V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ + V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into */ + V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field */ + V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field */ +}; + +/* Buffer mode */ + +enum v4l2_buf_mode +{ + V4L2_BUF_MODE_RING = 0, /* Ring structure */ + V4L2_BUF_MODE_FIFO = 1, /* FIFO structure */ +}; + +struct v4l2_requestbuffers +{ + uint32_t count; /* The number of buffers requested. + * Supported maximum is + * is V4L2_REQBUFS_COUNT_MAX(=256) + */ + uint32_t type; /* enum #v4l2_buf_type */ + uint32_t memory; /* enum #v4l2_memory */ + uint32_t mode; /* enum #v4l2_buf_mode */ +}; + +typedef struct v4l2_requestbuffers v4l2_requestbuffers_t; + +struct v4l2_timecode +{ + uint32_t type; + uint32_t flags; + uint8_t frames; + uint8_t seconds; + uint8_t minutes; + uint8_t hours; + uint8_t userbits[4]; +}; + +typedef struct v4l2_timecode v4l2_timecode_t; + +struct v4l2_plane +{ + uint32_t bytesused; + uint32_t length; + union + { + uint32_t mem_offset; + unsigned long userptr; + int fd; + } m; + uint32_t data_offset; + uint32_t reserved[11]; +}; + +typedef struct v4l2_plane v4l2_plane_t; + +/* struct v4l2_buffer + * Parameter of ioctl(VIDIOC_QBUF) and ioctl(VIDIOC_DQBUF). + * Currently, support only index, type, bytesused, memory, + * m.userptr, and length. + */ + +struct v4l2_buffer +{ + uint16_t index; /* buffer id */ + uint16_t type; /* enum #v4l2_buf_type */ + uint32_t bytesused; /* Driver sets the image size */ + uint16_t flags; /* buffer flags. */ + uint16_t field; /* the field order of the image */ + struct v4l2_timecode timecode; /* frame timecode */ + uint16_t sequence; /* frame sequence number */ + uint16_t memory; /* enum #v4l2_memory */ + union + { + uint32_t offset; + unsigned long userptr; /* address of buffer */ + struct v4l2_plane *planes; + int fd; + } m; + uint32_t length; /* user set the buffer size */ +}; + +typedef struct v4l2_buffer v4l2_buffer_t; + +struct v4l2_fmtdesc +{ + uint16_t index; /* Format number */ + uint16_t type; /* enum v4l2_buf_type */ + uint32_t flags; + char description[V4L2_FMT_DSC_MAX]; /* Description string */ + uint32_t pixelformat; /* Format fourcc */ + uint32_t subimg_pixelformat; /* Format fourcc */ +}; + +enum v4l2_frmsizetypes +{ + V4L2_FRMSIZE_TYPE_DISCRETE = 1, /* Discrete value */ + V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, /* Continous value */ + V4L2_FRMSIZE_TYPE_STEPWISE = 3, /* Step value */ +}; + +struct v4l2_frmsize_discrete +{ + uint16_t width; /* Frame width [pixel] */ + uint16_t height; /* Frame height [pixel] */ +}; + +struct v4l2_frmsize_stepwise +{ + uint16_t min_width; /* Minimum frame width [pixel] */ + uint16_t max_width; /* Maximum frame width [pixel] */ + uint16_t step_width; /* Frame width step size [pixel] */ + uint16_t min_height; /* Minimum frame height [pixel] */ + uint16_t max_height; /* Maximum frame height [pixel] */ + uint16_t step_height; /* Frame height step size [pixel] */ +}; + +struct v4l2_frmsizeenum +{ + uint32_t index; /* Frame size number */ + uint32_t buf_type; /* enum #v4l2_buf_type */ + uint32_t pixel_format; /* Pixel format */ + uint32_t type; /* Frame size type the device supports. */ + union + { /* Frame size */ + struct v4l2_frmsize_discrete discrete; /* Use in type = + * V4L2_FRMSIZE_TYPE_DISCRETE + * case + */ + struct v4l2_frmsize_stepwise stepwise; /* Use in type = + * V4L2_FRMSIZE_TYPE_CONTINUOUS + * or V4L2_FRMSIZE_TYPE_STEPWISE + * case + */ + }; + uint32_t subimg_pixel_format; /* Pixel format of sub image */ + uint32_t subimg_type; /* Frame size type of subimage. */ + + union + { /* Frame size of subimage */ + struct v4l2_frmsize_discrete discrete; /* Use in subimg_type = + * V4L2_FRMSIZE_TYPE_DISCRETE + * case + */ + struct v4l2_frmsize_stepwise stepwise; /* Use in subimg_type = + * V4L2_FRMSIZE_TYPE_CONTINUOUS + * or V4L2_FRMSIZE_TYPE_STEPWISE + * case + */ + } subimg; +}; + +/* type of frame interval enumeration */ + +enum v4l2_frmivaltypes +{ + V4L2_FRMIVAL_TYPE_DISCRETE = 1, /* Discrete value */ + V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, /* Continuous value */ + V4L2_FRMIVAL_TYPE_STEPWISE = 3, /* Step value */ +}; + +/* Fraction */ + +struct v4l2_fract +{ + uint32_t numerator; /* numerator */ + uint32_t denominator; /* denominator */ +}; + +/* frame interval enumeration with stepwise format */ + +struct v4l2_frmival_stepwise +{ + struct v4l2_fract min; /* Minimum frame interval [s] */ + struct v4l2_fract max; /* Maximum frame interval [s] */ + struct v4l2_fract step; /* Frame interval step size [s] */ +}; + +struct v4l2_frmivalenum +{ + uint32_t index; /* Frame format index */ + uint32_t buf_type; /* enum #v4l2_buf_type */ + uint32_t pixel_format; /* Pixel format */ + uint16_t width; /* Frame width */ + uint16_t height; /* Frame height */ + uint32_t subimg_pixel_format; /* Pixel format for sub image */ + uint16_t subimg_width; /* Frame width for sub image */ + uint16_t subimg_height; /* Frame height for sub image */ + uint32_t type; /* Frame interval type */ + union + { /* Frame interval */ + struct v4l2_fract discrete; + struct v4l2_frmival_stepwise stepwise; + }; +}; + +/* Single-planar format structure. */ + +struct v4l2_pix_format +{ + uint16_t width; /* Image width in pixels */ + uint16_t height; /* Image height in pixels */ + uint32_t pixelformat; /* The pixel format or type of compression. */ + uint16_t subimg_width; /* sub image width in pixels in case of pixelformat = V4L2_PIX_FMT_JPEG_WITH_SUBIMG */ + uint16_t subimg_height; /* sub image height in pixels in case of pixelformat = V4L2_PIX_FMT_JPEG_WITH_SUBIMG */ + uint32_t subimg_pixelformat; /* The pixel format of sub image in case of pixelformat = V4L2_PIX_FMT_JPEG_WITH_SUBIMG */ + uint32_t field; /* enum #v4l2_field */ + uint32_t bytesperline; /* for padding, zero if unused */ + uint32_t sizeimage; /* Size in bytes of the buffer to hold a complete image */ + uint32_t colorspace; /* Image colorspace */ + uint32_t priv; /* private data, depends on pixelformat */ + uint32_t flags; /* format flags (V4L2_PIX_FMT_FLAG_*) */ + union + { + uint32_t ycbcr_enc; /* enum v4l2_ycbcr_encoding */ + uint32_t hsv_enc; /* enum v4l2_hsv_encoding */ + }; + uint32_t quantization; /* enum v4l2_quantization */ + uint32_t xfer_func; /* enum v4l2_xfer_func */ +}; + +typedef struct v4l2_pix_format v4l2_pix_format_t; + +struct v4l2_format +{ + uint32_t type; /* enum #v4l2_buf_type. */ + union + { + struct v4l2_pix_format pix; /* image format */ + } fmt; +}; + +typedef struct v4l2_format v4l2_format_t; + +struct v4l2_captureparm +{ + uint32_t capability; /* Supported modes */ + uint32_t capturemode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in seconds */ + uint32_t extendedmode; /* Driver-specific extensions */ + uint32_t readbuffers; /* # of buffers for read */ +}; + +struct v4l2_streamparm +{ + uint32_t type; /* enum v4l2_buf_type */ + union + { + struct v4l2_captureparm capture; + } parm; +}; + +enum v4l2_ctrl_type +{ + V4L2_CTRL_TYPE_INTEGER = 1, + V4L2_CTRL_TYPE_BOOLEAN = 2, + V4L2_CTRL_TYPE_MENU = 3, + V4L2_CTRL_TYPE_BUTTON = 4, + V4L2_CTRL_TYPE_INTEGER64 = 5, + V4L2_CTRL_TYPE_CTRL_CLASS = 6, + V4L2_CTRL_TYPE_STRING = 7, + V4L2_CTRL_TYPE_BITMASK = 8, + V4L2_CTRL_TYPE_INTEGER_MENU = 9, + V4L2_CTRL_TYPE_U8FIXEDPOINT_Q7 = 10, + V4L2_CTRL_TYPE_U16FIXEDPOINT_Q8 = 11, + V4L2_CTRL_TYPE_INTEGER_TIMES_3 = 12, + + /* Compound types are >= 0x0100 */ + + V4L2_CTRL_COMPOUND_TYPES = 0x0100, + V4L2_CTRL_TYPE_U8 = 0x0100, + V4L2_CTRL_TYPE_U16 = 0x0101, + V4L2_CTRL_TYPE_U32 = 0x0102, +}; + +struct v4l2_queryctrl +{ + uint16_t ctrl_class; /* Control class */ + uint16_t id; /* Control id */ + uint16_t type; /* enum #v4l2_ctrl_type */ + char name[32]; /* Name of control */ + int32_t minimum; /* Minimum value */ + int32_t maximum; /* Maximum value */ + uint32_t step; /* step */ + int32_t default_value; /* Default value */ + uint32_t flags; /* Flag */}; + +struct v4l2_query_ext_ctrl +{ + uint16_t ctrl_class; /* Control class */ + uint16_t id; /* Control id */ + uint16_t type; /* enum #v4l2_ctrl_type */ + char name[32]; /* Name of control */ + int64_t minimum; /* Minimum value */ + int64_t maximum; /* Maximum value */ + uint64_t step; /* step */ + int64_t default_value; /* Default value */ + uint32_t flags; /* Flag */ + uint32_t elem_size; /* size of each element */ + uint32_t elems; /* number of elements */ + uint32_t nr_of_dims; /* number of dimensions */ + uint32_t dims[V4L2_CTRL_MAX_DIMS]; /* Dimensions */ +}; + +struct v4l2_querymenu +{ + uint16_t ctrl_class; /* camera control class */ + uint16_t id; /* camera control id */ + uint32_t index; /* index of menu. */ + union + { + char name[32]; /* name of menu */ + int64_t value; /* value of menu */ + }; +} __attribute__ ((packed)); + +struct v4l2_control +{ + uint16_t id; + int32_t value; +}; + +/* structure for each control of + * ioctl(VIDIOC_G_EXT_CTRLS / VIDIOC_S_EXT_CTRLS) + */ + +struct v4l2_ext_control +{ + uint16_t id; /* camera control id */ + uint16_t size; /* size of value(not use) */ + union + { + int32_t value; /* QUERY_EXT_CTRL type = INTEGER, xxx */ + int64_t value64; /* QUERY_EXT_CTRL type = INTEGER64, MENU */ + char *string; + uint8_t *p_u8; /* QUERY_EXT_CTRL type = U8 */ + uint16_t *p_u16; /* QUERY_EXT_CTRL type = U16 */ + uint32_t *p_u32; /* QUERY_EXT_CTRL type = U32 */ + void *ptr; + }; +} __attribute__ ((packed)); + +struct v4l2_ext_controls +{ + union + { + uint16_t ctrl_class; /* camera control class */ + uint16_t which; + }; + uint16_t count; /* number of requests */ + uint16_t error_idx; /* index in that error occured */ + struct v4l2_ext_control *controls; /* each control information */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Initialize video driver. + * + * param [in] devpath: path to video device + * + * return On success, 0 is returned. On failure, + * negative value is returned. + */ + +int video_initialize(FAR const char *devpath); + +/* Uninitialize video driver. + * + * return On success, 0 is returned. On failure, + * negative value is returned. + */ + +int video_uninitialize(void); + +#ifdef __cplusplus +} +#endif +#endif /* __INCLUDE_NUTTX_VIDEO_H */ diff --git a/include/nuttx/video/video_controls.h b/include/nuttx/video/video_controls.h new file mode 100644 index 0000000000..51a6064554 --- /dev/null +++ b/include/nuttx/video/video_controls.h @@ -0,0 +1,230 @@ +/**************************************************************************** + * modules/include/video/video.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_VIDEO_CONTROLS_H +#define __INCLUDE_NUTTX_VIDEO_CONTROLS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Control classes */ + +#define V4L2_CTRL_CLASS_USER (0x0000) /**< Old-style 'user' controls */ +#define V4L2_CTRL_CLASS_CAMERA (0x0001) /**< Camera class controls */ +#define V4L2_CTRL_CLASS_FLASH (0x0002) /**< Camera flash controls */ +#define V4L2_CTRL_CLASS_JPEG (0x0003) /**< JPEG-compression controls */ + +/* User-class control IDs */ + +#define V4L2_CID_BRIGHTNESS (0) /**< Brightness */ +#define V4L2_CID_CONTRAST (1) /**< Contrast */ +#define V4L2_CID_SATURATION (2) /**< Saturation */ +#define V4L2_CID_HUE (3) /**< Hue */ +#define V4L2_CID_AUTO_WHITE_BALANCE (4) /**< AWB */ +#define V4L2_CID_RED_BALANCE (5) /**< Red balance */ +#define V4L2_CID_BLUE_BALANCE (6) /**< Blue balance */ +#define V4L2_CID_GAMMA (7) /**< Gamma value adjustment */ +#define V4L2_CID_GAMMA_CURVE (8) /**< Gamma curve adjustment */ +#define V4L2_CID_EXPOSURE (9) /**< Exposure value */ +#define V4L2_CID_HFLIP (10) /**< Mirror horizontally(VIDEO) */ +#define V4L2_CID_VFLIP (11) /**< Mirror vertically(VIDEO) */ +#define V4L2_CID_HFLIP_STILL (12) /**< Mirror horizontally(STILL) */ +#define V4L2_CID_VFLIP_STILL (13) /**< Mirror vertically(STILL) */ +#define V4L2_CID_SHARPNESS (14) /**< Sharpness */ +#define V4L2_CID_COLOR_KILLER (15) /**< Color killer */ +#define V4L2_CID_COLORFX (16) /**< Color effect */ + +/** enumeration for V4L2_CID_COLORFX */ + +enum v4l2_colorfx +{ + V4L2_COLORFX_NONE = 0, /**< no effect */ + V4L2_COLORFX_BW = 1, /**< Black/white */ + V4L2_COLORFX_SEPIA = 2, /**< Sepia */ + V4L2_COLORFX_NEGATIVE = 3, /**< positive/negative inversion */ + V4L2_COLORFX_EMBOSS = 4, /**< Emboss */ + V4L2_COLORFX_SKETCH = 5, /**< Sketch */ + V4L2_COLORFX_SKY_BLUE = 6, /**< Sky blue */ + V4L2_COLORFX_GRASS_GREEN = 7, /**< Grass green */ + V4L2_COLORFX_SKIN_WHITEN = 8, /**< Skin whiten */ + V4L2_COLORFX_VIVID = 9, /**< Vivid */ + V4L2_COLORFX_AQUA = 10, /**< Aqua */ + V4L2_COLORFX_ART_FREEZE = 11, /**< Art freeze */ + V4L2_COLORFX_SILHOUETTE = 12, /**< Silhouette */ + V4L2_COLORFX_SOLARIZATION = 13, /**< Solarization */ + V4L2_COLORFX_ANTIQUE = 14, /**< Antique */ + V4L2_COLORFX_SET_CBCR = 15, /**< Set CbCr */ + V4L2_COLORFX_PASTEL = 16 /**< Pastel */ +}; +#define V4L2_CID_AUTOBRIGHTNESS (17) /**< Auto brightness */ +#define V4L2_CID_ROTATE (18) /**< Rotation */ + +/** Camera class control IDs */ + +#define V4L2_CID_EXPOSURE_AUTO (0) /**< Auto exposure */ + +/** enumeration for V4L2_CID_EXPOSURE_AUTO */ + +enum v4l2_exposure_auto_type +{ + /** exposure time:auto, iris aperture:auto */ + + V4L2_EXPOSURE_AUTO = 0, + + /** exposure time:manual, iris aperture:manual */ + + V4L2_EXPOSURE_MANUAL = 1, + + /** exposure time:manual, iris aperture:auto */ + + V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, + + /** exposure time:auto, iris aperture:manual */ + + V4L2_EXPOSURE_APERTURE_PRIORITY = 3 +}; +#define V4L2_CID_EXPOSURE_ABSOLUTE (1) /**< Exposure time */ + +#define V4L2_CID_FOCUS_ABSOLUTE (2) /** Focus */ +#define V4L2_CID_FOCUS_RELATIVE (3) /** Focus */ +#define V4L2_CID_FOCUS_AUTO (4) /** Auto focus */ + +#define V4L2_CID_ZOOM_ABSOLUTE (5) /** Zoom(absolute) */ +#define V4L2_CID_ZOOM_RELATIVE (6) /** Zoom(relative) */ +#define V4L2_CID_ZOOM_CONTINUOUS (7) /** Continuous zoom */ + +#define V4L2_CID_IRIS_ABSOLUTE (8) /** Iris(absolute) */ +#define V4L2_CID_IRIS_RELATIVE (9) /** Iris(relative) */ + +#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE (10) /**< Preset white balance */ + +/** enumeration for V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE */ + +enum v4l2_auto_n_preset_white_balance +{ + V4L2_WHITE_BALANCE_MANUAL = 0, /**< Manual */ + V4L2_WHITE_BALANCE_AUTO = 1, /**< Automatic */ + V4L2_WHITE_BALANCE_INCANDESCENT = 2, /**< Incandescent */ + V4L2_WHITE_BALANCE_FLUORESCENT = 3, /**< Fluorescent */ + V4L2_WHITE_BALANCE_FLUORESCENT_H = 4, /**< Fluorescent H */ + V4L2_WHITE_BALANCE_HORIZON = 5, /**< Horizon */ + V4L2_WHITE_BALANCE_DAYLIGHT = 6, /**< Daylight */ + V4L2_WHITE_BALANCE_FLASH = 7, /**< Flash */ + V4L2_WHITE_BALANCE_CLOUDY = 8, /**< Cloudy */ + V4L2_WHITE_BALANCE_SHADE = 9, /**< Shade */ +}; + +#define V4L2_CID_WIDE_DYNAMIC_RANGE (11) /**< Wide dynamic range */ +#define V4L2_CID_IMAGE_STABILIZATION (12) /**< Image stabilization */ + +#define V4L2_CID_ISO_SENSITIVITY (13) /**< ISO sensitivity */ +#define V4L2_CID_ISO_SENSITIVITY_AUTO (14) /**< Auto ISO sensitivity */ + +/** enumeration for V4L2_CID_ISO_SENSITIVITY_AUTO */ + +enum v4l2_iso_sensitivity_auto_type +{ + V4L2_ISO_SENSITIVITY_MANUAL = 0, /**< Manual */ + V4L2_ISO_SENSITIVITY_AUTO = 1, /**< Automatic */ +}; + +#define V4L2_CID_EXPOSURE_METERING (15) /**< Exposure metering */ + +/** enumeration for V4L2_CID_EXPOSURE_METERING */ + +enum v4l2_exposure_metering +{ + V4L2_EXPOSURE_METERING_AVERAGE = 0, /**< Average */ + V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1, /**< Center weighted */ + V4L2_EXPOSURE_METERING_SPOT = 2, /**< Spot */ + V4L2_EXPOSURE_METERING_MATRIX = 3, /**< Matrix */ +}; + +#define V4L2_CID_SCENE_MODE (16) /**< Scene selection */ + +/** enumeration for V4L2_CID_SCENE_MODE */ + +enum v4l2_scene_mode +{ + V4L2_SCENE_MODE_NONE = 0, /**< No scene */ + V4L2_SCENE_MODE_BACKLIGHT = 1, /**< Backlight */ + V4L2_SCENE_MODE_BEACH_SNOW = 2, /**< Beach snow */ + V4L2_SCENE_MODE_CANDLE_LIGHT = 3, /**< Candle light */ + V4L2_SCENE_MODE_DAWN_DUSK = 4, /**< Dawn dask */ + V4L2_SCENE_MODE_FALL_COLORS = 5, /**< Fall colors */ + V4L2_SCENE_MODE_FIREWORKS = 6, /**< Fire works */ + V4L2_SCENE_MODE_LANDSCAPE = 7, /**< Landscape */ + V4L2_SCENE_MODE_NIGHT = 8, /**< Night */ + V4L2_SCENE_MODE_PARTY_INDOOR = 9, /**< Indoor party */ + V4L2_SCENE_MODE_PORTRAIT = 10, /**< Portrait */ + V4L2_SCENE_MODE_SPORTS = 11, /**< Sports */ + V4L2_SCENE_MODE_SUNSET = 12, /**< Sunset */ + V4L2_SCENE_MODE_TEXT = 13 /**< Text */ +}; + +#define V4L2_CID_3A_LOCK (17) /**< Lock 3A */ +#define V4L2_LOCK_EXPOSURE (1 << 0) /**< Exposure bit for + V4L2_CID_3A_LOCK */ +#define V4L2_LOCK_WHITE_BALANCE (1 << 1) /**< White balance bit for + V4L2_CID_3A_LOCK */ +#define V4L2_LOCK_FOCUS (1 << 2) /**< Focus bit for + V4L2_CID_3A_LOCK */ + +#define V4L2_CID_AUTO_FOCUS_START (18) /**< Start single AF */ +#define V4L2_CID_AUTO_FOCUS_STOP (19) /**< Stop single AF */ + +/** Flash and privacy (indicator) light controls */ + +#define V4L2_CID_FLASH_LED_MODE (0) + +/** enumeration for V4L2_CID_FLASH_LED_MODE */ + +enum v4l2_flash_led_mode +{ + V4L2_FLASH_LED_MODE_NONE, /**< Not use LED */ + V4L2_FLASH_LED_MODE_FLASH, /**< Flash mode */ + V4L2_FLASH_LED_MODE_TORCH, /**< Torch mode */ +}; + +/* JPEG-class control IDs */ + +#define V4L2_CID_JPEG_COMPRESSION_QUALITY (0) /**< JPEG quality */ + +#endif /* __INCLUDE_NUTTX_VIDEO_CONTROLS_H */ diff --git a/include/nuttx/video/video_halif.h b/include/nuttx/video/video_halif.h new file mode 100644 index 0000000000..2518edc159 --- /dev/null +++ b/include/nuttx/video/video_halif.h @@ -0,0 +1,99 @@ +/**************************************************************************** + * modules/include/video/video_halif.h + * + * Copyright 2018 Sony Semiconductor Solutions Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of Sony Semiconductor Solutions Corporation nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_VIDEO_HALIF_H +#define __INCLUDE_NUTTX_VIDEO_HALIF_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct video_devops_s +{ + CODE int (*open)(FAR void *video_priv); + CODE int (*close)(void); + + CODE int (*do_halfpush)(bool enable); + CODE int (*set_buftype)(enum v4l2_buf_type type); + CODE int (*set_buf)(uint32_t bufaddr, uint32_t bufsize); + CODE int (*cancel_dma)(void); + CODE int (*get_range_of_fmt)(FAR struct v4l2_fmtdesc *format); + CODE int (*get_range_of_framesize)(FAR struct v4l2_frmsizeenum *frmsize); + CODE int (*try_format)(FAR struct v4l2_format *format); + CODE int (*set_format)(FAR struct v4l2_format *format); + CODE int (*get_range_of_frameinterval) + (FAR struct v4l2_frmivalenum *frmival); + CODE int (*set_frameinterval)(FAR struct v4l2_streamparm *parm); + CODE int (*get_range_of_ctrlvalue)(FAR struct v4l2_query_ext_ctrl *range); + CODE int (*get_menu_of_ctrlvalue)(FAR struct v4l2_querymenu *menu); + CODE int (*get_ctrlvalue)(uint16_t ctrl_class, + FAR struct v4l2_ext_control *control); + CODE int (*set_ctrlvalue)(uint16_t ctrl_class, + FAR struct v4l2_ext_control *control); + CODE int (*refresh)(void); +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int video_common_notify_dma_done(uint8_t err_code, + uint32_t buf_type, + uint32_t datasize, + FAR void *priv); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_NUTTX_VIDEO_HALIF_H */