• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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