video streaming about pcie

hello, FPGA is connected to jetson tx1 via PCIE,now my driver is working and i can see the video streaming,but the streaming is not very well. the video streaming resolution is 1080P/50Hz, but the display is not smooth it looks like only
<= 1080P/25Hz by cheese or xawtv.
my driver and Applications Using V4L2 IOCTL Directly. How is it happen?

gszqy,

Sorry that I don’t get it clear enough. Are you using below path: Camera -> FPGA -> PCIe -> input buffer through v4l2 ioctl?

If yes, next question is if this sluggish case only happens to preview or also to encoded video file as well.

Thanks for your reply.actually the situation is like this:
1.I used 12_camera_v4l2_cuda sample.the error is
./camera_v4l2_cuda -d /dev/video1 -s 1920x1080 -f UYVY -c
[INFO] (NvEglRenderer.cpp:109) Setting Screen width 1920 height 1080
WARN: request_camera_buff(): (line:327) Camera v4l2 buf length is not expected
ERROR: request_camera_buff(): (line:334) Failed to enqueue buffers: Bad address (14)
ERROR: prepare_buffers(): (line:386) Failed to set up camera buff
ERROR: main(): (line:535) Failed to prepare v4l2 buffs
App run failed
2.I don’t know why if i use V4L2_MEMORY_DMABUF, ioctl(ctx->cam_fd, VIDIOC_QBUF, &buf) is error!
3.if i use V4L2_MEMORY_MMAP param, it is no error, but the output is green screen!

gszqy,

How about your hardware configuration? Could you confirm my first question in #2?
Can you open the camera through other application?

1.FPGA generate test pattern 1080P/50Hz yuv422 format, FPGA----->PCIE------>TX1
2.i wrote a sample v4l2 test and also use the app such as xawtv, cheese, it can output video streaming.

Could you share your patch applied to mmapi sample?

of course.
the pcie driver:

/***************************************************************************
 *   Copyright (C) 2006-2010 by Marin Mitov                                *
 *   mitov@issp.bas.bg                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 ***************************************************************************/

#include <linux/module.h>
#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/videobuf2-dma-contig.h>
#include <asm/io.h>

#include "tmetrics.h"

#define TMETRICS_DEVICE_ID 0x7024


static int tmetrics_queue_setup(struct vb2_queue *vq, const void *parg,
		unsigned int *nbuffers, unsigned int *num_planes,
		unsigned int sizes[], void *alloc_ctxs[])

{
	const struct v4l2_format *fmt = parg;
	struct tmetrics_priv *pd = vb2_get_drv_priv(vq);
	unsigned size = pd->width * pd->height * IMAGE_PER_PIX_BYTE;
	
	if (vq->num_buffers + *nbuffers < 2)
		*nbuffers = 2 - vq->num_buffers;
	if (fmt && fmt->fmt.pix.sizeimage < size)
		return -EINVAL;
	*num_planes = 1;
	sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
	alloc_ctxs[0] = pd->alloc_ctx;
	return 0;
}

static int tmetrics_buf_prepare(struct vb2_buffer *vb)
{
	struct tmetrics_priv *pd = vb2_get_drv_priv(vb->vb2_queue);
	vb2_set_plane_payload(vb, 0, pd->width * pd->height * IMAGE_PER_PIX_BYTE);
	return 0;
}

static int tmetrics_start_streaming(struct vb2_queue *q, unsigned count)
{
	struct tmetrics_priv *pd = vb2_get_drv_priv(q);
	struct vb2_buffer *vb = &pd->curr_buf->vb2_buf;
	dma_addr_t dma_addr;
	
	pd->sequence = 0;
	dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);

	iowrite32be(dma_addr, pd->regs + REG_DMA_DST_LOW);
	iowrite32be(dma_addr >> 32, pd->regs + REG_DMA_DST_HIGH);
	iowrite32be(IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_PER_PIX_BYTE, pd->regs + REG_DMA_WRITE_LENGTH);

	/*  start the board  */
	iowrite32be(0x01, pd->regs + 0x100);
	iowrite32be(0x01, pd->regs + 0x14);
	return 0;
}

static void tmetrics_stop_streaming(struct vb2_queue *q)
{
	struct tmetrics_priv *pd = vb2_get_drv_priv(q);
	struct vb2_buffer *vb;
	
	spin_lock_irq(&pd->lock);
	/* stop the board */
	iowrite32be(0x00, pd->regs + 0x14);
	iowrite32be(0x00, pd->regs + 0x100);
	spin_unlock_irq(&pd->lock);

	/*
	 * It is not clear whether the DMA stops at once or whether it
	 * will finish the current frame or field first. To be on the
	 * safe side we wait a bit.
	 */
	msleep(45);

	spin_lock_irq(&pd->lock);
	if (pd->curr_buf) {
		vb2_buffer_done(&pd->curr_buf->vb2_buf, VB2_BUF_STATE_ERROR);
		pd->curr_buf = NULL;
	}

	while (!list_empty(&pd->dmaq)) {
		vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry);
		list_del(&vb->done_entry);
		vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
	}
	spin_unlock_irq(&pd->lock);
}

static void tmetrics_buf_queue(struct vb2_buffer *vb)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
	struct tmetrics_priv *pd = vb2_get_drv_priv(vb->vb2_queue);

	/*  pd->vidq.streaming = 1 when tmetrics_buf_queue() is invoked  */
	spin_lock_irq(&pd->lock);
	if (pd->curr_buf)
		list_add_tail(&vb->done_entry, &pd->dmaq);
	else
		pd->curr_buf = vbuf;
	spin_unlock_irq(&pd->lock);
}

static const struct vb2_ops q_ops = {
	.queue_setup = tmetrics_queue_setup,
	.wait_prepare = vb2_ops_wait_prepare,
	.wait_finish = vb2_ops_wait_finish,
	.buf_prepare = tmetrics_buf_prepare,
	.start_streaming = tmetrics_start_streaming,
	.stop_streaming = tmetrics_stop_streaming,
	.buf_queue = tmetrics_buf_queue,
};

static irqreturn_t tmetrics_irq_handler_even(int irq, void *dev_id)
{
	struct tmetrics_priv *ipd = dev_id;
	struct vb2_buffer *ivb;
	dma_addr_t dma_addr;

	spin_lock(&ipd->lock);
	if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
		v4l2_get_timestamp(&ipd->curr_buf->timestamp);
		ipd->curr_buf->sequence = ipd->sequence++;
		ipd->curr_buf->field = V4L2_FIELD_NONE;
		vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);

		ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry);
		list_del(&ivb->done_entry);
		ipd->curr_buf = to_vb2_v4l2_buffer(ivb);
		dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0);

		iowrite32be(dma_addr, ipd->regs + REG_DMA_DST_LOW);
		iowrite32be(dma_addr >> 32, ipd->regs + REG_DMA_DST_HIGH);
		iowrite32be(IMAGE_WIDTH * IMAGE_HEIGHT * IMAGE_PER_PIX_BYTE, ipd->regs + REG_DMA_WRITE_LENGTH);
		mmiowb();
	}

	iowrite32be(0x01, ipd->regs + 0x14);
	
	spin_unlock(&ipd->lock);
	return IRQ_HANDLED;
}

static const struct v4l2_file_operations tmetrics_fops = {
	.owner = THIS_MODULE,
	.open = v4l2_fh_open,
	.release = vb2_fop_release,
	.unlocked_ioctl = video_ioctl2,
	.read = vb2_fop_read,
	.mmap = vb2_fop_mmap,
	.poll = vb2_fop_poll
};

static int tmetrics_querycap(struct file *filp, void *p,
			   struct v4l2_capability *cap)
{
	struct tmetrics_priv *pd = video_drvdata(filp);

	strcpy(cap->driver, TMETRICS_NAME);
	strcpy(cap->card, TMETRICS_NAME " frame grabber");
	sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
	cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
		V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
	return 0;
}

static int tmetrics_enum_fmt_vid_cap(struct file *filp,
				   void *p, struct v4l2_fmtdesc *f)
{
	if (f->index)
		return -EINVAL;
	f->pixelformat = V4L2_PIX_FMT_UYVY;
	strcpy(f->description, "YUV422");
	return 0;
}

