Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
ffmpeg
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
ffmpeg
Commits
a6674d2e
Commit
a6674d2e
authored
Aug 24, 2014
by
Luca Barbato
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
xcbgrab: XCB-based screen capture
Matches the x11grab screen capture by features.
parent
ed6dad37
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
693 additions
and
8 deletions
+693
-8
Changelog
Changelog
+1
-0
configure
configure
+33
-6
Makefile
libavdevice/Makefile
+2
-1
alldevices.c
libavdevice/alldevices.c
+1
-0
version.h
libavdevice/version.h
+1
-1
xcbgrab.c
libavdevice/xcbgrab.c
+655
-0
No files found.
Changelog
View file @
a6674d2e
...
@@ -5,6 +5,7 @@ version <next>:
...
@@ -5,6 +5,7 @@ version <next>:
- aliases and defaults for Ogg subtypes (opus, spx)
- aliases and defaults for Ogg subtypes (opus, spx)
- HEVC/H.265 RTP payload format (draft v6) packetizer and depacketizer
- HEVC/H.265 RTP payload format (draft v6) packetizer and depacketizer
- avplay now exits by default at the end of playback
- avplay now exits by default at the end of playback
- XCB-based screen-grabber
version 11:
version 11:
...
...
configure
View file @
a6674d2e
...
@@ -210,10 +210,13 @@ External library support:
...
@@ -210,10 +210,13 @@ External library support:
--enable-libx264 enable H.264 encoding via x264 [no]
--enable-libx264 enable H.264 encoding via x264 [no]
--enable-libx265 enable HEVC encoding via x265 [no]
--enable-libx265 enable HEVC encoding via x265 [no]
--enable-libxavs enable AVS encoding via xavs [no]
--enable-libxavs enable AVS encoding via xavs [no]
--enable-libxcb enable X11 grabbing using XCB [no]
--enable-libxcb-shm enable X11 grabbing shm communication [auto]
--enable-libxcb-xfixes enable X11 grabbing mouse rendering [auto]
--enable-libxvid enable Xvid encoding via xvidcore,
--enable-libxvid enable Xvid encoding via xvidcore,
native MPEG-4/Xvid encoder exists [no]
native MPEG-4/Xvid encoder exists [no]
--enable-openssl enable openssl [no]
--enable-openssl enable openssl [no]
--enable-x11grab enable X11 grabbing [no]
--enable-x11grab enable X11 grabbing
(legacy)
[no]
--enable-zlib enable zlib [autodetect]
--enable-zlib enable zlib [autodetect]
Toolchain options:
Toolchain options:
...
@@ -1170,6 +1173,9 @@ EXTERNAL_LIBRARY_LIST="
...
@@ -1170,6 +1173,9 @@ EXTERNAL_LIBRARY_LIST="
libx264
libx264
libx265
libx265
libxavs
libxavs
libxcb
libxcb_shm
libxcb_xfixes
libxvid
libxvid
openssl
openssl
x11grab
x11grab
...
@@ -2102,7 +2108,8 @@ sndio_outdev_deps="sndio_h"
...
@@ -2102,7 +2108,8 @@ sndio_outdev_deps="sndio_h"
v4l2_indev_deps_any
=
"linux_videodev2_h sys_videoio_h"
v4l2_indev_deps_any
=
"linux_videodev2_h sys_videoio_h"
vfwcap_indev_deps
=
"capCreateCaptureWindow vfwcap_defines"
vfwcap_indev_deps
=
"capCreateCaptureWindow vfwcap_defines"
vfwcap_indev_extralibs
=
"-lavicap32"
vfwcap_indev_extralibs
=
"-lavicap32"
x11grab_indev_deps
=
"x11grab XShmCreateImage"
x11grab_indev_deps
=
"x11grab"
x11grab_xcb_indev_deps
=
"libxcb"
# protocols
# protocols
ffrtmpcrypt_protocol_deps
=
"!librtmp_protocol"
ffrtmpcrypt_protocol_deps
=
"!librtmp_protocol"
...
@@ -4273,10 +4280,30 @@ fi
...
@@ -4273,10 +4280,30 @@ fi
check_lib X11/Xlib.h XOpenDisplay
-lX11
&&
enable
xlib
check_lib X11/Xlib.h XOpenDisplay
-lX11
&&
enable
xlib
enabled x11grab
&&
if
enabled libxcb
||
enabled x11grab
&&
!
disabled libxcb
;
then
require Xext X11/extensions/XShm.h XShmCreateImage
-lXext
&&
check_pkg_config xcb-event xcb/xcb.h xcb_connect
||
{
require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage
-lXfixes
&&
enabled libxcb
&&
die
"ERROR: libxcb not found"
;
{
enabled xlib
||
die
"ERROR: Xlib not found"
;
}
}
&&
disable x11grab
&&
enable
libxcb
disabled libxcb_shm
||
check_pkg_config xcb-shm xcb/shm.h xcb_shm_attach
||
{
enabled libxcb_shm
&&
die
"ERROR: libxcb_shm not found"
;
}
&&
check_header sys/shm.h
&&
enable
libxcb_shm
disabled libxcb_xfixes
||
check_pkg_config xcb-xfixes xcb/xfixes.h xcb_xfixes_get_cursor_image
||
{
enabled libxcb_xfixes
&&
die
"ERROR: libxcb_xfixes not found"
;
}
&&
enable
libxcb_xfixes
add_cflags
"
$xcb_event_cflags
$xcb_shm_cflags
$xcb_xfixes_cflags
"
add_extralibs
"
$xcb_event_libs
$xcb_shm_libs
$xcb_xfixes_libs
"
fi
if
enabled x11grab
;
then
enabled xlib
||
die
"ERROR: Xlib not found"
require Xext X11/extensions/XShm.h XShmCreateImage
-lXext
require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage
-lXfixes
fi
enabled vdpau
&&
enabled vdpau
&&
check_cpp_condition vdpau/vdpau.h
"defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP"
||
check_cpp_condition vdpau/vdpau.h
"defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP"
||
...
...
libavdevice/Makefile
View file @
a6674d2e
...
@@ -22,7 +22,8 @@ OBJS-$(CONFIG_SNDIO_INDEV) += sndio_common.o sndio_dec.o
...
@@ -22,7 +22,8 @@ OBJS-$(CONFIG_SNDIO_INDEV) += sndio_common.o sndio_dec.o
OBJS-$(CONFIG_SNDIO_OUTDEV)
+=
sndio_common.o
sndio_enc.o
OBJS-$(CONFIG_SNDIO_OUTDEV)
+=
sndio_common.o
sndio_enc.o
OBJS-$(CONFIG_V4L2_INDEV)
+=
v4l2.o
OBJS-$(CONFIG_V4L2_INDEV)
+=
v4l2.o
OBJS-$(CONFIG_VFWCAP_INDEV)
+=
vfwcap.o
OBJS-$(CONFIG_VFWCAP_INDEV)
+=
vfwcap.o
OBJS-$(CONFIG_X11GRAB_INDEV)
+=
x11grab.o
OBJS-$(CONFIG_X11GRAB_XLIB_INDEV)
+=
x11grab.o
OBJS-$(CONFIG_X11GRAB_XCB_INDEV)
+=
xcbgrab.o
# external libraries
# external libraries
OBJS-$(CONFIG_LIBCDIO_INDEV)
+=
libcdio.o
OBJS-$(CONFIG_LIBCDIO_INDEV)
+=
libcdio.o
...
...
libavdevice/alldevices.c
View file @
a6674d2e
...
@@ -58,6 +58,7 @@ void avdevice_register_all(void)
...
@@ -58,6 +58,7 @@ void avdevice_register_all(void)
REGISTER_INDEV
(
V4L2
,
v4l2
);
REGISTER_INDEV
(
V4L2
,
v4l2
);
REGISTER_INDEV
(
VFWCAP
,
vfwcap
);
REGISTER_INDEV
(
VFWCAP
,
vfwcap
);
REGISTER_INDEV
(
X11GRAB
,
x11grab
);
REGISTER_INDEV
(
X11GRAB
,
x11grab
);
REGISTER_INDEV
(
X11GRAB_XCB
,
x11grab_xcb
);
/* external libraries */
/* external libraries */
REGISTER_INDEV
(
LIBCDIO
,
libcdio
);
REGISTER_INDEV
(
LIBCDIO
,
libcdio
);
...
...
libavdevice/version.h
View file @
a6674d2e
...
@@ -28,7 +28,7 @@
...
@@ -28,7 +28,7 @@
#include "libavutil/version.h"
#include "libavutil/version.h"
#define LIBAVDEVICE_VERSION_MAJOR 55
#define LIBAVDEVICE_VERSION_MAJOR 55
#define LIBAVDEVICE_VERSION_MINOR
0
#define LIBAVDEVICE_VERSION_MINOR
1
#define LIBAVDEVICE_VERSION_MICRO 0
#define LIBAVDEVICE_VERSION_MICRO 0
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
#define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \
...
...
libavdevice/xcbgrab.c
0 → 100644
View file @
a6674d2e
/*
* XCB input grabber
* Copyright (C) 2014 Luca Barbato <lu_zero@gentoo.org>
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include <stdlib.h>
#include <xcb/xcb.h>
#if CONFIG_LIBXCB_XFIXES
#include <xcb/xfixes.h>
#endif
#if CONFIG_LIBXCB_SHM
#include <sys/shm.h>
#include <xcb/shm.h>
#endif
#include "libavformat/avformat.h"
#include "libavformat/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "libavutil/time.h"
typedef
struct
XCBGrabContext
{
const
AVClass
*
class
;
xcb_connection_t
*
conn
;
xcb_screen_t
*
screen
;
xcb_window_t
window
;
xcb_shm_seg_t
segment
;
int64_t
time_frame
;
AVRational
time_base
;
int
x
,
y
;
int
width
,
height
;
int
frame_size
;
int
bpp
;
int
draw_mouse
;
int
follow_mouse
;
int
show_region
;
int
region_border
;
int
centered
;
const
char
*
video_size
;
const
char
*
framerate
;
int
has_shm
;
}
XCBGrabContext
;
#define FOLLOW_CENTER -1
#define OFFSET(x) offsetof(XCBGrabContext, x)
#define D AV_OPT_FLAG_DECODING_PARAM
static
const
AVOption
options
[]
=
{
{
"x"
,
"Initial x coordinate."
,
OFFSET
(
x
),
AV_OPT_TYPE_INT
,
{
.
i64
=
0
},
0
,
INT_MAX
,
D
},
{
"y"
,
"Initial y coordinate."
,
OFFSET
(
y
),
AV_OPT_TYPE_INT
,
{
.
i64
=
0
},
0
,
INT_MAX
,
D
},
{
"video_size"
,
"A string describing frame size, such as 640x480 or hd720."
,
OFFSET
(
video_size
),
AV_OPT_TYPE_STRING
,
{.
str
=
"vga"
},
0
,
0
,
D
},
{
"framerate"
,
""
,
OFFSET
(
framerate
),
AV_OPT_TYPE_STRING
,
{.
str
=
"ntsc"
},
0
,
0
,
D
},
{
"draw_mouse"
,
"Draw the mouse pointer."
,
OFFSET
(
draw_mouse
),
AV_OPT_TYPE_INT
,
{
.
i64
=
1
},
0
,
1
,
D
},
{
"follow_mouse"
,
"Move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region."
,
OFFSET
(
follow_mouse
),
AV_OPT_TYPE_INT
,
{
.
i64
=
0
},
FOLLOW_CENTER
,
INT_MAX
,
D
,
"follow_mouse"
},
{
"centered"
,
"Keep the mouse pointer at the center of grabbing region when following."
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
-
1
},
INT_MIN
,
INT_MAX
,
D
,
"follow_mouse"
},
{
"show_region"
,
"Show the grabbing region."
,
OFFSET
(
show_region
),
AV_OPT_TYPE_INT
,
{
.
i64
=
0
},
0
,
1
,
D
},
{
"region_border"
,
"Set the region border thickness."
,
OFFSET
(
region_border
),
AV_OPT_TYPE_INT
,
{
.
i64
=
3
},
1
,
128
,
D
},
{
NULL
},
};
static
const
AVClass
xcbgrab_class
=
{
.
class_name
=
"xcbgrab indev"
,
.
item_name
=
av_default_item_name
,
.
option
=
options
,
.
version
=
LIBAVUTIL_VERSION_INT
,
};
static
int
xcbgrab_reposition
(
AVFormatContext
*
s
,
xcb_query_pointer_reply_t
*
p
,
xcb_get_geometry_reply_t
*
geo
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
int
x
=
c
->
x
,
y
=
c
->
y
,
p_x
=
p
->
win_x
,
p_y
=
p
->
win_y
;
int
w
=
c
->
width
,
h
=
c
->
height
,
f
=
c
->
follow_mouse
;
if
(
!
p
||
!
geo
)
return
AVERROR
(
EIO
);
if
(
f
==
FOLLOW_CENTER
)
{
x
=
p_x
-
w
/
2
;
y
=
p_y
-
h
/
2
;
}
else
{
int
left
=
x
+
f
;
int
right
=
x
+
w
-
f
;
int
top
=
y
+
f
;
int
bottom
=
y
+
h
+
f
;
if
(
p_x
>
right
)
{
x
+=
p_x
-
right
;
}
else
if
(
p_x
<
left
)
{
x
-=
left
-
p_x
;
}
if
(
p_y
>
bottom
)
{
y
+=
p_y
-
bottom
;
}
else
if
(
p_y
<
top
)
{
y
-=
top
-
p_y
;
}
}
c
->
x
=
FFMIN
(
FFMAX
(
0
,
x
),
geo
->
width
-
w
);
c
->
y
=
FFMIN
(
FFMAX
(
0
,
y
),
geo
->
height
-
h
);
return
0
;
}
static
int
xcbgrab_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
xcb_get_image_cookie_t
iq
;
xcb_get_image_reply_t
*
img
;
xcb_drawable_t
drawable
=
c
->
screen
->
root
;
uint8_t
*
data
;
int
length
,
ret
;
iq
=
xcb_get_image
(
c
->
conn
,
XCB_IMAGE_FORMAT_Z_PIXMAP
,
drawable
,
c
->
x
,
c
->
y
,
c
->
width
,
c
->
height
,
~
0
);
img
=
xcb_get_image_reply
(
c
->
conn
,
iq
,
NULL
);
if
(
!
img
)
return
AVERROR
(
EAGAIN
);
data
=
xcb_get_image_data
(
img
);
length
=
xcb_get_image_data_length
(
img
);
ret
=
av_new_packet
(
pkt
,
length
);
if
(
!
ret
)
memcpy
(
pkt
->
data
,
data
,
length
);
free
(
img
);
return
ret
;
}
static
void
wait_frame
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
int64_t
curtime
,
delay
;
int64_t
frame_time
=
av_rescale_q
(
1
,
c
->
time_base
,
AV_TIME_BASE_Q
);
c
->
time_frame
+=
frame_time
;
for
(;;)
{
curtime
=
av_gettime
();
delay
=
c
->
time_frame
-
curtime
;
if
(
delay
<=
0
)
break
;
av_usleep
(
delay
);
}
pkt
->
pts
=
curtime
;
}
#if CONFIG_LIBXCB_SHM
static
int
check_shm
(
xcb_connection_t
*
conn
)
{
xcb_shm_query_version_cookie_t
cookie
=
xcb_shm_query_version
(
conn
);
xcb_shm_query_version_reply_t
*
reply
;
reply
=
xcb_shm_query_version_reply
(
conn
,
cookie
,
NULL
);
if
(
reply
)
{
free
(
reply
);
return
1
;
}
return
0
;
}
static
void
dealloc_shm
(
void
*
unused
,
uint8_t
*
data
)
{
shmdt
(
data
);
}
static
int
xcbgrab_frame_shm
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
xcb_shm_get_image_cookie_t
iq
;
xcb_shm_get_image_reply_t
*
img
;
xcb_drawable_t
drawable
=
c
->
screen
->
root
;
uint8_t
*
data
;
int
size
=
c
->
frame_size
+
FF_INPUT_BUFFER_PADDING_SIZE
;
int
id
=
shmget
(
IPC_PRIVATE
,
size
,
IPC_CREAT
|
0777
);
xcb_generic_error_t
*
e
=
NULL
;
if
(
id
==
-
1
)
{
char
errbuf
[
1024
];
int
err
=
AVERROR
(
errno
);
av_strerror
(
err
,
errbuf
,
sizeof
(
errbuf
));
av_log
(
s
,
AV_LOG_ERROR
,
"Cannot get %d bytes of shared memory: %s.
\n
"
,
size
,
errbuf
);
return
err
;
}
xcb_shm_attach
(
c
->
conn
,
c
->
segment
,
id
,
0
);
iq
=
xcb_shm_get_image
(
c
->
conn
,
drawable
,
c
->
x
,
c
->
y
,
c
->
width
,
c
->
height
,
~
0
,
XCB_IMAGE_FORMAT_Z_PIXMAP
,
c
->
segment
,
0
);
xcb_shm_detach
(
c
->
conn
,
c
->
segment
);
img
=
xcb_shm_get_image_reply
(
c
->
conn
,
iq
,
&
e
);
xcb_flush
(
c
->
conn
);
if
(
e
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"Cannot get the image data "
"event_error: response_type:%u error_code:%u "
"sequence:%u resource_id:%u minor_code:%u major_code:%u.
\n
"
,
e
->
response_type
,
e
->
error_code
,
e
->
sequence
,
e
->
resource_id
,
e
->
minor_code
,
e
->
major_code
);
shmctl
(
id
,
IPC_RMID
,
0
);
return
AVERROR
(
EACCES
);
}
free
(
img
);
data
=
shmat
(
id
,
NULL
,
0
);
shmctl
(
id
,
IPC_RMID
,
0
);
if
((
intptr_t
)
data
==
-
1
)
return
AVERROR
(
errno
);
pkt
->
buf
=
av_buffer_create
(
data
,
size
,
dealloc_shm
,
NULL
,
0
);
if
(
!
pkt
->
buf
)
{
shmdt
(
data
);
return
AVERROR
(
ENOMEM
);
}
pkt
->
data
=
pkt
->
buf
->
data
;
pkt
->
size
=
c
->
frame_size
;
return
0
;
}
#endif
/* CONFIG_LIBXCB_SHM */
#if CONFIG_LIBXCB_XFIXES
static
int
check_xfixes
(
xcb_connection_t
*
conn
)
{
xcb_xfixes_query_version_cookie_t
cookie
;
xcb_xfixes_query_version_reply_t
*
reply
;
cookie
=
xcb_xfixes_query_version
(
conn
,
XCB_XFIXES_MAJOR_VERSION
,
XCB_XFIXES_MINOR_VERSION
);
reply
=
xcb_xfixes_query_version_reply
(
conn
,
cookie
,
NULL
);
if
(
reply
)
{
free
(
reply
);
return
1
;
}
return
0
;
}
#define BLEND(target, source, alpha) \
(target) + ((source) * (255 - (alpha)) + 255 / 2) / 255
static
void
xcbgrab_draw_mouse
(
AVFormatContext
*
s
,
AVPacket
*
pkt
,
xcb_query_pointer_reply_t
*
p
,
xcb_get_geometry_reply_t
*
geo
)
{
XCBGrabContext
*
gr
=
s
->
priv_data
;
uint32_t
*
cursor
;
uint8_t
*
image
=
pkt
->
data
;
int
stride
=
gr
->
bpp
/
8
;
xcb_xfixes_get_cursor_image_cookie_t
cc
;
xcb_xfixes_get_cursor_image_reply_t
*
ci
;
int
cx
,
cy
,
x
,
y
,
w
,
h
,
c_off
,
i_off
;
cc
=
xcb_xfixes_get_cursor_image
(
gr
->
conn
);
ci
=
xcb_xfixes_get_cursor_image_reply
(
gr
->
conn
,
cc
,
NULL
);
if
(
!
ci
)
return
;
cursor
=
xcb_xfixes_get_cursor_image_cursor_image
(
ci
);
if
(
!
cursor
)
return
;
cx
=
ci
->
x
-
ci
->
xhot
;
cy
=
ci
->
y
-
ci
->
yhot
;
x
=
FFMAX
(
cx
,
gr
->
x
);
y
=
FFMAX
(
cy
,
gr
->
y
);
w
=
FFMIN
(
cx
+
ci
->
width
,
gr
->
x
+
gr
->
width
)
-
x
;
h
=
FFMIN
(
cy
+
ci
->
height
,
gr
->
y
+
gr
->
height
)
-
y
;
c_off
=
x
-
cx
;
i_off
=
x
-
gr
->
x
;
cursor
+=
(
y
-
cy
)
*
ci
->
width
;
image
+=
(
y
-
gr
->
y
)
*
gr
->
width
*
stride
;
for
(
y
=
0
;
y
<
h
;
y
++
)
{
cursor
+=
c_off
;
image
+=
i_off
*
stride
;
for
(
x
=
0
;
x
<
w
;
x
++
,
cursor
++
,
image
+=
stride
)
{
int
r
,
g
,
b
,
a
;
r
=
*
cursor
&
0xff
;
g
=
(
*
cursor
>>
8
)
&
0xff
;
b
=
(
*
cursor
>>
16
)
&
0xff
;
a
=
(
*
cursor
>>
24
)
&
0xff
;
if
(
!
a
)
continue
;
if
(
a
==
255
)
{
image
[
0
]
=
r
;
image
[
1
]
=
g
;
image
[
2
]
=
b
;
}
else
{
image
[
0
]
=
BLEND
(
r
,
image
[
0
],
a
);
image
[
1
]
=
BLEND
(
g
,
image
[
1
],
a
);
image
[
2
]
=
BLEND
(
b
,
image
[
2
],
a
);
}
}
cursor
+=
ci
->
width
-
w
-
c_off
;
image
+=
(
gr
->
width
-
w
-
i_off
)
*
stride
;
}
free
(
ci
);
}
#endif
/* CONFIG_LIBXCB_XFIXES */
static
void
xcbgrab_update_region
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
const
uint32_t
args
[]
=
{
c
->
x
-
c
->
region_border
,
c
->
y
-
c
->
region_border
};
xcb_configure_window
(
c
->
conn
,
c
->
window
,
XCB_CONFIG_WINDOW_X
|
XCB_CONFIG_WINDOW_Y
,
args
);
}
static
int
xcbgrab_read_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
xcb_query_pointer_cookie_t
pc
;
xcb_get_geometry_cookie_t
gc
;
xcb_query_pointer_reply_t
*
p
=
NULL
;
xcb_get_geometry_reply_t
*
geo
=
NULL
;
int
ret
=
0
;
wait_frame
(
s
,
pkt
);
if
(
c
->
follow_mouse
||
c
->
draw_mouse
)
{
pc
=
xcb_query_pointer
(
c
->
conn
,
c
->
screen
->
root
);
gc
=
xcb_get_geometry
(
c
->
conn
,
c
->
screen
->
root
);
p
=
xcb_query_pointer_reply
(
c
->
conn
,
pc
,
NULL
);
geo
=
xcb_get_geometry_reply
(
c
->
conn
,
gc
,
NULL
);
}
if
(
c
->
follow_mouse
&&
p
->
same_screen
)
xcbgrab_reposition
(
s
,
p
,
geo
);
if
(
c
->
show_region
)
xcbgrab_update_region
(
s
);
#if CONFIG_LIBXCB_SHM
if
(
c
->
has_shm
&&
xcbgrab_frame_shm
(
s
,
pkt
)
<
0
)
c
->
has_shm
=
0
;
#endif
if
(
!
c
->
has_shm
)
ret
=
xcbgrab_frame
(
s
,
pkt
);
#if CONFIG_LIBXCB_XFIXES
if
(
c
->
draw_mouse
&&
p
->
same_screen
)
xcbgrab_draw_mouse
(
s
,
pkt
,
p
,
geo
);
#endif
free
(
p
);
free
(
geo
);
return
ret
;
}
static
av_cold
int
xcbgrab_read_close
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
ctx
=
s
->
priv_data
;
xcb_disconnect
(
ctx
->
conn
);
return
0
;
}
static
xcb_screen_t
*
get_screen
(
const
xcb_setup_t
*
setup
,
int
screen_num
)
{
xcb_screen_iterator_t
it
=
xcb_setup_roots_iterator
(
setup
);
xcb_screen_t
*
screen
=
NULL
;
for
(;
it
.
rem
>
0
;
xcb_screen_next
(
&
it
))
{
if
(
!
screen_num
)
{
screen
=
it
.
data
;
break
;
}
screen_num
--
;
}
return
screen
;
}
static
int
pixfmt_from_pixmap_format
(
AVFormatContext
*
s
,
int
depth
,
int
*
pix_fmt
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
const
xcb_setup_t
*
setup
=
xcb_get_setup
(
c
->
conn
);
const
xcb_format_t
*
fmt
=
xcb_setup_pixmap_formats
(
setup
);
int
length
=
xcb_setup_pixmap_formats_length
(
setup
);
*
pix_fmt
=
0
;
while
(
length
--
)
{
if
(
fmt
->
depth
==
depth
)
{
switch
(
depth
)
{
case
32
:
if
(
fmt
->
bits_per_pixel
==
32
)
*
pix_fmt
=
AV_PIX_FMT_ARGB
;
break
;
case
24
:
if
(
fmt
->
bits_per_pixel
==
32
)
*
pix_fmt
=
AV_PIX_FMT_RGB32
;
else
if
(
fmt
->
bits_per_pixel
==
24
)
*
pix_fmt
=
AV_PIX_FMT_RGB24
;
break
;
case
16
:
if
(
fmt
->
bits_per_pixel
==
16
)
*
pix_fmt
=
AV_PIX_FMT_RGB565
;
break
;
case
15
:
if
(
fmt
->
bits_per_pixel
==
16
)
*
pix_fmt
=
AV_PIX_FMT_RGB555
;
break
;
case
8
:
if
(
fmt
->
bits_per_pixel
==
8
)
*
pix_fmt
=
AV_PIX_FMT_RGB8
;
break
;
}
}
if
(
*
pix_fmt
)
{
c
->
bpp
=
fmt
->
bits_per_pixel
;
c
->
frame_size
=
c
->
width
*
c
->
height
*
fmt
->
bits_per_pixel
/
8
;
return
0
;
}
fmt
++
;
}
av_log
(
s
,
AV_LOG_ERROR
,
"Pixmap format not mappable.
\n
"
);
return
AVERROR_PATCHWELCOME
;
}
static
int
create_stream
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
AVStream
*
st
=
avformat_new_stream
(
s
,
NULL
);
const
char
*
opts
=
strchr
(
s
->
filename
,
'+'
);
xcb_get_geometry_cookie_t
gc
;
xcb_get_geometry_reply_t
*
geo
;
int
ret
;
if
(
!
st
)
return
AVERROR
(
ENOMEM
);
ret
=
av_parse_video_size
(
&
c
->
width
,
&
c
->
height
,
c
->
video_size
);
if
(
ret
<
0
)
return
ret
;
ret
=
av_parse_video_rate
(
&
st
->
avg_frame_rate
,
c
->
framerate
);
if
(
ret
<
0
)
return
ret
;
if
(
opts
)
sscanf
(
opts
,
"%d,%d"
,
&
c
->
x
,
&
c
->
y
);
avpriv_set_pts_info
(
st
,
64
,
1
,
1000000
);
gc
=
xcb_get_geometry
(
c
->
conn
,
c
->
screen
->
root
);
geo
=
xcb_get_geometry_reply
(
c
->
conn
,
gc
,
NULL
);
c
->
width
=
FFMIN
(
geo
->
width
,
c
->
width
);
c
->
height
=
FFMIN
(
geo
->
height
,
c
->
height
);
c
->
time_base
=
(
AVRational
){
st
->
avg_frame_rate
.
den
,
st
->
avg_frame_rate
.
num
};
c
->
time_frame
=
av_gettime
();
st
->
codec
->
codec_type
=
AVMEDIA_TYPE_VIDEO
;
st
->
codec
->
codec_id
=
AV_CODEC_ID_RAWVIDEO
;
st
->
codec
->
width
=
c
->
width
;
st
->
codec
->
height
=
c
->
height
;
st
->
codec
->
time_base
=
c
->
time_base
;
ret
=
pixfmt_from_pixmap_format
(
s
,
geo
->
depth
,
&
st
->
codec
->
pix_fmt
);
free
(
geo
);
return
ret
;
}
static
void
draw_rectangle
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
xcb_gcontext_t
gc
=
xcb_generate_id
(
c
->
conn
);
uint32_t
mask
=
XCB_GC_FOREGROUND
|
XCB_GC_BACKGROUND
|
XCB_GC_LINE_WIDTH
|
XCB_GC_LINE_STYLE
|
XCB_GC_FILL_STYLE
;
uint32_t
values
[]
=
{
c
->
screen
->
black_pixel
,
c
->
screen
->
white_pixel
,
c
->
region_border
,
XCB_LINE_STYLE_DOUBLE_DASH
,
XCB_FILL_STYLE_SOLID
};
xcb_rectangle_t
r
=
{
1
,
1
,
c
->
width
+
c
->
region_border
*
2
-
3
,
c
->
height
+
c
->
region_border
*
2
-
3
};
xcb_create_gc
(
c
->
conn
,
gc
,
c
->
window
,
mask
,
values
);
xcb_poly_rectangle
(
c
->
conn
,
c
->
window
,
gc
,
1
,
&
r
);
}
static
void
setup_window
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
uint32_t
mask
=
XCB_CW_OVERRIDE_REDIRECT
|
XCB_CW_EVENT_MASK
;
uint32_t
values
[]
=
{
1
,
XCB_EVENT_MASK_EXPOSURE
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY
};
xcb_rectangle_t
rect
=
{
c
->
x
,
c
->
y
,
c
->
width
,
c
->
height
};
c
->
window
=
xcb_generate_id
(
c
->
conn
);
xcb_create_window
(
c
->
conn
,
XCB_COPY_FROM_PARENT
,
c
->
window
,
c
->
screen
->
root
,
c
->
x
-
c
->
region_border
,
c
->
y
-
c
->
region_border
,
c
->
width
+
c
->
region_border
*
2
,
c
->
height
+
c
->
region_border
*
2
,
0
,
XCB_WINDOW_CLASS_INPUT_OUTPUT
,
XCB_COPY_FROM_PARENT
,
mask
,
values
);
xcb_shape_rectangles
(
c
->
conn
,
XCB_SHAPE_SO_SUBTRACT
,
XCB_SHAPE_SK_BOUNDING
,
XCB_CLIP_ORDERING_UNSORTED
,
c
->
window
,
c
->
region_border
,
c
->
region_border
,
1
,
&
rect
);
xcb_map_window
(
c
->
conn
,
c
->
window
);
draw_rectangle
(
s
);
}
static
av_cold
int
xcbgrab_read_header
(
AVFormatContext
*
s
)
{
XCBGrabContext
*
c
=
s
->
priv_data
;
int
screen_num
,
ret
;
const
xcb_setup_t
*
setup
;
c
->
conn
=
xcb_connect
(
s
->
filename
,
&
screen_num
);
if
((
ret
=
xcb_connection_has_error
(
c
->
conn
)))
{
av_log
(
s
,
AV_LOG_ERROR
,
"Cannot open display %s, error %d.
\n
"
,
s
->
filename
?
s
->
filename
:
"default"
,
ret
);
return
AVERROR
(
EIO
);
}
setup
=
xcb_get_setup
(
c
->
conn
);
c
->
screen
=
get_screen
(
setup
,
screen_num
);
if
(
!
c
->
screen
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"The screen %d does not exist.
\n
"
,
screen_num
);
xcbgrab_read_close
(
s
);
return
AVERROR
(
EIO
);
}
c
->
segment
=
xcb_generate_id
(
c
->
conn
);
ret
=
create_stream
(
s
);
if
(
ret
<
0
)
{
xcbgrab_read_close
(
s
);
return
ret
;
}
#if CONFIG_LIBXCB_SHM
c
->
has_shm
=
check_shm
(
c
->
conn
);
#endif
#if CONFIG_LIBXCB_XFIXES
if
(
c
->
draw_mouse
)
{
if
(
!
(
c
->
draw_mouse
=
check_xfixes
(
c
->
conn
)))
{
av_log
(
s
,
AV_LOG_WARNING
,
"XFixes not available, cannot draw the mouse.
\n
"
);
}
if
(
c
->
bpp
<
24
)
{
avpriv_report_missing_feature
(
s
,
"%d bits per pixel screen"
,
c
->
bpp
);
c
->
draw_mouse
=
0
;
}
}
#endif
if
(
c
->
show_region
)
setup_window
(
s
);
return
0
;
}
AVInputFormat
ff_x11grab_xcb_demuxer
=
{
.
name
=
"x11grab"
,
.
long_name
=
NULL_IF_CONFIG_SMALL
(
"X11 screen capture, using XCB"
),
.
priv_data_size
=
sizeof
(
XCBGrabContext
),
.
read_header
=
xcbgrab_read_header
,
.
read_packet
=
xcbgrab_read_packet
,
.
read_close
=
xcbgrab_read_close
,
.
flags
=
AVFMT_NOFILE
,
.
priv_class
=
&
xcbgrab_class
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment