v4l2Device::~v4l2Device()
{
    if (m_fd > -1)
    {
        BYE_ON(close(m_fd) < 0, "V4L2 device close failed: %s\n", ERRSTR);
    }
}
void v4l2Device::V4L2StopCapture()
{
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    int ret = 0;

    ret = blockIOCTL(m_fd, VIDIOC_STREAMOFF, &type);
    BYE_ON(ret < 0, "STREAMOFF failed: %s\n", ERRSTR);
}
Buffer *v4l2Device::V4L2DeQueueBuffer(Buffer *buffer)
{
    struct v4l2_buffer buf;
    int ret;

    memset(&buf, 0, sizeof buf);

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_DMABUF;

    ret = blockIOCTL(m_fd, VIDIOC_DQBUF, &buf);
    BYE_ON(ret, "VIDIOC_DQBUF failed: %s\n", ERRSTR);

    return &buffer[buf.index];
}
void v4l2Device::V4L2QueueBuffer(Buffer *buffer)
{
    struct v4l2_buffer buf;
    int ret;

    memset(&buf, 0, sizeof buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_DMABUF;
    buf.index = buffer->index;
    buf.m.fd = buffer->fd;

    ret = blockIOCTL(m_fd, VIDIOC_QBUF, &buf);
    BYE_ON(ret < 0, "VIDIOC_QBUF for buffer %d failed: %s (fd %u) (i %u)\n",
    buf.index, ERRSTR, buffer->fd, buffer->index);
}
int main(int argc, char *argv[])
{
	int ret;
	struct setup s;

	ret = parse_args(argc, argv, &s);
	BYE_ON(ret, "failed to parse arguments\n");
	BYE_ON(s.module[0] == 0, "DRM module is missing\n");
	BYE_ON(s.video[0] == 0, "video node is missing\n");

	int drmfd = drmOpen(s.module, NULL);
	BYE_ON(drmfd < 0, "drmOpen(%s) failed: %s\n", s.module, ERRSTR);

	int v4lfd = open(s.video, O_RDWR);
	BYE_ON(v4lfd < 0, "failed to open %s: %s\n", s.video, ERRSTR);

	struct v4l2_capability caps;
	memset(&caps, 0, sizeof caps);

	ret = ioctl(v4lfd, VIDIOC_QUERYCAP, &caps);
	BYE_ON(ret, "VIDIOC_QUERYCAP failed: %s\n", ERRSTR);

	/* TODO: add single plane support */
	BYE_ON(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE,
		"video: singleplanar capture is not supported\n");

	struct v4l2_format fmt;
	memset(&fmt, 0, sizeof fmt);
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

	ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
	printf("G_FMT(start): width = %u, height = %u, 4cc = %.4s\n",
		fmt.fmt.pix.width, fmt.fmt.pix.height,
		(char*)&fmt.fmt.pix.pixelformat);

	if (s.use_wh) {
		fmt.fmt.pix.width = s.w;
		fmt.fmt.pix.height = s.h;
	}
	if (s.in_fourcc)
		fmt.fmt.pix.pixelformat = s.in_fourcc;

	ret = ioctl(v4lfd, VIDIOC_S_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR);

	ret = ioctl(v4lfd, VIDIOC_G_FMT, &fmt);
	BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
	printf("G_FMT(final): width = %u, height = %u, 4cc = %.4s\n",
		fmt.fmt.pix.width, fmt.fmt.pix.height,
		(char*)&fmt.fmt.pix.pixelformat);

	struct v4l2_requestbuffers rqbufs;
	memset(&rqbufs, 0, sizeof(rqbufs));
	rqbufs.count = s.buffer_count;
	rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	rqbufs.memory = V4L2_MEMORY_DMABUF;

	ret = ioctl(v4lfd, VIDIOC_REQBUFS, &rqbufs);
	BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR);
	BYE_ON(rqbufs.count < s.buffer_count, "video node allocated only "
		"%u of %u buffers\n", rqbufs.count, s.buffer_count);

	s.in_fourcc = fmt.fmt.pix.pixelformat;
	s.w = fmt.fmt.pix.width;
	s.h = fmt.fmt.pix.height;

	/* TODO: add support for multiplanar formats */
	struct buffer buffer[s.buffer_count];
	uint32_t size = fmt.fmt.pix.sizeimage;
	uint32_t pitch = fmt.fmt.pix.bytesperline;
	printf("size = %u pitch = %u\n", size, pitch);
	for (unsigned int i = 0; i < s.buffer_count; ++i) {
		ret = buffer_create(&buffer[i], drmfd, &s, size, pitch);
		BYE_ON(ret, "failed to create buffer%d\n", i);
	}
	printf("buffers ready\n");

	/*drmModeModeInfo drmmode;
	uint32_t con;
	ret = find_mode(&drmmode, drmfd, &s, &con);
	BYE_ON(ret, "failed to find valid mode\n");

	ret = find_plane(drmfd, &s);
	BYE_ON(ret, "failed to find compatible plane\n");*/

	for (unsigned int i = 0; i < s.buffer_count; ++i) {
		struct v4l2_buffer buf;
		memset(&buf, 0, sizeof buf);

		buf.index = i;
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_DMABUF;
		buf.m.fd = buffer[i].dbuf_fd;
		ret = ioctl(v4lfd, VIDIOC_QBUF, &buf);
		BYE_ON(ret < 0, "VIDIOC_QBUF for buffer %d failed: %s (fd %u)\n",
			buf.index, ERRSTR, buffer[i].dbuf_fd);
	}

	int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ret = ioctl(v4lfd, VIDIOC_STREAMON, &type);
	BYE_ON(ret < 0, "STREAMON failed: %s\n", ERRSTR);

	struct pollfd fds[] = {
		{ .fd = v4lfd, .events = POLLIN },
		{ .fd = drmfd, .events = POLLIN },
void v4l2Device::V4L2Init()
{
    int ret;
    struct v4l2_format fmt;
    struct v4l2_capability caps;
    struct v4l2_streamparm parm;
    struct v4l2_requestbuffers rqbufs;
    CLEAR(parm);

    m_fd = open(m_devname, O_RDWR);
    BYE_ON(m_fd < 0, "failed to open %s: %s\n", m_devname, ERRSTR);
    CLEAR(caps);

    /* Specifically for setting up mipi configuration. DMABUFF is
     * also enable by default here.
     */
    if (m_MipiPort > -1  && m_MipiMode != NONE) {
    parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    parm.parm.capture.capturemode = GetAtomISPModes(m_MipiMode);

    ret = blockIOCTL(m_fd, VIDIOC_S_INPUT, &m_MipiPort);
    BYE_ON(ret < 0, "VIDIOC_S_INPUT failed: %s\n", ERRSTR);

    ret = blockIOCTL(m_fd, VIDIOC_S_PARM, &parm);
    BYE_ON(ret < 0, "VIDIOC_S_PARAM failed: %s\n", ERRSTR);
    }

    ret = blockIOCTL(m_fd, VIDIOC_QUERYCAP, &caps);
    msdk_printf( "Driver Caps:\n"
            "  Driver: \"%s\"\n"
            "  Card: \"%s\"\n"
            "  Bus: \"%s\"\n"
            "  Version: %d.%d\n"
            "  Capabilities: %08x\n",
            caps.driver,
            caps.card,
            caps.bus_info,
            (caps.version>>16)&&0xff,
            (caps.version>>24)&&0xff,
            caps.capabilities);

    BYE_ON(ret, "VIDIOC_QUERYCAP failed: %s\n", ERRSTR);
    BYE_ON(~caps.capabilities & V4L2_CAP_VIDEO_CAPTURE,
                "video: singleplanar capture is not supported\n");

    CLEAR(fmt);
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = blockIOCTL(m_fd, VIDIOC_G_FMT, &fmt);

    BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);

    msdk_printf("G_FMT(start): width = %u, height = %u, 4cc = %.4s, BPP = %u sizeimage = %d field = %d\n",
        fmt.fmt.pix.width, fmt.fmt.pix.height,
        (char*)&fmt.fmt.pix.pixelformat,
        fmt.fmt.pix.bytesperline,
        fmt.fmt.pix.sizeimage,
        fmt.fmt.pix.field);

    fmt.fmt.pix = m_format;

    msdk_printf("G_FMT(pre): width = %u, height = %u, 4cc = %.4s, BPP = %u sizeimage = %d field = %d\n",
        fmt.fmt.pix.width, fmt.fmt.pix.height,
        (char*)&fmt.fmt.pix.pixelformat,
        fmt.fmt.pix.bytesperline,
        fmt.fmt.pix.sizeimage,
        fmt.fmt.pix.field);

    ret = blockIOCTL(m_fd, VIDIOC_S_FMT, &fmt);
    BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR);

    ret = blockIOCTL(m_fd, VIDIOC_G_FMT, &fmt);
    BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR);
    msdk_printf("G_FMT(final): width = %u, height = %u, 4cc = %.4s, BPP = %u\n",
        fmt.fmt.pix.width, fmt.fmt.pix.height,
        (char*)&fmt.fmt.pix.pixelformat,
        fmt.fmt.pix.bytesperline);

    CLEAR(rqbufs);
    rqbufs.count = m_num_buffers;
    rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    rqbufs.memory = V4L2_MEMORY_DMABUF;

    ret = blockIOCTL(m_fd, VIDIOC_REQBUFS, &rqbufs);
    BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR);
    BYE_ON(rqbufs.count < m_num_buffers, "video node allocated only "
            "%u of %u buffers\n", rqbufs.count, m_num_buffers);

    m_format = fmt.fmt.pix;
}