/*
 *  Copyright (c) 2013-2014, Texas Instruments Incorporated
 *  Author: alaganraj <alaganraj.s@ti.com>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  *  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *  *  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  *  Neither the name of Texas Instruments Incorporated nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  Contact information for paper mail:
 *  Texas Instruments
 *  Post Office Box 655303
 *  Dallas, Texas 75265
 *  Contact information:
 *  http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
 *  DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
 *  ============================================================================
 *
 */

/*
 * @File        vpe-common.c
 * @Brief       vpe specific common functions, used to integrate vpe
 *		with other modules.
 *
 *		Input buffer must be allocated in application, queue it to vpe
 *		by passing buffer index
 *
 *		Output buffer allocated in vpe_output_init() as vpe output intended
 *		to display on LCD.
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>

#include <linux/videodev2.h>
#include <linux/v4l2-controls.h>

#include <sys/mman.h>
#include <sys/ioctl.h>
#include <xf86drmMode.h>
#include <xf86drm.h>
#include <omap_drm.h>
#include <omap_drmif.h>

#include "util.h"

//#include "cmem_buf.h"

#define pexit(fmt, arg...) { \
		printf(fmt, ## arg); \
		exit(1); \
}

#define V4L2_CID_TRANS_NUM_BUFS         (V4L2_CID_PRIVATE_BASE)
#define NUMBUF                          6

//#define vpe_debug

#ifdef vpe_debug
#define dprintf(fmt, arg...) printf(fmt, ## arg)
#else
#define dprintf(fmt, arg...) do {} while(0)
#endif

struct image_params {
	int width;
	int height;
	int fourcc;
	int size;
	int size_uv;
	int coplanar;
	enum v4l2_colorspace colorspace;
	int numbuf;
};

struct vpe {
	int fd;
	int field;
	int deint;
	int translen;
	struct image_params src;
	struct image_params dst;
	struct  v4l2_crop crop;
	int input_buf_dmafd[NUMBUF];
	int input_buf_dmafd_uv[NUMBUF];
	int output_buf_dmafd[NUMBUF];
	int output_buf_dmafd_uv[NUMBUF];
	struct display *disp;
	struct buffer **disp_bufs;
};


static struct buffer* alloc_buffer(struct display *display,
		unsigned int fourcc, unsigned int w,
		unsigned int h)
{
	struct buffer *buf;
	unsigned int bo_handles[4] = {0}, offsets[4] = {0};
	int ret;
	int bytes_pp = 2; //capture buffer is in YUYV format
	
	buf = (struct buffer *) calloc(1, sizeof(struct buffer));
	if (!buf) {
		ERROR("allocation failed");
		return NULL;
	}

	buf->fourcc = fourcc;
	buf->width = w;
	buf->height = h;
	buf->nbo = 1;
	buf->pitches[0] = w*bytes_pp;

//#ifdef USE_CMEM_BUF
	//Allocate buffer from CMEM and get the buffer descriptor

	buf->fd[0] = alloc_cmem_buffer(w*h*bytes_pp, 1, &buf->cmem_buf);

	if(buf->fd[0] < 0){
		free_cmem_buffer(buf->cmem_buf);
		printf(" Cannot export CMEM buffer\n");
		return NULL;
	}
	//printf("alloc cmem address is 0x%x \n",buf->fd[0]);
	/* Get the omap bo from the fd allocted using CMEM */
	buf->bo[0] = omap_bo_from_dmabuf(display->dev, buf->fd[0]);
	if (buf->bo[0]){
		bo_handles[0] = omap_bo_handle(buf->bo[0]);
	}

	//printf("\n ***********cmem buffer of format 0x%x ***********\n",fourcc);
	ret = drmModeAddFB2(display->fd, buf->width, buf->height, fourcc,
		bo_handles, buf->pitches, offsets, &buf->fb_id, 0);

	if (ret) {
		ERROR("drmModeAddFB2 failed: %s (%d)", strerror(errno), ret);
		return NULL;
	}

	return buf;
}

