Commit e8534473 authored by Laurent Aimar's avatar Laurent Aimar

Converted vout xcb to "vout display" API.

parent c48d9cfc
...@@ -34,11 +34,27 @@ ...@@ -34,11 +34,27 @@
#include <xcb/shm.h> #include <xcb/shm.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_vout.h> #include <vlc_vout_display.h>
#include <vlc_vout_window.h>
#include "xcb_vlc.h" #include "xcb_vlc.h"
/**
* Check for an error
*/
int CheckError (vout_display_t *vd, xcb_connection_t *conn,
const char *str, xcb_void_cookie_t ck)
{
xcb_generic_error_t *err;
err = xcb_request_check (conn, ck);
if (err)
{
msg_Err (vd, "%s: X11 error %d", str, err->error_code);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/** /**
* Connect to the X server. * Connect to the X server.
*/ */
...@@ -62,7 +78,7 @@ xcb_connection_t *Connect (vlc_object_t *obj) ...@@ -62,7 +78,7 @@ xcb_connection_t *Connect (vlc_object_t *obj)
* Create a VLC video X window object, find the corresponding X server screen, * Create a VLC video X window object, find the corresponding X server screen,
* and probe the MIT-SHM extension. * and probe the MIT-SHM extension.
*/ */
vout_window_t *GetWindow (vout_thread_t *obj, vout_window_t *GetWindow (vout_display_t *vd,
xcb_connection_t *conn, xcb_connection_t *conn,
const xcb_screen_t **restrict pscreen, const xcb_screen_t **restrict pscreen,
bool *restrict pshm) bool *restrict pshm)
...@@ -73,14 +89,13 @@ vout_window_t *GetWindow (vout_thread_t *obj, ...@@ -73,14 +89,13 @@ vout_window_t *GetWindow (vout_thread_t *obj,
memset( &wnd_cfg, 0, sizeof(wnd_cfg) ); memset( &wnd_cfg, 0, sizeof(wnd_cfg) );
wnd_cfg.type = VOUT_WINDOW_TYPE_XID; wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
wnd_cfg.width = obj->i_window_width; wnd_cfg.width = vd->cfg->display.width;
wnd_cfg.height = obj->i_window_height; wnd_cfg.height = vd->cfg->display.height;
vout_window_t *wnd = vout_window_New (VLC_OBJECT(obj), NULL, &wnd_cfg);
vout_window_t *wnd = vout_display_NewWindow (vd, &wnd_cfg);
if (wnd == NULL) if (wnd == NULL)
{ {
msg_Err (obj, "parent window not available"); msg_Err (vd, "parent window not available");
return NULL; return NULL;
} }
else else
...@@ -92,7 +107,7 @@ vout_window_t *GetWindow (vout_thread_t *obj, ...@@ -92,7 +107,7 @@ vout_window_t *GetWindow (vout_thread_t *obj,
geo = xcb_get_geometry_reply (conn, ck, NULL); geo = xcb_get_geometry_reply (conn, ck, NULL);
if (geo == NULL) if (geo == NULL)
{ {
msg_Err (obj, "parent window not valid"); msg_Err (vd, "parent window not valid");
goto error; goto error;
} }
root = geo->root; root = geo->root;
...@@ -116,13 +131,13 @@ vout_window_t *GetWindow (vout_thread_t *obj, ...@@ -116,13 +131,13 @@ vout_window_t *GetWindow (vout_thread_t *obj,
if (screen == NULL) if (screen == NULL)
{ {
msg_Err (obj, "parent window screen not found"); msg_Err (vd, "parent window screen not found");
goto error; goto error;
} }
msg_Dbg (obj, "using screen 0x%"PRIx32, root); msg_Dbg (vd, "using screen 0x%"PRIx32, root);
/* Check MIT-SHM shared memory support */ /* Check MIT-SHM shared memory support */
bool shm = var_CreateGetBool (obj, "x11-shm") > 0; bool shm = var_CreateGetBool (vd, "x11-shm") > 0;
if (shm) if (shm)
{ {
xcb_shm_query_version_cookie_t ck; xcb_shm_query_version_cookie_t ck;
...@@ -132,8 +147,8 @@ vout_window_t *GetWindow (vout_thread_t *obj, ...@@ -132,8 +147,8 @@ vout_window_t *GetWindow (vout_thread_t *obj,
r = xcb_shm_query_version_reply (conn, ck, NULL); r = xcb_shm_query_version_reply (conn, ck, NULL);
if (!r) if (!r)
{ {
msg_Err (obj, "shared memory (MIT-SHM) not available"); msg_Err (vd, "shared memory (MIT-SHM) not available");
msg_Warn (obj, "display will be slow"); msg_Warn (vd, "display will be slow");
shm = false; shm = false;
} }
free (r); free (r);
...@@ -144,7 +159,7 @@ vout_window_t *GetWindow (vout_thread_t *obj, ...@@ -144,7 +159,7 @@ vout_window_t *GetWindow (vout_thread_t *obj,
return wnd; return wnd;
error: error:
vout_window_Delete (wnd); vout_display_DeleteWindow (vd, wnd);
return NULL; return NULL;
} }
...@@ -168,19 +183,22 @@ int GetWindowSize (struct vout_window_t *wnd, xcb_connection_t *conn, ...@@ -168,19 +183,22 @@ int GetWindowSize (struct vout_window_t *wnd, xcb_connection_t *conn,
/** /**
* Initialize a picture buffer as shared memory, according to the video output * Initialize a picture buffer as shared memory, according to the video output
* format. If a XCB connection pointer is supplied, the segment is attached to * format. If a attach is true, the segment is attached to
* the X server (MIT-SHM extension). * the X server (MIT-SHM extension).
*/ */
int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size, int PictureResourceAlloc (vout_display_t *vd, picture_resource_t *res, size_t size,
xcb_connection_t *conn) xcb_connection_t *conn, bool attach)
{ {
assert (pic->i_status == FREE_PICTURE); res->p_sys = malloc (sizeof(*res->p_sys));
if (!res->p_sys)
return VLC_EGENERIC;
/* Allocate shared memory segment */ /* Allocate shared memory segment */
int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700); int id = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700);
if (id == -1) if (id == -1)
{ {
msg_Err (vout, "shared memory allocation error: %m"); msg_Err (vd, "shared memory allocation error: %m");
free (res->p_sys);
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -188,13 +206,14 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size, ...@@ -188,13 +206,14 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size,
void *shm = shmat (id, NULL, 0 /* read/write */); void *shm = shmat (id, NULL, 0 /* read/write */);
if (-1 == (intptr_t)shm) if (-1 == (intptr_t)shm)
{ {
msg_Err (vout, "shared memory attachment error: %m"); msg_Err (vd, "shared memory attachment error: %m");
shmctl (id, IPC_RMID, 0); shmctl (id, IPC_RMID, 0);
free (res->p_sys);
return VLC_EGENERIC; return VLC_EGENERIC;
} }
xcb_shm_seg_t segment; xcb_shm_seg_t segment;
if (conn != NULL) if (attach)
{ {
/* Attach the segment to X */ /* Attach the segment to X */
xcb_void_cookie_t ck; xcb_void_cookie_t ck;
...@@ -202,9 +221,9 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size, ...@@ -202,9 +221,9 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size,
segment = xcb_generate_id (conn); segment = xcb_generate_id (conn);
ck = xcb_shm_attach_checked (conn, segment, id, 1); ck = xcb_shm_attach_checked (conn, segment, id, 1);
if (CheckError (vout, "shared memory server-side error", ck)) if (CheckError (vd, conn, "shared memory server-side error", ck))
{ {
msg_Info (vout, "using buggy X11 server - SSH proxying?"); msg_Info (vd, "using buggy X11 server - SSH proxying?");
segment = 0; segment = 0;
} }
} }
...@@ -212,67 +231,23 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size, ...@@ -212,67 +231,23 @@ int PictureAlloc (vout_thread_t *vout, picture_t *pic, size_t size,
segment = 0; segment = 0;
shmctl (id, IPC_RMID, 0); shmctl (id, IPC_RMID, 0);
pic->p_sys = (void *)(uintptr_t)segment; res->p_sys->segment = segment;
pic->p->p_pixels = shm; res->p->p_pixels = shm;
pic->i_status = DESTROYED_PICTURE;
pic->i_type = DIRECT_PICTURE;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/** /**
* Release picture private data: detach the shared memory segment. * Release picture private data: detach the shared memory segment.
*/ */
void PictureFree (picture_t *pic, xcb_connection_t *conn) void PictureResourceFree (picture_resource_t *res, xcb_connection_t *conn)
{ {
xcb_shm_seg_t segment = (uintptr_t)pic->p_sys; xcb_shm_seg_t segment = res->p_sys->segment;
if (segment != 0) if (segment != 0)
{ {
assert (conn != NULL); assert (conn != NULL);
xcb_shm_detach (conn, segment); xcb_shm_detach (conn, segment);
} }
shmdt (pic->p->p_pixels); shmdt (res->p->p_pixels);
} }
/**
* Video output thread management stuff.
* FIXME: Much of this should move to core
*/
void CommonManage (vout_thread_t *vout)
{
if (vout->i_changes & VOUT_SCALE_CHANGE)
{
vout->b_autoscale = var_GetBool (vout, "autoscale");
vout->i_zoom = ZOOM_FP_FACTOR;
vout->i_changes &= ~VOUT_SCALE_CHANGE;
vout->i_changes |= VOUT_SIZE_CHANGE;
}
if (vout->i_changes & VOUT_ZOOM_CHANGE)
{
vout->b_autoscale = false;
vout->i_zoom = var_GetFloat (vout, "scale") * ZOOM_FP_FACTOR;
vout->i_changes &= ~VOUT_ZOOM_CHANGE;
vout->i_changes |= VOUT_SIZE_CHANGE;
}
if (vout->i_changes & VOUT_CROP_CHANGE)
{
vout->fmt_out.i_x_offset = vout->fmt_in.i_x_offset;
vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset;
vout->fmt_out.i_visible_width = vout->fmt_in.i_visible_width;
vout->fmt_out.i_visible_height = vout->fmt_in.i_visible_height;
vout->i_changes &= ~VOUT_CROP_CHANGE;
vout->i_changes |= VOUT_SIZE_CHANGE;
}
if (vout->i_changes & VOUT_ASPECT_CHANGE)
{
vout->fmt_out.i_aspect = vout->fmt_in.i_aspect;
vout->fmt_out.i_sar_num = vout->fmt_in.i_sar_num;
vout->fmt_out.i_sar_den = vout->fmt_in.i_sar_den;
vout->output.i_aspect = vout->fmt_in.i_aspect;
vout->i_changes &= ~VOUT_ASPECT_CHANGE;
vout->i_changes |= VOUT_SIZE_CHANGE;
}
}
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <xcb/xcb.h> #include <xcb/xcb.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_vout.h> #include <vlc_vout_display.h>
#include "xcb_vlc.h" #include "xcb_vlc.h"
...@@ -39,76 +39,67 @@ ...@@ -39,76 +39,67 @@
* Otherwise, we'd var_OrInteger() and var_NandInteger() functions... * Otherwise, we'd var_OrInteger() and var_NandInteger() functions...
*/ */
static void HandleButtonPress (vout_thread_t *vout, /* FIXME we assume direct mapping between XCB and VLC */
static void HandleButtonPress (vout_display_t *vd,
xcb_button_press_event_t *ev) xcb_button_press_event_t *ev)
{ {
unsigned buttons = var_GetInteger (vout, "mouse-button-down"); vout_display_SendEventMousePressed (vd, ev->detail - 1);
buttons |= (1 << (ev->detail - 1));
var_SetInteger (vout, "mouse-button-down", buttons);
} }
static void HandleButtonRelease (vout_thread_t *vout, static void HandleButtonRelease (vout_display_t *vd,
xcb_button_release_event_t *ev) xcb_button_release_event_t *ev)
{ {
unsigned buttons = var_GetInteger (vout, "mouse-button-down"); vout_display_SendEventMouseReleased (vd, ev->detail - 1);
buttons &= ~(1 << (ev->detail - 1));
var_SetInteger (vout, "mouse-button-down", buttons);
switch (ev->detail)
{
case 1: /* left mouse button */
var_SetBool (vout, "mouse-clicked", true);
var_SetBool (vout->p_libvlc, "intf-popupmenu", false);
break;
case 3:
var_SetBool (vout->p_libvlc, "intf-popupmenu", true);
break;
}
} }
static void HandleMotionNotify (vout_thread_t *vout, static void HandleMotionNotify (vout_display_t *vd,
xcb_motion_notify_event_t *ev) xcb_motion_notify_event_t *ev)
{ {
unsigned x, y, width, height; vout_display_place_t place;
int v;
/* TODO it could be saved */
vout_PlacePicture (vout, vout->output.i_width, vout->output.i_height, vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
&x, &y, &width, &height);
v = vout->fmt_in.i_x_offset if (place.width <= 0 || place.height <= 0)
+ ((ev->event_x - x) * vout->fmt_in.i_visible_width / width); return;
if (v < 0)
v = 0; /* to the left of the picture */ const int x = vd->source.i_x_offset +
else if ((unsigned)v > vout->fmt_in.i_width) (int64_t)(ev->event_x -0*place.x) * vd->source.i_visible_width / place.width;
v = vout->fmt_in.i_width; /* to the right of the picture */ const int y = vd->source.i_y_offset +
var_SetInteger (vout, "mouse-x", v); (int64_t)(ev->event_y -0*place.y) * vd->source.i_visible_height/ place.height;
v = vout->fmt_in.i_y_offset /* TODO show the cursor ? */
+ ((ev->event_y - y) * vout->fmt_in.i_visible_height / height); if (x >= vd->source.i_x_offset && x < vd->source.i_x_offset + vd->source.i_visible_width &&
if (v < 0) y >= vd->source.i_y_offset && y < vd->source.i_y_offset + vd->source.i_visible_height)
v = 0; /* above the picture */ vout_display_SendEventMouseMoved (vd, x, y);
else if ((unsigned)v > vout->fmt_in.i_height) }
v = vout->fmt_in.i_height; /* below the picture */
var_SetInteger (vout, "mouse-y", v); static void
HandleParentStructure (vout_display_t *vd, xcb_configure_notify_event_t *ev)
{
if (ev->width != vd->cfg->display.width ||
ev->height != vd->cfg->display.height)
vout_display_SendEventDisplaySize (vd, ev->width, ev->height);
} }
/** /**
* Process an X11 event. * Process an X11 event.
*/ */
int ProcessEvent (vout_thread_t *vout, xcb_connection_t *conn, static int ProcessEvent (vout_display_t *vd,
xcb_window_t window, xcb_generic_event_t *ev) xcb_window_t window, xcb_generic_event_t *ev)
{ {
switch (ev->response_type & 0x7f) switch (ev->response_type & 0x7f)
{ {
case XCB_BUTTON_PRESS: case XCB_BUTTON_PRESS:
HandleButtonPress (vout, (xcb_button_press_event_t *)ev); HandleButtonPress (vd, (xcb_button_press_event_t *)ev);
break; break;
case XCB_BUTTON_RELEASE: case XCB_BUTTON_RELEASE:
HandleButtonRelease (vout, (xcb_button_release_event_t *)ev); HandleButtonRelease (vd, (xcb_button_release_event_t *)ev);
break; break;
case XCB_MOTION_NOTIFY: case XCB_MOTION_NOTIFY:
HandleMotionNotify (vout, (xcb_motion_notify_event_t *)ev); HandleMotionNotify (vd, (xcb_motion_notify_event_t *)ev);
break; break;
case XCB_CONFIGURE_NOTIFY: case XCB_CONFIGURE_NOTIFY:
...@@ -117,14 +108,41 @@ int ProcessEvent (vout_thread_t *vout, xcb_connection_t *conn, ...@@ -117,14 +108,41 @@ int ProcessEvent (vout_thread_t *vout, xcb_connection_t *conn,
(xcb_configure_notify_event_t *)ev; (xcb_configure_notify_event_t *)ev;
assert (cn->window != window); assert (cn->window != window);
HandleParentStructure (vout, conn, window, cn); HandleParentStructure (vd, cn);
break; break;
} }
/* FIXME I am not sure it is the right one */
case XCB_DESTROY_NOTIFY:
vout_display_SendEventClose (vd);
break;
default: default:
msg_Dbg (vout, "unhandled event %"PRIu8, ev->response_type); msg_Dbg (vd, "unhandled event %"PRIu8, ev->response_type);
} }
free (ev); free (ev);
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/**
* Process incoming X events.
*/
int ManageEvent (vout_display_t *vd, xcb_connection_t *conn, xcb_window_t window)
{
xcb_generic_event_t *ev;
while ((ev = xcb_poll_for_event (conn)) != NULL)
ProcessEvent (vd, window, ev);
if (xcb_connection_has_error (conn))
{
msg_Err (vd, "X server failure");
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
...@@ -32,8 +32,8 @@ ...@@ -32,8 +32,8 @@
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_vout.h> #include <vlc_vout_display.h>
#include <vlc_vout_window.h> #include <vlc_picture_pool.h>
#include "xcb_vlc.h" #include "xcb_vlc.h"
...@@ -57,7 +57,7 @@ vlc_module_begin () ...@@ -57,7 +57,7 @@ vlc_module_begin ()
set_description (N_("(Experimental) XCB video output")) set_description (N_("(Experimental) XCB video output"))
set_category (CAT_VIDEO) set_category (CAT_VIDEO)
set_subcategory (SUBCAT_VIDEO_VOUT) set_subcategory (SUBCAT_VIDEO_VOUT)
set_capability ("video output", 0) set_capability ("vout display", 0)
set_callbacks (Open, Close) set_callbacks (Open, Close)
add_string ("x11-display", NULL, NULL, add_string ("x11-display", NULL, NULL,
...@@ -65,7 +65,13 @@ vlc_module_begin () ...@@ -65,7 +65,13 @@ vlc_module_begin ()
add_bool ("x11-shm", true, NULL, SHM_TEXT, SHM_LONGTEXT, true) add_bool ("x11-shm", true, NULL, SHM_TEXT, SHM_LONGTEXT, true)
vlc_module_end () vlc_module_end ()
struct vout_sys_t /* It must be large enough to absorb the server display jitter but it is
* useless to used a too large value, direct rendering cannot be used with
* xcb x11
*/
#define MAX_PICTURES (3)
struct vout_display_sys_t
{ {
xcb_connection_t *conn; xcb_connection_t *conn;
vout_window_t *embed; /* VLC window (when windowed) */ vout_window_t *embed; /* VLC window (when windowed) */
...@@ -77,40 +83,29 @@ struct vout_sys_t ...@@ -77,40 +83,29 @@ struct vout_sys_t
uint8_t pad; /* scanline pad */ uint8_t pad; /* scanline pad */
uint8_t depth; /* useful bits per pixel */ uint8_t depth; /* useful bits per pixel */
uint8_t byte_order; /* server byte order */ uint8_t byte_order; /* server byte order */
};
static int Init (vout_thread_t *); picture_pool_t *pool; /* picture pool */
static void Deinit (vout_thread_t *); picture_resource_t resource[MAX_PICTURES];
static void Display (vout_thread_t *, picture_t *); };
static int Manage (vout_thread_t *);
static int Control (vout_thread_t *, int, va_list);
int CheckError (vout_thread_t *vout, const char *str, xcb_void_cookie_t ck)
{
xcb_generic_error_t *err;
err = xcb_request_check (vout->p_sys->conn, ck); static picture_t *Get (vout_display_t *);
if (err) static void Display (vout_display_t *, picture_t *);
{ static int Control (vout_display_t *, int, va_list);
msg_Err (vout, "%s: X11 error %d", str, err->error_code); static void Manage (vout_display_t *);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
#define p_vout vout static void ResetPictures (vout_display_t *);
/** /**
* Probe the X server. * Probe the X server.
*/ */
static int Open (vlc_object_t *obj) static int Open (vlc_object_t *obj)
{ {
vout_thread_t *vout = (vout_thread_t *)obj; vout_display_t *vd = (vout_display_t *)obj;
vout_sys_t *p_sys = malloc (sizeof (*p_sys)); vout_display_sys_t *p_sys = malloc (sizeof (*p_sys));
if (p_sys == NULL) if (p_sys == NULL)
return VLC_ENOMEM; return VLC_ENOMEM;
vout->p_sys = p_sys; vd->sys = p_sys;
/* Connect to X */ /* Connect to X */
p_sys->conn = Connect (obj); p_sys->conn = Connect (obj);
...@@ -122,7 +117,7 @@ static int Open (vlc_object_t *obj) ...@@ -122,7 +117,7 @@ static int Open (vlc_object_t *obj)
/* Get window */ /* Get window */
const xcb_screen_t *scr; const xcb_screen_t *scr;
p_sys->embed = GetWindow (vout, p_sys->conn, &scr, &p_sys->shm); p_sys->embed = GetWindow (vd, p_sys->conn, &scr, &p_sys->shm);
if (p_sys->embed == NULL) if (p_sys->embed == NULL)
{ {
xcb_disconnect (p_sys->conn); xcb_disconnect (p_sys->conn);
...@@ -133,6 +128,9 @@ static int Open (vlc_object_t *obj) ...@@ -133,6 +128,9 @@ static int Open (vlc_object_t *obj)
const xcb_setup_t *setup = xcb_get_setup (p_sys->conn); const xcb_setup_t *setup = xcb_get_setup (p_sys->conn);
p_sys->byte_order = setup->image_byte_order; p_sys->byte_order = setup->image_byte_order;
/* */
video_format_t fmt_pic = vd->fmt;
/* Determine our video format. Normally, this is done in pf_init(), but /* Determine our video format. Normally, this is done in pf_init(), but
* this plugin always uses the same format for a given X11 screen. */ * this plugin always uses the same format for a given X11 screen. */
xcb_visualid_t vid = 0; xcb_visualid_t vid = 0;
...@@ -213,12 +211,12 @@ static int Open (vlc_object_t *obj) ...@@ -213,12 +211,12 @@ static int Open (vlc_object_t *obj)
if (!vid) if (!vid)
continue; /* The screen does not *really* support this depth */ continue; /* The screen does not *really* support this depth */
vout->fmt_out.i_chroma = vout->output.i_chroma = chroma; fmt_pic.i_chroma = chroma;
if (!gray) if (!gray)
{ {
vout->fmt_out.i_rmask = vout->output.i_rmask = vt->red_mask; fmt_pic.i_rmask = vt->red_mask;
vout->fmt_out.i_gmask = vout->output.i_gmask = vt->green_mask; fmt_pic.i_gmask = vt->green_mask;
vout->fmt_out.i_bmask = vout->output.i_bmask = vt->blue_mask; fmt_pic.i_bmask = vt->blue_mask;
} }
p_sys->bpp = fmt->bits_per_pixel; p_sys->bpp = fmt->bits_per_pixel;
p_sys->pad = fmt->scanline_pad; p_sys->pad = fmt->scanline_pad;
...@@ -227,12 +225,12 @@ static int Open (vlc_object_t *obj) ...@@ -227,12 +225,12 @@ static int Open (vlc_object_t *obj)
if (depth == 0) if (depth == 0)
{ {
msg_Err (vout, "no supported pixmap formats or visual types"); msg_Err (vd, "no supported pixmap formats or visual types");
goto error; goto error;
} }
msg_Dbg (vout, "using X11 visual ID 0x%"PRIx32, vid); msg_Dbg (vd, "using X11 visual ID 0x%"PRIx32, vid);
msg_Dbg (vout, " %"PRIu8" bits per pixels, %"PRIu8" bits line pad", msg_Dbg (vd, " %"PRIu8" bits per pixels, %"PRIu8" bits line pad",
p_sys->bpp, p_sys->pad); p_sys->bpp, p_sys->pad);
/* Create colormap (needed to select non-default visual) */ /* Create colormap (needed to select non-default visual) */
...@@ -263,23 +261,41 @@ static int Open (vlc_object_t *obj) ...@@ -263,23 +261,41 @@ static int Open (vlc_object_t *obj)
p_sys->embed->handle.xid, 0, 0, 1, 1, 0, p_sys->embed->handle.xid, 0, 0, 1, 1, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_WINDOW_CLASS_INPUT_OUTPUT,
vid, mask, values); vid, mask, values);
if (CheckError (vout, "cannot create X11 window", c)) if (CheckError (vd, p_sys->conn, "cannot create X11 window", c))
goto error; goto error;
p_sys->window = window; p_sys->window = window;
msg_Dbg (vout, "using X11 window %08"PRIx32, p_sys->window); msg_Dbg (vd, "using X11 window %08"PRIx32, p_sys->window);
xcb_map_window (p_sys->conn, window); xcb_map_window (p_sys->conn, window);
} }
/* Create graphic context (I wonder why the heck do we need this) */ /* Create graphic context (I wonder why the heck do we need this) */
p_sys->gc = xcb_generate_id (p_sys->conn); p_sys->gc = xcb_generate_id (p_sys->conn);
xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL); xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);
msg_Dbg (vout, "using X11 graphic context %08"PRIx32, p_sys->gc); msg_Dbg (vd, "using X11 graphic context %08"PRIx32, p_sys->gc);
/* */
p_sys->pool = NULL;
/* */
vout_display_info_t info = vd->info;
info.has_pictures_invalid = true;
/* Setup vout_display_t once everything is fine */
vd->fmt = fmt_pic;
vd->info = info;
vd->get = Get;
vd->prepare = NULL;
vd->display = Display;
vd->control = Control;
vd->manage = Manage;
/* */
unsigned width, height;
if (!GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
vout_display_SendEventDisplaySize (vd, width, height);
vout_display_SendEventFullscreen (vd, false);
vout->pf_init = Init;
vout->pf_end = Deinit;
vout->pf_display = Display;
vout->pf_manage = Manage;
vout->pf_control = Control;
return VLC_SUCCESS; return VLC_SUCCESS;
error: error:
...@@ -293,174 +309,219 @@ error: ...@@ -293,174 +309,219 @@ error:
*/ */
static void Close (vlc_object_t *obj) static void Close (vlc_object_t *obj)
{ {
vout_thread_t *vout = (vout_thread_t *)obj; vout_display_t *vd = (vout_display_t *)obj;
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
vout_window_Delete (p_sys->embed); ResetPictures (vd);
vout_display_DeleteWindow (vd, p_sys->embed);
/* colormap and window are garbage-collected by X */ /* colormap and window are garbage-collected by X */
xcb_disconnect (p_sys->conn); xcb_disconnect (p_sys->conn);
free (p_sys); free (p_sys);
} }
/** /**
* Allocate drawable window and picture buffers. * Return a direct buffer
*/ */
static int Init (vout_thread_t *vout) static picture_t *Get (vout_display_t *vd)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
unsigned x, y, width, height;
if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height)) if (!p_sys->pool)
return VLC_EGENERIC;
vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
const uint32_t values[] = { x, y, width, height, };
xcb_configure_window (p_sys->conn, p_sys->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
/* FIXME: I don't get the subtlety between output and fmt_out here */
vout->fmt_out.i_visible_width = width;
vout->fmt_out.i_visible_height = height;
vout->fmt_out.i_sar_num = vout->fmt_out.i_sar_den = 1;
vout->output.i_width = vout->fmt_out.i_width =
width * vout->fmt_in.i_width / vout->fmt_in.i_visible_width;
vout->output.i_height = vout->fmt_out.i_height =
height * vout->fmt_in.i_height / vout->fmt_in.i_visible_height;
vout->fmt_out.i_x_offset =
width * vout->fmt_in.i_x_offset / vout->fmt_in.i_visible_width;
p_vout->fmt_out.i_y_offset =
height * vout->fmt_in.i_y_offset / vout->fmt_in.i_visible_height;
assert (height > 0);
vout->output.i_aspect = vout->fmt_out.i_aspect =
width * VOUT_ASPECT_FACTOR / height;
/* Allocate picture buffers */
I_OUTPUTPICTURES = 0;
for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
{ {
picture_t *pic = vout->p_picture + index; vout_display_place_t place;
if (index > sizeof (vout->p_picture) / sizeof (pic)) vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
break;
if (pic->i_status != FREE_PICTURE)
continue;
picture_Setup (pic, vout->output.i_chroma, /* */
vout->output.i_width, vout->output.i_height, const uint32_t values[] = { place.x, place.y, place.width, place.height };
vout->output.i_aspect); xcb_configure_window (p_sys->conn, p_sys->window,
if (PictureAlloc (vout, pic, pic->p->i_pitch * pic->p->i_lines, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
p_sys->shm ? p_sys->conn : NULL)) XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
break; values);
PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic;
picture_t *pic = picture_NewFromFormat (&vd->fmt);
if (!pic)
return NULL;
assert (pic->i_planes == 1);
memset (p_sys->resource, 0, sizeof(p_sys->resource));
unsigned count;
picture_t *pic_array[MAX_PICTURES];
for (count = 0; count < MAX_PICTURES; count++)
{
picture_resource_t *res = &p_sys->resource[count];
res->p->i_lines = pic->p->i_lines;
res->p->i_pitch = pic->p->i_pitch;
if (PictureResourceAlloc (vd, res, res->p->i_pitch * res->p->i_lines,
p_sys->conn, p_sys->shm))
break;
pic_array[count] = picture_NewFromResource (&vd->fmt, res);
if (!pic_array[count])
{
PictureResourceFree (res, p_sys->conn);
memset (res, 0, sizeof(*res));
break;
}
}
picture_Release (pic);
if (count == 0)
return NULL;
p_sys->pool = picture_pool_New (count, pic_array);
if (!p_sys->pool)
{
/* TODO release picture resources */
return NULL;
}
/* FIXME should also do it in case of error ? */
xcb_flush (p_sys->conn);
} }
xcb_flush (p_sys->conn);
return VLC_SUCCESS;
}
/** return picture_pool_Get (p_sys->pool);
* Free picture buffers.
*/
static void Deinit (vout_thread_t *vout)
{
for (int i = 0; i < I_OUTPUTPICTURES; i++)
PictureFree (PP_OUTPUTPICTURE[i], vout->p_sys->conn);
} }
/** /**
* Sends an image to the X server. * Sends an image to the X server.
*/ */
static void Display (vout_thread_t *vout, picture_t *pic) static void Display (vout_display_t *vd, picture_t *pic)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
xcb_shm_seg_t segment = (uintptr_t)pic->p_sys; xcb_shm_seg_t segment = pic->p_sys->segment;
if (segment != 0) if (segment != 0)
xcb_shm_put_image (p_sys->conn, p_sys->window, p_sys->gc, xcb_shm_put_image (p_sys->conn, p_sys->window, p_sys->gc,
/* real width */ pic->p->i_pitch / pic->p->i_pixel_pitch, /* real width */ pic->p->i_pitch / pic->p->i_pixel_pitch,
/* real height */ pic->p->i_lines, /* real height */ pic->p->i_lines,
/* x */ vout->fmt_out.i_x_offset, /* x */ vd->fmt.i_x_offset,
/* y */ vout->fmt_out.i_y_offset, /* y */ vd->fmt.i_y_offset,
/* width */ vout->fmt_out.i_visible_width, /* width */ vd->fmt.i_visible_width,
/* height */ vout->fmt_out.i_visible_height, /* height */ vd->fmt.i_visible_height,
0, 0, p_sys->depth, XCB_IMAGE_FORMAT_Z_PIXMAP, 0, 0, p_sys->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
0, segment, 0); 0, segment, 0);
else else
{ {
const size_t offset = vout->fmt_out.i_y_offset * pic->p->i_pitch; const size_t offset = vd->fmt.i_y_offset * pic->p->i_pitch;
const unsigned lines = pic->p->i_lines - vout->fmt_out.i_y_offset; const unsigned lines = pic->p->i_lines - vd->fmt.i_y_offset;
xcb_put_image (p_sys->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, xcb_put_image (p_sys->conn, XCB_IMAGE_FORMAT_Z_PIXMAP,
p_sys->window, p_sys->gc, p_sys->window, p_sys->gc,
pic->p->i_pitch / pic->p->i_pixel_pitch, pic->p->i_pitch / pic->p->i_pixel_pitch,
lines, -vout->fmt_out.i_x_offset, 0, 0, p_sys->depth, lines, -vd->fmt.i_x_offset, 0, 0, p_sys->depth,
pic->p->i_pitch * lines, pic->p->p_pixels + offset); pic->p->i_pitch * lines, pic->p->p_pixels + offset);
} }
xcb_flush (p_sys->conn); xcb_flush (p_sys->conn);
/* FIXME might be WAY better to wait in some case (be carefull with
* VOUT_DISPLAY_RESET_PICTURES if done) + does not work with
* vout_display wrapper. */
picture_Release (pic);
} }
/** static int Control (vout_display_t *vd, int query, va_list ap)
* Process incoming X events.
*/
static int Manage (vout_thread_t *vout)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
xcb_generic_event_t *ev;
while ((ev = xcb_poll_for_event (p_sys->conn)) != NULL)
ProcessEvent (vout, p_sys->conn, p_sys->window, ev);
if (xcb_connection_has_error (p_sys->conn)) switch (query)
{ {
msg_Err (vout, "X server failure"); case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
return VLC_EGENERIC; {
} const vout_display_cfg_t *p_cfg =
(const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *);
CommonManage (vout); /* FIXME: <-- move that to core */ if (vout_window_SetSize (p_sys->embed,
return VLC_SUCCESS; p_cfg->display.width,
} p_cfg->display.height))
return VLC_EGENERIC;
void vout_display_place_t place;
HandleParentStructure (vout_thread_t *vout, xcb_connection_t *conn, vout_display_PlacePicture (&place, &vd->source, p_cfg, false);
xcb_window_t xid, xcb_configure_notify_event_t *ev)
{
unsigned width, height, x, y;
vout_PlacePicture (vout, ev->width, ev->height, &x, &y, &width, &height); if (place.width != vd->fmt.i_visible_width ||
if (width != vout->fmt_out.i_visible_width place.height != vd->fmt.i_visible_height)
|| height != vout->fmt_out.i_visible_height) {
vout_display_SendEventPicturesInvalid (vd);
return VLC_SUCCESS;
}
/* Move the picture within the window */
const uint32_t values[] = { place.x, place.y };
xcb_configure_window (p_sys->conn, p_sys->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
values);
return VLC_SUCCESS;
}
case VOUT_DISPLAY_CHANGE_ON_TOP:
{ {
vout->i_changes |= VOUT_SIZE_CHANGE; int b_on_top = (int)va_arg (ap, int);
return; /* vout will be reinitialized */ return vout_window_SetOnTop (p_sys->embed, b_on_top);
} }
/* Move the picture within the window */ case VOUT_DISPLAY_CHANGE_ZOOM:
const uint32_t values[] = { x, y, }; case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
xcb_configure_window (conn, xid, case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
values); /* I am not sure it is always necessary, but it is way simpler ... */
} vout_display_SendEventPicturesInvalid (vd);
return VLC_SUCCESS;
static int Control (vout_thread_t *vout, int query, va_list ap) case VOUT_DISPLAY_RESET_PICTURES:
{
switch (query)
{ {
case VOUT_SET_SIZE: ResetPictures (vd);
{
const unsigned width = va_arg (ap, unsigned); vout_display_place_t place;
const unsigned height = va_arg (ap, unsigned); vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
return vout_window_SetSize (vout->p_sys->embed, width, height);
} vd->fmt.i_width = vd->source.i_width * place.width / vd->source.i_visible_width;
case VOUT_SET_STAY_ON_TOP: vd->fmt.i_height = vd->source.i_height * place.height / vd->source.i_visible_height;
{
const bool is_on_top = va_arg (ap, int); vd->fmt.i_visible_width = place.width;
return vout_window_SetOnTop (vout->p_sys->embed, is_on_top); vd->fmt.i_visible_height = place.height;
vd->fmt.i_x_offset = vd->source.i_x_offset * place.width / vd->source.i_visible_width;
vd->fmt.i_y_offset = vd->source.i_y_offset * place.height / vd->source.i_visible_height;
return VLC_SUCCESS;
} }
/* TODO */
#if 0
/* Hide the mouse. It will be send when
* vout_display_t::info.b_hide_mouse is false */
VOUT_DISPLAY_HIDE_MOUSE,
/* Ask the module to acknowledge/refuse the fullscreen state change after
* being requested (externaly or by VOUT_DISPLAY_EVENT_FULLSCREEN */
VOUT_DISPLAY_CHANGE_FULLSCREEN, /* const vout_display_cfg_t *p_cfg */
#endif
default: default:
msg_Err (vd, "Unknown request in XCB vout display");
return VLC_EGENERIC; return VLC_EGENERIC;
} }
} }
static void Manage (vout_display_t *vd)
{
vout_display_sys_t *p_sys = vd->sys;
ManageEvent (vd, p_sys->conn, p_sys->window);
}
static void ResetPictures (vout_display_t *vd)
{
vout_display_sys_t *p_sys = vd->sys;
if (!p_sys->pool)
return;
for (unsigned i = 0; i < MAX_PICTURES; i++)
{
picture_resource_t *res = &p_sys->resource[i];
if (!res->p->p_pixels)
break;
PictureResourceFree (res, p_sys->conn);
}
picture_pool_Delete (p_sys->pool);
p_sys->pool = NULL;
}
...@@ -26,12 +26,10 @@ ...@@ -26,12 +26,10 @@
# define ORDER XCB_IMAGE_ORDER_LSB_FIRST # define ORDER XCB_IMAGE_ORDER_LSB_FIRST
#endif #endif
int CheckError (vout_thread_t *, const char *str, xcb_void_cookie_t); #include <vlc_picture.h>
int ProcessEvent (vout_thread_t *, xcb_connection_t *, xcb_window_t, #include <vlc_vout_display.h>
xcb_generic_event_t *);
void HandleParentStructure (vout_thread_t *vout, xcb_connection_t *conn,
xcb_window_t xid, xcb_configure_notify_event_t *ev);
int ManageEvent (vout_display_t *vd, xcb_connection_t *conn, xcb_window_t window);
/* keys.c */ /* keys.c */
typedef struct key_handler_t key_handler_t; typedef struct key_handler_t key_handler_t;
...@@ -40,15 +38,25 @@ void DestroyKeyHandler (key_handler_t *); ...@@ -40,15 +38,25 @@ void DestroyKeyHandler (key_handler_t *);
int ProcessKeyEvent (key_handler_t *, xcb_generic_event_t *); int ProcessKeyEvent (key_handler_t *, xcb_generic_event_t *);
/* common.c */ /* common.c */
struct vout_window_t;
xcb_connection_t *Connect (vlc_object_t *obj); xcb_connection_t *Connect (vlc_object_t *obj);
struct vout_window_t *GetWindow (vout_thread_t *obj, struct vout_window_t *GetWindow (vout_display_t *obj,
xcb_connection_t *pconn, xcb_connection_t *pconn,
const xcb_screen_t **restrict pscreen, const xcb_screen_t **restrict pscreen,
bool *restrict pshm); bool *restrict pshm);
int GetWindowSize (struct vout_window_t *wnd, xcb_connection_t *conn, int GetWindowSize (struct vout_window_t *wnd, xcb_connection_t *conn,
unsigned *restrict width, unsigned *restrict height); unsigned *restrict width, unsigned *restrict height);
int PictureAlloc (vout_thread_t *, picture_t *, size_t, xcb_connection_t *);
void PictureFree (picture_t *pic, xcb_connection_t *conn); int CheckError (vout_display_t *, xcb_connection_t *conn,
void CommonManage (vout_thread_t *); const char *str, xcb_void_cookie_t);
/* FIXME
* maybe it would be better to split this header in 2 */
#include <xcb/shm.h>
struct picture_sys_t
{
xcb_shm_seg_t segment;
};
int PictureResourceAlloc (vout_display_t *vd, picture_resource_t *res, size_t size,
xcb_connection_t *conn, bool attach);
void PictureResourceFree (picture_resource_t *res, xcb_connection_t *conn);
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_plugin.h> #include <vlc_plugin.h>
#include <vlc_vout.h> #include <vlc_vout_display.h>
#include <vlc_vout_window.h> #include <vlc_picture_pool.h>
#include "xcb_vlc.h" #include "xcb_vlc.h"
...@@ -58,7 +58,7 @@ vlc_module_begin () ...@@ -58,7 +58,7 @@ vlc_module_begin ()
set_description (N_("(Experimental) XVideo output")) set_description (N_("(Experimental) XVideo output"))
set_category (CAT_VIDEO) set_category (CAT_VIDEO)
set_subcategory (SUBCAT_VIDEO_VOUT) set_subcategory (SUBCAT_VIDEO_VOUT)
set_capability ("video output", 0) set_capability ("vout display", 0)
set_callbacks (Open, Close) set_callbacks (Open, Close)
add_string ("x11-display", NULL, NULL, add_string ("x11-display", NULL, NULL,
...@@ -67,7 +67,9 @@ vlc_module_begin () ...@@ -67,7 +67,9 @@ vlc_module_begin ()
add_shortcut ("xcb-xv") add_shortcut ("xcb-xv")
vlc_module_end () vlc_module_end ()
struct vout_sys_t #define MAX_PICTURES (VOUT_MAX_PICTURES)
struct vout_display_sys_t
{ {
xcb_connection_t *conn; xcb_connection_t *conn;
xcb_xv_query_adaptors_reply_t *adaptors; xcb_xv_query_adaptors_reply_t *adaptors;
...@@ -81,31 +83,21 @@ struct vout_sys_t ...@@ -81,31 +83,21 @@ struct vout_sys_t
uint16_t height; /* display height */ uint16_t height; /* display height */
uint32_t data_size; /* picture byte size (for non-SHM) */ uint32_t data_size; /* picture byte size (for non-SHM) */
bool shm; /* whether to use MIT-SHM */ bool shm; /* whether to use MIT-SHM */
};
static int Init (vout_thread_t *); xcb_xv_query_image_attributes_reply_t *att;
static void Deinit (vout_thread_t *); picture_pool_t *pool; /* picture pool */
static void Display (vout_thread_t *, picture_t *); picture_resource_t resource[MAX_PICTURES];
static int Manage (vout_thread_t *); };
static int Control (vout_thread_t *, int, va_list);
int CheckError (vout_thread_t *vout, const char *str, xcb_void_cookie_t ck)
{
xcb_generic_error_t *err;
err = xcb_request_check (vout->p_sys->conn, ck); static picture_t *Get (vout_display_t *);
if (err) static void Display (vout_display_t *, picture_t *);
{ static int Control (vout_display_t *, int, va_list);
msg_Err (vout, "%s: X11 error %d", str, err->error_code); static void Manage (vout_display_t *);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/** /**
* Check that the X server supports the XVideo extension. * Check that the X server supports the XVideo extension.
*/ */
static bool CheckXVideo (vout_thread_t *vout, xcb_connection_t *conn) static bool CheckXVideo (vout_display_t *vd, xcb_connection_t *conn)
{ {
xcb_xv_query_extension_reply_t *r; xcb_xv_query_extension_reply_t *r;
xcb_xv_query_extension_cookie_t ck = xcb_xv_query_extension (conn); xcb_xv_query_extension_cookie_t ck = xcb_xv_query_extension (conn);
...@@ -116,129 +108,21 @@ static bool CheckXVideo (vout_thread_t *vout, xcb_connection_t *conn) ...@@ -116,129 +108,21 @@ static bool CheckXVideo (vout_thread_t *vout, xcb_connection_t *conn)
{ /* We need XVideo 2.2 for PutImage */ { /* We need XVideo 2.2 for PutImage */
if ((r->major > 2) || (r->major == 2 && r->minor >= 2)) if ((r->major > 2) || (r->major == 2 && r->minor >= 2))
{ {
msg_Dbg (vout, "using XVideo extension v%"PRIu8".%"PRIu8, msg_Dbg (vd, "using XVideo extension v%"PRIu8".%"PRIu8,
r->major, r->minor); r->major, r->minor);
ok = true; ok = true;
} }
else else
msg_Dbg (vout, "XVideo extension too old (v%"PRIu8".%"PRIu8, msg_Dbg (vd, "XVideo extension too old (v%"PRIu8".%"PRIu8,
r->major, r->minor); r->major, r->minor);
free (r); free (r);
} }
else else
msg_Dbg (vout, "XVideo extension not available"); msg_Dbg (vd, "XVideo extension not available");
return ok; return ok;
} }
/** static vlc_fourcc_t ParseFormat (vout_display_t *vd,
* Get a list of XVideo adaptors for a given window.
*/
static xcb_xv_query_adaptors_reply_t *GetAdaptors (vout_window_t *wnd,
xcb_connection_t *conn)
{
xcb_xv_query_adaptors_cookie_t ck;
ck = xcb_xv_query_adaptors (conn, wnd->handle.xid);
return xcb_xv_query_adaptors_reply (conn, ck, NULL);
}
#define p_vout vout
/**
* Probe the X server.
*/
static int Open (vlc_object_t *obj)
{
vout_thread_t *vout = (vout_thread_t *)obj;
vout_sys_t *p_sys = malloc (sizeof (*p_sys));
if (p_sys == NULL)
return VLC_ENOMEM;
vout->p_sys = p_sys;
/* Connect to X */
p_sys->conn = Connect (obj);
if (p_sys->conn == NULL)
{
free (p_sys);
return VLC_EGENERIC;
}
if (!CheckXVideo (vout, p_sys->conn))
{
msg_Warn (vout, "Please enable XVideo 2.2 for faster video display");
xcb_disconnect (p_sys->conn);
free (p_sys);
return VLC_EGENERIC;
}
const xcb_screen_t *screen;
p_sys->embed = GetWindow (vout, p_sys->conn, &screen, &p_sys->shm);
if (p_sys->embed == NULL)
{
xcb_disconnect (p_sys->conn);
free (p_sys);
return VLC_EGENERIC;
}
/* Cache adaptors infos */
p_sys->adaptors = GetAdaptors (p_sys->embed, p_sys->conn);
if (p_sys->adaptors == NULL)
goto error;
/* Create window */
{
const uint32_t mask =
/* XCB_CW_EVENT_MASK */
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION;
xcb_void_cookie_t c;
xcb_window_t window = xcb_generate_id (p_sys->conn);
c = xcb_create_window_checked (p_sys->conn, screen->root_depth, window,
p_sys->embed->handle.xid, 0, 0, 1, 1, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
screen->root_visual,
XCB_CW_EVENT_MASK, &mask);
if (CheckError (vout, "cannot create X11 window", c))
goto error;
p_sys->window = window;
msg_Dbg (vout, "using X11 window %08"PRIx32, p_sys->window);
xcb_map_window (p_sys->conn, window);
}
p_sys->gc = xcb_generate_id (p_sys->conn);
xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);
msg_Dbg (vout, "using X11 graphic context %08"PRIx32, p_sys->gc);
vout->pf_init = Init;
vout->pf_end = Deinit;
vout->pf_display = Display;
vout->pf_manage = Manage;
vout->pf_control = Control;
return VLC_SUCCESS;
error:
Close (obj);
return VLC_EGENERIC;
}
/**
* Disconnect from the X server.
*/
static void Close (vlc_object_t *obj)
{
vout_thread_t *vout = (vout_thread_t *)obj;
vout_sys_t *p_sys = vout->p_sys;
free (p_sys->adaptors);
vout_window_Delete (p_sys->embed);
xcb_disconnect (p_sys->conn);
free (p_sys);
}
static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
const xcb_xv_image_format_info_t *restrict f) const xcb_xv_image_format_info_t *restrict f)
{ {
if (f->byte_order != ORDER && f->bpp != 8) if (f->byte_order != ORDER && f->bpp != 8)
...@@ -273,9 +157,9 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout, ...@@ -273,9 +157,9 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
} }
break; break;
} }
msg_Err (vout, "unknown XVideo RGB format %"PRIx32" (%.4s)", msg_Err (vd, "unknown XVideo RGB format %"PRIx32" (%.4s)",
f->id, f->guid); f->id, f->guid);
msg_Dbg (vout, " %"PRIu8" planes, %"PRIu8" bits/pixel, " msg_Dbg (vd, " %"PRIu8" planes, %"PRIu8" bits/pixel, "
"depth %"PRIu8, f->num_planes, f->bpp, f->depth); "depth %"PRIu8, f->num_planes, f->bpp, f->depth);
break; break;
...@@ -321,16 +205,16 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout, ...@@ -321,16 +205,16 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
break; break;
} }
bad: bad:
msg_Err (vout, "unknown XVideo YUV format %"PRIx32" (%.4s)", f->id, msg_Err (vd, "unknown XVideo YUV format %"PRIx32" (%.4s)", f->id,
f->guid); f->guid);
msg_Dbg (vout, " %"PRIu8" planes, %"PRIu32" bits/pixel, " msg_Dbg (vd, " %"PRIu8" planes, %"PRIu32" bits/pixel, "
"%"PRIu32"/%"PRIu32"/%"PRIu32" bits/sample", f->num_planes, "%"PRIu32"/%"PRIu32"/%"PRIu32" bits/sample", f->num_planes,
f->bpp, f->y_sample_bits, f->u_sample_bits, f->v_sample_bits); f->bpp, f->y_sample_bits, f->u_sample_bits, f->v_sample_bits);
msg_Dbg (vout, " period: %"PRIu32"/%"PRIu32"/%"PRIu32"x" msg_Dbg (vd, " period: %"PRIu32"/%"PRIu32"/%"PRIu32"x"
"%"PRIu32"/%"PRIu32"/%"PRIu32, "%"PRIu32"/%"PRIu32"/%"PRIu32,
f->vhorz_y_period, f->vhorz_u_period, f->vhorz_v_period, f->vhorz_y_period, f->vhorz_u_period, f->vhorz_v_period,
f->vvert_y_period, f->vvert_u_period, f->vvert_v_period); f->vvert_y_period, f->vvert_u_period, f->vvert_v_period);
msg_Warn (vout, " order: %.32s", f->vcomp_order); msg_Warn (vd, " order: %.32s", f->vcomp_order);
break; break;
} }
return 0; return 0;
...@@ -338,11 +222,13 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout, ...@@ -338,11 +222,13 @@ static vlc_fourcc_t ParseFormat (vout_thread_t *vout,
static const xcb_xv_image_format_info_t * static const xcb_xv_image_format_info_t *
FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port, FindFormat (vout_display_t *vd,
vlc_fourcc_t chroma, const video_format_t *fmt,
xcb_xv_port_t port,
const xcb_xv_list_image_formats_reply_t *list, const xcb_xv_list_image_formats_reply_t *list,
xcb_xv_query_image_attributes_reply_t **restrict pa) xcb_xv_query_image_attributes_reply_t **restrict pa)
{ {
xcb_connection_t *conn = vout->p_sys->conn; xcb_connection_t *conn = vd->sys->conn;
const xcb_xv_image_format_info_t *f, *end; const xcb_xv_image_format_info_t *f, *end;
#ifndef XCB_XV_OLD #ifndef XCB_XV_OLD
...@@ -353,21 +239,21 @@ FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port, ...@@ -353,21 +239,21 @@ FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port,
end = f + xcb_xv_list_image_formats_format_length (list); end = f + xcb_xv_list_image_formats_format_length (list);
for (; f < end; f++) for (; f < end; f++)
{ {
if (chroma != ParseFormat (vout, f)) if (chroma != ParseFormat (vd, f))
continue; continue;
xcb_xv_query_image_attributes_reply_t *i; xcb_xv_query_image_attributes_reply_t *i;
i = xcb_xv_query_image_attributes_reply (conn, i = xcb_xv_query_image_attributes_reply (conn,
xcb_xv_query_image_attributes (conn, port, f->id, xcb_xv_query_image_attributes (conn, port, f->id,
vout->fmt_in.i_width, vout->fmt_in.i_height), NULL); fmt->i_width, fmt->i_height), NULL);
if (i == NULL) if (i == NULL)
continue; continue;
if (i->width != vout->fmt_in.i_width if (i->width != fmt->i_width
|| i->height != vout->fmt_in.i_height) || i->height != fmt->i_height)
{ {
msg_Warn (vout, "incompatible size %ux%u -> %"PRIu32"x%"PRIu32, msg_Warn (vd, "incompatible size %ux%u -> %"PRIu32"x%"PRIu32,
vout->fmt_in.i_width, vout->fmt_in.i_height, fmt->i_width, fmt->i_height,
i->width, i->height); i->width, i->height);
free (i); free (i);
continue; continue;
...@@ -378,14 +264,67 @@ FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port, ...@@ -378,14 +264,67 @@ FindFormat (vout_thread_t *vout, vlc_fourcc_t chroma, xcb_xv_port_t port,
return NULL; return NULL;
} }
/** /**
* Allocate drawable window and picture buffers. * Get a list of XVideo adaptors for a given window.
*/ */
static int Init (vout_thread_t *vout) static xcb_xv_query_adaptors_reply_t *GetAdaptors (vout_window_t *wnd,
xcb_connection_t *conn)
{ {
vout_sys_t *p_sys = vout->p_sys; xcb_xv_query_adaptors_cookie_t ck;
xcb_xv_query_image_attributes_reply_t *att = NULL;
bool swap_planes = false; /* whether X wants V before U */ ck = xcb_xv_query_adaptors (conn, wnd->handle.xid);
return xcb_xv_query_adaptors_reply (conn, ck, NULL);
}
/**
* Probe the X server.
*/
static int Open (vlc_object_t *obj)
{
vout_display_t *vd = (vout_display_t *)obj;
vout_display_sys_t *p_sys = malloc (sizeof (*p_sys));
if (p_sys == NULL)
return VLC_ENOMEM;
vd->sys = p_sys;
/* Connect to X */
p_sys->conn = Connect (obj);
if (p_sys->conn == NULL)
{
free (p_sys);
return VLC_EGENERIC;
}
if (!CheckXVideo (vd, p_sys->conn))
{
msg_Warn (vd, "Please enable XVideo 2.2 for faster video display");
xcb_disconnect (p_sys->conn);
free (p_sys);
return VLC_EGENERIC;
}
const xcb_screen_t *screen;
p_sys->embed = GetWindow (vd, p_sys->conn, &screen, &p_sys->shm);
if (p_sys->embed == NULL)
{
xcb_disconnect (p_sys->conn);
free (p_sys);
return VLC_EGENERIC;
}
/* Cache adaptors infos */
p_sys->adaptors = GetAdaptors (p_sys->embed, p_sys->conn);
if (p_sys->adaptors == NULL)
goto error;
/* */
video_format_t fmt = vd->fmt;
// TODO !
#if 1
p_sys->att = NULL;
bool found_adaptor = false;
/* FIXME: check max image size */ /* FIXME: check max image size */
xcb_xv_adaptor_info_iterator_t it; xcb_xv_adaptor_info_iterator_t it;
...@@ -405,11 +344,11 @@ static int Init (vout_thread_t *vout) ...@@ -405,11 +344,11 @@ static int Init (vout_thread_t *vout)
if (r == NULL) if (r == NULL)
continue; continue;
const xcb_xv_image_format_info_t *fmt; const xcb_xv_image_format_info_t *xfmt;
/* Video chroma in preference order */ /* Video chroma in preference order */
const vlc_fourcc_t chromas[] = { const vlc_fourcc_t chromas[] = {
vout->fmt_in.i_chroma, fmt.i_chroma,
VLC_CODEC_YUYV, VLC_CODEC_YUYV,
VLC_CODEC_RGB24, VLC_CODEC_RGB24,
VLC_CODEC_RGB15, VLC_CODEC_RGB15,
...@@ -417,10 +356,10 @@ static int Init (vout_thread_t *vout) ...@@ -417,10 +356,10 @@ static int Init (vout_thread_t *vout)
for (size_t i = 0; i < sizeof (chromas) / sizeof (chromas[0]); i++) for (size_t i = 0; i < sizeof (chromas) / sizeof (chromas[0]); i++)
{ {
vlc_fourcc_t chroma = chromas[i]; vlc_fourcc_t chroma = chromas[i];
fmt = FindFormat (vout, chroma, a->base_id, r, &att); xfmt = FindFormat (vd, chroma, &fmt, a->base_id, r, &p_sys->att);
if (fmt != NULL) if (xfmt != NULL)
{ {
vout->output.i_chroma = chroma; fmt.i_chroma = chroma;
goto found_format; goto found_format;
} }
} }
...@@ -430,203 +369,306 @@ static int Init (vout_thread_t *vout) ...@@ -430,203 +369,306 @@ static int Init (vout_thread_t *vout)
found_format: found_format:
/* TODO: grab port */ /* TODO: grab port */
p_sys->port = a->base_id; p_sys->port = a->base_id;
msg_Dbg (vout, "using port %"PRIu32, p_sys->port); msg_Dbg (vd, "using port %"PRIu32, p_sys->port);
p_sys->id = fmt->id; p_sys->id = xfmt->id;
msg_Dbg (vout, "using image format 0x%"PRIx32, p_sys->id); msg_Dbg (vd, "using image format 0x%"PRIx32, p_sys->id);
if (fmt->type == XCB_XV_IMAGE_FORMAT_INFO_TYPE_RGB) if (xfmt->type == XCB_XV_IMAGE_FORMAT_INFO_TYPE_RGB)
{ {
vout->fmt_out.i_rmask = vout->output.i_rmask = fmt->red_mask; fmt.i_rmask = xfmt->red_mask;
vout->fmt_out.i_gmask = vout->output.i_gmask = fmt->green_mask; fmt.i_gmask = xfmt->green_mask;
vout->fmt_out.i_bmask = vout->output.i_bmask = fmt->blue_mask; fmt.i_bmask = xfmt->blue_mask;
} }
else else
if (fmt->num_planes == 3) if (xfmt->num_planes == 3
swap_planes = !strcmp ((const char *)fmt->vcomp_order, "YVU"); && !strcmp ((const char *)xfmt->vcomp_order, "YVU"))
fmt.i_chroma = VLC_CODEC_YV12;
free (r); free (r);
goto found_adaptor; found_adaptor = true;
break;
} }
msg_Err (vout, "no available XVideo adaptor"); if (!found_adaptor)
return VLC_EGENERIC; /* no usable adaptor */ {
msg_Err (vd, "no available XVideo adaptor");
/* Allocate picture buffers */ goto error;
const uint32_t *offsets; }
found_adaptor: #endif
offsets = xcb_xv_query_image_attributes_offsets (att);
p_sys->data_size = att->data_size;
I_OUTPUTPICTURES = 0; /* Create window */
for (size_t index = 0; I_OUTPUTPICTURES < 2; index++)
{ {
picture_t *pic = vout->p_picture + index; const uint32_t mask =
/* XCB_CW_EVENT_MASK */
XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_POINTER_MOTION;
xcb_void_cookie_t c;
xcb_window_t window = xcb_generate_id (p_sys->conn);
if (index > sizeof (vout->p_picture) / sizeof (pic)) c = xcb_create_window_checked (p_sys->conn, screen->root_depth, window,
break; p_sys->embed->handle.xid, 0, 0, 1, 1, 0,
if (pic->i_status != FREE_PICTURE) XCB_WINDOW_CLASS_INPUT_OUTPUT,
continue; screen->root_visual,
XCB_CW_EVENT_MASK, &mask);
if (CheckError (vd, p_sys->conn, "cannot create X11 window", c))
goto error;
p_sys->window = window;
msg_Dbg (vd, "using X11 window %08"PRIx32, p_sys->window);
xcb_map_window (p_sys->conn, window);
picture_Setup (pic, vout->output.i_chroma, vout_display_place_t place;
att->width, att->height,
vout->fmt_in.i_aspect); vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
if (PictureAlloc (vout, pic, att->data_size, p_sys->width = place.width;
p_sys->shm ? p_sys->conn : NULL)) p_sys->height = place.height;
break;
/* Allocate further planes as specified by XVideo */ /* */
/* We assume that offsets[0] is zero */ const uint32_t values[] = { place.x, place.y, place.width, place.height };
for (int i = 1; i < pic->i_planes; i++) xcb_configure_window (p_sys->conn, p_sys->window,
pic->p[i].p_pixels = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
pic->p->p_pixels + offsets[swap_planes ? (3 - i) : i]; XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
PP_OUTPUTPICTURE[I_OUTPUTPICTURES++] = pic; values);
} }
free (att);
unsigned x, y, width, height; /* Create graphic context */
p_sys->gc = xcb_generate_id (p_sys->conn);
xcb_create_gc (p_sys->conn, p_sys->gc, p_sys->window, 0, NULL);
msg_Dbg (vd, "using X11 graphic context %08"PRIx32, p_sys->gc);
if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height)) /* */
return VLC_EGENERIC; p_sys->pool = NULL;
vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
const uint32_t values[] = { x, y, width, height, }; /* */
xcb_configure_window (p_sys->conn, p_sys->window, vout_display_info_t info = vd->info;
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | info.has_pictures_invalid = false;
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
xcb_flush (p_sys->conn);
p_sys->height = height;
p_sys->width = width;
vout->fmt_out.i_chroma = vout->output.i_chroma; /* Setup vout_display_t once everything is fine */
vout->fmt_out.i_visible_width = vout->fmt_in.i_visible_width; vd->fmt = fmt;
vout->fmt_out.i_visible_height = vout->fmt_in.i_visible_height; vd->info = info;
vout->fmt_out.i_sar_num = vout->fmt_out.i_sar_den = 1;
vout->output.i_width = vout->fmt_out.i_width = vout->fmt_in.i_width; vd->get = Get;
vout->output.i_height = vout->fmt_out.i_height = vout->fmt_in.i_height; vd->prepare = NULL;
vout->fmt_out.i_x_offset = vout->fmt_in.i_x_offset; vd->display = Display;
vout->fmt_out.i_y_offset = vout->fmt_in.i_y_offset; vd->control = Control;
vd->manage = Manage;
assert (height > 0); /* */
vout->output.i_aspect = vout->fmt_out.i_aspect = unsigned width, height;
width * VOUT_ASPECT_FACTOR / height; if (!GetWindowSize (p_sys->embed, p_sys->conn, &width, &height))
vout_display_SendEventDisplaySize (vd, width, height);
vout_display_SendEventFullscreen (vd, false);
return VLC_SUCCESS; return VLC_SUCCESS;
error:
Close (obj);
return VLC_EGENERIC;
}
/**
* Disconnect from the X server.
*/
static void Close (vlc_object_t *obj)
{
vout_display_t *vd = (vout_display_t *)obj;
vout_display_sys_t *p_sys = vd->sys;
if (p_sys->pool)
{
for (unsigned i = 0; i < MAX_PICTURES; i++)
{
picture_resource_t *res = &p_sys->resource[i];
if (!res->p->p_pixels)
break;
PictureResourceFree (res, p_sys->conn);
}
picture_pool_Delete (p_sys->pool);
}
free (p_sys->att);
free (p_sys->adaptors);
vout_display_DeleteWindow (vd, p_sys->embed);
xcb_disconnect (p_sys->conn);
free (p_sys);
} }
/** /**
* Free picture buffers. * Return a direct buffer
*/ */
static void Deinit (vout_thread_t *vout) static picture_t *Get (vout_display_t *vd)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
if (!p_sys->pool)
{
picture_t *pic = picture_New (vd->fmt.i_chroma,
p_sys->att->width, p_sys->att->height, 0);
if (!pic)
return NULL;
memset (p_sys->resource, 0, sizeof(p_sys->resource));
const uint32_t *offsets =
xcb_xv_query_image_attributes_offsets (p_sys->att);
p_sys->data_size = p_sys->att->data_size;
unsigned count;
picture_t *pic_array[MAX_PICTURES];
for (count = 0; count < MAX_PICTURES; count++)
{
picture_resource_t *res = &p_sys->resource[count];
for (int i = 0; i < pic->i_planes; i++)
{
res->p[i].i_lines = pic->p[i].i_lines; /* FIXME seems wrong*/
res->p[i].i_pitch = pic->p[i].i_pitch;
}
if (PictureResourceAlloc (vd, res, p_sys->att->data_size,
p_sys->conn, p_sys->shm))
break;
/* Allocate further planes as specified by XVideo */
/* We assume that offsets[0] is zero */
for (int i = 1; i < pic->i_planes; i++)
res->p[i].p_pixels = res->p[0].p_pixels + offsets[i];
pic_array[count] = picture_NewFromResource (&vd->fmt, res);
if (!pic_array[count])
{
PictureResourceFree (res, p_sys->conn);
memset (res, 0, sizeof(*res));
break;
}
}
picture_Release (pic);
if (count == 0)
return NULL;
p_sys->pool = picture_pool_New (count, pic_array);
if (!p_sys->pool)
{
/* TODO release picture resources */
return NULL;
}
/* FIXME should also do it in case of error ? */
xcb_flush (p_sys->conn);
}
for (int i = 0; i < I_OUTPUTPICTURES; i++) return picture_pool_Get (p_sys->pool);
PictureFree (PP_OUTPUTPICTURE[i], p_sys->conn);
} }
/** /**
* Sends an image to the X server. * Sends an image to the X server.
*/ */
static void Display (vout_thread_t *vout, picture_t *pic) static void Display (vout_display_t *vd, picture_t *pic)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
xcb_shm_seg_t segment = (uintptr_t)pic->p_sys; xcb_shm_seg_t segment = pic->p_sys->segment;
if (segment) if (segment)
xcb_xv_shm_put_image (p_sys->conn, p_sys->port, p_sys->window, xcb_xv_shm_put_image (p_sys->conn, p_sys->port, p_sys->window,
p_sys->gc, segment, p_sys->id, 0, p_sys->gc, segment, p_sys->id, 0,
/* Src: */ vout->fmt_out.i_x_offset, /* Src: */ vd->source.i_x_offset,
vout->fmt_out.i_y_offset, vd->source.i_y_offset,
vout->fmt_out.i_visible_width, vd->source.i_visible_width,
vout->fmt_out.i_visible_height, vd->source.i_visible_height,
/* Dst: */ 0, 0, p_sys->width, p_sys->height, /* Dst: */ 0, 0, p_sys->width, p_sys->height,
/* Memory: */ /* Memory: */ pic->p->i_pitch / pic->p->i_pixel_pitch,
pic->p->i_pitch / pic->p->i_pixel_pitch,
pic->p->i_lines, false); pic->p->i_lines, false);
else else
xcb_xv_put_image (p_sys->conn, p_sys->port, p_sys->window, xcb_xv_put_image (p_sys->conn, p_sys->port, p_sys->window,
p_sys->gc, p_sys->id, p_sys->gc, p_sys->id,
vout->fmt_out.i_x_offset, vout->fmt_out.i_y_offset, vd->source.i_x_offset,
vout->fmt_out.i_visible_width, vd->source.i_y_offset,
vout->fmt_out.i_visible_height, vd->source.i_visible_width,
vd->source.i_visible_height,
0, 0, p_sys->width, p_sys->height, 0, 0, p_sys->width, p_sys->height,
vout->fmt_out.i_width, vout->fmt_out.i_height, vd->source.i_width, vd->source.i_height,
p_sys->data_size, pic->p->p_pixels); p_sys->data_size, pic->p->p_pixels);
xcb_flush (p_sys->conn); xcb_flush (p_sys->conn);
picture_Release (pic);
} }
/** static int Control (vout_display_t *vd, int query, va_list ap)
* Process incoming X events.
*/
static int Manage (vout_thread_t *vout)
{ {
vout_sys_t *p_sys = vout->p_sys; vout_display_sys_t *p_sys = vd->sys;
xcb_generic_event_t *ev;
while ((ev = xcb_poll_for_event (p_sys->conn)) != NULL) switch (query)
ProcessEvent (vout, p_sys->conn, p_sys->window, ev);
if (xcb_connection_has_error (p_sys->conn))
{ {
msg_Err (vout, "X server failure"); case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
return VLC_EGENERIC; case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
} case VOUT_DISPLAY_CHANGE_ZOOM:
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
{
const vout_display_cfg_t *cfg;
const video_format_t *source;
CommonManage (vout); if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
if (vout->i_changes & VOUT_SIZE_CHANGE) || query == VOUT_DISPLAY_CHANGE_SOURCE_CROP)
{ /* TODO: factor this code with XV and X11 Init() */ {
unsigned x, y, width, height; source = (const video_format_t *)va_arg (ap, const video_format_t *);
cfg = vd->cfg;
}
else
{
source = &vd->source;
cfg = (const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *);
}
if (GetWindowSize (p_sys->embed, p_sys->conn, &width, &height)) /* */
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
&& (cfg->display.width != vd->cfg->display.width
||cfg->display.height != vd->cfg->display.height)
&& vout_window_SetSize (p_sys->embed,
cfg->display.width,
cfg->display.height))
return VLC_EGENERIC; return VLC_EGENERIC;
vout_PlacePicture (vout, width, height, &x, &y, &width, &height);
const uint32_t values[] = { x, y, width, height, };
xcb_configure_window (p_sys->conn, p_sys->window, XCB_CONFIG_WINDOW_X |
XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH |
XCB_CONFIG_WINDOW_HEIGHT, values);
vout->p_sys->width = width; // XXX: <-- this is useless, as the zoom is
vout->p_sys->height = height; // handled with VOUT_SET_SIZE anyway.
vout->i_changes &= ~VOUT_SIZE_CHANGE;
}
return VLC_SUCCESS;
}
void
HandleParentStructure (vout_thread_t *vout, xcb_connection_t *conn,
xcb_window_t xid, xcb_configure_notify_event_t *ev)
{
unsigned width, height, x, y;
vout_PlacePicture (vout, ev->width, ev->height, &x, &y, &width, &height);
/* Move the picture within the window */
const uint32_t values[] = { x, y, width, height, };
xcb_configure_window (conn, xid,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
vout->p_sys->width = width;
vout->p_sys->height = height;
}
static int Control (vout_thread_t *vout, int query, va_list ap) vout_display_place_t place;
{ vout_display_PlacePicture (&place, source, cfg, false);
/* FIXME it can be shared between x11 and xvideo */ p_sys->width = place.width;
switch (query) p_sys->height = place.height;
{
case VOUT_SET_SIZE: /* Move the picture within the window */
{ const uint32_t values[] = { place.x, place.y,
const unsigned width = va_arg (ap, unsigned); place.width, place.height, };
const unsigned height = va_arg (ap, unsigned); xcb_configure_window (p_sys->conn, p_sys->window,
return vout_window_SetSize (vout->p_sys->embed, width, height); XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
| XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
xcb_flush (p_sys->conn);
return VLC_SUCCESS;
} }
case VOUT_SET_STAY_ON_TOP: case VOUT_DISPLAY_CHANGE_ON_TOP:
{ {
const bool is_on_top = va_arg (ap, int); int on_top = (int)va_arg (ap, int);
return vout_window_SetOnTop (vout->p_sys->embed, is_on_top); return vout_window_SetOnTop (p_sys->embed, on_top);
} }
/* TODO */
#if 0
/* Hide the mouse. It will be send when
* vout_display_t::info.b_hide_mouse is false */
VOUT_DISPLAY_HIDE_MOUSE,
/* Ask the module to acknowledge/refuse the fullscreen state change after
* being requested (externaly or by VOUT_DISPLAY_EVENT_FULLSCREEN */
VOUT_DISPLAY_CHANGE_FULLSCREEN, /* const vout_display_cfg_t *p_cfg */
#endif
case VOUT_DISPLAY_RESET_PICTURES:
assert(0);
default: default:
msg_Err (vd, "Unknown request in XCB vout display");
return VLC_EGENERIC; return VLC_EGENERIC;
} }
}
static void Manage (vout_display_t *vd)
{
vout_display_sys_t *p_sys = vd->sys;
ManageEvent (vd, p_sys->conn, p_sys->window);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment