1 /*
2 * Copyright (c) 2013-2014, Texas Instruments Incorporated
3 * Author: alaganraj <alaganraj.s@ti.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Contact information for paper mail:
33 * Texas Instruments
34 * Post Office Box 655303
35 * Dallas, Texas 75265
36 * Contact information:
37 * http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
38 * DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
39 * ============================================================================
40 *
41 */
43 /*
44 * @File vpe-common.c
45 * @Brief vpe specific common functions, used to integrate vpe
46 * with other modules.
47 *
48 * Input buffer must be allocated in application, queue it to vpe
49 * by passing buffer index
50 *
51 * Output buffer allocated in vpe_output_init() as vpe output intended
52 * to display on LCD.
53 */
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <fcntl.h>
57 #include <unistd.h>
58 #include <stdint.h>
59 #include <string.h>
60 #include <errno.h>
62 #include <linux/videodev2.h>
63 #include <linux/v4l2-controls.h>
65 #include <sys/mman.h>
66 #include <sys/ioctl.h>
68 #include <xf86drm.h>
69 #include <omap_drm.h>
70 #include <omap_drmif.h>
72 #include "util.h"
74 #define pexit(fmt, arg...) { \
75 printf(fmt, ## arg); \
76 exit(1); \
77 }
79 #define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_PRIVATE_BASE)
80 #define NUMBUF 6
82 //#define vpe_debug
84 #ifdef vpe_debug
85 #define dprintf(fmt, arg...) printf(fmt, ## arg)
86 #else
87 #define dprintf(fmt, arg...) do {} while(0)
88 #endif
90 struct image_params {
91 int width;
92 int height;
93 int fourcc;
94 int size;
95 int size_uv;
96 int coplanar;
97 enum v4l2_colorspace colorspace;
98 int numbuf;
99 };
101 struct vpe {
102 int fd;
103 int field;
104 int deint;
105 int translen;
106 struct image_params src;
107 struct image_params dst;
108 struct v4l2_crop crop;
109 int input_buf_dmafd[NUMBUF];
110 int input_buf_dmafd_uv[NUMBUF];
111 int output_buf_dmafd[NUMBUF];
112 struct display *disp;
113 struct buffer **disp_bufs;
114 };
116 /**
117 *****************************************************************************
118 * @brief: open the device
119 *
120 * @return: vpe struct vpe pointer
121 *****************************************************************************
122 */
123 struct vpe *vpe_open(void)
124 {
125 char devname[20] = "/dev/video0";
126 struct vpe *vpe;
128 vpe = calloc(1, sizeof(*vpe));
130 vpe->fd = open(devname, O_RDWR);
131 if(vpe->fd < 0)
132 pexit("Cant open %s\n", devname);
134 printf("vpe:%s open success!!!\n", devname);
136 return vpe;
137 }
139 /**
140 *****************************************************************************
141 * @brief: close the device and free memory
142 *
143 * @param: vpe struct vpe pointer
144 *
145 * @return: 0 on success
146 *****************************************************************************
147 */
148 int vpe_close(struct vpe *vpe)
149 {
150 close(vpe->fd);
151 free(vpe);
153 return 0;
154 }
156 /**
157 *****************************************************************************
158 * @brief: fills 4cc, size, coplanar, colorspace based on command line input
159 *
160 * @param: format char pointer
161 * @param: image struct image_params pointer
162 *
163 * @return: 0 on success
164 *****************************************************************************
165 */
166 int describeFormat (char *format, struct image_params *image)
167 {
168 image->size = -1;
169 image->fourcc = -1;
170 if (strcmp (format, "rgb24") == 0) {
171 image->fourcc = V4L2_PIX_FMT_RGB24;
172 image->size = image->height * image->width * 3;
173 image->coplanar = 0;
174 image->colorspace = V4L2_COLORSPACE_SRGB;
176 } else if (strcmp (format, "bgr24") == 0) {
177 image->fourcc = V4L2_PIX_FMT_BGR24;
178 image->size = image->height * image->width * 3;
179 image->coplanar = 0;
180 image->colorspace = V4L2_COLORSPACE_SRGB;
182 } else if (strcmp (format, "argb32") == 0) {
183 image->fourcc = V4L2_PIX_FMT_RGB32;
184 image->size = image->height * image->width * 4;
185 image->coplanar = 0;
186 image->colorspace = V4L2_COLORSPACE_SRGB;
188 } else if (strcmp (format, "abgr32") == 0) {
189 image->fourcc = V4L2_PIX_FMT_BGR32;
190 image->size = image->height * image->width * 4;
191 image->coplanar = 0;
192 image->colorspace = V4L2_COLORSPACE_SRGB;
194 } else if (strcmp (format, "yuv444") == 0) {
195 image->fourcc = V4L2_PIX_FMT_YUV444;
196 image->size = image->height * image->width * 3;
197 image->coplanar = 0;
198 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
200 } else if (strcmp (format, "yvyu") == 0) {
201 image->fourcc = V4L2_PIX_FMT_YVYU;
202 image->size = image->height * image->width * 2;
203 image->coplanar = 0;
204 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
206 } else if (strcmp (format, "yuyv") == 0) {
207 image->fourcc = V4L2_PIX_FMT_YUYV;
208 image->size = image->height * image->width * 2;
209 image->coplanar = 0;
210 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
212 } else if (strcmp (format, "uyvy") == 0) {
213 image->fourcc = V4L2_PIX_FMT_UYVY;
214 image->size = image->height * image->width * 2;
215 image->coplanar = 0;
216 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
218 } else if (strcmp (format, "vyuy") == 0) {
219 image->fourcc = V4L2_PIX_FMT_VYUY;
220 image->size = image->height * image->width * 2;
221 image->coplanar = 0;
222 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
224 } else if (strcmp (format, "nv16") == 0) {
225 image->fourcc = V4L2_PIX_FMT_NV16;
226 image->size = image->height * image->width * 2;
227 image->coplanar = 0;
228 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
230 } else if (strcmp (format, "nv61") == 0) {
231 image->fourcc = V4L2_PIX_FMT_NV61;
232 image->size = image->height * image->width * 2;
233 image->coplanar = 0;
234 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
236 } else if (strcmp (format, "nv12") == 0) {
237 image->fourcc = V4L2_PIX_FMT_NV12;
238 image->size = image->height * image->width * 1.5;
239 image->coplanar = 1;
240 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
242 } else if (strcmp (format, "nv21") == 0) {
243 image->fourcc = V4L2_PIX_FMT_NV21;
244 image->size = image->height * image->width * 1.5;
245 image->coplanar = 1;
246 image->colorspace = V4L2_COLORSPACE_SMPTE170M;
248 } else {
249 return 0;
251 }
253 return 1;
254 }
256 /**
257 *****************************************************************************
258 * @brief: sets crop parameters
259 *
260 * @param: vpe struct vpe pointer
261 *
262 * @return: 0 on success
263 *****************************************************************************
264 */
265 static int set_crop(struct vpe *vpe)
266 {
267 int ret = 0;
269 if ((vpe->crop.c.top == 0) && (vpe->crop.c.left == 0) &&
270 (vpe->crop.c.width == 0) && (vpe->crop.c.height == 0)) {
271 dprintf("setting default crop params\n");
272 vpe->crop.c.top = 0;
273 vpe->crop.c.left = 0;
274 vpe->crop.c.width = vpe->src.width;
275 vpe->crop.c.height = vpe->src.height;
276 vpe->crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
277 }
279 ret = ioctl(vpe->fd, VIDIOC_S_CROP, &vpe->crop);
280 if (ret < 0)
281 pexit("error setting crop\n");
283 return 0;
284 }
286 /**
287 *****************************************************************************
288 * @brief: sets control, howmany jobs to be handled on multi instance
289 *
290 * @param: vpe struct vpe pointer
291 *
292 * @return: 0 on success
293 *****************************************************************************
294 */
295 static int set_ctrl(struct vpe *vpe)
296 {
297 int ret;
298 struct v4l2_control ctrl;
300 memset(&ctrl, 0, sizeof(ctrl));
301 ctrl.id = V4L2_CID_TRANS_NUM_BUFS;
302 ctrl.value = vpe->translen;
303 ret = ioctl(vpe->fd, VIDIOC_S_CTRL, &ctrl);
304 if (ret < 0)
305 pexit("vpe: S_CTRL failed\n");
307 return 0;
308 }
310 /**
311 *****************************************************************************
312 * @brief: Intialize the vpe input by calling set_control, set_format,
313 * set_crop, refbuf ioctls
314 *
315 * @param: vpe struct vpe pointer
316 *
317 * @return: 0 on success
318 *****************************************************************************
319 */
320 int vpe_input_init(struct vpe *vpe)
321 {
322 int ret;
323 struct v4l2_format fmt;
324 struct v4l2_requestbuffers rqbufs;
326 set_ctrl(vpe);
328 memset(&fmt, 0, sizeof fmt);
329 fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
331 ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
332 if (ret < 0)
333 pexit( "vpe i/p: G_FMT_1 failed: %s\n", strerror(errno));
335 fmt.fmt.pix_mp.width = vpe->src.width;
336 fmt.fmt.pix_mp.height = vpe->src.height;
337 fmt.fmt.pix_mp.pixelformat = vpe->src.fourcc;
339 switch (vpe->deint) {
340 case 1:
341 fmt.fmt.pix_mp.field = V4L2_FIELD_ALTERNATE;
342 break;
343 case 2:
344 fmt.fmt.pix_mp.field = V4L2_FIELD_SEQ_TB;
345 break;
346 case 0:
347 default:
348 fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
349 break;
350 }
352 ret = ioctl(vpe->fd, VIDIOC_S_FMT, &fmt);
353 if (ret < 0) {
354 pexit( "vpe i/p: S_FMT failed: %s\n", strerror(errno));
355 } else {
356 vpe->src.size = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
357 vpe->src.size_uv = fmt.fmt.pix_mp.plane_fmt[1].sizeimage;
358 }
360 ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
361 if (ret < 0)
362 pexit( "vpe i/p: G_FMT_2 failed: %s\n", strerror(errno));
364 printf("vpe i/p: G_FMT: width = %u, height = %u, 4cc = %.4s\n",
365 fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
366 (char*)&fmt.fmt.pix_mp.pixelformat);
368 set_crop(vpe);
370 memset(&rqbufs, 0, sizeof(rqbufs));
371 rqbufs.count = NUMBUF;
372 rqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
373 rqbufs.memory = V4L2_MEMORY_DMABUF;
375 ret = ioctl(vpe->fd, VIDIOC_REQBUFS, &rqbufs);
376 if (ret < 0)
377 pexit( "vpe i/p: REQBUFS failed: %s\n", strerror(errno));
379 vpe->src.numbuf = rqbufs.count;
380 dprintf("vpe i/p: allocated buffers = %d\n", rqbufs.count);
382 return 0;
384 }
386 /**
387 *****************************************************************************
388 * @brief: Initialize vpe output by calling set_format, reqbuf ioctls.
389 * Also allocates buffer to display the vpe output.
390 *
391 * @param: vpe struct vpe pointer
392 *
393 * @return: 0 on success
394 *****************************************************************************
395 */
396 int vpe_output_init(struct vpe *vpe)
397 {
398 int ret, i;
399 struct v4l2_format fmt;
400 struct v4l2_requestbuffers rqbufs;
402 memset(&fmt, 0, sizeof fmt);
403 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
405 ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
406 if (ret < 0)
407 pexit( "vpe o/p: G_FMT_1 failed: %s\n", strerror(errno));
409 fmt.fmt.pix_mp.width = vpe->dst.width;
410 fmt.fmt.pix_mp.height = vpe->dst.height;
411 fmt.fmt.pix_mp.pixelformat = vpe->dst.fourcc;
412 fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
414 ret = ioctl(vpe->fd, VIDIOC_S_FMT, &fmt);
415 if (ret < 0)
416 pexit( "vpe o/p: S_FMT failed: %s\n", strerror(errno));
418 ret = ioctl(vpe->fd, VIDIOC_G_FMT, &fmt);
419 if (ret < 0)
420 pexit( "vpe o/p: G_FMT_2 failed: %s\n", strerror(errno));
422 printf("vpe o/p: G_FMT: width = %u, height = %u, 4cc = %.4s\n",
423 fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
424 (char*)&fmt.fmt.pix_mp.pixelformat);
426 memset(&rqbufs, 0, sizeof(rqbufs));
427 rqbufs.count = NUMBUF;
428 rqbufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
429 rqbufs.memory = V4L2_MEMORY_DMABUF;
431 ret = ioctl(vpe->fd, VIDIOC_REQBUFS, &rqbufs);
432 if (ret < 0)
433 pexit( "vpe o/p: REQBUFS failed: %s\n", strerror(errno));
435 vpe->dst.numbuf = rqbufs.count;
436 dprintf("vpe o/p: allocated buffers = %d\n", rqbufs.count);
438 vpe->disp_bufs = disp_get_vid_buffers(vpe->disp, NUMBUF, vpe->dst.fourcc,
439 vpe->dst.width, vpe->dst.height);
440 if (!vpe->disp_bufs)
441 pexit("allocating display buffer failed\n");
443 for (i = 0; i < NUMBUF; i++) {
444 vpe->output_buf_dmafd[i] = omap_bo_dmabuf(vpe->disp_bufs[i]->bo[0]);
445 vpe->disp_bufs[i]->fd[0] = vpe->output_buf_dmafd[i];
446 /* display only image widthxheight, no full screen */
447 vpe->disp_bufs[i]->noScale = true;
448 dprintf("vpe->disp_bufs_fd[%d] = %d\n", i, vpe->output_buf_dmafd[i]);
449 }
451 dprintf("allocating display buffer success\n");
452 return 0;
453 }
455 /**
456 *****************************************************************************
457 * @brief: queue buffer to vpe input
458 *
459 * @param: vpe struct vpe pointer
460 * @param: index buffer index to queue
461 *
462 * @return: 0 on success
463 *****************************************************************************
464 */
465 int vpe_input_qbuf(struct vpe *vpe, int index)
466 {
467 int ret, i;
468 struct v4l2_buffer buf;
469 struct v4l2_plane planes[2];
471 dprintf("vpe input buffer queue\n");
473 memset(&buf, 0, sizeof buf);
474 memset(&planes, 0, sizeof planes);
476 planes[0].length = planes[0].bytesused = vpe->src.size;
477 if(vpe->src.coplanar)
478 planes[1].length = planes[1].bytesused = vpe->src.size_uv;
480 planes[0].data_offset = planes[1].data_offset = 0;
482 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
483 buf.memory = V4L2_MEMORY_DMABUF;
484 buf.index = index;
485 buf.m.planes = &planes;
486 buf.field = vpe->field;
487 if(vpe->src.coplanar)
488 buf.length = 2;
489 else
490 buf.length = 1;
492 buf.m.planes[0].m.fd = vpe->input_buf_dmafd[index];
493 if(vpe->src.coplanar)
494 buf.m.planes[1].m.fd = vpe->input_buf_dmafd_uv[index];
496 ret = ioctl(vpe->fd, VIDIOC_QBUF, &buf);
497 if (ret < 0)
498 pexit( "vpe i/p: QBUF failed: %s, index = %d\n",
499 strerror(errno), index);
501 return 0;
502 }
504 /**
505 *****************************************************************************
506 * @brief: queue buffer to vpe output
507 *
508 * @param: vpe struct vpe pointer
509 * @param: index buffer index to queue
510 *
511 * @return: 0 on success
512 *****************************************************************************
513 */
514 int vpe_output_qbuf(struct vpe *vpe, int index)
515 {
516 int ret, i;
517 struct v4l2_buffer buf;
518 struct v4l2_plane planes[2];
520 dprintf("vpe output buffer queue\n");
522 memset(&buf, 0, sizeof buf);
523 memset(&planes, 0, sizeof planes);
525 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
526 buf.memory = V4L2_MEMORY_DMABUF;
527 buf.index = index;
528 buf.m.planes = &planes;
529 buf.length = 2;
531 buf.m.planes[0].m.fd = vpe->output_buf_dmafd[index];
533 ret = ioctl(vpe->fd, VIDIOC_QBUF, &buf);
534 if (ret < 0)
535 pexit( "vpe o/p: QBUF failed: %s, index = %d\n",
536 strerror(errno), index);
538 return 0;
539 }
541 /**
542 *****************************************************************************
543 * @brief: start stream
544 *
545 * @param: fd device fd
546 * @param: type buffer type (CAPTURE or OUTPUT)
547 *
548 * @return: 0 on success
549 *****************************************************************************
550 */
551 int stream_ON(int fd, int type)
552 {
553 int ret;
555 ret = ioctl(fd, VIDIOC_STREAMON, &type);
556 if (ret < 0)
557 pexit("STREAMON failed, %d: %s\n", type, strerror(errno));
559 dprintf("stream ON: done! fd = %d, type = %d\n", fd, type);
561 return 0;
562 }
564 /**
565 *****************************************************************************
566 * @brief: stop stream
567 *
568 * @param: fd device fd
569 * @param: type buffer type (CAPTURE or OUTPUT)
570 *
571 * @return: 0 on success
572 *****************************************************************************
573 */
574 int stream_OFF(int fd, int type)
575 {
576 int ret;
578 ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
579 if (ret < 0)
580 pexit("STREAMOFF failed, %d: %s\n", type, strerror(errno));
582 dprintf("stream OFF: done! fd = %d, type = %d\n", fd, type);
584 return 0;
585 }
587 /**
588 *****************************************************************************
589 * @brief: dequeue vpe input buffer
590 *
591 * @param: vpe struct vpe pointer
592 *
593 * @return: buf.index index of dequeued buffer
594 *****************************************************************************
595 */
596 int vpe_input_dqbuf(struct vpe *vpe)
597 {
598 int ret;
599 struct v4l2_buffer buf;
600 struct v4l2_plane planes[2];
602 dprintf("vpe input dequeue buffer\n");
604 memset(&buf, 0, sizeof buf);
605 memset(&planes, 0, sizeof planes);
607 buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
608 buf.memory = V4L2_MEMORY_DMABUF;
609 buf.m.planes = &planes;
610 if(vpe->src.coplanar)
611 buf.length = 2;
612 else
613 buf.length = 1;
614 ret = ioctl(vpe->fd, VIDIOC_DQBUF, &buf);
615 if (ret < 0)
616 pexit("vpe i/p: DQBUF failed: %s\n", strerror(errno));
618 dprintf("vpe i/p: DQBUF index = %d\n", buf.index);
620 return buf.index;
621 }
623 /**
624 *****************************************************************************
625 * @brief: dequeue vpe output buffer
626 *
627 * @param: vpe struct vpe pointer
628 *
629 * @return: buf.index index of dequeued buffer
630 *****************************************************************************
631 */
632 int vpe_output_dqbuf(struct vpe *vpe)
633 {
634 int ret;
635 struct v4l2_buffer buf;
636 struct v4l2_plane planes[2];
638 dprintf("vpe output dequeue buffer\n");
640 memset(&buf, 0, sizeof buf);
641 memset(&planes, 0, sizeof planes);
643 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
644 buf.memory = V4L2_MEMORY_DMABUF;
645 buf.m.planes = &planes;
646 buf.length = 1;
647 ret = ioctl(vpe->fd, VIDIOC_DQBUF, &buf);
648 if (ret < 0)
649 pexit("vpe o/p: DQBUF failed: %s\n", strerror(errno));
651 dprintf("vpe o/p: DQBUF index = %d\n", buf.index);
653 return buf.index;
654 }
656 /**
657 *****************************************************************************
658 * @brief: buffer retried by index and displays the contents
659 *
660 * @param: vpe struct vpe pointer
661 * @param: index index of dequeued output buffer
662 *
663 * @return: 0 on success
664 *****************************************************************************
665 */
666 int display_buffer(struct vpe *vpe, int index)
667 {
668 int ret;
669 struct buffer *buf;
671 buf = vpe->disp_bufs[index];
672 ret = disp_post_vid_buffer(vpe->disp, buf, 0, 0, vpe->dst.width,
673 vpe->dst.height);
674 if (ret)
675 pexit("disp post vid buf failed\n");
677 return 0;
678 }