Commit 32eebfde authored by Jean-Paul Saman's avatar Jean-Paul Saman

VAAPI-X11 vout: Reworking X11 video output.

Create an X11 window with the right parent and handle its displaying, resizing and scaling of pictures.
parent 60211457
......@@ -94,12 +94,21 @@ struct vout_display_sys_t
/* */
Window window;
Screen *screen;
Cursor blank_cursor;
Pixmap bitmap;
XColor black;
struct {
int x, y;
unsigned int depth, width, height;
} geo;
};
static picture_pool_t *Pool (vout_display_t *, unsigned);
static void Render (vout_display_t *, picture_t *, subpicture_t *);
static void DisplayPicture (vout_display_t *, picture_t *, subpicture_t *);
static int Control (vout_display_t *, int, va_list);
static picture_pool_t *Pool(vout_display_t *, unsigned);
static void Render(vout_display_t *, picture_t *, subpicture_t *);
static void DisplayPicture(vout_display_t *, picture_t *, subpicture_t *);
static int Control(vout_display_t *, int, va_list);
static void Manage(vout_display_t *);
/* cache management */
static unsigned int cache_counter = 0;
......@@ -309,56 +318,178 @@ error:
static vout_window_t *MakeWindow (vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *)vd->sys;
vout_window_cfg_t wnd_cfg;
sys->conn->lock();
/* FIXME: Correct vout_window_t display size
* looks like it assumes fullscreen for
* vout_display_PlacePicture() to work as expected. */
unsigned int width, height;
int screen = DefaultScreen(sys->conn->p_x11);
width = DisplayWidth(sys->conn->p_x11, screen);
height = DisplayHeight(sys->conn->p_x11, screen);
sys->conn->unlock();
memset (&wnd_cfg, 0, sizeof (wnd_cfg));
wnd_cfg.type = VOUT_WINDOW_TYPE_XID;
wnd_cfg.x = var_InheritInteger (vd, "video-x");
wnd_cfg.y = var_InheritInteger (vd, "video-y");
wnd_cfg.width = width;
wnd_cfg.height = height;
wnd_cfg.width = vd->cfg->display.width;
wnd_cfg.height = vd->cfg->display.height;
vout_window_t *wnd = vout_display_NewWindow (vd, &wnd_cfg);
vout_window_t *wnd = vout_display_NewWindow(vd, &wnd_cfg);
if (wnd == NULL)
msg_Err (vd, "parent window not available");
return wnd;
}
static int GetWindowSize(vout_display_t *vd, unsigned int *pi_width, unsigned int *pi_height)
static Screen *FindScreen(vout_display_t *vd, Display *dpy,
int *px, int *py, unsigned int *pnum, unsigned int *pdepth,
unsigned int *pwidth, unsigned int *pheight)
{
vout_display_sys_t *sys = vd->sys;
Status status;
Window root_window;
int x, y;
unsigned int bw, depth;
unsigned int bw;
sys->conn->lock();
status = XGetGeometry(sys->conn->p_x11,
sys->embed->handle.xid,
status = XGetGeometry(dpy, sys->embed->handle.xid,
&root_window,
&x, &y, pi_width, pi_height,
&bw, &depth);
px, py, pwidth, pheight,
&bw, pdepth);
if (status == 0)
{
msg_Err (vd, "parent window not valid");
goto error;
}
int i = 0;
int num = 0;
Screen *screen;
Window root;
int count = XScreenCount(dpy);
for (i = 0; i < count; i++, num++)
{
screen = XScreenOfDisplay(dpy, i);
if (screen)
{
root = XRootWindowOfScreen(screen);
if (root == root_window)
{
/* found screen */
break;
}
}
}
if (i >= count)
{
msg_Err(vd, "Screen not found");
goto error;
}
/* Find the selected screen */
msg_Dbg (vd, "using screen number: %u", num);
*pnum = num;
sys->conn->unlock();
return screen;
if (status == 0)
error:
sys->conn->unlock();
return NULL;
}
static void WaitEvent(Display *dpy, Window w, int type)
{
XEvent e;
while (!XCheckTypedWindowEvent(dpy, w, type, &e))
usleep(10); /* FIXME: */
}
static Window CreateWindow(vout_display_t *vd, Display *dpy, Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
int scr = XScreenNumberOfScreen(screen);
XVisualInfo visualInfo;
XVisualInfo *vi;
vi = &visualInfo;
XMatchVisualInfo(sys->conn->p_x11, scr, sys->geo.depth, TrueColor, vi);
Colormap cmap = CopyFromParent;
XSetWindowAttributes xswa;
unsigned long xswa_mask;
xswa_mask = CWBorderPixel | CWBackPixel;
xswa.border_pixel = BlackPixel(dpy, scr);
xswa.background_pixel = BlackPixel(dpy, scr);
if (cmap != CopyFromParent)
{
msg_Err(vd, "failed getting geometry");
return VLC_EGENERIC;
xswa_mask |= CWColormap;
xswa.colormap = cmap;
}
Window window = XCreateWindow(dpy, sys->embed->handle.xid,
sys->geo.x, sys->geo.y,
sys->geo.width, sys->geo.height,
0, sys->geo.depth,
InputOutput,
vi->visual, xswa_mask, &xswa);
if (window == None)
{
XFree(vi);
return None;
}
return VLC_SUCCESS;
if (vi != &visualInfo)
XFree(vi);
/* */
long mask = (ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
ResizeRedirectMask | StructureNotifyMask | SubstructureRedirectMask |
ExposureMask | VisibilityChangeMask);
int err = XSelectInput(dpy, window, mask);
if (err == BadWindow)
return None;
XMapWindow(dpy, window);
WaitEvent(dpy, window, MapNotify);
WaitEvent(dpy, window, Expose); /* XXX: workaround an XvBA init bug */
XFlush(dpy);
return window;
}
static void DestroyWindow(Display *dpy, Window window)
{
XUnmapWindow(dpy, window);
WaitEvent(dpy, window, UnmapNotify);
XDestroyWindow(dpy, window);
}
static Cursor CreateBlankCursor(vout_display_t *vd, Display *dpy,
Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
Colormap cmap;
Cursor no_ptr;
XColor dummy;
static char bm_no_data[] = {0, 0, 0, 0, 0, 0, 0, 0};
int scr = XScreenNumberOfScreen(screen);
cmap = DefaultColormap(dpy, scr);
XAllocNamedColor(dpy, cmap, "black", &sys->black, &dummy);
sys->bitmap = XCreateBitmapFromData(dpy, sys->window, bm_no_data, 8, 8);
no_ptr = XCreatePixmapCursor(dpy, sys->bitmap, sys->bitmap, &sys->black, &sys->black, 0, 0);
return no_ptr;
}
static void DestroyBlankCursor(vout_display_t *vd, Display *dpy,
Window window, Screen *screen)
{
vout_display_sys_t *sys = vd->sys;
assert(screen);
int scr = XScreenNumberOfScreen(screen);
Colormap cmap = DefaultColormap(dpy, scr);
XUndefineCursor(dpy, window);
XFreeCursor(dpy, sys->blank_cursor);
if (sys->bitmap != None)
XFreePixmap(dpy, sys->bitmap);
XFreeColors(dpy, cmap, &sys->black.pixel, 1, 0);
}
/**
......@@ -387,20 +518,42 @@ int OpenVaapiX11 (vlc_object_t *obj)
sys->render.i_cache = VA_INVALID_ID;
sys->display.i_cache = VA_INVALID_ID;
sys->visible = false;
sys->embed = MakeWindow(vd);
if (unlikely(sys->embed == NULL))
goto error;
/* Create a VA display */
sys->conn = vlc_va_Initialize(NULL);
sys->conn = vlc_va_Initialize(sys->embed->display.x11);
if (!sys->conn)
goto error;
sys->embed = MakeWindow(vd);
if (unlikely(sys->embed == NULL))
if (FindVAFourCC(vd) != VLC_SUCCESS)
goto error;
if (FindVAFourCC(vd) != VLC_SUCCESS)
/* Find window parameters */
unsigned snum;
unsigned int depth;
unsigned int width, height;
int x, y;
sys->screen = FindScreen(vd, sys->conn->p_x11,
&x, &y, &snum, &depth,
&width, &height);
if (sys->screen == NULL)
goto error;
sys->geo.x = x;
sys->geo.y = y;
sys->geo.depth = depth;
sys->geo.width = width;
sys->geo.height = height;
sys->window = CreateWindow(vd, sys->conn->p_x11, sys->screen);
if (sys->window == None)
goto error;
sys->visible = false;
sys->blank_cursor = CreateBlankCursor(vd, sys->conn->p_x11, sys->screen);
msg_Info(vd, "using VAAPI X11 window (version %d.%d)",
sys->conn->i_version_major, sys->conn->i_version_minor);
......@@ -408,7 +561,7 @@ int OpenVaapiX11 (vlc_object_t *obj)
vout_display_info_t info = vd->info;
info.is_slow = false;
info.has_pictures_invalid = false;
info.has_event_thread = false;
info.has_event_thread = true;
info.has_hide_mouse = false;
/* Setup vout_display_t once everything is fine */
......@@ -426,20 +579,15 @@ int OpenVaapiX11 (vlc_object_t *obj)
vd->pool = Pool;
vd->display = DisplayPicture;
vd->control = Control;
vd->manage = NULL; //Manage;
vd->manage = Manage;
vd->info = info;
/* */
bool is_fullscreen = vd->cfg->is_fullscreen;
if (is_fullscreen && vout_window_SetFullScreen (sys->embed, true))
if (is_fullscreen && vout_window_SetFullScreen(sys->embed, true))
is_fullscreen = false;
vout_display_SendEventFullscreen (vd, is_fullscreen);
unsigned int width, height;
if (GetWindowSize(vd, &width, &height) == VLC_SUCCESS)
{
vout_window_SetSize (sys->embed, width, height);
vout_display_SendEventDisplaySize (vd, width, height, is_fullscreen);
}
vout_display_SendEventFullscreen(vd, is_fullscreen);
vout_display_SendEventDisplaySize(vd, width, height, is_fullscreen);
return VLC_SUCCESS;
error:
......@@ -452,14 +600,25 @@ void CloseVaapiX11 (vlc_object_t *obj)
vout_display_t *vd = (vout_display_t *) obj;
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
if (sys->conn && sys->conn->p_x11)
assert(sys->conn);
sys->conn->lock();
if (sys->conn->p_x11)
{
sys->conn->lock();
XFlush(sys->conn->p_x11);
XSync(sys->conn->p_x11, False);
sys->conn->unlock();
}
if (sys->blank_cursor != None)
DestroyBlankCursor(vd, sys->conn->p_x11,
sys->window, sys->screen);
if (sys->window != None)
DestroyWindow(sys->conn->p_x11, sys->window);
sys->blank_cursor = None;
sys->window = None;
sys->conn->unlock();
if (sys->embed)
vout_display_DeleteWindow (vd, sys->embed);
......@@ -502,14 +661,14 @@ static int Control (vout_display_t *vd, int query, va_list ap)
{
case VOUT_DISPLAY_CHANGE_FULLSCREEN:
{
const vout_display_cfg_t *c = va_arg (ap, const vout_display_cfg_t *);
return vout_window_SetFullScreen (sys->embed, c->is_fullscreen);
const vout_display_cfg_t *c = va_arg(ap, const vout_display_cfg_t *);
return vout_window_SetFullScreen(sys->embed, c->is_fullscreen);
}
case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
{
unsigned state = va_arg (ap, unsigned);
return vout_window_SetState (sys->embed, state);
unsigned state = va_arg(ap, unsigned);
return vout_window_SetState(sys->embed, state);
}
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
......@@ -525,26 +684,47 @@ static int Control (vout_display_t *vd, int query, va_list ap)
if (query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT
|| query == VOUT_DISPLAY_CHANGE_SOURCE_CROP)
{
source = (const video_format_t *)va_arg (ap, const video_format_t *);
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 *);
cfg = (const vout_display_cfg_t*)va_arg(ap, const vout_display_cfg_t *);
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE)
is_forced = (bool)va_arg (ap, int);
}
msg_Info(vd, "display size %dx%d %dx%d",
0, 0, cfg->display.width, cfg->display.height);
/* */
if (query == VOUT_DISPLAY_CHANGE_DISPLAY_SIZE
&& is_forced
&& (cfg->display.width != vd->cfg->display.width
||cfg->display.height != vd->cfg->display.height)
&& vout_window_SetSize (sys->embed,
cfg->display.width, cfg->display.height))
&& vout_window_SetSize(sys->embed,
cfg->display.width, cfg->display.height))
return VLC_EGENERIC;
vout_display_place_t place;
vout_display_PlacePicture(&place, source, cfg, false);
/* */
sys->geo.x = place.x;
sys->geo.y = place.y;
sys->geo.width = place.width;
sys->geo.height = place.height;
XWindowChanges changes = { .x = place.x, .y = place.y,
.width = place.width, .height = place.height };
int err = XConfigureWindow(sys->conn->p_x11, sys->window,
CWX | CWY | CWWidth | CWHeight, &changes);
if (err == BadMatch || err == BadValue || err == BadWindow)
return VLC_EGENERIC;
msg_Info(vd, "New window size %dx%d %dx%d",
place.x, place.y, place.width, place.height);
return VLC_SUCCESS;
}
case VOUT_DISPLAY_RESET_PICTURES:
......@@ -556,8 +736,14 @@ static int Control (vout_display_t *vd, int query, va_list ap)
/* Hide the mouse. It will be send when
* vout_display_t::info.b_hide_mouse is false */
case VOUT_DISPLAY_HIDE_MOUSE:
/* FIXME */
{
int err = XDefineCursor(sys->conn->p_x11, sys->window,
sys->blank_cursor);
if (err == BadAlloc || err == BadWindow || err == BadCursor)
return VLC_EGENERIC;
return VLC_SUCCESS;
}
default:
msg_Err (vd, "Unknown request in XCB vout display");
......@@ -565,6 +751,100 @@ static int Control (vout_display_t *vd, int query, va_list ap)
}
}
static int HandleEvent(vout_display_t *vd, Display *dpy, XEvent *event,
bool *visible)
{
vout_display_sys_t *sys = vd->sys;
switch(event->type)
{
case ButtonPress:
{
XButtonEvent *ev = (XButtonEvent *)event;
vout_display_SendEventMousePressed(vd, ev->button - 1);
break;
}
case ButtonRelease:
{
XButtonEvent *ev = (XButtonEvent *)event;
vout_display_SendEventMouseReleased(vd, ev->button - 1);
break;
}
case MotionNotify:
{
XMotionEvent *ev = (XMotionEvent *)event;
vout_display_place_t place;
/* show the default cursor */
XUndefineCursor(dpy, sys->window);
/* TODO it could be saved */
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
if (place.width <= 0 || place.height <= 0)
return VLC_EGENERIC;
const int x = vd->source.i_x_offset +
(int64_t)(ev->x - place.x) * vd->source.i_visible_width / place.width;
const int y = vd->source.i_y_offset +
(int64_t)(ev->y - place.y) * vd->source.i_visible_height/ place.height;
vout_display_SendEventMouseMoved(vd, x, y);
break;
}
case VisibilityNotify:
{
XVisibilityEvent *ev = (XVisibilityEvent *)event;
*visible = ev->state != VisibilityFullyObscured;
msg_Dbg (vd, "display is %svisible", *visible ? "" : "not ");
break;
}
case ConfigureNotify:
{
XConfigureEvent *ev = (XConfigureEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case ConfigureRequest:
{
XConfigureRequestEvent *ev = (XConfigureRequestEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case ResizeRequest:
{
XResizeRequestEvent *ev = (XResizeRequestEvent *)event;
vout_display_SendEventDisplaySize(vd, ev->width, ev->height,
vd->cfg->is_fullscreen);
break;
}
case DestroyNotify:
vout_display_SendEventClose(vd);
break;
case Expose:
case MappingNotify:
break;
default:
msg_Err(vd, "unhandled event %d", event->type);
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
static void Manage(vout_display_t *vd)
{
vout_display_sys_t *sys = vd->sys;
while (XPending(sys->conn->p_x11))
{
XEvent event;
XNextEvent(sys->conn->p_x11, &event);
HandleEvent(vd, sys->conn->p_x11, &event, &sys->visible);
}
}
static VASubpictureID SubpictureCreate(vout_display_t *vd, const subpicture_t *subpicture,
const subpicture_region_t *region, VAImage *image, const int flags)
{
......@@ -1139,16 +1419,13 @@ static void DisplayVASurface(vout_display_t *vd, VASurfaceID surface, picture_t
{
vout_display_sys_t *sys = vd->sys;
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
sys->conn->lock();
VAStatus status;
status = vaPutSurface(sys->conn->p_display, surface, sys->embed->handle.xid,
picture->format.i_x_offset, picture->format.i_y_offset,
picture->format.i_visible_width, picture->format.i_visible_height,
place.x, place.y, place.width, place.height,
status = vaPutSurface(sys->conn->p_display, surface, sys->window,
vd->source.i_x_offset, vd->source.i_y_offset,
vd->source.i_visible_width, vd->source.i_visible_height,
sys->geo.x, sys->geo.y, sys->geo.width, sys->geo.height,
NULL, 0, /* clipping */
/* NOTE: vaCreateContext() specifies VA_PROGRESSIVE */
picture->b_progressive ? VA_FRAME_PICTURE :
......@@ -1165,15 +1442,15 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
{
vout_display_sys_t *sys = vd->sys;
if (!sys->visible)
goto out;
assert(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE);
if ((pic->p_sys == NULL) || (pic->p_sys->i_id == VA_INVALID_SURFACE))
{
msg_Err(vd, "discarding picture without picture_sys_t information");
if (subpicture)
subpicture_Delete(subpicture);
picture_Release(pic);
return;
goto out;
}
picture_sys_t *surface = pic->p_sys;
......@@ -1209,7 +1486,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
/* */
sys->display.i_cache = surface->i_cache;
out:
if (subpicture)
subpicture_Delete(subpicture);
......@@ -1268,8 +1545,6 @@ static void PictureUnlock(picture_t *picture)
if (surface->i_refcount > 0)
surface->i_refcount--;
//assert(surface->i_refcount == 0);
//surface->i_refcount = 0;
surface->i_cache = VA_INVALID_ID;
}
......
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