From: Hans Verkuil Date: Mon, 24 Feb 2014 15:08:44 +0000 (+0100) Subject: v4l2-ctl: improve the overlay support X-Git-Tag: v4l-utils-1.2.0~188 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=af8f75f9b3ed7528e927558f8eb24630fb9d8fd7;p=platform%2Fupstream%2Fv4l-utils.git v4l2-ctl: improve the overlay support It is now possible to specify clip lists and a bitmap. With the --find-fb option it can find which fb device is associated with the overlay. And --set-fbuf can specify which fb device to open to fill in the framebuffer information. Dropped the old output overlay options: each video node can only be a video overlay or an output video overlay, not both at the same time. So there is no need to support both options. Signed-off-by: Hans Verkuil --- diff --git a/utils/v4l2-ctl/v4l2-ctl-overlay.cpp b/utils/v4l2-ctl/v4l2-ctl-overlay.cpp index 6b39df1..daa5e30 100644 --- a/utils/v4l2-ctl/v4l2-ctl-overlay.cpp +++ b/utils/v4l2-ctl/v4l2-ctl-overlay.cpp @@ -16,41 +16,54 @@ #include #include +#include #include #include +#include #include "v4l2-ctl.h" static unsigned int set_fbuf; static unsigned int set_overlay_fmt; -static unsigned int set_overlay_fmt_out; static struct v4l2_format overlay_fmt; /* set_format/get_format video overlay */ -static struct v4l2_format overlay_fmt_out; /* set_format/get_format video overlay output */ -static struct v4l2_framebuffer fbuf; /* fbuf */ +static struct v4l2_framebuffer fbuf; /* fbuf */ static int overlay; /* overlay */ +static const char *fb_device; +static std::vector clips; +static std::vector bitmap_rects; void overlay_usage(void) { printf("\nVideo Overlay options:\n" " --list-formats-overlay\n" " display supported overlay formats [VIDIOC_ENUM_FMT]\n" + " --find-fb find the fb device corresponding with the overlay\n" " --overlay= turn overlay on (1) or off (0) (VIDIOC_OVERLAY)\n" - " --get-fmt-overlay query the video overlay format [VIDIOC_G_FMT]\n" - " --get-fmt-output-overlay\n" - " query the video output overlay format [VIDIOC_G_FMT]\n" + " --get-fmt-overlay query the video or video output overlay format [VIDIOC_G_FMT]\n" " --set-fmt-overlay\n" - " --try-fmt-overlay\n" - " --set-fmt-output-overlay\n" - " --try-fmt-output-overlay=chromakey=,global_alpha=,\n" + " --try-fmt-overlay=chromakey=,global_alpha=,\n" " top=,left=,width=,height=,field=\n" - " set/try the video or video output overlay format\n" - " [VIDIOC_S/TRY_FMT], can be one of:\n" + " set/try the video or video output overlay format [VIDIOC_TRY/S_FMT]\n" + " can be one of:\n" " any, none, top, bottom, interlaced, seq_tb, seq_bt,\n" " alternate, interlaced_tb, interlaced_bt\n" + " If the width or height changed then the old clip list and bitmap will\n" + " be invalidated.\n" + " --clear-clips clear any old clips, to be used in combination with --try/set-fmt-overlay\n" + " --clear-bitmap clear any old bitmap, to be used in combination with --try/set-fmt-overlay\n" + " --add-clip=top=,left=,width=,height=\n" + " Add an entry to the clip list. May be used multiple times.\n" + " This clip list will be passed to --try/set-fmt-overlay\n" + " --add-bitmap=top=,left=,width=,height=\n" + " Set the bits in the given rectangle in the bitmap to 1. May be\n" + " used multiple times.\n" + " The bitmap will be passed to --try/set-fmt-overlay\n" " --get-fbuf query the overlay framebuffer data [VIDIOC_G_FBUF]\n" - " --set-fbuf=chromakey=,global_alpha=,local_alpha=,local_inv_alpha=\n" + " --set-fbuf=chromakey=,global_alpha=,local_alpha=,local_inv_alpha=,fb=\n" " set the overlay framebuffer [VIDIOC_S_FBUF]\n" - " b = 0 or 1\n" + " is 0 or 1\n" + " is the framebuffer device (/dev/fbX)\n" + " if starts with a digit, then /dev/fb is used\n" ); } @@ -104,7 +117,7 @@ static void printfbuf(const struct v4l2_framebuffer &fb) printf("\tCapability : %s", fbufcap2s(fb.capability).c_str() + 3); printf("\tFlags : %s", fbufflags2s(fb.flags).c_str() + 3); if (fb.base) - printf("\tBase : 0x%p\n", fb.base); + printf("\tBase : %p\n", fb.base); printf("\tWidth : %d\n", fb.fmt.width); printf("\tHeight : %d\n", fb.fmt.height); printf("\tPixel Format : '%s'\n", fcc2s(fb.fmt.pixelformat).c_str()); @@ -117,31 +130,144 @@ static void printfbuf(const struct v4l2_framebuffer &fb) } } +static void find_fb(int fd) +{ + struct v4l2_framebuffer fbuf; + unsigned int i; + int fb_fd; + + if (doioctl(fd, VIDIOC_G_FBUF, &fbuf)) + return; + if (fbuf.base == 0) { + printf("No framebuffer base address was defined\n"); + return; + } + + for (i = 0; i < 30; i++) { + struct fb_fix_screeninfo si; + char dev_name[16]; + + snprintf(dev_name, sizeof(dev_name), "/dev/fb%u", i); + + fb_fd = open(dev_name, O_RDWR); + if (fb_fd == -1) { + switch (errno) { + case ENOENT: /* no such file */ + case ENXIO: /* no driver */ + continue; + + default: + return; + } + } + + if (!ioctl(fb_fd, FBIOGET_FSCREENINFO, &si)) + if (si.smem_start == (unsigned long)fbuf.base) { + printf("%s is the framebuffer associated with base address %p\n", + dev_name, fbuf.base); + return; + } + close(fb_fd); + fb_fd = -1; + } + printf("No matching framebuffer found for base address %p\n", fbuf.base); +} + +struct bitfield2fmt { + unsigned red_off, red_len; + unsigned green_off, green_len; + unsigned blue_off, blue_len; + unsigned transp_off, transp_len; + __u32 pixfmt; +}; + +static const struct bitfield2fmt fb_formats[] = { + { 10, 5, 5, 5, 0, 5, 15, 1, V4L2_PIX_FMT_RGB555 }, + { 11, 5, 5, 6, 0, 5, 0, 0, V4L2_PIX_FMT_RGB565 }, + { 1, 5, 6, 5, 11, 5, 0, 1, V4L2_PIX_FMT_RGB555X }, + { 0, 5, 5, 6, 11, 5, 0, 0, V4L2_PIX_FMT_RGB565X }, + { 16, 8, 8, 8, 0, 8, 0, 0, V4L2_PIX_FMT_BGR24 }, + { 0, 8, 8, 8, 16, 8, 0, 0, V4L2_PIX_FMT_RGB24 }, + { 16, 8, 8, 8, 0, 8, 24, 8, V4L2_PIX_FMT_BGR32 }, + { 8, 8, 16, 8, 24, 8, 0, 8, V4L2_PIX_FMT_RGB32 }, + { } +}; + +static bool match_bitfield(const struct fb_bitfield &bf, unsigned off, unsigned len) +{ + if (bf.msb_right || bf.length != len) + return false; + return !len || bf.offset == off; +} + +static int fbuf_fill_from_fb(struct v4l2_framebuffer &fb, const char *fb_device) +{ + struct fb_fix_screeninfo si; + struct fb_var_screeninfo vi; + int fb_fd; + + if (fb_device == NULL) + return 0; + fb_fd = open(fb_device, O_RDWR); + if (fb_fd == -1) { + fprintf(stderr, "cannot open %s\n", fb_device); + return -1; + } + if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &si)) { + fprintf(stderr, "could not obtain fscreeninfo from %s\n", fb_device); + return -1; + } + if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vi)) { + fprintf(stderr, "could not obtain vscreeninfo from %s\n", fb_device); + return -1; + } + fb.base = (void *)si.smem_start; + fb.fmt.sizeimage = si.smem_len; + fb.fmt.width = vi.xres; + fb.fmt.height = vi.yres; + fb.fmt.bytesperline = si.line_length; + if (fb.fmt.height * fb.fmt.bytesperline > fb.fmt.sizeimage) { + fprintf(stderr, "height * bytesperline > sizeimage?!\n"); + return -1; + } + fb.fmt.pixelformat = 0; + if ((si.capabilities & FB_CAP_FOURCC) && vi.grayscale > 1) { + fb.fmt.pixelformat = vi.grayscale; + fb.fmt.colorspace = vi.colorspace; + } else { + if (vi.grayscale == 1) { + if (vi.bits_per_pixel == 8) + fb.fmt.pixelformat = V4L2_PIX_FMT_GREY; + } else { + for (int i = 0; fb_formats[i].pixfmt; i++) { + const struct bitfield2fmt &p = fb_formats[i]; + + if (match_bitfield(vi.blue, p.blue_off, p.blue_len) && + match_bitfield(vi.green, p.green_off, p.green_len) && + match_bitfield(vi.red, p.red_off, p.red_len) && + match_bitfield(vi.transp, p.transp_off, p.transp_len)) { + fb.fmt.pixelformat = p.pixfmt; + break; + } + } + } + fb.fmt.colorspace = V4L2_COLORSPACE_SRGB; + } + printfbuf(fb); + close(fb_fd); + return 0; +} + void overlay_cmd(int ch, char *optarg) { - unsigned int *set_overlay_fmt_ptr = NULL; - struct v4l2_format *overlay_fmt_ptr = NULL; + struct v4l2_rect r; char *value, *subs; switch (ch) { case OptSetOverlayFormat: case OptTryOverlayFormat: - case OptSetOutputOverlayFormat: - case OptTryOutputOverlayFormat: - switch (ch) { - case OptSetOverlayFormat: - case OptTryOverlayFormat: - set_overlay_fmt_ptr = &set_overlay_fmt; - overlay_fmt_ptr = &overlay_fmt; - break; - case OptSetOutputOverlayFormat: - case OptTryOutputOverlayFormat: - set_overlay_fmt_ptr = &set_overlay_fmt_out; - overlay_fmt_ptr = &overlay_fmt_out; - break; - } subs = optarg; - while (*subs != '\0') { + while (subs && *subs != '\0') { static const char *const subopts[] = { "chromakey", "global_alpha", @@ -155,32 +281,32 @@ void overlay_cmd(int ch, char *optarg) switch (parse_subopt(&subs, subopts, &value)) { case 0: - overlay_fmt_ptr->fmt.win.chromakey = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtChromaKey; + overlay_fmt.fmt.win.chromakey = strtoul(value, 0L, 0); + set_overlay_fmt |= FmtChromaKey; break; case 1: - overlay_fmt_ptr->fmt.win.global_alpha = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtGlobalAlpha; + overlay_fmt.fmt.win.global_alpha = strtoul(value, 0L, 0); + set_overlay_fmt |= FmtGlobalAlpha; break; case 2: - overlay_fmt_ptr->fmt.win.w.left = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtLeft; + overlay_fmt.fmt.win.w.left = strtol(value, 0L, 0); + set_overlay_fmt |= FmtLeft; break; case 3: - overlay_fmt_ptr->fmt.win.w.top = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtTop; + overlay_fmt.fmt.win.w.top = strtol(value, 0L, 0); + set_overlay_fmt |= FmtTop; break; case 4: - overlay_fmt_ptr->fmt.win.w.width = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtWidth; + overlay_fmt.fmt.win.w.width = strtoul(value, 0L, 0); + set_overlay_fmt |= FmtWidth; break; case 5: - overlay_fmt_ptr->fmt.win.w.height = strtol(value, 0L, 0); - *set_overlay_fmt_ptr |= FmtHeight; + overlay_fmt.fmt.win.w.height = strtoul(value, 0L, 0); + set_overlay_fmt |= FmtHeight; break; case 6: - overlay_fmt_ptr->fmt.win.field = parse_field(value); - *set_overlay_fmt_ptr |= FmtField; + overlay_fmt.fmt.win.field = parse_field(value); + set_overlay_fmt |= FmtField; break; default: overlay_usage(); @@ -188,6 +314,51 @@ void overlay_cmd(int ch, char *optarg) } } break; + case OptAddClip: + case OptAddBitmap: + subs = optarg; + memset(&r, 0, sizeof(r)); + while (*subs != '\0') { + static const char *const subopts[] = { + "left", + "top", + "width", + "height", + NULL + }; + + switch (parse_subopt(&subs, subopts, &value)) { + case 0: + r.left = strtoul(value, 0L, 0); + break; + case 1: + r.top = strtoul(value, 0L, 0); + break; + case 2: + r.width = strtoul(value, 0L, 0); + break; + case 3: + r.height = strtoul(value, 0L, 0); + break; + default: + overlay_usage(); + return; + } + } + if (r.width == 0 || r.height == 0) { + overlay_usage(); + return; + } + if (ch == OptAddBitmap) { + bitmap_rects.push_back(r); + } else { + struct v4l2_clip c; + + c.c = r; + c.next = NULL; + clips.push_back(c); + } + break; case OptSetFBuf: subs = optarg; while (*subs != '\0') { @@ -196,6 +367,7 @@ void overlay_cmd(int ch, char *optarg) "global_alpha", "local_alpha", "local_inv_alpha", + "fb", NULL }; @@ -216,6 +388,15 @@ void overlay_cmd(int ch, char *optarg) fbuf.flags |= strtol(value, 0L, 0) ? V4L2_FBUF_FLAG_LOCAL_INV_ALPHA : 0; set_fbuf |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; break; + case 4: + fb_device = value; + if (fb_device[0] >= '0' && fb_device[0] <= '9' && strlen(fb_device) <= 3) { + static char newdev[20]; + + sprintf(newdev, "/dev/fb%s", fb_device); + fb_device = newdev; + } + break; default: overlay_usage(); break; @@ -228,64 +409,103 @@ void overlay_cmd(int ch, char *optarg) } } -void overlay_set(int fd) +static void do_try_set_overlay(struct v4l2_format &fmt, int fd) { + struct v4l2_window &win = fmt.fmt.win; + bool keep_old_clip = true; + bool keep_old_bitmap = true; + struct v4l2_clip *cliplist = NULL; + unsigned stride = (win.w.width + 7) / 8; + unsigned char *bitmap = NULL; int ret; - if (options[OptSetOverlayFormat] || options[OptTryOverlayFormat]) { - struct v4l2_format fmt; + if (((set_overlay_fmt & FmtWidth) && win.w.width != overlay_fmt.fmt.win.w.width) || + ((set_overlay_fmt & FmtHeight) && win.w.height != overlay_fmt.fmt.win.w.height)) + keep_old_bitmap = keep_old_clip = false; + if (options[OptClearBitmap] || bitmap_rects.size()) + keep_old_bitmap = false; + if (options[OptClearClips] || clips.size()) + keep_old_clip = false; - fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; - if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) { - if (set_overlay_fmt & FmtChromaKey) - fmt.fmt.win.chromakey = overlay_fmt.fmt.win.chromakey; - if (set_overlay_fmt & FmtGlobalAlpha) - fmt.fmt.win.global_alpha = overlay_fmt.fmt.win.global_alpha; - if (set_overlay_fmt & FmtLeft) - fmt.fmt.win.w.left = overlay_fmt.fmt.win.w.left; - if (set_overlay_fmt & FmtTop) - fmt.fmt.win.w.top = overlay_fmt.fmt.win.w.top; - if (set_overlay_fmt & FmtWidth) - fmt.fmt.win.w.width = overlay_fmt.fmt.win.w.width; - if (set_overlay_fmt & FmtHeight) - fmt.fmt.win.w.height = overlay_fmt.fmt.win.w.height; - if (set_overlay_fmt & FmtField) - fmt.fmt.win.field = overlay_fmt.fmt.win.field; - if (options[OptSetOverlayFormat]) - ret = doioctl(fd, VIDIOC_S_FMT, &fmt); - else - ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt); - if (ret == 0 && (verbose || options[OptTryOverlayFormat])) - printfmt(fmt); + win.bitmap = NULL; + if (keep_old_bitmap) { + bitmap = (unsigned char *)calloc(1, stride * win.w.height); + win.bitmap = bitmap; + } + if (keep_old_clip) { + if (win.clipcount) + cliplist = (struct v4l2_clip *)malloc(win.clipcount * sizeof(*cliplist)); + win.clips = cliplist; + } + if (keep_old_clip || keep_old_bitmap) + if (doioctl(fd, VIDIOC_G_FMT, &fmt)) + goto free; + + if (set_overlay_fmt & FmtChromaKey) + win.chromakey = overlay_fmt.fmt.win.chromakey; + if (set_overlay_fmt & FmtGlobalAlpha) + win.global_alpha = overlay_fmt.fmt.win.global_alpha; + if (set_overlay_fmt & FmtLeft) + win.w.left = overlay_fmt.fmt.win.w.left; + if (set_overlay_fmt & FmtTop) + win.w.top = overlay_fmt.fmt.win.w.top; + if (set_overlay_fmt & FmtWidth) + win.w.width = overlay_fmt.fmt.win.w.width; + if (set_overlay_fmt & FmtHeight) + win.w.height = overlay_fmt.fmt.win.w.height; + if (set_overlay_fmt & FmtField) + win.field = overlay_fmt.fmt.win.field; + if (clips.size()) { + win.clipcount = clips.size(); + win.clips = &clips[0]; + } + if (bitmap_rects.size()) { + free(bitmap); + stride = (win.w.width + 7) / 8; + bitmap = (unsigned char *)calloc(1, stride * win.w.height); + win.bitmap = bitmap; + for (unsigned i = 0; i < bitmap_rects.size(); i++) { + const v4l2_rect &r = bitmap_rects[i]; + + if (r.left + r.width > win.w.width || + r.top + r.height > win.w.height) { + fprintf(stderr, "rectangle is out of range\n"); + return; + } + for (unsigned y = r.top; y < r.top + r.height; y++) + for (unsigned x = r.left; x < r.left + r.width; x++) + bitmap[y * stride + x / 8] |= 1 << (x & 7); } + win.bitmap = bitmap; } + if (options[OptSetOverlayFormat]) + ret = doioctl(fd, VIDIOC_S_FMT, &fmt); + else + ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt); + if (ret == 0 && (verbose || options[OptTryOverlayFormat])) + printfmt(fmt); + +free: + if (bitmap) + free(bitmap); + if (cliplist) + free(cliplist); +} - if (options[OptSetOutputOverlayFormat] || options[OptTryOutputOverlayFormat]) { +void overlay_set(int fd) +{ + if ((options[OptSetOverlayFormat] || options[OptTryOverlayFormat]) && + (set_overlay_fmt || bitmap_rects.size() || clips.size())) { struct v4l2_format fmt; - fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; - if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) { - if (set_overlay_fmt_out & FmtChromaKey) - fmt.fmt.win.chromakey = overlay_fmt_out.fmt.win.chromakey; - if (set_overlay_fmt_out & FmtGlobalAlpha) - fmt.fmt.win.global_alpha = overlay_fmt_out.fmt.win.global_alpha; - if (set_overlay_fmt_out & FmtLeft) - fmt.fmt.win.w.left = overlay_fmt_out.fmt.win.w.left; - if (set_overlay_fmt_out & FmtTop) - fmt.fmt.win.w.top = overlay_fmt_out.fmt.win.w.top; - if (set_overlay_fmt_out & FmtWidth) - fmt.fmt.win.w.width = overlay_fmt_out.fmt.win.w.width; - if (set_overlay_fmt_out & FmtHeight) - fmt.fmt.win.w.height = overlay_fmt_out.fmt.win.w.height; - if (set_overlay_fmt_out & FmtField) - fmt.fmt.win.field = overlay_fmt_out.fmt.win.field; - if (options[OptSetOutputOverlayFormat]) - ret = doioctl(fd, VIDIOC_S_FMT, &fmt); - else - ret = doioctl(fd, VIDIOC_TRY_FMT, &fmt); - if (ret == 0 && (verbose || options[OptTryOutputOverlayFormat])) - printfmt(fmt); - } + memset(&fmt, 0, sizeof(fmt)); + // You can never have both VIDEO_OVERLAY and VIDEO_OUTPUT_OVERLAY + if (capabilities & V4L2_CAP_VIDEO_OVERLAY) + fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + else + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; + if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) + do_try_set_overlay(fmt, fd); } if (options[OptSetFBuf]) { @@ -294,7 +514,8 @@ void overlay_set(int fd) if (doioctl(fd, VIDIOC_G_FBUF, &fb) == 0) { fb.flags &= ~set_fbuf; fb.flags |= fbuf.flags; - doioctl(fd, VIDIOC_S_FBUF, &fb); + if (!fbuf_fill_from_fb(fb, fb_device)) + doioctl(fd, VIDIOC_S_FBUF, &fb); } } @@ -307,18 +528,28 @@ void overlay_get(int fd) { if (options[OptGetOverlayFormat]) { struct v4l2_format fmt; + unsigned char *bitmap = NULL; - fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; - if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) - printfmt(fmt); - } - - if (options[OptGetOutputOverlayFormat]) { - struct v4l2_format fmt; + memset(&fmt, 0, sizeof(fmt)); + // You can never have both VIDEO_OVERLAY and VIDEO_OUTPUT_OVERLAY + if (capabilities & V4L2_CAP_VIDEO_OVERLAY) + fmt.type = V4L2_BUF_TYPE_VIDEO_OVERLAY; + else + fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; + if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) { + unsigned stride = (fmt.fmt.win.w.width + 7) / 8; - fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY; - if (doioctl(fd, VIDIOC_G_FMT, &fmt) == 0) + if (fmt.fmt.win.clipcount) + fmt.fmt.win.clips = (struct v4l2_clip *)malloc(fmt.fmt.win.clipcount * sizeof(clips[0])); + bitmap = (unsigned char *)calloc(1, stride * fmt.fmt.win.w.height); + fmt.fmt.win.bitmap = bitmap; + doioctl(fd, VIDIOC_G_FMT, &fmt); printfmt(fmt); + if (fmt.fmt.win.clips) + free(fmt.fmt.win.clips); + if (bitmap) + free(bitmap); + } } if (options[OptGetFBuf]) { @@ -334,4 +565,6 @@ void overlay_list(int fd) printf("ioctl: VIDIOC_ENUM_FMT\n"); print_video_formats(fd, V4L2_BUF_TYPE_VIDEO_OVERLAY); } + if (options[OptFindFb]) + find_fb(fd); } diff --git a/utils/v4l2-ctl/v4l2-ctl.cpp b/utils/v4l2-ctl/v4l2-ctl.cpp index cbc9e52..41930d2 100644 --- a/utils/v4l2-ctl/v4l2-ctl.cpp +++ b/utils/v4l2-ctl/v4l2-ctl.cpp @@ -111,6 +111,11 @@ static struct option long_options[] = { {"list-formats-overlay", no_argument, 0, OptListOverlayFormats}, {"list-formats-out", no_argument, 0, OptListOutFormats}, {"list-fields-out", no_argument, 0, OptListOutFields}, + {"clear-clips", no_argument, 0, OptClearClips}, + {"clear-bitmap", no_argument, 0, OptClearBitmap}, + {"add-clip", required_argument, 0, OptAddClip}, + {"add-bitmap", required_argument, 0, OptAddBitmap}, + {"find-fb", no_argument, 0, OptFindFb}, {"get-standard", no_argument, 0, OptGetStandard}, {"set-standard", required_argument, 0, OptSetStandard}, {"get-detected-standard", no_argument, 0, OptQueryStandard}, @@ -130,11 +135,8 @@ static struct option long_options[] = { {"verbose", no_argument, 0, OptVerbose}, {"log-status", no_argument, 0, OptLogStatus}, {"get-fmt-overlay", no_argument, 0, OptGetOverlayFormat}, - {"set-fmt-overlay", required_argument, 0, OptSetOverlayFormat}, - {"try-fmt-overlay", required_argument, 0, OptTryOverlayFormat}, - {"get-fmt-output-overlay", no_argument, 0, OptGetOutputOverlayFormat}, - {"set-fmt-output-overlay", required_argument, 0, OptSetOutputOverlayFormat}, - {"try-fmt-output-overlay", required_argument, 0, OptTryOutputOverlayFormat}, + {"set-fmt-overlay", optional_argument, 0, OptSetOverlayFormat}, + {"try-fmt-overlay", optional_argument, 0, OptTryOverlayFormat}, {"get-fmt-sliced-vbi", no_argument, 0, OptGetSlicedVbiFormat}, {"set-fmt-sliced-vbi", required_argument, 0, OptSetSlicedVbiFormat}, {"try-fmt-sliced-vbi", required_argument, 0, OptTrySlicedVbiFormat}, @@ -430,7 +432,26 @@ void printfmt(const struct v4l2_format &vfmt) printf("\tChroma Key : 0x%08x\n", vfmt.fmt.win.chromakey); printf("\tGlobal Alpha: 0x%02x\n", vfmt.fmt.win.global_alpha); printf("\tClip Count : %u\n", vfmt.fmt.win.clipcount); - printf("\tClip Bitmap : %s\n", vfmt.fmt.win.bitmap ? "Yes" : "No"); + if (vfmt.fmt.win.clips) + for (unsigned i = 0; i < vfmt.fmt.win.clipcount; i++) { + struct v4l2_rect &r = vfmt.fmt.win.clips[i].c; + + printf("\t\tClip %2d: %ux%u@%ux%u\n", i, + r.width, r.height, r.left, r.top); + } + printf("\tClip Bitmap : %s", vfmt.fmt.win.bitmap ? "Yes, " : "No\n"); + if (vfmt.fmt.win.bitmap) { + unsigned char *bitmap = (unsigned char *)vfmt.fmt.win.bitmap; + unsigned stride = (vfmt.fmt.win.w.width + 7) / 8; + unsigned cnt = 0; + + for (unsigned y = 0; y < vfmt.fmt.win.w.height; y++) + for (unsigned x = 0; x < vfmt.fmt.win.w.width; x++) + if (bitmap[y * stride + x / 8] & (1 << (x & 7))) + cnt++; + printf("%u bits of %u are set\n", cnt, + vfmt.fmt.win.w.width * vfmt.fmt.win.w.height); + } break; case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: @@ -1001,7 +1022,6 @@ int main(int argc, char **argv) options[OptGetTuner] = 1; options[OptGetModulator] = 1; options[OptGetOverlayFormat] = 1; - options[OptGetOutputOverlayFormat] = 1; options[OptGetVbiFormat] = 1; options[OptGetVbiOutFormat] = 1; options[OptGetSlicedVbiFormat] = 1; diff --git a/utils/v4l2-ctl/v4l2-ctl.h b/utils/v4l2-ctl/v4l2-ctl.h index ea983c9..fec9b50 100644 --- a/utils/v4l2-ctl/v4l2-ctl.h +++ b/utils/v4l2-ctl/v4l2-ctl.h @@ -40,12 +40,10 @@ enum Option { OptGetSlicedVbiOutFormat = 128, OptGetOverlayFormat, - OptGetOutputOverlayFormat, OptGetVbiFormat, OptGetVbiOutFormat, OptGetVideoOutFormat, OptSetSlicedVbiOutFormat, - OptSetOutputOverlayFormat, OptSetOverlayFormat, //OptSetVbiFormat, TODO //OptSetVbiOutFormat, TODO @@ -54,7 +52,6 @@ enum Option { OptTrySlicedVbiOutFormat, OptTrySlicedVbiFormat, OptTryVideoFormat, - OptTryOutputOverlayFormat, OptTryOverlayFormat, //OptTryVbiFormat, TODO //OptTryVbiOutFormat, TODO @@ -68,6 +65,11 @@ enum Option { OptListOverlayFormats, OptListOutFormats, OptListOutFields, + OptClearClips, + OptClearBitmap, + OptAddClip, + OptAddBitmap, + OptFindFb, OptLogStatus, OptVerbose, OptSilent,