|
|
@@ -60,6 +60,7 @@ typedef struct XCBGrabContext { |
|
|
|
AVRational time_base; |
|
|
|
int64_t frame_duration; |
|
|
|
|
|
|
|
xcb_window_t window_id; |
|
|
|
int x, y; |
|
|
|
int width, height; |
|
|
|
int frame_size; |
|
|
@@ -82,6 +83,7 @@ typedef struct XCBGrabContext { |
|
|
|
#define OFFSET(x) offsetof(XCBGrabContext, x) |
|
|
|
#define D AV_OPT_FLAG_DECODING_PARAM |
|
|
|
static const AVOption options[] = { |
|
|
|
{ "window_id", "Window to capture.", OFFSET(window_id), AV_OPT_TYPE_INT, { .i64 = XCB_NONE }, 0, UINT32_MAX, D }, |
|
|
|
{ "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 }, |
|
|
|
{ "grab_x", "Initial x coordinate.", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D }, |
|
|
@@ -157,7 +159,7 @@ 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; |
|
|
|
xcb_drawable_t drawable = c->window_id; |
|
|
|
xcb_generic_error_t *e = NULL; |
|
|
|
uint8_t *data; |
|
|
|
int length; |
|
|
@@ -267,7 +269,7 @@ 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; |
|
|
|
xcb_drawable_t drawable = c->window_id; |
|
|
|
xcb_generic_error_t *e = NULL; |
|
|
|
AVBufferRef *buf; |
|
|
|
xcb_shm_seg_t segment; |
|
|
@@ -333,7 +335,8 @@ static int check_xfixes(xcb_connection_t *conn) |
|
|
|
|
|
|
|
static void xcbgrab_draw_mouse(AVFormatContext *s, AVPacket *pkt, |
|
|
|
xcb_query_pointer_reply_t *p, |
|
|
|
xcb_get_geometry_reply_t *geo) |
|
|
|
xcb_get_geometry_reply_t *geo, |
|
|
|
int win_x, int win_y) |
|
|
|
{ |
|
|
|
XCBGrabContext *gr = s->priv_data; |
|
|
|
uint32_t *cursor; |
|
|
@@ -355,17 +358,17 @@ static void xcbgrab_draw_mouse(AVFormatContext *s, AVPacket *pkt, |
|
|
|
cx = ci->x - ci->xhot; |
|
|
|
cy = ci->y - ci->yhot; |
|
|
|
|
|
|
|
x = FFMAX(cx, gr->x); |
|
|
|
y = FFMAX(cy, gr->y); |
|
|
|
x = FFMAX(cx, win_x + gr->x); |
|
|
|
y = FFMAX(cy, win_y + gr->y); |
|
|
|
|
|
|
|
w = FFMIN(cx + ci->width, gr->x + gr->width) - x; |
|
|
|
h = FFMIN(cy + ci->height, gr->y + gr->height) - y; |
|
|
|
w = FFMIN(cx + ci->width, win_x + gr->x + gr->width) - x; |
|
|
|
h = FFMIN(cy + ci->height, win_y + gr->y + gr->height) - y; |
|
|
|
|
|
|
|
c_off = x - cx; |
|
|
|
i_off = x - gr->x; |
|
|
|
i_off = x - gr->x - win_x; |
|
|
|
|
|
|
|
cursor += (y - cy) * ci->width; |
|
|
|
image += (y - gr->y) * gr->width * stride; |
|
|
|
image += (y - gr->y - win_y) * gr->width * stride; |
|
|
|
|
|
|
|
for (y = 0; y < h; y++) { |
|
|
|
cursor += c_off; |
|
|
@@ -400,11 +403,11 @@ static void xcbgrab_draw_mouse(AVFormatContext *s, AVPacket *pkt, |
|
|
|
} |
|
|
|
#endif /* CONFIG_LIBXCB_XFIXES */ |
|
|
|
|
|
|
|
static void xcbgrab_update_region(AVFormatContext *s) |
|
|
|
static void xcbgrab_update_region(AVFormatContext *s, int win_x, int win_y) |
|
|
|
{ |
|
|
|
XCBGrabContext *c = s->priv_data; |
|
|
|
const uint32_t args[] = { c->x - c->region_border, |
|
|
|
c->y - c->region_border }; |
|
|
|
const uint32_t args[] = { win_x + c->x - c->region_border, |
|
|
|
win_y + c->y - c->region_border }; |
|
|
|
|
|
|
|
xcb_configure_window(c->conn, |
|
|
|
c->window, |
|
|
@@ -417,17 +420,20 @@ 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_translate_coordinates_cookie_t tc; |
|
|
|
xcb_query_pointer_reply_t *p = NULL; |
|
|
|
xcb_get_geometry_reply_t *geo = NULL; |
|
|
|
xcb_translate_coordinates_reply_t *translate = NULL; |
|
|
|
int ret = 0; |
|
|
|
int64_t pts; |
|
|
|
int win_x = 0, win_y = 0; |
|
|
|
|
|
|
|
wait_frame(s, pkt); |
|
|
|
pts = av_gettime(); |
|
|
|
|
|
|
|
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); |
|
|
|
pc = xcb_query_pointer(c->conn, c->window_id); |
|
|
|
gc = xcb_get_geometry(c->conn, c->window_id); |
|
|
|
p = xcb_query_pointer_reply(c->conn, pc, NULL); |
|
|
|
if (!p) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to query xcb pointer\n"); |
|
|
@@ -440,12 +446,25 @@ static int xcbgrab_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
} |
|
|
|
} |
|
|
|
if (c->window_id != c->screen->root) { |
|
|
|
tc = xcb_translate_coordinates(c->conn, c->window_id, c->screen->root, 0, 0); |
|
|
|
translate = xcb_translate_coordinates_reply(c->conn, tc, NULL); |
|
|
|
if (!translate) { |
|
|
|
free(p); |
|
|
|
free(geo); |
|
|
|
av_log(s, AV_LOG_ERROR, "Failed to translate xcb geometry\n"); |
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
} |
|
|
|
win_x = translate->dst_x; |
|
|
|
win_y = translate->dst_y; |
|
|
|
free(translate); |
|
|
|
} |
|
|
|
|
|
|
|
if (c->follow_mouse && p->same_screen) |
|
|
|
xcbgrab_reposition(s, p, geo); |
|
|
|
|
|
|
|
if (c->show_region) |
|
|
|
xcbgrab_update_region(s); |
|
|
|
xcbgrab_update_region(s, win_x, win_y); |
|
|
|
|
|
|
|
#if CONFIG_LIBXCB_SHM |
|
|
|
if (c->has_shm && xcbgrab_frame_shm(s, pkt) < 0) { |
|
|
@@ -460,7 +479,7 @@ static int xcbgrab_read_packet(AVFormatContext *s, AVPacket *pkt) |
|
|
|
|
|
|
|
#if CONFIG_LIBXCB_XFIXES |
|
|
|
if (ret >= 0 && c->draw_mouse && p->same_screen) |
|
|
|
xcbgrab_draw_mouse(s, pkt, p, geo); |
|
|
|
xcbgrab_draw_mouse(s, pkt, p, geo, win_x, win_y); |
|
|
|
#endif |
|
|
|
|
|
|
|
free(p); |
|
|
@@ -572,10 +591,12 @@ static int create_stream(AVFormatContext *s) |
|
|
|
|
|
|
|
avpriv_set_pts_info(st, 64, 1, 1000000); |
|
|
|
|
|
|
|
gc = xcb_get_geometry(c->conn, c->screen->root); |
|
|
|
gc = xcb_get_geometry(c->conn, c->window_id); |
|
|
|
geo = xcb_get_geometry_reply(c->conn, gc, NULL); |
|
|
|
if (!geo) |
|
|
|
if (!geo) { |
|
|
|
av_log(s, AV_LOG_ERROR, "Can't find window '0x%x', aborting.\n", c->window_id); |
|
|
|
return AVERROR_EXTERNAL; |
|
|
|
} |
|
|
|
|
|
|
|
if (!c->width || !c->height) { |
|
|
|
c->width = geo->width; |
|
|
@@ -831,6 +852,19 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s) |
|
|
|
return AVERROR(EIO); |
|
|
|
} |
|
|
|
|
|
|
|
if (c->window_id == XCB_NONE) |
|
|
|
c->window_id = c->screen->root; |
|
|
|
else { |
|
|
|
if (c->select_region) { |
|
|
|
av_log(s, AV_LOG_WARNING, "select_region ignored with window_id.\n"); |
|
|
|
c->select_region = 0; |
|
|
|
} |
|
|
|
if (c->follow_mouse) { |
|
|
|
av_log(s, AV_LOG_WARNING, "follow_mouse ignored with window_id.\n"); |
|
|
|
c->follow_mouse = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (c->select_region) { |
|
|
|
ret = select_region(s); |
|
|
|
if (ret < 0) { |
|
|
|