Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
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