• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "v4l2-ctl.h"
2 
3 struct v4l2_decoder_cmd dec_cmd; /* (try_)decoder_cmd */
4 static struct v4l2_encoder_cmd enc_cmd; /* (try_)encoder_cmd */
5 static struct v4l2_jpegcompression jpegcomp; /* jpeg compression */
6 static struct v4l2_streamparm parm;	/* get/set parm */
7 static double fps = 0;			/* set framerate speed, in fps */
8 static double output_fps = 0;		/* set framerate speed, in fps */
9 
misc_usage()10 void misc_usage()
11 {
12 	printf("\nMiscellaneous options:\n"
13 	       "  --wait-for-event <event>\n"
14 	       "                     wait for an event [VIDIOC_DQEVENT]\n"
15 	       "                     <event> is the event number or one of:\n"
16 	       "                     eos, vsync, ctrl=<id>, frame_sync, source_change=<pad>,\n"
17 	       "                     motion_det\n"
18 	       "                     where <id> is the name of the control\n"
19 	       "                     and where <pad> is the index of the pad or input\n"
20 	       "  --poll-for-event <event>\n"
21 	       "                     poll for an event [VIDIOC_DQEVENT]\n"
22 	       "                     see --wait-for-event for possible events\n"
23 	       "  --epoll-for-event <event>\n"
24 	       "                     epoll for an event [VIDIOC_DQEVENT]\n"
25 	       "                     see --wait-for-event for possible events\n"
26 	       "  -P, --get-parm     display video parameters [VIDIOC_G_PARM]\n"
27 	       "  -p, --set-parm <fps>\n"
28 	       "                     set video framerate in <fps> [VIDIOC_S_PARM]\n"
29 	       "  --get-output-parm  display output video parameters [VIDIOC_G_PARM]\n"
30 	       "  --set-output-parm <fps>\n"
31 	       "                     set output video framerate in <fps> [VIDIOC_S_PARM]\n"
32 	       "  --get-jpeg-comp    query the JPEG compression [VIDIOC_G_JPEGCOMP]\n"
33 	       "  --set-jpeg-comp quality=<q>,markers=<markers>,comment=<c>,app<n>=<a>\n"
34 	       "                     set the JPEG compression [VIDIOC_S_JPEGCOMP]\n"
35 	       "                     <n> is the app segment: 0-9/a-f, <a> is the actual string.\n"
36 	       "                     <markers> is a colon separated list of:\n"
37 	       "                     dht:      Define Huffman Tables\n"
38 	       "                     dqt:      Define Quantization Tables\n"
39 	       "                     dri:      Define Restart Interval\n"
40 	       "  --encoder-cmd cmd=<cmd>,flags=<flags>\n"
41 	       "                     Send a command to the encoder [VIDIOC_ENCODER_CMD]\n"
42 	       "                     cmd=start|stop|pause|resume\n"
43 	       "                     flags=stop_at_gop_end\n"
44 	       "  --try-encoder-cmd cmd=<cmd>,flags=<flags>\n"
45 	       "                     Try an encoder command [VIDIOC_TRY_ENCODER_CMD]\n"
46 	       "                     See --encoder-cmd for the arguments.\n"
47 	       "  --decoder-cmd cmd=<cmd>,flags=<flags>,stop_pts=<pts>,start_speed=<speed>,\n"
48 	       "                     start_format=<none|gop>\n"
49 	       "                     Send a command to the decoder [VIDIOC_DECODER_CMD]\n"
50 	       "                     cmd=start|stop|pause|resume\n"
51 	       "                     flags=start_mute_audio|pause_to_black|stop_to_black|\n"
52 	       "                           stop_immediately\n"
53 	       "  --try-decoder-cmd cmd=<cmd>,flags=<flags>\n"
54 	       "                     Try a decoder command [VIDIOC_TRY_DECODER_CMD]\n"
55 	       "                     See --decoder-cmd for the arguments.\n"
56 	       );
57 }
58 
markers2s(unsigned markers)59 static std::string markers2s(unsigned markers)
60 {
61 	std::string s;
62 
63 	if (markers & V4L2_JPEG_MARKER_DHT)
64 		s += "\t\tDefine Huffman Tables\n";
65 	if (markers & V4L2_JPEG_MARKER_DQT)
66 		s += "\t\tDefine Quantization Tables\n";
67 	if (markers & V4L2_JPEG_MARKER_DRI)
68 		s += "\t\tDefine Restart Interval\n";
69 	if (markers & V4L2_JPEG_MARKER_COM)
70 		s += "\t\tDefine Comment\n";
71 	if (markers & V4L2_JPEG_MARKER_APP)
72 		s += "\t\tDefine APP segment\n";
73 	return s;
74 }
75 
printjpegcomp(const struct v4l2_jpegcompression & jc)76 static void printjpegcomp(const struct v4l2_jpegcompression &jc)
77 {
78 	printf("JPEG compression:\n");
79 	printf("\tQuality: %d\n", jc.quality);
80 	if (jc.COM_len)
81 		printf("\tComment: '%s'\n", jc.COM_data);
82 	if (jc.APP_len)
83 		printf("\tAPP%x   : '%s'\n", jc.APPn, jc.APP_data);
84 	printf("\tMarkers: 0x%08x\n", jc.jpeg_markers);
85 	printf("%s", markers2s(jc.jpeg_markers).c_str());
86 }
87 
print_enccmd(const struct v4l2_encoder_cmd & cmd)88 static void print_enccmd(const struct v4l2_encoder_cmd &cmd)
89 {
90 	switch (cmd.cmd) {
91 	case V4L2_ENC_CMD_START:
92 		printf("\tstart\n");
93 		break;
94 	case V4L2_ENC_CMD_STOP:
95 		printf("\tstop%s\n",
96 			(cmd.flags & V4L2_ENC_CMD_STOP_AT_GOP_END) ? " at gop end" : "");
97 		break;
98 	case V4L2_ENC_CMD_PAUSE:
99 		printf("\tpause\n");
100 		break;
101 	case V4L2_ENC_CMD_RESUME:
102 		printf("\tresume\n");
103 		break;
104 	}
105 }
106 
print_deccmd(const struct v4l2_decoder_cmd & cmd)107 static void print_deccmd(const struct v4l2_decoder_cmd &cmd)
108 {
109 	__s32 speed;
110 
111 	switch (cmd.cmd) {
112 	case V4L2_DEC_CMD_START:
113 		speed = cmd.start.speed;
114 		if (speed == 0)
115 			speed = 1000;
116 		printf("\tstart%s%s, ",
117 			cmd.start.format == V4L2_DEC_START_FMT_GOP ? " (GOP aligned)" : "",
118 			(speed != 1000 &&
119 			 (cmd.flags & V4L2_DEC_CMD_START_MUTE_AUDIO)) ? " (mute audio)" : "");
120 		if (speed == 1 || speed == -1)
121 			printf("single step %s\n",
122 				speed == 1 ? "forward" : "backward");
123 		else
124 			printf("speed %.3fx\n", speed / 1000.0);
125 		break;
126 	case V4L2_DEC_CMD_STOP:
127 		printf("\tstop%s%s\n",
128 			(cmd.flags & V4L2_DEC_CMD_STOP_TO_BLACK) ? " to black" : "",
129 			(cmd.flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) ? " immediately" : "");
130 		break;
131 	case V4L2_DEC_CMD_PAUSE:
132 		printf("\tpause%s\n",
133 			(cmd.flags & V4L2_DEC_CMD_PAUSE_TO_BLACK) ? " to black" : "");
134 		break;
135 	case V4L2_DEC_CMD_RESUME:
136 		printf("\tresume\n");
137 		break;
138 	}
139 }
140 
141 /* Used for both encoder and decoder commands since they are the same
142    at the moment. */
parse_cmd(const char * s)143 static int parse_cmd(const char *s)
144 {
145 	if (!strcmp(s, "start")) return V4L2_ENC_CMD_START;
146 	if (!strcmp(s, "stop")) return V4L2_ENC_CMD_STOP;
147 	if (!strcmp(s, "pause")) return V4L2_ENC_CMD_PAUSE;
148 	if (!strcmp(s, "resume")) return V4L2_ENC_CMD_RESUME;
149 	return 0;
150 }
151 
parse_encflags(const char * s)152 static int parse_encflags(const char *s)
153 {
154 	if (!strcmp(s, "stop_at_gop_end")) return V4L2_ENC_CMD_STOP_AT_GOP_END;
155 	return 0;
156 }
157 
parse_decflags(const char * s)158 static int parse_decflags(const char *s)
159 {
160 	if (!strcmp(s, "start_mute_audio")) return V4L2_DEC_CMD_START_MUTE_AUDIO;
161 	if (!strcmp(s, "pause_to_black")) return V4L2_DEC_CMD_PAUSE_TO_BLACK;
162 	if (!strcmp(s, "stop_to_black")) return V4L2_DEC_CMD_STOP_TO_BLACK;
163 	if (!strcmp(s, "stop_immediately")) return V4L2_DEC_CMD_STOP_IMMEDIATELY;
164 	return 0;
165 }
166 
misc_cmd(int ch,char * optarg)167 void misc_cmd(int ch, char *optarg)
168 {
169 	char *value, *subs;
170 
171 	switch (ch) {
172 	case OptSetParm:
173 		fps = strtod(optarg, nullptr);
174 		break;
175 	case OptSetOutputParm:
176 		output_fps = strtod(optarg, nullptr);
177 		break;
178 	case OptSetJpegComp:
179 		subs = optarg;
180 		while (*subs != '\0') {
181 			static constexpr const char *subopts[] = {
182 				"app0", "app1", "app2", "app3",
183 				"app4", "app5", "app6", "app7",
184 				"app8", "app9", "appa", "appb",
185 				"appc", "appd", "appe", "appf",
186 				"quality",
187 				"markers",
188 				"comment",
189 				nullptr
190 			};
191 			size_t len;
192 			int opt = parse_subopt(&subs, subopts, &value);
193 
194 			switch (opt) {
195 			case 16:
196 				jpegcomp.quality = strtol(value, nullptr, 0);
197 				break;
198 			case 17:
199 				if (strstr(value, "dht"))
200 					jpegcomp.jpeg_markers |= V4L2_JPEG_MARKER_DHT;
201 				if (strstr(value, "dqt"))
202 					jpegcomp.jpeg_markers |= V4L2_JPEG_MARKER_DQT;
203 				if (strstr(value, "dri"))
204 					jpegcomp.jpeg_markers |= V4L2_JPEG_MARKER_DRI;
205 				break;
206 			case 18:
207 				len = strlen(value);
208 				if (len > sizeof(jpegcomp.COM_data) - 1)
209 					len = sizeof(jpegcomp.COM_data) - 1;
210 				jpegcomp.COM_len = len;
211 				memcpy(jpegcomp.COM_data, value, len);
212 				jpegcomp.COM_data[len] = '\0';
213 				break;
214 			default:
215 				if (opt < 0 || opt > 15) {
216 					misc_usage();
217 					std::exit(EXIT_FAILURE);
218 				}
219 				len = strlen(value);
220 				if (len > sizeof(jpegcomp.APP_data) - 1)
221 					len = sizeof(jpegcomp.APP_data) - 1;
222 				if (jpegcomp.APP_len) {
223 					fprintf(stderr, "Only one APP segment can be set\n");
224 					break;
225 				}
226 				jpegcomp.APP_len = len;
227 				memcpy(jpegcomp.APP_data, value, len);
228 				jpegcomp.APP_data[len] = '\0';
229 				jpegcomp.APPn = opt;
230 				break;
231 			}
232 		}
233 		break;
234 	case OptEncoderCmd:
235 	case OptTryEncoderCmd:
236 		subs = optarg;
237 		while (*subs != '\0') {
238 			static constexpr const char *subopts[] = {
239 				"cmd",
240 				"flags",
241 				nullptr
242 			};
243 
244 			switch (parse_subopt(&subs, subopts, &value)) {
245 			case 0:
246 				enc_cmd.cmd = parse_cmd(value);
247 				break;
248 			case 1:
249 				enc_cmd.flags = parse_encflags(value);
250 				break;
251 			default:
252 				misc_usage();
253 				std::exit(EXIT_FAILURE);
254 			}
255 		}
256 		break;
257 	case OptDecoderCmd:
258 	case OptTryDecoderCmd:
259 		subs = optarg;
260 		while (*subs != '\0') {
261 			static constexpr const char *subopts[] = {
262 				"cmd",
263 				"flags",
264 				"stop_pts",
265 				"start_speed",
266 				"start_format",
267 				nullptr
268 			};
269 
270 			switch (parse_subopt(&subs, subopts, &value)) {
271 			case 0:
272 				dec_cmd.cmd = parse_cmd(value);
273 				break;
274 			case 1:
275 				dec_cmd.flags = parse_decflags(value);
276 				break;
277 			case 2:
278 				dec_cmd.stop.pts = strtoull(value, nullptr, 0);
279 				break;
280 			case 3:
281 				dec_cmd.start.speed = strtol(value, nullptr, 0);
282 				break;
283 			case 4:
284 				if (!strcmp(value, "gop"))
285 					dec_cmd.start.format = V4L2_DEC_START_FMT_GOP;
286 				else if (!strcmp(value, "none"))
287 					dec_cmd.start.format = V4L2_DEC_START_FMT_NONE;
288 				break;
289 			default:
290 				misc_usage();
291 				std::exit(EXIT_FAILURE);
292 			}
293 		}
294 		break;
295 	}
296 }
297 
misc_set(cv4l_fd & _fd)298 void misc_set(cv4l_fd &_fd)
299 {
300 	int fd = _fd.g_fd();
301 
302 	if (options[OptSetParm]) {
303 		memset(&parm, 0, sizeof(parm));
304 		parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
305 		parm.parm.capture.timeperframe.numerator = 1000;
306 		parm.parm.capture.timeperframe.denominator =
307 			static_cast<uint32_t>(fps * parm.parm.capture.timeperframe.numerator);
308 
309 		if (doioctl(fd, VIDIOC_S_PARM, &parm) == 0) {
310 			struct v4l2_fract *tf = &parm.parm.capture.timeperframe;
311 
312 			if (!tf->denominator || !tf->numerator)
313 				info("Invalid frame rate\n");
314 			else
315 				info("Frame rate set to %.3f fps\n",
316 				     1.0 * tf->denominator / tf->numerator);
317 		}
318 	}
319 
320 	if (options[OptSetOutputParm]) {
321 		memset(&parm, 0, sizeof(parm));
322 		parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
323 		parm.parm.output.timeperframe.numerator = 1000;
324 		parm.parm.output.timeperframe.denominator =
325 			static_cast<uint32_t>(output_fps * parm.parm.output.timeperframe.numerator);
326 
327 		if (doioctl(fd, VIDIOC_S_PARM, &parm) == 0) {
328 			struct v4l2_fract *tf = &parm.parm.output.timeperframe;
329 
330 			if (!tf->denominator || !tf->numerator)
331 				info("Invalid frame rate\n");
332 			else
333 				info("Frame rate set to %.3f fps\n",
334 				     1.0 * tf->denominator / tf->numerator);
335 		}
336 	}
337 
338 	if (options[OptSetJpegComp]) {
339 		doioctl(fd, VIDIOC_S_JPEGCOMP, &jpegcomp);
340 	}
341 
342 	if (options[OptEncoderCmd])
343 		doioctl(fd, VIDIOC_ENCODER_CMD, &enc_cmd);
344 	if (options[OptTryEncoderCmd])
345 		if (doioctl(fd, VIDIOC_TRY_ENCODER_CMD, &enc_cmd) == 0)
346 			print_enccmd(enc_cmd);
347 	if (options[OptDecoderCmd])
348 		doioctl(fd, VIDIOC_DECODER_CMD, &dec_cmd);
349 	if (options[OptTryDecoderCmd])
350 		if (doioctl(fd, VIDIOC_TRY_DECODER_CMD, &dec_cmd) == 0)
351 			print_deccmd(dec_cmd);
352 }
353 
misc_get(cv4l_fd & _fd)354 void misc_get(cv4l_fd &_fd)
355 {
356 	int fd = _fd.g_fd();
357 
358 	if (options[OptGetJpegComp]) {
359 		struct v4l2_jpegcompression jc;
360 		if (doioctl(fd, VIDIOC_G_JPEGCOMP, &jc) == 0)
361 			printjpegcomp(jc);
362 	}
363 
364         if (options[OptGetParm]) {
365 		memset(&parm, 0, sizeof(parm));
366 		parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
367 		if (doioctl(fd, VIDIOC_G_PARM, &parm) == 0) {
368 			const struct v4l2_fract &tf = parm.parm.capture.timeperframe;
369 
370 			printf("Streaming Parameters %s:\n", buftype2s(parm.type).c_str());
371 			if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
372 				printf("\tCapabilities     : timeperframe\n");
373 			if (parm.parm.capture.capturemode & V4L2_MODE_HIGHQUALITY)
374 				printf("\tCapture mode     : high quality\n");
375 			if (!tf.denominator || !tf.numerator)
376 				printf("\tFrames per second: invalid (%d/%d)\n",
377 						tf.denominator, tf.numerator);
378 			else
379 				printf("\tFrames per second: %.3f (%d/%d)\n",
380 						(1.0 * tf.denominator) / tf.numerator,
381 						tf.denominator, tf.numerator);
382 			printf("\tRead buffers     : %d\n", parm.parm.capture.readbuffers);
383 		}
384 	}
385 
386 	if (options[OptGetOutputParm]) {
387 		memset(&parm, 0, sizeof(parm));
388 		parm.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
389 		if (doioctl(fd, VIDIOC_G_PARM, &parm) == 0) {
390 			const struct v4l2_fract &tf = parm.parm.output.timeperframe;
391 
392 			printf("Streaming Parameters %s:\n", buftype2s(parm.type).c_str());
393 			if (parm.parm.output.capability & V4L2_CAP_TIMEPERFRAME)
394 				printf("\tCapabilities     : timeperframe\n");
395 			if (parm.parm.output.outputmode & V4L2_MODE_HIGHQUALITY)
396 				printf("\tOutput mode      : high quality\n");
397 			if (!tf.denominator || !tf.numerator)
398 				printf("\tFrames per second: invalid (%d/%d)\n",
399 						tf.denominator, tf.numerator);
400 			else
401 				printf("\tFrames per second: %.3f (%d/%d)\n",
402 						(1.0 * tf.denominator) / tf.numerator,
403 						tf.denominator, tf.numerator);
404 			printf("\tWrite buffers    : %d\n", parm.parm.output.writebuffers);
405 		}
406 	}
407 }
408