This patch adds following commands for the selection API ioctls: --get-selection, --set-selection, --get-selection-output, --set-selection-output. All supported selection rectangles at a video node are now also displayed in case of --all command. Signed-off-by: Sylwester Nawrocki <sylvester.nawrocki@xxxxxxxxx> --- utils/v4l2-ctl/v4l2-ctl.cpp | 239 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 239 insertions(+), 0 deletions(-) diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp index 1a6c4ae..c70e88c 100644 --- a/utils/v4l2-ctl/v4l2-ctl.cpp +++ b/utils/v4l2-ctl/v4l2-ctl.cpp @@ -139,6 +139,10 @@ enum Option { OptSetOverlayCrop, OptGetOutputOverlayCrop, OptSetOutputOverlayCrop, + OptGetSelection, + OptSetSelection, + OptGetOutputSelection, + OptSetOutputSelection, OptGetAudioInput, OptSetAudioInput, OptGetAudioOutput, @@ -233,6 +237,13 @@ static const flag_def service_def[] = { #define CropLeft (1L<<2) #define CropTop (1L<<3) +/* selection specified */ +#define SelectionWidth (1L<<0) +#define SelectionHeight (1L<<1) +#define SelectionLeft (1L<<2) +#define SelectionTop (1L<<3) +#define SelectionFlags (1L<<4) + static struct option long_options[] = { {"list-audio-inputs", no_argument, 0, OptListAudioInputs}, {"list-audio-outputs", no_argument, 0, OptListAudioOutputs}, @@ -322,6 +333,10 @@ static struct option long_options[] = { {"get-cropcap-output-overlay", no_argument, 0, OptGetOutputOverlayCropCap}, {"get-crop-output-overlay", no_argument, 0, OptGetOutputOverlayCrop}, {"set-crop-output-overlay", required_argument, 0, OptSetOutputOverlayCrop}, + {"get-selection", required_argument, 0, OptGetSelection}, + {"set-selection", required_argument, 0, OptSetSelection}, + {"get-selection-output", required_argument, 0, OptGetOutputSelection}, + {"set-selection-output", required_argument, 0, OptSetOutputSelection}, {"get-jpeg-comp", no_argument, 0, OptGetJpegComp}, {"set-jpeg-comp", required_argument, 0, OptSetJpegComp}, {"get-modulator", no_argument, 0, OptGetModulator}, @@ -631,6 +646,26 @@ static void usage_crop(void) ); } +static void usage_selection(void) +{ + printf("\nSelection options:\n" + " --get-selection=target=<target>\n" + " query the video capture selection rectangle [VIDIOC_G_SELECTION]\n" + " See --set-selection command for the valid <target> values.\n" + " --set-selection=target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>\n" + " set the video capture selection rectangle [VIDIOC_S_SELECTION]\n" + " target=crop|crop_bounds|crop_default|compose|compose_bounds|\n" + " compose_default|compose_padded\n" + " flags=le|ge\n" + " --get-selection-output=target=<target>\n" + " query the video output selection rectangle [VIDIOC_G_SELECTION]\n" + " See --set-selection command for the valid <target> values.\n" + " --set-selection-output=target=<target>,flags=<flags>,top=<x>,left=<y>,width=<w>,height=<h>\n" + " set the video output selection rectangle [VIDIOC_S_SELECTION]\n" + " See --set-selection command for the arguments.\n" + ); +} + static void usage_misc(void) { printf("\nMiscellaneous options:\n" @@ -688,6 +723,7 @@ static void usage(void) usage_vidout(); usage_overlay(); usage_vbi(); + usage_selection(); usage_crop(); usage_misc(); } @@ -1267,6 +1303,35 @@ static void printcropcap(const struct v4l2_cropcap &cropcap) printf("\tPixel Aspect: %u/%u\n", cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); } +static const flag_def selection_targets_def[] = { + { V4L2_SEL_TGT_CROP_ACTIVE, "crop" }, + { V4L2_SEL_TGT_CROP_DEFAULT, "crop_default" }, + { V4L2_SEL_TGT_CROP_BOUNDS, "crop_bounds" }, + { V4L2_SEL_TGT_COMPOSE_ACTIVE, "compose" }, + { V4L2_SEL_TGT_COMPOSE_DEFAULT, "compose_default" }, + { V4L2_SEL_TGT_COMPOSE_BOUNDS, "compose_bounds" }, + { V4L2_SEL_TGT_COMPOSE_PADDED, "compose_padded" }, + { 0, NULL } +}; + +static std::string seltarget2s(__u32 target) +{ + int i = 0; + + while (selection_targets_def[i++].str != NULL) { + if (selection_targets_def[i].flag == target) + return selection_targets_def[i].str; + } + return "Unknown"; +} + +static void print_selection(const struct v4l2_selection &sel) +{ + printf("Selection: %s, Left %d, Top %d, Width %d, Height %d\n", + seltarget2s(sel.target).c_str(), + sel.r.left, sel.r.top, sel.r.width, sel.r.height); +} + static void printfmt(const struct v4l2_format &vfmt) { const flag_def vbi_def[] = { @@ -2008,6 +2073,103 @@ static void parse_crop(char *optarg, unsigned int &set_crop, v4l2_rect &vcrop) } } +static void do_selection(int fd, unsigned int set_selection, struct v4l2_selection &vsel, + v4l2_buf_type type) +{ + struct v4l2_selection in_selection; + + in_selection.type = type; + in_selection.target = vsel.target; + + if (doioctl(fd, VIDIOC_G_SELECTION, &in_selection) == 0) { + if (set_selection & SelectionWidth) + in_selection.r.width = vsel.r.width; + if (set_selection & SelectionHeight) + in_selection.r.height = vsel.r.height; + if (set_selection & SelectionLeft) + in_selection.r.left = vsel.r.left; + if (set_selection & SelectionTop) + in_selection.r.top = vsel.r.top; + in_selection.flags = (set_selection & SelectionFlags) ? vsel.flags : 0; + doioctl(fd, VIDIOC_S_SELECTION, &in_selection); + } +} + +static int parse_selection_target(const char *s, unsigned int &target) +{ + if (!strcmp(s, "crop")) target = V4L2_SEL_TGT_CROP_ACTIVE; + else if (!strcmp(s, "crop_default")) target = V4L2_SEL_TGT_CROP_DEFAULT; + else if (!strcmp(s, "crop_bounds")) target = V4L2_SEL_TGT_CROP_BOUNDS; + else if (!strcmp(s, "compose")) target = V4L2_SEL_TGT_COMPOSE_ACTIVE; + else if (!strcmp(s, "compose_default")) target = V4L2_SEL_TGT_COMPOSE_DEFAULT; + else if (!strcmp(s, "compose_bounds")) target = V4L2_SEL_TGT_COMPOSE_BOUNDS; + else if (!strcmp(s, "compose_padded")) target = V4L2_SEL_TGT_COMPOSE_PADDED; + else return -EINVAL; + + return 0; +} + +static int parse_selection_flags(const char *s) +{ + if (!strcmp(s, "le")) return V4L2_SEL_FLAG_LE; + if (!strcmp(s, "ge")) return V4L2_SEL_FLAG_GE; + return 0; +} + +static int parse_selection(char *optarg, unsigned int &set_sel, v4l2_selection &vsel) +{ + char *value; + char *subs = optarg; + + while (*subs != '\0') { + static const char *const subopts[] = { + "target", + "flags", + "left", + "top", + "width", + "height", + NULL + }; + + switch (parse_subopt(&subs, subopts, &value)) { + case 0: + if (parse_selection_target(value, vsel.target)) { + fprintf(stderr, "Unknown selection target\n"); + usage_selection(); + exit(1); + } + break; + case 1: + vsel.flags = parse_selection_flags(value); + set_sel |= SelectionFlags; + break; + case 2: + vsel.r.left = strtol(value, 0L, 0); + set_sel |= SelectionLeft; + break; + case 3: + vsel.r.top = strtol(value, 0L, 0); + set_sel |= SelectionTop; + break; + case 4: + vsel.r.width = strtol(value, 0L, 0); + set_sel |= SelectionWidth; + break; + case 5: + vsel.r.height = strtol(value, 0L, 0); + set_sel |= SelectionHeight; + break; + default: + fprintf(stderr, "Unknown option\n"); + usage_selection(); + exit(1); + } + } + + return 0; +} + static void parse_freq_seek(char *optarg, struct v4l2_hw_freq_seek &seek) { char *value; @@ -2323,6 +2485,9 @@ int main(int argc, char **argv) unsigned int set_crop_out = 0; unsigned int set_crop_overlay = 0; unsigned int set_crop_out_overlay = 0; + unsigned int set_selection = 0; + unsigned int set_selection_out = 0; + int get_sel_target = 0; unsigned int set_fbuf = 0; unsigned int set_overlay_fmt = 0; unsigned int set_overlay_fmt_out = 0; @@ -2353,6 +2518,8 @@ int main(int argc, char **argv) struct v4l2_rect vcrop_out; /* crop rect */ struct v4l2_rect vcrop_overlay; /* crop rect */ struct v4l2_rect vcrop_out_overlay; /* crop rect */ + struct v4l2_selection vselection; /* capture selection */ + struct v4l2_selection vselection_out; /* output selection */ struct v4l2_framebuffer fbuf; /* fbuf */ struct v4l2_jpegcompression jpegcomp; /* jpeg compression */ struct v4l2_streamparm parm; /* get/set parm */ @@ -2409,6 +2576,8 @@ int main(int argc, char **argv) memset(&vcrop_out, 0, sizeof(vcrop_out)); memset(&vcrop_overlay, 0, sizeof(vcrop_overlay)); memset(&vcrop_out_overlay, 0, sizeof(vcrop_out_overlay)); + memset(&vselection, 0, sizeof(vselection)); + memset(&vselection_out, 0, sizeof(vselection_out)); memset(&vf, 0, sizeof(vf)); memset(&vs, 0, sizeof(vs)); memset(&fbuf, 0, sizeof(fbuf)); @@ -2694,6 +2863,25 @@ int main(int argc, char **argv) case OptSetOutputOverlayCrop: parse_crop(optarg, set_crop_out_overlay, vcrop_out_overlay); break; + case OptSetSelection: + parse_selection(optarg, set_selection, vselection); + break; + case OptSetOutputSelection: + parse_selection(optarg, set_selection_out, vselection_out); + break; + case OptGetOutputSelection: + case OptGetSelection: { + struct v4l2_selection gsel; + unsigned int get_sel; + + if (parse_selection(optarg, get_sel, gsel)) { + fprintf(stderr, "Unknown selection target\n"); + usage_selection(); + exit(1); + } + get_sel_target = gsel.target; + break; + } case OptSetInput: input = strtol(optarg, 0L, 0); break; @@ -3097,6 +3285,9 @@ int main(int argc, char **argv) options[OptGetDvTimings] = 1; options[OptGetDvTimingsCap] = 1; options[OptGetPriority] = 1; + options[OptGetSelection] = 1; + options[OptGetOutputSelection] = 1; + get_sel_target = -1; options[OptSilent] = 1; } @@ -3489,6 +3680,14 @@ int main(int argc, char **argv) do_crop(fd, set_crop_out_overlay, vcrop_out_overlay, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY); } + if (options[OptSetSelection]) { + do_selection(fd, set_selection, vselection, V4L2_BUF_TYPE_VIDEO_CAPTURE); + } + + if (options[OptSetOutputSelection]) { + do_selection(fd, set_selection_out, vselection_out, V4L2_BUF_TYPE_VIDEO_OUTPUT); + } + if (options[OptSetCtrl] && !set_ctrls.empty()) { struct v4l2_ext_controls ctrls; class2ctrls_map class2ctrls; @@ -3720,6 +3919,46 @@ int main(int argc, char **argv) printcrop(crop); } + if (options[OptGetSelection]) { + struct v4l2_selection sel; + int t = 0; + + memset(&sel, 0, sizeof(sel)); + sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (get_sel_target == -1) { + while (selection_targets_def[t++].str != NULL) { + sel.target = selection_targets_def[t].flag; + if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0) + print_selection(sel); + } + } else { + sel.target = get_sel_target; + if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0) + print_selection(sel); + } + } + + if (options[OptGetOutputSelection]) { + struct v4l2_selection sel; + int t = 0; + + memset(&sel, 0, sizeof(sel)); + sel.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + + if (get_sel_target == -1) { + while (selection_targets_def[t++].str != NULL) { + sel.target = selection_targets_def[t].flag; + if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0) + print_selection(sel); + } + } else { + sel.target = get_sel_target; + if (doioctl(fd, VIDIOC_G_SELECTION, &sel) == 0) + print_selection(sel); + } + } + if (options[OptGetInput]) { if (doioctl(fd, VIDIOC_G_INPUT, &input) == 0) { printf("Video input : %d", input); -- 1.7.4.1 -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html