* arch/sim/src/sim/sim_camera.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 <errno.h>
#include <string.h>
#include <nuttx/wqueue.h>
#include <nuttx/spinlock.h>
#include <nuttx/video/imgsensor.h>
#include <nuttx/video/imgdata.h>
#include <nuttx/video/video.h>
#include "sim_hostvideo.h"
#include "sim_internal.h"
* Pre-processor Definitions
****************************************************************************/
#define SIM_CAMERA_PERIOD MSEC2TICK(CONFIG_SIM_LOOP_INTERVAL)
* Private Types
****************************************************************************/
typedef struct
{
struct imgdata_s data;
struct imgsensor_s sensor;
imgdata_capture_t capture_cb;
void *capture_arg;
uint32_t buf_size;
uint8_t *next_buf;
struct timeval *next_ts;
struct host_video_dev_s *vdev;
struct work_s work;
} sim_camera_priv_t;
* Private Function Prototypes
****************************************************************************/
static bool sim_camera_is_available(struct imgsensor_s *sensor);
static int sim_camera_init(struct imgsensor_s *sensor);
static int sim_camera_uninit(struct imgsensor_s *sensor);
static const char *sim_camera_get_driver_name(struct imgsensor_s *sensor);
static int sim_camera_validate_frame_setting(struct imgsensor_s *sensor,
imgsensor_stream_type_t type,
uint8_t nr_datafmt,
imgsensor_format_t *datafmts,
imgsensor_interval_t *interval);
static int sim_camera_start_capture(struct imgsensor_s *sensor,
imgsensor_stream_type_t type,
uint8_t nr_datafmt,
imgsensor_format_t *datafmts,
imgsensor_interval_t *interval);
static int sim_camera_stop_capture(struct imgsensor_s *sensor,
imgsensor_stream_type_t type);
static int sim_camera_data_init(struct imgdata_s *data);
static int sim_camera_data_uninit(struct imgdata_s *data);
static int
sim_camera_data_validate_frame_setting(struct imgdata_s *data,
uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interv);
static int sim_camera_data_start_capture(struct imgdata_s *data,
uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interval,
imgdata_capture_t callback,
void *arg);
static int sim_camera_data_stop_capture(struct imgdata_s *data);
static int sim_camera_data_set_buf(struct imgdata_s *data,
uint8_t nr_datafmts,
imgdata_format_t *datafmts,
uint8_t *addr, uint32_t size);
* Private Data
****************************************************************************/
static const struct imgsensor_ops_s g_sim_camera_ops =
{
.is_available = sim_camera_is_available,
.init = sim_camera_init,
.uninit = sim_camera_uninit,
.get_driver_name = sim_camera_get_driver_name,
.validate_frame_setting = sim_camera_validate_frame_setting,
.start_capture = sim_camera_start_capture,
.stop_capture = sim_camera_stop_capture,
};
static const struct imgdata_ops_s g_sim_camera_data_ops =
{
.init = sim_camera_data_init,
.uninit = sim_camera_data_uninit,
.set_buf = sim_camera_data_set_buf,
.validate_frame_setting = sim_camera_data_validate_frame_setting,
.start_capture = sim_camera_data_start_capture,
.stop_capture = sim_camera_data_stop_capture,
};
static const struct v4l2_frmsizeenum g_frmsizes[] =
{
{
.type = V4L2_FRMSIZE_TYPE_DISCRETE,
.discrete =
{
.width = 640,
.height = 480,
}
}
};
static struct v4l2_fmtdesc g_fmts[] =
{
{
.pixelformat = V4L2_PIX_FMT_YUV420,
.description = "YUV420",
}
};
static sim_camera_priv_t g_sim_camera_priv =
{
.data =
{
&g_sim_camera_data_ops
},
.sensor =
{
.ops = &g_sim_camera_ops,
.frmsizes_num = 1,
.frmsizes = g_frmsizes,
.fmtdescs_num = 1,
.fmtdescs = g_fmts,
}
};
* Private Functions
****************************************************************************/
static uint32_t imgdata_fmt_to_v4l2(uint32_t pixelformat)
{
uint32_t fourcc;
switch (pixelformat)
{
case IMGDATA_PIX_FMT_NV12:
fourcc = V4L2_PIX_FMT_NV12;
break;
case IMGDATA_PIX_FMT_YUV420P:
fourcc = V4L2_PIX_FMT_YUV420;
break;
case IMGDATA_PIX_FMT_YUYV:
fourcc = V4L2_PIX_FMT_YUYV;
break;
case IMGDATA_PIX_FMT_JPEG_WITH_SUBIMG:
fourcc = V4L2_PIX_FMT_JPEG;
break;
case IMGDATA_PIX_FMT_JPEG:
fourcc = V4L2_PIX_FMT_JPEG;
break;
case IMGDATA_PIX_FMT_RGB565:
fourcc = V4L2_PIX_FMT_RGB565;
break;
case IMGDATA_PIX_FMT_UYVY:
fourcc = V4L2_PIX_FMT_UYVY;
break;
default:
fourcc = 0;
}
return fourcc;
}
static bool sim_camera_is_available(struct imgsensor_s *sensor)
{
return true;
}
static int sim_camera_init(struct imgsensor_s *sensor)
{
return 0;
}
static int sim_camera_uninit(struct imgsensor_s *sensor)
{
return 0;
}
static const char *sim_camera_get_driver_name(struct imgsensor_s *sensor)
{
return "V4L2 NuttX Sim Driver";
}
static int sim_camera_validate_frame_setting(struct imgsensor_s *sensor,
imgsensor_stream_type_t type,
uint8_t nr_fmt,
imgsensor_format_t *fmt,
imgsensor_interval_t *interval)
{
return 0;
}
static int sim_camera_start_capture(struct imgsensor_s *sensor,
imgsensor_stream_type_t type,
uint8_t nr_fmt,
imgsensor_format_t *fmt,
imgsensor_interval_t *interval)
{
return 0;
}
static int sim_camera_stop_capture(struct imgsensor_s *sensor,
imgsensor_stream_type_t type)
{
return 0;
}
static int sim_camera_data_init(struct imgdata_s *data)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
priv->vdev = host_video_init(CONFIG_HOST_CAMERA_DEV_PATH);
if (priv->vdev == NULL)
{
return -ENODEV;
}
return 0;
}
static int sim_camera_data_uninit(struct imgdata_s *data)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
return host_video_uninit(priv->vdev);
}
static int sim_camera_data_validate_buf(uint8_t *addr, uint32_t size)
{
if (!addr || ((uintptr_t)(addr) & 0x1f))
{
return -EINVAL;
}
return 0;
}
static int sim_camera_data_set_buf(struct imgdata_s *data,
uint8_t nr_datafmts,
imgdata_format_t *datafmts,
uint8_t *addr, uint32_t size)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
if (sim_camera_data_validate_buf(addr, size) < 0)
{
return -EINVAL;
}
priv->next_buf = addr;
priv->buf_size = size;
return 0;
}
static int sim_camera_data_validate_frame_setting(struct imgdata_s *data,
uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interv)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
uint32_t v4l2_fmt;
if (nr_datafmt > 1)
{
return -ENOTSUP;
}
v4l2_fmt = imgdata_fmt_to_v4l2(datafmt->pixelformat);
return host_video_try_fmt(priv->vdev, datafmt->width,
datafmt->height, v4l2_fmt, interv->denominator,
interv->numerator);
}
static int sim_camera_data_start_capture(struct imgdata_s *data,
uint8_t nr_datafmt,
imgdata_format_t *datafmt,
imgdata_interval_t *interval,
imgdata_capture_t callback,
void *arg)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
int ret;
ret = host_video_set_fmt(priv->vdev,
datafmt[IMGDATA_FMT_MAIN].width,
datafmt[IMGDATA_FMT_MAIN].height,
imgdata_fmt_to_v4l2(
datafmt[IMGDATA_FMT_MAIN].pixelformat),
interval->denominator, interval->numerator);
if (ret < 0 && ret != -EBUSY)
{
return ret;
}
priv->capture_cb = callback;
priv->capture_arg = arg;
return host_video_start_capture(priv->vdev);
}
static int sim_camera_data_stop_capture(struct imgdata_s *data)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)data;
priv->next_buf = NULL;
return host_video_stop_capture(priv->vdev);
}
static void sim_camera_work(void *arg)
{
sim_camera_priv_t *priv = (sim_camera_priv_t *)arg;
struct timespec ts;
struct timeval tv;
int ret;
if (priv->next_buf)
{
irqstate_t flags = irq_save_nopreempt();
ret = host_video_dqbuf(priv->vdev, priv->next_buf, priv->buf_size);
if (ret > 0)
{
clock_gettime(CLOCK_MONOTONIC, &ts);
TIMESPEC_TO_TIMEVAL(&tv, &ts);
priv->capture_cb(0, ret, &tv, priv->capture_arg);
}
irq_restore_nopreempt(flags);
}
work_queue_next_wq(g_work_queue, &priv->work, sim_camera_work, arg,
SIM_CAMERA_PERIOD);
}
* Public Functions
****************************************************************************/
int sim_camera_initialize(void)
{
sim_camera_priv_t *priv = &g_sim_camera_priv;
imgsensor_register(&priv->sensor);
imgdata_register(&priv->data);
work_queue_wq(g_work_queue, &priv->work, sim_camera_work, priv,
SIM_CAMERA_PERIOD);
return 0;
}