v4l2-ctl: improve the overlay support
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 24 Feb 2014 15:08:44 +0000 (16:08 +0100)
committerHans Verkuil <hans.verkuil@cisco.com>
Mon, 24 Feb 2014 15:41:02 +0000 (16:41 +0100)
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 <hans.verkuil@cisco.com>
utils/v4l2-ctl/v4l2-ctl-overlay.cpp
utils/v4l2-ctl/v4l2-ctl.cpp
utils/v4l2-ctl/v4l2-ctl.h

index 6b39df1..daa5e30 100644 (file)
 #include <config.h>
 
 #include <linux/videodev2.h>
+#include <linux/fb.h>
 #include <libv4l2.h>
 #include <string>
+#include <vector>
 
 #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<struct v4l2_clip> clips;
+static std::vector<struct v4l2_rect> 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=<on>     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=<key>,global_alpha=<alpha>,\n"
+              "  --try-fmt-overlay=chromakey=<key>,global_alpha=<alpha>,\n"
               "                           top=<t>,left=<l>,width=<w>,height=<h>,field=<f>\n"
-              "                     set/try the video or video output overlay format\n"
-              "                     [VIDIOC_S/TRY_FMT], <f> can be one of:\n"
+              "                     set/try the video or video output overlay format [VIDIOC_TRY/S_FMT]\n"
+              "                     <f> 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=<t>,left=<l>,width=<w>,height=<h>\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=<t>,left=<l>,width=<w>,height=<h>\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=<b>,global_alpha=<b>,local_alpha=<b>,local_inv_alpha=<b>\n"
+              "  --set-fbuf=chromakey=<b>,global_alpha=<b>,local_alpha=<b>,local_inv_alpha=<b>,fb=<fb>\n"
               "                     set the overlay framebuffer [VIDIOC_S_FBUF]\n"
-              "                     b = 0 or 1\n"
+              "                     <b> is 0 or 1\n"
+              "                     <fb> is the framebuffer device (/dev/fbX)\n"
+              "                     if <fb> starts with a digit, then /dev/fb<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);
 }
index cbc9e52..41930d2 100644 (file)
@@ -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;
index ea983c9..fec9b50 100644 (file)
@@ -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,