Commit 7224e5eb authored by Jean-Paul Saman's avatar Jean-Paul Saman

codec/avcodec/vaapi: subtitle support for RGBA only

Each subpicture region is merged into one for libva 0.31.0 and applied
on top of the display surface by the GPU.
.
Higher versions of the libva library can handle multiple subpicture
region associations on a surface with vaAssociateSubpicture2() function.

- subtitles are readable
- some are clipped, this needs fixing
- crash in vlc_memcpy() (line: 545 of vaapi_x11.c file)
- fix positioning of subtitles (region->i_align)
- alpha is applied when available
- chroma is applied when available
parent 2b25e3e9
......@@ -213,6 +213,8 @@ 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_sub = 0;
p_surface->subpicture = NULL;
vlc_mutex_init(&p_surface->lock);
}
......@@ -393,17 +395,18 @@ static vlc_va_surface_t *FindSurface( vlc_va_t *p_external, const VASurfaceID i_
for( int i = 0; i < p_va->i_surface_count; i++ )
{
vlc_va_surface_t *p_tmp = &p_va->p_surface[i];
vlc_mutex_lock(&p_tmp->lock);
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);
vlc_mutex_unlock(&p_tmp->lock);
break;
}
vlc_mutex_unlock(&p_tmp->lock);
}
return p_surface;
}
......@@ -432,8 +435,10 @@ static int DisplayPicture( vlc_va_t *p_external, picture_t *p_picture, AVFrame *
if( !p_picture->p_sys->surface )
return VLC_EGENERIC;
vlc_mutex_lock(&p_picture->p_sys->surface->lock);
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;
vlc_mutex_unlock(&p_picture->p_sys->surface->lock);
return VLC_SUCCESS;
}
......@@ -465,7 +470,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++;
vlc_mutex_unlock(&p_surface->lock);
/* */
for( int i = 0; i < 4; i++ )
......@@ -476,6 +480,7 @@ static int Get( vlc_va_t *p_external, AVFrame *p_ff )
if( i == 0 || i == 3 )
p_ff->data[i] = (void*)(uintptr_t)p_surface->i_id;/* Yummie */
}
vlc_mutex_unlock(&p_surface->lock);
return VLC_SUCCESS;
}
static void Release( vlc_va_t *p_external, AVFrame *p_ff )
......@@ -488,13 +493,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);
if( p_surface->i_id == i_surface_id )
p_surface->i_refcount--;
vlc_mutex_unlock(&p_surface->lock);
}
}
}
static void Close( vlc_va_vaapi_t *p_va )
......
......@@ -31,12 +31,37 @@ struct vlc_va_conn_t
vlc_va_conn_t *vlc_va_Initialize(const char *display_name);
void vlc_va_Terminate(vlc_va_conn_t *conn);
typedef struct
{
VASubpictureID i_id; /* VASubpictureIDs */
VAImage image;
/* positioning */
unsigned int i_x;
unsigned int i_y;
unsigned int i_width;
unsigned int i_height;
/* */
unsigned int i_alpha;
struct {
unsigned int min;
unsigned int max;
unsigned int mask;
} chromakey;
} vlc_va_subpicture_t;
typedef struct
{
VASurfaceID i_id;
int i_refcount;
unsigned int i_order;
/* subpicture */
vlc_va_subpicture_t *subpicture;
unsigned int i_sub; /* number of vlc_va_subpicures_t */
vlc_mutex_t lock;
} vlc_va_surface_t;
......
......@@ -44,6 +44,7 @@
#endif
#include "avcodec.h"
#include "copy.h"
#include <vlc_xlib.h>
#include <libavcodec/vaapi.h>
......@@ -54,6 +55,11 @@
#include <X11/Xutil.h>
static const vlc_fourcc_t va_subpicture_chromas[] = {
VLC_CODEC_RGBA,
0
};
struct vout_display_sys_t
{
vlc_va_conn_t *conn;
......@@ -61,16 +67,62 @@ struct vout_display_sys_t
vout_window_t *embed;
picture_pool_t *pool; /* picture pool */
VAImageFormat sub_fmt; /* Subpicture format VA_FOURCC_RGBA */
unsigned int i_display_order;
bool b_alpha; /* whether subpictures support alpha */
bool b_chroma; /* whether subpictures support chroma keying */
bool visible; /* whether to draw */
};
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 int VASubtitleFourCC(vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
int num = vaMaxNumSubpictureFormats(sys->conn->p_display);
if (num <= 0)
goto out_warning;
VAImageFormat *p_fmt = calloc(num, sizeof(*p_fmt));
unsigned int *flags = calloc(num, sizeof(*flags));
if (!p_fmt || !flags)
goto out;
unsigned int num_fmt = 0;
VAStatus status = vaQuerySubpictureFormats(sys->conn->p_display,
p_fmt, flags, &num_fmt);
if (status != VA_STATUS_SUCCESS)
goto out;
for (unsigned int i = 0; i < num_fmt; i++)
{
VAImageFormat format = p_fmt[i];
if (format.fourcc == VA_FOURCC_RGBA)
{
sys->b_alpha = (flags[i] & VA_SUBPICTURE_GLOBAL_ALPHA);
sys->b_chroma = (flags[i] & VA_SUBPICTURE_CHROMA_KEYING);
memcpy((void*)&sys->sub_fmt, (void*)&format, sizeof(VAImageFormat));
free(p_fmt);
free(flags);
return VLC_SUCCESS;
}
}
out:
free(p_fmt);
free(flags);
out_warning:
msg_Warn(vd, "VAAP-X11 does not support fourcc RGBA subtitles");
return VLC_EGENERIC;
}
static int FindVAFourCC(vout_display_t *vd)
{
vout_display_sys_t *sys = (vout_display_sys_t *) vd->sys;
......@@ -139,7 +191,7 @@ int OpenVaapiX11 (vlc_object_t *obj)
if( !vlc_xlib_init( obj ) )
return VLC_EGENERIC;
vout_display_sys_t *sys = malloc(sizeof(*sys));
vout_display_sys_t *sys = calloc(1, sizeof(*sys));
if (unlikely(sys == NULL))
return VLC_ENOMEM;
......@@ -147,6 +199,9 @@ int OpenVaapiX11 (vlc_object_t *obj)
sys->conn = NULL;
sys->pool = NULL;
sys->b_alpha = false;
sys->b_chroma = false;
sys->visible = false;
sys->i_display_order = 0;
......@@ -171,16 +226,24 @@ int OpenVaapiX11 (vlc_object_t *obj)
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;
if (VASubtitleFourCC(vd) == VLC_SUCCESS)
{
info.subpicture_chromas = va_subpicture_chromas;
vd->prepare = Render;
}
else
{
vd->prepare = NULL;
info.subpicture_chromas = NULL;
}
vd->pool = Pool;
vd->prepare = NULL; //PictureRender;
vd->display = DisplayPicture;
vd->control = Control;
vd->manage = NULL; //Manage;
vd->info = info;
/* */
bool is_fullscreen = vd->cfg->is_fullscreen;
......@@ -219,6 +282,7 @@ void CloseVaapiX11 (vlc_object_t *obj)
picture_pool_Delete(sys->pool);
sys->pool = NULL;
}
free(vd->sys);
}
......@@ -295,52 +359,509 @@ static int Control (vout_display_t *vd, int query, va_list ap)
}
}
static void PictureRelease(picture_t *pic)
static VASubpictureID SubpictureCreate(vout_display_t *vd, vlc_va_surface_t *surface,
vlc_va_subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
VAStatus status;
VASubpictureID subpic = VA_INVALID_ID;
status = vaCreateSubpicture(sys->conn->p_display, subpicture->image.image_id, &subpic);
if (status != VA_STATUS_SUCCESS)
return VA_INVALID_ID;
if (sys->b_alpha)
{
assert(!sys->b_chroma);
status = vaSetSubpictureGlobalAlpha(sys->conn->p_display, subpic,
subpicture->i_alpha);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed applying alpha value to subpicture");
}
if (sys->b_chroma)
{
assert(!sys->b_alpha);
status = vaSetSubpictureChromakey(sys->conn->p_display, subpic,
subpicture->chromakey.min,
subpicture->chromakey.max,
subpicture->chromakey.mask);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed applying chroma valuesto subpicture");
}
int flags = sys->b_alpha ? VA_SUBPICTURE_GLOBAL_ALPHA :
(sys->b_chroma ? VA_SUBPICTURE_CHROMA_KEYING : 0);
/* 4 Associate subpicture with surface */
status = vaAssociateSubpicture(sys->conn->p_display, subpic,
&surface->i_id, 1, /* array of surfaces */
/* src rectangle */
0, 0,
subpicture->image.width, subpicture->image.height,
/* dest rectangle */
subpicture->i_x, 0, /*subpicture->i_y,*/
subpicture->image.width, subpicture->image.height,
flags);
if (status != VA_STATUS_SUCCESS)
{
vaDestroySubpicture(sys->conn->p_display, subpic);
return VA_INVALID_ID;
}
return subpic;
}
static void SubpictureDestroy(vout_display_t *vd, vlc_va_surface_t *surface)
{
vout_display_sys_t *sys = vd->sys;
vlc_va_subpicture_t *subpicture = surface->subpicture;
int i_sub = surface->i_sub;
surface->i_sub = 0;
surface->subpicture = NULL;
VAStatus status;
for (int i = 0; i < i_sub; i++)
{
if ((surface->i_id != VA_INVALID_ID) &&
(subpicture[i].i_id != VA_INVALID_ID))
{
status = vaDeassociateSubpicture(sys->conn->p_display,
subpicture[i].i_id,
&surface->i_id, 1);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed unlinking subpicture from surface (%d)", status);
}
if (subpicture[i].i_id != VA_INVALID_ID)
{
status = vaDestroySubpicture(sys->conn->p_display,
subpicture[i].i_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed destroying subpicture");
}
if (subpicture[i].image.image_id != VA_INVALID_ID)
{
status = vaDestroyImage(sys->conn->p_display,
subpicture[i].image.image_id);
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "Failed destroying subpicture image");
}
}
/* */
free(subpicture);
}
static int CopyPictureToVAImage(vout_display_t *vd, picture_t *pic,
vlc_va_subpicture_t *vasubpic, VAImageFormat *fmt)
{
vout_display_sys_t *sys = vd->sys;
assert(pic->format.i_width > 0 && pic->format.i_height > 0);
assert(pic->format.i_visible_width > 0 && pic->format.i_visible_height > 0);
assert(fmt->fourcc == VA_FOURCC_RGBA);
assert(vasubpic->image.image_id == VA_INVALID_ID);
VAStatus status;
status = vaCreateImage(sys->conn->p_display, fmt,
pic->format.i_width,
pic->format.i_height,
&vasubpic->image);
if (status != VA_STATUS_SUCCESS)
return VLC_EGENERIC;
/* Sanity checks */
if ((vasubpic->image.num_planes == 0) ||
(vasubpic->image.height == 0) ||
(vasubpic->image.width == 0))
{
msg_Err(vd, "subpicture region: planes %d, depth %d, width %d, height %d bpp %d",
vasubpic->image.num_planes, vasubpic->image.format.depth,
vasubpic->image.width, vasubpic->image.height,
vasubpic->image.format.bits_per_pixel);
goto out_va_free;
}
assert(vasubpic->image.data_size <=
pic->format.i_width * pic->format.i_height
* (pic->format.i_bits_per_pixel/8));
void *p_base;
status = vaMapBuffer(sys->conn->p_display, vasubpic->image.buf, &p_base);
if (status != VA_STATUS_SUCCESS)
{
msg_Err(vd, "Failed mapping image for copying (%d)", status);
goto out_va_free;
}
for (unsigned int i_plane = 0; i_plane < vasubpic->image.num_planes; i_plane++)
{
/* Does the pitch match? Then just copy it directly */
if (vasubpic->image.pitches[i_plane] == (unsigned int)pic->p[i_plane].i_pitch)
{
vlc_memcpy((uint8_t*)p_base + vasubpic->image.offsets[i_plane],
pic->p[i_plane].p_pixels + pic->format.i_x_offset +
(pic->format.i_y_offset * pic->p[i_plane].i_pitch),
pic->p[i_plane].i_pitch * pic->p[i_plane].i_lines);
}
else
{
/* proceed line by line */
uint8_t *p_in = pic->p[i_plane].p_pixels + pic->format.i_x_offset;
uint8_t *p_out = (uint8_t*)p_base + vasubpic->image.offsets[i_plane];
int i_line = pic->format.i_y_offset * pic->p[i_plane].i_pitch;
for (; i_line < pic->p[i_plane].i_visible_lines; i_line++)
{
/* NOTE: image.pitch[i_plane] includes image.offset[i_plane], thus
* visible_pitch = image.pitch[i_plane] - image.offset[i_plane] */
size_t i_size = vasubpic->image.pitches[i_plane] - vasubpic->image.offsets[i_plane];
#if 0
msg_Info(vd, "line %d pitch %d/%d offset %d/%d datasize %d consumed %d",
i_line,
vasubpic->image.pitches[i_plane], pic->p[i_plane].i_visible_pitch,
vasubpic->image.offsets[i_plane], pic->format.i_x_offset,
vasubpic->image.data_size, (p_out - (uint8_t*)p_base));
#endif
assert((uint8_t*)p_out + i_size <=
(uint8_t*)p_base + vasubpic->image.data_size);
assert(i_size <= (size_t)pic->p[i_plane].i_pitch);
vlc_memcpy(p_out, p_in, i_size);
p_in += pic->p[i_plane].i_pitch + pic->format.i_x_offset;
p_out += vasubpic->image.pitches[i_plane];
}
}
}
status = vaUnmapBuffer(sys->conn->p_display, vasubpic->image.buf);
if (status != VA_STATUS_SUCCESS)
{
msg_Err(vd, "Failed unmapping image for copying (%d)(buf id: %d)",
status, vasubpic->image.buf);
goto out_va_free;
}
return VLC_SUCCESS;
out_va_free:
vaDestroyImage(sys->conn->p_display, vasubpic->image.image_id);
vasubpic->image.image_id = VA_INVALID_ID;
return VLC_EGENERIC;
}
static void MergePicture(const picture_t *src, picture_t *dest)
{
assert(dest->i_planes == src->i_planes);
for (int i_plane = 0; i_plane < src->i_planes; i_plane++)
{
/* Does the pitch match? Then just copy it directly */
if (src->p[i_plane].i_pitch == dest->p[i_plane].i_pitch)
{
vlc_memcpy(dest->p[i_plane].p_pixels, src->p[i_plane].p_pixels,
src->p[i_plane].i_pitch * src->p[i_plane].i_lines);
}
else
{
/* proceed line by line */
uint8_t *p_in = src->p[i_plane].p_pixels;
uint8_t *p_out = dest->p[i_plane].p_pixels;
for (int i_line = 0; i_line < src->p[i_plane].i_lines; i_line++)
{
vlc_memcpy(p_out, p_in, src->p[i_plane].i_pitch);
p_in += src->p[i_plane].i_pitch;
p_out += dest->p[i_plane].i_pitch;
}
}
}
}
static void SubpictureRegionPlace(unsigned int *pi_x, unsigned int *pi_y,
const subpicture_t *p_subpic,
const subpicture_region_t *p_region)
{
assert(p_region->i_x != INT_MAX && p_region->i_y != INT_MAX);
if (p_subpic->b_absolute)
{
*pi_x = p_region->i_x;
*pi_y = p_region->i_y;
}
else
{
if (p_region->i_align & SUBPICTURE_ALIGN_TOP)
{
*pi_y = p_region->i_y;
}
else if (p_region->i_align & SUBPICTURE_ALIGN_BOTTOM)
{
*pi_y = p_subpic->i_original_picture_height - p_region->fmt.i_height - p_region->i_y;
}
else
{
*pi_y = p_subpic->i_original_picture_height / 2 - p_region->fmt.i_height / 2;
}
if (p_region->i_align & SUBPICTURE_ALIGN_LEFT)
{
*pi_x = p_region->i_x;
}
else if (p_region->i_align & SUBPICTURE_ALIGN_RIGHT)
{
*pi_x = p_subpic->i_original_picture_width - p_region->fmt.i_width - p_region->i_x;
}
else
{
*pi_x = p_subpic->i_original_picture_width / 2 - p_region->fmt.i_width / 2;
}
}
}
static void Render(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
if (!subpicture)
return;
if (subpicture->b_ephemer)
return;
if (!picture->p_sys && !picture->p_sys->surface)
return;
vlc_mutex_lock(&picture->p_sys->surface->lock);
/* count RGBA subpicture regions */
int i_region = 0; int i_alpha = 0;
unsigned int i_height = 0;
unsigned int i_visible_height = 0;
subpicture_region_t *region = NULL, *first = NULL;
for (region = subpicture->p_region; region != NULL; region = region->p_next)
{
/* Skip non-RGBA regions for now */
if (region->fmt.i_chroma == VLC_CODEC_RGBA)
{
i_alpha = __MAX(region->i_alpha, i_alpha);
i_height = __MAX(region->p_picture->format.i_height, i_height);
i_visible_height = __MAX(region->p_picture->format.i_visible_height, i_visible_height);
if (!first)
first = region;
i_region++;
}
}
if (i_region == 0)
goto out_unlock;
#if 1
if (!first)
goto out_unlock;
vlc_va_subpicture_t *vasubpic = (vlc_va_subpicture_t*) calloc(1, sizeof(vlc_va_subpicture_t));
if (!vasubpic)
goto out_unlock;
video_format_t subfmt;
memcpy(&subfmt, &first->p_picture->format, sizeof(video_format_t));
#if 1
subfmt.i_height += i_height;
subfmt.i_visible_height += i_visible_height;
#else
subfmt.i_height = __MAX(subfmt.i_height, i_height);
subfmt.i_visible_height = __MAX(subfmt.i_visible_height, i_visible_height);
#endif
picture_t *subpic = picture_NewFromFormat(&subfmt);
if (!subpic)
{
free(vasubpic);
goto out_unlock;
}
int i_sub = 0;
for (region = subpicture->p_region; region != NULL; region = region->p_next)
{
/* Skip non-RGBA regions for now */
if (region->fmt.i_chroma == VLC_CODEC_RGBA)
MergePicture(region->p_picture, subpic);
}
/* 1 Create VAImage for each subpicture region */
/* 2 Copy pixels from region into VAImage */
vasubpic->image.image_id = VA_INVALID_ID;
int err = CopyPictureToVAImage(vd, subpic, vasubpic, &sys->sub_fmt);
if (err != VLC_SUCCESS)
{
msg_Err(vd, "Failed to copy region into vaImage");
picture_Release(subpic);
free(vasubpic);
goto out_unlock;
}
/* set alpha and chromakey values */
vasubpic->i_alpha = __MAX(subpicture->i_alpha, i_alpha);
vasubpic->image.format.alpha_mask = 0xFFF0;
vasubpic->image.format.red_mask = subpic->format.i_rmask;
vasubpic->image.format.blue_mask = subpic->format.i_bmask;
vasubpic->image.format.green_mask = subpic->format.i_gmask;
vasubpic->chromakey.min = 0x0; /* ? */
vasubpic->chromakey.max = 0x0; /* ? */
vasubpic->chromakey.mask = (subpic->format.i_rmask << 24) |
(subpic->format.i_gmask << 16) |
(subpic->format.i_bmask << 8) | 0;
/* subpicture positioning */
vout_display_place_t place;
vout_display_PlacePicture (&place, &vd->source, vd->cfg, false);
SubpictureRegionPlace(&vasubpic->i_x, &vasubpic->i_y,
subpicture, first);
vasubpic->i_width = vasubpic->image.width;
vasubpic->i_height = vasubpic->image.height;
#if 0
msg_Info(vd, "Position: (%d,%d)/(%d,%d), Display: (%d,%d)/(%d,%d) (%d,%d)",
vasubpic->i_x, vasubpic->i_y,
vasubpic->i_width, vasubpic->i_height,
place.x, place.y,
place.width, place.height,
subpicture->i_original_picture_width,
subpicture->i_original_picture_height);
#endif
/* 3 Create Subpicture */
vasubpic->i_id = SubpictureCreate(vd, picture->p_sys->surface,
vasubpic);
if (vasubpic->i_id == VA_INVALID_ID)
{
vaDestroyImage(sys->conn->p_display, vasubpic->image.image_id);
picture_Release(subpic);
free(vasubpic);
assert(0);
goto out_unlock;
}
i_sub = 1;
picture_Release(subpic);
#else
vlc_va_subpicture_t *vasubpic = (vlc_va_subpicture_t*) calloc(i_region, sizeof(vlc_va_subpicture_t));
if (!vasubpic)
goto out_unlock;
int i_sub = 0;
for (region = subpicture->p_region; region != NULL; region = region->p_next)
{
/* Skip non-RGBA regions for now */
if (region->fmt.i_chroma != VLC_CODEC_RGBA)
continue;
picture_t *subpic = picture_NewFromFormat(&region->p_picture->format);
if (subpic)
{
/* 1 Create VAImage for each subpicture region */
/* 2 Copy pixels from region into VAImage */
vasubpic[i_sub].image.image_id = VA_INVALID_ID;
int err = CopyPictureToVAImage(vd, subpic, &vasubpic[i_sub], &sys->sub_fmt);
if (err != VLC_SUCCESS)
{
msg_Err(vd, "Failed to copy region into vaImage");
picture_Release(subpic);
continue;
}
/* set alpha and chromakey values */
vasubpic[i_sub].i_alpha = region->i_alpha;
vasubpic[i_sub].image.format.alpha_mask = 0xFFF0;
vasubpic[i_sub].image.format.red_mask = subpic->format.i_rmask;
vasubpic[i_sub].image.format.blue_mask = subpic->format.i_bmask;
vasubpic[i_sub].image.format.green_mask = subpic->format.i_gmask;
vasubpic[i_sub].chromakey.min = 0x0; /* ? */
vasubpic[i_sub].chromakey.max = 0x0; /* ? */
vasubpic[i_sub].chromakey.mask = (subpic->format.i_rmask << 24) |
(subpic->format.i_gmask << 16) |
(subpic->format.i_bmask << 8) | 0;
/* subpicture positioning */
SubpictureRegionPlace(&vasubpic[i_sub].i_x, &vasubpic[i_sub].i_y,
subpicture, region);
vasubpic[i_sub].i_width = vasubpic[i_sub].image.width;
vasubpic[i_sub].i_height = vasubpic[i_sub].image.height;
/* 3 Create Subpicture */
vasubpic[i_sub].i_id = SubpictureCreate(vd, picture->p_sys->surface,
&vasubpic[i_sub]);
if (vasubpic[i_sub].i_id == VA_INVALID_ID)
{
picture_Release(subpic);
vaDestroyImage(sys->conn->p_display, vasubpic[i_sub].image.image_id);
free(vasubpic);
goto out_unlock;
}
i_sub++;
picture_Release(subpic);
}
}
#endif
/* remember what was created, so it can be released in DisplayPicture() */
picture->p_sys->surface->subpicture = vasubpic;
picture->p_sys->surface->i_sub = i_sub;
out_unlock:
vlc_mutex_unlock(&picture->p_sys->surface->lock);
}
static void PictureReleaseLocked(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; /* FIXME: needed ? */
}
}
static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *subpicture)
{
vout_display_sys_t *sys = vd->sys;
VLC_UNUSED(subpicture);
#if 0
if (subpicture)
{
/* FIXME: blend subpicture into VAAPI structure */
}
#endif
assert(pic->p_sys);
if (pic->p_sys->surface == NULL)
{
/* FIXME: display picture with surface */
msg_Err(vd, "Discarding picture - no surface information");
if (subpicture)
subpicture_Delete(subpicture);
picture_Release(pic);
return;
}
vlc_mutex_lock(&pic->p_sys->surface->lock);
unsigned int i_order = (sys->i_display_order > 0) ?
sys->i_display_order++ : pic->p_sys->surface->i_order;
if (i_order != pic->p_sys->surface->i_order)
{
/* Reset picture */
vlc_mutex_lock(&pic->p_sys->surface->lock);
msg_Err(vd, "Reclaimed picture - id=%d, order=%d, refcount=%d (%p)",
pic->p_sys->surface->i_id, pic->p_sys->surface->i_order,
pic->p_sys->surface->i_refcount, pic);
if (pic->p_sys->surface->i_refcount > 1)
pic->p_sys->surface->i_refcount = 1;
if (subpicture)
{
SubpictureDestroy(vd, pic->p_sys->surface);
subpicture_Delete(subpicture);
}
PictureReleaseLocked(pic);
vlc_mutex_unlock(&pic->p_sys->surface->lock);
pic->p_sys->surface = NULL;
picture_Release(pic);
......@@ -354,17 +875,14 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
VAStatus status = vaPutSurface(sys->conn->p_display,
i_surface_id,
sys->embed->handle.xid,
pic->format.i_y_offset, pic->format.i_x_offset,
pic->format.i_x_offset, pic->format.i_y_offset,
pic->format.i_visible_width, pic->format.i_visible_height,
place.y, place.x, place.width, place.height,
place.x, place.y, place.width, place.height,
NULL, 0, /* clipping */
/* NOTE: vaCreateContext() specifies VA_PROGRESSIVE */
#if 0
VA_FRAME_PICTURE);
#else
pic->b_progressive ? VA_FRAME_PICTURE :
(pic->b_top_field_first ? VA_TOP_FIELD : VA_BOTTOM_FIELD));
#endif
if (status != VA_STATUS_SUCCESS)
msg_Err(vd, "failed displaying picture (id=%d) %d", i_surface_id, status);
#if 0
......@@ -373,9 +891,17 @@ static void DisplayPicture(vout_display_t *vd, picture_t *pic, subpicture_t *sub
pic->p_sys->surface->i_id, pic->p_sys->surface->i_order,
pic->p_sys->surface->i_refcount);
#endif
if ((status != VA_STATUS_ERROR_INVALID_SURFACE) &&
(status != VA_STATUS_ERROR_INVALID_DISPLAY))
PictureRelease(pic);
if (subpicture)
{
SubpictureDestroy(vd, pic->p_sys->surface);
subpicture_Delete(subpicture);
}
PictureReleaseLocked(pic);
vlc_mutex_unlock(&pic->p_sys->surface->lock);
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