static int tmetrics_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f)
{
	struct tmetrics_priv *pd = video_drvdata(filp);

	f->fmt.pix.width = pd->width;
	f->fmt.pix.height = pd->height;
	f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
	f->fmt.pix.field = V4L2_FIELD_NONE;
	f->fmt.pix.bytesperline = f->fmt.pix.width * IMAGE_PER_PIX_BYTE;
	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height ;
	f->fmt.pix.colorspace = V4L2_COLORSPACE_DEFAULT;
	return 0;
}

static int tmetrics_g_std(struct file *filp, void *p, v4l2_std_id *norm)
{
	return 0;
}

static int tmetrics_s_std(struct file *filp, void *p, v4l2_std_id norm)
{
	return 0;
}

static int tmetrics_enum_input(struct file *filp, void *p,
			     struct v4l2_input *input)
{
	if (input->index > 3)
		return -EINVAL;
	if (input->index)
		snprintf(input->name, sizeof(input->name), "Camera%d",
			 input->index);
	else
		strlcpy(input->name, "Camera", sizeof(input->name));
	input->type = V4L2_INPUT_TYPE_CAMERA;
	return 0;
}

static int tmetrics_g_input(struct file *filp, void *p, unsigned int *i)
{
	*i = 0;
	return 0;
}

static int tmetrics_s_input(struct file *filp, void *p, unsigned int i)
{
	return i == 0 ? 0 : -EINVAL;
}

static const struct v4l2_ioctl_ops tmetrics_ioctl_ops = {
	.vidioc_querycap = tmetrics_querycap,
	.vidioc_enum_fmt_vid_cap = tmetrics_enum_fmt_vid_cap,
	.vidioc_try_fmt_vid_cap = tmetrics_fmt_vid_cap,
	.vidioc_g_fmt_vid_cap = tmetrics_fmt_vid_cap,
	.vidioc_s_fmt_vid_cap = tmetrics_fmt_vid_cap,
	.vidioc_reqbufs = vb2_ioctl_reqbufs,
	.vidioc_create_bufs = vb2_ioctl_create_bufs,
	.vidioc_querybuf = vb2_ioctl_querybuf,
	.vidioc_expbuf = vb2_ioctl_expbuf,
	.vidioc_qbuf = vb2_ioctl_qbuf,
	.vidioc_dqbuf = vb2_ioctl_dqbuf,
	.vidioc_streamon = vb2_ioctl_streamon,
	.vidioc_streamoff = vb2_ioctl_streamoff,
	.vidioc_g_std = tmetrics_g_std,
	.vidioc_s_std = tmetrics_s_std,
	.vidioc_enum_input = tmetrics_enum_input,
	.vidioc_g_input = tmetrics_g_input,
	.vidioc_s_input = tmetrics_s_input,
};

static int tmetrics_init_board(struct tmetrics_priv *pd)
{
	struct pci_dev *pdev = pd->pdev;

	pci_set_master(pdev); /* tmetrics needs it */

	iowrite32be(0x02, pd->regs + 0x28);
	iowrite32be(0x01, pd->regs + 0x100);
	
	return 0;
}

static struct video_device tmetrics_vdev = {
	.name = TMETRICS_NAME,
	.fops = &tmetrics_fops,
	.ioctl_ops = &tmetrics_ioctl_ops,
	.minor = -1,
	.release = video_device_release_empty,
};

