1 #include <cstdlib>
2 #include <cstring>
3
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <inttypes.h>
8 #include <getopt.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <netdb.h>
14 #include <fcntl.h>
15 #include <ctype.h>
16 #include <errno.h>
17 #include <sys/ioctl.h>
18 #include <sys/time.h>
19 #include <sys/mman.h>
20 #include <dirent.h>
21 #include <math.h>
22 #include <linux/media.h>
23
24 #include <sys/cdefs.h>
25 #include "v4l2-ctl.h"
26 #include "v4l-stream.h"
27 #include <media-info.h>
28 #include <fwht-ctrls.h>
29
30 extern "C" {
31 #include "v4l2-tpg.h"
32 }
33
34 static unsigned stream_count;
35 static unsigned stream_skip;
36 static uint32_t memory = V4L2_MEMORY_MMAP;
37 static uint32_t out_memory = V4L2_MEMORY_MMAP;
38 static int stream_sleep = -1;
39 static bool stream_no_query;
40 static unsigned stream_pat;
41 static bool stream_loop;
42 static bool stream_out_square;
43 static bool stream_out_border;
44 static bool stream_out_sav;
45 static bool stream_out_eav;
46 static int stream_out_pixel_aspect = -1;
47 static tpg_video_aspect stream_out_video_aspect;
48 static u8 stream_out_alpha;
49 static bool stream_out_alpha_red_only;
50 static bool stream_out_rgb_lim_range;
51 static unsigned stream_out_perc_fill = 100;
52 static v4l2_std_id stream_out_std;
53 static bool stream_out_refresh;
54 static tpg_move_mode stream_out_hor_mode = TPG_MOVE_NONE;
55 static tpg_move_mode stream_out_vert_mode = TPG_MOVE_NONE;
56 static unsigned reqbufs_count_cap = 4;
57 static unsigned reqbufs_count_out = 4;
58 static char *file_to;
59 static bool to_with_hdr;
60 static char *host_to;
61 #ifndef NO_STREAM_TO
62 static unsigned host_port_to = V4L_STREAM_PORT;
63 static unsigned bpl_cap[VIDEO_MAX_PLANES];
64 #endif
65 static bool host_lossless;
66 static int host_fd_to = -1;
67 static unsigned comp_perc;
68 static unsigned comp_perc_count;
69 static char *file_from;
70 static bool from_with_hdr;
71 static char *host_from;
72 static unsigned host_port_from = V4L_STREAM_PORT;
73 static int host_fd_from = -1;
74 static struct tpg_data tpg;
75 static unsigned output_field = V4L2_FIELD_NONE;
76 static bool output_field_alt;
77 static unsigned bpl_out[VIDEO_MAX_PLANES];
78 static bool last_buffer = false;
79 static codec_ctx *ctx;
80
81 static unsigned int cropped_width;
82 static unsigned int cropped_height;
83 static unsigned int composed_width;
84 static unsigned int composed_height;
85 static bool support_cap_compose;
86 static bool support_out_crop;
87 static bool in_source_change_event;
88
89 static uint64_t last_fwht_bf_ts;
90 static fwht_cframe_hdr last_fwht_hdr;
91
92 struct request_fwht {
93 int fd;
94 uint64_t ts;
95 struct v4l2_ctrl_fwht_params params;
96 };
97
98 static request_fwht fwht_reqs[VIDEO_MAX_FRAME];
99
100 #define TS_WINDOW 241
101 #define FILE_HDR_ID v4l2_fourcc('V', 'h', 'd', 'r')
102
103 enum codec_type {
104 NOT_CODEC,
105 ENCODER,
106 DECODER
107 };
108
109 #define QUEUE_ERROR -1
110 #define QUEUE_STOPPED -2
111
112 class fps_timestamps {
113 private:
114 unsigned idx;
115 bool full;
116 double first;
117 double sum;
118 double ts[TS_WINDOW];
119 unsigned seq[TS_WINDOW];
120 unsigned dropped_buffers;
121 bool alternate_fields;
122 unsigned field_cnt;
123 unsigned last_field;
124
125 public:
fps_timestamps()126 fps_timestamps()
127 {
128 reset();
129 }
130
reset()131 void reset() {
132 idx = 0;
133 full = false;
134 first = sum = 0;
135 dropped_buffers = 0;
136 last_field = 0;
137 field_cnt = 0;
138 alternate_fields = false;
139 }
140
141 void determine_field(int fd, unsigned type);
142 bool add_ts(double ts_secs, unsigned sequence, unsigned field);
143 bool has_fps(bool continuous);
144 double fps();
145 unsigned dropped();
146 };
147
determine_field(int fd,unsigned type)148 void fps_timestamps::determine_field(int fd, unsigned type)
149 {
150 struct v4l2_format fmt = { };
151
152 fmt.type = type;
153 ioctl(fd, VIDIOC_G_FMT, &fmt);
154 cv4l_fmt cfmt(fmt);
155 alternate_fields = cfmt.g_field() == V4L2_FIELD_ALTERNATE;
156 }
157
add_ts(double ts_secs,unsigned sequence,unsigned field)158 bool fps_timestamps::add_ts(double ts_secs, unsigned sequence, unsigned field)
159 {
160 if (ts_secs <= 0) {
161 struct timespec ts_cur;
162
163 clock_gettime(CLOCK_MONOTONIC, &ts_cur);
164 ts_secs = ts_cur.tv_sec + ts_cur.tv_nsec / 1000000000.0;
165 }
166
167 if (alternate_fields &&
168 field != V4L2_FIELD_TOP && field != V4L2_FIELD_BOTTOM)
169 return false;
170
171 if (!full && idx == 0) {
172 ts[idx] = ts_secs;
173 seq[TS_WINDOW - 1] = sequence;
174 seq[idx++] = sequence;
175 first = ts_secs;
176 last_field = field;
177 field_cnt++;
178 return true;
179 }
180
181 unsigned prev_idx = (idx + TS_WINDOW - 1) % TS_WINDOW;
182 unsigned next_idx = (idx + 1) % TS_WINDOW;
183
184 if (seq[prev_idx] == sequence) {
185 if (alternate_fields) {
186 if (last_field == field)
187 return false;
188 if (field_cnt != 1)
189 return false;
190 field_cnt++;
191 last_field = field;
192 }
193 } else {
194 if (alternate_fields) {
195 if (field_cnt == 1) {
196 dropped_buffers++;
197 last_field = last_field == V4L2_FIELD_TOP ?
198 V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
199 }
200 field_cnt = 1;
201 if (field == last_field) {
202 dropped_buffers++;
203 field_cnt++;
204 }
205 last_field = field;
206 }
207 if (seq[prev_idx] - sequence > 1) {
208 unsigned dropped = sequence - seq[prev_idx] - 1;
209
210 if (alternate_fields)
211 dropped *= 2;
212 dropped_buffers += dropped;
213 }
214 }
215
216 if (!full) {
217 sum += ts_secs - ts[idx - 1];
218 ts[idx] = ts_secs;
219 seq[idx++] = sequence;
220 if (idx == TS_WINDOW) {
221 full = true;
222 idx = 0;
223 }
224 return true;
225 }
226
227 sum -= ts[next_idx] - ts[idx];
228 ts[idx] = ts_secs;
229 seq[idx] = sequence;
230 idx = next_idx;
231 sum += ts_secs - ts[prev_idx];
232 return true;
233 }
234
has_fps(bool continuous=false)235 bool fps_timestamps::has_fps(bool continuous = false)
236 {
237 unsigned prev_idx = (idx + TS_WINDOW - 1) % TS_WINDOW;
238
239 if (!continuous && ts[prev_idx] - first < 1.0)
240 return false;
241 return full || idx > 4;
242 }
243
dropped()244 unsigned fps_timestamps::dropped()
245 {
246 unsigned res = dropped_buffers;
247
248 dropped_buffers = 0;
249 return res;
250 }
251
fps()252 double fps_timestamps::fps()
253 {
254 unsigned prev_idx = (idx + TS_WINDOW - 1) % TS_WINDOW;
255 double cnt = seq[prev_idx] - seq[full ? idx : 0];
256 double period = sum / cnt;
257 double fps = 1.0 / period;
258
259 first += static_cast<unsigned>(ts[prev_idx] - first);
260 return fps;
261 };
262
streaming_usage()263 void streaming_usage()
264 {
265 printf("\nVideo Streaming options:\n"
266 " --stream-count <count>\n"
267 " stream <count> buffers. The default is to keep streaming\n"
268 " forever. This count does not include the number of initial\n"
269 " skipped buffers as is passed by --stream-skip.\n"
270 " --stream-skip <count>\n"
271 " skip the first <count> buffers. The default is 0.\n"
272 " --stream-sleep <count>\n"
273 " sleep for 1 second every <count> buffers. If <count> is 0,\n"
274 " then sleep forever right after streaming starts. The default\n"
275 " is -1 (never sleep).\n"
276 #ifndef NO_STREAM_TO
277 " --stream-to <file> stream to this file. The default is to discard the\n"
278 " data. If <file> is '-', then the data is written to stdout\n"
279 " and the --silent option is turned on automatically.\n"
280 " --stream-to-hdr <file> stream to this file. Same as --stream-to, but each\n"
281 " frame is prefixed by a header. Use for compressed data.\n"
282 " --stream-to-host <hostname[:port]>\n"
283 " stream to this host. The default port is %d.\n"
284 " --stream-lossless always use lossless video compression.\n"
285 #endif
286 " --stream-poll use non-blocking mode and select() to stream.\n"
287 " --stream-buf-caps show capture buffer capabilities\n"
288 " --stream-mmap <count>\n"
289 " capture video using mmap() [VIDIOC_(D)QBUF]\n"
290 " count: the number of buffers to allocate. The default is 3.\n"
291 " --stream-user <count>\n"
292 " capture video using user pointers [VIDIOC_(D)QBUF]\n"
293 " count: the number of buffers to allocate. The default is 3.\n"
294 " --stream-dmabuf capture video using dmabuf [VIDIOC_(D)QBUF]\n"
295 " Requires a corresponding --stream-out-mmap option.\n"
296 " --stream-from <file>\n"
297 " stream from this file. The default is to generate a pattern.\n"
298 " If <file> is '-', then the data is read from stdin.\n"
299 " --stream-from-hdr <file> stream from this file. Same as --stream-from, but each\n"
300 " frame is prefixed by a header. Use for compressed data.\n"
301 " --stream-from-host <hostname[:port]>\n"
302 " stream from this host. The default port is %d.\n"
303 " --stream-no-query Do not query and set the DV timings or standard before streaming.\n"
304 " --stream-loop loop when the end of the file we are streaming from is reached.\n"
305 " The default is to stop.\n"
306 " --stream-out-pattern <count>\n"
307 " choose output test pattern. The default is 0.\n"
308 " --stream-out-square\n"
309 " show a square in the middle of the output test pattern.\n"
310 " --stream-out-border\n"
311 " show a border around the pillar/letterboxed video.\n"
312 " --stream-out-sav insert an SAV code in every line.\n"
313 " --stream-out-eav insert an EAV code in every line.\n"
314 " --stream-out-pixel-aspect <aspect\n"
315 " select a pixel aspect ratio. The default is to autodetect.\n"
316 " <aspect> can be one of: square, ntsc, pal\n"
317 " --stream-out-video-aspect <aspect\n"
318 " select a video aspect ratio. The default is to use the frame ratio.\n"
319 " <aspect> can be one of: 4x3, 14x9, 16x9, anamorphic\n"
320 " --stream-out-alpha <alpha-value>\n"
321 " value to use for the alpha component, range 0-255. The default is 0.\n"
322 " --stream-out-alpha-red-only\n"
323 " only use the --stream-out-alpha value for the red colors,\n"
324 " for all others use 0.\n"
325 " --stream-out-rgb-lim-range\n"
326 " Encode RGB values as limited [16-235] instead of full range.\n"
327 " --stream-out-hor-speed <speed>\n"
328 " choose speed for horizontal movement. The default is 0,\n"
329 " and the range is [-3...3].\n"
330 " --stream-out-vert-speed <speed>\n"
331 " choose speed for vertical movement. The default is 0,\n"
332 " and the range is [-3...3].\n"
333 " --stream-out-perc-fill <percentage>\n"
334 " percentage of the frame to actually fill. The default is 100%%.\n"
335 " --stream-out-buf-caps\n"
336 " show output buffer capabilities\n"
337 " --stream-out-mmap <count>\n"
338 " output video using mmap() [VIDIOC_(D)QBUF]\n"
339 " count: the number of buffers to allocate. The default is 4.\n"
340 " --stream-out-user <count>\n"
341 " output video using user pointers [VIDIOC_(D)QBUF]\n"
342 " count: the number of buffers to allocate. The default is 4.\n"
343 " --stream-out-dmabuf\n"
344 " output video using dmabuf [VIDIOC_(D)QBUF]\n"
345 " Requires a corresponding --stream-mmap option.\n"
346 " --list-patterns list available patterns for use with --stream-pattern.\n"
347 " --list-buffers list all video buffers [VIDIOC_QUERYBUF]\n"
348 " --list-buffers-out list all video output buffers [VIDIOC_QUERYBUF]\n"
349 " --list-buffers-vbi list all VBI buffers [VIDIOC_QUERYBUF]\n"
350 " --list-buffers-vbi-out\n"
351 " list all VBI output buffers [VIDIOC_QUERYBUF]\n"
352 " --list-buffers-sliced-vbi\n"
353 " list all sliced VBI buffers [VIDIOC_QUERYBUF]\n"
354 " --list-buffers-sliced-vbi-out\n"
355 " list all sliced VBI output buffers [VIDIOC_QUERYBUF]\n"
356 " --list-buffers-sdr\n"
357 " list all SDR RX buffers [VIDIOC_QUERYBUF]\n"
358 " --list-buffers-sdr-out\n"
359 " list all SDR TX buffers [VIDIOC_QUERYBUF]\n"
360 " --list-buffers-meta\n"
361 " list all Meta RX buffers [VIDIOC_QUERYBUF]\n",
362 #ifndef NO_STREAM_TO
363 V4L_STREAM_PORT,
364 #endif
365 V4L_STREAM_PORT);
366 }
367
get_codec_type(cv4l_fd & fd)368 static enum codec_type get_codec_type(cv4l_fd &fd)
369 {
370 cv4l_disable_trace dt(fd);
371 struct v4l2_fmtdesc fmt_desc = {};
372 int num_cap_fmts = 0;
373 int num_compressed_cap_fmts = 0;
374 int num_out_fmts = 0;
375 int num_compressed_out_fmts = 0;
376
377 if (!fd.has_vid_m2m())
378 return NOT_CODEC;
379
380 if (fd.enum_fmt(fmt_desc, true, 0, fd.g_type()))
381 return NOT_CODEC;
382
383 do {
384 if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED)
385 num_compressed_cap_fmts++;
386 num_cap_fmts++;
387 } while (!fd.enum_fmt(fmt_desc));
388
389
390 if (fd.enum_fmt(fmt_desc, true, 0, v4l_type_invert(fd.g_type())))
391 return NOT_CODEC;
392
393 do {
394 if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED)
395 num_compressed_out_fmts++;
396 num_out_fmts++;
397 } while (!fd.enum_fmt(fmt_desc));
398
399 if (num_compressed_out_fmts == 0 && num_compressed_cap_fmts == num_cap_fmts) {
400 return ENCODER;
401 }
402
403 if (num_compressed_cap_fmts == 0 && num_compressed_out_fmts == num_out_fmts) {
404 return DECODER;
405 }
406
407 return NOT_CODEC;
408 }
409
get_cap_compose_rect(cv4l_fd & fd)410 static int get_cap_compose_rect(cv4l_fd &fd)
411 {
412 cv4l_disable_trace dt(fd);
413 v4l2_selection sel;
414
415 memset(&sel, 0, sizeof(sel));
416 sel.type = vidcap_buftype;
417 sel.target = V4L2_SEL_TGT_COMPOSE;
418
419 if (fd.g_selection(sel) == 0) {
420 support_cap_compose = true;
421 composed_width = sel.r.width;
422 composed_height = sel.r.height;
423 return 0;
424 }
425
426 support_cap_compose = false;
427 return 0;
428 }
429
get_out_crop_rect(cv4l_fd & fd)430 static int get_out_crop_rect(cv4l_fd &fd)
431 {
432 cv4l_disable_trace dt(fd);
433 v4l2_selection sel;
434
435 memset(&sel, 0, sizeof(sel));
436 sel.type = vidout_buftype;
437 sel.target = V4L2_SEL_TGT_CROP;
438
439 if (fd.g_selection(sel) == 0) {
440 support_out_crop = true;
441 cropped_width = sel.r.width;
442 cropped_height = sel.r.height;
443 return 0;
444 }
445
446 support_out_crop = false;
447 return 0;
448 }
449
set_time_stamp(cv4l_buffer & buf)450 static void set_time_stamp(cv4l_buffer &buf)
451 {
452 if ((buf.g_flags() & V4L2_BUF_FLAG_TIMESTAMP_MASK) != V4L2_BUF_FLAG_TIMESTAMP_COPY)
453 return;
454 buf.s_timestamp_clock();
455 }
456
read_u32(FILE * f)457 static uint32_t read_u32(FILE *f)
458 {
459 uint32_t v;
460
461 if (fread(&v, 1, sizeof(v), f) != sizeof(v))
462 return 0;
463 return ntohl(v);
464 }
465
write_u32(FILE * f,uint32_t v)466 static void write_u32(FILE *f, uint32_t v)
467 {
468 v = htonl(v);
469 fwrite(&v, 1, sizeof(v), f);
470 }
471
timestamp_type2s(uint32_t flags)472 static std::string timestamp_type2s(uint32_t flags)
473 {
474 char buf[20];
475
476 switch (flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) {
477 case V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN:
478 return "Unknown";
479 case V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC:
480 return "Monotonic";
481 case V4L2_BUF_FLAG_TIMESTAMP_COPY:
482 return "Copy";
483 default:
484 sprintf(buf, "Type %d", (flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) >> 13);
485 return std::string(buf);
486 }
487 }
488
timestamp_src2s(uint32_t flags)489 static std::string timestamp_src2s(uint32_t flags)
490 {
491 char buf[20];
492
493 switch (flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) {
494 case V4L2_BUF_FLAG_TSTAMP_SRC_EOF:
495 return "End-of-Frame";
496 case V4L2_BUF_FLAG_TSTAMP_SRC_SOE:
497 return "Start-of-Exposure";
498 default:
499 sprintf(buf, "Source %d", (flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) >> 16);
500 return std::string(buf);
501 }
502 }
503
print_buffer(FILE * f,struct v4l2_buffer & buf)504 static void print_buffer(FILE *f, struct v4l2_buffer &buf)
505 {
506 const unsigned ts_flags = V4L2_BUF_FLAG_TIMESTAMP_MASK | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
507
508 fprintf(f, "\tIndex : %d\n", buf.index);
509 fprintf(f, "\tType : %s\n", buftype2s(buf.type).c_str());
510 fprintf(f, "\tFlags : %s\n", bufferflags2s(buf.flags & ~ts_flags).c_str());
511 fprintf(f, "\tField : %s\n", field2s(buf.field).c_str());
512 fprintf(f, "\tSequence : %u\n", buf.sequence);
513 fprintf(f, "\tLength : %u\n", buf.length);
514 fprintf(f, "\tBytesused: %u\n", buf.bytesused);
515 fprintf(f, "\tTimestamp: %llu.%06llus (%s, %s)\n",
516 static_cast<uint64_t>(buf.timestamp.tv_sec), static_cast<uint64_t>(buf.timestamp.tv_usec),
517 timestamp_type2s(buf.flags).c_str(), timestamp_src2s(buf.flags).c_str());
518 if (buf.flags & V4L2_BUF_FLAG_TIMECODE) {
519 static const int fps_types[] = { 0, 24, 25, 30, 50, 60 };
520 int fps = buf.timecode.type;
521
522 if (fps > 5)
523 fps = 0;
524 fprintf(f, "\tTimecode : %dfps %s %dh %dm %ds %df (0x%02x 0x%02x 0x%02x 0x%02x)\n",
525 fps_types[fps],
526 tc_flags2s(buf.timecode.flags).c_str(),
527 buf.timecode.hours, buf.timecode.minutes,
528 buf.timecode.seconds, buf.timecode.frames,
529 buf.timecode.userbits[0], buf.timecode.userbits[1],
530 buf.timecode.userbits[2], buf.timecode.userbits[3]);
531 }
532 if (buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
533 buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
534 for (unsigned i = 0; i < buf.length; i++) {
535 struct v4l2_plane *p = buf.m.planes + i;
536
537 fprintf(f, "\tPlane : %d\n", i);
538 fprintf(f, "\t\tLength : %u\n", p->length);
539 fprintf(f, "\t\tBytesused : %u\n", p->bytesused);
540 fprintf(f, "\t\tData Offset: %u\n", p->data_offset);
541 }
542 }
543
544 fprintf(f, "\n");
545 }
546
print_concise_buffer(FILE * f,cv4l_buffer & buf,cv4l_fmt & fmt,cv4l_queue & q,fps_timestamps & fps_ts,int comp_perc,bool skip_ts=false)547 static void print_concise_buffer(FILE *f, cv4l_buffer &buf, cv4l_fmt &fmt,
548 cv4l_queue &q, fps_timestamps &fps_ts,
549 int comp_perc, bool skip_ts = false)
550 {
551 static double last_ts;
552
553 fprintf(f, "%s dqbuf: %*u seq: %6u bytesused: ",
554 v4l_type_is_output(buf.g_type()) ? "out" : "cap",
555 reqbufs_count_cap > 10 ? 2 : 1, buf.g_index(), buf.g_sequence());
556
557 bool have_data_offset = false;
558
559 for (unsigned i = 0; i < buf.g_num_planes(); i++) {
560 fprintf(f, "%s%u", i ? "/" : "", buf.g_bytesused(i));
561 if (buf.g_data_offset(i))
562 have_data_offset = true;
563 }
564 if (have_data_offset) {
565 fprintf(f, " offset: ");
566 for (unsigned i = 0; i < buf.g_num_planes(); i++)
567 fprintf(f, "%s%u", i ? "/" : "", buf.g_data_offset(i));
568 }
569 if (comp_perc >= 0)
570 fprintf(f, " compression: %d%%", comp_perc);
571
572 if (!skip_ts && (buf.g_flags() & V4L2_BUF_FLAG_TIMESTAMP_MASK) != V4L2_BUF_FLAG_TIMESTAMP_COPY) {
573 double ts = buf.g_timestamp().tv_sec + buf.g_timestamp().tv_usec / 1000000.0;
574 fprintf(f, " ts: %.06f", ts);
575 if (last_ts <= 0.0)
576 fprintf(f, " delta: %.03f ms", (ts - last_ts) * 1000.0);
577 last_ts = ts;
578
579 if (fps_ts.has_fps(true))
580 fprintf(stderr, " fps: %.02f", fps_ts.fps());
581
582 unsigned dropped = fps_ts.dropped();
583
584 if (dropped)
585 fprintf(stderr, " dropped: %u", dropped);
586 }
587
588 uint32_t fl = buf.g_flags() & (V4L2_BUF_FLAG_ERROR |
589 V4L2_BUF_FLAG_KEYFRAME |
590 V4L2_BUF_FLAG_PFRAME |
591 V4L2_BUF_FLAG_BFRAME |
592 V4L2_BUF_FLAG_LAST |
593 V4L2_BUF_FLAG_TIMESTAMP_MASK |
594 V4L2_BUF_FLAG_TSTAMP_SRC_MASK |
595 V4L2_BUF_FLAG_TIMECODE);
596 if (fl)
597 fprintf(f, " (%s)", bufferflags2s(fl).c_str());
598 fprintf(f, "\n");
599 if (v4l_type_is_meta(buf.g_type()) && buf.g_bytesused(0) &&
600 !(buf.g_flags() & V4L2_BUF_FLAG_ERROR))
601 print_meta_buffer(f, buf, fmt, q);
602
603 if ((capabilities & V4L2_CAP_TOUCH) && buf.g_bytesused(0) &&
604 !(buf.g_flags() & V4L2_BUF_FLAG_ERROR) &&
605 (fmt.g_width() < 64 || fmt.g_height() < 64))
606 print_touch_buffer(f, buf, fmt, q);
607 }
608
stream_buf_caps(cv4l_fd & fd,unsigned buftype)609 static void stream_buf_caps(cv4l_fd &fd, unsigned buftype)
610 {
611 v4l2_create_buffers cbufs;
612
613 memset(&cbufs, 0, sizeof(cbufs));
614 cbufs.format.type = buftype;
615 cbufs.memory = V4L2_MEMORY_MMAP;
616 if (!v4l_ioctl(fd.g_v4l_fd(), VIDIOC_CREATE_BUFS, &cbufs)) {
617 printf("Streaming I/O Capabilities for %s: %s\n",
618 buftype2s(buftype).c_str(),
619 bufcap2s(cbufs.capabilities).c_str());
620 return;
621 }
622 v4l2_requestbuffers rbufs;
623 memset(&rbufs, 0, sizeof(rbufs));
624 rbufs.type = buftype;
625 rbufs.memory = V4L2_MEMORY_MMAP;
626 if (v4l_ioctl(fd.g_v4l_fd(), VIDIOC_REQBUFS, &rbufs))
627 return;
628 printf("Streaming I/O Capabilities for %s: %s\n",
629 buftype2s(buftype).c_str(),
630 bufcap2s(rbufs.capabilities).c_str());
631 }
632
list_buffers(cv4l_fd & fd,unsigned buftype)633 static void list_buffers(cv4l_fd &fd, unsigned buftype)
634 {
635 cv4l_disable_trace dt(fd);
636 int i;
637
638 for (i = 0; i < VIDEO_MAX_FRAME; i++) {
639 cv4l_buffer buf(buftype);
640
641 if (fd.querybuf(buf, i))
642 break;
643 if (i == 0)
644 printf("VIDIOC_QUERYBUF:\n");
645 print_buffer(stdout, buf.buf);
646 }
647 }
648
streaming_cmd(int ch,char * optarg)649 void streaming_cmd(int ch, char *optarg)
650 {
651 unsigned i;
652 int speed;
653
654 switch (ch) {
655 case OptStreamCount:
656 stream_count = strtoul(optarg, 0L, 0);
657 break;
658 case OptStreamSkip:
659 stream_skip = strtoul(optarg, 0L, 0);
660 break;
661 case OptStreamSleep:
662 stream_sleep = strtol(optarg, 0L, 0);
663 break;
664 case OptStreamNoQuery:
665 stream_no_query = true;
666 break;
667 case OptStreamLoop:
668 stream_loop = true;
669 break;
670 case OptStreamOutPattern:
671 stream_pat = strtoul(optarg, 0L, 0);
672 for (i = 0; tpg_pattern_strings[i]; i++) ;
673 if (stream_pat >= i)
674 stream_pat = 0;
675 break;
676 case OptStreamOutSquare:
677 stream_out_square = true;
678 break;
679 case OptStreamOutBorder:
680 stream_out_border = true;
681 break;
682 case OptStreamOutInsertSAV:
683 stream_out_sav = true;
684 break;
685 case OptStreamOutInsertEAV:
686 stream_out_eav = true;
687 break;
688 case OptStreamOutPixelAspect:
689 if (!strcmp(optarg, "square"))
690 stream_out_pixel_aspect = TPG_PIXEL_ASPECT_SQUARE;
691 else if (!strcmp(optarg, "ntsc"))
692 stream_out_pixel_aspect = TPG_PIXEL_ASPECT_NTSC;
693 else if (!strcmp(optarg, "pal"))
694 stream_out_pixel_aspect = TPG_PIXEL_ASPECT_PAL;
695 else
696 streaming_usage();
697 break;
698 case OptStreamOutVideoAspect:
699 if (!strcmp(optarg, "4x3"))
700 stream_out_video_aspect = TPG_VIDEO_ASPECT_4X3;
701 else if (!strcmp(optarg, "14x9"))
702 stream_out_video_aspect = TPG_VIDEO_ASPECT_14X9_CENTRE;
703 else if (!strcmp(optarg, "16x9"))
704 stream_out_video_aspect = TPG_VIDEO_ASPECT_16X9_CENTRE;
705 else if (!strcmp(optarg, "anamorphic"))
706 stream_out_video_aspect = TPG_VIDEO_ASPECT_16X9_ANAMORPHIC;
707 else
708 streaming_usage();
709 break;
710 case OptStreamOutAlphaComponent:
711 stream_out_alpha = strtoul(optarg, 0L, 0);
712 break;
713 case OptStreamOutAlphaRedOnly:
714 stream_out_alpha_red_only = true;
715 break;
716 case OptStreamOutRGBLimitedRange:
717 stream_out_rgb_lim_range = true;
718 break;
719 case OptStreamOutHorSpeed:
720 case OptStreamOutVertSpeed:
721 speed = strtol(optarg, 0L, 0);
722 if (speed < -3)
723 speed = -3;
724 if (speed > 3)
725 speed = 3;
726 if (ch == OptStreamOutHorSpeed)
727 stream_out_hor_mode = static_cast<tpg_move_mode>(speed + 3);
728 else
729 stream_out_vert_mode = static_cast<tpg_move_mode>(speed + 3);
730 break;
731 case OptStreamOutPercFill:
732 stream_out_perc_fill = strtoul(optarg, 0L, 0);
733 if (stream_out_perc_fill > 100)
734 stream_out_perc_fill = 100;
735 if (stream_out_perc_fill < 1)
736 stream_out_perc_fill = 1;
737 break;
738 case OptStreamTo:
739 file_to = optarg;
740 to_with_hdr = false;
741 if (!strcmp(file_to, "-"))
742 options[OptSilent] = true;
743 break;
744 case OptStreamToHdr:
745 file_to = optarg;
746 to_with_hdr = true;
747 if (!strcmp(file_to, "-"))
748 options[OptSilent] = true;
749 break;
750 case OptStreamToHost:
751 host_to = optarg;
752 break;
753 case OptStreamLossless:
754 host_lossless = true;
755 break;
756 case OptStreamFrom:
757 file_from = optarg;
758 from_with_hdr = false;
759 break;
760 case OptStreamFromHdr:
761 file_from = optarg;
762 from_with_hdr = true;
763 break;
764 case OptStreamFromHost:
765 host_from = optarg;
766 break;
767 case OptStreamUser:
768 memory = V4L2_MEMORY_USERPTR;
769 ;
770 case OptStreamMmap:
771 if (optarg) {
772 reqbufs_count_cap = strtoul(optarg, 0L, 0);
773 if (reqbufs_count_cap == 0)
774 reqbufs_count_cap = 3;
775 }
776 break;
777 case OptStreamDmaBuf:
778 memory = V4L2_MEMORY_DMABUF;
779 break;
780 case OptStreamOutUser:
781 out_memory = V4L2_MEMORY_USERPTR;
782 ;
783 case OptStreamOutMmap:
784 if (optarg) {
785 reqbufs_count_out = strtoul(optarg, 0L, 0);
786 if (reqbufs_count_out == 0)
787 reqbufs_count_out = 3;
788 }
789 break;
790 case OptStreamOutDmaBuf:
791 out_memory = V4L2_MEMORY_DMABUF;
792 break;
793 }
794 }
795
796 /*
797 * Assume that the fwht stream is valid and that each
798 * frame starts right after the previous one.
799 */
read_fwht_frame(cv4l_fmt & fmt,unsigned char * buf,FILE * fpointer,unsigned & sz,unsigned & expected_len,unsigned buf_len)800 static bool read_fwht_frame(cv4l_fmt &fmt, unsigned char *buf,
801 FILE *fpointer, unsigned &sz,
802 unsigned &expected_len, unsigned buf_len)
803 {
804 expected_len = sizeof(struct fwht_cframe_hdr);
805 if (expected_len > buf_len)
806 return false;
807 sz = fread(&last_fwht_hdr, 1, sizeof(struct fwht_cframe_hdr), fpointer);
808 if (sz < sizeof(struct fwht_cframe_hdr))
809 return true;
810
811 expected_len = ntohl(last_fwht_hdr.size);
812 if (expected_len > buf_len)
813 return false;
814 sz = fread(buf, 1, ntohl(last_fwht_hdr.size), fpointer);
815 return true;
816 }
817
set_fwht_stateless_params(struct v4l2_ctrl_fwht_params & fwht_params,const struct fwht_cframe_hdr * hdr,uint64_t last_bf_ts)818 static void set_fwht_stateless_params(struct v4l2_ctrl_fwht_params &fwht_params,
819 const struct fwht_cframe_hdr *hdr,
820 uint64_t last_bf_ts)
821 {
822 fwht_params.backward_ref_ts = last_bf_ts;
823 fwht_params.version = ntohl(hdr->version);
824 fwht_params.width = ntohl(hdr->width);
825 fwht_params.height = ntohl(hdr->height);
826 fwht_params.flags = ntohl(hdr->flags);
827 fwht_params.colorspace = ntohl(hdr->colorspace);
828 fwht_params.xfer_func = ntohl(hdr->xfer_func);
829 fwht_params.ycbcr_enc = ntohl(hdr->ycbcr_enc);
830 fwht_params.quantization = ntohl(hdr->quantization);
831
832 /*
833 * if last_bf_ts is 0 it indicates that either this is the
834 * first frame, or that last frame returned with an error so
835 * it is better not to reference it so the error won't propagate
836 */
837 if (!last_bf_ts)
838 fwht_params.flags |= FWHT_FL_I_FRAME;
839 }
840
alloc_fwht_req(int media_fd,unsigned index)841 static int alloc_fwht_req(int media_fd, unsigned index)
842 {
843 int rc = 0;
844
845 rc = ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &fwht_reqs[index]);
846 if (rc < 0) {
847 fprintf(stderr, "Unable to allocate media request: %s\n",
848 strerror(errno));
849 return rc;
850 }
851
852 return 0;
853 }
854
set_fwht_req_by_idx(unsigned idx,const struct fwht_cframe_hdr * hdr,uint64_t last_bf_ts,uint64_t ts)855 static void set_fwht_req_by_idx(unsigned idx, const struct fwht_cframe_hdr *hdr,
856 uint64_t last_bf_ts, uint64_t ts)
857 {
858 struct v4l2_ctrl_fwht_params fwht_params;
859
860 set_fwht_stateless_params(fwht_params, hdr, last_bf_ts);
861
862 fwht_reqs[idx].ts = ts;
863 fwht_reqs[idx].params = fwht_params;
864 }
865
get_fwht_req_by_ts(uint64_t ts)866 static int get_fwht_req_by_ts(uint64_t ts)
867 {
868 for (int idx = 0; idx < VIDEO_MAX_FRAME; idx++) {
869 if (fwht_reqs[idx].ts == ts)
870 return idx;
871 }
872 return -1;
873 }
874
set_fwht_req_by_fd(const struct fwht_cframe_hdr * hdr,int req_fd,uint64_t last_bf_ts,uint64_t ts)875 static bool set_fwht_req_by_fd(const struct fwht_cframe_hdr *hdr,
876 int req_fd, uint64_t last_bf_ts, uint64_t ts)
877 {
878 struct v4l2_ctrl_fwht_params fwht_params;
879
880 set_fwht_stateless_params(fwht_params, hdr, last_bf_ts);
881
882 for (int idx = 0; idx < VIDEO_MAX_FRAME; idx++) {
883 if (fwht_reqs[idx].fd == req_fd) {
884 fwht_reqs[idx].ts = ts;
885 fwht_reqs[idx].params = fwht_params;
886 return true;
887 }
888 }
889 return false;
890 }
891
set_fwht_ext_ctrl(cv4l_fd & fd,const struct fwht_cframe_hdr * hdr,uint64_t last_bf_ts,int req_fd)892 static int set_fwht_ext_ctrl(cv4l_fd &fd, const struct fwht_cframe_hdr *hdr,
893 uint64_t last_bf_ts, int req_fd)
894 {
895 v4l2_ext_controls controls;
896 struct v4l2_ext_control control;
897 struct v4l2_ctrl_fwht_params fwht_params;
898
899 memset(&control, 0, sizeof(control));
900 memset(&controls, 0, sizeof(controls));
901
902 set_fwht_stateless_params(fwht_params, hdr, last_bf_ts);
903
904 control.id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS;
905 control.ptr = &fwht_params;
906 control.size = sizeof(fwht_params);
907 controls.which = V4L2_CTRL_WHICH_REQUEST_VAL;
908 controls.request_fd = req_fd;
909 controls.controls = &control;
910 controls.count = 1;
911 return fd.s_ext_ctrls(controls);
912 }
913
read_write_padded_frame(cv4l_fmt & fmt,unsigned char * buf,FILE * fpointer,unsigned & sz,unsigned & expected_len,unsigned buf_len,bool is_read)914 static bool read_write_padded_frame(cv4l_fmt &fmt, unsigned char *buf,
915 FILE *fpointer, unsigned &sz,
916 unsigned &expected_len, unsigned buf_len,
917 bool is_read)
918 {
919 const struct v4l2_fwht_pixfmt_info *info =
920 v4l2_fwht_find_pixfmt(fmt.g_pixelformat());
921 unsigned coded_height = fmt.g_height();
922 unsigned real_width;
923 unsigned real_height;
924 unsigned char *plane_p = buf;
925 unsigned char *row_p;
926 unsigned stride = fmt.g_bytesperline();
927
928 if (is_read) {
929 real_width = cropped_width;
930 real_height = cropped_height;
931 } else {
932 real_width = composed_width;
933 real_height = composed_height;
934 }
935
936 sz = 0;
937 expected_len = real_width * real_height * info->sizeimage_mult / info->sizeimage_div;
938 if (expected_len > buf_len)
939 return false;
940 for (unsigned plane_idx = 0; plane_idx < info->planes_num; plane_idx++) {
941 bool is_chroma_plane = plane_idx == 1 || plane_idx == 2;
942 unsigned h_div = is_chroma_plane ? info->height_div : 1;
943 unsigned w_div = is_chroma_plane ? info->width_div : 1;
944 unsigned step = is_chroma_plane ? info->chroma_step :
945 info->luma_alpha_step;
946 unsigned int consume_sz = step * real_width / w_div;
947
948 if (info->planes_num == 3 && plane_idx == 1)
949 stride /= 2;
950
951 if (plane_idx == 1 &&
952 (info->id == V4L2_PIX_FMT_NV24 || info->id == V4L2_PIX_FMT_NV42))
953 stride *= 2;
954
955 row_p = plane_p;
956 for (unsigned i = 0; i < real_height / h_div; i++) {
957 unsigned int wsz = 0;
958
959 if (is_read)
960 wsz = fread(row_p, 1, consume_sz, fpointer);
961 else
962 wsz = fwrite(row_p, 1, consume_sz, fpointer);
963 if (wsz == 0 && i == 0 && plane_idx == 0)
964 break;
965 if (wsz != consume_sz) {
966 fprintf(stderr, "padding: needed %u bytes, got %u\n", consume_sz, wsz);
967 return true;
968 }
969 sz += wsz;
970 row_p += stride;
971 }
972 plane_p += stride * (coded_height / h_div);
973 if (sz == 0)
974 break;
975 }
976 return true;
977 }
978
fill_buffer_from_file(cv4l_fd & fd,cv4l_queue & q,cv4l_buffer & b,cv4l_fmt & fmt,FILE * fin)979 static bool fill_buffer_from_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &b,
980 cv4l_fmt &fmt, FILE *fin)
981 {
982 static bool first = true;
983 static bool is_fwht = false;
984
985 if (host_fd_from >= 0) {
986 for (;;) {
987 unsigned packet = read_u32(fin);
988
989 if (packet == V4L_STREAM_PACKET_END) {
990 fprintf(stderr, "END packet read\n");
991 return false;
992 }
993
994 char buf[1024];
995 unsigned sz = read_u32(fin);
996
997 if (packet == V4L_STREAM_PACKET_FRAME_VIDEO_RLE ||
998 packet == V4L_STREAM_PACKET_FRAME_VIDEO_FWHT) {
999 is_fwht = packet == V4L_STREAM_PACKET_FRAME_VIDEO_FWHT;
1000 if (is_fwht && !ctx) {
1001 fprintf(stderr, "cannot support FWHT encoding\n");
1002 return false;
1003 }
1004 break;
1005 }
1006
1007 fprintf(stderr, "expected FRAME_VIDEO, got 0x%08x\n", packet);
1008 while (sz) {
1009 unsigned rdsize = sz > sizeof(buf) ? sizeof(buf) : sz;
1010
1011 int n = fread(buf, 1, rdsize, fin);
1012 if (n < 0) {
1013 fprintf(stderr, "error reading %d bytes\n", sz);
1014 return false;
1015 }
1016 sz -= n;
1017 }
1018 }
1019
1020 unsigned sz = read_u32(fin);
1021
1022 if (sz != V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_HDR) {
1023 fprintf(stderr, "unsupported FRAME_VIDEO size\n");
1024 return false;
1025 }
1026 read_u32(fin); // ignore field
1027 read_u32(fin); // ignore flags
1028 for (unsigned j = 0; j < q.g_num_planes(); j++) {
1029 uint8_t *buf = static_cast<uint8_t *>(q.g_dataptr(b.g_index(), j));
1030
1031 sz = read_u32(fin);
1032 if (sz != V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_PLANE_HDR) {
1033 fprintf(stderr, "unsupported FRAME_VIDEO plane size\n");
1034 return false;
1035 }
1036 uint32_t size = read_u32(fin);
1037 uint32_t comp_size = read_u32(fin);
1038 uint32_t offset = size - comp_size;
1039 unsigned sz = comp_size;
1040 uint8_t *read_buf = buf;
1041
1042 if (is_fwht) {
1043 read_buf = new uint8_t[comp_size];
1044 offset = 0;
1045 }
1046
1047 if (size > q.g_length(j)) {
1048 fprintf(stderr, "plane size is too large (%u > %u)\n",
1049 size, q.g_length(j));
1050 return false;
1051 }
1052 while (sz) {
1053 int n = fread(read_buf + offset, 1, sz, fin);
1054 if (n < 0) {
1055 fprintf(stderr, "error reading %d bytes\n", sz);
1056 return false;
1057 }
1058 if (static_cast<uint32_t>(n) == sz)
1059 break;
1060 offset += n;
1061 sz -= n;
1062 }
1063 if (is_fwht) {
1064 fwht_decompress(ctx, read_buf, comp_size, buf, size);
1065 delete [] read_buf;
1066 } else {
1067 rle_decompress(buf, size, comp_size, bpl_out[j]);
1068 }
1069 }
1070 return true;
1071 }
1072
1073 restart:
1074 if (from_with_hdr) {
1075 uint32_t v;
1076
1077 if (!fread(&v, sizeof(v), 1, fin)) {
1078 if (first) {
1079 fprintf(stderr, "Insufficient data\n");
1080 return false;
1081 }
1082 if (stream_loop) {
1083 fseek(fin, 0, SEEK_SET);
1084 first = true;
1085 goto restart;
1086 }
1087 return false;
1088 }
1089 if (ntohl(v) != FILE_HDR_ID) {
1090 fprintf(stderr, "Unknown header ID\n");
1091 return false;
1092 }
1093 }
1094
1095 for (unsigned j = 0; j < q.g_num_planes(); j++) {
1096 void *buf = q.g_dataptr(b.g_index(), j);
1097 unsigned buf_len = q.g_length(j);
1098 unsigned expected_len = q.g_length(j);
1099 unsigned sz;
1100 cv4l_fmt fmt;
1101 bool res = true;
1102
1103 fd.g_fmt(fmt, q.g_type());
1104 if (from_with_hdr) {
1105 expected_len = read_u32(fin);
1106 if (expected_len > q.g_length(j)) {
1107 fprintf(stderr, "plane size is too large (%u > %u)\n",
1108 expected_len, q.g_length(j));
1109 return false;
1110 }
1111 }
1112
1113 if (fmt.g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS)
1114 res = read_fwht_frame(fmt, static_cast<unsigned char *>(buf), fin,
1115 sz, expected_len, buf_len);
1116 else if (support_out_crop && v4l2_fwht_find_pixfmt(fmt.g_pixelformat()))
1117 res = read_write_padded_frame(fmt, static_cast<unsigned char *>(buf),
1118 fin, sz, expected_len, buf_len, true);
1119 else
1120 sz = fread(buf, 1, expected_len, fin);
1121
1122 if (!res) {
1123 fprintf(stderr, "amount intended to be read/written is larger than the buffer size\n");
1124 return false;
1125 }
1126 if (first && sz != expected_len && fmt.g_bytesperline(j)) {
1127 fprintf(stderr, "%s: size read (%u) is different than needed (%u) in the first frame\n",
1128 __func__, sz, expected_len);
1129 return false;
1130 }
1131 if (j == 0 && sz == 0 && stream_loop) {
1132 fseek(fin, 0, SEEK_SET);
1133 first = true;
1134 goto restart;
1135 }
1136 b.s_bytesused(sz, j);
1137 if (sz == expected_len)
1138 continue;
1139 if (sz == 0)
1140 return false;
1141 if (sz && fmt.g_bytesperline(j))
1142 fprintf(stderr, "%u != %u\n", sz, expected_len);
1143 }
1144 first = false;
1145 return true;
1146 }
1147
do_setup_out_buffers(cv4l_fd & fd,cv4l_queue & q,FILE * fin,bool qbuf,bool ignore_count_skip)1148 static int do_setup_out_buffers(cv4l_fd &fd, cv4l_queue &q, FILE *fin, bool qbuf,
1149 bool ignore_count_skip)
1150 {
1151 tpg_pixel_aspect aspect = TPG_PIXEL_ASPECT_SQUARE;
1152 cv4l_fmt fmt(q.g_type());
1153 u32 field;
1154 unsigned p;
1155 bool can_fill = false;
1156 bool is_video = q.g_type() == V4L2_BUF_TYPE_VIDEO_OUTPUT ||
1157 q.g_type() == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
1158 bool is_meta = q.g_type() == V4L2_BUF_TYPE_META_OUTPUT;
1159
1160 if (q.obtain_bufs(&fd))
1161 return QUEUE_ERROR;
1162
1163 fd.g_fmt(fmt, q.g_type());
1164 {
1165 cv4l_disable_trace dt(fd);
1166 if (fd.g_std(stream_out_std)) {
1167 struct v4l2_dv_timings timings;
1168
1169 stream_out_std = 0;
1170 if (fd.g_dv_timings(timings))
1171 memset(&timings, 0, sizeof(timings));
1172 else if (timings.bt.width == 720 && timings.bt.height == 480)
1173 aspect = TPG_PIXEL_ASPECT_NTSC;
1174 else if (timings.bt.width == 720 && timings.bt.height == 576)
1175 aspect = TPG_PIXEL_ASPECT_PAL;
1176 } else if (stream_out_std & V4L2_STD_525_60) {
1177 aspect = TPG_PIXEL_ASPECT_NTSC;
1178 } else if (stream_out_std & V4L2_STD_625_50) {
1179 aspect = TPG_PIXEL_ASPECT_PAL;
1180 }
1181 }
1182
1183 field = fmt.g_field();
1184
1185 output_field = field;
1186 output_field_alt = field == V4L2_FIELD_ALTERNATE;
1187 if (V4L2_FIELD_HAS_T_OR_B(field))
1188 output_field = (stream_out_std & V4L2_STD_525_60) ?
1189 V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
1190
1191 if (is_video) {
1192 tpg_init(&tpg, 640, 360);
1193 tpg_alloc(&tpg, fmt.g_width());
1194 can_fill = tpg_s_fourcc(&tpg, fmt.g_pixelformat());
1195 tpg_reset_source(&tpg, fmt.g_width(), fmt.g_frame_height(), field);
1196 tpg_s_colorspace(&tpg, fmt.g_colorspace());
1197 tpg_s_xfer_func(&tpg, fmt.g_xfer_func());
1198 tpg_s_ycbcr_enc(&tpg, fmt.g_ycbcr_enc());
1199 tpg_s_quantization(&tpg, fmt.g_quantization());
1200 for (p = 0; p < fmt.g_num_planes(); p++)
1201 tpg_s_bytesperline(&tpg, p,
1202 fmt.g_bytesperline(p));
1203 tpg_s_pattern(&tpg, static_cast<tpg_pattern>(stream_pat));
1204 tpg_s_mv_hor_mode(&tpg, stream_out_hor_mode);
1205 tpg_s_mv_vert_mode(&tpg, stream_out_vert_mode);
1206 tpg_s_show_square(&tpg, stream_out_square);
1207 tpg_s_show_border(&tpg, stream_out_border);
1208 tpg_s_insert_sav(&tpg, stream_out_sav);
1209 tpg_s_insert_eav(&tpg, stream_out_eav);
1210 tpg_s_perc_fill(&tpg, stream_out_perc_fill);
1211 if (stream_out_rgb_lim_range)
1212 tpg_s_real_rgb_range(&tpg, V4L2_DV_RGB_RANGE_LIMITED);
1213 tpg_s_alpha_component(&tpg, stream_out_alpha);
1214 tpg_s_alpha_mode(&tpg, stream_out_alpha_red_only);
1215 tpg_s_video_aspect(&tpg, stream_out_video_aspect);
1216 switch (stream_out_pixel_aspect) {
1217 case -1:
1218 tpg_s_pixel_aspect(&tpg, aspect);
1219 break;
1220 default:
1221 tpg_s_pixel_aspect(&tpg, static_cast<tpg_pixel_aspect>(stream_out_pixel_aspect));
1222 break;
1223 }
1224 field = output_field;
1225 if (can_fill && ((V4L2_FIELD_HAS_T_OR_B(field) && (stream_count & 1)) ||
1226 !tpg_pattern_is_static(&tpg)))
1227 stream_out_refresh = true;
1228 }
1229
1230 for (unsigned i = 0; i < q.g_buffers(); i++) {
1231 cv4l_buffer buf(q);
1232
1233 if (fd.querybuf(buf, i))
1234 return QUEUE_ERROR;
1235
1236 buf.update(q, i);
1237 for (unsigned j = 0; j < q.g_num_planes(); j++)
1238 buf.s_bytesused(buf.g_length(j), j);
1239 if (is_video) {
1240 buf.s_field(field);
1241 tpg_s_field(&tpg, field, output_field_alt);
1242 if (output_field_alt) {
1243 if (field == V4L2_FIELD_TOP)
1244 field = V4L2_FIELD_BOTTOM;
1245 else if (field == V4L2_FIELD_BOTTOM)
1246 field = V4L2_FIELD_TOP;
1247 }
1248
1249 if (can_fill) {
1250 for (unsigned j = 0; j < q.g_num_planes(); j++)
1251 tpg_fillbuffer(&tpg, stream_out_std, j, static_cast<u8 *>(q.g_dataptr(i, j)));
1252 }
1253 }
1254 if (is_meta)
1255 meta_fillbuffer(buf, fmt, q);
1256
1257 if (fin && !fill_buffer_from_file(fd, q, buf, fmt, fin))
1258 return QUEUE_STOPPED;
1259
1260 if (fmt.g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS) {
1261 int media_fd = mi_get_media_fd(fd.g_fd());
1262
1263 if (media_fd < 0) {
1264 fprintf(stderr, "%s: mi_get_media_fd failed\n", __func__);
1265 return media_fd;
1266 }
1267
1268 if (alloc_fwht_req(media_fd, i))
1269 return QUEUE_ERROR;
1270 buf.s_request_fd(fwht_reqs[i].fd);
1271 buf.or_flags(V4L2_BUF_FLAG_REQUEST_FD);
1272
1273 if (set_fwht_ext_ctrl(fd, &last_fwht_hdr, last_fwht_bf_ts,
1274 buf.g_request_fd())) {
1275 fprintf(stderr, "%s: set_fwht_ext_ctrl failed on %dth buf: %s\n",
1276 __func__, i, strerror(errno));
1277 return QUEUE_ERROR;
1278 }
1279 }
1280 if (qbuf) {
1281 fps_timestamps fps_ts;
1282
1283 set_time_stamp(buf);
1284 if (fd.qbuf(buf))
1285 return QUEUE_ERROR;
1286 tpg_update_mv_count(&tpg, V4L2_FIELD_HAS_T_OR_B(field));
1287 if (!verbose)
1288 fprintf(stderr, ">");
1289 fflush(stderr);
1290 if (!ignore_count_skip && stream_count)
1291 if (!--stream_count)
1292 return QUEUE_STOPPED;
1293 }
1294 if (fmt.g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS) {
1295 set_fwht_req_by_idx(i, &last_fwht_hdr,
1296 last_fwht_bf_ts, buf.g_timestamp_ns());
1297 last_fwht_bf_ts = buf.g_timestamp_ns();
1298 if (ioctl(buf.g_request_fd(), MEDIA_REQUEST_IOC_QUEUE) < 0) {
1299 fprintf(stderr, "Unable to queue media request: %s\n",
1300 strerror(errno));
1301 return QUEUE_ERROR;
1302 }
1303 }
1304 }
1305 if (qbuf)
1306 output_field = field;
1307 return 0;
1308 }
1309
write_buffer_to_file(cv4l_fd & fd,cv4l_queue & q,cv4l_buffer & buf,cv4l_fmt & fmt,FILE * fout)1310 static void write_buffer_to_file(cv4l_fd &fd, cv4l_queue &q, cv4l_buffer &buf,
1311 cv4l_fmt &fmt, FILE *fout)
1312 {
1313 #ifndef NO_STREAM_TO
1314 unsigned comp_size[VIDEO_MAX_PLANES];
1315 uint8_t *comp_ptr[VIDEO_MAX_PLANES];
1316
1317 if (host_fd_to >= 0) {
1318 unsigned tot_comp_size = 0;
1319 unsigned tot_used = 0;
1320
1321 for (unsigned j = 0; j < buf.g_num_planes(); j++) {
1322 uint32_t used = buf.g_bytesused(j);
1323 unsigned offset = buf.g_data_offset(j);
1324 u8 *p = static_cast<u8 *>(q.g_dataptr(buf.g_index(), j)) + offset;
1325
1326 if (ctx) {
1327 comp_ptr[j] = fwht_compress(ctx, p,
1328 used - offset, &comp_size[j]);
1329 } else {
1330 comp_ptr[j] = p;
1331 comp_size[j] = rle_compress(p, used - offset,
1332 bpl_cap[j]);
1333 }
1334 tot_comp_size += comp_size[j];
1335 tot_used += used - offset;
1336 }
1337 write_u32(fout, ctx ? V4L_STREAM_PACKET_FRAME_VIDEO_FWHT :
1338 V4L_STREAM_PACKET_FRAME_VIDEO_RLE);
1339 write_u32(fout, V4L_STREAM_PACKET_FRAME_VIDEO_SIZE(buf.g_num_planes()) + tot_comp_size);
1340 write_u32(fout, V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_HDR);
1341 write_u32(fout, buf.g_field());
1342 write_u32(fout, buf.g_flags());
1343 comp_perc += (tot_comp_size * 100 / tot_used);
1344 comp_perc_count++;
1345 }
1346 if (to_with_hdr)
1347 write_u32(fout, FILE_HDR_ID);
1348 for (unsigned j = 0; j < buf.g_num_planes(); j++) {
1349 uint32_t used = buf.g_bytesused(j);
1350 unsigned offset = buf.g_data_offset(j);
1351 unsigned sz;
1352
1353 if (offset > used) {
1354 // Should never happen
1355 fprintf(stderr, "offset %d > used %d!\n",
1356 offset, used);
1357 offset = 0;
1358 }
1359 used -= offset;
1360 if (host_fd_to >= 0) {
1361 write_u32(fout, V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_PLANE_HDR);
1362 write_u32(fout, used);
1363 write_u32(fout, comp_size[j]);
1364 used = comp_size[j];
1365 } else if (to_with_hdr) {
1366 write_u32(fout, used);
1367 }
1368 if (host_fd_to >= 0)
1369 sz = fwrite(comp_ptr[j] + offset, 1, used, fout);
1370 else if (support_cap_compose && v4l2_fwht_find_pixfmt(fmt.g_pixelformat()))
1371 read_write_padded_frame(fmt, static_cast<u8 *>(q.g_dataptr(buf.g_index(), j)) + offset,
1372 fout, sz, used, used, false);
1373 else
1374 sz = fwrite(static_cast<u8 *>(q.g_dataptr(buf.g_index(), j)) + offset, 1, used, fout);
1375
1376 if (sz != used)
1377 fprintf(stderr, "%u != %u\n", sz, used);
1378 }
1379 if (host_fd_to >= 0)
1380 fflush(fout);
1381 #endif
1382 }
1383
do_handle_cap(cv4l_fd & fd,cv4l_queue & q,FILE * fout,int * index,unsigned & count,fps_timestamps & fps_ts,cv4l_fmt & fmt,bool ignore_count_skip)1384 static int do_handle_cap(cv4l_fd &fd, cv4l_queue &q, FILE *fout, int *index,
1385 unsigned &count, fps_timestamps &fps_ts, cv4l_fmt &fmt,
1386 bool ignore_count_skip)
1387 {
1388 char ch = '<';
1389 int ret;
1390 cv4l_buffer buf(q);
1391
1392 for (;;) {
1393 ret = fd.dqbuf(buf);
1394 if (ret == EAGAIN)
1395 return 0;
1396 if (ret == EPIPE)
1397 return QUEUE_STOPPED;
1398 if (ret) {
1399 fprintf(stderr, "%s: failed: %s\n", "VIDIOC_DQBUF", strerror(errno));
1400 return QUEUE_ERROR;
1401 }
1402 if (buf.g_flags() & V4L2_BUF_FLAG_LAST) {
1403 last_buffer = true;
1404 break;
1405 }
1406 if (!(buf.g_flags() & V4L2_BUF_FLAG_ERROR))
1407 break;
1408 if (verbose)
1409 print_concise_buffer(stderr, buf, fmt, q, fps_ts, -1);
1410 if (fd.qbuf(buf))
1411 return QUEUE_ERROR;
1412 }
1413
1414 bool is_empty_frame = !buf.g_bytesused(0);
1415 bool is_error_frame = buf.g_flags() & V4L2_BUF_FLAG_ERROR;
1416
1417 double ts_secs = buf.g_timestamp().tv_sec + buf.g_timestamp().tv_usec / 1000000.0;
1418 fps_ts.add_ts(ts_secs, buf.g_sequence(), buf.g_field());
1419
1420 if (fout && (!stream_skip || ignore_count_skip) &&
1421 !is_empty_frame && !is_error_frame)
1422 write_buffer_to_file(fd, q, buf, fmt, fout);
1423
1424 if (buf.g_flags() & V4L2_BUF_FLAG_KEYFRAME)
1425 ch = 'K';
1426 else if (buf.g_flags() & V4L2_BUF_FLAG_PFRAME)
1427 ch = 'P';
1428 else if (buf.g_flags() & V4L2_BUF_FLAG_BFRAME)
1429 ch = 'B';
1430 if (verbose) {
1431 print_concise_buffer(stderr, buf, fmt, q, fps_ts,
1432 host_fd_to >= 0 ? 100 - comp_perc / comp_perc_count : -1);
1433 comp_perc_count = comp_perc = 0;
1434 }
1435 if (!last_buffer && index == NULL) {
1436 /*
1437 * EINVAL in qbuf can happen if this is the last buffer before
1438 * a dynamic resolution change sequence. In this case the buffer
1439 * has the size that fits the old resolution and might not
1440 * fit to the new one.
1441 */
1442 if (fd.qbuf(buf) && errno != EINVAL) {
1443 fprintf(stderr, "%s: qbuf error\n", __func__);
1444 return QUEUE_ERROR;
1445 }
1446 }
1447 if (index)
1448 *index = buf.g_index();
1449
1450 if (!verbose) {
1451 fprintf(stderr, "%c", ch);
1452 fflush(stderr);
1453
1454 if (fps_ts.has_fps()) {
1455 unsigned dropped = fps_ts.dropped();
1456
1457 fprintf(stderr, " %.02f fps", fps_ts.fps());
1458 if (dropped)
1459 fprintf(stderr, ", dropped buffers: %u", dropped);
1460 if (host_fd_to >= 0)
1461 fprintf(stderr, " %d%% compression", 100 - comp_perc / comp_perc_count);
1462 comp_perc_count = comp_perc = 0;
1463 fprintf(stderr, "\n");
1464 }
1465 }
1466 count++;
1467
1468 if (ignore_count_skip)
1469 return 0;
1470
1471 if (stream_sleep > 0 && count % stream_sleep == 0)
1472 sleep(1);
1473
1474 if (is_empty_frame || is_error_frame)
1475 return 0;
1476
1477 if (stream_skip) {
1478 stream_skip--;
1479 return 0;
1480 }
1481
1482 if (stream_count == 0)
1483 return 0;
1484
1485 if (--stream_count == 0)
1486 return QUEUE_STOPPED;
1487
1488 return 0;
1489 }
1490
do_handle_out(cv4l_fd & fd,cv4l_queue & q,FILE * fin,cv4l_buffer * cap,unsigned & count,fps_timestamps & fps_ts,cv4l_fmt fmt,bool stopped,bool ignore_count_skip)1491 static int do_handle_out(cv4l_fd &fd, cv4l_queue &q, FILE *fin, cv4l_buffer *cap,
1492 unsigned &count, fps_timestamps &fps_ts, cv4l_fmt fmt,
1493 bool stopped, bool ignore_count_skip)
1494 {
1495 cv4l_buffer buf(q);
1496 bool is_meta = q.g_type() == V4L2_BUF_TYPE_META_OUTPUT;
1497 int ret = 0;
1498
1499 if (cap) {
1500 buf.s_index(cap->g_index());
1501
1502 for (unsigned j = 0; j < buf.g_num_planes(); j++) {
1503 unsigned data_offset = cap->g_data_offset(j);
1504
1505 if (q.g_memory() == V4L2_MEMORY_USERPTR) {
1506 buf.s_userptr(static_cast<u8 *>(cap->g_userptr(j)) + data_offset, j);
1507 buf.s_bytesused(cap->g_bytesused(j) - data_offset, j);
1508 buf.s_data_offset(0, j);
1509 } else if (q.g_memory() == V4L2_MEMORY_DMABUF) {
1510 buf.s_bytesused(cap->g_bytesused(j), j);
1511 buf.s_data_offset(data_offset, j);
1512 }
1513 }
1514 } else {
1515 ret = fd.dqbuf(buf);
1516 if (ret == EAGAIN)
1517 return 0;
1518
1519 double ts_secs = buf.g_timestamp().tv_sec + buf.g_timestamp().tv_usec / 1000000.0;
1520 fps_ts.add_ts(ts_secs, buf.g_sequence(), buf.g_field());
1521 if (verbose)
1522 print_concise_buffer(stderr, buf, fmt, q, fps_ts, -1);
1523
1524 for (unsigned j = 0; j < buf.g_num_planes(); j++)
1525 buf.s_bytesused(buf.g_length(j), j);
1526 }
1527 if (ret) {
1528 fprintf(stderr, "%s: failed: %s\n", "VIDIOC_DQBUF", strerror(ret));
1529 return QUEUE_ERROR;
1530 }
1531 if (fps_ts.has_fps()) {
1532 unsigned dropped = fps_ts.dropped();
1533
1534 fprintf(stderr, " %.02f fps", fps_ts.fps());
1535 if (dropped)
1536 fprintf(stderr, ", dropped buffers: %u", dropped);
1537 fprintf(stderr, "\n");
1538 }
1539 if (stopped)
1540 return 0;
1541
1542 buf.s_field(output_field);
1543 tpg_s_field(&tpg, output_field, output_field_alt);
1544 if (output_field_alt) {
1545 if (output_field == V4L2_FIELD_TOP)
1546 output_field = V4L2_FIELD_BOTTOM;
1547 else if (output_field == V4L2_FIELD_BOTTOM)
1548 output_field = V4L2_FIELD_TOP;
1549 }
1550
1551 if (fin && !fill_buffer_from_file(fd, q, buf, fmt, fin))
1552 return QUEUE_STOPPED;
1553
1554 if (!fin && stream_out_refresh) {
1555 for (unsigned j = 0; j < buf.g_num_planes(); j++)
1556 tpg_fillbuffer(&tpg, stream_out_std, j,
1557 static_cast<u8 *>(q.g_dataptr(buf.g_index(), j)));
1558 }
1559 if (is_meta)
1560 meta_fillbuffer(buf, fmt, q);
1561
1562 if (fmt.g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS) {
1563 if (ioctl(buf.g_request_fd(), MEDIA_REQUEST_IOC_REINIT, NULL)) {
1564 fprintf(stderr, "Unable to reinit media request: %s\n",
1565 strerror(errno));
1566 return QUEUE_ERROR;
1567 }
1568
1569 if (set_fwht_ext_ctrl(fd, &last_fwht_hdr, last_fwht_bf_ts,
1570 buf.g_request_fd())) {
1571 fprintf(stderr, "%s: set_fwht_ext_ctrl failed: %s\n",
1572 __func__, strerror(errno));
1573 return QUEUE_ERROR;
1574 }
1575 }
1576
1577 set_time_stamp(buf);
1578
1579 if (fd.qbuf(buf)) {
1580 fprintf(stderr, "%s: failed: %s\n", "VIDIOC_QBUF", strerror(errno));
1581 return QUEUE_ERROR;
1582 }
1583 if (fmt.g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS) {
1584 if (!set_fwht_req_by_fd(&last_fwht_hdr, buf.g_request_fd(), last_fwht_bf_ts,
1585 buf.g_timestamp_ns())) {
1586 fprintf(stderr, "%s: request for fd %d does not exist\n",
1587 __func__, buf.g_request_fd());
1588 return QUEUE_ERROR;
1589 }
1590
1591 last_fwht_bf_ts = buf.g_timestamp_ns();
1592 if (ioctl(buf.g_request_fd(), MEDIA_REQUEST_IOC_QUEUE) < 0) {
1593 fprintf(stderr, "Unable to queue media request: %s\n",
1594 strerror(errno));
1595 return QUEUE_ERROR;
1596 }
1597 }
1598
1599 tpg_update_mv_count(&tpg, V4L2_FIELD_HAS_T_OR_B(output_field));
1600
1601 if (!verbose)
1602 fprintf(stderr, ">");
1603 fflush(stderr);
1604
1605 count++;
1606
1607 if (ignore_count_skip)
1608 return 0;
1609
1610 if (stream_sleep > 0 && count % stream_sleep == 0)
1611 sleep(1);
1612
1613 if (stream_skip) {
1614 stream_skip--;
1615 return 0;
1616 }
1617
1618 if (stream_count == 0)
1619 return 0;
1620 if (--stream_count == 0)
1621 return QUEUE_STOPPED;
1622
1623 return 0;
1624 }
1625
do_handle_out_to_in(cv4l_fd & out_fd,cv4l_fd & fd,cv4l_queue & out,cv4l_queue & in)1626 static int do_handle_out_to_in(cv4l_fd &out_fd, cv4l_fd &fd, cv4l_queue &out, cv4l_queue &in)
1627 {
1628 cv4l_buffer buf(out);
1629 int ret;
1630
1631 do {
1632 ret = out_fd.dqbuf(buf);
1633 } while (ret == EAGAIN);
1634 if (ret) {
1635 fprintf(stderr, "%s: failed: %s\n", "VIDIOC_DQBUF", strerror(errno));
1636 return QUEUE_ERROR;
1637 }
1638 buf.init(in, buf.g_index());
1639 ret = fd.querybuf(buf);
1640 if (ret == 0)
1641 ret = fd.qbuf(buf);
1642 if (ret) {
1643 fprintf(stderr, "%s: failed: %s\n", "VIDIOC_QBUF", strerror(errno));
1644 return QUEUE_ERROR;
1645 }
1646 return 0;
1647 }
1648
open_output_file(cv4l_fd & fd)1649 static FILE *open_output_file(cv4l_fd &fd)
1650 {
1651 FILE *fout = NULL;
1652
1653 #ifndef NO_STREAM_TO
1654 if (file_to) {
1655 if (!strcmp(file_to, "-"))
1656 return stdout;
1657 fout = fopen(file_to, "w+");
1658 if (!fout)
1659 fprintf(stderr, "could not open %s for writing\n", file_to);
1660 return fout;
1661 }
1662 if (!host_to)
1663 return NULL;
1664
1665 char *p = std::strchr(host_to, ':');
1666 struct sockaddr_in serv_addr;
1667 struct hostent *server;
1668 struct v4l2_fract aspect;
1669 unsigned width, height;
1670 cv4l_fmt cfmt;
1671
1672 fd.g_fmt(cfmt);
1673
1674 aspect = fd.g_pixel_aspect(width, height);
1675 if (p) {
1676 host_port_to = strtoul(p + 1, 0L, 0);
1677 *p = '\0';
1678 }
1679 host_fd_to = socket(AF_INET, SOCK_STREAM, 0);
1680 if (host_fd_to < 0) {
1681 fprintf(stderr, "cannot open socket");
1682 std::exit(EXIT_SUCCESS);
1683 }
1684 server = gethostbyname(host_to);
1685 if (server == NULL) {
1686 fprintf(stderr, "no such host %s\n", host_to);
1687 std::exit(EXIT_SUCCESS);
1688 }
1689 memset(reinterpret_cast<char *>(&serv_addr), 0, sizeof(serv_addr));
1690 serv_addr.sin_family = AF_INET;
1691 memcpy(reinterpret_cast<char *>(&serv_addr.sin_addr.s_addr),
1692 server->h_addr,
1693 server->h_length);
1694 serv_addr.sin_port = htons(host_port_to);
1695 if (connect(host_fd_to, reinterpret_cast<struct sockaddr *>(&serv_addr), sizeof(serv_addr)) < 0) {
1696 fprintf(stderr, "could not connect\n");
1697 std::exit(EXIT_SUCCESS);
1698 }
1699 fout = fdopen(host_fd_to, "a");
1700 write_u32(fout, V4L_STREAM_ID);
1701 write_u32(fout, V4L_STREAM_VERSION);
1702 write_u32(fout, V4L_STREAM_PACKET_FMT_VIDEO);
1703 write_u32(fout, V4L_STREAM_PACKET_FMT_VIDEO_SIZE(cfmt.g_num_planes()));
1704 write_u32(fout, V4L_STREAM_PACKET_FMT_VIDEO_SIZE_FMT);
1705 write_u32(fout, cfmt.g_num_planes());
1706 write_u32(fout, cfmt.g_pixelformat());
1707 write_u32(fout, cfmt.g_width());
1708 write_u32(fout, cfmt.g_height());
1709 write_u32(fout, cfmt.g_field());
1710 write_u32(fout, cfmt.g_colorspace());
1711 write_u32(fout, cfmt.g_ycbcr_enc());
1712 write_u32(fout, cfmt.g_quantization());
1713 write_u32(fout, cfmt.g_xfer_func());
1714 write_u32(fout, cfmt.g_flags());
1715 write_u32(fout, aspect.numerator);
1716 write_u32(fout, aspect.denominator);
1717 for (unsigned i = 0; i < cfmt.g_num_planes(); i++) {
1718 write_u32(fout, V4L_STREAM_PACKET_FMT_VIDEO_SIZE_FMT_PLANE);
1719 write_u32(fout, cfmt.g_sizeimage(i));
1720 write_u32(fout, cfmt.g_bytesperline(i));
1721 bpl_cap[i] = rle_calc_bpl(cfmt.g_bytesperline(i), cfmt.g_pixelformat());
1722 }
1723 if (!host_lossless) {
1724 unsigned visible_width = support_cap_compose ? composed_width : cfmt.g_width();
1725 unsigned visible_height = support_cap_compose ? composed_height : cfmt.g_height();
1726
1727 ctx = fwht_alloc(cfmt.g_pixelformat(), visible_width, visible_height,
1728 cfmt.g_width(), cfmt.g_height(),
1729 cfmt.g_field(), cfmt.g_colorspace(), cfmt.g_xfer_func(),
1730 cfmt.g_ycbcr_enc(), cfmt.g_quantization());
1731 }
1732 fflush(fout);
1733 #endif
1734 return fout;
1735 }
1736
streaming_set_cap(cv4l_fd & fd,cv4l_fd & exp_fd)1737 static void streaming_set_cap(cv4l_fd &fd, cv4l_fd &exp_fd)
1738 {
1739 int fd_flags = fcntl(fd.g_fd(), F_GETFL);
1740 cv4l_queue q(fd.g_type(), memory);
1741 cv4l_queue exp_q(exp_fd.g_type(), V4L2_MEMORY_MMAP);
1742 fps_timestamps fps_ts;
1743 bool use_poll = options[OptStreamPoll];
1744 unsigned count;
1745 bool eos;
1746 bool source_change;
1747 FILE *fout = NULL;
1748 cv4l_fmt fmt;
1749
1750 if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE |
1751 V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
1752 V4L2_CAP_META_CAPTURE | V4L2_CAP_SDR_CAPTURE |
1753 V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE))) {
1754 fprintf(stderr, "unsupported stream type\n");
1755 return;
1756 }
1757 if (options[OptStreamDmaBuf] && exp_fd.g_fd() < 0) {
1758 fprintf(stderr, "--stream-dmabuf can only work in combination with --export-device\n");
1759 return;
1760 }
1761 switch (q.g_type()) {
1762 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1763 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
1764 break;
1765 default:
1766 if (host_to) {
1767 fprintf(stderr, "--stream-to-host is not supported for non-video streams\n");
1768 return;
1769 }
1770 break;
1771 }
1772
1773 subscribe_event(fd, V4L2_EVENT_EOS);
1774 if (use_poll)
1775 subscribe_event(fd, V4L2_EVENT_SOURCE_CHANGE);
1776
1777 recover:
1778 eos = false;
1779 source_change = false;
1780 count = 0;
1781
1782 if (!stream_no_query) {
1783 cv4l_disable_trace dt(fd);
1784 struct v4l2_dv_timings new_dv_timings = {};
1785 v4l2_std_id new_std;
1786 struct v4l2_input in = { };
1787
1788 if (!fd.g_input(in.index) && !fd.enum_input(in, true, in.index)) {
1789 if (in.capabilities & V4L2_IN_CAP_DV_TIMINGS) {
1790 while (fd.query_dv_timings(new_dv_timings))
1791 sleep(1);
1792 fd.s_dv_timings(new_dv_timings);
1793 fprintf(stderr, "New timings found\n");
1794 } else if (in.capabilities & V4L2_IN_CAP_STD) {
1795 if (!fd.query_std(new_std))
1796 fd.s_std(new_std);
1797 }
1798 }
1799 }
1800
1801 fout = open_output_file(fd);
1802
1803 if (q.reqbufs(&fd, reqbufs_count_cap)) {
1804 if (q.g_type() != V4L2_BUF_TYPE_VBI_CAPTURE ||
1805 !fd.has_raw_vbi_cap() || !fd.has_sliced_vbi_cap())
1806 goto done;
1807 fd.s_type(V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
1808 q.init(fd.g_type(), memory);
1809 if (q.reqbufs(&fd, reqbufs_count_cap))
1810 goto done;
1811 }
1812
1813 if (options[OptStreamDmaBuf]) {
1814 if (exp_q.reqbufs(&exp_fd, reqbufs_count_cap))
1815 goto done;
1816 if (q.export_bufs(&exp_fd, exp_fd.g_type()))
1817 goto done;
1818 }
1819
1820 if (q.obtain_bufs(&fd))
1821 goto done;
1822
1823 if (q.queue_all(&fd))
1824 goto done;
1825
1826 fps_ts.determine_field(fd.g_fd(), q.g_type());
1827
1828 if (fd.streamon())
1829 goto done;
1830
1831 fd.s_trace(0);
1832 exp_fd.s_trace(0);
1833
1834 fd.g_fmt(fmt);
1835
1836 while (stream_sleep == 0)
1837 sleep(100);
1838
1839 if (use_poll)
1840 fcntl(fd.g_fd(), F_SETFL, fd_flags | O_NONBLOCK);
1841
1842 while (!eos && !source_change) {
1843 fd_set read_fds;
1844 fd_set exception_fds;
1845 struct timeval tv = { use_poll ? 2 : 0, 0 };
1846 int r;
1847
1848 FD_ZERO(&exception_fds);
1849 FD_SET(fd.g_fd(), &exception_fds);
1850 FD_ZERO(&read_fds);
1851 FD_SET(fd.g_fd(), &read_fds);
1852 r = select(fd.g_fd() + 1, use_poll ? &read_fds : NULL, NULL, &exception_fds, &tv);
1853
1854 if (r == -1) {
1855 if (EINTR == errno)
1856 continue;
1857 fprintf(stderr, "select error: %s\n",
1858 strerror(errno));
1859 goto done;
1860 }
1861 if (use_poll && r == 0) {
1862 fprintf(stderr, "select timeout\n");
1863 goto done;
1864 }
1865
1866 if (FD_ISSET(fd.g_fd(), &exception_fds)) {
1867 struct v4l2_event ev;
1868
1869 while (!fd.dqevent(ev)) {
1870 switch (ev.type) {
1871 case V4L2_EVENT_SOURCE_CHANGE:
1872 source_change = true;
1873 if (!verbose)
1874 fprintf(stderr, "\n");
1875 fprintf(stderr, "SOURCE CHANGE EVENT\n");
1876 break;
1877 case V4L2_EVENT_EOS:
1878 eos = true;
1879 if (!verbose)
1880 fprintf(stderr, "\n");
1881 fprintf(stderr, "EOS EVENT\n");
1882 fflush(stderr);
1883 break;
1884 }
1885 }
1886 }
1887
1888 if (FD_ISSET(fd.g_fd(), &read_fds)) {
1889 r = do_handle_cap(fd, q, fout, NULL,
1890 count, fps_ts, fmt, false);
1891 if (r < 0)
1892 break;
1893 }
1894
1895 }
1896 fd.streamoff();
1897 fcntl(fd.g_fd(), F_SETFL, fd_flags);
1898 fprintf(stderr, "\n");
1899
1900 q.free(&fd);
1901 tpg_free(&tpg);
1902 if (source_change && !stream_no_query)
1903 goto recover;
1904
1905 done:
1906 if (options[OptStreamDmaBuf])
1907 exp_q.close_exported_fds();
1908 if (fout && fout != stdout) {
1909 if (host_fd_to >= 0)
1910 write_u32(fout, V4L_STREAM_PACKET_END);
1911 fclose(fout);
1912 }
1913 }
1914
open_input_file(cv4l_fd & fd,uint32_t type)1915 static FILE *open_input_file(cv4l_fd &fd, uint32_t type)
1916 {
1917 FILE *fin = NULL;
1918
1919 if (file_from) {
1920 if (!strcmp(file_from, "-"))
1921 return stdin;
1922 fin = fopen(file_from, "r");
1923 if (!fin)
1924 fprintf(stderr, "could not open %s for reading\n", file_from);
1925 return fin;
1926 }
1927 if (!host_from)
1928 return NULL;
1929
1930 char *p = std::strchr(host_from, ':');
1931 int listen_fd;
1932 socklen_t clilen;
1933 struct sockaddr_in serv_addr = {}, cli_addr;
1934
1935 if (p) {
1936 host_port_from = strtoul(p + 1, 0L, 0);
1937 *p = '\0';
1938 }
1939 listen_fd = socket(AF_INET, SOCK_STREAM, 0);
1940 if (listen_fd < 0) {
1941 fprintf(stderr, "could not opening socket\n");
1942 std::exit(EXIT_FAILURE);
1943 }
1944 serv_addr.sin_family = AF_INET;
1945 serv_addr.sin_addr.s_addr = INADDR_ANY;
1946 serv_addr.sin_port = htons(host_port_from);
1947 if (bind(listen_fd, reinterpret_cast<struct sockaddr *>(&serv_addr), sizeof(serv_addr)) < 0) {
1948 fprintf(stderr, "could not bind\n");
1949 std::exit(EXIT_FAILURE);
1950 }
1951 listen(listen_fd, 1);
1952 clilen = sizeof(cli_addr);
1953 host_fd_from = accept(listen_fd, reinterpret_cast<struct sockaddr *>(&cli_addr), &clilen);
1954 if (host_fd_from < 0) {
1955 fprintf(stderr, "could not accept\n");
1956 std::exit(EXIT_FAILURE);
1957 }
1958 fin = fdopen(host_fd_from, "r");
1959 if (read_u32(fin) != V4L_STREAM_ID) {
1960 fprintf(stderr, "unknown protocol ID\n");
1961 std::exit(EXIT_FAILURE);
1962 }
1963 if (read_u32(fin) != V4L_STREAM_VERSION) {
1964 fprintf(stderr, "unknown protocol version\n");
1965 std::exit(EXIT_FAILURE);
1966 }
1967 for (;;) {
1968 uint32_t packet = read_u32(fin);
1969 char buf[1024];
1970
1971 if (packet == V4L_STREAM_PACKET_END) {
1972 fprintf(stderr, "END packet read\n");
1973 std::exit(EXIT_FAILURE);
1974 }
1975
1976 if (packet == V4L_STREAM_PACKET_FMT_VIDEO)
1977 break;
1978
1979 unsigned sz = read_u32(fin);
1980 while (sz) {
1981 unsigned rdsize = sz > sizeof(buf) ? sizeof(buf) : sz;
1982 int n;
1983
1984 n = fread(buf, 1, rdsize, fin);
1985 if (n < 0) {
1986 fprintf(stderr, "error reading %d bytes\n", sz);
1987 std::exit(EXIT_FAILURE);
1988 }
1989 sz -= n;
1990 }
1991 }
1992 read_u32(fin);
1993
1994 cv4l_fmt cfmt(type);
1995
1996 unsigned sz = read_u32(fin);
1997
1998 if (sz != V4L_STREAM_PACKET_FMT_VIDEO_SIZE_FMT) {
1999 fprintf(stderr, "unsupported FMT_VIDEO size\n");
2000 std::exit(EXIT_FAILURE);
2001 }
2002 cfmt.s_num_planes(read_u32(fin));
2003 cfmt.s_pixelformat(read_u32(fin));
2004 cfmt.s_width(read_u32(fin));
2005 cfmt.s_height(read_u32(fin));
2006 cfmt.s_field(read_u32(fin));
2007 cfmt.s_colorspace(read_u32(fin));
2008 cfmt.s_ycbcr_enc(read_u32(fin));
2009 cfmt.s_quantization(read_u32(fin));
2010 cfmt.s_xfer_func(read_u32(fin));
2011 cfmt.s_flags(read_u32(fin));
2012 unsigned visible_width = support_out_crop ? cropped_width : cfmt.g_width();
2013 unsigned visible_height = support_out_crop ? cropped_height : cfmt.g_height();
2014
2015 ctx = fwht_alloc(cfmt.g_pixelformat(), visible_width, visible_height,
2016 cfmt.g_width(), cfmt.g_height(),
2017 cfmt.g_field(), cfmt.g_colorspace(), cfmt.g_xfer_func(),
2018 cfmt.g_ycbcr_enc(), cfmt.g_quantization());
2019
2020 read_u32(fin); // pixelaspect.numerator
2021 read_u32(fin); // pixelaspect.denominator
2022
2023 for (unsigned i = 0; i < cfmt.g_num_planes(); i++) {
2024 unsigned sz = read_u32(fin);
2025
2026 if (sz != V4L_STREAM_PACKET_FMT_VIDEO_SIZE_FMT_PLANE) {
2027 fprintf(stderr, "unsupported FMT_VIDEO plane size\n");
2028 std::exit(EXIT_FAILURE);
2029 }
2030 cfmt.s_sizeimage(read_u32(fin), i);
2031 cfmt.s_bytesperline(read_u32(fin), i);
2032 bpl_out[i] = rle_calc_bpl(cfmt.g_bytesperline(i), cfmt.g_pixelformat());
2033 }
2034 if (fd.s_fmt(cfmt)) {
2035 fprintf(stderr, "failed to set new format\n");
2036 std::exit(EXIT_FAILURE);
2037 }
2038 return fin;
2039 }
2040
streaming_set_out(cv4l_fd & fd,cv4l_fd & exp_fd)2041 static void streaming_set_out(cv4l_fd &fd, cv4l_fd &exp_fd)
2042 {
2043 uint32_t type = fd.has_vid_m2m() ? v4l_type_invert(fd.g_type()) : fd.g_type();
2044 cv4l_queue q(type, out_memory);
2045 cv4l_queue exp_q(exp_fd.g_type(), V4L2_MEMORY_MMAP);
2046 int fd_flags = fcntl(fd.g_fd(), F_GETFL);
2047 bool use_poll = options[OptStreamPoll];
2048 fps_timestamps fps_ts;
2049 unsigned count = 0;
2050 bool stopped = false;
2051 FILE *fin = NULL;
2052 cv4l_fmt fmt;
2053
2054 fd.g_fmt(fmt);
2055
2056 if (!(capabilities & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
2057 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT |
2058 V4L2_CAP_SDR_OUTPUT | V4L2_CAP_META_OUTPUT |
2059 V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE))) {
2060 fprintf(stderr, "unsupported stream type\n");
2061 return;
2062 }
2063 if (options[OptStreamOutDmaBuf] && exp_fd.g_fd() < 0) {
2064 fprintf(stderr, "--stream-out-dmabuf can only work in combination with --export-device\n");
2065 return;
2066 }
2067 switch (q.g_type()) {
2068 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
2069 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
2070 break;
2071 default:
2072 if (host_from) {
2073 fprintf(stderr, "--stream-from-host is not supported for non-video streams\n");
2074 return;
2075 }
2076 break;
2077 }
2078
2079 fin = open_input_file(fd, type);
2080
2081 if (q.reqbufs(&fd, reqbufs_count_out)) {
2082 if (q.g_type() != V4L2_BUF_TYPE_VBI_OUTPUT ||
2083 !fd.has_raw_vbi_out() || !fd.has_sliced_vbi_out())
2084 goto done;
2085 fd.s_type(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
2086 q.init(fd.g_type(), memory);
2087 if (q.reqbufs(&fd, reqbufs_count_out))
2088 goto done;
2089 }
2090
2091 if (options[OptStreamOutDmaBuf]) {
2092 if (exp_q.reqbufs(&exp_fd, reqbufs_count_out))
2093 goto done;
2094 if (q.export_bufs(&exp_fd, exp_fd.g_type()))
2095 goto done;
2096 }
2097
2098 if (q.obtain_bufs(&fd))
2099 goto done;
2100
2101 if (do_setup_out_buffers(fd, q, fin, true, false) < 0)
2102 goto done;
2103
2104 fps_ts.determine_field(fd.g_fd(), type);
2105
2106 if (fd.streamon())
2107 goto done;
2108
2109 fd.s_trace(0);
2110 exp_fd.s_trace(0);
2111
2112 while (stream_sleep == 0)
2113 sleep(100);
2114
2115 if (use_poll)
2116 fcntl(fd.g_fd(), F_SETFL, fd_flags | O_NONBLOCK);
2117
2118 for (;;) {
2119 int r;
2120
2121 if (use_poll) {
2122 fd_set fds;
2123 struct timeval tv;
2124
2125 FD_ZERO(&fds);
2126 FD_SET(fd.g_fd(), &fds);
2127
2128 /* Timeout. */
2129 tv.tv_sec = 2;
2130 tv.tv_usec = 0;
2131
2132 r = select(fd.g_fd() + 1, NULL, &fds, NULL, &tv);
2133
2134 if (r == -1) {
2135 if (EINTR == errno)
2136 continue;
2137 fprintf(stderr, "select error: %s\n",
2138 strerror(errno));
2139 goto done;
2140 }
2141
2142 if (r == 0) {
2143 fprintf(stderr, "select timeout\n");
2144 goto done;
2145 }
2146 }
2147 r = do_handle_out(fd, q, fin, NULL,
2148 count, fps_ts, fmt, stopped, false);
2149 if (r == QUEUE_STOPPED)
2150 stopped = true;
2151 if (r < 0)
2152 break;
2153
2154 }
2155
2156 if (options[OptDecoderCmd]) {
2157 fd.decoder_cmd(dec_cmd);
2158 options[OptDecoderCmd] = false;
2159 }
2160 fd.streamoff();
2161 fcntl(fd.g_fd(), F_SETFL, fd_flags);
2162 fprintf(stderr, "\n");
2163
2164 q.free(&fd);
2165 tpg_free(&tpg);
2166
2167 done:
2168 if (options[OptStreamOutDmaBuf])
2169 exp_q.close_exported_fds();
2170 if (fin && fin != stdin)
2171 fclose(fin);
2172 }
2173
2174 enum stream_type {
2175 CAP,
2176 OUT,
2177 };
2178
capture_setup(cv4l_fd & fd,cv4l_queue & in,cv4l_fd * exp_fd,cv4l_fmt * new_fmt=NULL)2179 static int capture_setup(cv4l_fd &fd, cv4l_queue &in, cv4l_fd *exp_fd, cv4l_fmt *new_fmt = NULL)
2180 {
2181 if (fd.streamoff(in.g_type())) {
2182 fprintf(stderr, "%s: fd.streamoff error\n", __func__);
2183 return -1;
2184 }
2185
2186 /* release any buffer allocated */
2187 if (in.reqbufs(&fd)) {
2188 fprintf(stderr, "%s: in.reqbufs 0 error\n", __func__);
2189 return -1;
2190 }
2191
2192 if (options[OptSetVideoFormat]) {
2193 cv4l_fmt fmt;
2194
2195 if (vidcap_get_and_update_fmt(fd, fmt)) {
2196 fprintf(stderr, "%s: vidcap_get_and_update_fmt error\n",
2197 __func__);
2198 return -1;
2199 }
2200 fd.s_fmt(fmt, in.g_type());
2201 if (new_fmt)
2202 *new_fmt = fmt;
2203 } else if (new_fmt) {
2204 fd.g_fmt(*new_fmt, in.g_type());
2205 }
2206 get_cap_compose_rect(fd);
2207
2208 if (in.reqbufs(&fd, reqbufs_count_cap)) {
2209 fprintf(stderr, "%s: in.reqbufs %u error\n", __func__,
2210 reqbufs_count_cap);
2211 return -1;
2212 }
2213
2214 if (exp_fd && in.export_bufs(exp_fd, exp_fd->g_type()))
2215 return -1;
2216 if (in.obtain_bufs(&fd) || in.queue_all(&fd)) {
2217 fprintf(stderr, "%s: in.obtain_bufs error\n", __func__);
2218 return -1;
2219 }
2220
2221 if (fd.streamon(in.g_type())) {
2222 fprintf(stderr, "%s: fd.streamon error\n", __func__);
2223 return -1;
2224 }
2225 return 0;
2226 }
2227
stateful_m2m(cv4l_fd & fd,cv4l_queue & in,cv4l_queue & out,FILE * fin,FILE * fout,cv4l_fmt & fmt_in,cv4l_fmt & fmt_out,cv4l_fd * exp_fd_p)2228 static void stateful_m2m(cv4l_fd &fd, cv4l_queue &in, cv4l_queue &out,
2229 FILE *fin, FILE *fout, cv4l_fmt &fmt_in,
2230 cv4l_fmt &fmt_out, cv4l_fd *exp_fd_p)
2231 {
2232 int fd_flags = fcntl(fd.g_fd(), F_GETFL);
2233 fps_timestamps fps_ts[2];
2234 unsigned count[2] = { 0, 0 };
2235 fd_set fds[3];
2236 fd_set *rd_fds = &fds[0]; /* for capture */
2237 fd_set *ex_fds = &fds[1]; /* for capture */
2238 fd_set *wr_fds = &fds[2]; /* for output */
2239 bool cap_streaming = false;
2240 static struct v4l2_encoder_cmd enc_stop = {
2241 .cmd = V4L2_ENC_CMD_STOP,
2242 };
2243 static struct v4l2_decoder_cmd dec_stop = {
2244 .cmd = V4L2_DEC_CMD_STOP,
2245 };
2246
2247 bool have_eos = subscribe_event(fd, V4L2_EVENT_EOS);
2248 bool is_encoder = false;
2249 enum codec_type codec_type = get_codec_type(fd);
2250 bool ignore_count_skip = codec_type == ENCODER;
2251
2252 if (have_eos) {
2253 cv4l_fmt fmt(in.g_type());
2254
2255 fd.g_fmt(fmt);
2256 is_encoder = !fmt.g_bytesperline();
2257 }
2258
2259 bool have_source_change = subscribe_event(fd, V4L2_EVENT_SOURCE_CHANGE);
2260 bool stopped = false;
2261
2262 if (out.reqbufs(&fd, reqbufs_count_out))
2263 return;
2264
2265 switch (do_setup_out_buffers(fd, out, fout, true, !ignore_count_skip)) {
2266 case 0:
2267 break;
2268 case QUEUE_STOPPED:
2269 stopped = true;
2270 break;
2271 default:
2272 return;
2273 }
2274
2275 if (fd.streamon(out.g_type()))
2276 return;
2277
2278 fd.s_trace(0);
2279 if (exp_fd_p)
2280 exp_fd_p->s_trace(0);
2281
2282 if (codec_type != DECODER || !have_source_change)
2283 if (capture_setup(fd, in, exp_fd_p))
2284 return;
2285
2286 fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
2287 fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
2288
2289 while (stream_sleep == 0)
2290 sleep(100);
2291
2292 fcntl(fd.g_fd(), F_SETFL, fd_flags | O_NONBLOCK);
2293
2294 if (have_eos && stopped) {
2295 if (!verbose)
2296 fprintf(stderr, "\n");
2297 fprintf(stderr, "STOP %sCODER\n", is_encoder ? "EN" : "DE");
2298 if (is_encoder)
2299 fd.encoder_cmd(enc_stop);
2300 else
2301 fd.decoder_cmd(dec_stop);
2302 }
2303
2304 while (rd_fds || wr_fds || ex_fds) {
2305 struct timeval tv = { 2, 0 };
2306 struct timeval stopped_tv = { 0, 500000 };
2307 int r = 0;
2308
2309 if (rd_fds) {
2310 FD_ZERO(rd_fds);
2311 FD_SET(fd.g_fd(), rd_fds);
2312 }
2313
2314 if (ex_fds) {
2315 FD_ZERO(ex_fds);
2316 FD_SET(fd.g_fd(), ex_fds);
2317 }
2318
2319 if (wr_fds) {
2320 FD_ZERO(wr_fds);
2321 FD_SET(fd.g_fd(), wr_fds);
2322 }
2323
2324 r = select(fd.g_fd() + 1, rd_fds, wr_fds, ex_fds,
2325 stopped ? &stopped_tv : &tv);
2326
2327 if (r == -1) {
2328 if (EINTR == errno)
2329 continue;
2330 fprintf(stderr, "select error: %s\n",
2331 strerror(errno));
2332 return;
2333 }
2334 if (r == 0) {
2335 if (!stopped)
2336 fprintf(stderr, "select timeout");
2337 fprintf(stderr, "\n");
2338 return;
2339 }
2340
2341 if (rd_fds && FD_ISSET(fd.g_fd(), rd_fds)) {
2342 r = do_handle_cap(fd, in, fin, NULL,
2343 count[CAP], fps_ts[CAP], fmt_in,
2344 ignore_count_skip);
2345 if (r == QUEUE_STOPPED)
2346 break;
2347 if (r < 0) {
2348 rd_fds = NULL;
2349 if (!have_eos) {
2350 ex_fds = NULL;
2351 break;
2352 }
2353 }
2354 }
2355
2356 if (wr_fds && FD_ISSET(fd.g_fd(), wr_fds)) {
2357 r = do_handle_out(fd, out, fout, NULL,
2358 count[OUT], fps_ts[OUT], fmt_out, stopped,
2359 !ignore_count_skip);
2360 if (r == QUEUE_STOPPED) {
2361 stopped = true;
2362 if (have_eos) {
2363 if (!verbose)
2364 fprintf(stderr, "\n");
2365 fprintf(stderr, "STOP %sCODER\n", is_encoder ? "EN" : "DE");
2366 if (is_encoder)
2367 fd.encoder_cmd(enc_stop);
2368 else
2369 fd.decoder_cmd(dec_stop);
2370 }
2371 } else if (r < 0) {
2372 break;
2373 }
2374 }
2375
2376 if (ex_fds && FD_ISSET(fd.g_fd(), ex_fds)) {
2377 struct v4l2_event ev;
2378
2379 while (!fd.dqevent(ev)) {
2380 if (ev.type == V4L2_EVENT_EOS) {
2381 wr_fds = NULL;
2382 if (!verbose)
2383 fprintf(stderr, "\n");
2384 fprintf(stderr, "EOS EVENT\n");
2385 fflush(stderr);
2386 } else if (ev.type == V4L2_EVENT_SOURCE_CHANGE) {
2387 if (!verbose)
2388 fprintf(stderr, "\n");
2389 fprintf(stderr, "SOURCE CHANGE EVENT\n");
2390 in_source_change_event = true;
2391
2392 /*
2393 * if capture is not streaming, the
2394 * driver will not send a last buffer so
2395 * we set it here
2396 */
2397 if (!cap_streaming)
2398 last_buffer = true;
2399 }
2400 }
2401 }
2402
2403 if (last_buffer) {
2404 if (in_source_change_event) {
2405 in_source_change_event = false;
2406 last_buffer = false;
2407 if (capture_setup(fd, in, exp_fd_p, &fmt_in))
2408 return;
2409 fps_ts[CAP].reset();
2410 fps_ts[OUT].reset();
2411 cap_streaming = true;
2412 } else {
2413 break;
2414 }
2415 }
2416 }
2417
2418 fcntl(fd.g_fd(), F_SETFL, fd_flags);
2419 fprintf(stderr, "\n");
2420
2421 fd.streamoff(in.g_type());
2422 fd.streamoff(out.g_type());
2423 in.free(&fd);
2424 out.free(&fd);
2425 tpg_free(&tpg);
2426 }
2427
stateless_m2m(cv4l_fd & fd,cv4l_queue & in,cv4l_queue & out,FILE * fin,FILE * fout,cv4l_fmt & fmt_in,cv4l_fmt & fmt_out,cv4l_fd * exp_fd_p)2428 static void stateless_m2m(cv4l_fd &fd, cv4l_queue &in, cv4l_queue &out,
2429 FILE *fin, FILE *fout, cv4l_fmt &fmt_in,
2430 cv4l_fmt &fmt_out, cv4l_fd *exp_fd_p)
2431 {
2432 fps_timestamps fps_ts[2];
2433 unsigned count[2] = { 0, 0 };
2434 int fd_flags = fcntl(fd.g_fd(), F_GETFL);
2435 bool stopped = false;
2436
2437 if (out.reqbufs(&fd, reqbufs_count_out)) {
2438 fprintf(stderr, "%s: out.reqbufs failed\n", __func__);
2439 return;
2440 }
2441
2442 if (in.reqbufs(&fd, reqbufs_count_cap)) {
2443 fprintf(stderr, "%s: in.reqbufs failed\n", __func__);
2444 return;
2445 }
2446
2447 if (exp_fd_p && in.export_bufs(exp_fd_p, exp_fd_p->g_type()))
2448 return;
2449
2450 if (in.obtain_bufs(&fd)) {
2451 fprintf(stderr, "%s: in.obtain_bufs error\n", __func__);
2452 return;
2453 }
2454
2455 if (do_setup_out_buffers(fd, out, fout, true, true) == QUEUE_ERROR) {
2456 fprintf(stderr, "%s: do_setup_out_buffers failed\n", __func__);
2457 return;
2458 }
2459
2460 if (in.queue_all(&fd)) {
2461 fprintf(stderr, "%s: in.queue_all failed\n", __func__);
2462 return;
2463 }
2464
2465 if (fd.streamon(out.g_type())) {
2466 fprintf(stderr, "%s: streamon for out failed\n", __func__);
2467 return;
2468 }
2469
2470 if (fd.streamon(in.g_type())) {
2471 fprintf(stderr, "%s: streamon for in failed\n", __func__);
2472 return;
2473 }
2474 int index = 0;
2475 bool queue_lst_buf = false;
2476 cv4l_buffer last_in_buf;
2477
2478 fcntl(fd.g_fd(), F_SETFL, fd_flags | O_NONBLOCK);
2479
2480 while (true) {
2481 fd_set except_fds;
2482 int req_fd = fwht_reqs[index].fd;
2483 struct timeval tv = { 2, 0 };
2484
2485 if (req_fd < 0)
2486 break;
2487
2488 FD_ZERO(&except_fds);
2489 FD_SET(req_fd, &except_fds);
2490
2491 int rc = select(req_fd + 1, NULL, NULL, &except_fds, &tv);
2492
2493 if (rc == 0) {
2494 fprintf(stderr, "Timeout when waiting for media request\n");
2495 return;
2496 }
2497 if (rc < 0) {
2498 fprintf(stderr, "Unable to select media request: %s\n",
2499 strerror(errno));
2500 return;
2501 }
2502 /*
2503 * it is safe to queue back last cap buffer only after
2504 * the following request is done so that the buffer
2505 * is not needed anymore as a reference frame
2506 */
2507 if (queue_lst_buf) {
2508 if (fd.qbuf(last_in_buf) < 0) {
2509 fprintf(stderr, "%s: qbuf failed\n", __func__);
2510 return;
2511 }
2512 }
2513 int buf_idx = -1;
2514 /*
2515 * fin is not sent to do_handle_cap since the capture buf is
2516 * written to the file in current function
2517 */
2518 rc = do_handle_cap(fd, in, NULL, &buf_idx, count[CAP],
2519 fps_ts[CAP], fmt_in, false);
2520 if (rc && rc != QUEUE_STOPPED) {
2521 fprintf(stderr, "%s: do_handle_cap err\n", __func__);
2522 return;
2523 }
2524 /*
2525 * in case of an error in the frame, set last ts to 0 as a
2526 * means to recover so that next request will not use a
2527 * reference buffer. Otherwise the error flag will be set to
2528 * all the future capture buffers.
2529 */
2530 if (buf_idx == -1) {
2531 fprintf(stderr, "%s: frame returned with error\n", __func__);
2532 last_fwht_bf_ts = 0;
2533 } else {
2534 cv4l_buffer cap_buf(in, index);
2535 if (fd.querybuf(cap_buf))
2536 return;
2537 last_in_buf = cap_buf;
2538 queue_lst_buf = true;
2539 if (fin && cap_buf.g_bytesused(0) &&
2540 !(cap_buf.g_flags() & V4L2_BUF_FLAG_ERROR)) {
2541 int idx = get_fwht_req_by_ts(cap_buf.g_timestamp_ns());
2542
2543 if (idx < 0) {
2544 fprintf(stderr, "%s: could not find request from buffer\n", __func__);
2545 fprintf(stderr, "%s: ts = %llu\n", __func__, cap_buf.g_timestamp_ns());
2546 return;
2547 }
2548 composed_width = fwht_reqs[idx].params.width;
2549 composed_height = fwht_reqs[idx].params.height;
2550 write_buffer_to_file(fd, in, cap_buf,
2551 fmt_in, fin);
2552 }
2553 }
2554 if (rc == QUEUE_STOPPED)
2555 return;
2556
2557 if (!stopped) {
2558 rc = do_handle_out(fd, out, fout, NULL, count[OUT],
2559 fps_ts[OUT], fmt_out, false, true);
2560 if (rc) {
2561 stopped = true;
2562 if (rc != QUEUE_STOPPED)
2563 fprintf(stderr, "%s: output stream ended\n", __func__);
2564 close(req_fd);
2565 fwht_reqs[index].fd = -1;
2566 }
2567 }
2568 index = (index + 1) % out.g_buffers();
2569 }
2570
2571 fcntl(fd.g_fd(), F_SETFL, fd_flags);
2572 fprintf(stderr, "\n");
2573
2574 fd.streamoff(in.g_type());
2575 fd.streamoff(out.g_type());
2576 in.free(&fd);
2577 out.free(&fd);
2578 tpg_free(&tpg);
2579 }
2580
streaming_set_m2m(cv4l_fd & fd,cv4l_fd & exp_fd)2581 static void streaming_set_m2m(cv4l_fd &fd, cv4l_fd &exp_fd)
2582 {
2583 cv4l_queue in(fd.g_type(), memory);
2584 cv4l_queue out(v4l_type_invert(fd.g_type()), out_memory);
2585 cv4l_queue exp_q(exp_fd.g_type(), V4L2_MEMORY_MMAP);
2586 cv4l_fd *exp_fd_p = NULL;
2587 FILE *file[2] = {NULL, NULL};
2588 cv4l_fmt fmt[2];
2589
2590 fd.g_fmt(fmt[OUT], out.g_type());
2591 fd.g_fmt(fmt[CAP], in.g_type());
2592
2593 if (!fd.has_vid_m2m()) {
2594 fprintf(stderr, "unsupported m2m stream type\n");
2595 return;
2596 }
2597 if (options[OptStreamDmaBuf] && options[OptStreamOutDmaBuf]) {
2598 fprintf(stderr, "--stream-dmabuf and --stream-out-dmabuf not supported for m2m devices\n");
2599 return;
2600 }
2601 if ((options[OptStreamDmaBuf] || options[OptStreamOutDmaBuf]) && exp_fd.g_fd() < 0) {
2602 fprintf(stderr, "--stream-dmabuf or --stream-out-dmabuf can only work in combination with --export-device\n");
2603 return;
2604 }
2605
2606 file[CAP] = open_output_file(fd);
2607 file[OUT] = open_input_file(fd, out.g_type());
2608
2609 if (options[OptStreamDmaBuf]) {
2610 if (exp_q.reqbufs(&exp_fd, reqbufs_count_cap))
2611 goto done;
2612 exp_fd_p = &exp_fd;
2613 }
2614
2615 if (options[OptStreamOutDmaBuf]) {
2616 if (exp_q.reqbufs(&exp_fd, reqbufs_count_out))
2617 goto done;
2618 if (out.export_bufs(&exp_fd, exp_fd.g_type()))
2619 goto done;
2620 }
2621 if (fmt[OUT].g_pixelformat() == V4L2_PIX_FMT_FWHT_STATELESS)
2622 stateless_m2m(fd, in, out, file[CAP], file[OUT], fmt[CAP], fmt[OUT], exp_fd_p);
2623 else
2624 stateful_m2m(fd, in, out, file[CAP], file[OUT], fmt[CAP], fmt[OUT], exp_fd_p);
2625
2626 done:
2627 if (options[OptStreamDmaBuf] || options[OptStreamOutDmaBuf])
2628 exp_q.close_exported_fds();
2629
2630 if (file[CAP] && file[CAP] != stdout)
2631 fclose(file[CAP]);
2632
2633 if (file[OUT] && file[OUT] != stdin)
2634 fclose(file[OUT]);
2635 }
2636
streaming_set_cap2out(cv4l_fd & fd,cv4l_fd & out_fd)2637 static void streaming_set_cap2out(cv4l_fd &fd, cv4l_fd &out_fd)
2638 {
2639 int fd_flags = fcntl(fd.g_fd(), F_GETFL);
2640 bool use_poll = options[OptStreamPoll];
2641 bool use_dmabuf = options[OptStreamDmaBuf] || options[OptStreamOutDmaBuf];
2642 bool use_userptr = options[OptStreamUser] && options[OptStreamOutUser];
2643 uint32_t out_type = out_fd.has_vid_m2m() ? v4l_type_invert(out_fd.g_type()) : out_fd.g_type();
2644 cv4l_queue in(fd.g_type(), memory);
2645 cv4l_queue out(out_type, out_memory);
2646 fps_timestamps fps_ts[2];
2647 unsigned count[2] = { 0, 0 };
2648 FILE *file[2] = {NULL, NULL};
2649 fd_set fds;
2650 unsigned cnt = 0;
2651 cv4l_fmt fmt[2];
2652
2653 fd.g_fmt(fmt[OUT], out.g_type());
2654 fd.g_fmt(fmt[CAP], in.g_type());
2655 if (!(capabilities & (V4L2_CAP_VIDEO_CAPTURE |
2656 V4L2_CAP_VIDEO_CAPTURE_MPLANE |
2657 V4L2_CAP_VIDEO_M2M |
2658 V4L2_CAP_VIDEO_M2M_MPLANE))) {
2659 fprintf(stderr, "unsupported capture stream type\n");
2660 return;
2661 }
2662 if (!(out_capabilities & (V4L2_CAP_VIDEO_OUTPUT |
2663 V4L2_CAP_VIDEO_OUTPUT_MPLANE |
2664 V4L2_CAP_VIDEO_M2M |
2665 V4L2_CAP_VIDEO_M2M_MPLANE))) {
2666 fprintf(stderr, "unsupported output stream type\n");
2667 return;
2668 }
2669 if (options[OptStreamDmaBuf] && !options[OptStreamOutMmap]) {
2670 fprintf(stderr, "--stream-dmabuf can only work in combination with --stream-out-mmap\n");
2671 return;
2672 }
2673 if (options[OptStreamOutDmaBuf] && !options[OptStreamMmap]) {
2674 fprintf(stderr, "--stream-out-dmabuf can only work in combination with --stream-mmap\n");
2675 return;
2676 }
2677 if (options[OptStreamDmaBuf])
2678 reqbufs_count_cap = reqbufs_count_out;
2679 if (options[OptStreamOutDmaBuf])
2680 reqbufs_count_out = reqbufs_count_cap;
2681 if (!use_dmabuf && !use_userptr) {
2682 fprintf(stderr, "Allowed combinations (for now):\n");
2683 fprintf(stderr, "\t--stream-mmap and --stream-out-dmabuf\n");
2684 fprintf(stderr, "\t--stream-dmabuf and --stream-out-mmap\n");
2685 fprintf(stderr, "\t--stream-user and --stream-out-user\n");
2686 return;
2687 }
2688
2689 if (file_to) {
2690 if (!strcmp(file_to, "-"))
2691 file[CAP] = stdout;
2692 else
2693 file[CAP] = fopen(file_to, "w+");
2694 if (!file[CAP]) {
2695 fprintf(stderr, "could not open %s for writing\n", file_to);
2696 return;
2697 }
2698 }
2699
2700 if (file_from) {
2701 if (!strcmp(file_from, "-"))
2702 file[OUT] = stdin;
2703 else
2704 file[OUT] = fopen(file_from, "r");
2705 if (!file[OUT]) {
2706 fprintf(stderr, "could not open %s for reading\n", file_from);
2707 return;
2708 }
2709 }
2710
2711 if (in.reqbufs(&fd, reqbufs_count_cap) ||
2712 out.reqbufs(&out_fd, reqbufs_count_out))
2713 goto done;
2714
2715 if (options[OptStreamDmaBuf]) {
2716 if (in.export_bufs(&out_fd, out.g_type()))
2717 goto done;
2718 } else if (options[OptStreamOutDmaBuf]) {
2719 if (out.export_bufs(&fd, in.g_type()))
2720 goto done;
2721 }
2722
2723 if (in.g_num_planes() != out.g_num_planes()) {
2724 fprintf(stderr, "mismatch between number of planes\n");
2725 goto done;
2726 }
2727
2728 if (in.obtain_bufs(&fd) ||
2729 in.queue_all(&fd) ||
2730 do_setup_out_buffers(out_fd, out, file[OUT], false, false) == QUEUE_ERROR)
2731 goto done;
2732
2733 fps_ts[CAP].determine_field(fd.g_fd(), in.g_type());
2734 fps_ts[OUT].determine_field(fd.g_fd(), out.g_type());
2735
2736 if (fd.streamon() || out_fd.streamon())
2737 goto done;
2738
2739 fd.s_trace(0);
2740 out_fd.s_trace(0);
2741
2742 while (stream_sleep == 0)
2743 sleep(100);
2744
2745 if (use_poll)
2746 fcntl(fd.g_fd(), F_SETFL, fd_flags | O_NONBLOCK);
2747
2748 while (true) {
2749 struct timeval tv = { use_poll ? 2 : 0, 0 };
2750 int r = 0;
2751
2752 FD_ZERO(&fds);
2753 FD_SET(fd.g_fd(), &fds);
2754
2755 if (use_poll)
2756 r = select(fd.g_fd() + 1, &fds, NULL, NULL, &tv);
2757
2758 if (r == -1) {
2759 if (EINTR == errno)
2760 continue;
2761 fprintf(stderr, "select error: %s\n",
2762 strerror(errno));
2763 goto done;
2764 }
2765 if (use_poll && r == 0) {
2766 fprintf(stderr, "select timeout\n");
2767 goto done;
2768 }
2769
2770 if (FD_ISSET(fd.g_fd(), &fds)) {
2771 int index = -1;
2772
2773 r = do_handle_cap(fd, in, file[CAP], &index,
2774 count[CAP], fps_ts[CAP], fmt[CAP], true);
2775 if (r)
2776 fprintf(stderr, "handle cap %d\n", r);
2777 if (!r) {
2778 cv4l_buffer buf(in, index);
2779
2780 if (fd.querybuf(buf))
2781 break;
2782 r = do_handle_out(out_fd, out, file[OUT], &buf,
2783 count[OUT], fps_ts[OUT], fmt[OUT],
2784 false, false);
2785 }
2786 if (r)
2787 fprintf(stderr, "handle out %d\n", r);
2788 if (!r && cnt++ > 1)
2789 r = do_handle_out_to_in(out_fd, fd, out, in);
2790 if (r)
2791 fprintf(stderr, "handle out2in %d\n", r);
2792 if (r < 0) {
2793 fd.streamoff();
2794 out_fd.streamoff();
2795 break;
2796 }
2797 }
2798 }
2799
2800 done:
2801 fcntl(fd.g_fd(), F_SETFL, fd_flags);
2802 fprintf(stderr, "\n");
2803
2804 if (options[OptStreamDmaBuf])
2805 out.close_exported_fds();
2806 if (options[OptStreamOutDmaBuf])
2807 in.close_exported_fds();
2808
2809 in.free(&fd);
2810 out.free(&out_fd);
2811 tpg_free(&tpg);
2812
2813 if (file[CAP] && file[CAP] != stdout)
2814 fclose(file[CAP]);
2815
2816 if (file[OUT] && file[OUT] != stdin)
2817 fclose(file[OUT]);
2818 }
2819
streaming_set(cv4l_fd & fd,cv4l_fd & out_fd,cv4l_fd & exp_fd)2820 void streaming_set(cv4l_fd &fd, cv4l_fd &out_fd, cv4l_fd &exp_fd)
2821 {
2822 int do_cap = options[OptStreamMmap] + options[OptStreamUser] + options[OptStreamDmaBuf];
2823 int do_out = options[OptStreamOutMmap] + options[OptStreamOutUser] + options[OptStreamOutDmaBuf];
2824
2825 if (out_fd.g_fd() < 0) {
2826 out_capabilities = capabilities;
2827 out_priv_magic = priv_magic;
2828 }
2829
2830 if (do_cap > 1) {
2831 fprintf(stderr, "only one of --stream-mmap/user/dmabuf is allowed\n");
2832 return;
2833 }
2834 if (do_out > 1) {
2835 fprintf(stderr, "only one of --stream-out-mmap/user/dmabuf is allowed\n");
2836 return;
2837 }
2838
2839 unsigned int old_trace_fd = fd.g_trace();
2840 unsigned int old_trace_out_fd = out_fd.g_trace();
2841 unsigned int old_trace_exp_fd = exp_fd.g_trace();
2842
2843 get_cap_compose_rect(fd);
2844 get_out_crop_rect(fd);
2845
2846 if (do_cap && do_out && out_fd.g_fd() < 0)
2847 streaming_set_m2m(fd, exp_fd);
2848 else if (do_cap && do_out)
2849 streaming_set_cap2out(fd, out_fd);
2850 else if (do_cap)
2851 streaming_set_cap(fd, exp_fd);
2852 else if (do_out)
2853 streaming_set_out(fd, exp_fd);
2854
2855 fd.s_trace(old_trace_fd);
2856 out_fd.s_trace(old_trace_out_fd);
2857 exp_fd.s_trace(old_trace_exp_fd);
2858 }
2859
streaming_list(cv4l_fd & fd,cv4l_fd & out_fd)2860 void streaming_list(cv4l_fd &fd, cv4l_fd &out_fd)
2861 {
2862 cv4l_fd *p_out_fd = out_fd.g_fd() < 0 ? &fd : &out_fd;
2863
2864 if (out_fd.g_fd() < 0)
2865 out_capabilities = capabilities;
2866
2867 if (options[OptListBuffers])
2868 list_buffers(fd, fd.g_type());
2869
2870 if (options[OptListBuffersOut])
2871 list_buffers(*p_out_fd, p_out_fd->has_vid_m2m() ?
2872 v4l_type_invert(p_out_fd->g_type()) : p_out_fd->g_type());
2873
2874 if (options[OptStreamBufCaps])
2875 stream_buf_caps(fd, fd.g_type());
2876
2877 if (options[OptStreamOutBufCaps])
2878 stream_buf_caps(*p_out_fd, v4l_type_invert(p_out_fd->g_type()));
2879
2880 if (options[OptListBuffersVbi])
2881 list_buffers(fd, V4L2_BUF_TYPE_VBI_CAPTURE);
2882
2883 if (options[OptListBuffersSlicedVbi])
2884 list_buffers(fd, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
2885
2886 if (options[OptListBuffersVbiOut])
2887 list_buffers(*p_out_fd, V4L2_BUF_TYPE_VBI_OUTPUT);
2888
2889 if (options[OptListBuffersSlicedVbiOut])
2890 list_buffers(*p_out_fd, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
2891
2892 if (options[OptListBuffersSdr])
2893 list_buffers(fd, V4L2_BUF_TYPE_SDR_CAPTURE);
2894
2895 if (options[OptListBuffersSdrOut])
2896 list_buffers(fd, V4L2_BUF_TYPE_SDR_OUTPUT);
2897
2898 if (options[OptListBuffersMeta])
2899 list_buffers(fd, V4L2_BUF_TYPE_META_CAPTURE);
2900
2901 if (options[OptListPatterns]) {
2902 printf("List of available patterns:\n");
2903 for (unsigned i = 0; tpg_pattern_strings[i]; i++)
2904 printf("\t%2d: %s\n", i, tpg_pattern_strings[i]);
2905 }
2906 }
2907