static struct buffer **get_cmem_buffers(struct display *display,
		unsigned int n,
		unsigned int fourcc, unsigned int w, unsigned int h)
{
	struct buffer **bufs;
	unsigned int i = 0;

	bufs = (struct buffer **) calloc(n, sizeof(*bufs));
	if (!bufs) {
		ERROR("allocation failed");
		goto fail;
	}

	for (i = 0; i < n; i++) {
		bufs[i] = alloc_buffer(display, fourcc, w, h);
		if (!bufs[i]) {
			ERROR("allocation failed");
			goto fail;
		}
	}

	if (bufs) {
		/* if allocation succeeded, store in the unlocked
		 * video buffer list
		 */
		list_init(&display->unlocked);
		for (i = 0; i < n; i++)
			list_add(&bufs[i]->unlocked, &display->unlocked);
	}



	return bufs;

fail:
	return NULL;
}






/**
 *****************************************************************************
 * @brief:  open the device
 *
 * @return: vpe  struct vpe pointer
 *****************************************************************************
*/
struct vpe *vpe_open(void)
{
	char devname[20] = "/dev/video0";
	struct vpe *vpe;

	vpe = calloc(1, sizeof(*vpe));

	vpe->fd =  open(devname, O_RDWR);
        if(vpe->fd < 0)
                pexit("Cant open %s\n", devname);

        printf("vpe:%s open success!!!\n", devname);

	return vpe;
}

/**
 *****************************************************************************
 * @brief:  close the device and free memory
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: 0 on success
 *****************************************************************************
*/
int vpe_close(struct vpe *vpe)
{
	close(vpe->fd);
	free(vpe);

	return 0;
}

/**
 *****************************************************************************
 * @brief:  fills 4cc, size, coplanar, colorspace based on command line input
 *
 * @param:  format  char pointer
 * @param:  image  struct image_params pointer
 *
 * @return: 0 on success
 *****************************************************************************
*/
int describeFormat (char *format, struct image_params *image)
{
        image->size   = -1;
        image->fourcc = -1;
        if (strcmp (format, "rgb24") == 0) {
                image->fourcc = V4L2_PIX_FMT_RGB24;
                image->size = image->height * image->width * 3;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SRGB;

        } else if (strcmp (format, "bgr24") == 0) {
                image->fourcc = V4L2_PIX_FMT_BGR24;
                image->size = image->height * image->width * 3;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SRGB;

        } else if (strcmp (format, "argb32") == 0) {
                image->fourcc = V4L2_PIX_FMT_RGB32;
                image->size = image->height * image->width * 4;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SRGB;

        } else if (strcmp (format, "abgr32") == 0) {
                image->fourcc = V4L2_PIX_FMT_BGR32;
                image->size = image->height * image->width * 4;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SRGB;

        } else if (strcmp (format, "yuv444") == 0) {
                image->fourcc = V4L2_PIX_FMT_YUV444;
                image->size = image->height * image->width * 3;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "yvyu") == 0) {
                image->fourcc = V4L2_PIX_FMT_YVYU;
                image->size = image->height * image->width * 2;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "yuyv") == 0) {
                image->fourcc = V4L2_PIX_FMT_YUYV;
                image->size = image->height * image->width * 2;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "uyvy") == 0) {
                image->fourcc = V4L2_PIX_FMT_UYVY;
                image->size = image->height * image->width * 2;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "vyuy") == 0) {
                image->fourcc = V4L2_PIX_FMT_VYUY;
                image->size = image->height * image->width * 2;
                image->coplanar = 0;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "nv16") == 0) {
                image->fourcc = V4L2_PIX_FMT_NV16;
                image->size = image->height * image->width * 2;
                image->coplanar = 1;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "nv61") == 0) {
                image->fourcc = V4L2_PIX_FMT_NV61;
                image->size = image->height * image->width * 2;
                image->coplanar = 1;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "nv12") == 0) {
                image->fourcc = V4L2_PIX_FMT_NV12;
                image->size = image->height * image->width * 1.5;
                image->coplanar = 1;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else if (strcmp (format, "nv21") == 0) {
                image->fourcc = V4L2_PIX_FMT_NV21;
                image->size = image->height * image->width * 1.5;
                image->coplanar = 1;
                image->colorspace = V4L2_COLORSPACE_SMPTE170M;

        } else {
                return 0;

        }

        return 1;
}

/**
 *****************************************************************************
 * @brief:  sets crop parameters
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: 0 on success
 *****************************************************************************
*/
static int set_ctrl(struct vpe *vpe)
{
	int ret;
	struct	v4l2_control ctrl;

	memset(&ctrl, 0, sizeof(ctrl));
	ctrl.id = V4L2_CID_TRANS_NUM_BUFS;
	ctrl.value = vpe->translen;
	ret = ioctl(vpe->fd, VIDIOC_S_CTRL, &ctrl);
	if (ret < 0)
		pexit("vpe: S_CTRL failed\n");

	return 0;
}