static int tmetrics_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	int err;
	struct tmetrics_priv *pd = NULL;

	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
	if (err)
		return -ENODEV;
	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
	if (!pd)
		return -ENOMEM;

	err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev);
	if (err)
		return err;
	pd->vdev = tmetrics_vdev;
	pd->vdev.v4l2_dev = &pd->v4l2_dev;
	video_set_drvdata(&pd->vdev, pd);  /* for use in video_fops */
	pd->pdev = pdev;
	pd->width = IMAGE_WIDTH;
	pd->height = IMAGE_HEIGHT;
	INIT_LIST_HEAD(&pd->dmaq);
	mutex_init(&pd->mux);
	pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */
	pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
	pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
	pd->vidq.ops = &q_ops;
	pd->vidq.mem_ops = &vb2_dma_contig_memops;
	pd->vidq.drv_priv = pd;
	pd->vidq.min_buffers_needed = 2;
	pd->vidq.gfp_flags = GFP_DMA32;
	pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */
	pd->vdev.queue = &pd->vidq;
	err = vb2_queue_init(&pd->vidq);
	if (err < 0)
		goto err_v4l2_dev_unreg;
	pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
	if (IS_ERR(pd->alloc_ctx)) {
		dev_err(&pdev->dev, "Can't allocate buffer context");
		err = PTR_ERR(pd->alloc_ctx);
		goto err_v4l2_dev_unreg;
	}
	spin_lock_init(&pd->lock);
	err = pci_enable_device(pdev);
	if (err)
		goto err_free_ctx;
	err = pci_request_region(pdev, 0, pci_name(pdev));
	if (err)
		goto err_pci_disable;
	pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0));
	if (!pd->regs) {
		err = -ENOMEM;
		goto err_free_reg;
	}
	err = tmetrics_init_board(pd);
	if (err)
		goto err_iounmap;

	pci_enable_msi(pdev);
	
	err = request_irq(pd->pdev->irq, tmetrics_irq_handler_even,
					IRQF_SHARED, TMETRICS_NAME, pd);
	if (err)
		goto err_iounmap;
	err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1);
	if (err)
		goto err_free_irq;
		
	dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor);
	return 0;  /*   success   */

err_free_irq:
	free_irq(pd->pdev->irq, pd);
err_iounmap:
	pci_iounmap(pdev, pd->regs);
err_free_reg:
	pci_release_region(pdev, 0);
err_pci_disable:
	pci_disable_device(pdev);
err_free_ctx:
	vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
err_v4l2_dev_unreg:
	v4l2_device_unregister(&pd->v4l2_dev);
	return err;
}

static void tmetrics_remove(struct pci_dev *pdev)
{
	struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
	struct tmetrics_priv *pd = container_of(v4l2_dev, struct tmetrics_priv,
					      v4l2_dev);

	video_unregister_device(&pd->vdev);
	free_irq(pd->pdev->irq, pd);
	pci_disable_msi(pdev);
	vb2_queue_release(&pd->vidq);
	v4l2_device_unregister(&pd->v4l2_dev);
	pci_iounmap(pdev, pd->regs);
	pci_release_region(pdev, 0);
	pci_disable_device(pdev);
	vb2_dma_contig_cleanup_ctx(pd->alloc_ctx);
}

static const struct pci_device_id pci_ids[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_XILINX, TMETRICS_DEVICE_ID) },
	{ 0, /* zero marks the end */ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);

static struct pci_driver pci_driver = {
	.name = TMETRICS_NAME,
	.id_table = pci_ids,
	.probe = tmetrics_probe,
	.remove = tmetrics_remove,
};

module_pci_driver(pci_driver);

MODULE_DESCRIPTION("video4linux pci-driver for tmetrics frame grabber");
MODULE_AUTHOR("gszqy <gszqy@163.com>");
MODULE_VERSION(TMETRICS_VERSION);
MODULE_LICENSE("GPL");

the sample test :

#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <pthread.h>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <iomanip>
#include <string>

using namespace std;
using namespace cv;

#define CLEAR(x) memset(&(x), 0, sizeof(x))

#define IMAGEWIDTH 1920
#define IMAGEHEIGHT 1080

class V4L2Capture {
public:
    V4L2Capture(char *devName, int width, int height);
    virtual ~V4L2Capture();

    int openDevice();
    int closeDevice();
    int initDevice();
    int startCapture();
    int stopCapture();
    int freeBuffers();
    int getFrame(void **,size_t *);
    int backFrame();
    static void test();

private:
    int initBuffers();

    struct cam_buffer
    {
        void* start;
        unsigned int length;
    };
    char *devName;
    int capW;
    int capH;
    int fd_cam;
    cam_buffer *buffers;
    unsigned int n_buffers;
    int frameIndex;
};

