VDMA读取图片数据有撕裂
故障现象如图:
使用硬件平台zynqMP
工具pelalinux 生成的linux工程
硬件框图:
linux应用操作:
配置设备树
&v_tpg_0{
compatible = "xlnx,v-tpg-8.0";
xlnx,ppc = <1>;
reset-gpios = <&gpio 81 1>;
xlnx,max-width = <1280>;
xlnx,max-height = <720>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
xlnx,video-format = <XVIP_VF_YUV_422>;
xlnx,video-width = <8>;
tpg_out: endpoint {
remote-endpoint = <&csc_in>;
};
};
};
};
&v_proc_ss_0{
compatible = "xlnx,v-vpss-csc";
reset-gpios = <&gpio 80 1>;
csc_ports: ports {
#address-cells = <1>;
#size-cells = <0>;
xlnx,max-width = <1280>;
xlnx,max-height = <720>;
csc_port0: port@0 {
reg = <0>;
xlnx,video-format = <XVIP_VF_YUV_422>;
xlnx,video-width = <8>;
csc_in: endpoint {
remote-endpoint = <&tpg_out>;
};
};
csc_port1: port@1 {
reg = <1>;
xlnx,video-format = <XVIP_VF_RBG>;
xlnx,video-width = <8>;
csc_out: endpoint {
remote-endpoint = <&vcap_tpg_in>;
};
};
};
};
&amba_pl {
vcap_tpg{
compatible = "xlnx,video";
dma-names = "port0";
dmas = <&axi_vdma_0 1>;
ports{
#address-cells = <1>;
#size-cells = <0>;
port@0{
reg = <0>;
direction = "input";
vcap_tpg_in: endpoint{
remote-endpoint = <&csc_out>;
};
};
};
};
};
root@xilinx-3eg:/mnt/dervice_ov5640/char_appcam# media-ctl -p -d /dev/media0
Media controller API version 5.4.0
Media device information
------------------------
driver xilinx-video
model Xilinx Video Composite Device
serial
bus info
hw revision 0x0
driver version 5.4.0
Device topology
- entity 1: vcap_tpg output 0 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video0
pad0: Sink
<- "80050000.v_proc_ss":1 [ENABLED]
- entity 5: 80000000.v_tpg (1 pad, 1 link)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Source
[fmt:UYVY8_1X16/1280x720@1/30 field:none colorspace:srgb]
-> "80050000.v_proc_ss":0 [ENABLED]
- entity 7: 80050000.v_proc_ss (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev1
pad0: Sink
[fmt:UYVY8_1X16/1280x720 field:none colorspace:srgb]
<- "80000000.v_tpg":0 [ENABLED]
pad1: Source
[fmt:RBG888_1X24/1280x720 field:none colorspace:rec709]
-> "vcap_tpg output 0":0 [ENABLED]
使用V4L2 获取图像数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <dlfcn.h>
#include <signal.h>
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
#include <linux/fb.h>
#include <poll.h>
#include <time.h>
#include <linux/xilinx-v4l2-controls.h>
#include <linux/sched.h>
#include <sched.h>
#define VIDEO_DEVICE_NAME "/dev/video0"
#define V4LSUB_DEVICE_NAME "/dev/v4l-subdev0"
#define FRAMEBUFFER_NAME "/dev/fb0"
#define IMAGE_FILE "f1.rgb"
#define BUFFER_COUNT 10
struct buffer {
void *start;
size_t length;
};
struct buffer* buffer_mmap;
char *fbp;
int fbfd;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
void Mem_Cpy(void *pTag,const void *pSrc,int nLen)
{
unsigned int *pTagBuf = (unsigned int *)pTag;
unsigned int *pSrcBuf = (unsigned int *)pSrc;
int i = 0;
for(i = 0;i < nLen / 4;i++)
{
pTagBuf[i] = pSrcBuf[i];
}
}
int GetSensorFormat(int fd)
{
struct v4l2_subdev_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.which = 1;
if (-1 == ioctl(fd, VIDIOC_SUBDEV_G_FMT, &fmt)){
printf("VIDIOC_SUBDEV_G_FMT fail\n");
return -1;
}
printf("fmt.which=%d\n",(int)fmt.which);
printf("fmt.format.width=%d\n",(int)fmt.format.width);
printf("fmt.format.height=%d\n",(int)fmt.format.height);
printf("fmt.format.code=%d\n",(int)fmt.format.code);
printf("fmt.format.field=%d\n",(int)fmt.format.field);
printf("fmt.format.colorspace=%d\n",(int)fmt.format.colorspace);
return 0;
}
int SetSensorFormat(int fd)
{
struct v4l2_subdev_format fmt;
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_TEST_PATTERN;
ctrl.value = 10;
ioctl(fd,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_XILINX_TPG_MOTION_SPEED;
ctrl.value = 10;
ioctl(fd,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_XILINX_TPG_ZPLATE_HOR_SPEED;
ctrl.value = 10;
ioctl(fd,VIDIOC_S_CTRL,&ctrl);
return 0;
}
int QueryVideoCap(int fd)
{
struct v4l2_capability cap;
if (-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
printf("VIDIOC_QUERYCAP fail\n");
return -1;
}
printf("cap.driver: %s\n", cap.driver);
printf("cap.card: %s\n", cap.card);
printf("cap.bus_info: %s\n", cap.bus_info);
printf("cap.capabilities= 0x%x\n", cap.capabilities);
printf("cap.device_caps= 0x%x\n", cap.device_caps);
return 0;
}
int GetVideoFormat(int fd)
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
{
printf("VIDIOC_G_FMT failed\n");
return -1;
}
//printf stream format
printf("Stream format informations:\n");
printf(" type: %d\n", fmt.type);
printf(" width: %d\n", fmt.fmt.pix.width);
printf(" height: %d\n", fmt.fmt.pix.height);
char fmtstr[8];
memset(fmtstr, 0, 8);
memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 8);
printf(" pixelformat: %s\n", fmtstr);
printf(" field: %d\n", fmt.fmt.pix.field);
printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);
printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);
printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);
return 0;
}
int SetVideoFormat(int fd)
{
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(struct v4l2_format));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width =1280;
fmt.fmt.pix.height =720;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
printf("Set format fail\n");
return -1;
}
printf("width = %d\n", fmt.fmt.pix.width);
printf("height = %d\n", fmt.fmt.pix.height);
printf("pixelformat = %d\n", fmt.fmt.pix.pixelformat);
return 0;
}
static void errno_exit(const char *s)
{
printf("ERR(%s):%s failed\r\n", __func__, s); //显示错误函数
fprintf(stderr,"%s error %d, %s\r\n",s ,errno, strerror(errno));
exit(EXIT_FAILURE);
}
int init_mmap(int fd)
{
struct v4l2_requestbuffers req;
req.count = BUFFER_COUNT;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
printf("BUFFER_COUNT is %d\n", BUFFER_COUNT);
if (ioctl(fd, VIDIOC_REQBUFS, &req)<0) {
printf("VIDIOC_REQBUFS fail\n");
return -1;
}
if (req.count < 2) {
printf("req.count is too small, req.count= %d\n", req.count);
return -1;
}
buffer_mmap = (struct buffer*)calloc(req.count, sizeof(struct buffer));
printf("buffer_mmap\r\n");
struct v4l2_buffer buf;
int i;
for (i = 0; i < req.count; ++i) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf)<0) {
printf("VIDIOC_QUERYBUF fail\n");
return -1;
}
buffer_mmap[i].length = buf.length;
buffer_mmap[i].start =
mmap(NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
fd, buf.m.offset);
if (MAP_FAILED == buffer_mmap[i].start) {
printf("mmap fail\n");
return -1;
}
printf("buffer_mmap[%d].length= %d\n",i,(int)buffer_mmap[i].length);
}
for (i = 0; i < req.count; ++i) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd, VIDIOC_QBUF, &buf)<0) {
printf("VIDIOC_QBUF fail\n");
return -1;
}
}
enum v4l2_buf_type type;
type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(fd, VIDIOC_STREAMON, &type)<0) {
printf("VIDIOC_STREAMON fail\n");
errno_exit("STREAMON");
return -1;
}
return 0;
}
int read_frame(int VideoFd, FILE *ImageFileFd)
{
struct v4l2_buffer buf;
int i, bytesused;
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (0>ioctl(VideoFd, VIDIOC_DQBUF, &buf)) {
printf("VIDIOC_DQBUF fail\n");
return -1;
}
i = buf.index;
bytesused = buf.bytesused;
fwrite(buffer_mmap[i].start, bytesused, 1, ImageFileFd);
fflush(ImageFileFd);
if (0>ioctl(VideoFd, VIDIOC_QBUF, &buf)) {
printf("read_frame VIDIOC_QBUF fail\n");
return -1;
}
return 0;
}
int display(int VideoFd)
{
struct timespec time_start,time_end;
long long diff;
struct v4l2_buffer buf;
int bytesused;
struct pollfd tfds[1];
unsigned char* addr;
unsigned char* image_store;
fd_set fds;
struct timeval tv;
int ret;
image_store=malloc(1280*720*3);
/*
tfds[0].fd=VideoFd;
tfds[0].events=POLLIN;
if(poll(tfds, 1, -1)<=0){
printf("poll fail\n");
return -1;
}
*/
while(1)
{
/*
if(poll(tfds, 1, -1)<=0){
printf("poll fail\n");
return -1;
}
*/
buf.bytesused = 0;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.field = V4L2_BUF_FLAG_QUEUED;
if (0>ioctl(VideoFd, VIDIOC_DQBUF, &buf)) {
printf("VIDIOC_DQBUF fail\n");
return -1;
}
//usleep(3300);
addr=(unsigned char*)(buffer_mmap[buf.index ].start);
printf("buffer_mmap[buf.index] %d\r\n",buf.index);
memcpy(fbp,addr,1280*720*3);
printf("timestamp %ld %ld\r\n",buf.timestamp.tv_sec,buf.timestamp.tv_usec);
if (0>ioctl(VideoFd, VIDIOC_QBUF, &buf)) {
printf("read_frame VIDIOC_QBUF fail\n");
return -1;
}
}
}
int display_initialize()
{
long int screensize = 0;
fbfd = open(FRAMEBUFFER_NAME, O_RDWR);
if (fbfd==-1) {
printf("Error: cannot open framebuffer device.\n");
return -1;
}
printf("The framebuffer device was opened successfully.\n");
/* Get fixed screen information */
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
return -1;
}
/* Get variable screen information */
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
return -1;
}
/* show these information*/
printf("vinfo.xres=%d\n",vinfo.xres);
printf("vinfo.yres=%d\n",vinfo.yres);
printf("vinfo.bits_per_bits=%d\n",vinfo.bits_per_pixel);
printf("vinfo.xoffset=%d\n",vinfo.xoffset);
printf("vinfo.yoffset=%d\n",vinfo.yoffset);
printf("finfo.line_length=%d\n",finfo.line_length);
/* Figure out the size of the screen in bytes */
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
/* Map the device to memory */
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbfd, 0);
if (fbp == MAP_FAILED) {
printf("Error: failed to map framebuffer device to memory.\n");
close(fbfd);
return -1;
}
printf("The framebuffer device was mapped to memory successfully.\n");
memset(fbp,0,screensize);
return 0;
}
int main(int argc, char **argv)
{
struct sched_param schedParam;
schedParam.sched_priority = 1; // 设置优先级为 99
sched_setscheduler(0, SCHED_FIFO, &schedParam);
int fd0,fd1;
FILE* fd2;
fd0 = open(VIDEO_DEVICE_NAME, O_RDWR);
// int flags = fcntl(fd0, F_GETFL, 0);
//flags |= O_NONBLOCK;
// fcntl(fd0, F_SETFL, flags);
if (-1 == fd0) {
printf("Cannot open %s\n", VIDEO_DEVICE_NAME);
return -1;
}
fd1 = open(V4LSUB_DEVICE_NAME, O_RDWR);
if (-1 == fd1) {
printf("Cannot open %s\n", V4LSUB_DEVICE_NAME);
return -1;
}
/*
fd2 = fopen(IMAGE_FILE, "w+");
if (fd2 == NULL) {
printf("Cannot open %s\n", IMAGE_FILE);
return -1;
}
*/
GetSensorFormat(fd1);
SetSensorFormat(fd1);
QueryVideoCap(fd0);
GetVideoFormat(fd0);
SetVideoFormat(fd0);
GetVideoFormat(fd0);
init_mmap(fd0);
display_initialize();
display(fd0);
close(fd0);
close(fd1);
fclose(fd2);
return 0;
}