/**
 *****************************************************************************
 * @brief:  Intialize the vpe input by calling set_control, set_format,
 *	    set_crop, refbuf ioctls
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: 0 on success
 *****************************************************************************
*/
int vpe_input_init(struct vpe *vpe)
{
	int ret;
	struct v4l2_format fmt;
	struct v4l2_requestbuffers rqbufs;

	set_ctrl(vpe);

	memset(&fmt, 0, sizeof fmt);
	fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	fmt.fmt.pix_mp.width = vpe->src.width;
	fmt.fmt.pix_mp.height = vpe->src.height;
	fmt.fmt.pix_mp.pixelformat = vpe->src.fourcc;
	fmt.fmt.pix_mp.colorspace = vpe->src.colorspace;
	fmt.fmt.pix_mp.num_planes = vpe->src.coplanar ? 2 : 1;

	switch (vpe->deint) {
	case 1:
		fmt.fmt.pix_mp.field = V4L2_FIELD_ALTERNATE;
		break;
	case 2:
		fmt.fmt.pix_mp.field = V4L2_FIELD_SEQ_TB;
		break;
	case 0:
	default:
		fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
		break;
	}

	ret = ioctl(vpe->fd, VIDIOC_S_FMT, &fmt);
	if (ret < 0) {
		pexit( "vpe i/p: S_FMT failed: %s\n", strerror(errno));
	} else {
                vpe->src.size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
                vpe->src.size_uv = fmt.fmt.pix_mp.plane_fmt[1].sizeimage;
        }

	ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
	if (ret < 0)
		pexit( "vpe i/p: G_FMT_2 failed: %s\n", strerror(errno));

	printf("vpe i/p: G_FMT: width = %u, height = %u, 4cc = %.4s\n",
			fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
			(char*)&fmt.fmt.pix_mp.pixelformat);

	memset(&rqbufs, 0, sizeof(rqbufs));
	rqbufs.count = NUMBUF;
	rqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	rqbufs.memory = V4L2_MEMORY_DMABUF;

	ret = ioctl(vpe->fd, VIDIOC_REQBUFS, &rqbufs);
	if (ret < 0)
		pexit( "vpe i/p: REQBUFS failed: %s\n", strerror(errno));

	vpe->src.numbuf = rqbufs.count;
	dprintf("vpe i/p: allocated buffers = %d\n", rqbufs.count);

	return 0;

}

