diff mbox

[FFmpeg-devel,v3,1/1] avdevice/gdigrab: Add use_captureblt option for disable or use CAPTUREBLT flag, when useing the bitblt function with CAPTUREBLT it caused the mouse cursor flicker. most time we don't need this flag to capture window

Message ID HK2PR03MB4596B2A4FF488FC645340D00C6270@HK2PR03MB4596.apcprd03.prod.outlook.com
State New
Headers show

Commit Message

fgodtdev@hotmail.com Dec. 30, 2019, 8:31 a.m. UTC
From: FgoDt <fgodtdev@hotmail.com>

Signed-off-by: fgodt <fgodtdev@hotmail.com>
---
 doc/indevs.texi       |  6 ++++++
 libavdevice/gdigrab.c | 10 +++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

Comments

Marton Balint Dec. 30, 2019, 11:31 a.m. UTC | #1
On Mon, 30 Dec 2019, fgodtdev@hotmail.com wrote:

> From: FgoDt <fgodtdev@hotmail.com>

The commit description should go here, not in the commit title.

>
> Signed-off-by: fgodt <fgodtdev@hotmail.com>
> ---
> doc/indevs.texi       |  6 ++++++
> libavdevice/gdigrab.c | 10 +++++++++-
> 2 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/doc/indevs.texi b/doc/indevs.texi
> index 92bc65be41..43b0bd0465 100644
> --- a/doc/indevs.texi
> +++ b/doc/indevs.texi
> @@ -748,6 +748,12 @@ When capturing a region with @var{video_size}, set the distance from the top edg
> 
> Note that the offset calculation is from the top left corner of the primary monitor on Windows. If you have a monitor positioned above your primary monitor, you will need to use a negative @var{offset_y} value to move the region to that monitor.
> 
> +@item use_captureblt
> +When use gdigrab to capture window or desktop, the mouse cursor will flicker.

Why? Does this happen with every windows version? This does not seem like 
the right fix. In fact, I dont't see how this can work, because mouse is 
drawn upon the captured video "manually" in paint_mouse_pointer. Could you 
dig deeper what is the main cause of the issue?

> +Disable CAPTUREBLT FLAG by set value @code{0} to fix cursor flickering. Default value is @code{1}
> +

Doesn't this change what is captured when the user captures a single 
window and something is dragged on top? That alone might be a useful 
addition, but the documentation as is would be totally misleading.

