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