/**
 *****************************************************************************
 * @brief:  Initialize vpe output by calling set_format, reqbuf ioctls.
 *	    Also allocates buffer to display the vpe output.
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: 0 on success
 *****************************************************************************
*/
int vpe_output_init(struct vpe *vpe)
{
	int ret, i;
	struct v4l2_format fmt;
	struct v4l2_requestbuffers rqbufs;
	bool saved_multiplanar;

	memset(&fmt, 0, sizeof fmt);
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	fmt.fmt.pix_mp.width = vpe->dst.width;
	fmt.fmt.pix_mp.height = vpe->dst.height;
	fmt.fmt.pix_mp.pixelformat = vpe->dst.fourcc;
	fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
	fmt.fmt.pix_mp.colorspace = vpe->dst.colorspace;
	fmt.fmt.pix_mp.num_planes = vpe->dst.coplanar ? 2 : 1;

	ret = ioctl(vpe->fd, VIDIOC_S_FMT, &fmt);
	if (ret < 0)
		pexit( "vpe o/p: S_FMT failed: %s\n", strerror(errno));

	ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
	if (ret < 0)
		pexit( "vpe o/p: G_FMT_2 failed: %s\n", strerror(errno));



	printf("vpe o/p: G_FMT: width = %u, height = %u, 4cc = %.4s\n",
			fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
			(char*)&fmt.fmt.pix_mp.pixelformat);



	memset(&rqbufs, 0, sizeof(rqbufs));
	rqbufs.count = NUMBUF;
	rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	rqbufs.memory = V4L2_MEMORY_DMABUF;


	ret = ioctl(vpe->fd, VIDIOC_REQBUFS, &rqbufs);
	if (ret < 0)
		pexit( "vpe o/p: REQBUFS failed: %s\n", strerror(errno));

	vpe->dst.numbuf = rqbufs.count;
	dprintf("vpe o/p: allocated buffers = %d\n", rqbufs.count);

	/*
	 * disp->multiplanar is used when allocating buffers to enable
	 * allocating multiplane buffer in separate buffers.
	 * VPE does handle mulitplane NV12 buffer correctly
	 * but VIP can only handle single plane buffers
	 * So by default we are setup to use single plane and only overwrite
	 * it when allocating strictly VPE buffers.
	 * Here we saved to current value and restore it after we are done
	 * allocating the buffers VPE will use for output.
	 */

	saved_multiplanar = vpe->disp->multiplanar;
	vpe->disp->multiplanar = true;

	//vpe->disp_bufs = disp_get_vid_buffers(vpe->disp, NUMBUF, vpe->dst.fourcc,
	//				      vpe->dst.width, vpe->dst.height);	

	vpe->disp_bufs = get_cmem_buffers(vpe->disp, NUMBUF, vpe->dst.fourcc,
					      vpe->dst.width, vpe->dst.height);


	vpe->disp->multiplanar = saved_multiplanar;
	if (!vpe->disp_bufs)
		pexit("allocating display buffer failed\n");

	/* SetCrtc with an RGB buffer first */
	//disp_get_fb(vpe->disp);


	for (i = 0; i < NUMBUF; i++) {
		vpe->output_buf_dmafd[i]=vpe->disp_bufs[i]->fd[0];
		//vpe->output_buf_dmafd[i] = omap_bo_dmabuf(vpe->disp_bufs[i]->bo[0]);
		//vpe->disp_bufs[i]->fd[0] = vpe->output_buf_dmafd[i];

		if(vpe->dst.coplanar) {
			vpe->output_buf_dmafd_uv[i] = omap_bo_dmabuf(vpe->disp_bufs[i]->bo[1]);
			vpe->disp_bufs[i]->fd[1] = vpe->output_buf_dmafd_uv[i];
			
		}
		/* Scale back to display resolution */
		vpe->disp_bufs[i]->noScale = false;
		dprintf("vpe->disp_bufs_fd[%d] = %d\n", i, vpe->output_buf_dmafd[i]);
	}

	dprintf("allocating display buffer success\n");
	return 0;
}

/**
 *****************************************************************************
 * @brief:  queue buffer to vpe input
 *
 * @param:  vpe  struct vpe pointer
 * @param:  index  buffer index to queue
 *
 * @return: 0 on success
 *****************************************************************************
*/
int vpe_input_qbuf(struct vpe *vpe, int index)
{
	int ret;
	struct v4l2_buffer buf;
	struct v4l2_plane planes[2];

	dprintf("vpe: src QBUF (%d):%s field", vpe->field,
		vpe->field==V4L2_FIELD_TOP?"top":"bottom");

	memset(&buf, 0, sizeof buf);
	memset(&planes, 0, sizeof planes);

	planes[0].length = planes[0].bytesused = vpe->src.size;
	if(vpe->src.coplanar)
		planes[1].length = planes[1].bytesused = vpe->src.size_uv;

	planes[0].data_offset = planes[1].data_offset = 0;

	buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	buf.memory = V4L2_MEMORY_DMABUF;
	buf.index = index;
	buf.m.planes = &planes[0];
	buf.field = vpe->field;
	if(vpe->src.coplanar)
		buf.length = 2;
	else
		buf.length = 1;

	buf.m.planes[0].m.fd = vpe->input_buf_dmafd[index];
	if(vpe->src.coplanar)
		buf.m.planes[1].m.fd = vpe->input_buf_dmafd_uv[index];

	ret = ioctl(vpe->fd, VIDIOC_QBUF, &buf);
	if (ret < 0)
		pexit( "vpe i/p: QBUF failed: %s, index = %d\n",
			strerror(errno), index);

	return 0;
}

