RK3588 has powerful Video Input function. It can support up to
2 MIPI DCPHY + 4 MIPI CSI DPHY (2 lanes), totally support 6 cameras input
The following takes the operation of MIPI DCPHY 0 and a GC8034 canmera as an example to introduce how to program the camera. GC8034 supports up to 3264x2448 pixels, and the wiring diagram is as follows
The V4L2 framework is used to operate the camera under Linux. This framework has a lot of content. This article only introduces its application programming part.
The nodes of "/dev/video*" require root privileges to perform read and write operations. Using the command line or the program compiled in C language to operate the camera requires root privileges. If you are using ssh or LX terminal, execute the following command to obtain root privileges first.
sudo su
The ISP-related services on the board are not running by default when they are turned on, and the data of this camera is currently configured in the kernel to be input to the ISP. Therefore, you must first run the following command to start the ISP-related services
/rockchip-test/camera/camera_rkaiq_test.sh
Whether you use the command line or C language to operate the camera device, you must first obtain its node. Under Linux, a camera channel (camera/isp/cif combination) is reflected as a media device in the system. There are three media devices on the board, namely /dev/media0 /dev/media1 /dev/media2, and you need to find the corresponding media devices. Execute the following commands
media-ctl -p -d /dev/media0
media-ctl -p -d /dev/media1
media-ctl -p -d /dev/media2
You can view the corresponding channels of the three media devices respectively.
Find the entity corresponding to rkisp_mainpath, which is the node of isp, as shown in the figure below
You can see that /dev/video22 is the node to be operated
Linux provides the v4l2-ctl command to operate the video node. If you want to capture images, you can execute the following command
v4l2-ctl -d /dev/video22 --set-fmt-video=width=1632,height=1224,pixelformat=NV12 --stream-mmap --stream-skip=3 --stream-to=/tmp/isp.out --stream-count=10 --stream-poll
to capture images.
Among them, -d is the specified node
--set-fmt-video specifies the length, width and format of the image. isp has the function of reducing. The format can be NV12 or NV16, which has nothing to do with the data format of the camera. The original format of the camera is generally RGB, and it is NV12 or NV16 after isp conversion
--stream-mmap specifies the buffer type as mmap
--stream-skip discards the previous frames before starting to capture
--stream-to specifies the output file
--stream-count captures the number of frames
--stream-poll uses poll to capture images
After executing the above command, the NV12 format file will be saved in /tmp/isp.out, and put on the PC using adb or ssh. Under Windows, you can use the tool YUView to view it.
The following demo introduces how to grab a frame of image from the camera and store it in a file
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#define FMT_NUM_PLANES 1
struct frame_buffer {
void *start;
size_t length;
};
int main(int argc, char **argv)
{
int ret = 0;
enum v4l2_buf_type type;
int dev_fd = -1;
struct frame_buffer *buffers = NULL;
int file_fd = -1;
if (argc < 3) {
printf("v4l2_test dev_name save_file\n");
}
char *dev_name = argv[1]; // Camera device name
char *save_file_name = argv[2]; // Storage file name
file_fd = open(save_file_name, O_RDWR | O_CREAT , 0666); // Open the stored file
if(file_fd < 0) {
printf("cannot open %s \n",save_file_name);
return -1;
}
dev_fd = open(dev_name, O_RDWR | O_NONBLOCK, 0); // Open device
if(file_fd < 0) {
printf("cannot open %s \n",dev_name);
return -1;
}
// Get camera parameters
struct v4l2_capability cap;
memset(&cap, 0, sizeof(cap));
ret = ioctl(dev_fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0)
printf("failure VIDIOC_QUERYCAP\n");
else {
printf(" driver: %s\n", cap.driver);
printf(" card: %s\n", cap.card);
printf(" bus_info: %s\n", cap.bus_info);
printf(" version: %08X\n", cap.version);
printf(" capabilities: %08X\n", cap.capabilities);
}
// Set the video data format of the video device
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix.width = 1632;
fmt.fmt.pix.height = 1224;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; // V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;
// fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
ret = ioctl(dev_fd, VIDIOC_S_FMT, &fmt); // Set image format
if (ret < 0)
printf("VIDIOC_S_FMT failed\n");
// Apply for a kernel buffer to cache a frame
struct v4l2_requestbuffers req;
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
req.memory = V4L2_MEMORY_MMAP;
ret = ioctl(dev_fd, VIDIOC_REQBUFS, &req); // Request buffer, count is the number of requests
if (ret < 0)
printf("VIDIOC_REQBUFS failed\n");
if (req.count < 1)
printf("Insufficient buffer memory\n");
buffers = calloc(req.count, sizeof(*buffers)); // Create corresponding space in memory
struct v4l2_buffer buf; // A frame in the driver
struct v4l2_plane planes[1];
for (unsigned int i = 0; i < req.count; ++i) {
memset(&buf, 0, sizeof(buf));
memset(&planes, 0, sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
// If it is V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE type
buf.m.planes = planes;
buf.length = FMT_NUM_PLANES;
if (-1 == ioctl(dev_fd, VIDIOC_QUERYBUF, &buf)) // Map user space
printf("VIDIOC_QUERYBUF failed\n");
buffers[i].length = buf.m.planes[0].length;
buffers[i].start =
mmap(NULL /* start anywhere /, // Establish mapping relationship through mmap
buf.m.planes[0].length,
PROT_READ | PROT_WRITE / required /,
MAP_SHARED / recommended */,
dev_fd, buf.m.planes[0].m.mem_offset);
if (MAP_FAILED == buffers[i].start)
printf("mmap failed\n");
}
for (unsigned int i = 0; i < req.count; ++i) {
memset(&buf, 0, sizeof(buf));
memset(&planes, 0, sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
// If it is V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE type
bu