Commit a844bbbb authored by Jean-Paul Saman's avatar Jean-Paul Saman

codec/avcodec/vaapi: Pass VASurface' s to vaapi-x11 vout

When -V vaapi-x11 is used (and ffmpeg-vaapi-x11 option), then pass
VASurface information in picture->p_sys. This only works with direct
rendering and video filters that directly operate on the picture are
a no go.

* vaapi.c: protect surface->i_refcount
* vaapi_x11.c: use direct rendering
parent 92ba7483
/*****************************************************************************
* vaapi.c: VAAPI helpers for the ffmpeg decoder
*****************************************************************************
* Copyright (C) 2009 Laurent Aimar
* Copyright (C) 2009-2011 Laurent Aimar
* $Id$
*
* Authors: Laurent Aimar <fenrir_AT_ videolan _DOT_ org>
......@@ -48,14 +48,6 @@
#ifdef HAVE_AVCODEC_VAAPI
typedef struct
{
VASurfaceID i_id;
int i_refcount;
unsigned int i_order;
} vlc_va_surface_t;
typedef struct
{
vlc_va_t va;
......@@ -176,7 +168,7 @@ static void DestroySurfaces( vlc_va_vaapi_t *p_va )
for( int i = 0; i < p_va->i_surface_count && p_va->p_surface; i++ )
{
vlc_va_surface_t *p_surface = &p_va->p_surface[i];
vlc_mutex_destroy(&p_surface->lock);
if( p_surface->i_id != VA_INVALID_SURFACE )
vaDestroySurfaces( p_va->conn->p_display, &p_surface->i_id, 1 );
}
......@@ -218,6 +210,7 @@ static int CreateSurfaces( vlc_va_vaapi_t *p_va, void **pp_hw_ctx, vlc_fourcc_t
p_surface->i_id = pi_surface_id[i];
p_surface->i_refcount = 0;
p_surface->i_order = 0;
vlc_mutex_init(&p_surface->lock);
}
/* Create a context */
......@@ -388,12 +381,33 @@ static int Extract( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
return VLC_SUCCESS;
}
static int DisplayPicture( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
static vlc_va_surface_t *FindSurface( vlc_va_t *p_external, const VASurfaceID i_surface_id )
{
vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
vlc_va_surface_t *p_surface = NULL;
if( !p_va->image_cache.buffer )
return VLC_EGENERIC;
for( int i = 0; i < p_va->i_surface_count; i++ )
{
vlc_va_surface_t *p_tmp = &p_va->p_surface[i];
if( p_tmp->i_id == i_surface_id )
{
vlc_mutex_lock(&p_tmp->lock);
/* NOTE: p_tmp->i_refcount can be greater then 1, when surfaces are being reclaimed
* this usually only happens when the vout vaapi-x11 is not instantiated yet.
*/
p_tmp->i_refcount++;
p_surface = p_tmp;
vlc_mutex_unlock(&p_surface->lock);
break;
}
}
return p_surface;
}
static int DisplayPicture( vlc_va_t *p_external, picture_t *p_picture, AVFrame *p_ff )
{
vlc_va_vaapi_t *p_va = vlc_va_vaapi_Get(p_external);
VASurfaceID i_surface_id = (VASurfaceID)(uintptr_t)p_ff->data[3];
......@@ -404,12 +418,19 @@ static int DisplayPicture( vlc_va_t *p_external, picture_t *p_picture, AVFrame *
#endif
return VLC_EGENERIC;
assert(p_picture->p_sys);
if (!p_picture->p_sys)
return VLC_ENOMEM;
return VLC_EGENERIC;
assert( sizeof(p_picture->p_sys) == sizeof(picture_sys_t) );
p_picture->p_sys->i_surface_id = i_surface_id;
/* FindSurface */
p_picture->p_sys->surface = FindSurface( p_external, i_surface_id );
if( !p_picture->p_sys->surface )
return VLC_EGENERIC;
p_picture->format.i_width = p_picture->format.i_visible_width = p_va->i_surface_width;
p_picture->format.i_height = p_picture->format.i_visible_height = p_va->i_surface_height;
return VLC_SUCCESS;
}
......@@ -425,7 +446,7 @@ static int Get( vlc_va_t *p_external, AVFrame *p_ff )
{
vlc_va_surface_t *p_surface = &p_va->p_surface[i];
if( !p_surface->i_refcount )
if( p_surface->i_refcount == 0 )
break;
if( p_surface->i_order < p_va->p_surface[i_old].i_order )
......@@ -435,9 +456,13 @@ static int Get( vlc_va_t *p_external, AVFrame *p_ff )
i = i_old;
vlc_va_surface_t *p_surface = &p_va->p_surface[i];
p_surface->i_refcount = 1;
vlc_mutex_lock(&p_surface->lock);
/* NOTE: when the surface is in use and not consumed by vout vaapi-x11,
* then p_surface->i_refcount can be greater then 0. Thus always increment.
*/
p_surface->i_refcount++;
p_surface->i_order = p_va->i_surface_order++;
vlc_mutex_unlock(&p_surface->lock);
/* */
for( int i = 0; i < 4; i++ )
......@@ -461,7 +486,11 @@ static void Release( vlc_va_t *p_external, AVFrame *p_ff )
vlc_va_surface_t *p_surface = &p_va->p_surface[i];
if( p_surface->i_id == i_surface_id )
{
vlc_mutex_lock(&p_surface->lock);
p_surface->i_refcount--;
vlc_mutex_unlock(&p_surface->lock);
}
}
}
......
......@@ -52,11 +52,6 @@
#include <X11/Xutil.h>
/* It must be large enough to absorb the server display jitter but it is
* useless to used a too large value.
*/
#define MAX_PICTURES (3)
typedef struct vlc_vaapi_x11_window_t
{
int screen;
......@@ -78,11 +73,11 @@ struct vout_display_sys_t
};
static picture_pool_t *Pool (vout_display_t *, unsigned);
static void PictureDisplay (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 *);
/* */
static int FindVAFourCC(vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
......@@ -136,18 +131,8 @@ static int CreateWindow(vout_display_t *vd)
XWindowAttributes attr;
XGetWindowAttributes(sys->conn->p_display_x11, sys->x11.root, &attr);
uint32_t depth = attr.depth;
switch(attr.depth)
{
case 8:
case 15:
case 16:
case 24:
case 32: /* de nothing */
break;
default:
depth = 24;
break;
}
if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
depth = 24;
XVisualInfo vi;
XVisualInfo *vi_info = &vi;
......@@ -159,6 +144,9 @@ static int CreateWindow(vout_display_t *vd)
xswa.border_pixel = BlackPixel(sys->conn->p_display_x11, sys->x11.screen);
xswa.background_pixel = WhitePixel(sys->conn->p_display_x11, sys->x11.screen);
msg_Info(vd, "Creating X11 window with: x=%d,y=%d - w=%d,h=%d",
vd->source.i_y_offset, vd->source.i_x_offset,
vd->cfg->display.width, vd->cfg->display.height);
sys->x11.window = XCreateWindow(sys->conn->p_display_x11, sys->x11.root,
vd->source.i_y_offset, vd->source.i_x_offset,
vd->cfg->display.width, vd->cfg->display.height,
......@@ -178,7 +166,7 @@ static void DestroyWindow(vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
if (sys->x11.window)
if (sys->x11.window != None)
{
XUnmapWindow(sys->conn->p_display_x11, sys->x11.window);
//x11_wait_event(sys->conn->p_display_x11, sys->x11.window, UnmapNotify);
......@@ -210,8 +198,11 @@ static vout_window_t *MakeWindow (vout_display_t *vd)
int OpenVaapiX11 (vlc_object_t *obj)
{
vout_display_t *vd = (vout_display_t *) obj;
vout_display_sys_t *sys = malloc(sizeof(*sys));
if( !vlc_xlib_init( obj ) )
return VLC_EGENERIC;
vout_display_sys_t *sys = malloc(sizeof(*sys));
if (unlikely(sys == NULL))
return VLC_ENOMEM;
......@@ -220,6 +211,7 @@ int OpenVaapiX11 (vlc_object_t *obj)
sys->conn = NULL;
sys->pool = NULL;
sys->visible = false;
sys->embed = MakeWindow(vd);
if (unlikely(sys->embed == NULL))
goto error;
......@@ -240,15 +232,18 @@ int OpenVaapiX11 (vlc_object_t *obj)
/* */
vout_display_info_t info = vd->info;
info.has_pictures_invalid = true;
info.is_slow = false;
info.has_pictures_invalid = false;
info.has_event_thread = false;
info.has_hide_mouse = false;
info.subpicture_chromas = &vd->fmt.i_chroma;
/* Setup vout_display_t once everything is fine */
vd->info = info;
vd->pool = Pool;
vd->prepare = NULL; //PictureRender;
vd->display = PictureDisplay;
vd->display = DisplayPicture;
vd->control = Control;
vd->manage = NULL; //Manage;
......@@ -306,55 +301,61 @@ static int Control (vout_display_t *vd, int query, va_list ap)
return vout_window_SetFullScreen (sys->embed, c->is_fullscreen);
}
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
{
const vout_display_cfg_t *p_cfg =
(const vout_display_cfg_t*)va_arg (ap, const vout_display_cfg_t *);
const bool is_forced = (bool)va_arg (ap, int);
if (is_forced
&& vout_window_SetSize (sys->embed,
p_cfg->display.width,
p_cfg->display.height))
return VLC_EGENERIC;
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, p_cfg, false);
if (place.width != vd->fmt.i_visible_width ||
place.height != vd->fmt.i_visible_height)
{
vout_display_SendEventPicturesInvalid (vd);
return VLC_SUCCESS;
}
#if 0 /* FIXME */
/* Move the picture within the window */
const uint32_t values[] = { place.x, place.y };
xcb_configure_window (sys->conn, sys->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
values);
#endif
return VLC_SUCCESS;
}
case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
{
unsigned state = va_arg (ap, unsigned);
return vout_window_SetState (sys->embed, state);
}
case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
case VOUT_DISPLAY_CHANGE_ZOOM:
case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
{
/* I am not sure it is always necessary, but it is way simpler ... */
vout_display_SendEventPicturesInvalid (vd);
return VLC_SUCCESS;
/* FIXME: adjust picture size */
const vout_display_cfg_t *cfg;
const video_format_t *source;
bool is_forced = false;
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 *);
cfg = vd->cfg;
}
else
{
source = &vd->source;
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);
}
/* */
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))
return VLC_EGENERIC;
vout_display_place_t place;
vout_display_PlacePicture (&place, source, cfg, false);
return VLC_SUCCESS;
}
case VOUT_DISPLAY_RESET_PICTURES:
{
picture_pool_Delete (sys->pool);
sys->pool = NULL;
#if 0
if (sys->pool)
{
picture_pool_Delete (sys->pool);
sys->pool = NULL;
}
#endif
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
......@@ -368,14 +369,12 @@ static int Control (vout_display_t *vd, int query, va_list ap)
return VLC_SUCCESS;
}
#if 0 /* FIXME */
/* Hide the mouse. It will be send when
* vout_display_t::info.b_hide_mouse is false */
case VOUT_DISPLAY_HIDE_MOUSE:
xcb_change_window_attributes (sys->conn, sys->embed->handle.xid,
XCB_CW_CURSOR, &(uint32_t){ sys->cursor });
/* FIXME */
return VLC_SUCCESS;
#endif
default:
msg_Err (vd, "Unknown request in XCB vout display");
return VLC_EGENERIC;
......@@ -393,7 +392,22 @@ static void Manage (vout_display_t *vd)
#endif
}
static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
static void PictureRelease(picture_t *pic)
{
assert(pic);
assert(sizeof(pic->p_sys) == sizeof(picture_sys_t));
if( pic->p_sys->surface )
{
vlc_mutex_lock(&pic->p_sys->surface->lock);
pic->p_sys->surface->i_refcount--;
assert(pic->p_sys->surface->i_refcount == 0);
vlc_mutex_unlock(&pic->p_sys->surface->lock);
pic->p_sys->surface = NULL;
}
}
static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
VLC_UNUSED(subpicture);
......@@ -406,94 +420,100 @@ static void PictureDisplay (vout_display_t *vd, picture_t *pic, subpicture_t *su
#endif
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
VARectangle va_rec = { .x = place.x, .y = place.y,
.width = place.width, .height = place.height };
unsigned int flags = VA_FRAME_PICTURE;
if (!pic->b_progressive)
flags = pic->b_top_field_first ? VA_TOP_FIELD : VA_BOTTOM_FIELD;
VASurfaceID i_surface_id = pic->p_sys->i_surface_id;
assert(pic->p_sys);
if (pic->p_sys->surface == NULL)
{
msg_Err(vd, "Discarding picture - no surface information");
picture_Release(pic);
return;
}
if (pic->p_sys->surface->i_refcount > 1)
{
vlc_mutex_lock(&pic->p_sys->surface->lock);
msg_Err(vd, "Reclaimed picture - %d (%p)", pic->p_sys->surface->i_id, pic);
pic->p_sys->surface->i_refcount--;
assert(pic->p_sys->surface->i_refcount < 3);
vlc_mutex_unlock(&pic->p_sys->surface->lock);
return;
}
VASurfaceID i_surface_id = pic->p_sys->surface->i_id;
assert(sys->x11.window != None);
VAStatus status = vaPutSurface(sys->conn->p_display,
i_surface_id,
sys->x11.window,
pic->format.i_y_offset, pic->format.i_x_offset,
pic->format.i_visible_width, pic->format.i_visible_height,
vd->source.i_y_offset, vd->source.i_x_offset,
vd->fmt.i_visible_width, vd->fmt.i_visible_height,
place.x, place.y, place.width, place.height,
NULL, 0, /* client supplied destination clip list, cliplist count */
NULL, 0, //&va_rec, 1, /* client supplied destination clip list, cliplist count */
flags);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "failed displaying picture");
msg_Err(vd, "failed displaying picture (id=%d) %d", i_surface_id, status);
PictureRelease(pic); /* Release pic->p_sys->surface */
picture_Release(pic);
}
static void vlc_va_PictureRelease(picture_t *pic)
{
assert(pic);
assert(sizeof(pic->p_sys) == sizeof(picture_sys_t));
if( --pic->i_refcount > 0 )
return;
picture_Delete(pic);
}
/**
* Return a direct buffer
*/
static picture_pool_t *Pool (vout_display_t *vd, unsigned requested_count)
{
vout_display_sys_t *sys = vd->sys;
VLC_UNUSED(requested_count);
assert(requested_count > 0);
if (sys->pool)
return sys->pool;
#if 0
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
const uint32_t values[] = { place.x, place.y, place.width, place.height };
xcb_configure_window (sys->conn, sys->window,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y |
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
values);
#endif
picture_t **pic_array = (picture_t **) calloc(requested_count, sizeof(picture_t *));
if (!pic_array)
return NULL;
picture_t *pic_array[MAX_PICTURES];
unsigned int count;
for (count = 0; count < MAX_PICTURES; count++)
for (count = 0; count < requested_count; count++)
{
pic_array[count] = picture_NewFromFormat(&vd->fmt);
if (!pic_array[count])
picture_t *pic = (picture_t*) picture_NewFromFormat(&vd->fmt);
if (!pic)
break;
assert(pic->p_sys == NULL);
picture_sys_t *sys = (picture_sys_t *) calloc(1, sizeof(picture_sys_t));
if (!sys)
{
picture_Release(pic_array[count]);
picture_Release(pic);
break;
}
pic_array[count] = pic;
pic_array[count]->p_sys = sys;
pic_array[count]->pf_release = vlc_va_PictureRelease;
//pic_array[count]->pf_release = PictureRelease;
}
if (count == 0)
return NULL;
goto error;
sys->pool = picture_pool_New (count, pic_array);
sys->pool = picture_pool_New(count, pic_array);
if (!sys->pool)
goto error;
free(pic_array);
XFlush(sys->conn->p_display_x11);
return sys->pool;
error:
/* Cleanup on error */
for (int i = 0; i < MAX_PICTURES; i++)
for (unsigned int i = 0; i < count; i++)
{
picture_t *pic = pic_array[i];
if (pic)
picture_Release(pic);
}
free(pic_array);
return NULL;
}
......
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