video : graphics : test : Advance video use case
[sitara-linux/video-graphics-test.git] / loopback.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <fcntl.h>
6 #include <sys/mman.h>
7 #include <malloc.h>
8 #include <sys/stat.h>
9 #include <sys/ioctl.h>
10 #include <stdbool.h>
11 #include <linux/videodev2.h>
12 #include <omap_drm.h>
13 #include <omap_drmif.h>
14 #include <xf86drmMode.h>
15 #include "loopback.h"
17 #define ERROR(fmt, ...) \
18         do { fprintf(stderr, "ERROR:%s:%d: " fmt "\n", __func__, __LINE__,\
19 ##__VA_ARGS__); } while (0)
21 #define MSG(fmt, ...) \
22         do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); } while (0)
24 /* Dynamic debug. */
25 #define DBG(fmt, ...) \
26         do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); } while (0)
28 /* align x to next highest multiple of 2^n */
29 #define ALIGN2(x,n)   (((x) + ((1 << (n)) - 1)) & ~((1 << (n)) - 1))
30 #define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | \
31         ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | \
32         ((uint32_t)(uint8_t)(d) << 24 ))
33 #define FOURCC_STR(str)    FOURCC(str[0], str[1], str[2], str[3])
35 #define PAGE_SHIFT 12
36 #define NBUF (3)
37 #define MAX_DRM_PLANES 5
38 #define CAP_WIDTH 800
39 #define CAP_HEIGHT 600
40 #define PIP_POS_X  25
41 #define PIP_POS_Y  25
42 #define MAX_ZORDER_VAL 3 //For AM57x device, max zoder value is 3
44 struct control status;
46 struct dmabuf_buffer {
47         uint32_t fourcc, width, height;
48         int nbo;
49         struct omap_bo *bo[4];
50         uint32_t pitches[4];
51         int fd[4];              /* dmabuf */
52         unsigned fb_id;
53 };
55 struct connector_info {
56         unsigned int id;
57         char mode_str[64];
58         drmModeModeInfo *mode;
59         drmModeEncoder *encoder;
60         int crtc;
61         int pipe;
62 };
64 /*
65 * drm output device structure declaration
66 */
67 struct drm_device_info
68 {
69         int fd;
70         int width;
71         int height;
72         char dev_name[9];
73         char name[4];
74         unsigned int bo_flags;
75         struct dmabuf_buffer **buf[2];
76         struct omap_device *dev;
77         unsigned int crtc_id;
78         unsigned int plane_id[2];
79         unsigned int prop_fbid;
80         unsigned int prop_crtcid;
81         uint64_t zorder_val_primary_plane;
82         uint64_t trans_key_mode_val;
83         uint32_t zorder_val[MAX_DRM_PLANES-1];
84 } drm_device;
86 /*
87 * V4L2 capture device structure declaration
88 */
89 struct v4l2_device_info {
90         int type;
91         int fd;
92         enum v4l2_memory memory_mode;
93         unsigned int num_buffers;
94         int width;
95         int height;
96         char dev_name[12];
97         char name[10];
99         struct v4l2_buffer *buf;
100         struct v4l2_format fmt;
101         struct dmabuf_buffer **buffers;
102 } cap0_device, cap1_device;
104 static volatile int waiting_for_flip;
106 static struct omap_bo *alloc_bo(struct drm_device_info *device, unsigned int bpp,
107                                                                 unsigned int width, unsigned int height,
108                                                                 unsigned int *bo_handle, unsigned int *pitch)
110         struct omap_bo *bo;
111         unsigned int bo_flags = device->bo_flags;
113         bo_flags |= OMAP_BO_WC;
114         bo = omap_bo_new(device->dev, width * height * bpp / 8, bo_flags);
116         if (bo) {
117                 *bo_handle = omap_bo_handle(bo);
118                 *pitch = width * bpp / 8;
119                 if (bo_flags & OMAP_BO_TILED)
120                         *pitch = ALIGN2(*pitch, PAGE_SHIFT);
121         }
123         return bo;
126 //You can use DRM ioctl as well to allocate buffers (DRM_IOCTL_MODE_CREATE_DUMB)
127 //and drmPrimeHandleToFD() to get the buffer descriptors
128 static struct dmabuf_buffer *alloc_buffer(struct drm_device_info *device,
129                                                                                   unsigned int fourcc, unsigned int w,
130                                                                                   unsigned int h)
132         struct dmabuf_buffer *buf;
133         unsigned int bo_handles[4] = {0}, offsets[4] = {0};
134         int ret;
136         buf = (struct dmabuf_buffer *) calloc(1, sizeof(struct dmabuf_buffer));
137         if (!buf) {
138                 ERROR("allocation failed");
139                 return NULL;
140         }
142         buf->fourcc = fourcc;
143         buf->width = w;
144         buf->height = h;
145         buf->nbo = 1;
146         buf->bo[0] = alloc_bo(device, 16, buf->width, buf->height,
147                 &bo_handles[0], &buf->pitches[0]);
149         ret = drmModeAddFB2(device->fd, buf->width, buf->height, fourcc,
150                 bo_handles, buf->pitches, offsets, &buf->fb_id, 0);
152         if (ret) {
153                 ERROR("drmModeAddFB2 failed: %s (%d)", strerror(errno), ret);
154                 return NULL;
155         }
157         return buf;
160 void free_vid_buffers(struct dmabuf_buffer **buf, unsigned int n)
162         unsigned int i;
164         if (buf == NULL) return;
165         for (i = 0; i < n; i++) {
166                 if (buf[i]) {
167                         close(buf[i]->fd[0]);
168                         omap_bo_del(buf[i]->bo[0]);
169                         free(buf[i]);
170                 }
171         }
172         free(buf);
176 static struct dmabuf_buffer **get_vid_buffers(struct drm_device_info *device,
177                                                                                           unsigned int n,
178                                                                                           unsigned int fourcc, unsigned int w, unsigned int h)
180         struct dmabuf_buffer **bufs;
181         unsigned int i = 0;
183         bufs = (struct dmabuf_buffer **) calloc(n, sizeof(*bufs));
184         if (!bufs) {
185                 ERROR("allocation failed");
186                 goto fail;
187         }
189         for (i = 0; i < n; i++) {
190                 bufs[i] = alloc_buffer(device, fourcc, w, h);
191                 if (!bufs[i]) {
192                         ERROR("allocation failed");
193                         goto fail;
194                 }
195         }
196         return bufs;
198 fail:
199         return NULL;
202 static int v4l2_init_device(struct v4l2_device_info *device)
204         int ret;
205         struct v4l2_capability capability;
207         /* Open the capture device */
208         device->fd = open((const char *) device->dev_name, O_RDWR);
209         if (device->fd <= 0) {
210                 printf("Cannot open %s device\n", device->dev_name);
211                 return -1;
212         }
214         MSG("\n%s: Opened Channel\n", device->name);
216         /* Check if the device is capable of streaming */
217         if (ioctl(device->fd, VIDIOC_QUERYCAP, &capability) < 0) {
218                 perror("VIDIOC_QUERYCAP");
219                 goto ERROR;
220         }
222         if (capability.capabilities & V4L2_CAP_STREAMING)
223                 MSG("%s: Capable of streaming\n", device->name);
224         else {
225                 ERROR("%s: Not capable of streaming\n", device->name);
226                 goto ERROR;
227         }
229         {
230                 struct v4l2_streamparm streamparam;
231                 streamparam.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
232                 if (ioctl(device->fd, VIDIOC_G_PARM, &streamparam) < 0){
233                         perror("VIDIOC_G_PARM");
234                         goto ERROR;
235                 }
236         }
238         device->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
239         ret = ioctl(device->fd, VIDIOC_G_FMT, &device->fmt);
240         if (ret < 0) {
241                 ERROR("VIDIOC_G_FMT failed: %s (%d)", strerror(errno), ret);
242                 goto ERROR;
243         }
245         device->fmt.fmt.pix.pixelformat = FOURCC_STR("YUYV");
246         device->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
247         device->fmt.fmt.pix.width = device->width;
248         device->fmt.fmt.pix.height = device->height;
250         ret = ioctl(device->fd, VIDIOC_S_FMT, &device->fmt);
251         if (ret < 0) {
252                 perror("VIDIOC_S_FMT");
253                 goto ERROR;
254         }
256         MSG("%s: Init done successfully\n", device->name);
257         return 0;
259 ERROR:
260         close(device->fd);
262         return -1;
265 static void v4l2_exit_device(struct v4l2_device_info *device)
268         free(device->buf);
269         close(device->fd);
271         return;
275 /*
276 * Enable streaming for V4L2 capture device
277 */
278 static int v4l2_stream_on(struct v4l2_device_info *device)
280         enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
281         int ret = 0;
283         ret = ioctl(device->fd, VIDIOC_STREAMON, &type);
285         if (ret) {
286                 ERROR("VIDIOC_STREAMON failed: %s (%d)", strerror(errno), ret);
287         }
289         return ret;
292 /*
293 * Disable streaming for V4L2 capture device
294 */
295 static int v4l2_stream_off(struct v4l2_device_info *device)
297         enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
298         int ret = -1;
300         if (device->fd <= 0) {
301                 return ret;
302         }
304         ret = ioctl(device->fd, VIDIOC_STREAMOFF, &type);
306         if (ret) {
307                 ERROR("VIDIOC_STREAMOFF failed: %s (%d)", strerror(errno), ret);
308         }
310         return ret;
313 static int v4l2_request_buffer(struct v4l2_device_info *device,
314 struct dmabuf_buffer **bufs)
316         struct v4l2_requestbuffers reqbuf;
317         unsigned int i;
318         int ret,dmafd;
320         if (device->buf) {
321                 // maybe eventually need to support this?
322                 ERROR("already reqbuf'd");
323                 return -1;
324         }
326         reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
327         reqbuf.memory = device->memory_mode;
328         reqbuf.count = device->num_buffers;
330         ret = ioctl(device->fd, VIDIOC_REQBUFS, &reqbuf);
331         if (ret < 0) {
332                 ERROR("VIDIOC_REQBUFS failed: %s (%d)", strerror(errno), ret);
333                 return ret;
334         }
336         if ((reqbuf.count != device->num_buffers) ||
337                 (reqbuf.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
338                 (reqbuf.memory != V4L2_MEMORY_DMABUF)) {
339                         ERROR("unsupported..");
340                         return -1;
341         }
343         device->num_buffers = reqbuf.count;
344         device->buffers = bufs;
345         device->buf = (struct v4l2_buffer *) calloc(device->num_buffers, \
346                 sizeof(struct v4l2_buffer));
347         if (!device->buf) {
348                 ERROR("allocation failed");
349                 return -1;
350         }
352         for (i = 0; i < device->num_buffers; i++) {
353                 if (bufs[i]->nbo != 1){
354                         ERROR("Number of buffers not right");
355                 };
357                 /* Call omap_bo_dmabuf only once, to export only once
358                 * Otherwise, each call will return duplicated fds
359                 * This way, every call to omap_bo_dmabuf will return a new fd
360                 * Which won't match with any previously exported fds
361                 * Instead, store dma fd in buf->fd[] */
362                 dmafd = omap_bo_dmabuf(bufs[i]->bo[0]);
363                 bufs[i]->fd[0] = dmafd;
365                 device->buf[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
366                 device->buf[i].memory = V4L2_MEMORY_DMABUF;
367                 device->buf[i].index = i;
369                 MSG("Exported buffer fd = %d\n", dmafd);
370                 ret = ioctl(device->fd, VIDIOC_QUERYBUF, &device->buf[i]);
371                 device->buf[i].m.fd = dmafd;
373                 if (ret) {
374                         ERROR("VIDIOC_QUERYBUF failed: %s (%d)", strerror(errno), ret);
375                         return ret;
376                 }
377         }
379         return 0;
382 /*
383 * Queue V4L2 buffer
384 */
385 static int v4l2_queue_buffer(struct v4l2_device_info *device,
386 struct dmabuf_buffer *buf)
388         struct v4l2_buffer *v4l2buf = NULL;
389         int  ret, fd;
390         unsigned char i;
392         if(buf->nbo != 1){
393                 ERROR("number of bufers not right\n");
394                 return -1;
395         }
397         fd = buf->fd[0];
399         for (i = 0; i < device->num_buffers; i++) {
400                 if (device->buf[i].m.fd == fd) {
401                         v4l2buf = &device->buf[i];
402                 }
403         }
405         if (!v4l2buf) {
406                 ERROR("invalid buffer");
407                 return -1;
408         }
409         ret = ioctl(device->fd, VIDIOC_QBUF, v4l2buf);
410         if (ret) {
411                 ERROR("VIDIOC_QBUF failed: %s (%d)", strerror(errno), ret);
412         }
414         return ret;
417 /*
418 * DeQueue V4L2 buffer
419 */
420 struct dmabuf_buffer *v4l2_dequeue_buffer(struct v4l2_device_info *device)
422         struct dmabuf_buffer *buf;
423         struct v4l2_buffer v4l2buf;
424         int ret;
426         v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
427         v4l2buf.memory = V4L2_MEMORY_DMABUF;
428         ret = ioctl(device->fd, VIDIOC_DQBUF, &v4l2buf);
429         if (ret) {
430                 ERROR("VIDIOC_DQBUF failed: %s (%d)\n", strerror(errno), ret);
431                 return NULL;
432         }
434         buf = device->buffers[v4l2buf.index];
436         device->buf[v4l2buf.index].timestamp = v4l2buf.timestamp;
437         if(buf->nbo != 1){
438                 ERROR("num buffers not proper\n");
439                 return NULL;
440         }
442         return buf;
447 unsigned int get_drm_prop_val(int fd, drmModeObjectPropertiesPtr props,
448                                                           const char *name)
450         drmModePropertyPtr p;
451         unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
453         for (i = 0; !prop_id && i < props->count_props; i++) {
454                 p = drmModeGetProperty(fd, props->props[i]);
455                 if (!strcmp(p->name, name)){
456                         prop_id = p->prop_id;
457                         break;
458                 }
459                 drmModeFreeProperty(p);
460         }
461         if (!prop_id) {
462                 printf("Could not find %s property\n", name);
463                 drmModeFreeObjectProperties(props);
464                 exit(-1);
465         }
467         drmModeFreeProperty(p);
468         return props->prop_values[i];
471 unsigned int find_drm_prop_id(int fd, drmModeObjectPropertiesPtr props,
472                                                           const char *name)
474         drmModePropertyPtr p;
475         unsigned int i, prop_id = 0; /* Property ID should always be > 0 */
477         for (i = 0; !prop_id && i < props->count_props; i++) {
478                 p = drmModeGetProperty(fd, props->props[i]);
479                 if (!strcmp(p->name, name)){
480                         prop_id = p->prop_id;
481                         break;
482                 }
483                 drmModeFreeProperty(p);
484         }
485         if (!prop_id) {
486                 printf("Could not find %s property\n", name);
487                 drmModeFreeObjectProperties(props);
488                 exit(-1);
489         }
491         return prop_id;
494 void add_property(int fd, drmModeAtomicReqPtr req,
495                                   drmModeObjectPropertiesPtr props,
496                                   unsigned int plane_id,
497                                   const char *name, int value)
499         unsigned int prop_id = find_drm_prop_id(fd, props, name);
500         if(drmModeAtomicAddProperty(req, plane_id, prop_id, value) < 0){
501                 printf("failed to add property\n");
502         }
505 void drm_add_plane_property(struct drm_device_info *dev, drmModeAtomicReqPtr req)
507         unsigned int i;
508         unsigned int crtc_x_val = 0;
509         unsigned int crtc_y_val = 0;
510         unsigned int crtc_w_val = dev->width;
511         unsigned int crtc_h_val = dev->height;
512         drmModeObjectProperties *props;
513         unsigned int zorder_val = 1;
514         unsigned int buf_index;
515         struct v4l2_device_info  *v4l2_device;
517         for(i = 0; i < status.num_cams; i++){
518                 unsigned int plane_id = dev->plane_id[i];
520                 if(i) {
521                         crtc_x_val = PIP_POS_X;
522                         crtc_y_val = PIP_POS_Y;
523                         crtc_w_val /= 3;
524                         crtc_h_val /= 3;
525                 }
526                 props = drmModeObjectGetProperties(dev->fd, plane_id,
527                         DRM_MODE_OBJECT_PLANE);
529                 if(props == NULL){
530                         ERROR("drm obeject properties for plane type is NULL\n");
531                         exit (-1);
532                 }
534                 //fb id value will be set every time new frame is to be displayed
535                 dev->prop_fbid = find_drm_prop_id(drm_device.fd, props, "FB_ID");
537                 //Will need to change run time crtc id to disable/enable display of plane
538                 dev->prop_crtcid = find_drm_prop_id(drm_device.fd, props, "CRTC_ID");
540                 //storing zorder val to restore it before quitting the demo
541                 drm_device.zorder_val[i] = get_drm_prop_val(drm_device.fd, props, "zorder");
543                 //Set the fb id based on which camera is chosen to be main camera 
544                 if (status.main_cam  == 1){
545                         buf_index = (i+1)%2;
546                 }
547                 else {
548                         buf_index = i;
549                 }
551                 if(buf_index == 0){
552                         v4l2_device = &cap0_device;
553                 }
554                 else{
555                         v4l2_device = &cap1_device;
556                 }
557                 printf("w=%d, h=%d\n", v4l2_device->width, v4l2_device->height);
558                 add_property(dev->fd, req, props, plane_id, "FB_ID", dev->buf[buf_index][0]->fb_id);
560                 //set the plane properties once. No need to set these values every time
561                 //with the display of frame. 
562                 add_property(dev->fd, req, props, plane_id, "CRTC_ID", dev->crtc_id);
563                 add_property(dev->fd, req, props, plane_id, "CRTC_X", crtc_x_val);
564                 add_property(dev->fd, req, props, plane_id, "CRTC_Y", crtc_y_val);
565                 add_property(dev->fd, req, props, plane_id, "CRTC_W", crtc_w_val);
566                 add_property(dev->fd, req, props, plane_id, "CRTC_H", crtc_h_val);
567                 add_property(dev->fd, req, props, plane_id, "SRC_X", 0);
568                 add_property(dev->fd, req, props, plane_id, "SRC_Y", 0);
569                 add_property(dev->fd, req, props, plane_id, "SRC_W", v4l2_device->width << 16);
570                 add_property(dev->fd, req, props, plane_id, "SRC_H", v4l2_device->height << 16);
571                 add_property(dev->fd, req, props, plane_id, "zorder", zorder_val++);
572         }
575 uint32_t drm_reserve_plane(int fd, unsigned int *ptr_plane_id, int num_planes)
577         unsigned int i;
578         int idx = 0;
579         drmModeObjectProperties *props;
580         drmModePlaneRes *res = drmModeGetPlaneResources(fd);
581         if(res == NULL){
582                 ERROR("plane resources not found\n");
583         }
585         for (i = 0; i < res->count_planes; i++) {
586                 uint32_t plane_id = res->planes[i];
587                 unsigned int type_val;
589                 drmModePlane *plane = drmModeGetPlane(fd, plane_id);
590                 if(plane == NULL){
591                         ERROR("plane  not found\n");
592                 }
594                 props = drmModeObjectGetProperties(fd, plane->plane_id, DRM_MODE_OBJECT_PLANE);
596                 if(props == NULL){
597                         ERROR("plane (%d) properties not found\n",  plane->plane_id);
598                 }
600                 type_val = get_drm_prop_val(fd, props, "type");
602                 if(type_val == DRM_PLANE_TYPE_OVERLAY){
603                         ptr_plane_id[idx++] = plane_id;
604                 }
606                 drmModeFreeObjectProperties(props);
607                 drmModeFreePlane(plane);
609                 if(idx == num_planes){
610                         drmModeFreePlaneResources(res);
611                         return 0;
612                 }
613         }
615         ERROR("plane couldn't be reserved\n");
616         return -1;
620 /* Get crtc id and resolution. */
621 void drm_crtc_resolution(struct drm_device_info *device)
623         drmModeCrtc *crtc;
624         int i;
626         drmModeResPtr res = drmModeGetResources(device->fd);
628         if (res == NULL){
629                 ERROR("drmModeGetResources failed: %s\n", strerror(errno));
630                 exit(0);
631         };
633         for (i = 0; i < res->count_crtcs; i++) {
634                 unsigned int crtc_id = res->crtcs[i];
636                 crtc = drmModeGetCrtc(device->fd, crtc_id);
637                 if (!crtc) {
638                         DBG("could not get crtc %i: %s\n", res->crtcs[i], strerror(errno));
639                         continue;
640                 }
641                 if (!crtc->mode_valid) {
642                         drmModeFreeCrtc(crtc);
643                         continue;
644                 }
646                 printf("CRTCs size: %dx%d\n", crtc->width, crtc->height);
647                 device->crtc_id = crtc_id;
648                 device->width = crtc->width;
649                 device->height = crtc->height;
651                 drmModeFreeCrtc(crtc);
652         }
654         drmModeFreeResources(res);
657 /*
658 * DRM restore properties
659 */
660 static void drm_restore_props(struct drm_device_info *device)
662         unsigned int i;
663         drmModeObjectProperties *props;
664         int ret;
666         drmModeAtomicReqPtr req = drmModeAtomicAlloc();
668         props = drmModeObjectGetProperties(device->fd, device->crtc_id,
669                 DRM_MODE_OBJECT_CRTC);
671         //restore trans-key-mode and z-order of promary plane
672         add_property(device->fd, req, props, device->crtc_id, "trans-key-mode", \
673                 device->trans_key_mode_val);
674         add_property(device->fd, req, props, device->crtc_id, "zorder", \
675                 device->zorder_val_primary_plane);
677         //restore z-order of overlay planes
678         for(i = 0; i < status.num_cams; i++){
679                 props = drmModeObjectGetProperties(device->fd, device->plane_id[i],
680                         DRM_MODE_OBJECT_PLANE);
682                 if(props == NULL){
683                         ERROR("drm obeject properties for plane type is NULL\n");
684                         exit (-1);
685                 }
687                 add_property(device->fd, req, props, device->plane_id[i], \
688                         "zorder", device->zorder_val[i]);
689         }
691         //Commit all the added properties
692         ret = drmModeAtomicCommit(device->fd, req, DRM_MODE_ATOMIC_TEST_ONLY, 0);
693         if(!ret){
694                 drmModeAtomicCommit(device->fd, req, 0, 0);
695         }
696         else{
697                 ERROR("ret from drmModeAtomicCommit = %d\n", ret);
698         }
700         drmModeAtomicFree(req);
703 /*
704 * drm device init
705 */
706 static int drm_init_device(struct drm_device_info *device)
708         device->fd = status.drm_fd;
710         device->dev = omap_device_new(device->fd);
712         /* Get CRTC id and resolution. As well set the global display width and height */
713         drm_crtc_resolution(device);
715         /* Store display resolution so GUI can be configured */
716         status.display_xres = device->width;
717         status.display_yres = device->height;
719         drm_reserve_plane(device->fd, device->plane_id, status.num_cams);
721         return 0;
724 /*
725 *Clean resources while exiting drm device
726 */
727 static void drm_exit_device(struct drm_device_info *device)
729         drm_restore_props(device);
730         omap_device_del(device->dev);
731         device->dev = NULL;
733         return;
736 /*
737 * Set up the DSS for blending of video and graphics planes
738 */
739 static int drm_init_dss(void)
741         drmModeObjectProperties *props;
742         int ret;
743         FILE *fp;
744         char str[10];
745         char trans_key_mode = 2;
747         /*
748         * Dual camera demo is supported on Am437x and AM57xx evm. Find which
749         * specific SoC the demo is running to set the trans key mode -
750         * found at the corresponding TRM, for example,
751         * For AM437x: trans_key_mode = 1 GFX Dest Trans
752         *             TransKey applies to GFX overlay, marking which
753         *              pixels come from VID overlays)
754         * For AM57xx: trans_key_mode = 2 Source Key.
755         *             Match on Layer4 makes Layer4 transparent (zorder 3)
756         *
757         * The deault mode is 1 for backward compatibility
758         */
760         fp = fopen("/proc/sys/kernel/hostname", "r");
761         fscanf(fp, "%s", str);
763         //terminate the string after the processor name. "-evm" extension is
764         //ignored in case the demo gets supported on other boards like idk etc
765         str[6] = '\0';
766         printf("Running the demo on %s processor\n", str);
768         //Set trans-key-mode to 1 if dual camera demo is running on AM437x
769         if (strcmp(str,"am437x") == 0){
770                 trans_key_mode = 1;
771         }
773         drmModeAtomicReqPtr req = drmModeAtomicAlloc();
775         /* Set CRTC properties */
776         props = drmModeObjectGetProperties(drm_device.fd, drm_device.crtc_id,
777                 DRM_MODE_OBJECT_CRTC);
779         drm_device.zorder_val_primary_plane = get_drm_prop_val(drm_device.fd,
780                 props, "zorder");
781         drm_device.trans_key_mode_val = get_drm_prop_val(drm_device.fd, props,
782                 "trans-key-mode");
784         add_property(drm_device.fd, req, props, drm_device.crtc_id,
785                 "trans-key-mode", trans_key_mode);
786         add_property(drm_device.fd, req, props, drm_device.crtc_id,
787                 "alpha_blender", 1);
788         add_property(drm_device.fd, req, props, drm_device.crtc_id,
789                 "zorder", MAX_ZORDER_VAL);
791         /* Set overlay plane properties like zorder, crtc_id, buf_id, src and */
792         /* dst w, h etc                                                       */
793         drm_add_plane_property(&drm_device, req);
795         //Commit all the added properties
796         ret = drmModeAtomicCommit(drm_device.fd, req, DRM_MODE_ATOMIC_TEST_ONLY, 0);
797         if(!ret){
798                 drmModeAtomicCommit(drm_device.fd, req, 0, 0);
799         }
800         else{
801                 ERROR("ret from drmModeAtomicCommit = %d\n", ret);
802                 return -1;
803         }
805         drmModeAtomicFree(req);
806         return 0;
810 /*
811 * drm disable pip layer
812 */
813 void drm_disable_pip(void)
815         int ret;
816         drmModeAtomicReqPtr req = drmModeAtomicAlloc();
818         drmModeAtomicAddProperty(req, drm_device.plane_id[1],
819                 drm_device.prop_fbid, 0);
820         drmModeAtomicAddProperty(req, drm_device.plane_id[1],
821                 drm_device.prop_crtcid, 0);
823         ret = drmModeAtomicCommit(drm_device.fd, req,
824                 DRM_MODE_ATOMIC_TEST_ONLY, 0);
825         if(!ret){
826                 drmModeAtomicCommit(drm_device.fd, req,
827                         0, 0);
828         }
829         else{
830                 ERROR("failed to enable plane %d atomically: %s",
831                         drm_device.plane_id[!status.main_cam], strerror(errno));
832         }
834         drmModeAtomicFree(req);
837 void drm_enable_pip(void)
839         int ret;
841         drmModeAtomicReqPtr req = drmModeAtomicAlloc();
843         drmModeAtomicAddProperty(req, drm_device.plane_id[1],
844                 drm_device.prop_fbid, drm_device.buf[!status.main_cam][0]->fb_id);
845         drmModeAtomicAddProperty(req, drm_device.plane_id[1],
846                 drm_device.prop_crtcid, drm_device.crtc_id);
848         ret = drmModeAtomicCommit(drm_device.fd, req,
849                 DRM_MODE_ATOMIC_TEST_ONLY, 0);
851         if(!ret){
852                 drmModeAtomicCommit(drm_device.fd, req, 0, 0);
853         }
854         else{
855                 ERROR("failed to enable plane %d atomically: %s",
856                         drm_device.plane_id[!status.main_cam], strerror(errno));
857         }
859         drmModeAtomicFree(req);
863 static int capture_frame(struct v4l2_device_info *v4l2_device,
864 struct dmabuf_buffer *buf)
867         return 0;
870 /*
871 * Initialize the app resources with default parameters
872 */
873 void default_parameters(void)
875         /* Main camera display */
876         memset(&drm_device, 0, sizeof(drm_device));
877         strcpy(drm_device.dev_name,"/dev/drm");
878         strcpy(drm_device.name,"drm");
879         drm_device.width=0;
880         drm_device.height=0;
881         drm_device.bo_flags = OMAP_BO_SCANOUT;
882         drm_device.fd = 0;
884         /* Main camera */
885         cap0_device.memory_mode = V4L2_MEMORY_DMABUF;
886         cap0_device.num_buffers = NBUF;
887         strcpy(cap0_device.dev_name,"/dev/video1");
888         strcpy(cap0_device.name,"Capture 0");
889         cap0_device.buffers = NULL;
890         cap0_device.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
891         cap0_device.width = CAP_WIDTH;
892         cap0_device.height = CAP_HEIGHT;
894         /* PiP camera */
895         cap1_device.memory_mode = V4L2_MEMORY_DMABUF;
896         cap1_device.num_buffers = NBUF;
897         strcpy(cap1_device.dev_name,"/dev/video0");
898         strcpy(cap1_device.name,"Capture 1");
899         cap1_device.buffers = NULL;
900         cap1_device.fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
901         cap1_device.width = CAP_WIDTH;
902         cap1_device.height = CAP_HEIGHT;
904         /* Set the default parameters for device options */
905         status.main_cam=0;
906         status.num_cams=2;
907         if(status.num_cams == 1){
908                 status.pip=false;
909         }
910         else{
911                 status.pip=true;
912         }
913         status.exit=false;
915         return;
918 /*
919 * Free resource and exit devices
920 */
921 void exit_devices(void)
923         v4l2_exit_device(&cap0_device);
924         if (status.num_cams==2) {
925                 v4l2_exit_device(&cap1_device);
926         }
927         free_vid_buffers(drm_device.buf[0], NBUF);
928         free_vid_buffers(drm_device.buf[1], NBUF);
929         drm_exit_device(&drm_device);
932 /*
933 * End camera streaming
934 */
935 void end_streaming(void)
937         v4l2_stream_off(&cap0_device);
938         if (status.num_cams==2) {
939                 v4l2_stream_off(&cap1_device);
940         }
943 void set_plane_properties()
945         int ret;
946         drmModeAtomicReqPtr req = drmModeAtomicAlloc();
948         drmModeAtomicAddProperty(req, drm_device.plane_id[0],
949                 drm_device.prop_fbid, drm_device.buf[status.main_cam][0]->fb_id);
951         if(status.pip){
952                 drmModeAtomicAddProperty(req, drm_device.plane_id[1],
953                         drm_device.prop_fbid, drm_device.buf[!status.main_cam][0]->fb_id);
954         }
955         ret = drmModeAtomicCommit(drm_device.fd, req,
956                 DRM_MODE_ATOMIC_TEST_ONLY, 0);
957         if(!ret){
958                 drmModeAtomicCommit(drm_device.fd, req,
959                         0, 0);
960         }
961         else{
962                 ERROR("failed to enable plane %d atomically: %s",
963                         drm_device.plane_id[!status.main_cam], strerror(errno));
964         }
965         drmModeAtomicFree(req);
967 /*
968 * Initializes all drm and v4l2 devices for loopback
969 */
970 int init_loopback(void)
972         bool status_cam0 = 0;
973         bool status_cam1 = 0;
975         /* Declare properties for video and capture devices */
976         default_parameters();
978         /* Initialize the drm display devic */
979         if (drm_init_device(&drm_device)) goto Error;
981         /* Check to see if the display resolution is very small.  If so, the
982         * camera capture resolution needs to be lowered so that the scaling
983         * limits of the DSS are not reached */
984         if (drm_device.width < 640) {
985                 /* Set capture 0 device resolution */
986                 cap0_device.width = 640;
987                 cap0_device.height = 480;
989                 /* Set capture 1 device resolution */
990                 cap1_device.width = 640;
991                 cap1_device.height = 480;
992         }
994         /* Initialize the v4l2 capture devices */
995         if (v4l2_init_device(&cap0_device) < 0) {
996                 printf("first camera detection failed\n");
997                 /* If there is not a second camera, program can still continue */
998                 status.num_cams=1;
999                 status.main_cam=1;
1000                 status.pip=false;
1001         }
1002         else{
1003                 unsigned int i;
1004                 struct dmabuf_buffer **buffers = get_vid_buffers(&drm_device, cap0_device.num_buffers, 
1005                         cap0_device.fmt.fmt.pix.pixelformat, cap0_device.width, cap0_device.height);
1007                 if (!buffers) {
1008                         goto Error;
1009                 }
1011                 drm_device.buf[0] = buffers;
1013                 /* Pass these buffers to the capture drivers */
1014                 if (v4l2_request_buffer(&cap0_device, buffers) < 0) {
1015                         goto Error;
1016                 }
1018                 for (i = 0; i < cap0_device.num_buffers; i++) {
1019                         v4l2_queue_buffer(&cap0_device, buffers[i]);
1020                 }
1022                 status_cam0 = 1;
1023         }
1025         if(v4l2_init_device(&cap1_device) < 0) {
1026                 /* If there is not a second camera, program can still continue */
1027                 if(status.num_cams ==2){
1028                         status.num_cams=1;
1029                         status.pip=false;
1030                         printf("Only one camera detected\n");
1031                 }
1032                 //first camera wasn't detected
1033                 else if (!status_cam0){
1034                         printf("No camera detected\n");
1035                         goto Error;
1036                 }
1037         }
1038         else{
1039                 unsigned int i;
1040                 struct dmabuf_buffer **buffers = get_vid_buffers(&drm_device, cap1_device.num_buffers, 
1041                         cap1_device.fmt.fmt.pix.pixelformat, cap1_device.width, cap1_device.height);
1042                 if (!buffers) {
1043                         goto Error;
1044                 }
1046                 drm_device.buf[1] = buffers;
1048                 /* Pass these buffers to the capture drivers */
1049                 if (v4l2_request_buffer(&cap1_device, buffers) < 0) {
1050                         goto Error;
1051                 }
1053                 for (i = 0; i < cap1_device.num_buffers; i++) {
1054                         v4l2_queue_buffer(&cap1_device, buffers[i]);
1055                 }
1057                 status_cam1 = 1;
1058         }
1060         /* Enable streaming for the v4l2 capture devices */
1061         if(status_cam0){
1062                 if (v4l2_stream_on(&cap0_device) < 0) goto Error;
1063         }
1065         if (status_cam1) {
1066                 if (v4l2_stream_on(&cap1_device) < 0) goto Error;
1067         }
1069         /* Configure the DSS to blend video and graphics layers */
1070         if (drm_init_dss() < 0 ) goto Error;
1072         return 0;
1074 Error:
1075         status.exit = true;
1076         return -1;
1079 static void page_flip_handler(int fd, unsigned int frame,
1080                                                           unsigned int sec, unsigned int usec,
1081                                                           void *data)
1083         int *flip_status = data;
1084         *flip_status = 0;
1087 static void page_flip_handler_null(int fd, unsigned int frame,
1088                                                                unsigned int sec, unsigned int usec,
1089                                                                void *data)
1094 void process_frame(void)
1096         int ret;
1097         struct dmabuf_buffer *buf[2] = {NULL, NULL};
1098         struct v4l2_device_info *v4l2_device[2] =
1099         {&cap0_device, &cap1_device};
1101         /* Request a capture buffer from the driver that can be copied to */
1102         /* framebuffer */
1103         buf[status.main_cam] =
1104                 v4l2_dequeue_buffer(v4l2_device[status.main_cam]);
1106         waiting_for_flip = 1;
1108         status.drm_plane_sreq_handler(drm_device.plane_id[0],
1109                 drm_device.prop_fbid,
1110                 buf[status.main_cam]->fb_id,
1111                 (status.pip==true)?page_flip_handler_null:
1112                 page_flip_handler,
1113                 (void *)&waiting_for_flip);
1116         if (status.pip==true) {
1117                 buf[!status.main_cam] =
1118                         v4l2_dequeue_buffer(v4l2_device[!status.main_cam]);
1120                 status.drm_plane_sreq_handler(drm_device.plane_id[1],
1121                         drm_device.prop_fbid,
1122                         buf[!status.main_cam]->fb_id,
1123                         page_flip_handler,
1124                         (void *)&waiting_for_flip);
1125         }
1128         while (waiting_for_flip) {
1129                 usleep(1000);
1130         }
1132         v4l2_queue_buffer(v4l2_device[status.main_cam], buf[status.main_cam]);
1133         if(status.pip == true){
1134                 v4l2_queue_buffer(v4l2_device[!status.main_cam], buf[!status.main_cam]);
1135         }