Add DRM compile flags
[jacinto7_multimedia/viddec-test-app.git] / main.c
1 /*
2  * Texas Instruments IMG video driver test application.
3  *
4  * Copyright (c) 2018 Texas Instruments Incorporated - http://www.ti.com/
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation version 2.
9  *
10  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11  * kind, whether express or implied; without even the implied warranty
12  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <assert.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <malloc.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/mman.h>
29 #include <sys/ioctl.h>
30 #include <signal.h>
31 #include <poll.h>
32 #include <dirent.h>
34 #include <asm/types.h>
35 #include <linux/videodev2.h>
36 #include <linux/v4l2-controls.h>
38 #ifdef DRMMODE
39 #include <xf86drmMode.h>
40 #else
41 #ifdef DRM
42 #include <drm.h>
43 #endif /* DRM */
44 #endif /* DRMMODE */
46 #include "demux.h"
48 /* HEVC aka H.265 */
49 #define V4L2_PIX_FMT_HEVC     v4l2_fourcc('H', 'E', 'V', 'C')
50 /* TI NV12 10-bit, two bytes per channel */
51 #define V4L2_PIX_FMT_TI1210   v4l2_fourcc('T', 'I', '1', '2')
52 /* TI YUV422 10-bit, two bytes per channel */
53 #define V4L2_PIX_FMT_TI1610   v4l2_fourcc('T', 'I', '1', '6')
55 static const struct AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
56                 [AV_PIX_FMT_YUV420P] = {
57                                 .name = "yuv420p",
58                 },
59                 [AV_PIX_FMT_YUYV422] = {
60                                 .name = "yuyv422",
61                 },
62                 [AV_PIX_FMT_YVYU422] = {
63                                 .name = "yvyu422",
64                 },
65                 [AV_PIX_FMT_YUV422P] = {
66                                 .name = "yuv422p",
67                 },
68                 [AV_PIX_FMT_YUV444P] = {
69                                 .name = "yuv444p",
70                 },
71                 [AV_PIX_FMT_YUV410P] = {
72                                 .name = "yuv410p",
73                 },
74                 [AV_PIX_FMT_YUV411P] = {
75                                 .name = "yuv411p",
76                 },
77                 [AV_PIX_FMT_YUVJ411P] = {
78                                 .name = "yuvj411p",
79                 },
80                 [AV_PIX_FMT_YUVJ420P] = {
81                                 .name = "yuvj420p",
82                 },
83                 [AV_PIX_FMT_YUVJ422P] = {
84                                 .name = "yuvj422p",
85                 },
86                 [AV_PIX_FMT_YUVJ444P] = {
87                                 .name = "yuvj444p",
88                 },
89                 [AV_PIX_FMT_XVMC] = {
90                                 .name = "xvmc",
91                                 .flags = AV_PIX_FMT_FLAG_HWACCEL,
92                 },
93                 [AV_PIX_FMT_UYVY422] = {
94                                 .name = "uyvy422",
95                 },
96                 [AV_PIX_FMT_UYYVYY411] = {
97                                 .name = "uyyvyy411",
98                 },
99                 [AV_PIX_FMT_NV12] = {
100                                 .name = "nv12",
101                 },
102                 [AV_PIX_FMT_NV21] = {
103                                 .name = "nv21",
104                 },
105                 [AV_PIX_FMT_YUV440P] = {
106                                 .name = "yuv440p",
107                 },
108                 [AV_PIX_FMT_YUVJ440P] = {
109                                 .name = "yuvj440p",
110                 },
111                 [AV_PIX_FMT_YUV440P10LE] = {
112                                 .name = "yuv440p10le",
113                 },
114                 [AV_PIX_FMT_YUV440P10BE] = {
115                                 .name = "yuv440p10be",
116                 },
117                 [AV_PIX_FMT_YUV440P12LE] = {
118                                 .name = "yuv440p12le",
119                 },
120                 [AV_PIX_FMT_YUV440P12BE] = {
121                                 .name = "yuv440p12be",
122                 },
123                 [AV_PIX_FMT_YUVA420P] = {
124                                 .name = "yuva420p",
125                 },
126                 [AV_PIX_FMT_YUVA422P] = {
127                                 .name = "yuva422p",
128                 },
129                 [AV_PIX_FMT_YUVA444P] = {
130                                 .name = "yuva444p",
131                 },
132                 [AV_PIX_FMT_YUVA420P9BE] = {
133                                 .name = "yuva420p9be",
134                 },
135                 [AV_PIX_FMT_YUVA420P9LE] = {
136                                 .name = "yuva420p9le",
137                 },
138                 [AV_PIX_FMT_YUVA422P9BE] = {
139                                 .name = "yuva422p9be",
140                 },
141                 [AV_PIX_FMT_YUVA422P9LE] = {
142                                 .name = "yuva422p9le",
143                 },
144                 [AV_PIX_FMT_YUVA444P9BE] = {
145                                 .name = "yuva444p9be",
146                 },
147                 [AV_PIX_FMT_YUVA444P9LE] = {
148                                 .name = "yuva444p9le",
149                 },
150                 [AV_PIX_FMT_YUVA420P10BE] = {
151                                 .name = "yuva420p10be",
152                 },
153                 [AV_PIX_FMT_YUVA420P10LE] = {
154                                 .name = "yuva420p10le",
155                 },
156                 [AV_PIX_FMT_YUVA422P10BE] = {
157                                 .name = "yuva422p10be",
158                 },
159                 [AV_PIX_FMT_YUVA422P10LE] = {
160                                 .name = "yuva422p10le",
161                 },
162                 [AV_PIX_FMT_YUVA444P10BE] = {
163                                 .name = "yuva444p10be",
164                 },
165                 [AV_PIX_FMT_YUVA444P10LE] = {
166                                 .name = "yuva444p10le",
167                 },
168                 [AV_PIX_FMT_YUVA420P16BE] = {
169                                 .name = "yuva420p16be",
170                 },
171                 [AV_PIX_FMT_YUVA420P16LE] = {
172                                 .name = "yuva420p16le",
173                 },
174                 [AV_PIX_FMT_YUVA422P16BE] = {
175                                 .name = "yuva422p16be",
176                 },
177                 [AV_PIX_FMT_YUVA422P16LE] = {
178                                 .name = "yuva422p16le",
179                 },
180                 [AV_PIX_FMT_YUVA444P16BE] = {
181                                 .name = "yuva444p16be",
182                 },
183                 [AV_PIX_FMT_YUVA444P16LE] = {
184                                 .name = "yuva444p16le",
185                 },
186                 [AV_PIX_FMT_YUV420P9LE] = {
187                                 .name = "yuv420p9le",
188                 },
189                 [AV_PIX_FMT_YUV420P9BE] = {
190                                 .name = "yuv420p9be",
191                 },
192                 [AV_PIX_FMT_YUV420P10LE] = {
193                                 .name = "yuv420p10le",
194                 },
195                 [AV_PIX_FMT_YUV420P10BE] = {
196                                 .name = "yuv420p10be",
197                 },
198                 [AV_PIX_FMT_YUV420P12LE] = {
199                                 .name = "yuv420p12le",
200                 },
201                 [AV_PIX_FMT_YUV420P12BE] = {
202                                 .name = "yuv420p12be",
203                 },
204                 [AV_PIX_FMT_YUV420P14LE] = {
205                                 .name = "yuv420p14le",
206                 },
207                 [AV_PIX_FMT_YUV420P14BE] = {
208                                 .name = "yuv420p14be",
209                 },
210                 [AV_PIX_FMT_YUV420P16LE] = {
211                                 .name = "yuv420p16le",
212                 },
213                 [AV_PIX_FMT_YUV420P16BE] = {
214                                 .name = "yuv420p16be",
215                 },
216                 [AV_PIX_FMT_YUV422P9LE] = {
217                                 .name = "yuv422p9le",
218                 },
219                 [AV_PIX_FMT_YUV422P9BE] = {
220                                 .name = "yuv422p9be",
221                 },
222                 [AV_PIX_FMT_YUV422P10LE] = {
223                                 .name = "yuv422p10le",
224                 },
225                 [AV_PIX_FMT_YUV422P10BE] = {
226                                 .name = "yuv422p10be",
227                 },
228                 [AV_PIX_FMT_YUV422P12LE] = {
229                                 .name = "yuv422p12le",
230                 },
231                 [AV_PIX_FMT_YUV422P12BE] = {
232                                 .name = "yuv422p12be",
233                 },
234                 [AV_PIX_FMT_YUV422P14LE] = {
235                                 .name = "yuv422p14le",
236                 },
237                 [AV_PIX_FMT_YUV422P14BE] = {
238                                 .name = "yuv422p14be",
239                 },
240                 [AV_PIX_FMT_YUV422P16LE] = {
241                                 .name = "yuv422p16le",
242                 },
243                 [AV_PIX_FMT_YUV422P16BE] = {
244                                 .name = "yuv422p16be",
245                 },
246                 [AV_PIX_FMT_YUV444P16LE] = {
247                                 .name = "yuv444p16le",
248                 },
249                 [AV_PIX_FMT_YUV444P16BE] = {
250                                 .name = "yuv444p16be",
251                 },
252                 [AV_PIX_FMT_YUV444P10LE] = {
253                                 .name = "yuv444p10le",
254                 },
255                 [AV_PIX_FMT_YUV444P10BE] = {
256                                 .name = "yuv444p10be",
257                 },
258                 [AV_PIX_FMT_YUV444P9LE] = {
259                                 .name = "yuv444p9le",
260                 },
261                 [AV_PIX_FMT_YUV444P9BE] = {
262                                 .name = "yuv444p9be",
263                 },
264                 [AV_PIX_FMT_YUV444P12LE] = {
265                                 .name = "yuv444p12le",
266                 },
267                 [AV_PIX_FMT_YUV444P12BE] = {
268                                 .name = "yuv444p12be",
269                 },
270                 [AV_PIX_FMT_YUV444P14LE] = {
271                                 .name = "yuv444p14le",
272                 },
273                 [AV_PIX_FMT_YUV444P14BE] = {
274                                 .name = "yuv444p14be",
275                 },
276                 [AV_PIX_FMT_P010LE] = {
277                                 .name = "p010le",
278                 },
279                 [AV_PIX_FMT_P010BE] = {
280                                 .name = "p010be",
281                 },
282                 [AV_PIX_FMT_P016LE] = {
283                                 .name = "p016le",
284                 },
285                 [AV_PIX_FMT_P016BE] = {
286                                 .name = "p016be",
287                 }
288 };
290 #define memzero(x)      memset(&(x), 0, sizeof (x))
291 #define MAX_TEST_FDS    10
292 #define MAX_FRAMES      1000
293 #define ALIGN(x,a)      (((x) + (a) - 1L) & ~((a) - 1L))
294 #define HW_ALIGN        64
296 #define MAX_OUTBUFS 2
298 #define DISPLAY_LAG 3
300 #define MAX_CAPBUFS_H264 16
301 #define MAX_CAPBUFS (MAX_CAPBUFS_H264 + DISPLAY_LAG)
303 #define MIN(a, b) ((a < b) ? a : b)
305 #define DEVICE_NAME "cardx"
307 //#define DEBUG
308 #ifdef DEBUG
309 #define debug_printf(fmt, arg...) printf(fmt, ##arg);
310 #else
311 #define debug_printf(fmt, arg...)
312 #endif
314 /* Enable the below option for converting YUV422 decoded output to NV12 format*/
315 #define CC_YUV422PLANAR_TO_NV12
317 #define PROFILE
318 #ifdef PROFILE
319 #define perf_printf(fmt, arg...) printf(fmt, ##arg);
320 #else
321         perf_printf(fmt, arg...)
322 #endif
324 static int drmfd1 = -1;
325 #define FMT_NUM_PLANES 1 /* Used when creating V4l2 buffers for capture buffers */
326 #define FMT_NUM_MJPEG_PLANES 3 /* Used when creating V4l2 buffers for capture buffers */
328 /*
329  * @bo_handle: drm buffer handle
330  * @dbuf_fd: dma buffer handle
331  * @mapped: Pointer to mmap'ed buffer memory
332  * @offset: offset of buffer
333  * @length: Buffer length for munmap
334  */
335 struct buffer {
336         unsigned int bo_handle;
337         int dbuf_fd;
338         void *mapped;
339         int offset;
340         int length;
341 };
343 struct stream_context
345         size_t frame_sizes[MAX_FRAMES];
346         int width;
347         int height;
348         int bitdepth;
349         int num_bytes_per_pix;
350         enum AVPixelFormat pix_fmt;
351         enum AVCodecID codec;
352 };
354 /*
355  *
356  * @fourcc: The V4L2 fourcc value
357  * @size_num: The numerator to multiply image size by
358  * @size_den: The denominator to divide image size by
359  */
360 struct output_format
362         uint32_t fourcc;
363         int size_num;
364         int size_den;
365 };
367 static void errno_exit(const char *s)
369         printf("%s error %d, %s\n", s, errno, strerror(errno));
370         exit(EXIT_FAILURE);
373 static int handle_outbuf(int fd, int index, int rdfd, struct buffer buff,
374         struct stream_context *str, int nframes, int sleep_time)
376         struct v4l2_buffer buf;
377         struct v4l2_plane buf_planes[1];
378         struct v4l2_decoder_cmd cmd = {};
379         int ret = 0;
380         int send_cmd = 0;
381         static int fs_ind = 0;
383         memset(buff.mapped, 0, (str->width * str->height));
384         read(rdfd, buff.mapped, str->frame_sizes[fs_ind]);
386         memzero(buf);
387         memzero(buf_planes[0]);
389         buf_planes[0].bytesused = str->frame_sizes[fs_ind];
390         buf_planes[0].m.mem_offset = buff.offset;
391         buf_planes[0].data_offset = 0;
393         fs_ind++;
395         /* Stop queueing OUTPUT buffers if no more content */
396         if (fs_ind > nframes)
397                 return ret;
399         if (fs_ind == nframes) {
400                 debug_printf("[fd%d] handle_outbuf sending DEC_CMD_STOP\n", fd);
401                 cmd.cmd = V4L2_DEC_CMD_STOP;
402                 ret = ioctl(fd, VIDIOC_TRY_DECODER_CMD, &cmd);
403                 if (ret < 0) {
404                         printf("[fd%d] handle_outbuf TRY_DECODER_CMD failed trying FLAG_LAST ret=%d err=%s\n",
405                                         fd, ret, strerror(errno));
406                         buf.flags |= V4L2_BUF_FLAG_LAST;
407                 } else {
408                         send_cmd = 1;
409                 }
410         }
412         buf.index = index;
413         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
414         buf.memory = V4L2_MEMORY_MMAP;
415         buf.m.planes = buf_planes;
416         buf.length = 1;
418         ret = ioctl(fd, VIDIOC_QBUF, &buf);
419         if (ret < 0)
420                 printf("[fd%d] handle_outbuf QBUF failed ret=%d err=%s\n",
421                                 fd, ret, strerror(errno));
422         else
423                 debug_printf("[fd%d] handle_outbuf QBUF success\n", fd);
425         if (send_cmd) {
426                 debug_printf("[fd%d] handle_outbuf sending DEC_CMD_STOP after %d ms delay\n", fd, sleep_time / 1000);
427                 usleep(sleep_time);
428                 cmd.cmd = V4L2_DEC_CMD_STOP;
429                 ret = ioctl(fd, VIDIOC_DECODER_CMD, &cmd);
430                 if (ret < 0)
431                         printf("[fd%d] handle_outbuf DECODER_CMD failed ret=%d err=%s\n",
432                                         fd, ret, strerror(errno));
433         }
435         return ret;
438 static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff[],
439                 int save, struct stream_context *str, struct output_format fmt, int usedrmbuff)
441         struct v4l2_buffer buf;
442         struct v4l2_plane buf_planes[3];
443         int ret = 0;
444         int i;
445         int h = ALIGN(str->height, HW_ALIGN);
446         int s = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
448         if(save && (wrfd >= 0))
449         {
450                 switch (fmt.fourcc) {
451                         case (V4L2_PIX_FMT_NV12):
452                         case (V4L2_PIX_FMT_TI1210):
453                                 /*
454                                 for(i=0; i<str->height; i++)
455                                         write(wrfd, buff.mapped + (i * s),
456                                                         str->width);
458                                 for(i=0; i<(str->height/2); i++)
459                                         write(wrfd, buff.mapped + (h * s) +
460                                                         (i * s), str->width);
461                                 */
462                                 for(i=0; i<str->height; i++)
463                                         write(wrfd, buff[index].mapped + (i * s),
464                                                         (str->width *
465                                                          str->num_bytes_per_pix));
467                                 for(i=0; i<(str->height/2); i++)
468                                         write(wrfd, buff[index].mapped + (h * s) +
469                                                         (i * s),
470                                                         (str->width *
471                                                          str->num_bytes_per_pix));
472                                 break;
473                         case (V4L2_PIX_FMT_NV16):
474                         case (V4L2_PIX_FMT_TI1610):
475 #ifdef CC_YUV422PLANAR_TO_NV12
476                                 for (i = 0; i < str->height; i++)
477                                         write(wrfd, buff[index].mapped + (i * s),
478                                                 str->width * str->num_bytes_per_pix);
479                                 for (i = 0; i < str->height; i+=2)
480                                         write(wrfd, buff[index].mapped + (h * s) + (i * s), str->width * str->num_bytes_per_pix);
482 #else
483                                 for (i = 0; i < str->height; i++)
484                                         write(wrfd, buff[index].mapped + (i * s),
485                                                         2* str->width * str->num_bytes_per_pix);
486 #endif
487                                 break;
488                         case V4L2_PIX_FMT_YUV420M:
490                                 for(i=0; i<str->height; i++)
491                                         write(wrfd, buff[(index*3)].mapped + (i * s),
492                                                 (str->width *
493                                                  str->num_bytes_per_pix));
496                                 for(i=0; i<(str->height/2); i++)
497                                         write(wrfd, buff[(index*3)+1].mapped + (i * s),
498                                                 (str->width *
499                                                 str->num_bytes_per_pix) / 2);
501                                 for(i=0; i<(str->height/2); i++)
502                                         write(wrfd, buff[(index*3)+2].mapped + (i * s),
503                                                 (str->width *
504                                                 str->num_bytes_per_pix) / 2);
505                                 break;
506                         case V4L2_PIX_FMT_YUV422M:
507                                 for(i=0; i<str->height; i++)
508                                         write(wrfd, buff[(index*3)].mapped + (i * s),
509                                                 (str->width *
510                                                  str->num_bytes_per_pix));
512                                 for(i=0; i<(str->height); i++)
513                                         write(wrfd, buff[(index*3)+1].mapped + (i * s),
514                                                 (str->width *
515                                                 str->num_bytes_per_pix) / 2);
517                                 for(i=0; i<(str->height); i++)
518                                         write(wrfd, buff[(index*3)+2].mapped + (i * s),
519                                                 (str->width *
520                                                 str->num_bytes_per_pix) / 2);
521                                 break;
522                         default:
523                                 break;
524                 }
525         }
527         memzero(buf);
528         memzero(buf_planes[0]);
530         if(str->codec == AV_CODEC_ID_MJPEG) {
531                 memzero(buf_planes[1]);
532                 memzero(buf_planes[2]);
533         }
535         if(str->codec == AV_CODEC_ID_MJPEG) {
536                 buf_planes[0].m.fd = buff[(index*3)].dbuf_fd;
537                 buf_planes[0].length = buff[(index*3)].length;
539                 buf_planes[1].m.fd = buff[((index*3) + 1)].dbuf_fd;
540                 buf_planes[1].length = buff[((index*3) + 1)].length;
542                 buf_planes[2].m.fd = buff[((index*3) + 2)].dbuf_fd;
543                 buf_planes[2].length = buff[((index*3) + 2)].length;
544         } else {
545                 buf_planes[0].m.fd = buff[index].dbuf_fd;
546                 buf_planes[0].length = buff[index].length;
547         }
549         buf.index = index;
550         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
551         if (usedrmbuff == 0) {
552                 /* Using v4l2 buffers for capture */
553                 buf.memory = V4L2_MEMORY_MMAP;
554         } else {
555                 /* Using drm buffers for capture */
556                 buf.memory = V4L2_MEMORY_DMABUF;
557         }
558         buf.m.planes = buf_planes;
559         if(str->codec == AV_CODEC_ID_MJPEG)
560                 buf.length = 3;
561         else
562                 buf.length = 1;
564         ret = ioctl(fd, VIDIOC_QBUF, &buf);
565         if (ret < 0)
566                 printf("[fd%d] handle_capbuf QBUF failed ret=%d err=%s\n",
567                                 fd, ret, strerror(errno));
568         else
569                 debug_printf("[fd%d] handle_capbuf QBUF success\n", fd);
571         return ret;
574 static int mainloop(int fd, int rdfd, int wrfd,
575                 struct stream_context *str, struct buffer outbufs[],
576                 struct buffer capbufs[], int n_outbufs,
577                 int n_capbufs, int nframes, int enable_prof,
578                 struct output_format fmt, int sleep_time, int usedrmbuff)
580         int type, i, ret = 0;
581         uint32_t flags = 0;
582         struct v4l2_buffer buf;
583         struct v4l2_plane buf_planes[3];
584         struct pollfd pfd;
585         struct timeval times;
586         long curr_time = 0;
587         static long prev_time = 0;
588         struct v4l2_event event;
590         debug_printf("[fd%d] MAINLOOP\n", fd);
592         pfd.fd = fd;
593         pfd.events = POLLIN | POLLOUT | POLLPRI;
594         pfd.revents = 0;
596         for (i = 0; i < n_outbufs; i++)
597                 handle_outbuf(fd, i, rdfd, outbufs[i], str, nframes, 0);
599         if(str->codec == AV_CODEC_ID_MJPEG) {
600                 for (i = 0; i < (n_capbufs / 3); i++)
601                         handle_capbuf(fd, wrfd, i, capbufs, 0, str, fmt, usedrmbuff);
602         } else {
603                 for (i = 0; i < n_capbufs; i++)
604                         handle_capbuf(fd, wrfd, i, capbufs, 0, str, fmt, usedrmbuff);
605         }
606         type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
607         ret = ioctl(fd, VIDIOC_STREAMON, &type);
608         if (ret) {
609                 printf("[fd%d] OUTPUT VIDIOC_STREAMON failed with ret %d\n",
610                         fd, ret);
611                 return ret;
612         }
614         type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
615         ret = ioctl(fd, VIDIOC_STREAMON, &type);
616         if (ret)
617                 printf("[fd%d] CAPTURE VIDIOC_STREAMON failed with ret %d\n",
618                         fd, ret);
620         i = 0;
621         while (!(flags & V4L2_BUF_FLAG_LAST)) {
622                 pfd.revents = 0;
624                 /* Poll for any event for 100ms */
625                 ret = poll(&pfd, 1, 100);
626                 if (ret < 0) {
627                         printf("poll had an error %d: %s\n",
628                                 errno, strerror(errno));
629                 } else if (ret > 0) {
630                         if (pfd.revents & POLLOUT) {
631                                 while (1) {
632                                         /* Check for OUTPUT buffer */
633                                         memzero(buf);
634                                         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
635                                         buf.memory = V4L2_MEMORY_MMAP;
636                                         buf.m.planes = buf_planes;
637                                         buf.length = 1;
638                                         ret = ioctl(fd, VIDIOC_DQBUF, &buf);
639                                         if (ret < 0) {
640                                                 if (errno != EAGAIN) {
641                                                         printf("[fd%d] OUTPUT VIDIOC_DQBUF failed: ret=%d errno=%d: %s\n",
642                                                                 fd, ret, errno,
643                                                                 strerror(errno));
644                                                 } else {
645                                                         debug_printf("[fd%d] OUTPUT EAGAIN\n", fd);
646                                                         break;
647                                                 }
648                                         } else {
650                                                 handle_outbuf(fd, buf.index, rdfd,
651                                                                 outbufs[buf.index],
652                                                                 str, nframes,
653                                                                 sleep_time);
654                                         }
655                                 }
656                         }
657                         if (pfd.revents & POLLIN) {
658                                 while (1) {
659                                         /* Check for CAPTURE buffer */
660                                         memzero(buf);
661                                         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
662                                         if (usedrmbuff == 0) {
663                                                 /* Using v4l2 bufffers for capture */
664                                                 buf.memory = V4L2_MEMORY_MMAP;
665                                         } else {
666                                                 /* Using drm buffers for capture */
667                                                 buf.memory = V4L2_MEMORY_DMABUF;
668                                         }
669                                         buf.m.planes = buf_planes;
670                                         if(str->codec == AV_CODEC_ID_MJPEG)
671                                                 buf.length = 3;
672                                         else
673                                                 buf.length = 2;
674                                         ret = ioctl(fd, VIDIOC_DQBUF, &buf);
675                                         if (ret < 0) {
676                                                 if (errno != EAGAIN) {
677                                                         printf("[fd%d] CAPTURE VIDIOC_DQBUF failed: ret=%d errno=%d: %s\n",
678                                                                 fd, ret, errno,
679                                                                 strerror(errno));
680                                                 } else {
681                                                         debug_printf("[fd%d] CAPTURE EAGAIN\n", fd);
682                                                         break;
683                                                 }
684                                         } else {
686                                                 if (enable_prof) {
687                                                         gettimeofday(&times, NULL);
688                                                         curr_time =
689                                                         (times.tv_sec * 1000000 + times.tv_usec);
691                                                         perf_printf("Picture buffer dequeue time is %ld us\n",
692                                                                         (curr_time - prev_time));
694                                                         prev_time = curr_time;
695                                                 }
696                                                 debug_printf("[fd%d] CAPTURE VIDIOC_DQBUF bytesused=%d\n",
697                                                                 fd, buf.m.planes[0].bytesused);
698                                                 if (buf.m.planes[0].bytesused)
699                                                         handle_capbuf(fd, wrfd,
700                                                                       buf.index,
701                                                                       capbufs,
702                                                                       1, str,
703                                                                       fmt, usedrmbuff);
704                                                 flags = buf.flags;
705                                                 debug_printf("[fd%d] CAPTURE VIDIOC_DQBUF buffer %d flags=%08x FLAG_LAST=%08x\n",
706                                                                 fd, buf.index,
707                                                                 flags,
708                                                                 V4L2_BUF_FLAG_LAST);
709                                                 if (buf.flags & V4L2_BUF_FLAG_LAST)
710                                                         break;
711                                         }
712                                 }
713                         }
714                         if (pfd.revents & POLLPRI) {
715                                 /* Check for events */
716                                 memzero(event);
717                                 ret = ioctl(fd, VIDIOC_DQEVENT, &event);
718                                 if (ret < 0) {
719                                         printf("[fd%d] VIDIOC_DQEVENT failed:: ret=%d errno=%d: %s\n",
720                                                         fd, ret, errno,
721                                                         strerror(errno));
722                                 } else if (event.type == V4L2_EVENT_EOS) {
723                                         debug_printf("[fd%d] GOT EVENT\n", fd);
724                                 } else {
725                                         printf("[fd%d] VIDIOC_DQEVENT got unexpected event %d\n",
726                                                         fd, event.type);
727                                 }
728                         }
729                 }
730         }
732         debug_printf("Stream ended, calling STREAMOFF\n");
733         type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
734         ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
735         if (ret) {
736                 printf("[fd%d] VIDIOC_STREAMOFF on OUTPUT failed with ret %d\n",
737                                 fd, ret);
738                 return ret;
739         }
741         type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
742         ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
743         if (ret)
744                 printf("[fd%d] VIDIOC_STREAMOFF on CAPTURE failed with ret %d\n",
745                                 fd, ret);
747         return ret;
750 static void uninit_device(int fd, struct buffer outbufs[],
751                 struct buffer capbufs[], int *n_outbufs, int *n_capbufs, int usedrmbuff)
753 #ifdef DRM
754         struct drm_mode_destroy_dumb gem_destroy;
755 #endif
756         int i, ret = 0;
757         struct v4l2_event_subscription sub;
759         debug_printf("[fd%d] uninit_device\n", fd);
761         for (i = 0; i < *n_outbufs; i++) {
762                 debug_printf("[fd%d] munmap outbuf %d mapped=0x%p length=%d\n",
763                                 fd, i, outbufs[i].mapped, outbufs[i].length);
764                 ret = munmap(outbufs[i].mapped, outbufs[i].length);
765                 if (ret) {
766                         printf("[fd%d] munmap failed for outbuf %d: %d %s\n",
767                                         fd, i, errno, strerror(errno));
768                 }
769         }
771 /* For unint capbufs, check which was used, drm or v4l2*/
772         if (usedrmbuff == 0) {
773                 /* Using v4l2 bufffers for capture */
774                 for (i = 0; i < *n_capbufs; i++) {
775                         debug_printf("[fd%d] munmap capbuf %d mapped=0x%p length=%d\n", fd, i, capbufs[i].mapped, capbufs[i].length);
776                         ret = munmap(capbufs[i].mapped, capbufs[i].length);
777                         if (ret) {
778                                 printf("[fd%d] munmap failed for capbuf %d: %d %s\n", fd, i, errno, strerror(errno));
779                         }
780                 }
781         } else {
782 #ifdef DRM
783                 /* Using drm bufffers for capture */
784                 for (i = 0; i < *n_capbufs; i++) {
785                         debug_printf("[fd%d] munmap capbuf %d mapped=0x%p length=%d\n", fd, i, capbufs[i].mapped, capbufs[i].length);
786                         ret = munmap(capbufs[i].mapped, capbufs[i].length);
787                         if (ret) {
788                                 printf("[fd%d] munmap failed for  %d: %d %s\n", fd, i, errno, strerror(errno));
789                         }
790                         debug_printf("[fd%d] destroy gem capbuf %d handle=%d\n",
791                                         fd, i, capbufs[i].bo_handle);
792                         memset(&gem_destroy, 0, sizeof(gem_destroy));
793                         gem_destroy.handle = capbufs[i].bo_handle;
794                         ret = ioctl(drmfd1, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy);
795                         if (ret)
796                                 printf("    DRM_IOCTL_MODE_DESTROY_DUMB failed\n");
797                 }
798 #endif
799         }
801         memset(&sub, 0, sizeof(sub));
802         sub.type = V4L2_EVENT_ALL;
804         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n", fd);
805         ret = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
806         if (ret != 0) {
807                 printf("[fd%d] Failed to unsubscribe to events: err: %d %s\n",
808                                 fd, errno, strerror(errno));
809         }
812 #ifdef DRM
813 static int create_drm_buffer(struct buffer *b,
814         unsigned int width, unsigned int height)
816         struct drm_mode_create_dumb gem;
817         struct drm_mode_map_dumb gem_map;
818         struct drm_mode_destroy_dumb gem_destroy;
819         int ret;
821         memset(&gem, 0, sizeof gem);
822         gem.width = width;
823         gem.height = height;
824         gem.bpp = 8;
826         ret = ioctl(drmfd1, DRM_IOCTL_MODE_CREATE_DUMB, &gem);
827         if (ret) {
828                 printf("    DRM_IOCTL_MODE_CREATE_DUMB failed\n");
829                 return ret;
830         }
832         b->bo_handle = gem.handle;
834         struct drm_prime_handle prime;
835         memset(&prime, 0, sizeof prime);
836         prime.handle = b->bo_handle;
838         ret = ioctl(drmfd1, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime);
839         if (ret) {
840                 printf("    DRM_IOCTL_PRIME_HANDLE_TO_FD failed\n");
841                 goto fail_gem;
842         }
843         b->dbuf_fd = prime.fd;
845         memset(&gem_map, 0, sizeof(gem_map));
846         gem_map.handle = gem.handle;
848         ret = ioctl(drmfd1, DRM_IOCTL_MODE_MAP_DUMB, &gem_map);
849         if (ret) {
850                 printf("    DRM_IOCTL_MODE_MAP_DUMB failed\n");
851                 goto fail_gem;
852         }
854         b->mapped = mmap(NULL, (size_t)gem.size, PROT_READ,
855                         MAP_SHARED, drmfd1, gem_map.offset);
856         if (MAP_FAILED == b->mapped) {
857                 printf("    mmap failed %d: %s\n", errno, strerror(errno));
858                 goto fail_gem;
859         }
860         b->offset = gem_map.offset;
861         b->length = gem.size;
863         return 0;
864 fail_gem:
865         memset(&gem_destroy, 0, sizeof gem_destroy);
866         gem_destroy.handle = b->bo_handle;
867         ret = ioctl(drmfd1, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy);
869         return ret;
871 #endif
873 int stream_framelevel_parsing(struct stream_context *str, char *input_file, int max_frames)
875         struct demux *demux;
876         int inp_buf_len = 0;
877         int inp_width, inp_height;
878         int frame_num = 0;
879         int frame_size = 0;
880         int bitdepth = 0;
881         enum AVPixelFormat pix_fmt;
882         enum AVCodecID codec;
884         /* Demux initialization */
885         demux = demux_init(input_file, &inp_width, &inp_height, &bitdepth, &pix_fmt, &codec);
886         if (!demux)
887         {
888                 printf("%s: could not open demuxer\n", __FUNCTION__);
889                 return -1;
890         }
892         debug_printf("\n%s: bitdepth: %d\n",__FUNCTION__, bitdepth);
893         debug_printf("%s: pix_fmt: %d\n",__FUNCTION__, pix_fmt);
894         debug_printf("%s: pix_fmt_string: %s\n",__FUNCTION__, pix_fmt != AV_PIX_FMT_NONE ?
895                         av_pix_fmt_descriptors[pix_fmt].name : "unknown");
896         debug_printf("\n%s: codec: %d\n",__FUNCTION__, codec);
897         if(codec == AV_CODEC_ID_H264)
898                 debug_printf("\n%s: codec: H264",__FUNCTION__);
899         if(codec == AV_CODEC_ID_HEVC)
900                 debug_printf("\n%s: codec format: HEVC\n",__FUNCTION__);
901         if(codec == AV_CODEC_ID_MJPEG)
902                 debug_printf("\n%s: codec format: MJPEG\n",__FUNCTION__);
904         inp_buf_len = (inp_width * inp_height);
906         unsigned char *inp_buf = malloc(inp_buf_len);
907         if(inp_buf == NULL)
908         {
909                 printf("%s: Memory allocation failed for inp_buf\n",
910                                 __FUNCTION__);
911                 return -1;
912         }
914         debug_printf("%s: demuxer is initialized, width=%d, height=%d\n",
915                 __FUNCTION__, inp_width, inp_height);
916         str->width = inp_width;
917         str->height = inp_height;
918         str->bitdepth = bitdepth;
919         str->pix_fmt = pix_fmt;
920         str->codec = codec;
922         if(bitdepth == 8 || pix_fmt == AV_PIX_FMT_YUV420P ||
923                         pix_fmt == AV_PIX_FMT_YUV422P)
924                 str->num_bytes_per_pix = 1;
925         if(bitdepth == 10 || pix_fmt == AV_PIX_FMT_YUV420P10LE ||
926                         pix_fmt == AV_PIX_FMT_YUV422P10LE)
927                 str->num_bytes_per_pix = 2;
929         /*read the frame size and store into array*/
930         while(1)
931         {
932                 frame_size = demux_read(demux, inp_buf, inp_buf_len);
933                 if (frame_size)
934                 {
935                         debug_printf("frame %d frame size in demux %d\n",
936                                 frame_num, frame_size);
937                         str->frame_sizes[frame_num] = frame_size;
938                         frame_num++;
939                 }
940                 else
941                 {
942                         /*if the input file contains less number frames*/
943                         break;
944                 }
945                 if (max_frames > 0 && frame_num >= max_frames)
946                         break;
947         }
949         /* Demux de-initialization */
950         demux_deinit(demux);
951         free(inp_buf);
953         debug_printf("H264 frame sizes update is done\n");
954         return frame_num;
957 static int init_device(int fd, int rdfd,
958                 struct stream_context *str, struct buffer outbufs[],
959                 struct buffer capbufs[], int *n_outbufs, int *n_capbufs,
960                 struct output_format format, int usedrmbuff)
962         struct v4l2_format fmt;
963         struct v4l2_requestbuffers reqbuf;
964         struct v4l2_buffer buffer;
965         struct v4l2_plane buf_planes[1];
966         int ret = 0;
967         int i, j;
968         /*for v4l2 based capture buffers*/
969         struct v4l2_buffer buffer_cap;
971         debug_printf("[fd%d] init_device\n", fd);
973         memzero(fmt);
974         fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
975         fmt.fmt.pix_mp.width = str->width;
976         fmt.fmt.pix_mp.height = str->height;
977         fmt.fmt.pix_mp.plane_fmt[0].sizeimage = (str->width * str->height);
978         fmt.fmt.pix_mp.num_planes = 1;
980         if(str->codec == AV_CODEC_ID_H264)
981                 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
982         if(str->codec == AV_CODEC_ID_HEVC)
983                 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_HEVC;
984         if(str->codec == AV_CODEC_ID_MJPEG)
985                 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_MJPEG;
987         ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
988         if (ret != 0) {
989                 printf("[fd%d] VIDIOC_S_FMT errorno %d, %s\n",
990                         fd, errno, strerror(errno));
991                 return ret;
992         }
994         debug_printf("[fd%d] After S_FMT on OUTPUT\n", fd);
996         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
997         fmt.fmt.pix_mp.pixelformat = format.fourcc;
999         if(str->codec == AV_CODEC_ID_MJPEG) {
1000                 fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
1001                                 ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix));
1002                 fmt.fmt.pix_mp.plane_fmt[1].sizeimage =
1003                                 ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix)) / 2;
1004                 fmt.fmt.pix_mp.plane_fmt[2].sizeimage =
1005                                 ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) * (str->num_bytes_per_pix)) / 2;
1007                 fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
1008                 fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
1009                 fmt.fmt.pix_mp.num_planes = 3;
1010                 fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
1011                 fmt.fmt.pix_mp.plane_fmt[1].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
1012                 fmt.fmt.pix_mp.plane_fmt[2].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
1013         } else {
1014                 fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
1015                                 ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) *
1016                                                 format.size_num) * (str->num_bytes_per_pix) / format.size_den;
1017                 fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
1018                 fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
1019                 fmt.fmt.pix_mp.num_planes = 1;
1020                 fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
1021         }
1023         ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
1024         if (ret) {
1025                 printf("[fd%d] VIDIOC_S_FMT errorno %d, %s\n",
1026                         fd, errno, strerror(errno));
1027                 return ret;
1028         }
1030         debug_printf("[fd%d] After S_FMT on CAPTURE\n", fd);
1032         fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1034         ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
1035         if (ret) {
1036                 printf("[fd%d] VIDIOC_G_FMT errorno %d, %s\n",
1037                         fd, errno, strerror(errno));
1038                 return ret;
1039         }
1041         debug_printf("[fd%d] After G_FMT on OUTPUT\n", fd);
1042         debug_printf("[fd%d] After G_FMT fmt.fmt.pix_mp.pixelformat = %c%c%c%c numplanes %d\n",
1043                         fd, fmt.fmt.pix_mp.pixelformat & 0xff,
1044                         (fmt.fmt.pix_mp.pixelformat >> 8) & 0xff,
1045                         (fmt.fmt.pix_mp.pixelformat >>16) & 0xff,
1046                         (fmt.fmt.pix_mp.pixelformat >> 24) & 0xff,
1047                         fmt.fmt.pix_mp.num_planes);
1049         debug_printf("[fd%d] fmt.fmt.pix_mp.width %d fmt.fmt.pix_mp.height %d"
1050                         " sizeimage %d bytesperline %d\n",
1051                         fd, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
1052                         fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
1053                         fmt.fmt.pix_mp.plane_fmt[0].bytesperline);
1055         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1057         ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
1058         if (ret) {
1059                 printf("[fd%d] VIDIOC_G_FMT errorno %d, %s\n",
1060                         fd, errno, strerror(errno));
1061                 return ret;
1062         }
1064         debug_printf("[fd%d] After G_FMT on CAPTURE\n", fd);
1065         debug_printf("[fd%d] After G_FMT fmt.fmt.pix_mp.pixelformat = %c%c%c%c numplanes %d\n",
1066                         fd, fmt.fmt.pix_mp.pixelformat & 0xff,
1067                         (fmt.fmt.pix_mp.pixelformat >> 8) & 0xff,
1068                         (fmt.fmt.pix_mp.pixelformat >>16) & 0xff,
1069                         (fmt.fmt.pix_mp.pixelformat >> 24) & 0xff,
1070                         fmt.fmt.pix_mp.num_planes);
1072         debug_printf("[fd%d] fmt.fmt.pix_mp.width %d fmt.fmt.pix_mp.height %d"
1073                         " sizeimage %d bytesperline %d\n",
1074                         fd, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
1075                         fmt.fmt.pix_mp.plane_fmt[1].sizeimage,
1076                         fmt.fmt.pix_mp.plane_fmt[1].bytesperline);
1078         /* Setup Decoder OUTPUT (SRC buffer) through VIDIOC_REQBUFS */
1079         debug_printf("[fd%d] Setup decoding OUTPUT with VIDIOC_REQBUFS buffer size %u\n",
1080                 fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1082         memzero(reqbuf);
1083         reqbuf.count = *n_outbufs;
1084         reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1085         reqbuf.memory = V4L2_MEMORY_MMAP;
1087         ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
1088         if (ret) {
1089                 printf("[fd%d] Err REQBUFS failed on OUTPUT queue ret %d errno %d\n",
1090                         fd, ret, errno);
1091                 return ret;
1092         }
1093         debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1094                 fd, reqbuf.count);
1095         *n_outbufs = reqbuf.count;
1097         /* QUERYBUF on OUTPUT - memory of V4L2_MEMORY_MMAP */
1098         for (i = 0; i < *n_outbufs; i++) {
1099                 memset(&buffer, 0, sizeof(buffer));
1100                 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1101                 buffer.index = i;
1102                 buffer.m.planes = buf_planes;
1103                 buffer.length = 1;
1105                 ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer);
1106                 if (ret < 0) {
1107                         printf("[fd%d] CANNOT QUERY BUFFERS ret = %d\n",
1108                                 fd, ret);
1109                         return -1;
1110                 }
1112                 debug_printf("[fd%d] query buf, buffer %p plane 0 = %d buffer.length %d buffer.data_offset %d buffer.mem_offset %d\n",
1113                                 fd, &buffer, buffer.m.planes[0].length,
1114                                 buffer.length, buffer.m.planes[0].data_offset,
1115                                 buffer.m.planes[0].m.mem_offset);
1117                 outbufs[i].mapped = mmap(NULL, buffer.m.planes[0].length,
1118                                 PROT_READ | PROT_WRITE, MAP_SHARED,
1119                                 fd, buffer.m.planes[0].m.mem_offset);
1120                 outbufs[i].offset = buffer.m.planes[0].m.mem_offset;
1121                 outbufs[i].length = buffer.m.planes[0].length;
1123                 debug_printf("[fd%d] After mmap -> outbufs[%d].mapped = 0x%p\n",
1124                         fd, i, outbufs[i].mapped);
1126                 if (MAP_FAILED == outbufs[i].mapped) {
1127                         while (i >= 0) {
1128                                 /* Unmap all previous buffers */
1129                                 i--;
1130                                 munmap(outbufs[i].mapped,
1131                                         fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1132                                 outbufs[i].mapped = NULL;
1133                         }
1134                         printf("[fd%d] Cant mmap buffers Y", fd);
1135                         return -1;
1136                 }
1137         }
1139         /* Setup Decoder CAPTURE (DST buffer) through VIDIOC_REQBUFS */
1141         if (usedrmbuff == 0) {
1142                 /* Setup Decoder CAPTURE (DST buffer) through VIDIOC_REQBUFS */
1143                 debug_printf("[fd%d] Setup decoding CAPTURE with VIDIOC_REQBUFS\n", fd);
1144                 debug_printf("[fd%d] buffer(y) size %u buffer(uv) size %u\n",
1145                                         fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
1146                                         fmt.fmt.pix_mp.plane_fmt[1].sizeimage);
1148                 memzero(reqbuf);
1149                 reqbuf.count = *n_capbufs;
1150                 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1151                 reqbuf.memory = V4L2_MEMORY_MMAP;
1153                 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
1154                 if (ret) {
1155                         printf("[fd%d] Err REQBUFS failed on CAPTURE queue ret %d errno %d\n",
1156                                 fd, ret, errno);
1157                         return ret;
1158                 }
1159                 debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1160                         fd, reqbuf.count);
1161                 *n_capbufs = reqbuf.count;
1162                 /*Creating Capbuffers with v4l2 BUFFERS*/
1163                 /* QUERYBUF on Capture - memory of V4L2_MEMORY_MMAP */
1165                 if(str->codec == AV_CODEC_ID_MJPEG) {
1166                         struct v4l2_plane buf_planes_cap[FMT_NUM_MJPEG_PLANES];
1168                         for (j = 0; j < (*n_capbufs / 3); j++) {
1169                                 memset(&buffer_cap, 0, sizeof(buffer_cap));
1170                                 buffer_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1171                                 buffer_cap.index = j;
1172                                 buffer_cap.m.planes = buf_planes_cap;
1173                                 buffer_cap.length = FMT_NUM_MJPEG_PLANES;
1174                                 buffer_cap.memory = V4L2_MEMORY_MMAP;
1177                                 ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer_cap);
1178                                 if (ret < 0) {
1179                                         printf("[fd%d] CANNOT QUERY BUFFERS for Capture ret = %d\n", fd, ret);
1180                                         return -1;
1181                                 }
1182                                 for (i = 0; i < buffer_cap.length; i++) {
1183                                 debug_printf("[fd%d] query buf, buffer %p plane %d = %d buffer_cap.length %d buffer_cap.data_offset %d buffer_cap.mem_offset %d\n",
1184                                                 fd, &buffer_cap, i,buffer_cap.m.planes[i].length,
1185                                                 buffer_cap.length, buffer_cap.m.planes[i].data_offset,
1186                                                 buffer_cap.m.planes[i].m.mem_offset);
1188                                 capbufs[(j*3)+i].mapped = mmap(NULL, buffer_cap.m.planes[i].length,
1189                                                 PROT_READ, MAP_SHARED,
1190                                                 fd, buffer_cap.m.planes[i].m.mem_offset);
1191                                 capbufs[(j*3)+i].offset = buffer_cap.m.planes[i].m.mem_offset;
1192                                 capbufs[(j*3)+i].length = buffer_cap.m.planes[i].length;
1194                                 debug_printf("[fd%d] After mmap -> capbufs[%d].mapped = 0x%p\n",
1195                                         fd, (j*3)+i, capbufs[(j*3)+i].mapped);
1197                                 if (MAP_FAILED == capbufs[(j*3)+i].mapped) {
1198                                         while (j >= 0) {
1199                                                 /* Unmap all previous buffers */
1200                                                 j--;
1201                                                 munmap(capbufs[(j*3)+i].mapped,
1202                                                          fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1203                                                          capbufs[(j*3)+i].mapped = NULL;
1204                                         }
1205                                         printf("[fd%d] Cant mmap capture buffers Y\n", fd);
1206                                         return -1;
1207                                 }
1208                                 }
1209                         }
1210                 } else {
1211                         struct v4l2_plane buf_planes_cap[FMT_NUM_PLANES];
1212                 for (j = 0; j < *n_capbufs; j++) {
1213                         memset(&buffer_cap, 0, sizeof(buffer_cap));
1214                         buffer_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1215                         buffer_cap.index = j;
1216                         buffer_cap.m.planes = buf_planes_cap;
1217                         buffer_cap.length = FMT_NUM_PLANES;
1218                         buffer_cap.memory = V4L2_MEMORY_MMAP;
1221                         ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer_cap);
1222                         if (ret < 0) {
1223                                 printf("[fd%d] CANNOT QUERY BUFFERS for Capture ret = %d\n",
1224                                                 fd, ret);
1225                                 return -1;
1226                         }
1227                         debug_printf("[fd%d] query buf, buffer %p plane 0 = %d buffer_cap.length %d buffer_cap.data_offset %d buffer_cap.mem_offset %d\n",
1228                                         fd, &buffer_cap,
1229                                         buffer_cap.m.planes[0].length,
1230                                         buffer_cap.length,
1231                                         buffer_cap.m.planes[0].data_offset,
1232                                         buffer_cap.m.planes[0].m.mem_offset);
1234                         capbufs[j].mapped = mmap(NULL, buffer_cap.m.planes[0].length,
1235                                         PROT_READ, MAP_SHARED,
1236                                         fd, buffer_cap.m.planes[0].m.mem_offset);
1237                         capbufs[j].offset = buffer_cap.m.planes[0].m.mem_offset;
1238                         capbufs[j].length = buffer_cap.m.planes[0].length;
1240                         debug_printf("[fd%d] After mmap -> capbufs[%d].mapped = 0x%p\n",
1241                                         fd, j, capbufs[j].mapped);
1243                         if (MAP_FAILED == capbufs[j].mapped) {
1244                                 while (j >= 0) {
1245                                         /* Unmap all previous buffers */
1246                                         j--;
1247                                         munmap(capbufs[j].mapped,
1248                                                  fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1249                                                  capbufs[j].mapped = NULL;
1250                                 }
1251                                 printf("[fd%d] Cant mmap capture buffers Y\n", fd);
1252                                 return -1;
1253                         }
1254                 }
1255                 }
1256         } else {
1257 #ifdef DRM
1258                 debug_printf("[fd%d] Setup decoding CAPTURE with VIDIOC_REQBUFS\n", fd);
1259                 debug_printf("[fd%d] buffer(y) size %u buffer(uv) size %u\n",
1260                                 fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
1261                                 fmt.fmt.pix_mp.plane_fmt[1].sizeimage);
1263                 memzero(reqbuf);
1264                 reqbuf.count = *n_capbufs;
1265                 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1266                 reqbuf.memory = V4L2_MEMORY_DMABUF;
1268                 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
1269                 if (ret) {
1270                         printf("[fd%d] Err REQBUFS failed on CAPTURE queue ret %d errno %d\n",
1271                                         fd, ret, errno);
1272                         return ret;
1273                 }
1274                 debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1275                                 fd, reqbuf.count);
1276                 *n_capbufs = reqbuf.count;
1278                 /* Create DRM buffers */
1279                 for (i = 0; i < *n_capbufs; i++) {
1280                         ret = create_drm_buffer(&capbufs[i],
1281                                         ALIGN(fmt.fmt.pix_mp.width, HW_ALIGN),
1282                                         ((str->num_bytes_per_pix *
1283                                                 fmt.fmt.pix_mp.height * format.size_num) /
1284                                          format.size_den));
1285                         if (ret) {
1286                                 printf("[fd%d] failed to create drm buffers\n", fd);
1287                                 return -1;
1288                         }
1289                         debug_printf("[fd%d] Create_DRM_BUFFERS drm_y_buffer[%d].dbuf_fd 0x%x, length %d offset %d\n",
1290                                         fd, i, capbufs[i].dbuf_fd, capbufs[i].length, capbufs[i].offset);
1291                 }
1292 #else
1293                 printf("Cannot allocate DRM buffers\n");
1294                 return -1;
1295 #endif
1296         }
1297         return ret;
1300 static void close_device(int fd)
1302         debug_printf("[fd%d] close_device\n", fd);
1303         if (-1 == close(fd))
1304                 errno_exit ("close");
1305         fd = -1;
1308 static int open_device(char *dev_name)
1310         struct v4l2_capability cap;
1311         struct v4l2_fmtdesc argp;
1312         struct v4l2_event_subscription sub;
1313         int ret = 0, fd = -1;
1315         fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
1316         if (-1 == fd) {
1317                 printf("Cannot open '%s': %d, %s\n",
1318                                 dev_name, errno, strerror(errno));
1319                 return -1;
1320         }
1322         ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
1323         if (ret != 0) {
1324                 printf("Failed to verify capabilities\n");
1325                 return -1;
1326         }
1328         debug_printf("[fd%d] Info (%s): driver\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x\n",
1329                         fd, dev_name, cap.driver, cap.bus_info, cap.card, fd);
1331         debug_printf("[fd%d] Info (%s): capabilities\"0x%x\" device_caps=\"0x%x\" \n",
1332                         fd, dev_name, cap.capabilities, cap.device_caps);
1334         memset(&argp, 0, sizeof(argp));
1335         argp.index = 0;
1336         argp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1338         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_ENUM_FMT on CAPTURE\n",
1339                         fd);
1340         while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &argp)) == 0) {
1341                 debug_printf("[fd%d] argp.index = %d, {pixelformat = %c%c%c%c}, description = '%s'\n",
1342                                 fd, argp.index, argp.pixelformat & 0xff,
1343                                 (argp.pixelformat >> 8) & 0xff,
1344                                 (argp.pixelformat >>16) & 0xff,
1345                                 (argp.pixelformat >> 24) & 0xff,
1346                                 argp.description);
1347                 argp.index ++;
1348         }
1350         argp.index = 0;
1351         argp.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1353         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_ENUM_FMT on OUTPUT\n",
1354                         fd);
1355         while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &argp)) == 0) {
1356                 debug_printf("[fd%d] argp.index = %d, {pixelformat = %c%c%c%c}, description = '%s'\n",
1357                                 fd, argp.index, argp.pixelformat & 0xff,
1358                                 (argp.pixelformat >> 8) & 0xff,
1359                                 (argp.pixelformat >>16) & 0xff,
1360                                 (argp.pixelformat >> 24) & 0xff,
1361                                 argp.description);
1362                 argp.index ++;
1363         }
1365         memset(&sub, 0, sizeof(sub));
1366         sub.type = V4L2_EVENT_EOS;
1368         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n", fd);
1369         ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
1370         if (ret != 0) {
1371                 printf("[fd%d] Failed to subscribe to events: err: %d %s\n",
1372                                 fd, errno, strerror(errno));
1373         }
1375         return fd;
1378 static int find_device(char *dev_name)
1380         const char *default_dev_path = "/dev/";
1381         const char *dev_name_mask = "videox";
1382         const char *driver_name = "vxd-dec";
1383         struct v4l2_capability cap = {0};
1384         char name[256] = "";
1385         DIR *d;
1386         struct dirent *dir;
1387         int fd = -1;
1389         d = opendir(default_dev_path);
1390         if (!d) {
1391                 printf("Failed to open device path %s %d %s\n",
1392                        default_dev_path, errno, strerror(errno));
1393                 return -1;
1394         }
1396         while ((dir = readdir(d)) != NULL) {
1397                 if (strncmp(dir->d_name, dev_name_mask, 5) == 0) {
1398                         strncpy(name, default_dev_path, sizeof(name));
1399                         strncat(name, dir->d_name, sizeof(name));
1401                         fd = open(name, O_RDWR | O_NONBLOCK, 0);
1402                         if (fd < 0) {
1403                                 printf("Failed to open device %s %d %s\n",
1404                                        name, errno, strerror(errno));
1405                                 continue;
1406                         }
1408                         memset(&cap, 0, sizeof(cap));
1410                         if (ioctl(fd, VIDIOC_QUERYCAP, &cap)) {
1411                                 printf("VIDIOC_QUERYCAP failed on device %s %d %s\n",
1412                                        name, errno, strerror(errno));
1413                                 close(fd);
1414                                 continue;
1415                         }
1417                         if (strcmp((const char *)cap.driver, driver_name) == 0) {
1418                                 close(fd);
1419                                 fd = -1;
1420                                 debug_printf("No device specified, using %s\n",
1421                                              name);
1422                                 snprintf(dev_name, sizeof(name), "%s", name);
1423                                 return 0;
1424                         }
1426                         close(fd);
1427                         fd = -1;
1428                 }
1429         }
1431         printf("Failed to find device in %s\n", default_dev_path);
1432         return -1;
1435 int main(int argc, char **argv)
1437         char dev_name[256] = "";
1438         int i = 0;
1439         int ret = 0;
1440         unsigned int num_devs = 1;
1441         int fds[MAX_TEST_FDS];
1442         int rdfd = -1;
1443         int wrfd = -1;
1444         int c;
1445         int n_outbufs, n_capbufs, n_frames;
1446         struct buffer outbufs[MAX_OUTBUFS];
1447         struct buffer capbufs[MAX_CAPBUFS];
1448         struct stream_context str_context;
1449         char input_file[256];
1450         char output_file_base[120];
1451         char output_file[128];
1452         char drm_file_name[20];
1453 #ifdef DRMMODE
1454         const char *dir_path = "/dev/dri/";
1455         DIR *d;
1456         struct dirent *dir;
1457         drmModeResPtr res;
1458 #endif
1459         int max_frames = -1;
1460         int enable_prof = 0;
1461         int sleep_time = 0;
1462         struct output_format fmt;
1463         int use_drm_capbuff = 1; /* Defaulting to use drm dss Capture Buffers */
1465         printf("TI DEC V4L2 Codec decoding example application\n");
1466         printf("Copyright (c) 2018 Texas Instruments, Inc.\n");
1468         /* Parse the input args */
1469         while (1)
1470         {
1471                 c = getopt (argc, argv, "nf:hbi:o:d:te:v:");
1472                 if (c == -1)
1473                         break;
1475                 switch (c) {
1476                         case 'n':
1477                                 num_devs = atoi(optarg);
1478                                 break;
1479                         case 'h':
1480                                 printf("Use:\n");
1481                                 printf("\t./tidec_decode -i <input_file> [OPTIONS]\n");
1482                                 printf("\tThe final output file/s will be '<output_file_base>_xx.out'\n");
1483                                 printf("\twhere xx ranges from 00, 01, 02, ...\n");
1484                                 printf("\tdepending on how many fds are specified to -n\n");
1485                                 printf("\tOPTIONS:\n");
1486                                 printf("\t\t-h help\n");
1487                                 printf("\t\t-b DO NOT use drm dss device capture buffer (instead, use v4l2)\n");
1488                                 printf("\t\t-n <number> number of fds to open\n");
1489                                 printf("\t\t-o <output_file_base> Dump output stream to file\n");
1490                                 printf("\t\t\tThe final output file/s will be '<output_file_base>_xx.out'\n");
1491                                 printf("\t\t\twhere xx ranges from 00, 01, 02, ...\n");
1492                                 printf("\t\t\tdepending on how many fds are specified to -n\n");
1493                                 printf("\t\t-f <number of frames to decode> Maximum number of frames to decode\n");
1494                                 printf("\t\t-d <path> Path to which drm device to use for buffer allocation\n");
1495                                 printf("\t\t-t for enable time profiling\n");
1496                                 printf("\t\t-e <number of ms> Number of milliseconds to sleep between\n");
1497                                 printf("\t\t\tqueueing the last bitstream buffer and sending CMD_STOP\n");
1498                                 printf("\t\t\tUsed to test various timing scenarios for EOS\n");
1499                                 printf("\t\t-v <dev_name>\n");
1500                                 printf("\t\t\tUsed to specify which device node is the decoder\n");
1501                                 break;
1502                         case 'b':
1503                                 use_drm_capbuff = 0; /* DO NOT use drm dss device*/
1504                                 break;
1505                         case 'i':
1506                                 snprintf(input_file, sizeof(input_file),
1507                                                 "%s", optarg);
1508                                 break;
1509                         case 'o':
1510                                 snprintf(output_file_base,
1511                                                 sizeof(output_file_base),
1512                                                 "%s", optarg);
1513                                 break;
1514                         case 'f':
1515                                 max_frames = atoi(optarg);
1516                                 break;
1517                         case 'd':
1518                                 snprintf(drm_file_name, sizeof(drm_file_name),
1519                                                 "%s", optarg);
1520                                 break;
1521                         case 't':
1522                                 enable_prof = 1;
1523                                 break;
1524                         case 'e':
1525                                 sleep_time = 1000 * atoi(optarg);
1526                                 break;
1527                         case 'v':
1528                                 snprintf(dev_name, sizeof(dev_name),
1529                                          "%s", optarg);
1530                                 break;
1531                         default:
1532                                 printf("Unrecognized argument %c\n", c);
1533                 }
1534         }
1536         if (0 == strlen(input_file)) {
1537                 printf("Requires an input value\n");
1538                 printf("\t./tidec_decode -i <input_file> [OPTIONS]\n");
1539                 return EXIT_FAILURE;
1540         }
1542         /* validate input args */
1543         if (num_devs > MAX_TEST_FDS) {
1544                 printf("Invalid value passed for number of devices %d\n",
1545                                 num_devs);
1546                 return EXIT_FAILURE;
1547         }
1549         if (strlen(dev_name) == 0) {
1550                 ret = find_device(dev_name);
1551                 if (ret)
1552                         return EXIT_FAILURE;
1553         }
1555         for (i = 0; i < num_devs; i++) {
1556                 debug_printf("*** Calling open_device for device %d \n", i);
1557                 fds[i] = open_device(dev_name);
1558                 if (fds[i] < 0) {
1559                         printf("Failed to open device %s\n", dev_name);
1560                         return EXIT_FAILURE;
1561                 }
1562                 debug_printf("*** device %d is fd %d", i, fds[i]);
1563         }
1565         if (use_drm_capbuff == 0) {
1566                 printf("\nUsing v4l2 for capture buffers\n");
1567         } else {
1568                 if (strlen(drm_file_name) > 0) {
1569 #ifdef DRM
1570                         drmfd1 = open(drm_file_name, O_CLOEXEC);
1571                         if (drmfd1 < 0) {
1572                                 printf("Failed to open drm device\n");
1573                                 return EXIT_FAILURE;
1574                         }
1575 #else
1576                         printf("DRM not supported with current build arguments\n");
1577                         return EXIT_FAILURE;
1578 #endif
1579                 } else {
1580 #ifdef DRMMODE
1581                         d = opendir(dir_path);
1582                         if (!d) {
1583                                 printf("Failed to open drm device directory\n");
1584                                 return EXIT_FAILURE;
1585                         }
1586                         while ((dir = readdir(d)) != NULL) {
1587                                 if(strncmp(dir->d_name, DEVICE_NAME, 4) == 0) {
1588                                         strcpy(drm_file_name, dir_path);
1589                                         strncat(drm_file_name, dir->d_name,
1590                                                 sizeof(DEVICE_NAME));
1591                                         drmfd1 = open(drm_file_name, O_CLOEXEC);
1592                                         if (drmfd1 < 0) {
1593                                                 printf("Failed to open drm device %s\n",
1594                                                                 drm_file_name);
1595                                         }
1596                                         printf("No drm device specified, testing %s\n",
1597                                                         drm_file_name);
1598                                         res = drmModeGetResources(drmfd1);
1599                                         if (res && res->count_crtcs > 0 &&
1600                                                         res->count_connectors > 0 &&
1601                                                         res->count_encoders > 0) {
1602                                                 printf("No drm device specified, using %s\n",
1603                                                                 drm_file_name);
1604                                                 break;
1605                                         }
1606                                         close(drmfd1);
1607                                         drmfd1 = -1;
1608                                 }
1609                         }
1610 #else
1611                         printf("Can't search DRM directory\n");
1612                         return EXIT_FAILURE;
1613 #endif
1614                 }
1615                 if (drmfd1 < 0) {
1616                         printf("Failed to open drm device\n");
1617                         return EXIT_FAILURE;
1618                 }
1619         }
1621         /* Get the stream width, height and framesizes of H264 stream */
1622         n_frames = stream_framelevel_parsing(&str_context, input_file, max_frames);
1623         if (n_frames < 0) {
1624                 printf("Failed to init frame sizes\n");
1625                 return EXIT_FAILURE;
1626         }
1628         switch (str_context.pix_fmt) {
1629                 case AV_PIX_FMT_YUV420P:
1630                         fmt.fourcc = V4L2_PIX_FMT_NV12;
1631                         fmt.size_num = 3;
1632                         fmt.size_den = 2;
1633                         break;
1634                 case AV_PIX_FMT_YUV422P:
1635                         fmt.fourcc = V4L2_PIX_FMT_NV16;
1636                         fmt.size_num = 2;
1637                         fmt.size_den = 1;
1638                         break;
1639                 case AV_PIX_FMT_YUV420P10LE:
1640                         fmt.fourcc = V4L2_PIX_FMT_TI1210;
1641                         fmt.size_num = 3;
1642                         fmt.size_den = 2;
1643                         break;
1644                 case AV_PIX_FMT_YUV422P10LE:
1645                         fmt.fourcc = V4L2_PIX_FMT_TI1610;
1646                         fmt.size_num = 2;
1647                         fmt.size_den = 1;
1648                         break;
1649                 case AV_PIX_FMT_YUVJ420P:
1650                         fmt.fourcc = V4L2_PIX_FMT_YUV420M;
1651                         fmt.size_num = 1;
1652                         fmt.size_den = 1;
1653                         break;
1654                 case AV_PIX_FMT_YUVJ422P:
1655                         fmt.fourcc = V4L2_PIX_FMT_YUV422M;
1656                         fmt.size_num = 1;
1657                         fmt.size_den = 1;
1658                         break;
1659                 default:
1660                         printf("Invalid pixel format detected\n");
1661                         return -1;
1662         }
1664         for (i = 0; i < num_devs; i++) {
1665                 n_outbufs = MAX_OUTBUFS;
1666                 /* Request number of output buffers based on h264 spec
1667                  * + display delay */
1668                 n_capbufs = MIN(MAX_CAPBUFS_H264, (32768 /
1669                                         ((str_context.width / 16) *
1670                                         (str_context.height / 16)))) +
1671                                         DISPLAY_LAG;
1673                 debug_printf("Opening input file\n");
1674                 rdfd = open(input_file, O_RDONLY);
1675                 if (rdfd < 0) {
1676                         printf("Failed to open input file %s", input_file);
1677                 }
1679                 if (strcmp(output_file_base, "")) {
1680                         snprintf(output_file, sizeof(output_file),
1681                                         "%s_%02d.raw", output_file_base, i);
1682                         wrfd = open(output_file,
1683                                         O_CREAT | O_WRONLY | O_SYNC | O_TRUNC,
1684                                         0777);
1685                 }
1687                 if (wrfd < 0) {
1688                         if (strcmp(output_file_base, "")) {
1689                                 printf("Failed to open output file %s\n",
1690                                                 output_file);
1691                                 return EXIT_FAILURE;
1692                         } else {
1693                                 printf("No output file specified\n");
1694                         }
1695                 } else {
1696                         debug_printf("Opened output file %s\n", output_file);
1697                 }
1699                 ret = init_device(fds[i], rdfd, &str_context, outbufs,
1700                                 capbufs, &n_outbufs, &n_capbufs, fmt, use_drm_capbuff);
1701                 if (ret) {
1702                         printf("init_device failed with ret %d for device %d [fd%d]\n",
1703                                         ret, i, fds[i]);
1704                         return EXIT_FAILURE;
1705                 }
1707                 if (mainloop(fds[i], rdfd, wrfd, &str_context, outbufs,
1708                                         capbufs, n_outbufs,
1709                                         n_capbufs, n_frames,
1710                                         enable_prof, fmt,
1711                                         sleep_time, use_drm_capbuff)) {
1712                         return EXIT_FAILURE;
1713                 }
1715                 close(rdfd);
1716                 if (!(wrfd < 0))
1717                         close(wrfd);
1718                 rdfd = -1;
1719                 wrfd = -1;
1721                 uninit_device(fds[i], outbufs, capbufs, &n_outbufs, &n_capbufs, use_drm_capbuff);
1723                 debug_printf("*** Calling close_device for device %d [fd%d]\n",
1724                                 i, fds[i]);
1725                 close_device(fds[i]);
1726         }
1728         if (use_drm_capbuff && drmfd1)
1729                 close(drmfd1);
1731         printf("test app completed successfully\n");
1732         return 0;