[01/02] x11grab: add followmouse option.

Message ID CAFPbVP9kO8awkjC1hDE5OpE4RA97+iVAyO5oxvadABYQQ=0t7w@mail.gmail.com
State Committed
Headers show

Commit Message

Yu-Jie Lin July 31, 2011, 4:58 a.m.
Updated the patch.

Correct my poor English and edit doc (including a few lines of current
example commands).
Removed useless code.
Add a constant "centered" for "follow_mouse".

(I apologize that I didn't notice that I should've checked To address
in Gmail when I replied.)

On Sun, Jul 31, 2011 at 01:18, Anton Khirnov <anton@khirnov.net> wrote:
> On Sun, 31 Jul 2011 00:24:00 +0800, Yu-Jie Lin <livibetter@gmail.com> wrote:
>> @@ -400,12 +422,45 @@ x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
>> +        if (follow_mouse == -1) {
>> +            // follow the mouse, put it at center of grabbing region
>> +            if (pointer_x - s->width / 2 != s->x_off)
>
> You can get rid of those two if()s completely, the line below evaluates
> to x_off += 0; when it's false, which doesn't do anything.
>
>> +                x_off += pointer_x - s->width / 2 - s->x_off;
>> +            if (pointer_y - s->height / 2 != s->y_off)
>> +                y_off += pointer_y - s->height / 2 - s->y_off;
>> +        } else {
>> +            // follow the mouse, but only move the grabbing region when mouse
>> +            // reaches within certain pixels to the edge.
>> +            if (x_off < screen_w - s->width && pointer_x > x_off + s->width - follow_mouse) {
>                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> When is this not true? Shouldn't x_off always be between 0 and
> screen_w - s->width?

I really put a lot of useless code into my patch...

>> @@ -452,6 +507,7 @@ static const AVOption options[] = {
>>      { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
>>      { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
>>      { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), FF_OPT_TYPE_INT, { 1 }, 0, 1, DEC },
>> +    { "follow_mouse", "Follow the mouse pointer.", OFFSET(follow_mouse), FF_OPT_TYPE_INT, { 0 }, -1, INT_MAX, DEC },
>
> You should elaborate on the help text here. Any program using lavf can
> set private options, so people using it might never see the ffmpeg
> manual.
>
> Note that AVOptions allow for named constants, so you can assign a
> symbolic name like 'centered' to -1. See e.g. libavcodec/flacenc.c for
> an example.

Thanks for the advices, I added "centered" and more description.

Comments

Anton Khirnov July 31, 2011, 5:30 a.m. | #1
On Sun, 31 Jul 2011 12:58:48 +0800, Yu-Jie Lin <livibetter@gmail.com> wrote:
> Updated the patch.
> 
> Correct my poor English and edit doc (including a few lines of current
> example commands).
> Removed useless code.
> Add a constant "centered" for "follow_mouse".
> 
> (I apologize that I didn't notice that I should've checked To address
> in Gmail when I replied.)
> 
> On Sun, Jul 31, 2011 at 01:18, Anton Khirnov <anton@khirnov.net> wrote:
> > On Sun, 31 Jul 2011 00:24:00 +0800, Yu-Jie Lin <livibetter@gmail.com> wrote:
> >> @@ -400,12 +422,45 @@ x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
> >> +        if (follow_mouse == -1) {
> >> +            // follow the mouse, put it at center of grabbing region
> >> +            if (pointer_x - s->width / 2 != s->x_off)
> >
> > You can get rid of those two if()s completely, the line below evaluates
> > to x_off += 0; when it's false, which doesn't do anything.
> >
> >> +                x_off += pointer_x - s->width / 2 - s->x_off;
> >> +            if (pointer_y - s->height / 2 != s->y_off)
> >> +                y_off += pointer_y - s->height / 2 - s->y_off;
> >> +        } else {
> >> +            // follow the mouse, but only move the grabbing region when mouse
> >> +            // reaches within certain pixels to the edge.
> >> +            if (x_off < screen_w - s->width && pointer_x > x_off + s->width - follow_mouse) {
> >                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > When is this not true? Shouldn't x_off always be between 0 and
> > screen_w - s->width?
> 
> I really put a lot of useless code into my patch...
> 
> >> @@ -452,6 +507,7 @@ static const AVOption options[] = {
> >>      { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
> >>      { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
> >>      { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), FF_OPT_TYPE_INT, { 1 }, 0, 1, DEC },
> >> +    { "follow_mouse", "Follow the mouse pointer.", OFFSET(follow_mouse), FF_OPT_TYPE_INT, { 0 }, -1, INT_MAX, DEC },
> >
> > You should elaborate on the help text here. Any program using lavf can
> > set private options, so people using it might never see the ffmpeg
> > manual.
> >
> > Note that AVOptions allow for named constants, so you can assign a
> > symbolic name like 'centered' to -1. See e.g. libavcodec/flacenc.c for
> > an example.
> 
> Thanks for the advices, I added "centered" and more description.
> From 99cfe170483005a9b034356a720310de4b8d9ab5 Mon Sep 17 00:00:00 2001
> From: Yu-Jie Lin <livibetter@gmail.com>
> Date: Sat, 30 Jul 2011 18:46:36 +0800
> Subject: [PATCH] x11grab: add follow_mouse AVOption.
> 
> -follow_mouse centered|PIXELS
>   move grabbing region to where mouse pointer at the center; or
>   only move when pointer reaches within PIXELS to the edge.
> 
> Signed-off-by: Yu-Jie Lin <livibetter@gmail.com>
> ---
>  doc/ffmpeg.texi       |   21 +++++++++++++---
>  doc/indevs.texi       |   22 +++++++++++++++++-
>  libavdevice/x11grab.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++--
>  3 files changed, 96 insertions(+), 8 deletions(-)
> 

Looks fine now, except for a few long lines which I'll fix myself.
I'll push later today if nobody has other comments.

Thanks for your contribution.

Patch

From 99cfe170483005a9b034356a720310de4b8d9ab5 Mon Sep 17 00:00:00 2001
From: Yu-Jie Lin <livibetter@gmail.com>
Date: Sat, 30 Jul 2011 18:46:36 +0800
Subject: [PATCH] x11grab: add follow_mouse AVOption.

-follow_mouse centered|PIXELS
  move grabbing region to where mouse pointer at the center; or
  only move when pointer reaches within PIXELS to the edge.

Signed-off-by: Yu-Jie Lin <livibetter@gmail.com>
---
 doc/ffmpeg.texi       |   21 +++++++++++++---
 doc/indevs.texi       |   22 +++++++++++++++++-
 libavdevice/x11grab.c |   61 ++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 96 insertions(+), 8 deletions(-)

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 4dca5d8..eb3bd89 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -893,15 +893,28 @@  Grab the X11 display with ffmpeg via
 ffmpeg -f x11grab -s cif -r 25 -i :0.0 /tmp/out.mpg
 @end example
 
-0.0 is display.screen number of your X11 server, same as
-the DISPLAY environment variable.
+0.0 is the display.screen number of your X11 server, same as the DISPLAY
+environment variable.
 
 @example
 ffmpeg -f x11grab -s cif -r 25 -i :0.0+10,20 /tmp/out.mpg
 @end example
 
-0.0 is display.screen number of your X11 server, same as the DISPLAY environment
-variable. 10 is the x-offset and 20 the y-offset for the grabbing.
+10 is the x-offset and 20 the y-offset for the grabbing.
+
+@example
+ffmpeg -f x11grab -follow_mouse centered -s cif -r 25 -i :0.0 /tmp/out.mpg
+@end example
+
+The grabbing region follows the mouse pointer, which stays at the center of
+region.
+
+@example
+ffmpeg -f x11grab -follow_mouse 100 -s cif -r 25 -i :0.0 /tmp/out.mpg
+@end example
+
+Only follows when mouse pointer reaches within 100 pixels to the edge of
+region.
 
 @section Video and Audio file format conversion
 
diff --git a/doc/indevs.texi b/doc/indevs.texi
index c5e04b0..aa001cd 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -248,7 +248,27 @@  For example to grab from @file{:0.0} using @file{ffmpeg}:
 ffmpeg -f x11grab -r 25 -s cif -i :0.0 out.mpg
 
 # Grab at position 10,20.
-ffmpeg -f x11grab -25 -s cif -i :0.0+10,20 out.mpg
+ffmpeg -f x11grab -r 25 -s cif -i :0.0+10,20 out.mpg
+@end example
+
+@subsection @var{follow_mouse} AVOption
+
+The syntax is:
+@example
+-follow_mouse centered|@var{PIXELS}
+@end example
+
+When it is specified with "centered", the grabbing region follows the mouse
+pointer and keeps the pointer at the center of region; otherwise, the region
+follows only when the mouse pointer reaches within @var{PIXELS} (greater than
+zero) to the edge of region.
+
+For example:
+@example
+ffmpeg -f x11grab -follow_mouse centered -r 25 -s cif -i :0.0 out.mpg
+
+# Follows only when the mouse pointer reaches within 100 pixels to edge
+ffmpeg -f x11grab -follow_mouse 100 -r 25 -s cif -i :0.0 out.mpg
 @end example
 
 @c man end INPUT DEVICES
diff --git a/libavdevice/x11grab.c b/libavdevice/x11grab.c
index 80507ab..70a64c6 100644
--- a/libavdevice/x11grab.c
+++ b/libavdevice/x11grab.c
@@ -71,6 +71,7 @@  struct x11_grab
     int use_shm;             /**< !0 when using XShm extension */
     XShmSegmentInfo shminfo; /**< When using XShm, keeps track of XShm infos */
     int  draw_mouse;         /**< Set by a private option. */
+    int  follow_mouse;       /**< Set by a private option. */
     char *framerate;         /**< Set by a private option. */
 };
 
@@ -95,6 +96,7 @@  x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
     XImage *image;
     int x_off = 0;
     int y_off = 0;
+    int screen;
     int use_shm;
     char *param, *offset;
     int ret = 0;
@@ -141,6 +143,22 @@  x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
     }
     av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
 
+    screen = DefaultScreen(dpy);
+
+    if (x11grab->follow_mouse) {
+        int screen_w, screen_h;
+        Window w;
+
+        screen_w = DisplayWidth(dpy, screen);
+        screen_h = DisplayHeight(dpy, screen);
+        XQueryPointer(dpy, RootWindow(dpy, screen), &w, &w, &x_off, &y_off, &ret, &ret, &ret);
+        x_off -= x11grab->width / 2;
+        y_off -= x11grab->height / 2;
+        x_off = FFMIN(FFMAX(x_off, 0), screen_w - x11grab->width);
+        y_off = FFMIN(FFMAX(y_off, 0), screen_h - x11grab->height);
+        av_log(s1, AV_LOG_INFO, "followmouse is enabled, resetting grabbing region to x: %d y: %d\n", x_off, y_off);
+    }
+
     use_shm = XShmQueryExtension(dpy);
     av_log(s1, AV_LOG_INFO, "shared memory extension %s found\n", use_shm ? "" : "not");
 
@@ -171,7 +189,7 @@  x11grab_read_header(AVFormatContext *s1, AVFormatParameters *ap)
             goto out;
         }
     } else {
-        image = XGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)),
+        image = XGetImage(dpy, RootWindow(dpy, screen),
                           x_off,y_off,
                           x11grab->width, x11grab->height,
                           AllPlanes, ZPixmap);
@@ -374,6 +392,10 @@  x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
     int x_off = s->x_off;
     int y_off = s->y_off;
 
+    int screen;
+    Window root;
+    int follow_mouse = s->follow_mouse;
+
     int64_t curtime, delay;
     struct timespec ts;
 
@@ -400,12 +422,43 @@  x11grab_read_packet(AVFormatContext *s1, AVPacket *pkt)
     pkt->size = s->frame_size;
     pkt->pts = curtime;
 
+    screen = DefaultScreen(dpy);
+    root = RootWindow(dpy, screen);
+    if (follow_mouse) {
+        int screen_w, screen_h;
+        int pointer_x, pointer_y, _;
+        Window w;
+
+        screen_w = DisplayWidth(dpy, screen);
+        screen_h = DisplayHeight(dpy, screen);
+        XQueryPointer(dpy, root, &w, &w, &pointer_x, &pointer_y, &_, &_, &_);
+        if (follow_mouse == -1) {
+            // follow the mouse, put it at center of grabbing region
+            x_off += pointer_x - s->width  / 2 - x_off;
+            y_off += pointer_y - s->height / 2 - y_off;
+        } else {
+            // follow the mouse, but only move the grabbing region when mouse
+            // reaches within certain pixels to the edge.
+            if (pointer_x > x_off + s->width - follow_mouse) {
+                x_off += pointer_x - (x_off + s->width - follow_mouse);
+            } else if (pointer_x < x_off + follow_mouse)
+                x_off -= (x_off + follow_mouse) - pointer_x;
+            if (pointer_y > y_off + s->height - follow_mouse) {
+                y_off += pointer_y - (y_off + s->height - follow_mouse);
+            } else if (pointer_y < y_off + follow_mouse)
+                y_off -= (y_off + follow_mouse) - pointer_y;
+        }
+        // adjust grabbing region position if it goes out of screen.
+        s->x_off = x_off = FFMIN(FFMAX(x_off, 0), screen_w - s->width);
+        s->y_off = y_off = FFMIN(FFMAX(y_off, 0), screen_h - s->height);
+    }
+
     if(s->use_shm) {
-        if (!XShmGetImage(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off, AllPlanes)) {
+        if (!XShmGetImage(dpy, root, image, x_off, y_off, AllPlanes)) {
             av_log (s1, AV_LOG_INFO, "XShmGetImage() failed\n");
         }
     } else {
-        if (!xget_zpixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)), image, x_off, y_off)) {
+        if (!xget_zpixmap(dpy, root, image, x_off, y_off)) {
             av_log (s1, AV_LOG_INFO, "XGetZPixmap() failed\n");
         }
     }
@@ -452,6 +505,8 @@  static const AVOption options[] = {
     { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(video_size), FF_OPT_TYPE_STRING, {.str = "vga"}, 0, 0, DEC },
     { "framerate", "", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "ntsc"}, 0, 0, DEC },
     { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), FF_OPT_TYPE_INT, { 1 }, 0, 1, DEC },
+    { "follow_mouse", "Move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region. Or \"centered\" can be used, the pointer is kept at the center of the region.", OFFSET(follow_mouse), FF_OPT_TYPE_INT, { 0 }, -1, INT_MAX, DEC, "follow_mouse" },
+    { "centered", "Keep the mouse pointer at the center of grabbing region when following.", 0, FF_OPT_TYPE_CONST, {.dbl = -1 }, INT_MIN, INT_MAX, DEC, "follow_mouse" },
     { NULL },
 };
 
-- 
1.7.3.4