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