blob: 30b4b6068de3bd7946e80132ba07419d38c8a8de [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
Steve Chodc8f92a2021-03-03 17:43:38 -080024static const char* kDecodeDevice = "/dev/video-dec0";
Fritz Koenig7d0e8412021-02-05 15:40:08 -080025static 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 {
Steve Chodc8f92a2021-03-03 17:43:38 -080030 void* start[VIDEO_MAX_PLANES];
31 size_t length[VIDEO_MAX_PLANES];
32 struct gbm_bo* bo;
Fritz Koenig7d0e8412021-02-05 15:40:08 -080033};
34
35struct queue {
Steve Chodc8f92a2021-03-03 17:43:38 -080036 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;
Fritz Koenig7d0e8412021-02-05 15:40:08 -080045};
46
47struct ivf_file_header {
Steve Chodc8f92a2021-03-03 17:43:38 -080048 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;
Fritz Koenig7d0e8412021-02-05 15:40:08 -080058} __attribute__((packed));
59
60struct ivf_frame_header {
Steve Chodc8f92a2021-03-03 17:43:38 -080061 uint32_t size;
62 uint64_t timestamp;
Fritz Koenig7d0e8412021-02-05 15:40:08 -080063} __attribute__((packed));
64
65struct compressed_file {
Steve Chodc8f92a2021-03-03 17:43:38 -080066 FILE* fp;
67 struct ivf_file_header header;
68 uint32_t submitted_frames;
Fritz Koenig7d0e8412021-02-05 15:40:08 -080069};
70
Steve Chodc8f92a2021-03-03 17:43:38 -080071void print_fourcc(uint32_t fourcc) {
72 printf("%c%c%c%c\n", fourcc & 0xff, fourcc >> 8 & 0xff, fourcc >> 16 & 0xff,
73 fourcc >> 24 & 0xff);
Fritz Koenig7d0e8412021-02-05 15:40:08 -080074}
75
Steve Chodc8f92a2021-03-03 17:43:38 -080076struct compressed_file open_file(const char* file_name) {
77 struct compressed_file file = {0};
Fritz Koenig7d0e8412021-02-05 15:40:08 -080078
Steve Chodc8f92a2021-03-03 17:43:38 -080079 FILE* fp = fopen(file_name, "rb");
80 if (fp) {
81 if (fread(&file.header, sizeof(struct ivf_file_header), 1, fp) != 1) {
82 fclose(fp);
83 fprintf(stderr, "unable to read ivf file header\n");
84 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -080085
Steve Chodc8f92a2021-03-03 17:43:38 -080086 if (file.header.signature != kIVFHeaderSignature) {
87 fclose(fp);
88 fprintf(stderr, "Incorrect header signature : 0x%0x != 0x%0x\n",
89 file.header.signature, kIVFHeaderSignature);
90 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -080091
Steve Chodc8f92a2021-03-03 17:43:38 -080092 file.fp = fp;
93 print_fourcc(file.header.fourcc);
94 printf("ivf file header: %d x %d\n", file.header.width, file.header.height);
95 } else {
96 fprintf(stderr, "unable to open file: %s\n", file_name);
97 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -080098
Steve Chodc8f92a2021-03-03 17:43:38 -080099 return file;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800100}
101
Steve Chodc8f92a2021-03-03 17:43:38 -0800102int query_format(int v4lfd, enum v4l2_buf_type type, uint32_t fourcc) {
103 struct v4l2_fmtdesc fmtdesc;
104 memset(&fmtdesc, 0, sizeof(fmtdesc));
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800105
Steve Chodc8f92a2021-03-03 17:43:38 -0800106 fmtdesc.type = type;
107 while (ioctl(v4lfd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
108 if (fourcc == 0)
109 print_fourcc(fmtdesc.pixelformat);
110 else if (fourcc == fmtdesc.pixelformat)
111 return 1;
112 fmtdesc.index++;
113 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800114
Steve Chodc8f92a2021-03-03 17:43:38 -0800115 return 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800116}
117
Steve Chodc8f92a2021-03-03 17:43:38 -0800118int capabilities(int v4lfd,
119 uint32_t compressed_format,
120 uint32_t uncompressed_format) {
121 struct v4l2_capability cap;
122 memset(&cap, 0, sizeof(cap));
123 int ret = ioctl(v4lfd, VIDIOC_QUERYCAP, &cap);
124 if (ret != 0)
125 perror("VIDIOC_QUERYCAP failed");
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800126
Steve Chodc8f92a2021-03-03 17:43:38 -0800127 printf("driver=\"%s\" bus_info=\"%s\" card=\"%s\" fd=0x%x\n", cap.driver,
128 cap.bus_info, cap.card, v4lfd);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800129
Steve Chodc8f92a2021-03-03 17:43:38 -0800130 if (!query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
131 compressed_format)) {
132 printf("Supported compressed formats:\n");
133 query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 0);
134 ret = 1;
135 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800136
Steve Chodc8f92a2021-03-03 17:43:38 -0800137 if (!query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
138 uncompressed_format)) {
139 printf("Supported uncompressed formats:\n");
140 query_format(v4lfd, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 0);
141 ret = 1;
142 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800143
Steve Chodc8f92a2021-03-03 17:43:38 -0800144 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800145}
146
Steve Chodc8f92a2021-03-03 17:43:38 -0800147int request_mmap_buffers(struct queue* queue,
148 struct v4l2_requestbuffers* reqbuf) {
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;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800155
Steve Chodc8f92a2021-03-03 17:43:38 -0800156 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 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800171
Steve Chodc8f92a2021-03-03 17:43:38 -0800172 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 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800184
Steve Chodc8f92a2021-03-03 17:43:38 -0800185 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800186}
187
188// this is the input queue that will take compressed data
189// 4.5.1.5
Steve Chodc8f92a2021-03-03 17:43:38 -0800190int setup_OUTPUT(struct queue* OUTPUT_queue) {
191 int ret = 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800192
Steve Chodc8f92a2021-03-03 17:43:38 -0800193 // 1. Set the coded format on OUTPUT via VIDIOC_S_FMT()
194 if (!ret) {
195 struct v4l2_format fmt;
196 memset(&fmt, 0, sizeof(fmt));
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800197
Steve Chodc8f92a2021-03-03 17:43:38 -0800198 fmt.type = OUTPUT_queue->type;
199 fmt.fmt.pix_mp.pixelformat = OUTPUT_queue->fourcc;
200 fmt.fmt.pix_mp.plane_fmt[0].sizeimage = kInputbufferMaxSize;
201 fmt.fmt.pix_mp.num_planes = 1;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800202
Steve Chodc8f92a2021-03-03 17:43:38 -0800203 int ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_S_FMT, &fmt);
204 if (ret != 0)
205 perror("VIDIOC_S_FMT failed");
206 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800207
Steve Chodc8f92a2021-03-03 17:43:38 -0800208 // 2. Allocate source (bytestream) buffers via VIDIOC_REQBUFS() on OUTPUT.
209 if (!ret) {
210 struct v4l2_requestbuffers reqbuf;
211 memset(&reqbuf, 0, sizeof(reqbuf));
212 reqbuf.count = kRequestBufferCount;
213 reqbuf.type = OUTPUT_queue->type;
214 reqbuf.memory = OUTPUT_queue->memory;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800215
Steve Chodc8f92a2021-03-03 17:43:38 -0800216 ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_REQBUFS, &reqbuf);
217 if (ret != 0)
218 perror("VIDIOC_REQBUFS failed");
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800219
Steve Chodc8f92a2021-03-03 17:43:38 -0800220 printf("%d buffers requested, %d buffers for compressed data returned\n",
221 kRequestBufferCount, reqbuf.count);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800222
Steve Chodc8f92a2021-03-03 17:43:38 -0800223 ret = request_mmap_buffers(OUTPUT_queue, &reqbuf);
224 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800225
Steve Chodc8f92a2021-03-03 17:43:38 -0800226 // 3. Start streaming on the OUTPUT queue via VIDIOC_STREAMON().
227 if (!ret) {
228 ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_STREAMON, &OUTPUT_queue->type);
229 if (ret != 0)
230 perror("VIDIOC_STREAMON failed");
231 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800232
Steve Chodc8f92a2021-03-03 17:43:38 -0800233 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800234}
235
Steve Chodc8f92a2021-03-03 17:43:38 -0800236int submit_compressed_frame(struct compressed_file* file,
237 struct queue* OUTPUT_queue,
238 uint32_t index) {
239 const uint32_t num = file->header.numerator;
240 const uint32_t den = file->header.denominator;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800241
Steve Chodc8f92a2021-03-03 17:43:38 -0800242 struct ivf_frame_header frame_header = {0};
243 if (fread(&frame_header, sizeof(struct ivf_frame_header), 1, file->fp) != 1) {
244 if (!feof(file->fp))
245 fprintf(stderr, "unable to read ivf frame header\n");
246 return -1;
247 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800248
Steve Chodc8f92a2021-03-03 17:43:38 -0800249 struct mmap_buffers* buffers = OUTPUT_queue->buffers;
250 if (fread(buffers[index].start[0], sizeof(uint8_t), frame_header.size,
251 file->fp) != frame_header.size) {
252 fprintf(stderr, "unable to read ivf frame data\n");
253 return -1;
254 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800255
Steve Chodc8f92a2021-03-03 17:43:38 -0800256 struct v4l2_buffer v4l2_buffer;
257 struct v4l2_plane planes[VIDEO_MAX_PLANES];
258 memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
259 v4l2_buffer.index = index;
260 v4l2_buffer.type = OUTPUT_queue->type;
261 v4l2_buffer.memory = OUTPUT_queue->memory;
262 v4l2_buffer.length = 1;
263 v4l2_buffer.timestamp.tv_sec = 0;
264 v4l2_buffer.timestamp.tv_usec = ((frame_header.timestamp * den) / num) * 100;
265 v4l2_buffer.m.planes = planes;
266 v4l2_buffer.m.planes[0].length = buffers[index].length[0];
267 v4l2_buffer.m.planes[0].bytesused = frame_header.size;
268 v4l2_buffer.m.planes[0].data_offset = 0;
269 int ret = ioctl(OUTPUT_queue->v4lfd, VIDIOC_QBUF, &v4l2_buffer);
270 if (ret != 0) {
271 perror("VIDIOC_QBUF failed");
272 return -1;
273 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800274
Steve Chodc8f92a2021-03-03 17:43:38 -0800275 file->submitted_frames++;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800276
Steve Chodc8f92a2021-03-03 17:43:38 -0800277 return 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800278}
279
Steve Chodc8f92a2021-03-03 17:43:38 -0800280int prime_OUTPUT(struct compressed_file* file, struct queue* OUTPUT_queue) {
281 int ret = 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800282
Steve Chodc8f92a2021-03-03 17:43:38 -0800283 for (uint32_t i = 0; i < OUTPUT_queue->cnt; ++i) {
284 ret = submit_compressed_frame(file, OUTPUT_queue, i);
285 if (ret)
286 break;
287 }
288 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800289}
290
Steve Chodc8f92a2021-03-03 17:43:38 -0800291void cleanup_queue(struct queue* queue) {
292 if (queue->cnt) {
293 struct mmap_buffers* buffers = queue->buffers;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800294
Steve Chodc8f92a2021-03-03 17:43:38 -0800295 for (uint32_t i = 0; i < queue->cnt; i++)
296 for (uint32_t j = 0; j < queue->num_planes; j++) {
297 if (buffers[i].length[j])
298 munmap(buffers[i].start[j], buffers[i].length[j]);
299 if (buffers[i].bo)
300 gbm_bo_destroy(buffers[i].bo);
301 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800302
Steve Chodc8f92a2021-03-03 17:43:38 -0800303 free(queue->buffers);
304 queue->cnt = 0;
305 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800306}
307
Steve Chodc8f92a2021-03-03 17:43:38 -0800308int queue_buffer_CAPTURE(struct queue* queue, uint32_t index) {
309 struct v4l2_buffer v4l2_buffer;
310 struct v4l2_plane planes[VIDEO_MAX_PLANES];
311 memset(&v4l2_buffer, 0, sizeof v4l2_buffer);
312 memset(&planes, 0, sizeof planes);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800313
Steve Chodc8f92a2021-03-03 17:43:38 -0800314 v4l2_buffer.type = queue->type;
315 v4l2_buffer.memory = queue->memory;
316 v4l2_buffer.index = index;
317 v4l2_buffer.m.planes = planes;
318 v4l2_buffer.length = queue->num_planes;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800319
Steve Chodc8f92a2021-03-03 17:43:38 -0800320 struct gbm_bo* bo = queue->buffers[index].bo;
321 for (uint32_t i = 0; i < queue->num_planes; ++i) {
322 if (queue->memory == V4L2_MEMORY_DMABUF) {
323 v4l2_buffer.m.planes[i].m.fd = gbm_bo_get_plane_fd(bo, i);
324 } else if (queue->memory == V4L2_MEMORY_MMAP) {
325 struct mmap_buffers* buffers = queue->buffers;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800326
Steve Chodc8f92a2021-03-03 17:43:38 -0800327 v4l2_buffer.m.planes[i].length = buffers[index].length[i];
328 v4l2_buffer.m.planes[i].bytesused = buffers[index].length[i];
329 v4l2_buffer.m.planes[i].data_offset = 0;
330 }
331 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800332
Steve Chodc8f92a2021-03-03 17:43:38 -0800333 int ret = ioctl(queue->v4lfd, VIDIOC_QBUF, &v4l2_buffer);
334 if (ret != 0) {
335 perror("VIDIOC_QBUF failed");
336 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800337
Steve Chodc8f92a2021-03-03 17:43:38 -0800338 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800339}
340
341// this is the output queue that will produce uncompressed frames
342// 4.5.1.6
Steve Chodc8f92a2021-03-03 17:43:38 -0800343int setup_CAPTURE(struct gbm_device* gbm,
344 struct queue* CAPTURE_queue,
345 uint64_t modifier) {
346 int ret = 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800347
Steve Chodc8f92a2021-03-03 17:43:38 -0800348 // 1. Call VIDIOC_G_FMT() on the CAPTURE queue to get format for the
349 // destination buffers parsed/decoded from the bytestream.
350 if (!ret) {
351 struct v4l2_format fmt;
352 memset(&fmt, 0, sizeof(fmt));
353 fmt.type = CAPTURE_queue->type;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800354
Steve Chodc8f92a2021-03-03 17:43:38 -0800355 int ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_G_FMT, &fmt);
356 if (ret != 0)
357 perror("VIDIOC_G_FMT failed");
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800358
Steve Chodc8f92a2021-03-03 17:43:38 -0800359 CAPTURE_queue->image_width = fmt.fmt.pix_mp.width;
360 CAPTURE_queue->image_height = fmt.fmt.pix_mp.height;
361 CAPTURE_queue->num_planes = fmt.fmt.pix_mp.num_planes;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800362
Steve Chodc8f92a2021-03-03 17:43:38 -0800363 printf("CAPTURE: %d x %d\n", fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height);
364 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800365
Steve Chodc8f92a2021-03-03 17:43:38 -0800366 // 4. Optional. Set the CAPTURE format via VIDIOC_S_FMT() on the CAPTURE
367 // queue.
368 // The client may choose a different format than selected/suggested by the
369 // decoder in VIDIOC_G_FMT().
370 if (!ret) {
371 struct v4l2_format fmt;
372 memset(&fmt, 0, sizeof(fmt));
373 fmt.type = CAPTURE_queue->type;
374 fmt.fmt.pix_mp.pixelformat = CAPTURE_queue->fourcc;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800375
Steve Chodc8f92a2021-03-03 17:43:38 -0800376 fmt.fmt.pix_mp.width = CAPTURE_queue->image_width;
377 fmt.fmt.pix_mp.height = CAPTURE_queue->image_height;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800378
Steve Chodc8f92a2021-03-03 17:43:38 -0800379 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_S_FMT, &fmt);
380 if (ret != 0)
381 perror("VIDIOC_S_FMT failed");
382 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800383
Steve Chodc8f92a2021-03-03 17:43:38 -0800384 // 10. Allocate CAPTURE buffers via VIDIOC_REQBUFS() on the CAPTURE queue.
385 if (!ret) {
386 struct v4l2_requestbuffers reqbuf;
387 memset(&reqbuf, 0, sizeof(reqbuf));
388 reqbuf.count = kRequestBufferCount;
389 reqbuf.type = CAPTURE_queue->type;
390 reqbuf.memory = CAPTURE_queue->memory;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800391
Steve Chodc8f92a2021-03-03 17:43:38 -0800392 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_REQBUFS, &reqbuf);
393 if (ret != 0)
394 perror("VIDIOC_REQBUFS failed");
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800395
Steve Chodc8f92a2021-03-03 17:43:38 -0800396 printf("%d buffers requested, %d buffers for decoded data returned\n",
397 kRequestBufferCount, reqbuf.count);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800398
Steve Chodc8f92a2021-03-03 17:43:38 -0800399 if (CAPTURE_queue->memory == V4L2_MEMORY_DMABUF) {
400 const uint32_t buffer_alloc = reqbuf.count * sizeof(struct mmap_buffers);
401 struct mmap_buffers* buffers = (struct mmap_buffers*)malloc(buffer_alloc);
402 memset(buffers, 0, buffer_alloc);
403 CAPTURE_queue->buffers = buffers;
404 CAPTURE_queue->cnt = reqbuf.count;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800405
Steve Chodc8f92a2021-03-03 17:43:38 -0800406 for (uint32_t i = 0; i < CAPTURE_queue->cnt; ++i) {
407 const uint32_t width = CAPTURE_queue->image_width;
408 const uint32_t height = CAPTURE_queue->image_height;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800409
Steve Chodc8f92a2021-03-03 17:43:38 -0800410 struct gbm_bo* bo = gbm_bo_create_with_modifiers(
411 gbm, width, height, GBM_FORMAT_NV12, &modifier, 1);
412 CAPTURE_queue->buffers[i].bo = bo;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800413
Steve Chodc8f92a2021-03-03 17:43:38 -0800414 if (bo) {
415 ret = queue_buffer_CAPTURE(CAPTURE_queue, i);
416 if (ret != 0)
417 break;
418 } else {
419 fprintf(stderr, "could not allocate a bo %d x %d\n", width, height);
420 ret = -1;
421 break;
422 }
423 }
424 } else if (CAPTURE_queue->memory == V4L2_MEMORY_MMAP) {
425 ret = request_mmap_buffers(CAPTURE_queue, &reqbuf);
426 for (uint32_t i = 0; i < reqbuf.count; i++) {
427 queue_buffer_CAPTURE(CAPTURE_queue, i);
428 }
429 } else {
430 ret = -1;
431 }
432 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800433
Steve Chodc8f92a2021-03-03 17:43:38 -0800434 // 11. Call VIDIOC_STREAMON() on the CAPTURE queue to start decoding frames.
435 if (!ret) {
436 ret = ioctl(CAPTURE_queue->v4lfd, VIDIOC_STREAMON, &CAPTURE_queue->type);
437 if (ret != 0)
438 perror("VIDIOC_STREAMON failed");
439 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800440
Steve Chodc8f92a2021-03-03 17:43:38 -0800441 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800442}
443
Steve Chodc8f92a2021-03-03 17:43:38 -0800444void write_file_to_disk(struct queue* CAPTURE_queue,
445 uint32_t index,
446 uint32_t cnt) {
447 char filename[256];
448 sprintf(filename, "image_%dx%d_%d.yuv", CAPTURE_queue->image_width,
449 CAPTURE_queue->image_height, cnt);
450 FILE* fp = fopen(filename, "wb");
451 if (fp) {
452 if (V4L2_MEMORY_DMABUF == CAPTURE_queue->memory) {
453 struct gbm_bo* bo = CAPTURE_queue->buffers[index].bo;
454 int bo_fd = gbm_bo_get_fd(bo);
455 size_t buffer_size = lseek(bo_fd, 0, SEEK_END);
456 lseek(bo_fd, 0, SEEK_SET);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800457
Steve Chodc8f92a2021-03-03 17:43:38 -0800458 uint8_t* buffer = mmap(0, buffer_size, PROT_READ, MAP_SHARED, bo_fd, 0);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800459
Steve Chodc8f92a2021-03-03 17:43:38 -0800460 fwrite(buffer, buffer_size, 1, fp);
461 munmap(buffer, buffer_size);
462 } else {
463 if (CAPTURE_queue->num_planes == 1) {
464 size_t buffer_size =
465 (3 * CAPTURE_queue->image_width * CAPTURE_queue->image_height) >> 1;
466 uint8_t* buffer = CAPTURE_queue->buffers[index].start[0];
467 fwrite(buffer, buffer_size, 1, fp);
468 } else {
469 for (uint32_t i = 0; i < CAPTURE_queue->num_planes; ++i) {
470 size_t buffer_size =
471 (CAPTURE_queue->image_width * CAPTURE_queue->image_height) >> i;
472 uint8_t* buffer = CAPTURE_queue->buffers[index].start[i];
473 fwrite(buffer, buffer_size, 1, fp);
474 }
475 }
476 }
477 fclose(fp);
478 } else {
479 fprintf(stderr, "Unable to open file: %s\n", filename);
480 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800481}
482
Steve Chodc8f92a2021-03-03 17:43:38 -0800483int dequeue_buffer(struct queue* queue, uint32_t* index) {
484 struct v4l2_buffer v4l2_buffer;
485 struct v4l2_plane planes[VIDEO_MAX_PLANES] = {0};
486 memset(&v4l2_buffer, 0, sizeof(v4l2_buffer));
487 v4l2_buffer.type = queue->type;
488 v4l2_buffer.length = queue->num_planes;
489 v4l2_buffer.m.planes = planes;
490 v4l2_buffer.m.planes[0].bytesused = 0;
491 int ret = ioctl(queue->v4lfd, VIDIOC_DQBUF, &v4l2_buffer);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800492
Steve Chodc8f92a2021-03-03 17:43:38 -0800493 *index = v4l2_buffer.index;
494 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800495}
496
Steve Chodc8f92a2021-03-03 17:43:38 -0800497int decode(struct compressed_file* file,
498 struct queue* CAPTURE_queue,
499 struct queue* OUTPUT_queue,
500 uint64_t modifier,
501 bool write_out,
502 uint32_t frames_to_decode) {
503 int ret = 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800504
Steve Chodc8f92a2021-03-03 17:43:38 -0800505 if (!ret) {
506 uint32_t cnt = 0;
507 while (cnt < frames_to_decode) {
508 {
509 uint32_t index = 0;
510 ret = dequeue_buffer(CAPTURE_queue, &index);
511 if (ret != 0) {
512 if (errno != EAGAIN)
513 perror("VIDIOC_DQBUF failed");
514 continue;
515 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800516
Steve Chodc8f92a2021-03-03 17:43:38 -0800517 if (write_out)
518 write_file_to_disk(CAPTURE_queue, index, cnt);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800519
Steve Chodc8f92a2021-03-03 17:43:38 -0800520 // Done with buffer, queue it back up.
521 ret = queue_buffer_CAPTURE(CAPTURE_queue, index);
522 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800523
Steve Chodc8f92a2021-03-03 17:43:38 -0800524 // A frame was recieved on the CAPTURE queue, that means there should
525 // now be a free OUTPUT buffer.
526 {
527 uint32_t index = 0;
528 ret = dequeue_buffer(OUTPUT_queue, &index);
529 if (ret != 0) {
530 if (errno != EAGAIN)
531 perror("VIDIOC_DQBUF failed");
532 continue;
533 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800534
Steve Chodc8f92a2021-03-03 17:43:38 -0800535 if (submit_compressed_frame(file, OUTPUT_queue, index))
536 break;
537 }
538 cnt++;
539 }
540 printf("%d frames decoded.\n", cnt);
541 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800542
Steve Chodc8f92a2021-03-03 17:43:38 -0800543 return ret;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800544}
545
Steve Chodc8f92a2021-03-03 17:43:38 -0800546static void print_help(const char* argv0) {
547 printf("usage: %s [OPTIONS]\n", argv0);
548 printf(" -f, --file ivf file to decode\n");
549 printf(" -w, --write write out decompressed frames\n");
550 printf(" -m, --max max number of frames to decode\n");
551 printf(" -b, --buffer use mmap instead of dmabuf\n");
552 printf(" -o, --output_fmt fourcc of output format\n");
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800553}
554
555static const struct option longopts[] = {
Steve Chodc8f92a2021-03-03 17:43:38 -0800556 {"file", required_argument, NULL, 'f'}, {"write", no_argument, NULL, 'w'},
557 {"max", required_argument, NULL, 'm'}, {"buffer", no_argument, NULL, 'b'},
558 {"output_fmt", no_argument, NULL, 'o'}, {0, 0, 0, 0},
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800559};
560
Steve Chodc8f92a2021-03-03 17:43:38 -0800561int main(int argc, char* argv[]) {
562 printf("simple v4l2 decode\n");
563 int c;
564 char* file_name = NULL;
565 bool write_out = false;
566 uint32_t frames_to_decode = UINT_MAX;
567 uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
568 uint32_t uncompressed_fourcc = v4l2_fourcc('N', 'V', '1', '2');
569 uint32_t CAPTURE_memory = V4L2_MEMORY_DMABUF;
570 while ((c = getopt_long(argc, argv, "wbm:f:o:", longopts, NULL)) != -1) {
571 switch (c) {
572 case 'f':
573 file_name = strdup(optarg);
574 break;
575 case 'm':
576 frames_to_decode = atoi(optarg);
577 printf("only decoding a max of %d frames.\n", frames_to_decode);
578 break;
579 case 'w':
580 write_out = true;
581 break;
582 case 'b':
583 CAPTURE_memory = V4L2_MEMORY_MMAP;
584 break;
585 case 'o':
586 if (strlen(optarg) == 4) {
587 uncompressed_fourcc =
588 v4l2_fourcc(toupper(optarg[0]), toupper(optarg[1]),
589 toupper(optarg[2]), toupper(optarg[3]));
590 printf("using (%s) as the CAPTURE format\n", optarg);
591 if (uncompressed_fourcc == v4l2_fourcc('Q', '1', '2', '8')) {
592 printf("compressed format, setting modifier\n");
593 modifier = DRM_FORMAT_MOD_QCOM_COMPRESSED;
594 }
595 }
596 break;
597 default:
598 break;
599 }
600 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800601
Steve Chodc8f92a2021-03-03 17:43:38 -0800602 if (!file_name) {
603 print_help(argv[0]);
604 exit(1);
605 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800606
Steve Chodc8f92a2021-03-03 17:43:38 -0800607 int drm_device_fd = bs_drm_open_main_display();
608 if (drm_device_fd < 0) {
609 fprintf(stderr, "failed to open card for display\n");
610 return 1;
611 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800612
Steve Chodc8f92a2021-03-03 17:43:38 -0800613 struct gbm_device* gbm = gbm_create_device(drm_device_fd);
614 if (!gbm) {
615 fprintf(stderr, "failed to create gbm device\n");
616 close(drm_device_fd);
617 exit(EXIT_FAILURE);
618 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800619
Steve Chodc8f92a2021-03-03 17:43:38 -0800620 struct compressed_file compressed_file = open_file(file_name);
621 if (!compressed_file.fp) {
622 fprintf(stderr, "Unable to open ivf file: %s\n", file_name);
623 exit(EXIT_FAILURE);
624 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800625
Steve Chodc8f92a2021-03-03 17:43:38 -0800626 int v4lfd = open(kDecodeDevice, O_RDWR | O_NONBLOCK | O_CLOEXEC);
627 if (v4lfd < 0) {
628 fprintf(stderr, "Unable to open device file: %s\n", kDecodeDevice);
629 exit(EXIT_FAILURE);
630 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800631
Steve Chodc8f92a2021-03-03 17:43:38 -0800632 if (capabilities(v4lfd, compressed_file.header.fourcc, uncompressed_fourcc) !=
633 0) {
634 fprintf(stderr, "Capabilities not present for decode.\n");
635 exit(EXIT_FAILURE);
636 }
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800637
Steve Chodc8f92a2021-03-03 17:43:38 -0800638 struct queue OUTPUT_queue = {.v4lfd = v4lfd,
639 .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
640 .fourcc = compressed_file.header.fourcc,
641 .num_planes = 1,
642 .memory = V4L2_MEMORY_MMAP};
643 int ret = setup_OUTPUT(&OUTPUT_queue);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800644
Steve Chodc8f92a2021-03-03 17:43:38 -0800645 if (!ret)
646 ret = prime_OUTPUT(&compressed_file, &OUTPUT_queue);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800647
Steve Chodc8f92a2021-03-03 17:43:38 -0800648 struct queue CAPTURE_queue = {.v4lfd = v4lfd,
649 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
650 .fourcc = uncompressed_fourcc,
651 .num_planes = 1,
652 .memory = CAPTURE_memory};
653 if (!ret)
654 ret = setup_CAPTURE(gbm, &CAPTURE_queue, modifier);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800655
Steve Chodc8f92a2021-03-03 17:43:38 -0800656 if (!ret)
657 ret = decode(&compressed_file, &CAPTURE_queue, &OUTPUT_queue, modifier,
658 write_out, frames_to_decode);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800659
Steve Chodc8f92a2021-03-03 17:43:38 -0800660 cleanup_queue(&OUTPUT_queue);
661 cleanup_queue(&CAPTURE_queue);
662 close(v4lfd);
663 fclose(compressed_file.fp);
664 close(drm_device_fd);
665 free(file_name);
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800666
Steve Chodc8f92a2021-03-03 17:43:38 -0800667 return 0;
Fritz Koenig7d0e8412021-02-05 15:40:08 -0800668}