blob: aee3e16df4fd7733379d177867ba37a14d797a70 [file] [log] [blame]
Fritz Koenig7d0e8412021-02-05 15:40:08 -08001/*
2 * Copyright 2021 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7// As per https://www.kernel.org/doc/html/v5.4/media/uapi/v4l/dev-decoder.html
8#include <ctype.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <getopt.h>
12#include <limits.h>
13#include <linux/videodev2.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <sys/ioctl.h>
19#include <sys/mman.h>
20#include <unistd.h>
21
22#include "bs_drm.h"
23
24static const char *kDecodeDevice = "/dev/video-dec0";
25static const int kInputbufferMaxSize = 4 * 1024 * 1024;
26static const int kRequestBufferCount = 8;
27static const uint32_t kIVFHeaderSignature = v4l2_fourcc('D', 'K', 'I', 'F');
28
29struct mmap_buffers {
30 void *start[VIDEO_MAX_PLANES];
31 size_t length[VIDEO_MAX_PLANES];
32 struct gbm_bo *bo;
33};
34
35struct queue {
36 int v4lfd;
37 enum v4l2_buf_type type;
38 uint32_t fourcc;
39 struct mmap_buffers *buffers;
40 uint32_t image_width;
41 uint32_t image_height;
42 uint32_t cnt;
43 uint32_t num_planes;
44 uint32_t memory;
45};
46
47struct ivf_file_header {
48 uint32_t signature;
49 uint16_t version;
50 uint16_t header_length;
51 uint32_t fourcc;
52 uint16_t width;
53 uint16_t height;
54 uint32_t denominator;
55 uint32_t numerator;
56 uint32_t frame_cnt;
57 uint32_t unused;
58} __attribute__((packed));
59
60struct ivf_frame_header {
61 uint32_t size;
62 uint64_t timestamp;
63} __attribute__((packed));
64
65struct compressed_file {
66 FILE *fp;
67 struct ivf_file_header header;
68 uint32_t submitted_frames;
69};
70
71void print_fourcc(uint32_t fourcc)
72{
73 printf("%c%c%c%c\n", fourcc & 0xff, fourcc >> 8 & 0xff, fourcc >> 16 & 0xff,
74 fourcc >> 24 & 0xff);
75}
76
77struct compressed_file open_file(const char *file_name)
78{
79 struct compressed_file file = { 0 };
80
81 FILE *fp = fopen(file_name, "rb");
82 if (fp) {
83 if (fread(&file.header, sizeof(struct ivf_file_header), 1, fp) != 1) {
84 fclose(fp);
85 fprintf(stderr, "unable to read ivf file header\n");
86 }
87
88 if (file.header.signature != kIVFHeaderSignature) {
89 fclose(fp);
90 fprintf(stderr, "Incorrect header signature : 0x%0x != 0x%0x\n",
91 file.header.signature, kIVFHeaderSignature);
92 }
93
94 file.fp = fp;
95 print_fourcc(file.header.fourcc);
96 printf("ivf file header: %d x %d\n", file.header.width, file.header.height);
97 } else {
98 fprintf(stderr, "unable to open file: %s\n", file_name);
99 }
100
101 return file;
102}
103
104int query_format(int v4lfd, enum v4l2_buf_type type, uint32_t fourcc)
105{
106 struct v4l2_fmtdesc fmtdesc;
107 memset(&fmtdesc, 0, sizeof(fmtdesc));
108
109 fmtdesc.type = type;
110 while (ioctl(v4lfd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
111 if (fourcc == 0)
112 print_fourcc(fmtdesc.pixelformat);
113 else if (fourcc == fmtdesc.pixelformat)
114 return 1;
115 fmtdesc.index++;
116 }
117
118 return 0;
119}
120
121int capabilities(int v4lfd, uint32_t compressed_format, uint32_t uncompressed_format)
122{
123 struct v4l2_capability cap;
124 memset(&cap, 0, sizeof(cap));
125 int ret = ioctl(v4lfd, VIDIOC_QUERYCAP, &cap);
126 if (ret != 0)
127 perror("VIDIOC_QUERYCAP failed");
128
129 printf("driver=\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x\n", cap.driver, cap.bus_info,
130 cap.card, v4lfd);
131
132 if (!query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, compressed_format)) {
133 printf("Supported compressed formats:\n");
134 query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 0);
135 ret = 1;
136 }
137
138 if (!query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, uncompressed_format)) {
139 printf("Supported uncompressed formats:\n");
140 query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 0);
141 ret = 1;
142 }
143
144 return ret;
145}
146
147int request_mmap_buffers(struct queue *queue, struct v4l2_requestbuffers *reqbuf)
148{
149 const int v4lfd = queue->v4lfd;
150 const uint32_t buffer_alloc = reqbuf->count * sizeof(struct mmap_buffers);
151 struct mmap_buffers *buffers = (struct mmap_buffers *)malloc(buffer_alloc);
152 memset(buffers, 0, buffer_alloc);
153 queue->buffers = buffers;
154 queue->cnt = reqbuf->count;
155
156 int ret;
157 for (uint32_t i = 0; i < reqbuf->count; i++) {
158 struct v4l2_buffer buffer;
159 struct v4l2_plane planes[VIDEO_MAX_PLANES];
160 memset(&buffer, 0, sizeof(buffer));
161 buffer.type = reqbuf->type;
162 buffer.memory = queue->memory;
163 buffer.index = i;
164 buffer.length = queue->num_planes;
165 buffer.m.planes = planes;
166 ret = ioctl(v4lfd, VIDIOC_QUERYBUF, &buffer);
167 if (ret != 0) {
168 printf("VIDIOC_QUERYBUF failed: %d\n", ret);
169 break;
170 }
171
172 for (uint32_t j = 0; j < queue->num_planes; j++) {
173 buffers[i].length[j] = buffer.m.planes[j].length;
174 buffers[i].start[j] =
175 mmap(NULL, buffer.m.planes[j].length, PROT_READ | PROT_WRITE,
176 MAP_SHARED, v4lfd, buffer.m.planes[j].m.mem_offset);
177 if (MAP_FAILED == buffers[i].start[j]) {
178 fprintf(stderr,
179 "failed to mmap buffer of length(%d) and offset(0x%x)\n",
180 buffer.m.planes[j].length, buffer.m.planes[j].m.mem_offset);
181 }
182 }
183 }
184
185 return ret;
186}
187
188// this is the input queue that will take compressed data
189// 4.5.1.5
190int setup_OUTPUT(struct queue *OUTPUT_queue)
191{
192 int ret = 0;
193
194 // 1. Set the coded format on OUTPUT via VIDIOC_S_FMT()
195 if (!ret) {
196 struct v4l2_format fmt;
197 memset(&fmt, 0, sizeof(fmt));
198
199 fmt.type = OUTPUT_queue->type;
200 fmt.fmt.pix_mp.pixelformat = OUTPUT_queue->fourcc;
201 fmt.fmt.pix_mp.plane_fmt[0].sizeimage = kInputbufferMaxSize;
202 fmt.fmt.pix_mp.num_planes = 1;
203
204 int ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_S_FMT, &fmt);
205 if (ret != 0)
206 perror("VIDIOC_S_FMT failed");
207 }
208
209 // 2. Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on OUTPUT.
210 if (!ret) {
211 struct v4l2_requestbuffers reqbuf;
212 memset(&reqbuf, 0, sizeof(reqbuf));
213 reqbuf.count = kRequestBufferCount;
214 reqbuf.type = OUTPUT_queue->type;
215 reqbuf.memory = OUTPUT_queue->memory;
216
217 ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_REQBUFS, &reqbuf);
218 if (ret != 0)
219 perror("VIDIOC_REQBUFS failed");
220
221 printf("%d buffers requested, %d buffers for compressed data returned\n",
222 kRequestBufferCount, reqbuf.count);
223
224 ret = request_mmap_buffers(OUTPUT_queue, &reqbuf);
225 }
226
227 // 3. Start streaming on the OUTPUT queue via VIDIOC_STREAMON().
228 if (!ret) {
229 ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_STREAMON, &OUTPUT_queue->type);
230 if (ret != 0)
231 perror("VIDIOC_STREAMON failed");
232 }
233
234 return ret;
235}
236
237int submit_compressed_frame(struct compressed_file *file, struct queue *OUTPUT_queue,
238 uint32_t index)
239{
240 const uint32_t num = file->header.numerator;
241 const uint32_t den = file->header.denominator;
242
243 struct ivf_frame_header frame_header = { 0 };
244 if (fread(&frame_header, sizeof(struct ivf_frame_header), 1, file->fp) != 1) {
245 if (!feof(file->fp))
246 fprintf(stderr, "unable to read ivf frame header\n");
247 return -1;
248 }
249
250 struct mmap_buffers *buffers = OUTPUT_queue->buffers;
251 if (fread(buffers[index].start[0], sizeof(uint8_t), frame_header.size, file->fp) !=
252 frame_header.size) {
253 fprintf(stderr, "unable to read ivf frame data\n");
254 return -1;
255 }
256
257 struct v4l2_buffer v4l2_buffer;
258 struct v4l2_plane planes[VIDEO_MAX_PLANES];
259 memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
260 v4l2_buffer.index = index;
261 v4l2_buffer.type = OUTPUT_queue->type;
262 v4l2_buffer.memory = OUTPUT_queue->memory;
263 v4l2_buffer.length = 1;
264 v4l2_buffer.timestamp.tv_sec = 0;
265 v4l2_buffer.timestamp.tv_usec = ((frame_header.timestamp * den) / num) * 100;
266 v4l2_buffer.m.planes = planes;
267 v4l2_buffer.m.planes[0].length = buffers[index].length[0];
268 v4l2_buffer.m.planes[0].bytesused = frame_header.size;
269 v4l2_buffer.m.planes[0].data_offset = 0;
270 int ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_QBUF, &v4l2_buffer);
271 if (ret != 0) {
272 perror("VIDIOC_QBUF failed");
273 return -1;
274 }
275
276 file->submitted_frames++;
277
278 return 0;
279}
280
281int prime_OUTPUT(struct compressed_file *file, struct queue *OUTPUT_queue)
282{
283 int ret = 0;
284
285 for (uint32_t i = 0; i < OUTPUT_queue->cnt; ++i) {
286 ret = submit_compressed_frame(file, OUTPUT_queue, i);
287 if (ret)
288 break;
289 }
290 return ret;
291}
292
293void cleanup_queue(struct queue *queue)
294{
295 if (queue->cnt) {
296 struct mmap_buffers *buffers = queue->buffers;
297
298 for (uint32_t i = 0; i < queue->cnt; i++)
299 for (uint32_t j = 0; j < queue->num_planes; j++) {
300 if (buffers[i].length[j])
301 munmap(buffers[i].start[j], buffers[i].length[j]);
302 if (buffers[i].bo)
303 gbm_bo_destroy(buffers[i].bo);
304 }
305
306 free(queue->buffers);
307 queue->cnt = 0;
308 }
309}
310
311int queue_buffer_CAPTURE(struct queue *queue, uint32_t index)
312{
313 struct v4l2_buffer v4l2_buffer;
314 struct v4l2_plane planes[VIDEO_MAX_PLANES];
315 memset(&v4l2_buffer, 0, sizeof v4l2_buffer);
316 memset(&planes, 0, sizeof planes);
317
318 v4l2_buffer.type = queue->type;
319 v4l2_buffer.memory = queue->memory;
320 v4l2_buffer.index = index;
321 v4l2_buffer.m.planes = planes;
322 v4l2_buffer.length = queue->num_planes;
323
324 struct gbm_bo *bo = queue->buffers[index].bo;
325 for (uint32_t i = 0; i < queue->num_planes; ++i) {
326 if (queue->memory == V4L2_MEMORY_DMABUF) {
327 v4l2_buffer.m.planes[i].m.fd = gbm_bo_get_plane_fd(bo, i);
328 } else if (queue->memory == V4L2_MEMORY_MMAP) {
329 struct mmap_buffers *buffers = queue->buffers;
330
331 v4l2_buffer.m.planes[i].length = buffers[index].length[i];
332 v4l2_buffer.m.planes[i].bytesused = buffers[index].length[i];
333 v4l2_buffer.m.planes[i].data_offset = 0;
334 }
335 }
336
337 int ret = ioctl(queue->v4lfd, VIDIOC_QBUF, &v4l2_buffer);
338 if (ret != 0) {
339 perror("VIDIOC_QBUF failed");
340 }
341
342 return ret;
343}
344
345// this is the output queue that will produce uncompressed frames
346// 4.5.1.6
347int setup_CAPTURE(struct gbm_device *gbm, struct queue *CAPTURE_queue, uint64_t modifier)
348{
349 int ret = 0;
350
351 // 1. Call VIDIOC_G_FMT() on the CAPTURE queue to get format for the
352 // destination buffers parsed/decoded from the bytestream.
353 if (!ret) {
354 struct v4l2_format fmt;
355 memset(&fmt, 0, sizeof(fmt));
356 fmt.type = CAPTURE_queue->type;
357
358 int ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_G_FMT, &fmt);
359 if (ret != 0)
360 perror("VIDIOC_G_FMT failed");
361
362 CAPTURE_queue->image_width = fmt.fmt.pix_mp.width;
363 CAPTURE_queue->image_height = fmt.fmt.pix_mp.height;
364 CAPTURE_queue->num_planes = fmt.fmt.pix_mp.num_planes;
365
366 printf("CAPTURE: %d x %d\n", fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height);
367 }
368
369 // 4. Optional. Set the CAPTURE format via VIDIOC_S_FMT() on the CAPTURE queue.
370 // The client may choose a different format than selected/suggested by the decoder in
371 // VIDIOC_G_FMT().
372 if (!ret) {
373 struct v4l2_format fmt;
374 memset(&fmt, 0, sizeof(fmt));
375 fmt.type = CAPTURE_queue->type;
376 fmt.fmt.pix_mp.pixelformat = CAPTURE_queue->fourcc;
377
378 fmt.fmt.pix_mp.width = CAPTURE_queue->image_width;
379 fmt.fmt.pix_mp.height = CAPTURE_queue->image_height;
380
381 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_S_FMT, &fmt);
382 if (ret != 0)
383 perror("VIDIOC_S_FMT failed");
384 }
385
386 // 10. Allocate CAPTURE buffers via VIDIOC_REQBUFS() on the CAPTURE queue.
387 if (!ret) {
388 struct v4l2_requestbuffers reqbuf;
389 memset(&reqbuf, 0, sizeof(reqbuf));
390 reqbuf.count = kRequestBufferCount;
391 reqbuf.type = CAPTURE_queue->type;
392 reqbuf.memory = CAPTURE_queue->memory;
393
394 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_REQBUFS, &reqbuf);
395 if (ret != 0)
396 perror("VIDIOC_REQBUFS failed");
397
398 printf("%d buffers requested, %d buffers for decoded data returned\n",
399 kRequestBufferCount, reqbuf.count);
400
401 if (CAPTURE_queue->memory == V4L2_MEMORY_DMABUF) {
402 const uint32_t buffer_alloc = reqbuf.count * sizeof(struct mmap_buffers);
403 struct mmap_buffers *buffers = (struct mmap_buffers *)malloc(buffer_alloc);
404 memset(buffers, 0, buffer_alloc);
405 CAPTURE_queue->buffers = buffers;
406 CAPTURE_queue->cnt = reqbuf.count;
407
408 for (uint32_t i = 0; i < CAPTURE_queue->cnt; ++i) {
409 const uint32_t width = CAPTURE_queue->image_width;
410 const uint32_t height = CAPTURE_queue->image_height;
411
412 struct gbm_bo *bo = gbm_bo_create_with_modifiers(
413 gbm, width, height, GBM_FORMAT_NV12, &modifier, 1);
414 CAPTURE_queue->buffers[i].bo = bo;
415
416 if (bo) {
417 ret = queue_buffer_CAPTURE(CAPTURE_queue, i);
418 if (ret != 0)
419 break;
420 } else {
421 fprintf(stderr, "could not allocate a bo %d x %d\n", width,
422 height);
423 ret = -1;
424 break;
425 }
426 }
427 } else if (CAPTURE_queue->memory == V4L2_MEMORY_MMAP) {
428 ret = request_mmap_buffers(CAPTURE_queue, &reqbuf);
429 for (uint32_t i = 0; i < reqbuf.count; i++) {
430 queue_buffer_CAPTURE(CAPTURE_queue, i);
431 }
432 } else {
433 ret = -1;
434 }
435 }
436
437 // 11. Call VIDIOC_STREAMON() on the CAPTURE queue to start decoding frames.
438 if (!ret) {
439 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_STREAMON, &CAPTURE_queue->type);
440 if (ret != 0)
441 perror("VIDIOC_STREAMON failed");
442 }
443
444 return ret;
445}
446
447void write_file_to_disk(struct queue *CAPTURE_queue, uint32_t index, uint32_t cnt)
448{
449 char filename[256];
450 sprintf(filename, "image_%dx%d_%d.yuv", CAPTURE_queue->image_width,
451 CAPTURE_queue->image_height, cnt);
452 FILE *fp = fopen(filename, "wb");
453 if (fp) {
454 if (V4L2_MEMORY_DMABUF == CAPTURE_queue->memory) {
455 struct gbm_bo *bo = CAPTURE_queue->buffers[index].bo;
456 int bo_fd = gbm_bo_get_fd(bo);
457 size_t buffer_size = lseek(bo_fd, 0, SEEK_END);
458 lseek(bo_fd, 0, SEEK_SET);
459
460 uint8_t *buffer = mmap(0, buffer_size, PROT_READ, MAP_SHARED, bo_fd, 0);
461
462 fwrite(buffer, buffer_size, 1, fp);
463 munmap(buffer, buffer_size);
464 } else {
465 if (CAPTURE_queue->num_planes == 1) {
466 size_t buffer_size = (3 * CAPTURE_queue->image_width *
467 CAPTURE_queue->image_height) >>
468 1;
469 uint8_t *buffer = CAPTURE_queue->buffers[index].start[0];
470 fwrite(buffer, buffer_size, 1, fp);
471 } else {
472 for (uint32_t i = 0; i < CAPTURE_queue->num_planes; ++i) {
473 size_t buffer_size = (CAPTURE_queue->image_width *
474 CAPTURE_queue->image_height) >>
475 i;
476 uint8_t *buffer = CAPTURE_queue->buffers[index].start[i];
477 fwrite(buffer, buffer_size, 1, fp);
478 }
479 }
480 }
481 fclose(fp);
482 } else {
483 fprintf(stderr, "Unable to open file: %s\n", filename);
484 }
485}
486
487int dequeue_buffer(struct queue *queue, uint32_t *index)
488{
489 struct v4l2_buffer v4l2_buffer;
490 struct v4l2_plane planes[VIDEO_MAX_PLANES] = { 0 };
491 memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
492 v4l2_buffer.type = queue->type;
493 v4l2_buffer.length = queue->num_planes;
494 v4l2_buffer.m.planes = planes;
495 v4l2_buffer.m.planes[0].bytesused = 0;
496 int ret = ioctl(queue->v4lfd, VIDIOC_DQBUF, &v4l2_buffer);
497
498 *index = v4l2_buffer.index;
499 return ret;
500}
501
502int decode(struct compressed_file *file, struct queue *CAPTURE_queue,
503 struct queue *OUTPUT_queue, uint64_t modifier, bool write_out, uint32_t frames_to_decode)
504{
505 int ret = 0;
506
507 if (!ret) {
508 uint32_t cnt = 0;
509 while (cnt < frames_to_decode) {
510 {
511 uint32_t index = 0;
512 ret = dequeue_buffer(CAPTURE_queue, &index);
513 if (ret != 0) {
514 if (errno != EAGAIN)
515 perror("VIDIOC_DQBUF failed");
516 continue;
517 }
518
519 if (write_out)
520 write_file_to_disk(CAPTURE_queue, index, cnt);
521
522 // Done with buffer, queue it back up.
523 ret = queue_buffer_CAPTURE(CAPTURE_queue, index);
524 }
525
526 // A frame was recieved on the CAPTURE queue, that means there should
527 // now be a free OUTPUT buffer.
528 {
529 uint32_t index = 0;
530 ret = dequeue_buffer(OUTPUT_queue, &index);
531 if (ret != 0) {
532 if (errno != EAGAIN)
533 perror("VIDIOC_DQBUF failed");
534 continue;
535 }
536
537 if (submit_compressed_frame(file, OUTPUT_queue, index))
538 break;
539 }
540 cnt++;
541 }
542 printf("%d frames decoded.\n", cnt);
543 }
544
545 return ret;
546}
547
548static void print_help(const char *argv0)
549{
550 printf("usage: %s [OPTIONS]\n", argv0);
551 printf(" -f, --file ivf file to decode\n");
552 printf(" -w, --write write out decompressed frames\n");
553 printf(" -m, --max max number of frames to decode\n");
554 printf(" -b, --buffer use mmap instead of dmabuf\n");
555 printf(" -o, --output_fmt fourcc of output format\n");
556}
557
558static const struct option longopts[] = {
559 { "file", required_argument, NULL, 'f' },
560 { "write", no_argument, NULL, 'w' },
561 { "max", required_argument, NULL, 'm' },
562 { "buffer", no_argument, NULL, 'b' },
563 { "output_fmt", no_argument, NULL, 'o' },
564 { 0, 0, 0, 0 },
565};
566
567int main(int argc, char *argv[])
568{
569 printf("simple v4l2 decode\n");
570 int c;
571 char *file_name = NULL;
572 bool write_out = false;
573 uint32_t frames_to_decode = UINT_MAX;
574 uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
575 uint32_t uncompressed_fourcc = v4l2_fourcc('N', 'V', '1', '2');
576 uint32_t CAPTURE_memory = V4L2_MEMORY_DMABUF;
577 while ((c = getopt_long(argc, argv, "wbm:f:o:", longopts, NULL)) != -1) {
578 switch (c) {
579 case 'f':
580 file_name = strdup(optarg);
581 break;
582 case 'm':
583 frames_to_decode = atoi(optarg);
584 printf("only decoding a max of %d frames.\n", frames_to_decode);
585 break;
586 case 'w':
587 write_out = true;
588 break;
589 case 'b':
590 CAPTURE_memory = V4L2_MEMORY_MMAP;
591 break;
592 case 'o':
593 if (strlen(optarg) == 4) {
594 uncompressed_fourcc =
595 v4l2_fourcc(toupper(optarg[0]), toupper(optarg[1]),
596 toupper(optarg[2]), toupper(optarg[3]));
597 printf("using (%s) as the CAPTURE format\n", optarg);
598 if (uncompressed_fourcc ==
599 v4l2_fourcc('Q', '1', '2', '8')) {
600 printf("compressed format, setting modifier\n");
601 modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
602 }
603 }
604 break;
605 default:
606 break;
607 }
608 }
609
610 if (!file_name) {
611 print_help(argv[0]);
612 exit(1);
613 }
614
615 int drm_device_fd = bs_drm_open_main_display();
616 if (drm_device_fd < 0) {
617 fprintf(stderr, "failed to open card for display\n");
618 return 1;
619 }
620
621 struct gbm_device *gbm = gbm_create_device(drm_device_fd);
622 if (!gbm) {
623 fprintf(stderr, "failed to create gbm device\n");
624 close(drm_device_fd);
625 exit(EXIT_FAILURE);
626 }
627
628 struct compressed_file compressed_file = open_file(file_name);
629 if (!compressed_file.fp) {
630 fprintf(stderr, "Unable to open ivf file: %s\n", file_name);
631 exit(EXIT_FAILURE);
632 }
633
634 int v4lfd = open(kDecodeDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC);
635 if (v4lfd < 0) {
636 fprintf(stderr, "Unable to open device file: %s\n", kDecodeDevice);
637 exit(EXIT_FAILURE);
638 }
639
640 if (capabilities(v4lfd, compressed_file.header.fourcc, uncompressed_fourcc) != 0) {
641 fprintf(stderr, "Capabilities not present for decode.\n");
642 exit(EXIT_FAILURE);
643 }
644
645 struct queue OUTPUT_queue = { .v4lfd = v4lfd,
646 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
647 .fourcc = compressed_file.header.fourcc,
648 .num_planes = 1,
649 .memory = V4L2_MEMORY_MMAP };
650 int ret = setup_OUTPUT(&OUTPUT_queue);
651
652 if (!ret)
653 ret = prime_OUTPUT(&compressed_file, &OUTPUT_queue);
654
655 struct queue CAPTURE_queue = { .v4lfd = v4lfd,
656 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
657 .fourcc = uncompressed_fourcc,
658 .num_planes = 1,
659 .memory = CAPTURE_memory };
660 if (!ret)
661 ret = setup_CAPTURE(gbm, &CAPTURE_queue, modifier);
662
663 if (!ret)
664 ret = decode(&compressed_file, &CAPTURE_queue, &OUTPUT_queue, modifier,
665 write_out, frames_to_decode);
666
667 cleanup_queue(&OUTPUT_queue);
668 cleanup_queue(&CAPTURE_queue);
669 close(v4lfd);
670 fclose(compressed_file.fp);
671 close(drm_device_fd);
672 free(file_name);
673
674 return 0;
675}