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