V4L2Capture::V4L2Capture(char *devName, int width, int height) {
    // TODO Auto-generated constructor stub
    this->devName = devName;
    this->fd_cam = -1;
    this->buffers = NULL;
    this->n_buffers = 0;
    this->frameIndex = -1;
    this->capW=width;
    this->capH=height;
}

V4L2Capture::~V4L2Capture() {
    // TODO Auto-generated destructor stub
}

int V4L2Capture::openDevice() {
    /*设备的打开*/
    printf("video dev : %s\n", devName);
    fd_cam = open(devName, O_RDWR);
    if (fd_cam < 0) {
        perror("Can't open video device");
    }
    return 0;
}

int V4L2Capture::closeDevice() {
    if (fd_cam > 0) {
        int ret = 0;
        if ((ret = close(fd_cam)) < 0) {
            perror("Can't close video device");
        }
        return 0;
    } else {
        return -1;
    }
}

int V4L2Capture::initDevice() {
    int ret;
    struct v4l2_capability cam_cap;		//显示设备信息
    struct v4l2_cropcap cam_cropcap;	//设置摄像头的捕捉能力
    struct v4l2_fmtdesc cam_fmtdesc;	//查询所有支持的格式:VIDIOC_ENUM_FMT
    struct v4l2_crop cam_crop;			//图像的缩放
    struct v4l2_format cam_format;		//设置摄像头的视频制式、帧格式等

    /* 使用IOCTL命令VIDIOC_QUERYCAP,获取摄像头的基本信息*/
    ret = ioctl(fd_cam, VIDIOC_QUERYCAP, &cam_cap);
    if (ret < 0) {
        perror("Can't get device information: VIDIOCGCAP");
    }
    printf(
            "Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n",
            cam_cap.driver, cam_cap.card, cam_cap.bus_info,
            (cam_cap.version >> 16) & 0XFF, (cam_cap.version >> 8) & 0XFF,
            cam_cap.version & 0XFF);

    /* 使用IOCTL命令VIDIOC_ENUM_FMT,获取摄像头所有支持的格式*/
    cam_fmtdesc.index = 0;
    cam_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("Support format:\n");
    while (ioctl(fd_cam, VIDIOC_ENUM_FMT, &cam_fmtdesc) != -1) {
        printf("\t%d.%s\n", cam_fmtdesc.index + 1, cam_fmtdesc.description);
        cam_fmtdesc.index++;
    }

    #if 0
    /* 使用IOCTL命令VIDIOC_CROPCAP,获取摄像头的捕捉能力*/
    cam_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (0 == ioctl(fd_cam, VIDIOC_CROPCAP, &cam_cropcap)) {
        printf("Default rec:\n\tleft:%d\n\ttop:%d\n\twidth:%d\n\theight:%d\n",
                cam_cropcap.defrect.left, cam_cropcap.defrect.top,
                cam_cropcap.defrect.width, cam_cropcap.defrect.height);
        /* 使用IOCTL命令VIDIOC_S_CROP,获取摄像头的窗口取景参数*/
        cam_crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        cam_crop.c = cam_cropcap.defrect;		//默认取景窗口大小
        if (-1 == ioctl(fd_cam, VIDIOC_S_CROP, &cam_crop)) {
            //printf("Can't set crop para\n");
        }
    } else {
        printf("Can't set cropcap para\n");
    }
#endif

    /* 使用IOCTL命令VIDIOC_S_FMT,设置摄像头帧信息*/
    cam_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    cam_format.fmt.pix.width = capW;
    cam_format.fmt.pix.height = capH;
    cam_format.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;		//要和摄像头支持的类型对应
    cam_format.fmt.pix.field = V4L2_FIELD_NONE;
    ret = ioctl(fd_cam, VIDIOC_S_FMT, &cam_format);
    if (ret < 0) {
        perror("Can't set frame information");
    }
    /* 使用IOCTL命令VIDIOC_G_FMT,获取摄像头帧信息*/
    cam_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(fd_cam, VIDIOC_G_FMT, &cam_format);
    if (ret < 0) {
        perror("Can't get frame information");
    }
    printf("Current data format information:\n\twidth:%d\n\theight:%d\n",
            cam_format.fmt.pix.width, cam_format.fmt.pix.height);

    ret = initBuffers();
    if (ret < 0) {
        perror("Buffers init error");
        //exit(-1);
    }
    return 0;
}