> +Note the value @code{1} is essential to capture specific  window
> +
> @end table
> 
> @section iec61883
> diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c
> index f4444406fa..658719e929 100644
> --- a/libavdevice/gdigrab.c
> +++ b/libavdevice/gdigrab.c
> @@ -53,6 +53,8 @@ struct gdigrab {
>     int        offset_x;    /**< Capture x offset (private option) */
>     int        offset_y;    /**< Capture y offset (private option) */
> 
> +    int        use_captureblt; /**< Capture gdi window with CAPTUREBLT flag (private option) */
> +
>     HWND       hwnd;        /**< Handle of the window for the grab */
>     HDC        source_hdc;  /**< Source device context */
>     HDC        dest_hdc;    /**< Destination, source-compatible DC */
> @@ -542,6 +544,8 @@ static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
>
>     int64_t curtime, delay;
> 
> +    unsigned long flag = SRCCOPY;
> +
>     /* Calculate the time of the next frame */
>     time_frame += INT64_C(1000000);
> 
> @@ -570,12 +574,15 @@ static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
>         return AVERROR(ENOMEM);
>     pkt->pts = curtime;
> 
> +    if(gdigrab->use_captureblt)
> +        flag |= CAPTUREBLT;
> +
>     /* Blit screen grab */
>     if (!BitBlt(dest_hdc, 0, 0,
>                 clip_rect.right - clip_rect.left,
>                 clip_rect.bottom - clip_rect.top,
>                 source_hdc,
> -                clip_rect.left, clip_rect.top, SRCCOPY | CAPTUREBLT)) {
> +                clip_rect.left, clip_rect.top, flag)) {
>         WIN32_API_ERROR("Failed to capture image");
>         return AVERROR(EIO);
>     }
> @@ -639,6 +646,7 @@ static const AVOption options[] = {
>     { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
>     { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
>     { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
> +    { "use_captureblt", "capture gdi window use CAPTTUREBLT flag", OFFSET(use_captureblt), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
>     { NULL },
> };
>

Regards,
Marton
Calvin Walton Dec. 30, 2019, 5:37 p.m. UTC | #2
On Mon, 2019-12-30 at 12:31 +0100, Marton Balint wrote:
> 
> On Mon, 30 Dec 2019, fgodtdev@hotmail.com wrote:
> 
> > From: FgoDt <fgodtdev@hotmail.com>
> 
> > +@item use_captureblt
> > +When use gdigrab to capture window or desktop, the mouse cursor
> > will flicker.
> 
> Why? Does this happen with every windows version? This does not seem
> like 
> the right fix. In fact, I dont't see how this can work, because mouse
> is 
> drawn upon the captured video "manually" in paint_mouse_pointer.
> Could you 
> dig deeper what is the main cause of the issue?

I'm guessing that what happens here is that on some OS versions, with
some graphics drivers, the cursor on the *real* display might flicker
while ffmpeg is capturing. I've never actually seen this happen, but if
you have bad/old drivers and have desktop compositing disabled, maybe?

> > +Disable CAPTUREBLT FLAG by set value @code{0} to fix cursor
> > flickering. Default value is @code{1}
> > +
> 
> Doesn't this change what is captured when the user captures a single 
> window and something is dragged on top? That alone might be a useful 
> addition, but the documentation as is would be totally misleading.

Yes, this definitely needs to be clarified in docs.

Another thing to check: If the cursor is included in the captured image
when the CAPTUREBLT flag is disabled, then you should make ffmpeg skip
adding the cursor itself in that case.
fgodtdev@hotmail.com Jan. 2, 2020, 2:56 p.m. UTC | #3
在 2020/1/2 3:39, Marton Balint 写道:
>
>
> On Tue, 31 Dec 2019, fgodt wrote:
>
>>
>> 在 2019/12/31 19:30, Marton Balint 写道:
>>>
>>>
>>> On Tue, 31 Dec 2019, fgodt wrote:
>>>
>>>>
>>>> On 2019/12/31 上午1:37, Calvin Walton wrote:
>>>>> On Mon, 2019-12-30 at 12:31 +0100, Marton Balint wrote:
>>>>>> On Mon, 30 Dec 2019, fgodtdev@hotmail.com wrote:
>>>>>>
>>>>>>> From: FgoDt <fgodtdev@hotmail.com>
>>>>>>> +@item use_captureblt
>>>>>>> +When use gdigrab to capture window or desktop, the mouse cursor
>>>>>>> will flicker.
>>>>>> Why? Does this happen with every windows version? This does not seem
>>>>>> like
>>>>>> the right fix. In fact, I dont't see how this can work, because 
>>>>>> mouse
>>>>>> is
>>>>>> drawn upon the captured video "manually" in paint_mouse_pointer.
>>>>>> Could you
>>>>>> dig deeper what is the main cause of the issue?
>>>>> I'm guessing that what happens here is that on some OS versions, with
>>>>> some graphics drivers, the cursor on the *real* display might flicker
>>>>> while ffmpeg is capturing. I've never actually seen this happen, 
>>>>> but if
>>>>> you have bad/old drivers and have desktop compositing disabled, 
>>>>> maybe?
>>>> sorry i'm not describe clear. as you say the capture video mouse is 
>>>> "manually" paint,
>>>>
>>>> so the flicker is not the video, but windows mouse cursor. the 
>>>> reason is CAPTUREBLT flag
>>>>
>>>> use to capture layered window, and the animated cursors or software 
>>>> cursor became know
>>>>
>>>> as layered window in Windows. so when we call bitblt with 
>>>> CAPTUREBLT windows will hide
>>>>
>>>> cursor do capture , and then reshow the cursor,this will make 
>>>> Windows mouse cursor flicker.
>>>>
>>>> if user not capture layered window, without CAPTUREBLT flag does 
>>>> not change anything.
>>>>
>>>> see details 
>>>> https://docs.microsoft.com/en-us/previous-versions/technet-magazine/dd392008(v=msdn.10)?redirectedfrom=MSDN
>>>
>>> This is still not the whole story, if you google deeper you should 
>>> find that this only affects Windows XP and earlier or Windows 7 if 
>>> Aero is disabled.
>>>
>>> Considering this, I am not sure if we should add this flag, maybe a 
>>> warning should be printed instead if Aero is disabled.
>>>
>> But on my Windows 10 the mouse still flicker when i use CAPTUREBLT flag.
>>
>
> Ok, that is indeed strange, because I always read that on Windows8+ 
> the compositor is always enabled.
>
Ye, i tested on Windows 7 sp1 today the flicker still here, so I think 
this flag would be better if it was optional
fgodtdev@hotmail.com Jan. 7, 2020, 2:22 p.m. UTC | #4
在 2020/1/2 22:56, fgodt 写道:
>
> 在 2020/1/2 3:39, Marton Balint 写道:
>>
>>
>> On Tue, 31 Dec 2019, fgodt wrote:
>>
>>>
>>> 在 2019/12/31 19:30, Marton Balint 写道:
>>>>
>>>>
>>>> On Tue, 31 Dec 2019, fgodt wrote:
>>>>
>>>>>
>>>>> On 2019/12/31 上午1:37, Calvin Walton wrote:
>>>>>> On Mon, 2019-12-30 at 12:31 +0100, Marton Balint wrote:
>>>>>>> On Mon, 30 Dec 2019, fgodtdev@hotmail.com wrote:
>>>>>>>
>>>>>>>> From: FgoDt <fgodtdev@hotmail.com>
>>>>>>>> +@item use_captureblt
>>>>>>>> +When use gdigrab to capture window or desktop, the mouse cursor
>>>>>>>> will flicker.
>>>>>>> Why? Does this happen with every windows version? This does not 
>>>>>>> seem
>>>>>>> like
>>>>>>> the right fix. In fact, I dont't see how this can work, because 
>>>>>>> mouse
>>>>>>> is
>>>>>>> drawn upon the captured video "manually" in paint_mouse_pointer.
>>>>>>> Could you
>>>>>>> dig deeper what is the main cause of the issue?
>>>>>> I'm guessing that what happens here is that on some OS versions, 
>>>>>> with
>>>>>> some graphics drivers, the cursor on the *real* display might 
>>>>>> flicker
>>>>>> while ffmpeg is capturing. I've never actually seen this happen, 
>>>>>> but if
>>>>>> you have bad/old drivers and have desktop compositing disabled, 
>>>>>> maybe?
>>>>> sorry i'm not describe clear. as you say the capture video mouse 
>>>>> is "manually" paint,
>>>>>
>>>>> so the flicker is not the video, but windows mouse cursor. the 
>>>>> reason is CAPTUREBLT flag
>>>>>
>>>>> use to capture layered window, and the animated cursors or 
>>>>> software cursor became know
>>>>>
>>>>> as layered window in Windows. so when we call bitblt with 
>>>>> CAPTUREBLT windows will hide
>>>>>
>>>>> cursor do capture , and then reshow the cursor,this will make 
>>>>> Windows mouse cursor flicker.
>>>>>
>>>>> if user not capture layered window, without CAPTUREBLT flag does 
>>>>> not change anything.
>>>>>
>>>>> see details 
>>>>> https://docs.microsoft.com/en-us/previous-versions/technet-magazine/dd392008(v=msdn.10)?redirectedfrom=MSDN
>>>>
>>>> This is still not the whole story, if you google deeper you should 
>>>> find that this only affects Windows XP and earlier or Windows 7 if 
>>>> Aero is disabled.
>>>>
>>>> Considering this, I am not sure if we should add this flag, maybe a 
>>>> warning should be printed instead if Aero is disabled.
>>>>
>>> But on my Windows 10 the mouse still flicker when i use CAPTUREBLT 
>>> flag.
>>>
>>
>> Ok, that is indeed strange, because I always read that on Windows8+ 
>> the compositor is always enabled.
>>
> Ye, i tested on Windows 7 sp1 today the flicker still here, so I think 
> this flag would be better if it was optional
>
So should i resend this patch with clear doc, or just ignore this issue
Marton Balint Jan. 7, 2020, 6:22 p.m. UTC | #5
On Tue, 7 Jan 2020, fgodt wrote:

>
> 在 2020/1/2 22:56, fgodt 写道:
>>
>> 在 2020/1/2 3:39, Marton Balint 写道:
>>>
>>>
>>> On Tue, 31 Dec 2019, fgodt wrote:
>>>
>>>>
>>>> 在 2019/12/31 19:30, Marton Balint 写道:
>>>>>
>>>>>
>>>>> On Tue, 31 Dec 2019, fgodt wrote:
>>>>>
>>>>>>
>>>>>> On 2019/12/31 上午1:37, Calvin Walton wrote:
>>>>>>> On Mon, 2019-12-30 at 12:31 +0100, Marton Balint wrote:
>>>>>>>> On Mon, 30 Dec 2019, fgodtdev@hotmail.com wrote:
>>>>>>>>
>>>>>>>>> From: FgoDt <fgodtdev@hotmail.com>
>>>>>>>>> +@item use_captureblt
>>>>>>>>> +When use gdigrab to capture window or desktop, the mouse cursor
>>>>>>>>> will flicker.
>>>>>>>> Why? Does this happen with every windows version? This does not 
>>>>>>>> seem
>>>>>>>> like
>>>>>>>> the right fix. In fact, I dont't see how this can work, because 
>>>>>>>> mouse
>>>>>>>> is
>>>>>>>> drawn upon the captured video "manually" in paint_mouse_pointer.
>>>>>>>> Could you
>>>>>>>> dig deeper what is the main cause of the issue?
>>>>>>> I'm guessing that what happens here is that on some OS versions, 
>>>>>>> with
>>>>>>> some graphics drivers, the cursor on the *real* display might 
>>>>>>> flicker
>>>>>>> while ffmpeg is capturing. I've never actually seen this happen, 
>>>>>>> but if
>>>>>>> you have bad/old drivers and have desktop compositing disabled, 
>>>>>>> maybe?
>>>>>> sorry i'm not describe clear. as you say the capture video mouse 
>>>>>> is "manually" paint,
>>>>>>
>>>>>> so the flicker is not the video, but windows mouse cursor. the 
>>>>>> reason is CAPTUREBLT flag
>>>>>>
>>>>>> use to capture layered window, and the animated cursors or 
>>>>>> software cursor became know
>>>>>>
>>>>>> as layered window in Windows. so when we call bitblt with 
>>>>>> CAPTUREBLT windows will hide
>>>>>>
>>>>>> cursor do capture , and then reshow the cursor,this will make 
>>>>>> Windows mouse cursor flicker.
>>>>>>
>>>>>> if user not capture layered window, without CAPTUREBLT flag does 
>>>>>> not change anything.
>>>>>>
>>>>>> see details 
>>>>>> 
> https://docs.microsoft.com/en-us/previous-versions/technet-magazine/dd392008(v=msdn.10)?redirectedfrom=MSDN
>>>>>
>>>>> This is still not the whole story, if you google deeper you should 
>>>>> find that this only affects Windows XP and earlier or Windows 7 if 
>>>>> Aero is disabled.
>>>>>
>>>>> Considering this, I am not sure if we should add this flag, maybe a 
>>>>> warning should be printed instead if Aero is disabled.
>>>>>
>>>> But on my Windows 10 the mouse still flicker when i use CAPTUREBLT 
>>>> flag.
>>>>
>>>
>>> Ok, that is indeed strange, because I always read that on Windows8+ 
>>> the compositor is always enabled.
>>>
>> Ye, i tested on Windows 7 sp1 today the flicker still here, so I think 
>> this flag would be better if it was optional
>>
> So should i resend this patch with clear doc, or just ignore this issue

Yes, please clarify the docs, unfortunately I don't know enough about 
windows/gdi to decide if it is a worthy addition, so I will let others 
decide and apply.

Regards,
Marton
diff mbox

Patch

diff --git a/doc/indevs.texi b/doc/indevs.texi
index 92bc65be41..43b0bd0465 100644
--- a/doc/indevs.texi
+++ b/doc/indevs.texi
@@ -748,6 +748,12 @@  When capturing a region with @var{video_size}, set the distance from the top edg
 
 Note that the offset calculation is from the top left corner of the primary monitor on Windows. If you have a monitor positioned above your primary monitor, you will need to use a negative @var{offset_y} value to move the region to that monitor.
 
+@item use_captureblt
+When use gdigrab to capture window or desktop, the mouse cursor will flicker.
+Disable CAPTUREBLT FLAG by set value @code{0} to fix cursor flickering. Default value is @code{1}
+
+Note the value @code{1} is essential to capture specific  window
+
 @end table
 
 @section iec61883
diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c
index f4444406fa..658719e929 100644
--- a/libavdevice/gdigrab.c
+++ b/libavdevice/gdigrab.c
@@ -53,6 +53,8 @@  struct gdigrab {
     int        offset_x;    /**< Capture x offset (private option) */
     int        offset_y;    /**< Capture y offset (private option) */
 
+    int        use_captureblt; /**< Capture gdi window with CAPTUREBLT flag (private option) */
+
     HWND       hwnd;        /**< Handle of the window for the grab */
     HDC        source_hdc;  /**< Source device context */
     HDC        dest_hdc;    /**< Destination, source-compatible DC */
@@ -542,6 +544,8 @@  static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
 
     int64_t curtime, delay;
 
+    unsigned long flag = SRCCOPY;
+
     /* Calculate the time of the next frame */
     time_frame += INT64_C(1000000);
 
@@ -570,12 +574,15 @@  static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
         return AVERROR(ENOMEM);
     pkt->pts = curtime;
 
+    if(gdigrab->use_captureblt)
+        flag |= CAPTUREBLT;
+
     /* Blit screen grab */
     if (!BitBlt(dest_hdc, 0, 0,
                 clip_rect.right - clip_rect.left,
                 clip_rect.bottom - clip_rect.top,
                 source_hdc,
-                clip_rect.left, clip_rect.top, SRCCOPY | CAPTUREBLT)) {
+                clip_rect.left, clip_rect.top, flag)) {
         WIN32_API_ERROR("Failed to capture image");
         return AVERROR(EIO);
     }
@@ -639,6 +646,7 @@  static const AVOption options[] = {
     { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
     { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
     { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+    { "use_captureblt", "capture gdi window use CAPTTUREBLT flag", OFFSET(use_captureblt), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
     { NULL },
 };