• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "v4l2-ctl.h"
2 
3 /* crop specified */
4 #define CropWidth		(1L<<0)
5 #define CropHeight		(1L<<1)
6 #define CropLeft		(1L<<2)
7 #define CropTop 		(1L<<3)
8 
9 /* selection specified */
10 #define SelectionWidth		(1L<<0)
11 #define SelectionHeight		(1L<<1)
12 #define SelectionLeft		(1L<<2)
13 #define SelectionTop 		(1L<<3)
14 #define SelectionFlags 		(1L<<4)
15 
16 /* bitfield for fmts */
17 static unsigned int set_crop;
18 static unsigned int set_crop_out;
19 static unsigned int set_crop_overlay;
20 static unsigned int set_crop_out_overlay;
21 static unsigned int set_selection;
22 static unsigned int set_selection_out;
23 static int get_sel_target;
24 static struct v4l2_rect vcrop; 	/* crop rect */
25 static struct v4l2_rect vcrop_out; 	/* crop rect */
26 static struct v4l2_rect vcrop_overlay; 	/* crop rect */
27 static struct v4l2_rect vcrop_out_overlay; 	/* crop rect */
28 static struct v4l2_selection vselection; 	/* capture selection */
29 static struct v4l2_selection vselection_out;	/* output selection */
30 
selection_usage()31 void selection_usage()
32 {
33 	printf("\nSelection/Cropping options:\n"
34 	       "  --get-cropcap      query the crop capabilities [VIDIOC_CROPCAP]\n"
35 	       "  --get-crop	     query the video capture crop window [VIDIOC_G_CROP]\n"
36 	       "  --set-crop top=<x>,left=<y>,width=<w>,height=<h>\n"
37 	       "                     set the video capture crop window [VIDIOC_S_CROP]\n"
38 	       "  --get-cropcap-output\n"
39 	       "                     query crop capabilities for video output [VIDIOC_CROPCAP]\n"
40 	       "  --get-crop-output  query the video output crop window [VIDIOC_G_CROP]\n"
41 	       "  --set-crop-output top=<x>,left=<y>,width=<w>,height=<h>\n"
42 	       "                     set the video output crop window [VIDIOC_S_CROP]\n"
43 	       "  --get-cropcap-overlay\n"
44 	       "                     query crop capabilities for video overlay [VIDIOC_CROPCAP]\n"
45 	       "  --get-crop-overlay query the video overlay crop window [VIDIOC_G_CROP]\n"
46 	       "  --set-crop-overlay top=<x>,left=<y>,width=<w>,height=<h>\n"
47 	       "                     set the video overlay crop window [VIDIOC_S_CROP]\n"
48 	       "  --get-cropcap-output-overlay\n"
49 	       "                     query the crop capabilities for video output overlays\n"
50 	       "                     [VIDIOC_CROPCAP]\n"
51 	       "  --get-crop-output-overlay\n"
52 	       "                     query the video output overlay crop window [VIDIOC_G_CROP]\n"
53 	       "  --set-crop-output-overlay top=<x>,left=<y>,width=<w>,height=<h>\n"
54 	       "                     set the video output overlay crop window [VIDIOC_S_CROP]\n"
55 	       "  --get-selection target=<target>\n"
56 	       "                     query the video capture selection rectangle [VIDIOC_G_SELECTION]\n"
57 	       "                     See --set-selection command for the valid <target> values.\n"
58 	       "  --set-selection target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>\n"
59 	       "                     set the video capture selection rectangle [VIDIOC_S_SELECTION]\n"
60 	       "                     target=crop|crop_bounds|crop_default|compose|compose_bounds|\n"
61 	       "                            compose_default|compose_padded|native_size\n"
62 	       "                     flags=le|ge|keep-config\n"
63 	       "  --get-selection-output target=<target>\n"
64 	       "                     query the video output selection rectangle [VIDIOC_G_SELECTION]\n"
65 	       "                     See --set-selection command for the valid <target> values.\n"
66 	       "  --set-selection-output target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>\n"
67 	       "                     set the video output selection rectangle [VIDIOC_S_SELECTION]\n"
68 	       "                     See --set-selection command for the arguments.\n"
69 	       );
70 }
71 
do_crop(int fd,unsigned int set_crop,const struct v4l2_rect & vcrop,v4l2_buf_type type)72 static void do_crop(int fd, unsigned int set_crop, const struct v4l2_rect &vcrop, v4l2_buf_type type)
73 {
74 	struct v4l2_crop in_crop;
75 
76 	in_crop.type = type;
77 	if (doioctl(fd, VIDIOC_G_CROP, &in_crop) == 0) {
78 		if (set_crop & CropWidth)
79 			in_crop.c.width = vcrop.width;
80 		if (set_crop & CropHeight)
81 			in_crop.c.height = vcrop.height;
82 		if (set_crop & CropLeft)
83 			in_crop.c.left = vcrop.left;
84 		if (set_crop & CropTop)
85 			in_crop.c.top = vcrop.top;
86 		doioctl(fd, VIDIOC_S_CROP, &in_crop);
87 	}
88 }
89 
parse_crop(char * optarg,unsigned int & set_crop,v4l2_rect & vcrop)90 static void parse_crop(char *optarg, unsigned int &set_crop, v4l2_rect &vcrop)
91 {
92 	char *value;
93 	char *subs = optarg;
94 
95 	while (*subs != '\0') {
96 		static constexpr const char *subopts[] = {
97 			"left",
98 			"top",
99 			"width",
100 			"height",
101 			nullptr
102 		};
103 
104 		switch (parse_subopt(&subs, subopts, &value)) {
105 		case 0:
106 			vcrop.left = strtol(value, nullptr, 0);
107 			set_crop |= CropLeft;
108 			break;
109 		case 1:
110 			vcrop.top = strtol(value, nullptr, 0);
111 			set_crop |= CropTop;
112 			break;
113 		case 2:
114 			vcrop.width = strtol(value, nullptr, 0);
115 			set_crop |= CropWidth;
116 			break;
117 		case 3:
118 			vcrop.height = strtol(value, nullptr, 0);
119 			set_crop |= CropHeight;
120 			break;
121 		default:
122 			selection_usage();
123 			std::exit(EXIT_FAILURE);
124 		}
125 	}
126 }
127 
do_selection(int fd,unsigned int set_selection,const struct v4l2_selection & vsel,v4l2_buf_type type)128 static void do_selection(int fd, unsigned int set_selection, const struct v4l2_selection &vsel,
129 			 v4l2_buf_type type)
130 {
131 	struct v4l2_selection in_selection;
132 
133 	in_selection.type = type;
134 	in_selection.target = vsel.target;
135 
136 	if (doioctl(fd, VIDIOC_G_SELECTION, &in_selection) == 0) {
137 		if (set_selection & SelectionWidth)
138 			in_selection.r.width = vsel.r.width;
139 		if (set_selection & SelectionHeight)
140 			in_selection.r.height = vsel.r.height;
141 		if (set_selection & SelectionLeft)
142 			in_selection.r.left = vsel.r.left;
143 		if (set_selection & SelectionTop)
144 			in_selection.r.top = vsel.r.top;
145 		in_selection.flags = (set_selection & SelectionFlags) ? vsel.flags : 0;
146 		doioctl(fd, VIDIOC_S_SELECTION, &in_selection);
147 	}
148 }
149 
parse_selection(char * optarg,unsigned int & set_sel,v4l2_selection & vsel)150 static int parse_selection(char *optarg, unsigned int &set_sel, v4l2_selection &vsel)
151 {
152 	char *value;
153 	char *subs = optarg;
154 
155 	while (*subs != '\0') {
156 		static constexpr const char *subopts[] = {
157 			"target",
158 			"flags",
159 			"left",
160 			"top",
161 			"width",
162 			"height",
163 			nullptr
164 		};
165 
166 		switch (parse_subopt(&subs, subopts, &value)) {
167 		case 0:
168 			if (parse_selection_target(value, vsel.target)) {
169 				fprintf(stderr, "Unknown selection target\n");
170 				selection_usage();
171 				std::exit(EXIT_FAILURE);
172 			}
173 			break;
174 		case 1:
175 			vsel.flags = parse_selection_flags(value);
176 			set_sel |= SelectionFlags;
177 			break;
178 		case 2:
179 			vsel.r.left = strtol(value, nullptr, 0);
180 			set_sel |= SelectionLeft;
181 			break;
182 		case 3:
183 			vsel.r.top = strtol(value, nullptr, 0);
184 			set_sel |= SelectionTop;
185 			break;
186 		case 4:
187 			vsel.r.width = strtoul(value, nullptr, 0);
188 			set_sel |= SelectionWidth;
189 			break;
190 		case 5:
191 			vsel.r.height = strtoul(value, nullptr, 0);
192 			set_sel |= SelectionHeight;
193 			break;
194 		default:
195 			fprintf(stderr, "Unknown option\n");
196 			selection_usage();
197 			std::exit(EXIT_FAILURE);
198 		}
199 	}
200 
201 	return 0;
202 }
203 
printcrop(const struct v4l2_crop & crop)204 static void printcrop(const struct v4l2_crop &crop)
205 {
206 	printf("Crop: Left %d, Top %d, Width %d, Height %d\n",
207 			crop.c.left, crop.c.top, crop.c.width, crop.c.height);
208 }
209 
printcropcap(const struct v4l2_cropcap & cropcap)210 static void printcropcap(const struct v4l2_cropcap &cropcap)
211 {
212 	printf("Crop Capability %s:\n", buftype2s(cropcap.type).c_str());
213 	printf("\tBounds      : Left %d, Top %d, Width %d, Height %d\n",
214 			cropcap.bounds.left, cropcap.bounds.top, cropcap.bounds.width, cropcap.bounds.height);
215 	printf("\tDefault     : Left %d, Top %d, Width %d, Height %d\n",
216 			cropcap.defrect.left, cropcap.defrect.top, cropcap.defrect.width, cropcap.defrect.height);
217 	printf("\tPixel Aspect: %u/%u\n", cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator);
218 }
219 
selection_cmd(int ch,char * optarg)220 void selection_cmd(int ch, char *optarg)
221 {
222 	switch (ch) {
223 		case OptSetCrop:
224 			parse_crop(optarg, set_crop, vcrop);
225 			break;
226 		case OptSetOutputCrop:
227 			parse_crop(optarg, set_crop_out, vcrop_out);
228 			break;
229 		case OptSetOverlayCrop:
230 			parse_crop(optarg, set_crop_overlay, vcrop_overlay);
231 			break;
232 		case OptSetOutputOverlayCrop:
233 			parse_crop(optarg, set_crop_out_overlay, vcrop_out_overlay);
234 			break;
235 		case OptSetSelection:
236 			parse_selection(optarg, set_selection, vselection);
237 			break;
238 		case OptSetOutputSelection:
239 			parse_selection(optarg, set_selection_out, vselection_out);
240 			break;
241 		case OptGetOutputSelection:
242 		case OptGetSelection: {
243 			struct v4l2_selection gsel;
244 			unsigned int get_sel;
245 
246 			if (parse_selection(optarg, get_sel, gsel)) {
247 				fprintf(stderr, "Unknown selection target\n");
248 				selection_usage();
249 				std::exit(EXIT_FAILURE);
250 			}
251 			get_sel_target = gsel.target;
252 			break;
253 		}
254 	}
255 }
256 
selection_set(cv4l_fd & _fd)257 void selection_set(cv4l_fd &_fd)
258 {
259 	int fd = _fd.g_fd();
260 
261 	if (options[OptSetCrop]) {
262 		do_crop(fd, set_crop, vcrop, V4L2_BUF_TYPE_VIDEO_CAPTURE);
263 	}
264 
265 	if (options[OptSetOutputCrop]) {
266 		do_crop(fd, set_crop_out, vcrop_out, V4L2_BUF_TYPE_VIDEO_OUTPUT);
267 	}
268 
269 	if (options[OptSetOverlayCrop]) {
270 		do_crop(fd, set_crop_overlay, vcrop_overlay, V4L2_BUF_TYPE_VIDEO_OVERLAY);
271 	}
272 
273 	if (options[OptSetOutputOverlayCrop]) {
274 		do_crop(fd, set_crop_out_overlay, vcrop_out_overlay, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY);
275 	}
276 
277 	if (options[OptSetSelection]) {
278 		do_selection(fd, set_selection, vselection, V4L2_BUF_TYPE_VIDEO_CAPTURE);
279 	}
280 
281 	if (options[OptSetOutputSelection]) {
282 		do_selection(fd, set_selection_out, vselection_out, V4L2_BUF_TYPE_VIDEO_OUTPUT);
283 	}
284 }
285 
selection_get(cv4l_fd & _fd)286 void selection_get(cv4l_fd &_fd)
287 {
288 	int fd = _fd.g_fd();
289 
290 	if (options[OptGetCropCap]) {
291 		struct v4l2_cropcap cropcap;
292 
293 		cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
294 		if (doioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0)
295 			printcropcap(cropcap);
296 	}
297 
298 	if (options[OptGetOutputCropCap]) {
299 		struct v4l2_cropcap cropcap;
300 
301 		cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
302 		if (doioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0)
303 			printcropcap(cropcap);
304 	}
305 
306 	if (options[OptGetOverlayCropCap]) {
307 		struct v4l2_cropcap cropcap;
308 
309 		cropcap.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
310 		if (doioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0)
311 			printcropcap(cropcap);
312 	}
313 
314 	if (options[OptGetOutputOverlayCropCap]) {
315 		struct v4l2_cropcap cropcap;
316 
317 		cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
318 		if (doioctl(fd, VIDIOC_CROPCAP, &cropcap) == 0)
319 			printcropcap(cropcap);
320 	}
321 
322 	if (options[OptGetCrop]) {
323 		struct v4l2_crop crop;
324 
325 		crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
326 		if (doioctl(fd, VIDIOC_G_CROP, &crop) == 0)
327 			printcrop(crop);
328 	}
329 
330 	if (options[OptGetOutputCrop]) {
331 		struct v4l2_crop crop;
332 
333 		crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
334 		if (doioctl(fd, VIDIOC_G_CROP, &crop) == 0)
335 			printcrop(crop);
336 	}
337 
338 	if (options[OptGetOverlayCrop]) {
339 		struct v4l2_crop crop;
340 
341 		crop.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
342 		if (doioctl(fd, VIDIOC_G_CROP, &crop) == 0)
343 			printcrop(crop);
344 	}
345 
346 	if (options[OptGetOutputOverlayCrop]) {
347 		struct v4l2_crop crop;
348 
349 		crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY;
350 		if (doioctl(fd, VIDIOC_G_CROP, &crop) == 0)
351 			printcrop(crop);
352 	}
353 
354 	if (options[OptGetSelection]) {
355 		struct v4l2_selection sel;
356 		unsigned idx = 0;
357 
358 		memset(&sel, 0, sizeof(sel));
359 		sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
360 
361 		if (options[OptAll] || get_sel_target == -1) {
362 			while (valid_seltarget_at_idx(idx)) {
363 				sel.target = seltarget_at_idx(idx);
364 				if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0)
365 					print_selection(sel);
366 				idx++;
367 			}
368 		} else {
369 			sel.target = get_sel_target;
370 			if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0)
371 				print_selection(sel);
372 		}
373 	}
374 
375 	if (options[OptGetOutputSelection]) {
376 		struct v4l2_selection sel;
377 		unsigned idx = 0;
378 
379 		memset(&sel, 0, sizeof(sel));
380 		sel.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
381 
382 		if (options[OptAll] || get_sel_target == -1) {
383 			while (valid_seltarget_at_idx(idx)) {
384 				sel.target = seltarget_at_idx(idx);
385 				if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0)
386 					print_selection(sel);
387 				idx++;
388 			}
389 		} else {
390 			sel.target = get_sel_target;
391 			if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0)
392 				print_selection(sel);
393 		}
394 	}
395 }
396