/**
 *****************************************************************************
 * @brief:  queue buffer to vpe output
 *
 * @param:  vpe  struct vpe pointer
 * @param:  index  buffer index to queue
 *
 * @return: 0 on success
 *****************************************************************************
*/
int vpe_output_qbuf(struct vpe *vpe, int index)
{
	int ret;
	struct v4l2_buffer buf;
	struct v4l2_plane planes[2];

	dprintf("vpe output buffer queue\n");

	memset(&buf, 0, sizeof buf);
	memset(&planes, 0, sizeof planes);

	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	buf.memory = V4L2_MEMORY_DMABUF;
	buf.index = index;
	buf.m.planes = &planes[0];
	if(vpe->dst.coplanar)
		buf.length = 2;
	else
		buf.length = 1;

	buf.m.planes[0].m.fd = vpe->output_buf_dmafd[index];

	if(vpe->dst.coplanar)
		buf.m.planes[1].m.fd = vpe->output_buf_dmafd_uv[index];

	ret = ioctl(vpe->fd, VIDIOC_QBUF, &buf);
	if (ret < 0)
		pexit( "vpe o/p: QBUF failed: %s, index = %d\n",
			strerror(errno), index);

	return 0;
}

/**
 *****************************************************************************
 * @brief:  start stream
 *
 * @param:  fd  device fd
 * @param:  type  buffer type (CAPTURE or OUTPUT)
 *
 * @return: 0 on success
 *****************************************************************************
*/
int stream_ON(int fd, int type)
{
	int ret;

	ret = ioctl(fd, VIDIOC_STREAMON, &type);
	if (ret < 0)
		pexit("STREAMON failed,  %d: %s\n", type, strerror(errno));

	dprintf("stream ON: done! fd = %d,  type = %d\n", fd, type);

	return 0;
}

/**
 *****************************************************************************
 * @brief:  stop stream
 *
 * @param:  fd  device fd
 * @param:  type  buffer type (CAPTURE or OUTPUT)
 *
 * @return: 0 on success
 *****************************************************************************
*/
int stream_OFF(int fd, int type)
{
	int ret;

	ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
	if (ret < 0)
		pexit("STREAMOFF failed, %d: %s\n", type, strerror(errno));

	dprintf("stream OFF: done! fd = %d,  type = %d\n", fd, type);

	return 0;
}

/**
 *****************************************************************************
 * @brief:  dequeue vpe input buffer
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: buf.index index of dequeued buffer
 *****************************************************************************
*/
int vpe_input_dqbuf(struct vpe *vpe)
{
	int ret;
	struct v4l2_buffer buf;
	struct v4l2_plane planes[2];

	dprintf("vpe input dequeue buffer\n");

	memset(&buf, 0, sizeof buf);
	memset(&planes, 0, sizeof planes);

	buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
	buf.memory = V4L2_MEMORY_DMABUF;
        buf.m.planes = &planes[0];
        if (vpe->src.coplanar)
		buf.length = 2;
	else
		buf.length = 1;
	ret = ioctl(vpe->fd, VIDIOC_DQBUF, &buf);
	if (ret < 0)
		pexit("vpe i/p: DQBUF failed: %s\n", strerror(errno));

	dprintf("vpe i/p: DQBUF index = %d\n", buf.index);

	return buf.index;
}

/**
 *****************************************************************************
 * @brief:  dequeue vpe output buffer
 *
 * @param:  vpe  struct vpe pointer
 *
 * @return: buf.index index of dequeued buffer
 *****************************************************************************
*/
int vpe_output_dqbuf(struct vpe *vpe)
{
	int ret;
	struct v4l2_buffer buf;
	struct v4l2_plane planes[2];
	//printf("**********************cxy_test**********************\n");
	dprintf("vpe output dequeue buffer\n");

	memset(&buf, 0, sizeof buf);
	memset(&planes, 0, sizeof planes);

	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
	buf.memory = V4L2_MEMORY_DMABUF;
        buf.m.planes = &planes[0];
	if(vpe->dst.coplanar)
		buf.length = 2;
	else
		buf.length = 1;
	ret = ioctl(vpe->fd, VIDIOC_DQBUF, &buf);
	if (ret < 0)
		pexit("vpe o/p: DQBUF failed: %s\n", strerror(errno));

	dprintf("vpe o/p: DQBUF index = %d\n", buf.index);

	return buf.index;
}

/**
 *****************************************************************************
 * @brief:  buffer retried by index and displays the contents
 *
 * @param:  vpe  struct vpe pointer
 * @param: index index of dequeued output buffer
 *
 * @return: 0 on success
 *****************************************************************************
*/
int display_buffer(struct vpe *vpe, int index)
{
	int ret;
	struct buffer *buf;

	buf = vpe->disp_bufs[index];
	ret = disp_post_vid_buffer(vpe->disp, buf, 0, 0, vpe->dst.width,
				   vpe->dst.height);
	if (ret)
		pexit("disp post vid buf failed\n");

	return 0;
}

