@ -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 ) {