int V4L2Capture::initBuffers() {
    int ret;
    /* 使用IOCTL命令VIDIOC_REQBUFS,申请帧缓冲*/
    struct v4l2_requestbuffers req;
    CLEAR(req);
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    ret = ioctl(fd_cam, VIDIOC_REQBUFS, &req);
    if (ret < 0) {
        perror("Request frame buffers failed");
    }
    if (req.count < 2) {
        perror("Request frame buffers while insufficient buffer memory");
    }
    buffers = (struct cam_buffer*) calloc(req.count, sizeof(*buffers));
    if (!buffers) {
        perror("Out of memory");
    }
    for (n_buffers = 0; n_buffers < req.count; n_buffers++) {
        struct v4l2_buffer buf;
        CLEAR(buf);
        // 查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_DMABUF;
        buf.index = n_buffers;
        ret = ioctl(fd_cam, VIDIOC_QUERYBUF, &buf);
        if (ret < 0) {
            printf("VIDIOC_QUERYBUF %d failed\n", n_buffers);
            return -1;
        }
        buffers[n_buffers].length = buf.length;
        printf("buf.length= %d\n",buf.length);
        // 映射内存
        buffers[n_buffers].start = mmap(
                NULL, // start anywhere
                buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_cam,
                buf.m.offset);
        if (MAP_FAILED == buffers[n_buffers].start) {
            printf("mmap buffer%d failed\n", n_buffers);
            return -1;
        }
    }
    return 0;
}

int V4L2Capture::startCapture() {
    unsigned int i;
    for (i = 0; i < n_buffers; i++) {
        struct v4l2_buffer buf;
        CLEAR(buf);
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_DMABUF;
        buf.index = i;
        if (-1 == ioctl(fd_cam, VIDIOC_QBUF, &buf)) {
            printf("VIDIOC_QBUF buffer%d failed\n", i);
            return -1;
        }
    }
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == ioctl(fd_cam, VIDIOC_STREAMON, &type)) {
        printf("VIDIOC_STREAMON error");
        return -1;
    }
    return 0;
}

int V4L2Capture::stopCapture() {
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (-1 == ioctl(fd_cam, VIDIOC_STREAMOFF, &type)) {
        printf("VIDIOC_STREAMOFF error\n");
        return -1;
    }
    return 0;
}

int V4L2Capture::freeBuffers() {
    unsigned int i;
    for (i = 0; i < n_buffers; ++i) {
        if (-1 == munmap(buffers[i].start, buffers[i].length)) {
            printf("munmap buffer%d failed\n", i);
            return -1;
        }
    }
    free(buffers);
    return 0;
}

int V4L2Capture::getFrame(void **frame_buf, size_t* len) {
    struct v4l2_buffer queue_buf;
    CLEAR(queue_buf);
    queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    queue_buf.memory = V4L2_MEMORY_DMABUF;
    if (-1 == ioctl(fd_cam, VIDIOC_DQBUF, &queue_buf)) {
        printf("VIDIOC_DQBUF error\n");
        return -1;
    }
    *frame_buf = buffers[queue_buf.index].start;
    *len = buffers[queue_buf.index].length;
    frameIndex = queue_buf.index;

    //printf("start = 0x%08x\nlen = %d\nindex = %d\n", (*frame_buf), *len, frameIndex);

    return 0;
}

int V4L2Capture::backFrame() {
    if (frameIndex != -1) {
        struct v4l2_buffer queue_buf;
        CLEAR(queue_buf);
        queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        queue_buf.memory = V4L2_MEMORY_DMABUF;
        queue_buf.index = frameIndex;
        if (-1 == ioctl(fd_cam, VIDIOC_QBUF, &queue_buf)) {
            printf("VIDIOC_QBUF error\n");
            return -1;
        }
        return 0;
    }
    return -1;
}

