mirror of
https://github.com/apache/nuttx.git
synced 2025-12-10 20:24:51 +08:00
arch/sim: add v4l2 driver for sim
communicate with Linux host v4l2 drivers Signed-off-by: Peter Bee <bijunda1@xiaomi.com>
This commit is contained in:
@@ -265,6 +265,33 @@ endchoice
|
||||
|
||||
endif
|
||||
|
||||
config SIM_VIDEO
|
||||
bool "Simulated video support"
|
||||
depends on VIDEO
|
||||
default y
|
||||
|
||||
if SIM_VIDEO
|
||||
|
||||
choice
|
||||
prompt "Simulated video device type"
|
||||
default SIM_VIDEO_V4L2
|
||||
|
||||
config SIM_VIDEO_V4L2
|
||||
bool "V4L2 camera support on sim"
|
||||
depends on HOST_LINUX
|
||||
|
||||
endchoice
|
||||
|
||||
config HOST_VIDEO_DEV_PATH
|
||||
string "Host video device path"
|
||||
default "/dev/video0"
|
||||
|
||||
config SIM_VIDEO_DEV_PATH
|
||||
string "NuttX video device path"
|
||||
default "/dev/video"
|
||||
|
||||
endif
|
||||
|
||||
menu "Simulated Graphics/Input"
|
||||
|
||||
config SIM_X11FB
|
||||
@@ -462,10 +489,10 @@ config SIM_UART_NUMBER
|
||||
Under simulation, a NuttX port can be bound to a serial
|
||||
port on the host machine. This way NuttX can access the
|
||||
host's hardware directly.
|
||||
|
||||
|
||||
There are two possibilities regarding the host's port:
|
||||
it can be either a physical one, or a simulated one.
|
||||
|
||||
|
||||
In case of a physical port, NuttX will be able to open
|
||||
this port and communicate with any actual hardware that
|
||||
it is connected to. This is useful for testing code that
|
||||
@@ -473,18 +500,18 @@ config SIM_UART_NUMBER
|
||||
In order for this to work, NuttX port name must be set to
|
||||
the same name that the host is using for this port (e.g.
|
||||
/dev/ttyUSB0).
|
||||
|
||||
|
||||
Alternativelly, a "simulated" host port may be used to.
|
||||
This is useful if you need to also simulate the external
|
||||
hardware, or to have NuttX communicate with any other
|
||||
software in your system.
|
||||
You can create a "simulated" port in your host,
|
||||
by running:
|
||||
|
||||
|
||||
socat PTY,link=/dev/ttySIM0 PTY,link=/dev/ttyNX0
|
||||
stty -F /dev/ttySIM0 raw
|
||||
stty -F /dev/ttyNX0 raw
|
||||
|
||||
|
||||
This will create two new ports on your system.
|
||||
NuttX will use the ttySIM0 port, and another software
|
||||
may open and use the ttyNX0 port.
|
||||
@@ -498,7 +525,7 @@ config SIM_UART_BUFFER_SIZE
|
||||
---help---
|
||||
The size of the transmit and receive buffers of the
|
||||
simulated UART ports.
|
||||
|
||||
|
||||
Note that all ports will have the same buffer size.
|
||||
|
||||
config SIM_UART0_NAME
|
||||
@@ -508,7 +535,7 @@ config SIM_UART0_NAME
|
||||
---help---
|
||||
This is the name of the simulated UART port.
|
||||
The port will be mounted in NuttX under this name.
|
||||
|
||||
|
||||
A UART port must also exist on the host system
|
||||
with the exact same name specified here.
|
||||
|
||||
@@ -519,7 +546,7 @@ config SIM_UART1_NAME
|
||||
---help---
|
||||
This is the name of the simulated UART port.
|
||||
The port will be mounted in NuttX under this name.
|
||||
|
||||
|
||||
A UART port must also exist on the host system
|
||||
with the exact same name specified here.
|
||||
|
||||
@@ -530,7 +557,7 @@ config SIM_UART2_NAME
|
||||
---help---
|
||||
This is the name of the simulated UART port.
|
||||
The port will be mounted in NuttX under this name.
|
||||
|
||||
|
||||
A UART port must also exist on the host system
|
||||
with the exact same name specified here.
|
||||
|
||||
@@ -541,7 +568,7 @@ config SIM_UART3_NAME
|
||||
---help---
|
||||
This is the name of the simulated UART port.
|
||||
The port will be mounted in NuttX under this name.
|
||||
|
||||
|
||||
A UART port must also exist on the host system
|
||||
with the exact same name specified here.
|
||||
|
||||
|
||||
@@ -204,6 +204,12 @@ ifeq ($(CONFIG_SIM_SOUND_ALSA),y)
|
||||
STDLIBS += -lmad
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_VIDEO_V4L2),y)
|
||||
HOSTSRCS += sim_host_v4l2.c
|
||||
CSRCS += sim_video.c
|
||||
STDLIBS += -lv4l2
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SIM_HOSTFS),y)
|
||||
HOSTSRCS += sim_hostfs.c
|
||||
|
||||
|
||||
364
arch/sim/src/sim/posix/sim_host_v4l2.c
Normal file
364
arch/sim/src/sim/posix/sim_host_v4l2.c
Normal file
@@ -0,0 +1,364 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/posix/sim_host_v4l2.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 <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "sim_hostvideo.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define MAX_REQBUFS 3
|
||||
|
||||
#define WARN(fmt, ...) \
|
||||
syslog(LOG_WARNING, "sim_host_video: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct host_video_dev_s
|
||||
{
|
||||
int fd;
|
||||
void *addrs[MAX_REQBUFS];
|
||||
size_t buflen[MAX_REQBUFS];
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static int host_video_ioctl(int fd, int request, void *arg)
|
||||
{
|
||||
int r;
|
||||
|
||||
do
|
||||
{
|
||||
r = ioctl(fd, request, arg);
|
||||
}
|
||||
while (-1 == r && EINTR == errno);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
bool host_video_is_available(const char *host_video_dev_path)
|
||||
{
|
||||
return access(host_video_dev_path, F_OK) == 0;
|
||||
}
|
||||
|
||||
struct host_video_dev_s *host_video_init(const char *host_video_dev_path)
|
||||
{
|
||||
int fd;
|
||||
struct host_video_dev_s *vdev;
|
||||
|
||||
fd = open(host_video_dev_path, O_RDWR | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror(host_video_dev_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev = calloc(1, sizeof(*vdev));
|
||||
if (vdev == NULL)
|
||||
{
|
||||
perror("host_video_init failed");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev->fd = fd;
|
||||
return vdev;
|
||||
}
|
||||
|
||||
int host_video_dq_buf(struct host_video_dev_s *vdev, uint8_t *addr,
|
||||
uint32_t size)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
/* Dequeue a buffer */
|
||||
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_DQBUF, &buf))
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
|
||||
/* No buffer in the outgoing queue */
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
perror("VIDIOC_DQBUF");
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > buf.bytesused)
|
||||
{
|
||||
size = buf.bytesused;
|
||||
}
|
||||
|
||||
memcpy(addr, vdev->addrs[buf.index], size);
|
||||
if (-1 == ioctl(vdev->fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
perror("VIDIOC_QBUF");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int host_video_uninit(struct host_video_dev_s *vdev)
|
||||
{
|
||||
if (vdev != NULL)
|
||||
{
|
||||
close(vdev->fd);
|
||||
free(vdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host_video_start_capture(struct host_video_dev_s *vdev)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
struct v4l2_requestbuffers reqbuf;
|
||||
enum v4l2_buf_type type;
|
||||
int i;
|
||||
|
||||
/* VIDIOC_REQBUFS initiate user pointer I/O */
|
||||
|
||||
memset(&reqbuf, 0, sizeof(reqbuf));
|
||||
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
reqbuf.memory = V4L2_MEMORY_MMAP;
|
||||
reqbuf.count = MAX_REQBUFS;
|
||||
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_REQBUFS, &reqbuf))
|
||||
{
|
||||
perror("VIDIOC_REQBUFS");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (reqbuf.count < 2)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
perror("Not enough buffers");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < reqbuf.count; i++)
|
||||
{
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_QUERYBUF, &buf))
|
||||
{
|
||||
perror("VIDIOC_QUERYBUF");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
vdev->addrs[i] = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, vdev->fd, buf.m.offset);
|
||||
if (vdev->addrs[i] == MAP_FAILED)
|
||||
{
|
||||
perror("Mmap failed");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
vdev->buflen[i] = buf.length;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_QBUF, &buf))
|
||||
{
|
||||
perror("VIDIOC_QBUF");
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_STREAMON, &type))
|
||||
{
|
||||
perror("VIDIOC_STREAMON");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
while (i--)
|
||||
{
|
||||
munmap(vdev->addrs[i], vdev->buflen[i]);
|
||||
vdev->addrs[i] = NULL;
|
||||
vdev->buflen[i] = 0;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int host_video_stop_capture(struct host_video_dev_s *vdev)
|
||||
{
|
||||
enum v4l2_buf_type type;
|
||||
int i;
|
||||
|
||||
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_STREAMOFF, &type))
|
||||
{
|
||||
perror("VIDIOC_STREAMOFF");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_REQBUFS; i++)
|
||||
{
|
||||
if (vdev->buflen[i] == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
munmap(vdev->addrs[i], vdev->buflen[i]);
|
||||
vdev->addrs[i] = NULL;
|
||||
vdev->buflen[i] = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host_video_set_fmt(struct host_video_dev_s *vdev,
|
||||
uint16_t width, uint16_t height, uint32_t fmt,
|
||||
uint32_t denom, uint32_t numer)
|
||||
{
|
||||
struct v4l2_format v4l2_fmt;
|
||||
struct v4l2_streamparm streamparm;
|
||||
|
||||
memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
|
||||
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
v4l2_fmt.fmt.pix.width = width;
|
||||
v4l2_fmt.fmt.pix.height = height;
|
||||
v4l2_fmt.fmt.pix.pixelformat = fmt;
|
||||
v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_S_FMT, &v4l2_fmt))
|
||||
{
|
||||
perror("VIDIOC_S_FMT");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&streamparm, 0, sizeof(streamparm));
|
||||
streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_G_PARM, &streamparm))
|
||||
{
|
||||
perror("VIDIOC_G_PARM");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
streamparm.parm.capture.capturemode |= V4L2_CAP_TIMEPERFRAME;
|
||||
streamparm.parm.capture.timeperframe.numerator = numer;
|
||||
streamparm.parm.capture.timeperframe.denominator = denom;
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_S_PARM, &streamparm))
|
||||
{
|
||||
perror("VIDIOC_S_PARM");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int host_video_try_fmt(struct host_video_dev_s *vdev,
|
||||
uint16_t width, uint16_t height, uint32_t fmt,
|
||||
uint32_t denom, uint32_t numer)
|
||||
{
|
||||
struct v4l2_format v4l2_fmt;
|
||||
struct v4l2_frmivalenum v4l2_frmival;
|
||||
|
||||
memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
|
||||
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
v4l2_fmt.fmt.pix.width = width;
|
||||
v4l2_fmt.fmt.pix.height = height;
|
||||
v4l2_fmt.fmt.pix.pixelformat = fmt;
|
||||
v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
|
||||
|
||||
if (-1 == host_video_ioctl(vdev->fd, VIDIOC_TRY_FMT, &v4l2_fmt))
|
||||
{
|
||||
perror("VIDIOC_TRY_FMT");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (v4l2_fmt.fmt.pix.pixelformat != fmt)
|
||||
{
|
||||
WARN("Pixel format not supported");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Need not check frame interval for STILL type */
|
||||
|
||||
if (!denom)
|
||||
{
|
||||
memset(&v4l2_frmival, 0, sizeof(v4l2_frmival));
|
||||
v4l2_frmival.width = width;
|
||||
v4l2_frmival.height = height;
|
||||
v4l2_frmival.pixel_format = fmt;
|
||||
while (host_video_ioctl(vdev->fd, VIDIOC_ENUM_FRAMEINTERVALS,
|
||||
&v4l2_frmival) == 0)
|
||||
{
|
||||
if (v4l2_frmival.type == V4L2_FRMSIZE_TYPE_DISCRETE &&
|
||||
v4l2_frmival.discrete.denominator == denom &&
|
||||
v4l2_frmival.discrete.numerator == numer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
v4l2_frmival.index++;
|
||||
}
|
||||
|
||||
WARN("Invalid frame interval, fallback to default");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
55
arch/sim/src/sim/sim_hostvideo.h
Normal file
55
arch/sim/src/sim/sim_hostvideo.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/sim_hostvideo.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H
|
||||
#define __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
struct host_video_dev_s;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
bool host_video_is_available(const char *host_video_dev_path);
|
||||
struct host_video_dev_s *host_video_init(const char *host_video_dev_path);
|
||||
int host_video_uninit(struct host_video_dev_s *vdev);
|
||||
int host_video_start_capture(struct host_video_dev_s *vdev);
|
||||
int host_video_stop_capture(struct host_video_dev_s *vdev);
|
||||
int host_video_dq_buf(struct host_video_dev_s *vdev, uint8_t *addr,
|
||||
uint32_t size);
|
||||
int host_video_set_fmt(struct host_video_dev_s *vdev,
|
||||
uint16_t width, uint16_t height, uint32_t fmt,
|
||||
uint32_t denom, uint32_t numer);
|
||||
int host_video_try_fmt(struct host_video_dev_s *vdev,
|
||||
uint16_t width, uint16_t height, uint32_t fmt,
|
||||
uint32_t denom, uint32_t numer);
|
||||
|
||||
#endif /* __ARCH_SIM_SRC_SIM_SIM_HOSTVIDEO_H */
|
||||
@@ -195,6 +195,10 @@ static int sim_loop_task(int argc, char **argv)
|
||||
sim_audio_loop();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SIM_VIDEO
|
||||
sim_video_loop();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MOTOR_FOC_DUMMY
|
||||
/* Update simulated FOC device */
|
||||
|
||||
|
||||
@@ -357,6 +357,13 @@ struct spi_dev_s *sim_spi_initialize(const char *filename);
|
||||
int sim_spi_uninitialize(struct spi_dev_s *dev);
|
||||
#endif
|
||||
|
||||
/* up_video.c ***************************************************************/
|
||||
|
||||
#ifdef CONFIG_SIM_VIDEO
|
||||
int sim_video_initialize(void);
|
||||
void sim_video_loop(void);
|
||||
#endif
|
||||
|
||||
/* Debug ********************************************************************/
|
||||
|
||||
#ifdef CONFIG_STACK_COLORATION
|
||||
|
||||
314
arch/sim/src/sim/sim_video.c
Normal file
314
arch/sim/src/sim/sim_video.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/****************************************************************************
|
||||
* arch/sim/src/sim/sim_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 <errno.h>
|
||||
#include <string.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
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
imgdata_capture_t capture_cb;
|
||||
uint32_t buf_size;
|
||||
uint8_t *next_buf;
|
||||
struct host_video_dev_s *vdev;
|
||||
} sim_video_priv_t;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Video image sensor operations */
|
||||
|
||||
static bool sim_video_is_available(void);
|
||||
static int sim_video_init(void);
|
||||
static int sim_video_uninit(void);
|
||||
static const char *sim_video_get_driver_name(void);
|
||||
static int sim_video_validate_frame_setting(imgsensor_stream_type_t type,
|
||||
uint8_t nr_datafmt,
|
||||
imgsensor_format_t *datafmts,
|
||||
imgsensor_interval_t *interval);
|
||||
static int sim_video_start_capture(imgsensor_stream_type_t type,
|
||||
uint8_t nr_datafmt,
|
||||
imgsensor_format_t *datafmts,
|
||||
imgsensor_interval_t *interval);
|
||||
static int sim_video_stop_capture(imgsensor_stream_type_t type);
|
||||
|
||||
/* Video image data operations */
|
||||
|
||||
static int sim_video_data_init(void);
|
||||
static int sim_video_data_uninit(void);
|
||||
static int sim_video_data_validate_frame_setting(uint8_t nr_datafmt,
|
||||
imgdata_format_t *datafmt,
|
||||
imgdata_interval_t *interv);
|
||||
static int sim_video_data_start_capture(uint8_t nr_datafmt,
|
||||
imgdata_format_t *datafmt,
|
||||
imgdata_interval_t *interval,
|
||||
imgdata_capture_t callback);
|
||||
static int sim_video_data_stop_capture(void);
|
||||
static int sim_video_data_validate_buf(uint8_t *addr, uint32_t size);
|
||||
static int sim_video_data_set_buf(uint8_t *addr, uint32_t size);
|
||||
|
||||
static uint32_t imgdata_fmt_to_v4l2(uint32_t pixelformat);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct imgsensor_ops_s g_sim_video_ops =
|
||||
{
|
||||
.is_available = sim_video_is_available,
|
||||
.init = sim_video_init,
|
||||
.uninit = sim_video_uninit,
|
||||
.get_driver_name = sim_video_get_driver_name,
|
||||
.validate_frame_setting = sim_video_validate_frame_setting,
|
||||
.start_capture = sim_video_start_capture,
|
||||
.stop_capture = sim_video_stop_capture,
|
||||
};
|
||||
|
||||
static const struct imgdata_ops_s g_sim_video_data_ops =
|
||||
{
|
||||
.init = sim_video_data_init,
|
||||
.uninit = sim_video_data_uninit,
|
||||
.validate_buf = sim_video_data_validate_buf,
|
||||
.set_buf = sim_video_data_set_buf,
|
||||
.validate_frame_setting = sim_video_data_validate_frame_setting,
|
||||
.start_capture = sim_video_data_start_capture,
|
||||
.stop_capture = sim_video_data_stop_capture,
|
||||
};
|
||||
|
||||
static sim_video_priv_t g_sim_video_priv;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/* Sensor op functions are mostly dummy */
|
||||
|
||||
static bool sim_video_is_available(void)
|
||||
{
|
||||
return host_video_is_available(CONFIG_HOST_VIDEO_DEV_PATH);
|
||||
}
|
||||
|
||||
static int sim_video_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_uninit(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *sim_video_get_driver_name(void)
|
||||
{
|
||||
return "V4L2 NuttX Sim Driver";
|
||||
}
|
||||
|
||||
static int sim_video_validate_frame_setting(imgsensor_stream_type_t type,
|
||||
uint8_t nr_fmt,
|
||||
imgsensor_format_t *fmt,
|
||||
imgsensor_interval_t *interval)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_start_capture(imgsensor_stream_type_t type,
|
||||
uint8_t nr_fmt,
|
||||
imgsensor_format_t *fmt,
|
||||
imgsensor_interval_t *interval)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_stop_capture(imgsensor_stream_type_t type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Data op functions do all the real work */
|
||||
|
||||
static int sim_video_data_init(void)
|
||||
{
|
||||
memset(&g_sim_video_priv, 0, sizeof(g_sim_video_priv));
|
||||
g_sim_video_priv.vdev = host_video_init(CONFIG_HOST_VIDEO_DEV_PATH);
|
||||
if (g_sim_video_priv.vdev == NULL)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_data_uninit(void)
|
||||
{
|
||||
return host_video_uninit(g_sim_video_priv.vdev);
|
||||
}
|
||||
|
||||
static int sim_video_data_validate_buf(uint8_t *addr, uint32_t size)
|
||||
{
|
||||
if (!addr || ((uintptr_t)(addr) & 0x1f))
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_data_set_buf(uint8_t *addr, uint32_t size)
|
||||
{
|
||||
g_sim_video_priv.next_buf = addr;
|
||||
g_sim_video_priv.buf_size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sim_video_data_validate_frame_setting(uint8_t nr_datafmt,
|
||||
imgdata_format_t *datafmt,
|
||||
imgdata_interval_t *interv)
|
||||
{
|
||||
uint32_t v4l2_fmt;
|
||||
|
||||
if (nr_datafmt > 1)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
v4l2_fmt = imgdata_fmt_to_v4l2(datafmt->pixelformat);
|
||||
return host_video_try_fmt(g_sim_video_priv.vdev, datafmt->width,
|
||||
datafmt->height, v4l2_fmt, interv->denominator,
|
||||
interv->numerator);
|
||||
}
|
||||
|
||||
static int sim_video_data_start_capture(uint8_t nr_datafmt,
|
||||
imgdata_format_t *datafmt,
|
||||
imgdata_interval_t *interval,
|
||||
imgdata_capture_t callback)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = host_video_set_fmt(g_sim_video_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)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
g_sim_video_priv.capture_cb = callback;
|
||||
return host_video_start_capture(g_sim_video_priv.vdev);
|
||||
}
|
||||
|
||||
static int sim_video_data_stop_capture(void)
|
||||
{
|
||||
g_sim_video_priv.next_buf = NULL;
|
||||
return host_video_stop_capture(g_sim_video_priv.vdev);
|
||||
}
|
||||
|
||||
/* Helper functions */
|
||||
|
||||
static uint32_t imgdata_fmt_to_v4l2(uint32_t pixelformat)
|
||||
{
|
||||
uint32_t fourcc;
|
||||
switch (pixelformat)
|
||||
{
|
||||
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:
|
||||
|
||||
/* Unsupported format */
|
||||
|
||||
fourcc = 0;
|
||||
}
|
||||
|
||||
return fourcc;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int sim_video_initialize(void)
|
||||
{
|
||||
imgsensor_register(&g_sim_video_ops);
|
||||
imgdata_register(&g_sim_video_data_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sim_video_uninitialize(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sim_video_loop(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (g_sim_video_priv.next_buf)
|
||||
{
|
||||
ret = host_video_dq_buf(g_sim_video_priv.vdev,
|
||||
g_sim_video_priv.next_buf,
|
||||
g_sim_video_priv.buf_size);
|
||||
if (ret > 0)
|
||||
{
|
||||
g_sim_video_priv.capture_cb(0, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <nuttx/serial/uart_rpmsg.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
#include <nuttx/video/fb.h>
|
||||
#include <nuttx/video/video.h>
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
#include <nuttx/wireless/pktradio.h>
|
||||
#include <nuttx/wireless/bluetooth/bt_null.h>
|
||||
@@ -291,6 +292,18 @@ int sim_bringup(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SIM_VIDEO
|
||||
/* Initialize and register the simulated video driver */
|
||||
|
||||
ret = video_initialize(CONFIG_SIM_VIDEO_DEV_PATH);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: video_initialize() failed: %d\n", ret);
|
||||
}
|
||||
|
||||
sim_video_initialize();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LCD
|
||||
|
||||
ret = board_lcd_initialize();
|
||||
|
||||
Reference in New Issue
Block a user