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

codec/avcodec/vaapi*: Smooth subtitle subpicture display.

The subtitle subpictures are regenerated for each call to vd->Prepare.
This is not very efficient and results in flickering display of subtitles.
Implement a VASubpicture's cache to solve the flickering.
parent 78d2cc9e
......@@ -216,6 +216,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;
p_surface->i_cache = VA_INVALID_ID;
}
/* Create a context */
......@@ -429,8 +430,6 @@ static int DisplayPicture( vlc_va_t *p_external, picture_t *p_picture, AVFrame *
if( !p_picture->p_sys->surface )
abort();
assert(p_picture->p_sys->surface->subpicture == NULL);
return VLC_SUCCESS;
}
......@@ -462,13 +461,6 @@ static int Get( vlc_va_t *p_external, AVFrame *p_ff )
p_surface->i_refcount++;
p_surface->i_order = p_va->i_surface_order++;
if (p_surface->subpicture)
SubpictureDestroy( p_va->conn, &p_surface->i_id,
p_surface->subpicture, p_surface->i_sub );
p_surface->subpicture = NULL;
p_surface->i_sub = 0;
/* */
for( int i = 0; i < 4; i++ )
{
......@@ -513,45 +505,6 @@ static void Delete( vlc_va_t *p_external )
free( p_va );
}
/* */
void SubpictureDestroy( vlc_va_conn_t *p_connection, VASurfaceID *i_surface_id,
vlc_va_subpicture_t *subpicture, const int i_sub )
{
VAStatus status;
for( int i = 0; i < i_sub; i++ )
{
if( ((*i_surface_id) != VA_INVALID_SURFACE) &&
(subpicture[i].i_id != VA_INVALID_ID) )
{
status = vaDeassociateSubpicture( p_connection->p_display, subpicture[i].i_id,
i_surface_id, 1) ;
assert( status == VA_STATUS_SUCCESS );
}
if( subpicture[i].i_id != VA_INVALID_ID )
{
status = vaDestroySubpicture( p_connection->p_display,
subpicture[i].i_id );
assert( status == VA_STATUS_SUCCESS );
}
if( subpicture[i].image.image_id != VA_INVALID_ID )
{
status = vaDestroyImage( p_connection->p_display,
subpicture[i].image.image_id );
assert( status == VA_STATUS_SUCCESS );
}
subpicture[i].image.image_id = VA_INVALID_ID;
subpicture[i].image.buf = VA_INVALID_ID;
subpicture[i].i_id = VA_INVALID_ID;
}
/* */
free( subpicture );
}
/* */
vlc_va_t *vlc_va_NewVaapi( vlc_object_t *obj, int i_codec_id )
{
......
......@@ -27,12 +27,6 @@ struct vlc_va_conn_t
int i_ref_count; /* for internal use only */
};
typedef struct
{
VASubpictureID i_id; /* VASubpictureIDs */
VAImage image;
} vlc_va_subpicture_t;
typedef struct
{
VASurfaceID i_id;
......@@ -40,8 +34,7 @@ typedef struct
unsigned int i_order;
/* subpicture */
vlc_va_subpicture_t *subpicture;
unsigned int i_sub; /* number of vlc_va_subpicures_t */
unsigned int i_cache;
} vlc_va_surface_t;
struct picture_sys_t
......@@ -50,7 +43,4 @@ struct picture_sys_t
vlc_va_surface_t *surface;
};
void SubpictureDestroy( vlc_va_conn_t *p_connection, VASurfaceID *i_surface_id,
vlc_va_subpicture_t *subpicture, const int i_sub );
#endif
......@@ -35,6 +35,8 @@
#include <vlc_vout_window.h>
#include <vlc_picture_pool.h>
#include <vlc_arrays.h>
#ifdef HAVE_AVCODEC_VAAPI
#ifdef HAVE_LIBAVCODEC_AVCODEC_H
......@@ -55,6 +57,9 @@
#include <X11/Xutil.h>
/* define for extra debugging */
#undef VAAPI_DEBUG
static const vlc_fourcc_t va_subpicture_chromas[] = {
VLC_CODEC_RGBA,
0
......@@ -71,6 +76,19 @@ struct vout_display_sys_t
VAImageFormat sub_fmt; /* Subpicture format VA_FOURCC_RGBA */
int sflags; /* Subtitle format flags */
struct {
unsigned int i_cache;
mtime_t i_start;
mtime_t i_stop;
subpicture_t *prev_subpicture;
} render;
struct {
unsigned int i_cache;
} display;
vlc_mutex_t cache_lock;
vlc_array_t cache; /* array of subpicture_subpicture_cache_t */
unsigned int i_display_order;
bool visible; /* whether to draw */
};
......@@ -80,7 +98,120 @@ 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);
/* */
/* cache management */
static unsigned int cache_counter = 0;
typedef struct
{
VASubpictureID i_id;
VAImage image;
} vasubpicture_cache_t;
typedef struct
{
unsigned int i_id;
mtime_t i_start; /* start display date */
mtime_t i_stop; /* stop display date */
vlc_array_t subpictures;
} subpicture_cache_t;
static subpicture_cache_t *cache_new(void)
{
subpicture_cache_t *cache = malloc(sizeof(subpicture_cache_t));
if (cache)
{
cache->i_id = cache_counter++;
if (cache_counter == VA_INVALID_ID)
cache_counter = 0;
vlc_array_init(&cache->subpictures);
}
return cache;
}
static void cache_destroy(subpicture_cache_t *cache)
{
assert(cache);
assert(vlc_array_count(&cache->subpictures) == 0);
vlc_array_clear(&cache->subpictures);
free(cache);
}
static subpicture_cache_t *cache_find(vlc_array_t *cache, const unsigned int id)
{
const int count = vlc_array_count(cache);
for (int i = 0; i < count; i++)
{
subpicture_cache_t *c = (subpicture_cache_t *) vlc_array_item_at_index(cache, i);
if (c)
{
if (c->i_id == id)
return c;
}
}
return NULL;
}
static vasubpicture_cache_t *subpicture_cache_new( void )
{
vasubpicture_cache_t *cache = malloc(sizeof(vasubpicture_cache_t));
if (cache)
{
cache->i_id = VA_INVALID_ID;
cache->image.buf = VA_INVALID_ID;
cache->image.image_id = VA_INVALID_ID;
}
return cache;
}
static void subpicture_cache_destroy(vasubpicture_cache_t *cache)
{
assert(cache);
assert(cache->i_id == VA_INVALID_ID);
assert(cache->image.buf == VA_INVALID_ID);
assert(cache->image.image_id == VA_INVALID_ID);
free(cache);
}
/* Clear subpicture cache for this surface and
* release allocated VA API resources */
static void SubpictureCacheClean(vout_display_t *vd, vlc_va_conn_t *conn, subpicture_cache_t *cache)
{
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "subpictureCacheClean cache %d", cache->i_id);
#else
VLC_UNUSED(vd);
#endif
const int num = vlc_array_count(&cache->subpictures);
for (int i = num - 1; i >= 0; i--)
{
vasubpicture_cache_t *subpic;
subpic = (vasubpicture_cache_t *)vlc_array_item_at_index(&cache->subpictures, i);
if (!subpic)
continue;
vlc_array_remove(&cache->subpictures, i);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "- %d: sub_id %d, image_id %d",
i, subpic->i_id, subpic->image.image_id);
#endif
assert(subpic->i_id != VA_INVALID_ID);
assert(subpic->image.image_id != VA_INVALID_ID);
vaDestroySubpicture(conn->p_display, subpic->i_id);
vaDestroyImage(conn->p_display, subpic->image.image_id);
subpic->i_id = VA_INVALID_ID;
subpic->image.buf = VA_INVALID_ID;
subpic->image.image_id = VA_INVALID_ID;
subpicture_cache_destroy(subpic);
subpic = NULL;
}
}
/* VA API support functions */
static int VASubtitleFourCC(vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
......@@ -200,6 +331,13 @@ int OpenVaapiX11 (vlc_object_t *obj)
sys->conn = NULL;
sys->pool = NULL;
vlc_array_init(&sys->cache);
vlc_mutex_init(&sys->cache_lock);
sys->render.prev_subpicture = NULL;
sys->render.i_cache = VA_INVALID_ID;
sys->display.i_cache = VA_INVALID_ID;
sys->visible = false;
sys->embed = MakeWindow(vd);
......@@ -269,8 +407,29 @@ void CloseVaapiX11 (vlc_object_t *obj)
XSync(sys->conn->p_display_x11, False);
}
}
if (sys->embed)
vout_display_DeleteWindow (vd, sys->embed);
/* Cleanup cache */
vlc_mutex_destroy(&sys->cache_lock);
const int count = vlc_array_count(&sys->cache);
for (int i = count - 1; i >= 0; i--)
{
subpicture_cache_t *cache;
cache = (subpicture_cache_t*) vlc_array_item_at_index(&sys->cache, i);
if (!cache)
continue;
vlc_array_remove(&sys->cache, i);
SubpictureCacheClean(vd, sys->conn, cache);
cache_destroy(cache);
cache = NULL;
}
vlc_array_clear(&sys->cache);
/* */
if (sys->conn)
vlc_va_Terminate(sys->conn);
......@@ -356,15 +515,15 @@ static int Control (vout_display_t *vd, int query, va_list ap)
}
}
static VASubpictureID SubpictureCreate(vout_display_t *vd, VASurfaceID *i_surface_id, const subpicture_t *subpicture,
const subpicture_region_t *region, vlc_va_subpicture_t *vasubpicture, const int flags)
static VASubpictureID SubpictureCreate(vout_display_t *vd, const subpicture_t *subpicture,
const subpicture_region_t *region, VAImage *image, const int flags)
{
vout_display_sys_t *sys = vd->sys;
VAStatus status;
VASubpictureID subpic = VA_INVALID_ID;
VASubpictureID sub_id = VA_INVALID_ID;
status = vaCreateSubpicture(sys->conn->p_display, vasubpicture->image.image_id, &subpic);
status = vaCreateSubpicture(sys->conn->p_display, image->image_id, &sub_id);
if (status != VA_STATUS_SUCCESS)
return VA_INVALID_ID;
......@@ -376,9 +535,9 @@ static VASubpictureID SubpictureCreate(vout_display_t *vd, VASurfaceID *i_surfac
assert(!b_chroma);
float global_alpha = (float)(subpicture->i_alpha * region->i_alpha / 255) / 255;
status = vaSetSubpictureGlobalAlpha(sys->conn->p_display, subpic, global_alpha);
status = vaSetSubpictureGlobalAlpha(sys->conn->p_display, sub_id, global_alpha);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed applying alpha value to subpicture");
msg_Err(vd, "failed applying alpha value to subpicture");
}
if (b_chroma)
......@@ -392,12 +551,24 @@ static VASubpictureID SubpictureCreate(vout_display_t *vd, VASurfaceID *i_surfac
(region->p_picture->format.i_gmask << 16) |
(region->p_picture->format.i_bmask << 8) | 0;
status = vaSetSubpictureChromakey(sys->conn->p_display, subpic,
status = vaSetSubpictureChromakey(sys->conn->p_display, sub_id,
min, max, mask);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed applying chroma valuesto subpicture");
msg_Err(vd, "failed applying chroma valuesto subpicture");
}
return sub_id;
}
static int SubpictureLink(vout_display_t *vd, VASurfaceID surface_id,
const subpicture_t *subpicture, const subpicture_region_t *region,
VASubpictureID vasub_id, const int flags)
{
vout_display_sys_t *sys = vd->sys;
assert(surface_id != VA_INVALID_ID);
assert(vasub_id != VA_INVALID_ID);
/* subpicture positioning */
vout_display_place_t video;
vout_display_PlacePicture (&video, &vd->source, vd->cfg, false);
......@@ -416,8 +587,9 @@ static VASubpictureID SubpictureCreate(vout_display_t *vd, VASurfaceID *i_surfac
unsigned int dst_bottom = dst_top + scale_h * region->fmt.i_visible_height;
/* Associate subpicture with surface */
status = vaAssociateSubpicture(sys->conn->p_display, subpic,
i_surface_id, 1, /* array of surfaces */
VAStatus status;
status = vaAssociateSubpicture(sys->conn->p_display, vasub_id,
&surface_id, 1, /* array of surfaces */
/* src rectangle */
src_left, src_top, src_right, src_bottom,
/* dest rectangle */
......@@ -425,11 +597,22 @@ static VASubpictureID SubpictureCreate(vout_display_t *vd, VASurfaceID *i_surfac
dst_right - dst_left, dst_bottom - dst_top,
flags);
if (status != VA_STATUS_SUCCESS)
return VLC_EGENERIC;
return VLC_SUCCESS;
}
static VAStatus SubpictureUnlink( vlc_va_conn_t *p_connection, VASurfaceID surface_id,
VASubpictureID sub_id )
{
VAStatus status = VA_STATUS_ERROR_UNKNOWN;
if( (surface_id != VA_INVALID_SURFACE) &&
(sub_id != VA_INVALID_ID) )
{
vaDestroySubpicture(sys->conn->p_display, subpic);
return VA_INVALID_ID;
status = vaDeassociateSubpicture( p_connection->p_display, sub_id,
&surface_id, 1 );
}
return subpic;
return status;
}
static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
......@@ -444,7 +627,8 @@ static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
return VLC_EGENERIC;
/* Sanity checks */
if ((image->format.fourcc != VA_FOURCC_RGBA) ||
if ((image->image_id == VA_INVALID_ID) ||
(image->format.fourcc != VA_FOURCC_RGBA) ||
(image->num_planes != (unsigned int) pic->i_planes) ||
(image->height != pic->format.i_height) ||
(image->width != pic->format.i_width) ||
......@@ -458,12 +642,13 @@ static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
image->format.bits_per_pixel, pic->format.i_bits_per_pixel);
goto out_va_free;
}
assert(image->image_id != VA_INVALID_ID);
void *p_base;
status = vaMapBuffer(sys->conn->p_display, image->buf, &p_base);
if (status != VA_STATUS_SUCCESS)
{
msg_Err(vd, "Failed mapping image for copying (%d)", status);
msg_Err(vd, "failed mapping image for copying (%d)", status);
goto out_va_free;
}
......@@ -497,8 +682,7 @@ static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
status = vaUnmapBuffer(sys->conn->p_display, image->buf);
if (status != VA_STATUS_SUCCESS)
{
msg_Err(vd, "Failed unmapping image for copying (%d)(buf id: %d)",
status, image->buf);
msg_Err(vd, "failed unmapping image for copying (%d)", status);
goto out_va_free;
}
......@@ -507,22 +691,24 @@ static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
out_va_free:
vaDestroyImage(sys->conn->p_display, image->image_id);
image->image_id = VA_INVALID_ID;
image->buf = VA_INVALID_ID;
return VLC_EGENERIC;
}
static int RenderDirectSubpicture(vout_display_t *vd, picture_t *picture,
subpicture_t *subpicture, const unsigned int i_region)
static int RenderDirectSubpicture(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
vlc_va_surface_t *surface = picture->p_sys->surface;
assert(surface->subpicture == NULL);
vlc_va_subpicture_t *vasubpic = (vlc_va_subpicture_t*) calloc(i_region, sizeof(vlc_va_subpicture_t));
if (!vasubpic)
subpicture_cache_t *cache = cache_new();
if (!cache)
return VLC_EGENERIC;
unsigned int i_sub = 0;
cache->i_start = subpicture->i_start;
cache->i_stop = subpicture->i_stop;
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "link surface %d cache %d", surface->i_id, cache->i_id);
#endif
int i_sub = 0;
subpicture_region_t *region;
for (region = subpicture->p_region; region != NULL; region = region->p_next)
{
......@@ -531,88 +717,192 @@ static int RenderDirectSubpicture(vout_display_t *vd, picture_t *picture,
continue;
/* Copy pixels from region into VAImage */
VAImage *image = &vasubpic[i_sub].image;
vasubpicture_cache_t *vasub_cache = subpicture_cache_new();
if (!vasub_cache)
goto cleanup;
VAImage *image = &vasub_cache->image;
image->image_id = VA_INVALID_ID;
image->buf = VA_INVALID_ID;
int err = CopyPictureToVAImage(vd, region->p_picture, image, &sys->sub_fmt);
if (err != VLC_SUCCESS)
{
msg_Err(vd, "Failed to copy region into vaImage");
free(vasubpic);
return VLC_EGENERIC;
msg_Err(vd, "failed to copy region into vaImage id=%d", image->image_id);
free(vasub_cache);
goto cleanup;
}
vasubpic[i_sub].image.format.alpha_mask = 0xFFFFFF00;
vasubpic[i_sub].image.format.red_mask = region->p_picture->format.i_rmask;
vasubpic[i_sub].image.format.blue_mask = region->p_picture->format.i_bmask;
vasubpic[i_sub].image.format.green_mask = region->p_picture->format.i_gmask;
image->format.alpha_mask = 0xFFFFFF00;
image->format.red_mask = region->p_picture->format.i_rmask;
image->format.blue_mask = region->p_picture->format.i_bmask;
image->format.green_mask = region->p_picture->format.i_gmask;
/* Create Subpicture */
vasubpic[i_sub].i_id = SubpictureCreate(vd, &surface->i_id, subpicture, region,
&vasubpic[i_sub], sys->sflags);
if (vasubpic[i_sub].i_id == VA_INVALID_ID)
vasub_cache->i_id = SubpictureCreate(vd, subpicture, region,
image, sys->sflags);
if (vasub_cache->i_id == VA_INVALID_ID)
{
vaDestroyImage(sys->conn->p_display, vasubpic[i_sub].image.image_id);
free(vasubpic);
return VLC_EGENERIC;
vaDestroyImage(sys->conn->p_display, image->image_id);
vasub_cache->i_id = VA_INVALID_ID;
image->image_id = VA_INVALID_ID;
image->buf = VA_INVALID_ID;
subpicture_cache_destroy(vasub_cache);
vasub_cache = NULL;
goto cleanup;
}
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "+ %d: subid %d", i_sub, vasub_cache->i_id);
#endif
err = SubpictureLink(vd, surface->i_id, subpicture, region,
vasub_cache->i_id, sys->sflags);
if (err != VLC_SUCCESS)
{
vaDestroySubpicture(sys->conn->p_display, vasub_cache->i_id);
vaDestroyImage(sys->conn->p_display, image->image_id);
vasub_cache->i_id = VA_INVALID_ID;
image->image_id = VA_INVALID_ID;
image->buf = VA_INVALID_ID;
subpicture_cache_destroy(vasub_cache);
vasub_cache = NULL;
goto cleanup;
}
vlc_array_append(&cache->subpictures, (void *)vasub_cache);
vasub_cache = NULL;
i_sub++;
}
/* remember what was created, so it can be released in DisplayPicture() */
surface->subpicture = vasubpic;
surface->i_sub = i_sub;
vlc_mutex_lock(&sys->cache_lock);
vlc_array_append(&sys->cache, (void *)cache);
sys->render.i_cache = cache->i_id;
surface->i_cache = cache->i_id;
vlc_mutex_unlock(&sys->cache_lock);
return VLC_SUCCESS;
cleanup:
surface->i_cache = VA_INVALID_ID;
msg_Err(vd, "unlink surface %d cache %d", surface->i_id, cache->i_id);
for (int i = 0; i < i_sub; i++)
{
vasubpicture_cache_t *sub = vlc_array_item_at_index(&cache->subpictures, i);
assert(sub);
msg_Err(vd, "- %u: subid %d", i, sub->i_id);
VAStatus status = SubpictureUnlink(sys->conn, surface->i_id, sub->i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "failed unlinking (error %d)", status);
}
SubpictureCacheClean(vd, sys->conn, cache);
cache_destroy(cache);
cache = NULL;
return VLC_EGENERIC;
}
static void PictureRelease(picture_t *picture)
static int RenderCachedSubpictures(vout_display_t *vd, picture_t *picture,
subpicture_t *subpicture, subpicture_cache_t *cache)
{
if (picture->i_refcount > 0)
picture->i_refcount--;
if (picture->p_sys)
{
vlc_va_conn_t *conn = vlc_va_get_conn();
vout_display_sys_t *sys = vd->sys;
vlc_va_surface_t *surface = picture->p_sys->surface;
vlc_va_subpicture_t *subpicture = surface->subpicture;
if (surface)
{
VAStatus status;
const int i_sub = surface->i_sub;
for (int i = 0; i < i_sub; i++)
const int count = vlc_array_count(&cache->subpictures);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "link surface %d cache %d size %d",
surface->i_id, cache->i_id, count);
#endif
int i_sub = 0;
subpicture_region_t *region = NULL;
for (region = subpicture->p_region; region != NULL; region = region->p_next)
{
if ((surface->i_id != VA_INVALID_SURFACE) &&
(subpicture[i].i_id != VA_INVALID_ID))
/* Skip non-RGBA regions for now */
if (region->fmt.i_chroma == VLC_CODEC_RGBA)
{
status = vaDeassociateSubpicture(conn->p_display,
subpicture[i].i_id, &surface->i_id, 1);
assert(status == VA_STATUS_SUCCESS);
if (i_sub >= count)
break;
vasubpicture_cache_t *vasubpic;
vasubpic = (vasubpicture_cache_t *) vlc_array_item_at_index(&cache->subpictures, i_sub);
if (!vasubpic)
goto cleanup;
if ((vasubpic->image.width != region->fmt.i_width) ||
(vasubpic->image.height != region->fmt.i_height))
goto cleanup;
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "+ %d: subid %d", i_sub, vasubpic->i_id);
#endif
int err = SubpictureLink(vd, surface->i_id, subpicture, region,
vasubpic->i_id, sys->sflags);
if (err != VLC_SUCCESS)
goto cleanup;
vasubpic = NULL;
i_sub++;
}
}
if (subpicture[i].i_id != VA_INVALID_ID)
/* FIXME: should not happen */
if (i_sub < count)
goto cleanup;
surface->i_cache = cache->i_id;
return VLC_SUCCESS;
cleanup:
surface->i_cache = VA_INVALID_ID;
msg_Warn(vd, "unlink surface %d cache %d", surface->i_id, cache->i_id);
for (int i = 0; i < i_sub; i++)
{
status = vaDestroySubpicture(conn->p_display, subpicture[i].i_id);
assert(status == VA_STATUS_SUCCESS);
vasubpicture_cache_t *vasubpic;
vasubpic = (vasubpicture_cache_t *) vlc_array_item_at_index(&cache->subpictures, i);
assert(vasubpic);
msg_Warn(vd, "- %u: subid %d", i, vasubpic->i_id);
VAStatus status = SubpictureUnlink(sys->conn, surface->i_id, vasubpic->i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "- %d unlink failed (status = %d)", i, status);
}
return VLC_EGENERIC;
}
if (subpicture[i].image.image_id != VA_INVALID_ID)
static void PictureRelease(picture_t *picture)
{
if (picture->i_refcount > 0)
picture->i_refcount--;
if (picture->p_sys)
{
status = vaDestroyImage(conn->p_display,
subpicture[i].image.image_id);
assert(status == VA_STATUS_SUCCESS);
vlc_va_surface_t *surface = picture->p_sys->surface;
if (surface && (surface->i_cache != VA_INVALID_ID))
{
#if 0 /* FIXME: leaking subpicture associations */
vlc_va_conn_t *conn = vlc_va_get_conn();
vlc_mutex_lock(&sys->cache_lock);
subpicture_cache_t *cache = cache_find(&sys->cache, surface->i_cache);
assert(cache);
const int count = vlc_array_count(&cache->subpictures);
for (int i = 0; i < count; i++)
{
vasubpicture_cache_t *vasubpic;
vasubpic = (vasubpicture_cache_t *) vlc_array_item_at_index(&cache->subpictures, i_sub);
assert(vasubpic);
VAStatus status = SubpictureUnlink(conn, surface->i_id, vasubpic->i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "- %d unlink failed (status = %d)", i, status);
}
vlc_mutex_unlock(&sys->cache_lock);
#endif
}
/* */
free(surface->subpicture);
surface->subpicture = NULL;
surface->i_sub = 0;
picture->p_sys->surface = NULL;
}
}
free(picture->p_sys);
picture->p_sys = NULL;
}
......@@ -627,16 +917,37 @@ static void Render(vout_display_t *vd, picture_t *picture, subpicture_t *subpict
assert(!subpicture->b_ephemer);
/* Cleanup for reclaimed surface */
if (picture->p_sys &&
picture->p_sys->surface &&
picture->p_sys->surface->subpicture &&
if (picture->p_sys && picture->p_sys->surface &&
(picture->p_sys->surface->i_cache != VA_INVALID_ID) &&
(picture->format.i_chroma == VLC_CODEC_VAAPI_SURFACE))
{
assert(0);
#if 0
vlc_va_surface_t *surface = picture->p_sys->surface;
SubpictureDestroy(sys->conn, &surface->i_id,
surface->subpicture, surface->i_sub);
surface->subpicture = NULL;
surface->i_sub = 0;
if (surface->i_cache != VA_INVALID_ID)
{
vlc_mutex_lock(&sys->cache_lock);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "unlink surface %d cache %d", surface->i_id, surface->i_cache);
#endif
subpicture_cache_t *cache = cache_find(&sys->cache, surface->i_cache);
assert(cache);
const int count = vlc_array_count(&cache->subpictures);
for (unsigned int i = 0; i < count; i++)
{
vasubpicture_cache_t *sub = vlc_array_item_at_index(&cache->subpictures, i);
assert(sub);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "- %u: subid %d", i, sub->i_id);
#endif
VAStatus status = SubpictureUnlink(sys->conn, surface->i_id, sub->i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "failed unlinking (error %d)", status);
}
vlc_mutex_unlock(&sys->cache_lock);
}
#endif
}
assert(picture->format.i_chroma == VLC_CODEC_VAAPI_SURFACE);
......@@ -657,9 +968,65 @@ static void Render(vout_display_t *vd, picture_t *picture, subpicture_t *subpict
}
}
if ((i_region > 0) &&
(RenderDirectSubpicture(vd, picture, subpicture, i_region) != VLC_SUCCESS))
if (i_region == 0)
return;
again:
/* same as previous subpicture? */
if ((sys->render.prev_subpicture == subpicture) &&
(sys->render.i_cache != VA_INVALID_ID) &&
(sys->render.i_start == subpicture->i_start) &&
(sys->render.i_stop == subpicture->i_stop))
{
assert(sys->render.i_cache != VA_INVALID_ID);
vlc_mutex_lock(&sys->cache_lock);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "reuse subpicture %p prev %p cache %d",
subpicture, sys->render.prev_subpicture,
sys->render.i_cache);
#endif
subpicture_cache_t *cache = (subpicture_cache_t *) cache_find(&sys->cache, sys->render.i_cache);
if (!cache)
{
msg_Dbg(vd, "did not find cached subpictures, resetting");
sys->render.i_cache = VA_INVALID_ID;
sys->render.prev_subpicture = NULL;
vlc_mutex_unlock(&sys->cache_lock);
goto again;
}
if ((cache->i_start != subpicture->i_start) &&
(cache->i_stop != subpicture->i_stop))
{
msg_Dbg(vd, "different cached subpictures, resetting");
sys->render.i_cache = VA_INVALID_ID;
sys->render.prev_subpicture = NULL;
vlc_mutex_unlock(&sys->cache_lock);
goto again;
}
if (RenderCachedSubpictures(vd, picture, subpicture, cache) != VLC_SUCCESS)
{
msg_Dbg(vd, "failed using cached subpictures, resetting");
sys->render.i_cache = VA_INVALID_ID;
sys->render.prev_subpicture = NULL;
vlc_mutex_unlock(&sys->cache_lock);
goto again;
}
vlc_mutex_unlock(&sys->cache_lock);
}
else
{
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "new subpicture %p prev %p", subpicture, sys->render.prev_subpicture);
#endif
if (RenderDirectSubpicture(vd, picture, subpicture) != VLC_SUCCESS)
{
msg_Err(vd, "failed rendering subtitles");
return;
}
sys->render.prev_subpicture = subpicture;
sys->render.i_start = subpicture->i_start;
sys->render.i_stop = subpicture->i_stop;
}
}
static void ReleaseSurface(vlc_va_surface_t *surface)
......@@ -697,7 +1064,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
if (pic->p_sys == NULL)
{
assert(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE);
msg_Err(vd, "Discarding picture without picture_sys_t information");
msg_Err(vd, "discarding picture without picture_sys_t information");
if (subpicture)
subpicture_Delete(subpicture);
picture_Release(pic);
......@@ -707,7 +1074,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
if (pic->p_sys->surface == NULL)
{
assert(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE);
msg_Err(vd, "Discarding picture without surface information: %p", pic);
msg_Err(vd, "discarding picture without surface information: %p", pic);
if (subpicture)
subpicture_Delete(subpicture);
picture_Release(pic);
......@@ -723,7 +1090,7 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
(pic->format.i_chroma == VLC_CODEC_VAAPI_SURFACE))
{
/* Reset picture */
msg_Err(vd, "Reclaimed picture - id=%d, order=%d, refcount=%d (%p)",
msg_Err(vd, "reclaimed picture - id=%d, order=%d, refcount=%d (%p)",
surface->i_id, surface->i_order, surface->i_refcount, pic);
if (surface->i_refcount > 1)
surface->i_refcount = 1;
......@@ -734,17 +1101,64 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
DisplayVASurface(vd, surface->i_id, pic);
cleanup:
if (surface->subpicture)
SubpictureDestroy(sys->conn, &surface->i_id,
surface->subpicture, surface->i_sub);
surface->subpicture = NULL;
if (surface->i_cache != VA_INVALID_ID)
{
vlc_mutex_lock(&sys->cache_lock);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "unlink surface %d cache %d", surface->i_id, surface->i_cache);
#endif
subpicture_cache_t *cache = cache_find(&sys->cache, surface->i_cache);
assert(cache);
const int count = vlc_array_count(&cache->subpictures);
for (int i = 0; i < count; i++)
{
vasubpicture_cache_t *sub = vlc_array_item_at_index(&cache->subpictures, i);
assert(sub);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "- %u: subid %d", i, sub->i_id);
#endif
VAStatus status = SubpictureUnlink(sys->conn, surface->i_id, sub->i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "failed unlinking (error %d)", status);
}
vlc_mutex_unlock(&sys->cache_lock);
}
if (subpicture &&
(mdate() > subpicture->i_stop) &&
(surface->i_cache != VA_INVALID_ID) &&
(surface->i_cache != sys->display.i_cache))
{
if (sys->display.i_cache != VA_INVALID_ID)
{
vlc_mutex_lock(&sys->cache_lock);
assert(sys->display.i_cache != surface->i_cache);
#ifdef VAAPI_DEBUG
msg_Dbg(vd, "display subpicture %p cache size %d, search for cache %d",
subpicture, vlc_array_count(&sys->cache), sys->display.i_cache);
#endif
subpicture_cache_t *cache;
cache = (subpicture_cache_t*) cache_find(&sys->cache, sys->display.i_cache);
assert(cache);
int index = vlc_array_index_of_item(&sys->cache, (void*)cache);
vlc_array_remove(&sys->cache, index);
SubpictureCacheClean(vd, sys->conn, cache);
cache_destroy(cache);
cache = NULL;
vlc_mutex_unlock(&sys->cache_lock);
}
}
sys->display.i_cache = surface->i_cache;
surface->i_cache = VA_INVALID_ID;
ReleaseSurface(surface);
if (subpicture)
subpicture_Delete(subpicture);
ReleaseSurface(surface);
pic->p_sys->surface = NULL;
picture_Release(pic);
}
......
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