]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - jacinto7_multimedia/viddec-test-app.git/blob - main.c
Initial commit
[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 <assert.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <malloc.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #include <sys/mman.h>
28 #include <sys/ioctl.h>
29 #include <signal.h>
30 #include <poll.h>
31 #include <dirent.h>
33 #include <asm/types.h>
34 #include <linux/videodev2.h>
35 #include <linux/v4l2-controls.h>
37 #include <drm.h>
38 #include <xf86drm.h>
39 #include <xf86drmMode.h>
40 #include <drm_fourcc.h>
42 #include "demux.h"
44 /* HEVC aka H.265 */
45 #define V4L2_PIX_FMT_HEVC     v4l2_fourcc('H', 'E', 'V', 'C')
46 /* TI NV12 10-bit, two bytes per channel */
47 #define V4L2_PIX_FMT_TI1210   v4l2_fourcc('T', 'I', '1', '2')
48 /* TI YUV422 10-bit, two bytes per channel */
49 #define V4L2_PIX_FMT_TI1610   v4l2_fourcc('T', 'I', '1', '6')
51 static const struct AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = {
52                 [AV_PIX_FMT_YUV420P] = {
53                                 .name = "yuv420p",
54                 },
55                 [AV_PIX_FMT_YUYV422] = {
56                                 .name = "yuyv422",
57                 },
58                 [AV_PIX_FMT_YVYU422] = {
59                                 .name = "yvyu422",
60                 },
61                 [AV_PIX_FMT_YUV422P] = {
62                                 .name = "yuv422p",
63                 },
64                 [AV_PIX_FMT_YUV444P] = {
65                                 .name = "yuv444p",
66                 },
67                 [AV_PIX_FMT_YUV410P] = {
68                                 .name = "yuv410p",
69                 },
70                 [AV_PIX_FMT_YUV411P] = {
71                                 .name = "yuv411p",
72                 },
73                 [AV_PIX_FMT_YUVJ411P] = {
74                                 .name = "yuvj411p",
75                 },
76                 [AV_PIX_FMT_YUVJ420P] = {
77                                 .name = "yuvj420p",
78                 },
79                 [AV_PIX_FMT_YUVJ422P] = {
80                                 .name = "yuvj422p",
81                 },
82                 [AV_PIX_FMT_YUVJ444P] = {
83                                 .name = "yuvj444p",
84                 },
85                 [AV_PIX_FMT_XVMC] = {
86                                 .name = "xvmc",
87                                 .flags = AV_PIX_FMT_FLAG_HWACCEL,
88                 },
89                 [AV_PIX_FMT_UYVY422] = {
90                                 .name = "uyvy422",
91                 },
92                 [AV_PIX_FMT_UYYVYY411] = {
93                                 .name = "uyyvyy411",
94                 },
95                 [AV_PIX_FMT_NV12] = {
96                                 .name = "nv12",
97                 },
98                 [AV_PIX_FMT_NV21] = {
99                                 .name = "nv21",
100                 },
101                 [AV_PIX_FMT_YUV440P] = {
102                                 .name = "yuv440p",
103                 },
104                 [AV_PIX_FMT_YUVJ440P] = {
105                                 .name = "yuvj440p",
106                 },
107                 [AV_PIX_FMT_YUV440P10LE] = {
108                                 .name = "yuv440p10le",
109                 },
110                 [AV_PIX_FMT_YUV440P10BE] = {
111                                 .name = "yuv440p10be",
112                 },
113                 [AV_PIX_FMT_YUV440P12LE] = {
114                                 .name = "yuv440p12le",
115                 },
116                 [AV_PIX_FMT_YUV440P12BE] = {
117                                 .name = "yuv440p12be",
118                 },
119                 [AV_PIX_FMT_YUVA420P] = {
120                                 .name = "yuva420p",
121                 },
122                 [AV_PIX_FMT_YUVA422P] = {
123                                 .name = "yuva422p",
124                 },
125                 [AV_PIX_FMT_YUVA444P] = {
126                                 .name = "yuva444p",
127                 },
128                 [AV_PIX_FMT_YUVA420P9BE] = {
129                                 .name = "yuva420p9be",
130                 },
131                 [AV_PIX_FMT_YUVA420P9LE] = {
132                                 .name = "yuva420p9le",
133                 },
134                 [AV_PIX_FMT_YUVA422P9BE] = {
135                                 .name = "yuva422p9be",
136                 },
137                 [AV_PIX_FMT_YUVA422P9LE] = {
138                                 .name = "yuva422p9le",
139                 },
140                 [AV_PIX_FMT_YUVA444P9BE] = {
141                                 .name = "yuva444p9be",
142                 },
143                 [AV_PIX_FMT_YUVA444P9LE] = {
144                                 .name = "yuva444p9le",
145                 },
146                 [AV_PIX_FMT_YUVA420P10BE] = {
147                                 .name = "yuva420p10be",
148                 },
149                 [AV_PIX_FMT_YUVA420P10LE] = {
150                                 .name = "yuva420p10le",
151                 },
152                 [AV_PIX_FMT_YUVA422P10BE] = {
153                                 .name = "yuva422p10be",
154                 },
155                 [AV_PIX_FMT_YUVA422P10LE] = {
156                                 .name = "yuva422p10le",
157                 },
158                 [AV_PIX_FMT_YUVA444P10BE] = {
159                                 .name = "yuva444p10be",
160                 },
161                 [AV_PIX_FMT_YUVA444P10LE] = {
162                                 .name = "yuva444p10le",
163                 },
164                 [AV_PIX_FMT_YUVA420P16BE] = {
165                                 .name = "yuva420p16be",
166                 },
167                 [AV_PIX_FMT_YUVA420P16LE] = {
168                                 .name = "yuva420p16le",
169                 },
170                 [AV_PIX_FMT_YUVA422P16BE] = {
171                                 .name = "yuva422p16be",
172                 },
173                 [AV_PIX_FMT_YUVA422P16LE] = {
174                                 .name = "yuva422p16le",
175                 },
176                 [AV_PIX_FMT_YUVA444P16BE] = {
177                                 .name = "yuva444p16be",
178                 },
179                 [AV_PIX_FMT_YUVA444P16LE] = {
180                                 .name = "yuva444p16le",
181                 },
182                 [AV_PIX_FMT_YUV420P9LE] = {
183                                 .name = "yuv420p9le",
184                 },
185                 [AV_PIX_FMT_YUV420P9BE] = {
186                                 .name = "yuv420p9be",
187                 },
188                 [AV_PIX_FMT_YUV420P10LE] = {
189                                 .name = "yuv420p10le",
190                 },
191                 [AV_PIX_FMT_YUV420P10BE] = {
192                                 .name = "yuv420p10be",
193                 },
194                 [AV_PIX_FMT_YUV420P12LE] = {
195                                 .name = "yuv420p12le",
196                 },
197                 [AV_PIX_FMT_YUV420P12BE] = {
198                                 .name = "yuv420p12be",
199                 },
200                 [AV_PIX_FMT_YUV420P14LE] = {
201                                 .name = "yuv420p14le",
202                 },
203                 [AV_PIX_FMT_YUV420P14BE] = {
204                                 .name = "yuv420p14be",
205                 },
206                 [AV_PIX_FMT_YUV420P16LE] = {
207                                 .name = "yuv420p16le",
208                 },
209                 [AV_PIX_FMT_YUV420P16BE] = {
210                                 .name = "yuv420p16be",
211                 },
212                 [AV_PIX_FMT_YUV422P9LE] = {
213                                 .name = "yuv422p9le",
214                 },
215                 [AV_PIX_FMT_YUV422P9BE] = {
216                                 .name = "yuv422p9be",
217                 },
218                 [AV_PIX_FMT_YUV422P10LE] = {
219                                 .name = "yuv422p10le",
220                 },
221                 [AV_PIX_FMT_YUV422P10BE] = {
222                                 .name = "yuv422p10be",
223                 },
224                 [AV_PIX_FMT_YUV422P12LE] = {
225                                 .name = "yuv422p12le",
226                 },
227                 [AV_PIX_FMT_YUV422P12BE] = {
228                                 .name = "yuv422p12be",
229                 },
230                 [AV_PIX_FMT_YUV422P14LE] = {
231                                 .name = "yuv422p14le",
232                 },
233                 [AV_PIX_FMT_YUV422P14BE] = {
234                                 .name = "yuv422p14be",
235                 },
236                 [AV_PIX_FMT_YUV422P16LE] = {
237                                 .name = "yuv422p16le",
238                 },
239                 [AV_PIX_FMT_YUV422P16BE] = {
240                                 .name = "yuv422p16be",
241                 },
242                 [AV_PIX_FMT_YUV444P16LE] = {
243                                 .name = "yuv444p16le",
244                 },
245                 [AV_PIX_FMT_YUV444P16BE] = {
246                                 .name = "yuv444p16be",
247                 },
248                 [AV_PIX_FMT_YUV444P10LE] = {
249                                 .name = "yuv444p10le",
250                 },
251                 [AV_PIX_FMT_YUV444P10BE] = {
252                                 .name = "yuv444p10be",
253                 },
254                 [AV_PIX_FMT_YUV444P9LE] = {
255                                 .name = "yuv444p9le",
256                 },
257                 [AV_PIX_FMT_YUV444P9BE] = {
258                                 .name = "yuv444p9be",
259                 },
260                 [AV_PIX_FMT_YUV444P12LE] = {
261                                 .name = "yuv444p12le",
262                 },
263                 [AV_PIX_FMT_YUV444P12BE] = {
264                                 .name = "yuv444p12be",
265                 },
266                 [AV_PIX_FMT_YUV444P14LE] = {
267                                 .name = "yuv444p14le",
268                 },
269                 [AV_PIX_FMT_YUV444P14BE] = {
270                                 .name = "yuv444p14be",
271                 },
272                 [AV_PIX_FMT_P010LE] = {
273                                 .name = "p010le",
274                 },
275                 [AV_PIX_FMT_P010BE] = {
276                                 .name = "p010be",
277                 },
278                 [AV_PIX_FMT_P016LE] = {
279                                 .name = "p016le",
280                 },
281                 [AV_PIX_FMT_P016BE] = {
282                                 .name = "p016be",
283                 }
284 };
286 #define memzero(x)      memset(&(x), 0, sizeof (x))
287 #define MAX_TEST_FDS    10
288 #define MAX_FRAMES      1000
289 #define ALIGN(x,a)      (((x) + (a) - 1L) & ~((a) - 1L))
290 #define HW_ALIGN        64
292 #define MAX_OUTBUFS 2
294 #define DISPLAY_LAG 3
296 #define MAX_CAPBUFS_H264 16
297 #define MAX_CAPBUFS (MAX_CAPBUFS_H264 + DISPLAY_LAG)
299 #define MIN(a, b) ((a < b) ? a : b)
301 #define DEVICE_NAME "cardx"
303 //#define DEBUG
304 #ifdef DEBUG
305 #define debug_printf(fmt, arg...) printf(fmt, ##arg);
306 #else
307 #define debug_printf(fmt, arg...)
308 #endif
310 /* Enable the below option for converting YUV422 decoded output to NV12 format*/
311 #define CC_YUV422PLANAR_TO_NV12
313 #define PROFILE
314 #ifdef PROFILE
315 #define perf_printf(fmt, arg...) printf(fmt, ##arg);
316 #else
317         perf_printf(fmt, arg...)
318 #endif
320 static int drmfd1 = -1;
321 #define FMT_NUM_PLANES 1 /* Used when creating V4l2 buffers for capture buffers */
323 /*
324  * @bo_handle: drm buffer handle
325  * @dbuf_fd: dma buffer handle
326  * @mapped: Pointer to mmap'ed buffer memory
327  * @offset: offset of buffer
328  * @length: Buffer length for munmap
329  */
330 struct buffer {
331         unsigned int bo_handle;
332         int dbuf_fd;
333         void *mapped;
334         int offset;
335         int length;
336 };
338 struct stream_context
340         size_t frame_sizes[MAX_FRAMES];
341         int width;
342         int height;
343         int bitdepth;
344         int num_bytes_per_pix;
345         enum AVPixelFormat pix_fmt;
346         enum AVCodecID codec;
347 };
349 /*
350  *
351  * @fourcc: The V4L2 fourcc value
352  * @size_num: The numerator to multiply image size by
353  * @size_den: The denominator to divide image size by
354  */
355 struct output_format
357         uint32_t fourcc;
358         int size_num;
359         int size_den;
360 };
362 static void errno_exit(const char *s)
364         printf("%s error %d, %s\n", s, errno, strerror(errno));
365         exit(EXIT_FAILURE);
368 static int handle_outbuf(int fd, int index, int rdfd, struct buffer buff,
369         struct stream_context *str, int nframes, int sleep_time)
371         struct v4l2_buffer buf;
372         struct v4l2_plane buf_planes[1];
373         struct v4l2_decoder_cmd cmd = {};
374         int ret = 0;
375         int send_cmd = 0;
376         static int fs_ind = 0;
378         memset(buff.mapped, 0, (str->width * str->height));
379         read(rdfd, buff.mapped, str->frame_sizes[fs_ind]);
381         memzero(buf);
382         memzero(buf_planes[0]);
384         buf_planes[0].bytesused = str->frame_sizes[fs_ind];
385         buf_planes[0].m.mem_offset = buff.offset;
386         buf_planes[0].data_offset = 0;
388         fs_ind++;
390         /* Stop queueing OUTPUT buffers if no more content */
391         if (fs_ind > nframes)
392                 return ret;
394         if (fs_ind == nframes) {
395                 debug_printf("[fd%d] handle_outbuf sending DEC_CMD_STOP\n", fd);
396                 cmd.cmd = V4L2_DEC_CMD_STOP;
397                 ret = ioctl(fd, VIDIOC_TRY_DECODER_CMD, &cmd);
398                 if (ret < 0) {
399                         printf("[fd%d] handle_outbuf TRY_DECODER_CMD failed trying FLAG_LAST ret=%d err=%s\n",
400                                         fd, ret, strerror(errno));
401                         buf.flags |= V4L2_BUF_FLAG_LAST;
402                 } else {
403                         send_cmd = 1;
404                 }
405         }
407         buf.index = index;
408         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
409         buf.memory = V4L2_MEMORY_MMAP;
410         buf.m.planes = buf_planes;
411         buf.length = 1;
413         ret = ioctl(fd, VIDIOC_QBUF, &buf);
414         if (ret < 0)
415                 printf("[fd%d] handle_outbuf QBUF failed ret=%d err=%s\n",
416                                 fd, ret, strerror(errno));
417         else
418                 debug_printf("[fd%d] handle_outbuf QBUF success\n", fd);
420         if (send_cmd) {
421                 debug_printf("[fd%d] handle_outbuf sending DEC_CMD_STOP after %d ms delay\n", fd, sleep_time / 1000);
422                 usleep(sleep_time);
423                 cmd.cmd = V4L2_DEC_CMD_STOP;
424                 ret = ioctl(fd, VIDIOC_DECODER_CMD, &cmd);
425                 if (ret < 0)
426                         printf("[fd%d] handle_outbuf DECODER_CMD failed ret=%d err=%s\n",
427                                         fd, ret, strerror(errno));
428         }
430         return ret;
433 static int handle_capbuf(int fd, int wrfd, int index, struct buffer buff,
434                 int save, struct stream_context *str, struct output_format fmt, int usedrmbuff)
436         struct v4l2_buffer buf;
437         struct v4l2_plane buf_planes[1];
438         int ret = 0;
439         int i;
440         int h = ALIGN(str->height, HW_ALIGN);
441         int s = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
443         if(save && (wrfd >= 0))
444         {
445                 switch (fmt.fourcc) {
446                         case (V4L2_PIX_FMT_NV12):
447                         case (V4L2_PIX_FMT_TI1210):
448                                 /*
449                                 for(i=0; i<str->height; i++)
450                                         write(wrfd, buff.mapped + (i * s),
451                                                         str->width);
453                                 for(i=0; i<(str->height/2); i++)
454                                         write(wrfd, buff.mapped + (h * s) +
455                                                         (i * s), str->width);
456                                 */
457                                 for(i=0; i<str->height; i++)
458                                         write(wrfd, buff.mapped + (i * s),
459                                                         (str->width *
460                                                          str->num_bytes_per_pix));
462                                 for(i=0; i<(str->height/2); i++)
463                                         write(wrfd, buff.mapped + (h * s) +
464                                                         (i * s),
465                                                         (str->width *
466                                                          str->num_bytes_per_pix));
467                                 break;
468                         case (V4L2_PIX_FMT_NV16):
469                         case (V4L2_PIX_FMT_TI1610):
470 #ifdef CC_YUV422PLANAR_TO_NV12
471                                 for (i = 0; i < str->height; i++)
472                                         write(wrfd, buff.mapped + (i * s),
473                                                 str->width * str->num_bytes_per_pix);
474                                 for (i = 0; i < str->height; i+=2)
475                                         write(wrfd, buff.mapped + (h * s) + (i * s), str->width * str->num_bytes_per_pix);
477 #else
478                                 for (i = 0; i < str->height; i++)
479                                         write(wrfd, buff.mapped + (i * s),
480                                                         2* str->width * str->num_bytes_per_pix);
481 #endif
482                                 break;
483                         default:
484                                 break;
485                 }
486         }
488         memzero(buf);
489         memzero(buf_planes[0]);
491         buf_planes[0].m.fd = buff.dbuf_fd;
492         buf_planes[0].length = buff.length;
494         buf.index = index;
495         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
496         if (usedrmbuff == 0) {
497                 /* Using v4l2 buffers for capture */
498                 buf.memory = V4L2_MEMORY_MMAP;
499         } else {
500                 /* Using drm buffers for capture */
501                 buf.memory = V4L2_MEMORY_DMABUF;
502         }
503         buf.m.planes = buf_planes;
504         buf.length = 1;
506         ret = ioctl(fd, VIDIOC_QBUF, &buf);
507         if (ret < 0)
508                 printf("[fd%d] handle_capbuf QBUF failed ret=%d err=%s\n",
509                                 fd, ret, strerror(errno));
510         else
511                 debug_printf("[fd%d] handle_capbuf QBUF success\n", fd);
513         return ret;
516 static int mainloop(int fd, int rdfd, int wrfd,
517                 struct stream_context *str, struct buffer outbufs[],
518                 struct buffer capbufs[], int n_outbufs,
519                 int n_capbufs, int nframes, int enable_prof,
520                 struct output_format fmt, int sleep_time, int usedrmbuff)
522         int type, i, ret = 0;
523         uint32_t flags = 0;
524         struct v4l2_buffer buf;
525         struct v4l2_plane buf_planes[2];
526         struct pollfd pfd;
527         struct timeval times;
528         long curr_time = 0;
529         static long prev_time = 0;
530         struct v4l2_event event;
532         debug_printf("[fd%d] MAINLOOP\n", fd);
534         pfd.fd = fd;
535         pfd.events = POLLIN | POLLOUT | POLLPRI;
536         pfd.revents = 0;
538         for (i = 0; i < n_outbufs; i++)
539                 handle_outbuf(fd, i, rdfd, outbufs[i], str, nframes, 0);
541         for (i = 0; i < n_capbufs; i++)
542                 handle_capbuf(fd, wrfd, i, capbufs[i], 0, str, fmt, usedrmbuff);
544         type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
545         ret = ioctl(fd, VIDIOC_STREAMON, &type);
546         if (ret) {
547                 printf("[fd%d] OUTPUT VIDIOC_STREAMON failed with ret %d\n",
548                         fd, ret);
549                 return ret;
550         }
552         type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
553         ret = ioctl(fd, VIDIOC_STREAMON, &type);
554         if (ret)
555                 printf("[fd%d] CAPTURE VIDIOC_STREAMON failed with ret %d\n",
556                         fd, ret);
558         i = 0;
559         while (!(flags & V4L2_BUF_FLAG_LAST)) {
560                 pfd.revents = 0;
562                 /* Poll for any event for 100ms */
563                 ret = poll(&pfd, 1, 100);
564                 if (ret < 0) {
565                         printf("poll had an error %d: %s\n",
566                                 errno, strerror(errno));
567                 } else if (ret > 0) {
568                         if (pfd.revents & POLLOUT) {
569                                 while (1) {
570                                         /* Check for OUTPUT buffer */
571                                         memzero(buf);
572                                         buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
573                                         buf.memory = V4L2_MEMORY_MMAP;
574                                         buf.m.planes = buf_planes;
575                                         buf.length = 1;
576                                         ret = ioctl(fd, VIDIOC_DQBUF, &buf);
577                                         if (ret < 0) {
578                                                 if (errno != EAGAIN) {
579                                                         printf("[fd%d] OUTPUT VIDIOC_DQBUF failed: ret=%d errno=%d: %s\n",
580                                                                 fd, ret, errno,
581                                                                 strerror(errno));
582                                                 } else {
583                                                         debug_printf("[fd%d] OUTPUT EAGAIN\n", fd);
584                                                         break;
585                                                 }
586                                         } else {
587                                                 handle_outbuf(fd, buf.index, rdfd,
588                                                                 outbufs[buf.index],
589                                                                 str, nframes,
590                                                                 sleep_time);
591                                         }
592                                 }
593                         }
594                         if (pfd.revents & POLLIN) {
595                                 while (1) {
596                                         /* Check for CAPTURE buffer */
597                                         memzero(buf);
598                                         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
599                                         if (usedrmbuff == 0) {
600                                                 /* Using v4l2 bufffers for capture */
601                                                 buf.memory = V4L2_MEMORY_MMAP;
602                                         } else {
603                                                 /* Using drm buffers for capture */
604                                                 buf.memory = V4L2_MEMORY_DMABUF;
605                                         }
606                                         buf.m.planes = buf_planes;
607                                         buf.length = 2;
608                                         ret = ioctl(fd, VIDIOC_DQBUF, &buf);
609                                         if (ret < 0) {
610                                                 if (errno != EAGAIN) {
611                                                         printf("[fd%d] CAPTURE VIDIOC_DQBUF failed: ret=%d errno=%d: %s\n",
612                                                                 fd, ret, errno,
613                                                                 strerror(errno));
614                                                 } else {
615                                                         debug_printf("[fd%d] CAPTURE EAGAIN\n", fd);
616                                                         break;
617                                                 }
618                                         } else {
619                                                 if (enable_prof) {
620                                                         gettimeofday(&times, NULL);
621                                                         curr_time =
622                                                         (times.tv_sec * 1000000 + times.tv_usec);
624                                                         perf_printf("Picture buffer dequeue time is %ld us\n",
625                                                                         (curr_time - prev_time));
627                                                         prev_time = curr_time;
628                                                 }
629                                                 debug_printf("[fd%d] CAPTURE VIDIOC_DQBUF bytesused=%d\n",
630                                                                 fd, buf.m.planes[0].bytesused);
631                                                 if (buf.m.planes[0].bytesused)
632                                                         handle_capbuf(fd, wrfd,
633                                                                       buf.index,
634                                                                       capbufs[buf.index],
635                                                                       1, str,
636                                                                       fmt, usedrmbuff);
637                                                 flags = buf.flags;
638                                                 debug_printf("[fd%d] CAPTURE VIDIOC_DQBUF buffer %d flags=%08x FLAG_LAST=%08x\n",
639                                                                 fd, buf.index,
640                                                                 flags,
641                                                                 V4L2_BUF_FLAG_LAST);
642                                                 if (buf.flags & V4L2_BUF_FLAG_LAST)
643                                                         break;
644                                         }
645                                 }
646                         }
647                         if (pfd.revents & POLLPRI) {
648                                 /* Check for events */
649                                 memzero(event);
650                                 ret = ioctl(fd, VIDIOC_DQEVENT, &event);
651                                 if (ret < 0) {
652                                         printf("[fd%d] VIDIOC_DQEVENT failed:: ret=%d errno=%d: %s\n",
653                                                         fd, ret, errno,
654                                                         strerror(errno));
655                                 } else if (event.type == V4L2_EVENT_EOS) {
656                                         debug_printf("[fd%d] GOT EVENT\n", fd);
657                                 } else {
658                                         printf("[fd%d] VIDIOC_DQEVENT got unexpected event %d\n",
659                                                         fd, event.type);
660                                 }
661                         }
662                 }
663         }
665         debug_printf("Stream ended, calling STREAMOFF\n");
666         type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
667         ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
668         if (ret) {
669                 printf("[fd%d] VIDIOC_STREAMOFF on OUTPUT failed with ret %d\n",
670                                 fd, ret);
671                 return ret;
672         }
674         type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
675         ret = ioctl(fd, VIDIOC_STREAMOFF, &type);
676         if (ret)
677                 printf("[fd%d] VIDIOC_STREAMOFF on CAPTURE failed with ret %d\n",
678                                 fd, ret);
680         return ret;
683 static void uninit_device(int fd, struct buffer outbufs[],
684                 struct buffer capbufs[], int *n_outbufs, int *n_capbufs, int usedrmbuff)
686         struct drm_mode_destroy_dumb gem_destroy;
687         int i, ret = 0;
688         struct v4l2_event_subscription sub;
690         debug_printf("[fd%d] uninit_device\n", fd);
692         for (i = 0; i < *n_outbufs; i++) {
693                 debug_printf("[fd%d] munmap outbuf %d mapped=0x%p length=%d\n",
694                                 fd, i, outbufs[i].mapped, outbufs[i].length);
695                 ret = munmap(outbufs[i].mapped, outbufs[i].length);
696                 if (ret) {
697                         printf("[fd%d] munmap failed for outbuf %d: %d %s\n",
698                                         fd, i, errno, strerror(errno));
699                 }
700         }
702 /* For unint capbufs, check which was used, drm or v4l2*/
703         if (usedrmbuff == 0) {
704                 /* Using v4l2 bufffers for capture */
705                 for (i = 0; i < *n_capbufs; i++) {
706                         debug_printf("[fd%d] munmap capbuf %d mapped=0x%p length=%d\n", fd, i, capbufs[i].mapped, capbufs[i].length);
707                         ret = munmap(capbufs[i].mapped, capbufs[i].length);
708                         if (ret) {
709                                 printf("[fd%d] munmap failed for capbuf %d: %d %s\n", fd, i, errno, strerror(errno));
710                         }
711                 }
712         } else {
713                 /* Using drm bufffers for capture */
714                 for (i = 0; i < *n_capbufs; i++) {
715                         debug_printf("[fd%d] munmap capbuf %d mapped=0x%p length=%d\n", fd, i, capbufs[i].mapped, capbufs[i].length);
716                         ret = munmap(capbufs[i].mapped, capbufs[i].length);
717                         if (ret) {
718                                 printf("[fd%d] munmap failed for  %d: %d %s\n", fd, i, errno, strerror(errno));
719                         }
720                         debug_printf("[fd%d] destroy gem capbuf %d handle=%d\n",
721                                         fd, i, capbufs[i].bo_handle);
722                         memset(&gem_destroy, 0, sizeof(gem_destroy));
723                         gem_destroy.handle = capbufs[i].bo_handle;
724                         ret = ioctl(drmfd1, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy);
725                         if (ret)
726                                 printf("    DRM_IOCTL_MODE_DESTROY_DUMB failed\n");
727                 }
728         }
730         memset(&sub, 0, sizeof(sub));
731         sub.type = V4L2_EVENT_ALL;
733         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n", fd);
734         ret = ioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
735         if (ret != 0) {
736                 printf("[fd%d] Failed to unsubscribe to events: err: %d %s\n",
737                                 fd, errno, strerror(errno));
738         }
741 static int create_drm_buffer(struct buffer *b,
742         unsigned int width, unsigned int height)
744         struct drm_mode_create_dumb gem;
745         struct drm_mode_map_dumb gem_map;
746         struct drm_mode_destroy_dumb gem_destroy;
747         int ret;
749         memset(&gem, 0, sizeof gem);
750         gem.width = width;
751         gem.height = height;
752         gem.bpp = 8;
754         ret = ioctl(drmfd1, DRM_IOCTL_MODE_CREATE_DUMB, &gem);
755         if (ret) {
756                 printf("    DRM_IOCTL_MODE_CREATE_DUMB failed\n");
757                 return ret;
758         }
760         b->bo_handle = gem.handle;
762         struct drm_prime_handle prime;
763         memset(&prime, 0, sizeof prime);
764         prime.handle = b->bo_handle;
766         ret = ioctl(drmfd1, DRM_IOCTL_PRIME_HANDLE_TO_FD, &prime);
767         if (ret) {
768                 printf("    DRM_IOCTL_PRIME_HANDLE_TO_FD failed\n");
769                 goto fail_gem;
770         }
771         b->dbuf_fd = prime.fd;
773         memset(&gem_map, 0, sizeof(gem_map));
774         gem_map.handle = gem.handle;
776         ret = ioctl(drmfd1, DRM_IOCTL_MODE_MAP_DUMB, &gem_map);
777         if (ret) {
778                 printf("    DRM_IOCTL_MODE_MAP_DUMB failed\n");
779                 goto fail_gem;
780         }
782         b->mapped = mmap(NULL, (size_t)gem.size, PROT_READ,
783                         MAP_SHARED, drmfd1, gem_map.offset);
784         if (MAP_FAILED == b->mapped) {
785                 printf("    mmap failed %d: %s\n", errno, strerror(errno));
786                 goto fail_gem;
787         }
788         b->offset = gem_map.offset;
789         b->length = gem.size;
791         return 0;
792 fail_gem:
793         memset(&gem_destroy, 0, sizeof gem_destroy);
794         gem_destroy.handle = b->bo_handle;
795         ret = ioctl(drmfd1, DRM_IOCTL_MODE_DESTROY_DUMB, &gem_destroy);
797         return ret;
800 int stream_framelevel_parsing(struct stream_context *str, char *input_file, int max_frames)
802         struct demux *demux;
803         int inp_buf_len = 0;
804         int inp_width, inp_height;
805         int frame_num = 0;
806         int frame_size = 0;
807         int bitdepth = 0;
808         enum AVPixelFormat pix_fmt;
809         enum AVCodecID codec;
811         /* Demux initialization */
812         demux = demux_init(input_file, &inp_width, &inp_height, &bitdepth, &pix_fmt, &codec);
813         if (!demux)
814         {
815                 printf("%s: could not open demuxer\n", __FUNCTION__);
816                 return -1;
817         }
819         debug_printf("\n%s: bitdepth: %d\n",__FUNCTION__, bitdepth);
820         debug_printf("%s: pix_fmt: %d\n",__FUNCTION__, pix_fmt);
821         debug_printf("%s: pix_fmt_string: %s\n",__FUNCTION__, pix_fmt != AV_PIX_FMT_NONE ?
822                         av_pix_fmt_descriptors[pix_fmt].name : "unknown");
823         debug_printf("\n%s: codec: %d\n",__FUNCTION__, codec);
824         if(codec == AV_CODEC_ID_H264)
825                 debug_printf("\n%s: codec: H264",__FUNCTION__);
826         if(codec == AV_CODEC_ID_HEVC)
827                 debug_printf("\n%s: codec format: HEVC\n",__FUNCTION__);
829         inp_buf_len = (inp_width * inp_height);
831         unsigned char *inp_buf = malloc(inp_buf_len);
832         if(inp_buf == NULL)
833         {
834                 printf("%s: Memory allocation failed for inp_buf\n",
835                                 __FUNCTION__);
836                 return -1;
837         }
839         debug_printf("%s: demuxer is initialized, width=%d, height=%d\n",
840                 __FUNCTION__, inp_width, inp_height);
841         str->width = inp_width;
842         str->height = inp_height;
843         str->bitdepth = bitdepth;
844         str->pix_fmt = pix_fmt;
845         str->codec = codec;
847         if(bitdepth == 8 || pix_fmt == AV_PIX_FMT_YUV420P ||
848                         pix_fmt == AV_PIX_FMT_YUV422P)
849                 str->num_bytes_per_pix = 1;
850         if(bitdepth == 10 || pix_fmt == AV_PIX_FMT_YUV420P10LE ||
851                         pix_fmt == AV_PIX_FMT_YUV422P10LE)
852                 str->num_bytes_per_pix = 2;
854         /*read the frame size and store into array*/
855         while(1)
856         {
857                 frame_size = demux_read(demux, inp_buf, inp_buf_len);
858                 if (frame_size)
859                 {
860                         debug_printf("frame %d frame size in demux %d\n",
861                                 frame_num, frame_size);
862                         str->frame_sizes[frame_num] = frame_size;
863                         frame_num++;
864                 }
865                 else
866                 {
867                         /*if the input file contains less number frames*/
868                         break;
869                 }
870                 if (max_frames > 0 && frame_num >= max_frames)
871                         break;
872         }
874         /* Demux de-initialization */
875         demux_deinit(demux);
876         free(inp_buf);
878         debug_printf("H264 frame sizes update is done\n");
879         return frame_num;
882 static int init_device(int fd, int rdfd,
883                 struct stream_context *str, struct buffer outbufs[],
884                 struct buffer capbufs[], int *n_outbufs, int *n_capbufs,
885                 struct output_format format, int usedrmbuff)
887         struct v4l2_format fmt;
888         struct v4l2_requestbuffers reqbuf;
889         struct v4l2_buffer buffer;
890         struct v4l2_plane buf_planes[1];
891         int ret = 0;
892         int i, j;
893         /*for v4l2 based capture buffers*/
894         struct v4l2_buffer buffer_cap;
895         struct v4l2_plane buf_planes_cap[FMT_NUM_PLANES];
897         debug_printf("[fd%d] init_device\n", fd);
899         memzero(fmt);
900         fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
901         fmt.fmt.pix_mp.width = str->width;
902         fmt.fmt.pix_mp.height = str->height;
903         fmt.fmt.pix_mp.plane_fmt[0].sizeimage = (str->width * str->height);
904         fmt.fmt.pix_mp.num_planes = 1;
906         if(str->codec == AV_CODEC_ID_H264)
907                 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
908         if(str->codec == AV_CODEC_ID_HEVC)
909                 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_HEVC;
911         ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
912         if (ret != 0) {
913                 printf("[fd%d] VIDIOC_S_FMT errorno %d, %s\n",
914                         fd, errno, strerror(errno));
915                 return ret;
916         }
918         debug_printf("[fd%d] After S_FMT on OUTPUT\n", fd);
920         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
921         fmt.fmt.pix_mp.pixelformat = format.fourcc;
922         fmt.fmt.pix_mp.plane_fmt[0].sizeimage =
923                 ((fmt.fmt.pix_mp.width * fmt.fmt.pix_mp.height) *
924                  format.size_num) * (str->num_bytes_per_pix) / format.size_den;
925         fmt.fmt.pix_mp.width = ALIGN(str->width, HW_ALIGN);
926         fmt.fmt.pix_mp.height = ALIGN(str->height, HW_ALIGN);
927         fmt.fmt.pix_mp.num_planes = 1;
928         fmt.fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(str->width, HW_ALIGN) * str->num_bytes_per_pix;
930         ret = ioctl(fd, VIDIOC_S_FMT, &fmt);
931         if (ret) {
932                 printf("[fd%d] VIDIOC_S_FMT errorno %d, %s\n",
933                         fd, errno, strerror(errno));
934                 return ret;
935         }
937         debug_printf("[fd%d] After S_FMT on CAPTURE\n", fd);
939         fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
941         ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
942         if (ret) {
943                 printf("[fd%d] VIDIOC_G_FMT errorno %d, %s\n",
944                         fd, errno, strerror(errno));
945                 return ret;
946         }
948         debug_printf("[fd%d] After G_FMT on OUTPUT\n", fd);
949         debug_printf("[fd%d] After G_FMT fmt.fmt.pix_mp.pixelformat = %c%c%c%c numplanes %d\n",
950                         fd, fmt.fmt.pix_mp.pixelformat & 0xff,
951                         (fmt.fmt.pix_mp.pixelformat >> 8) & 0xff,
952                         (fmt.fmt.pix_mp.pixelformat >>16) & 0xff,
953                         (fmt.fmt.pix_mp.pixelformat >> 24) & 0xff,
954                         fmt.fmt.pix_mp.num_planes);
956         debug_printf("[fd%d] fmt.fmt.pix_mp.width %d fmt.fmt.pix_mp.height %d"
957                         " sizeimage %d bytesperline %d\n",
958                         fd, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
959                         fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
960                         fmt.fmt.pix_mp.plane_fmt[0].bytesperline);
962         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
964         ret = ioctl(fd, VIDIOC_G_FMT, &fmt);
965         if (ret) {
966                 printf("[fd%d] VIDIOC_G_FMT errorno %d, %s\n",
967                         fd, errno, strerror(errno));
968                 return ret;
969         }
971         debug_printf("[fd%d] After G_FMT on CAPTURE\n", fd);
972         debug_printf("[fd%d] After G_FMT fmt.fmt.pix_mp.pixelformat = %c%c%c%c numplanes %d\n",
973                         fd, fmt.fmt.pix_mp.pixelformat & 0xff,
974                         (fmt.fmt.pix_mp.pixelformat >> 8) & 0xff,
975                         (fmt.fmt.pix_mp.pixelformat >>16) & 0xff,
976                         (fmt.fmt.pix_mp.pixelformat >> 24) & 0xff,
977                         fmt.fmt.pix_mp.num_planes);
979         debug_printf("[fd%d] fmt.fmt.pix_mp.width %d fmt.fmt.pix_mp.height %d"
980                         " sizeimage %d bytesperline %d\n",
981                         fd, fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height,
982                         fmt.fmt.pix_mp.plane_fmt[1].sizeimage,
983                         fmt.fmt.pix_mp.plane_fmt[1].bytesperline);
985         /* Setup Decoder OUTPUT (SRC buffer) through VIDIOC_REQBUFS */
986         debug_printf("[fd%d] Setup decoding OUTPUT with VIDIOC_REQBUFS buffer size %u\n",
987                 fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
989         memzero(reqbuf);
990         reqbuf.count = *n_outbufs;
991         reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
992         reqbuf.memory = V4L2_MEMORY_MMAP;
994         ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
995         if (ret) {
996                 printf("[fd%d] Err REQBUFS failed on OUTPUT queue ret %d errno %d\n",
997                         fd, ret, errno);
998                 return ret;
999         }
1000         debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1001                 fd, reqbuf.count);
1002         *n_outbufs = reqbuf.count;
1004         /* QUERYBUF on OUTPUT - memory of V4L2_MEMORY_MMAP */
1005         for (i = 0; i < *n_outbufs; i++) {
1006                 memset(&buffer, 0, sizeof(buffer));
1007                 buffer.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1008                 buffer.index = i;
1009                 buffer.m.planes = buf_planes;
1010                 buffer.length = 1;
1012                 ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer);
1013                 if (ret < 0) {
1014                         printf("[fd%d] CANNOT QUERY BUFFERS ret = %d\n",
1015                                 fd, ret);
1016                         return -1;
1017                 }
1019                 debug_printf("[fd%d] query buf, buffer %p plane 0 = %d buffer.length %d buffer.data_offset %d buffer.mem_offset %d\n",
1020                                 fd, &buffer, buffer.m.planes[0].length,
1021                                 buffer.length, buffer.m.planes[0].data_offset,
1022                                 buffer.m.planes[0].m.mem_offset);
1024                 outbufs[i].mapped = mmap(NULL, buffer.m.planes[0].length,
1025                                 PROT_READ | PROT_WRITE, MAP_SHARED,
1026                                 fd, buffer.m.planes[0].m.mem_offset);
1027                 outbufs[i].offset = buffer.m.planes[0].m.mem_offset;
1028                 outbufs[i].length = buffer.m.planes[0].length;
1030                 debug_printf("[fd%d] After mmap -> outbufs[%d].mapped = 0x%p\n",
1031                         fd, i, outbufs[i].mapped);
1033                 if (MAP_FAILED == outbufs[i].mapped) {
1034                         while (i >= 0) {
1035                                 /* Unmap all previous buffers */
1036                                 i--;
1037                                 munmap(outbufs[i].mapped,
1038                                         fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1039                                 outbufs[i].mapped = NULL;
1040                         }
1041                         printf("[fd%d] Cant mmap buffers Y", fd);
1042                         return -1;
1043                 }
1044         }
1046         /* Setup Decoder CAPTURE (DST buffer) through VIDIOC_REQBUFS */
1048         if (usedrmbuff == 0) {
1049                 /* Setup Decoder CAPTURE (DST buffer) through VIDIOC_REQBUFS */
1050                 debug_printf("[fd%d] Setup decoding CAPTURE with VIDIOC_REQBUFS\n", fd);
1051                 debug_printf("[fd%d] buffer(y) size %u buffer(uv) size %u\n",
1052                                         fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
1053                                         fmt.fmt.pix_mp.plane_fmt[1].sizeimage);
1055                 memzero(reqbuf);
1056                 reqbuf.count = *n_capbufs;
1057                 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1058                 reqbuf.memory = V4L2_MEMORY_MMAP;
1060                 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
1061                 if (ret) {
1062                         printf("[fd%d] Err REQBUFS failed on CAPTURE queue ret %d errno %d\n",
1063                                 fd, ret, errno);
1064                         return ret;
1065                 }
1066                 debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1067                         fd, reqbuf.count);
1068                 *n_capbufs = reqbuf.count;
1069                 /*Creating Capbuffers with v4l2 BUFFERS*/
1070                 /* QUERYBUF on Capture - memory of V4L2_MEMORY_MMAP */
1071                 for (j = 0; j < *n_capbufs; j++) {
1072                         memset(&buffer_cap, 0, sizeof(buffer_cap));
1073                         buffer_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1074                         buffer_cap.index = j;
1075                         buffer_cap.m.planes = buf_planes_cap;
1076                         buffer_cap.length = FMT_NUM_PLANES;
1077                         buffer_cap.memory = V4L2_MEMORY_MMAP;
1079                         ret = ioctl(fd, VIDIOC_QUERYBUF, &buffer_cap);
1080                         if (ret < 0) {
1081                                 printf("[fd%d] CANNOT QUERY BUFFERS for Capture ret = %d\n",
1082                                                 fd, ret);
1083                                 return -1;
1084                         }
1085                         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",
1086                                         fd, &buffer_cap,
1087                                         buffer_cap.m.planes[0].length,
1088                                         buffer_cap.length,
1089                                         buffer_cap.m.planes[0].data_offset,
1090                                         buffer_cap.m.planes[0].m.mem_offset);
1092                         capbufs[j].mapped = mmap(NULL, buffer_cap.m.planes[0].length,
1093                                         PROT_READ, MAP_SHARED,
1094                                         fd, buffer_cap.m.planes[0].m.mem_offset);
1095                         capbufs[j].offset = buffer_cap.m.planes[0].m.mem_offset;
1096                         capbufs[j].length = buffer_cap.m.planes[0].length;
1098                         debug_printf("[fd%d] After mmap -> capbufs[%d].mapped = 0x%p\n",
1099                                         fd, j, capbufs[j].mapped);
1101                         if (MAP_FAILED == capbufs[j].mapped) {
1102                                 while (j >= 0) {
1103                                         /* Unmap all previous buffers */
1104                                         j--;
1105                                         munmap(capbufs[j].mapped,
1106                                                  fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
1107                                                  capbufs[j].mapped = NULL;
1108                                 }
1109                                 printf("[fd%d] Cant mmap capture buffers Y\n", fd);
1110                                 return -1;
1111                         }
1112                 }
1113         } else {
1114                 debug_printf("[fd%d] Setup decoding CAPTURE with VIDIOC_REQBUFS\n", fd);
1115                 debug_printf("[fd%d] buffer(y) size %u buffer(uv) size %u\n",
1116                                 fd, fmt.fmt.pix_mp.plane_fmt[0].sizeimage,
1117                                 fmt.fmt.pix_mp.plane_fmt[1].sizeimage);
1119                 memzero(reqbuf);
1120                 reqbuf.count = *n_capbufs;
1121                 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1122                 reqbuf.memory = V4L2_MEMORY_DMABUF;
1124                 ret = ioctl(fd, VIDIOC_REQBUFS, &reqbuf);
1125                 if (ret) {
1126                         printf("[fd%d] Err REQBUFS failed on CAPTURE queue ret %d errno %d\n",
1127                                         fd, ret, errno);
1128                         return ret;
1129                 }
1130                 debug_printf("[fd%d] After VIDIOC_REQBUFS getting buf_cnt %d\n",
1131                                 fd, reqbuf.count);
1132                 *n_capbufs = reqbuf.count;
1134                 /* Create DRM buffers */
1135                 for (i = 0; i < *n_capbufs; i++) {
1136                         ret = create_drm_buffer(&capbufs[i],
1137                                         ALIGN(fmt.fmt.pix_mp.width, HW_ALIGN),
1138                                         ((str->num_bytes_per_pix *
1139                                                 fmt.fmt.pix_mp.height * format.size_num) /
1140                                          format.size_den));
1141                         if (ret) {
1142                                 printf("[fd%d] failed to create drm buffers\n", fd);
1143                                 return -1;
1144                         }
1145                         debug_printf("[fd%d] Create_DRM_BUFFERS drm_y_buffer[%d].dbuf_fd 0x%x\n",
1146                                         fd, i, capbufs[i].dbuf_fd);
1147                 }
1148         }
1149         return ret;
1152 static void close_device(int fd)
1154         debug_printf("[fd%d] close_device\n", fd);
1155         if (-1 == close(fd))
1156                 errno_exit ("close");
1157         fd = -1;
1160 static int open_device(char *dev_name)
1162         struct v4l2_capability cap;
1163         struct v4l2_fmtdesc argp;
1164         int ret = 0;
1165         int fd = -1;
1166         struct v4l2_event_subscription sub;
1168         fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
1169         if (-1 == fd) {
1170                 printf("Cannot open '%s': %d, %s\n",
1171                                 dev_name, errno, strerror(errno));
1172                 return -1;
1173         }
1175         ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
1176         if (ret != 0) {
1177                 printf("Failed to verify capabilities\n");
1178                 return -1;
1179         }
1181         debug_printf("[fd%d] Info (%s): driver\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x\n",
1182                         fd, dev_name, cap.driver, cap.bus_info, cap.card, fd);
1184         debug_printf("[fd%d] Info (%s): capabilities\"0x%x\" device_caps=\"0x%x\" \n",
1185                         fd, dev_name, cap.capabilities, cap.device_caps);
1187         memset(&argp, 0, sizeof(argp));
1188         argp.index = 0;
1189         argp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1191         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_ENUM_FMT on CAPTURE\n",
1192                         fd);
1193         while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &argp)) == 0) {
1194                 debug_printf("[fd%d] argp.index = %d, {pixelformat = %c%c%c%c}, description = '%s'\n",
1195                                 fd, argp.index, argp.pixelformat & 0xff,
1196                                 (argp.pixelformat >> 8) & 0xff,
1197                                 (argp.pixelformat >>16) & 0xff,
1198                                 (argp.pixelformat >> 24) & 0xff,
1199                                 argp.description);
1200                 argp.index ++;
1201         }
1203         argp.index = 0;
1204         argp.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1206         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_ENUM_FMT on OUTPUT\n",
1207                         fd);
1208         while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &argp)) == 0) {
1209                 debug_printf("[fd%d] argp.index = %d, {pixelformat = %c%c%c%c}, description = '%s'\n",
1210                                 fd, argp.index, argp.pixelformat & 0xff,
1211                                 (argp.pixelformat >> 8) & 0xff,
1212                                 (argp.pixelformat >>16) & 0xff,
1213                                 (argp.pixelformat >> 24) & 0xff,
1214                                 argp.description);
1215                 argp.index ++;
1216         }
1218         memset(&sub, 0, sizeof(sub));
1219         sub.type = V4L2_EVENT_EOS;
1221         debug_printf("[fd%d] Calling V4L2 IOCTL VIDIOC_SUBSCRIBE_EVENT\n", fd);
1222         ret = ioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
1223         if (ret != 0) {
1224                 printf("[fd%d] Failed to subscribe to events: err: %d %s\n",
1225                                 fd, errno, strerror(errno));
1226         }
1228         return fd;
1231 int main(int argc, char **argv)
1233         char *dev_name = "/dev/video0";
1234         int i = 0;
1235         int ret = 0;
1236         unsigned int num_devs = 1;
1237         int fds[MAX_TEST_FDS];
1238         int rdfd = -1;
1239         int wrfd = -1;
1240         int c;
1241         int n_outbufs, n_capbufs, n_frames;
1242         struct buffer outbufs[MAX_OUTBUFS];
1243         struct buffer capbufs[MAX_CAPBUFS];
1244         struct stream_context str_context;
1245         char input_file[256];
1246         char output_file_base[120];
1247         char output_file[128];
1248         const char *dir_path = "/dev/dri/";
1249         char drm_file_name[20];
1250         DIR *d;
1251         struct dirent *dir;
1252         drmModeResPtr res;
1253         int max_frames = -1;
1254         int enable_prof = 0;
1255         int sleep_time = 0;
1256         struct output_format fmt;
1257         int use_drm_capbuff = 1; /* Defaulting to use drm dss Capture Buffers */
1259         printf("TI DEC V4L2 Codec decoding example application\n");
1260         printf("Copyright (c) 2018 Texas Instruments, Inc.\n");
1262         /* Parse the input args */
1263         while (1)
1264         {
1265                 c = getopt (argc, argv, "nf:hbi:o:d:te:");
1266                 if (c == -1)
1267                         break;
1269                 switch (c) {
1270                         case 'n':
1271                                 num_devs = atoi(optarg);
1272                                 break;
1273                         case 'h':
1274                                 printf("Use:\n");
1275                                 printf("\t./tidec_decode -i <input_file> [OPTIONS]\n");
1276                                 printf("\tThe final output file/s will be '<output_file_base>_xx.out'\n");
1277                                 printf("\twhere xx ranges from 00, 01, 02, ...\n");
1278                                 printf("\tdepending on how many fds are specified to -n\n");
1279                                 printf("\tOPTIONS:\n");
1280                                 printf("\t\t-h help\n");
1281                                 printf("\t\t-b DO NOT use drm dss device capture buffer (instead, use v4l2)\n");
1282                                 printf("\t\t-n <number> number of fds to open\n");
1283                                 printf("\t\t-o <output_file_base> Dump output stream to file\n");
1284                                 printf("\t\t\tThe final output file/s will be '<output_file_base>_xx.out'\n");
1285                                 printf("\t\t\twhere xx ranges from 00, 01, 02, ...\n");
1286                                 printf("\t\t\tdepending on how many fds are specified to -n\n");
1287                                 printf("\t\t-f <number of frames to decode> Maximum number of frames to decode\n");
1288                                 printf("\t\t-d <path> Path to which drm device to use for buffer allocation\n");
1289                                 printf("\t\t-t for enable time profiling\n");
1290                                 printf("\t\t-e <number of ms> Number of milliseconds to sleep between\n");
1291                                 printf("\t\t\tqueueing the last bitstream buffer and sending CMD_STOP\n");
1292                                 printf("\t\t\tUsed to test various timing scenarios for EOS\n");
1293                                 break;
1294                         case 'b':
1295                                 use_drm_capbuff = 0; /* DO NOT use drm dss device*/
1296                                 break;
1297                         case 'i':
1298                                 snprintf(input_file, sizeof(input_file),
1299                                                 "%s", optarg);
1300                                 break;
1301                         case 'o':
1302                                 snprintf(output_file_base,
1303                                                 sizeof(output_file_base),
1304                                                 "%s", optarg);
1305                                 break;
1306                         case 'f':
1307                                 max_frames = atoi(optarg);
1308                                 break;
1309                         case 'd':
1310                                 snprintf(drm_file_name, sizeof(drm_file_name),
1311                                                 "%s", optarg);
1312                                 break;
1313                         case 't':
1314                                 enable_prof = 1;
1315                                 break;
1316                         case 'e':
1317                                 sleep_time = 1000 * atoi(optarg);
1318                                 break;
1319                         default:
1320                                 printf("Unrecognized argument %c\n", c);
1321                 }
1322         }
1324         if (0 == strlen(input_file)) {
1325                 printf("Requires an input value\n");
1326                 printf("\t./tidec_decode -i <input_file> [OPTIONS]\n");
1327                 return EXIT_FAILURE;
1328         }
1330         /* validate input args */
1331         if (num_devs > MAX_TEST_FDS) {
1332                 printf("Invalid value passed for number of devices %d\n",
1333                                 num_devs);
1334                 return EXIT_FAILURE;
1335         }
1337         for (i = 0; i < num_devs; i++) {
1338                 debug_printf("*** Calling open_device for device %d \n", i);
1339                 fds[i] = open_device(dev_name);
1340                 if (fds[i] < 0)
1341                         return EXIT_FAILURE;
1342                 debug_printf("*** device %d is fd %d", i, fds[i]);
1343         }
1345         if (use_drm_capbuff == 0) {
1346                 printf("\nUsing v4l2 for capture buffers\n");
1347         } else {
1348                 if (strlen(drm_file_name) > 0) {
1349                         drmfd1 = open(drm_file_name, O_CLOEXEC);
1350                         if (drmfd1 < 0) {
1351                                 printf("Failed to open drm device\n");
1352                                 return EXIT_FAILURE;
1353                         }
1354                 } else {
1355                         d = opendir(dir_path);
1356                         if (!d) {
1357                                 printf("Failed to open drm device directory\n");
1358                                 return EXIT_FAILURE;
1359                         }
1360                         while ((dir = readdir(d)) != NULL) {
1361                                 if(strncmp(dir->d_name, DEVICE_NAME, 4) == 0) {
1362                                         strcpy(drm_file_name, dir_path);
1363                                         strncat(drm_file_name, dir->d_name,
1364                                                 sizeof(DEVICE_NAME));
1365                                         drmfd1 = open(drm_file_name, O_CLOEXEC);
1366                                         if (drmfd1 < 0) {
1367                                                 printf("Failed to open drm device %s\n",
1368                                                                 drm_file_name);
1369                                         }
1370                                         printf("No drm device specified, testing %s\n",
1371                                                         drm_file_name);
1372                                         res = drmModeGetResources(drmfd1);
1373                                         if (res && res->count_crtcs > 0 &&
1374                                                         res->count_connectors > 0 &&
1375                                                         res->count_encoders > 0) {
1376                                                 printf("No drm device specified, using %s\n",
1377                                                                 drm_file_name);
1378                                                 break;
1379                                         }
1380                                         close(drmfd1);
1381                                         drmfd1 = -1;
1382                                 }
1383                         }
1384                 }
1385                 if (drmfd1 < 0) {
1386                         printf("Failed to open drm device\n");
1387                         return EXIT_FAILURE;
1388                 }
1389         }
1391         /* Get the stream width, height and framesizes of H264 stream */
1392         n_frames = stream_framelevel_parsing(&str_context, input_file, max_frames);
1393         if (n_frames < 0) {
1394                 printf("Failed to init frame sizes\n");
1395                 return EXIT_FAILURE;
1396         }
1398         switch (str_context.pix_fmt) {
1399                 case AV_PIX_FMT_YUV420P:
1400                         fmt.fourcc = V4L2_PIX_FMT_NV12;
1401                         fmt.size_num = 3;
1402                         fmt.size_den = 2;
1403                         break;
1404                 case AV_PIX_FMT_YUV422P:
1405                         fmt.fourcc = V4L2_PIX_FMT_NV16;
1406                         fmt.size_num = 2;
1407                         fmt.size_den = 1;
1408                         break;
1409                 case AV_PIX_FMT_YUV420P10LE:
1410                         fmt.fourcc = V4L2_PIX_FMT_TI1210;
1411                         fmt.size_num = 3;
1412                         fmt.size_den = 2;
1413                         break;
1414                 case AV_PIX_FMT_YUV422P10LE:
1415                         fmt.fourcc = V4L2_PIX_FMT_TI1610;
1416                         fmt.size_num = 2;
1417                         fmt.size_den = 1;
1418                         break;
1419                 default:
1420                         printf("Invalid pixel format detected\n");
1421                         return -1;
1422         }
1424         for (i = 0; i < num_devs; i++) {
1425                 n_outbufs = MAX_OUTBUFS;
1426                 /* Request number of output buffers based on h264 spec
1427                  * + display delay */
1428                 n_capbufs = MIN(MAX_CAPBUFS_H264, (32768 /
1429                                         ((str_context.width / 16) *
1430                                         (str_context.height / 16)))) +
1431                                         DISPLAY_LAG;
1433                 debug_printf("Opening input file\n");
1434                 rdfd = open(input_file, O_RDONLY);
1435                 if (rdfd < 0) {
1436                         printf("Failed to open input file %s", input_file);
1437                 }
1439                 if (strcmp(output_file_base, "")) {
1440                         snprintf(output_file, sizeof(output_file),
1441                                         "%s_%02d.raw", output_file_base, i);
1442                         wrfd = open(output_file,
1443                                         O_CREAT | O_WRONLY | O_SYNC | O_TRUNC,
1444                                         0777);
1445                 }
1447                 if (wrfd < 0) {
1448                         if (strcmp(output_file_base, "")) {
1449                                 printf("Failed to open output file %s\n",
1450                                                 output_file);
1451                                 return EXIT_FAILURE;
1452                         } else {
1453                                 printf("No output file specified\n");
1454                         }
1455                 } else {
1456                         debug_printf("Opened output file %s\n", output_file);
1457                 }
1459                 ret = init_device(fds[i], rdfd, &str_context, outbufs,
1460                                 capbufs, &n_outbufs, &n_capbufs, fmt, use_drm_capbuff);
1461                 if (ret) {
1462                         printf("init_device failed with ret %d for device %d [fd%d]\n",
1463                                         ret, i, fds[i]);
1464                         return EXIT_FAILURE;
1465                 }
1467                 if (mainloop(fds[i], rdfd, wrfd, &str_context, outbufs,
1468                                         capbufs, n_outbufs,
1469                                         n_capbufs, n_frames,
1470                                         enable_prof, fmt,
1471                                         sleep_time, use_drm_capbuff)) {
1472                         return EXIT_FAILURE;
1473                 }
1475                 close(rdfd);
1476                 if (!(wrfd < 0))
1477                         close(wrfd);
1478                 rdfd = -1;
1479                 wrfd = -1;
1481                 uninit_device(fds[i], outbufs, capbufs, &n_outbufs, &n_capbufs, use_drm_capbuff);
1483                 debug_printf("*** Calling close_device for device %d [fd%d]\n",
1484                                 i, fds[i]);
1485                 close_device(fds[i]);
1486         }
1488         if (use_drm_capbuff && drmfd1)
1489                 close(drmfd1);
1491         printf("test app completed successfully\n");
1492         return 0;