void V4L2Capture::test() {
    unsigned char *yuv422frame = NULL;
    unsigned long yuvframeSize = 0;

    string videoDev="/dev/video1";
    V4L2Capture *vcap = new V4L2Capture(const_cast<char*>(videoDev.c_str()),
            1920, 1080);
    vcap->openDevice();
    vcap->initDevice();
    vcap->startCapture();
    vcap->getFrame((void **) &yuv422frame, (size_t *)&yuvframeSize);

    vcap->backFrame();
    vcap->freeBuffers();
    vcap->closeDevice();
}

void VideoPlayer() {
    unsigned char *yuv422frame = NULL;
    unsigned long yuvframeSize = 0;

    string videoDev = "/dev/video1";
    V4L2Capture *vcap = new V4L2Capture(const_cast<char*>(videoDev.c_str()), 1920, 1080);
    vcap->openDevice();
    vcap->initDevice();

    vcap->startCapture();

   // cvNamedWindow("Capture",CV_WINDOW_AUTOSIZE);
    //IplImage* img;
    //CvMat cvmat;
    Mat mat(IMAGEHEIGHT,IMAGEWIDTH,CV_8UC1);

    double t;
    while(1){
        t = (double)cvGetTickCount();
        vcap->getFrame((void **) &yuv422frame, (size_t *)&yuvframeSize);
        //cvmat = cvMat(IMAGEHEIGHT,IMAGEWIDTH,CV_8UC3,(void*)yuv422frame);		//CV_8UC3
        //t = (double)cvGetTickCount() - t;
        //printf("Used time is %g ms\n",( t / (cvGetTickFrequency()*1000)));
        mat.data = yuv422frame;
        imshow("mat",mat);
        #if 0
        //解码
        img = cvDecodeImage(&cvmat,1);
        if(!img){
            printf("DecodeImage error!\n");
        }
        #endif

        //cvShowImage("Capture",img);
       // cvReleaseImage(&img);

        vcap->backFrame();
        if((cvWaitKey(1)&255) == 27){
            exit(0);
        }
        t = (double)cvGetTickCount() - t;
        printf("Used time is %g ms\n",( t / (cvGetTickFrequency()*1000)));
    }
    vcap->stopCapture();
    vcap->freeBuffers();
    vcap->closeDevice();

}

int main() {
    VideoPlayer();
    return 0;
}

gszqy,

Have you profiled your pipeline?

pipeline should be supported by driver?

I meant you could first debug if camera source really gives out 1080P/50Hz? If yes, we could then check if buffer handling taking too much time or display delay.

Thanks for your patiently answer.
i think the reason is buffer handling taking too much time or display delay.because if i give out 1080p/25Hz it is the same situation.
so i want to use sample 12_camera_v4l2_cuda to test.but with some runing error in #3.

gszqy,

If this is related to buffer handling/copy time, have you tried to raise all clock to maximum?

For display, what is your current monitor mode?

thanks,i already raise clock to maximum.
1.v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=“UYVY” --device=/dev/video1 --stream-count=300 --stream-mmap
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 53.00 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 52.73 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 52.66 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 52.61 fps
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 52.60 fps

2.by gst-launch-1.0 v4l2src device=/dev/video1 ! ‘video/x-raw,format=UYVY,width=1920,height=1080’ ! xvimagesink,video straming looks better than my own sample.but i think it is not the best.
3.i found https://devtalk.nvidia.com/default/topic/1020521/jetson-tx1/show-video-via-hdmi-ultrahd-3840x2160/, so i use 12_camera_v4l2_cuda to display,but it is error in #3.

so my question is why 12_camera_v4l2_cuda can not be runing?

gszqy,

I would like to start it in case 2 first, which uses gstreamer. Could you try to encoded it to a file and gives out the actual frame rate instead of using preview?

gszqy,

Any update?

hi,WayneWWW,now the question has been solved.
gst-launch-1.0 v4l2src io-mode=4 device=/dev/video1 ! ‘video/x-raw,format=UYVY,width=1920,height=1080’ ! xvimagesink sync=false.
the key is sync=false.thanks for your help.