gstreamer/gst-libs/gst/vaapi/gstvaapicontext.c
Gwenole Beauchesne 67eea92044 libs: drop GST_VAAPI_IS_xxx() helper macros.
Drop obsolete GST_VAAPI_IS_xxx() helper macros since we are no longer
deriving from GObject and so those were only checking for whether the
argument was NULL or not. This is now irrelevant, and even confusing
to some extent, because we no longer have type checking.

Note: this incurs more type checking (review) but the libgstvaapi is
rather small, so this is manageable.
2013-05-23 18:15:48 +02:00

987 lines
27 KiB
C

/*
* gstvaapicontext.c - VA context abstraction
*
* Copyright (C) 2010-2011 Splitted-Desktop Systems
* Copyright (C) 2011-2013 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
/**
* SECTION:gstvaapicontext
* @short_description: VA context abstraction
*/
#include "sysdeps.h"
#include <assert.h>
#include "gstvaapicompat.h"
#include "gstvaapicontext.h"
#include "gstvaapiobject_priv.h"
#include "gstvaapisurface.h"
#include "gstvaapisurface_priv.h"
#include "gstvaapisurfacepool.h"
#include "gstvaapisurfaceproxy.h"
#include "gstvaapivideopool_priv.h"
#include "gstvaapiimage.h"
#include "gstvaapisubpicture.h"
#include "gstvaapiutils.h"
#define DEBUG 1
#include "gstvaapidebug.h"
typedef struct _GstVaapiContextClass GstVaapiContextClass;
/**
* GstVaapiContext:
*
* A VA context wrapper.
*/
struct _GstVaapiContext {
/*< private >*/
GstVaapiObject parent_instance;
GstVaapiContextInfo info;
VAConfigID config_id;
GPtrArray *surfaces;
GstVaapiVideoPool *surfaces_pool;
GPtrArray *overlays[2];
guint overlay_id;
};
/**
* GstVaapiContextClass:
*
* A VA context wrapper class.
*/
struct _GstVaapiContextClass {
/*< private >*/
GstVaapiObjectClass parent_class;
};
typedef struct _GstVaapiOverlayRectangle GstVaapiOverlayRectangle;
struct _GstVaapiOverlayRectangle {
GstVaapiContext *context;
GstVaapiSubpicture *subpicture;
GstVaapiRectangle render_rect;
guint seq_num;
guint layer_id;
GstBuffer *rect_buffer;
GstVideoOverlayRectangle *rect;
guint is_associated : 1;
};
static guint
get_max_ref_frames(GstVaapiProfile profile)
{
guint ref_frames;
switch (gst_vaapi_profile_get_codec(profile)) {
case GST_VAAPI_CODEC_H264: ref_frames = 16; break;
case GST_VAAPI_CODEC_JPEG: ref_frames = 0; break;
default: ref_frames = 2; break;
}
return ref_frames;
}
static inline void
gst_video_overlay_rectangle_replace(GstVideoOverlayRectangle **old_rect_ptr,
GstVideoOverlayRectangle *new_rect)
{
gst_mini_object_replace((GstMiniObject **)old_rect_ptr,
GST_MINI_OBJECT_CAST(new_rect));
}
#define overlay_rectangle_ref(overlay) \
gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(overlay))
#define overlay_rectangle_unref(overlay) \
gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(overlay))
#define overlay_rectangle_replace(old_overlay_ptr, new_overlay) \
gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_overlay_ptr), \
(GstVaapiMiniObject *)(new_overlay))
static void
overlay_rectangle_finalize(GstVaapiOverlayRectangle *overlay);
static gboolean
overlay_rectangle_associate(GstVaapiOverlayRectangle *overlay);
static gboolean
overlay_rectangle_deassociate(GstVaapiOverlayRectangle *overlay);
static inline const GstVaapiMiniObjectClass *
overlay_rectangle_class(void)
{
static const GstVaapiMiniObjectClass GstVaapiOverlayRectangleClass = {
sizeof(GstVaapiOverlayRectangle),
(GDestroyNotify)overlay_rectangle_finalize
};
return &GstVaapiOverlayRectangleClass;
}
static GstVaapiOverlayRectangle *
overlay_rectangle_new(GstVideoOverlayRectangle *rect, GstVaapiContext *context,
guint layer_id)
{
GstVaapiOverlayRectangle *overlay;
GstVaapiRectangle *render_rect;
guint width, height, flags;
gint x, y;
overlay = (GstVaapiOverlayRectangle *)
gst_vaapi_mini_object_new0(overlay_rectangle_class());
if (!overlay)
return NULL;
overlay->context = context;
overlay->seq_num = gst_video_overlay_rectangle_get_seqnum(rect);
overlay->layer_id = layer_id;
overlay->rect = gst_video_overlay_rectangle_ref(rect);
flags = gst_video_overlay_rectangle_get_flags(rect);
gst_buffer_replace(&overlay->rect_buffer,
gst_video_overlay_rectangle_get_pixels_unscaled_raw(rect, flags));
if (!overlay->rect_buffer)
goto error;
overlay->subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle(
GST_VAAPI_OBJECT_DISPLAY(context), rect);
if (!overlay->subpicture)
goto error;
gst_video_overlay_rectangle_get_render_rectangle(rect,
&x, &y, &width, &height);
render_rect = &overlay->render_rect;
render_rect->x = x;
render_rect->y = y;
render_rect->width = width;
render_rect->height = height;
return overlay;
error:
overlay_rectangle_unref(overlay);
return NULL;
}
static void
overlay_rectangle_finalize(GstVaapiOverlayRectangle *overlay)
{
gst_buffer_replace(&overlay->rect_buffer, NULL);
gst_video_overlay_rectangle_unref(overlay->rect);
if (overlay->subpicture) {
overlay_rectangle_deassociate(overlay);
gst_vaapi_object_unref(overlay->subpicture);
overlay->subpicture = NULL;
}
}
static gboolean
overlay_rectangle_associate(GstVaapiOverlayRectangle *overlay)
{
GstVaapiSubpicture * const subpicture = overlay->subpicture;
GPtrArray * const surfaces = overlay->context->surfaces;
guint i, n_associated;
if (overlay->is_associated)
return TRUE;
n_associated = 0;
for (i = 0; i < surfaces->len; i++) {
GstVaapiSurface * const surface = g_ptr_array_index(surfaces, i);
if (gst_vaapi_surface_associate_subpicture(surface, subpicture,
NULL, &overlay->render_rect))
n_associated++;
}
overlay->is_associated = TRUE;
return n_associated == surfaces->len;
}
static gboolean
overlay_rectangle_deassociate(GstVaapiOverlayRectangle *overlay)
{
GstVaapiSubpicture * const subpicture = overlay->subpicture;
GPtrArray * const surfaces = overlay->context->surfaces;
guint i, n_associated;
if (!overlay->is_associated)
return TRUE;
n_associated = surfaces->len;
for (i = 0; i < surfaces->len; i++) {
GstVaapiSurface * const surface = g_ptr_array_index(surfaces, i);
if (gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
n_associated--;
}
overlay->is_associated = FALSE;
return n_associated == 0;
}
static gboolean
overlay_rectangle_changed_pixels(GstVaapiOverlayRectangle *overlay,
GstVideoOverlayRectangle *rect)
{
guint flags;
GstBuffer *buffer;
if (overlay->seq_num == gst_video_overlay_rectangle_get_seqnum(rect))
return FALSE;
flags = to_GstVideoOverlayFormatFlags(
gst_vaapi_subpicture_get_flags(overlay->subpicture));
buffer = gst_video_overlay_rectangle_get_pixels_unscaled_raw(rect, flags);
if (!buffer)
return FALSE;
#if GST_CHECK_VERSION(1,0,0)
{
const guint n_blocks = gst_buffer_n_memory(buffer);
gsize ofs;
guint i;
if (buffer == overlay->rect_buffer)
return TRUE;
if (n_blocks != gst_buffer_n_memory(overlay->rect_buffer))
return FALSE;
for (i = 0; i < n_blocks; i++) {
GstMemory * const mem1 = gst_buffer_peek_memory(buffer, i);
GstMemory * const mem2 =
gst_buffer_peek_memory(overlay->rect_buffer, i);
if (!gst_memory_is_span(mem1, mem2, &ofs))
return FALSE;
}
}
#else
if (GST_BUFFER_DATA(overlay->rect_buffer) != GST_BUFFER_DATA(buffer))
return FALSE;
#endif
return TRUE;
}
static gboolean
overlay_rectangle_changed_render_rect(GstVaapiOverlayRectangle *overlay,
GstVideoOverlayRectangle *rect)
{
GstVaapiRectangle * const render_rect = &overlay->render_rect;
guint width, height;
gint x, y;
gst_video_overlay_rectangle_get_render_rectangle(rect,
&x, &y, &width, &height);
if (x == render_rect->x &&
y == render_rect->y &&
width == render_rect->width &&
height == render_rect->height)
return FALSE;
render_rect->x = x;
render_rect->y = y;
render_rect->width = width;
render_rect->height = height;
return TRUE;
}
static inline gboolean
overlay_rectangle_update_global_alpha(GstVaapiOverlayRectangle *overlay,
GstVideoOverlayRectangle *rect)
{
#ifdef HAVE_GST_VIDEO_OVERLAY_HWCAPS
const guint flags = gst_video_overlay_rectangle_get_flags(rect);
if (!(flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA))
return TRUE;
#endif
return gst_vaapi_subpicture_set_global_alpha(overlay->subpicture,
gst_video_overlay_rectangle_get_global_alpha(rect));
}
static gboolean
overlay_rectangle_update(GstVaapiOverlayRectangle *overlay,
GstVideoOverlayRectangle *rect, gboolean *reassociate_ptr)
{
if (overlay_rectangle_changed_pixels(overlay, rect))
return FALSE;
if (overlay_rectangle_changed_render_rect(overlay, rect))
*reassociate_ptr = TRUE;
if (!overlay_rectangle_update_global_alpha(overlay, rect))
return FALSE;
gst_video_overlay_rectangle_replace(&overlay->rect, rect);
return TRUE;
}
static inline GPtrArray *
overlay_new(void)
{
return g_ptr_array_new_with_free_func(
(GDestroyNotify)gst_vaapi_mini_object_unref);
}
static void
overlay_destroy(GPtrArray **overlay_ptr)
{
GPtrArray * const overlay = *overlay_ptr;
if (!overlay)
return;
g_ptr_array_unref(overlay);
*overlay_ptr = NULL;
}
static void
overlay_clear(GPtrArray *overlay)
{
if (overlay && overlay->len > 0)
g_ptr_array_remove_range(overlay, 0, overlay->len);
}
static GstVaapiOverlayRectangle *
overlay_lookup(GPtrArray *overlays, GstVideoOverlayRectangle *rect)
{
guint i;
for (i = 0; i < overlays->len; i++) {
GstVaapiOverlayRectangle * const overlay =
g_ptr_array_index(overlays, i);
if (overlay->rect == rect)
return overlay;
}
return NULL;
}
static gboolean
overlay_reassociate(GPtrArray *overlays)
{
guint i;
for (i = 0; i < overlays->len; i++)
overlay_rectangle_deassociate(g_ptr_array_index(overlays, i));
for (i = 0; i < overlays->len; i++) {
if (!overlay_rectangle_associate(g_ptr_array_index(overlays, i)))
return FALSE;
}
return TRUE;
}
static void
gst_vaapi_context_clear_overlay(GstVaapiContext *context)
{
overlay_clear(context->overlays[0]);
overlay_clear(context->overlays[1]);
context->overlay_id = 0;
}
static inline void
gst_vaapi_context_destroy_overlay(GstVaapiContext *context)
{
gst_vaapi_context_clear_overlay(context);
}
static void
unref_surface_cb(gpointer data, gpointer user_data)
{
GstVaapiSurface * const surface = GST_VAAPI_SURFACE(data);
gst_vaapi_surface_set_parent_context(surface, NULL);
gst_vaapi_object_unref(surface);
}
static void
gst_vaapi_context_destroy_surfaces(GstVaapiContext *context)
{
gst_vaapi_context_destroy_overlay(context);
if (context->surfaces) {
g_ptr_array_foreach(context->surfaces, unref_surface_cb, NULL);
g_ptr_array_free(context->surfaces, TRUE);
context->surfaces = NULL;
}
gst_vaapi_video_pool_replace(&context->surfaces_pool, NULL);
}
static void
gst_vaapi_context_destroy(GstVaapiContext *context)
{
GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context);
VAContextID context_id;
VAStatus status;
context_id = GST_VAAPI_OBJECT_ID(context);
GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id));
if (context_id != VA_INVALID_ID) {
GST_VAAPI_DISPLAY_LOCK(display);
status = vaDestroyContext(
GST_VAAPI_DISPLAY_VADISPLAY(display),
context_id
);
GST_VAAPI_DISPLAY_UNLOCK(display);
if (!vaapi_check_status(status, "vaDestroyContext()"))
g_warning("failed to destroy context %" GST_VAAPI_ID_FORMAT,
GST_VAAPI_ID_ARGS(context_id));
GST_VAAPI_OBJECT_ID(context) = VA_INVALID_ID;
}
if (context->config_id != VA_INVALID_ID) {
GST_VAAPI_DISPLAY_LOCK(display);
status = vaDestroyConfig(
GST_VAAPI_DISPLAY_VADISPLAY(display),
context->config_id
);
GST_VAAPI_DISPLAY_UNLOCK(display);
if (!vaapi_check_status(status, "vaDestroyConfig()"))
g_warning("failed to destroy config %" GST_VAAPI_ID_FORMAT,
GST_VAAPI_ID_ARGS(context->config_id));
context->config_id = VA_INVALID_ID;
}
}
static gboolean
gst_vaapi_context_create_overlay(GstVaapiContext *context)
{
if (!context->overlays[0] || !context->overlays[1])
return FALSE;
gst_vaapi_context_clear_overlay(context);
return TRUE;
}
static gboolean
gst_vaapi_context_create_surfaces(GstVaapiContext *context)
{
const GstVaapiContextInfo * const cip = &context->info;
GstCaps *caps;
GstVaapiSurface *surface;
guint i, num_surfaces;
/* Number of scratch surfaces beyond those used as reference */
const guint SCRATCH_SURFACES_COUNT = 4;
if (!gst_vaapi_context_create_overlay(context))
return FALSE;
if (!context->surfaces) {
context->surfaces = g_ptr_array_new();
if (!context->surfaces)
return FALSE;
}
if (!context->surfaces_pool) {
caps = gst_caps_new_simple(
GST_VAAPI_SURFACE_CAPS_NAME,
"type", G_TYPE_STRING, "vaapi",
"width", G_TYPE_INT, cip->width,
"height", G_TYPE_INT, cip->height,
NULL
);
if (!caps)
return FALSE;
context->surfaces_pool = gst_vaapi_surface_pool_new(
GST_VAAPI_OBJECT_DISPLAY(context),
caps
);
gst_caps_unref(caps);
if (!context->surfaces_pool)
return FALSE;
}
num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
gst_vaapi_video_pool_set_capacity(context->surfaces_pool, num_surfaces);
for (i = context->surfaces->len; i < num_surfaces; i++) {
surface = gst_vaapi_surface_new(
GST_VAAPI_OBJECT_DISPLAY(context),
GST_VAAPI_CHROMA_TYPE_YUV420,
cip->width, cip->height
);
if (!surface)
return FALSE;
gst_vaapi_surface_set_parent_context(surface, context);
g_ptr_array_add(context->surfaces, surface);
if (!gst_vaapi_video_pool_add_object(context->surfaces_pool, surface))
return FALSE;
}
return TRUE;
}
static gboolean
gst_vaapi_context_create(GstVaapiContext *context)
{
const GstVaapiContextInfo * const cip = &context->info;
GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(context);
VAProfile va_profile;
VAEntrypoint va_entrypoint;
VAConfigAttrib attrib;
VAContextID context_id;
VASurfaceID surface_id;
VAStatus status;
GArray *surfaces = NULL;
gboolean success = FALSE;
guint i;
if (!context->surfaces && !gst_vaapi_context_create_surfaces(context))
goto end;
surfaces = g_array_sized_new(
FALSE,
FALSE,
sizeof(VASurfaceID),
context->surfaces->len
);
if (!surfaces)
goto end;
for (i = 0; i < context->surfaces->len; i++) {
GstVaapiSurface * const surface =
g_ptr_array_index(context->surfaces, i);
if (!surface)
goto end;
surface_id = GST_VAAPI_OBJECT_ID(surface);
g_array_append_val(surfaces, surface_id);
}
assert(surfaces->len == context->surfaces->len);
if (!cip->profile || !cip->entrypoint)
goto end;
va_profile = gst_vaapi_profile_get_va_profile(cip->profile);
va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint(cip->entrypoint);
GST_VAAPI_DISPLAY_LOCK(display);
attrib.type = VAConfigAttribRTFormat;
status = vaGetConfigAttributes(
GST_VAAPI_DISPLAY_VADISPLAY(display),
va_profile,
va_entrypoint,
&attrib, 1
);
GST_VAAPI_DISPLAY_UNLOCK(display);
if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
goto end;
if (!(attrib.value & VA_RT_FORMAT_YUV420))
goto end;
GST_VAAPI_DISPLAY_LOCK(display);
status = vaCreateConfig(
GST_VAAPI_DISPLAY_VADISPLAY(display),
va_profile,
va_entrypoint,
&attrib, 1,
&context->config_id
);
GST_VAAPI_DISPLAY_UNLOCK(display);
if (!vaapi_check_status(status, "vaCreateConfig()"))
goto end;
GST_VAAPI_DISPLAY_LOCK(display);
status = vaCreateContext(
GST_VAAPI_DISPLAY_VADISPLAY(display),
context->config_id,
cip->width, cip->height,
VA_PROGRESSIVE,
(VASurfaceID *)surfaces->data, surfaces->len,
&context_id
);
GST_VAAPI_DISPLAY_UNLOCK(display);
if (!vaapi_check_status(status, "vaCreateContext()"))
goto end;
GST_DEBUG("context %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(context_id));
GST_VAAPI_OBJECT_ID(context) = context_id;
success = TRUE;
end:
if (surfaces)
g_array_free(surfaces, TRUE);
return success;
}
static inline void
gst_vaapi_context_init(GstVaapiContext *context, const GstVaapiContextInfo *cip)
{
context->info = *cip;
context->config_id = VA_INVALID_ID;
context->overlays[0] = overlay_new();
context->overlays[1] = overlay_new();
}
static void
gst_vaapi_context_finalize(GstVaapiContext *context)
{
overlay_destroy(&context->overlays[0]);
overlay_destroy(&context->overlays[1]);
gst_vaapi_context_destroy(context);
gst_vaapi_context_destroy_surfaces(context);
}
GST_VAAPI_OBJECT_DEFINE_CLASS(GstVaapiContext, gst_vaapi_context)
/**
* gst_vaapi_context_new:
* @display: a #GstVaapiDisplay
* @profile: a #GstVaapiProfile
* @entrypoint: a #GstVaapiEntrypoint
* @width: coded width from the bitstream
* @height: coded height from the bitstream
*
* Creates a new #GstVaapiContext with the specified codec @profile
* and @entrypoint.
*
* Return value: the newly allocated #GstVaapiContext object
*/
GstVaapiContext *
gst_vaapi_context_new(
GstVaapiDisplay *display,
GstVaapiProfile profile,
GstVaapiEntrypoint entrypoint,
guint width,
guint height
)
{
GstVaapiContextInfo info;
info.profile = profile;
info.entrypoint = entrypoint;
info.width = width;
info.height = height;
info.ref_frames = get_max_ref_frames(profile);
return gst_vaapi_context_new_full(display, &info);
}
/**
* gst_vaapi_context_new_full:
* @display: a #GstVaapiDisplay
* @cip: a pointer to the #GstVaapiContextInfo
*
* Creates a new #GstVaapiContext with the configuration specified by
* @cip, thus including profile, entry-point, encoded size and maximum
* number of reference frames reported by the bitstream.
*
* Return value: the newly allocated #GstVaapiContext object
*/
GstVaapiContext *
gst_vaapi_context_new_full(GstVaapiDisplay *display,
const GstVaapiContextInfo *cip)
{
GstVaapiContext *context;
g_return_val_if_fail(cip->profile, NULL);
g_return_val_if_fail(cip->entrypoint, NULL);
g_return_val_if_fail(cip->width > 0, NULL);
g_return_val_if_fail(cip->height > 0, NULL);
context = gst_vaapi_object_new(gst_vaapi_context_class(), display);
if (!context)
return NULL;
gst_vaapi_context_init(context, cip);
if (!gst_vaapi_context_create(context))
goto error;
return context;
error:
gst_vaapi_object_unref(context);
return NULL;
}
/**
* gst_vaapi_context_reset:
* @context: a #GstVaapiContext
* @profile: a #GstVaapiProfile
* @entrypoint: a #GstVaapiEntrypoint
* @width: coded width from the bitstream
* @height: coded height from the bitstream
*
* Resets @context to the specified codec @profile and @entrypoint.
* The surfaces will be reallocated if the coded size changed.
*
* Return value: %TRUE on success
*/
gboolean
gst_vaapi_context_reset(
GstVaapiContext *context,
GstVaapiProfile profile,
GstVaapiEntrypoint entrypoint,
unsigned int width,
unsigned int height
)
{
GstVaapiContextInfo info;
info.profile = profile;
info.entrypoint = entrypoint;
info.width = width;
info.height = height;
info.ref_frames = context->info.ref_frames;
return gst_vaapi_context_reset_full(context, &info);
}
/**
* gst_vaapi_context_reset_full:
* @context: a #GstVaapiContext
* @new_cip: a pointer to the new #GstVaapiContextInfo details
*
* Resets @context to the configuration specified by @new_cip, thus
* including profile, entry-point, encoded size and maximum number of
* reference frames reported by the bitstream.
*
* Return value: %TRUE on success
*/
gboolean
gst_vaapi_context_reset_full(GstVaapiContext *context,
const GstVaapiContextInfo *new_cip)
{
GstVaapiContextInfo * const cip = &context->info;
gboolean size_changed, codec_changed;
size_changed = cip->width != new_cip->width ||
cip->height != new_cip->height;
if (size_changed) {
gst_vaapi_context_destroy_surfaces(context);
cip->width = new_cip->width;
cip->height = new_cip->height;
}
codec_changed = cip->profile != new_cip->profile ||
cip->entrypoint != new_cip->entrypoint;
if (codec_changed) {
gst_vaapi_context_destroy(context);
cip->profile = new_cip->profile;
cip->entrypoint = new_cip->entrypoint;
}
if (size_changed && !gst_vaapi_context_create_surfaces(context))
return FALSE;
if (codec_changed && !gst_vaapi_context_create(context))
return FALSE;
return TRUE;
}
/**
* gst_vaapi_context_get_id:
* @context: a #GstVaapiContext
*
* Returns the underlying VAContextID of the @context.
*
* Return value: the underlying VA context id
*/
GstVaapiID
gst_vaapi_context_get_id(GstVaapiContext *context)
{
g_return_val_if_fail(context != NULL, VA_INVALID_ID);
return GST_VAAPI_OBJECT_ID(context);
}
/**
* gst_vaapi_context_get_profile:
* @context: a #GstVaapiContext
*
* Returns the VA profile used by the @context.
*
* Return value: the VA profile used by the @context
*/
GstVaapiProfile
gst_vaapi_context_get_profile(GstVaapiContext *context)
{
g_return_val_if_fail(context != NULL, 0);
return context->info.profile;
}
/**
* gst_vaapi_context_set_profile:
* @context: a #GstVaapiContext
* @profile: the new #GstVaapiProfile to use
*
* Sets the new @profile to use with the @context. If @profile matches
* the previous profile, this call has no effect. Otherwise, the
* underlying VA context is recreated, while keeping the previously
* allocated surfaces.
*
* Return value: %TRUE on success
*/
gboolean
gst_vaapi_context_set_profile(GstVaapiContext *context, GstVaapiProfile profile)
{
g_return_val_if_fail(context != NULL, FALSE);
g_return_val_if_fail(profile, FALSE);
return gst_vaapi_context_reset(context,
profile,
context->info.entrypoint,
context->info.width,
context->info.height);
}
/**
* gst_vaapi_context_get_entrypoint:
* @context: a #GstVaapiContext
*
* Returns the VA entrypoint used by the @context
*
* Return value: the VA entrypoint used by the @context
*/
GstVaapiEntrypoint
gst_vaapi_context_get_entrypoint(GstVaapiContext *context)
{
g_return_val_if_fail(context != NULL, 0);
return context->info.entrypoint;
}
/**
* gst_vaapi_context_get_size:
* @context: a #GstVaapiContext
* @pwidth: return location for the width, or %NULL
* @pheight: return location for the height, or %NULL
*
* Retrieves the size of the surfaces attached to @context.
*/
void
gst_vaapi_context_get_size(
GstVaapiContext *context,
guint *pwidth,
guint *pheight
)
{
g_return_if_fail(context != NULL);
if (pwidth)
*pwidth = context->info.width;
if (pheight)
*pheight = context->info.height;
}
/**
* gst_vaapi_context_get_surface_proxy:
* @context: a #GstVaapiContext
*
* Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
* returned surface will be automatically released when the proxy is
* destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
* after usage.
*
* This function returns %NULL if there is no free surface available
* in the pool. The surfaces are pre-allocated during context creation
* though.
*
* Return value: a free surface, or %NULL if none is available
*/
GstVaapiSurfaceProxy *
gst_vaapi_context_get_surface_proxy(GstVaapiContext *context)
{
g_return_val_if_fail(context != NULL, NULL);
return gst_vaapi_surface_proxy_new_from_pool(
GST_VAAPI_SURFACE_POOL(context->surfaces_pool));
}
/**
* gst_vaapi_context_get_surface_count:
* @context: a #GstVaapiContext
*
* Retrieves the number of free surfaces left in the pool.
*
* Return value: the number of free surfaces available in the pool
*/
guint
gst_vaapi_context_get_surface_count(GstVaapiContext *context)
{
g_return_val_if_fail(context != NULL, 0);
return gst_vaapi_video_pool_get_size(context->surfaces_pool);
}
/**
* gst_vaapi_context_apply_composition:
* @context: a #GstVaapiContext
* @composition: a #GstVideoOverlayComposition
*
* Applies video composition planes to all surfaces bound to @context.
* This helper function resets any additional subpictures the user may
* have associated himself. A %NULL @composition will also clear all
* the existing subpictures.
*
* Return value: %TRUE if all composition planes could be applied,
* %FALSE otherwise
*/
gboolean
gst_vaapi_context_apply_composition(
GstVaapiContext *context,
GstVideoOverlayComposition *composition
)
{
GPtrArray *curr_overlay, *next_overlay;
guint i, n_rectangles;
gboolean reassociate = FALSE;
g_return_val_if_fail(context != NULL, FALSE);
if (!context->surfaces)
return FALSE;
if (!composition) {
gst_vaapi_context_clear_overlay(context);
return TRUE;
}
curr_overlay = context->overlays[context->overlay_id];
next_overlay = context->overlays[context->overlay_id ^ 1];
overlay_clear(next_overlay);
n_rectangles = gst_video_overlay_composition_n_rectangles(composition);
for (i = 0; i < n_rectangles; i++) {
GstVideoOverlayRectangle * const rect =
gst_video_overlay_composition_get_rectangle(composition, i);
GstVaapiOverlayRectangle *overlay;
overlay = overlay_lookup(curr_overlay, rect);
if (overlay && overlay_rectangle_update(overlay, rect, &reassociate)) {
overlay_rectangle_ref(overlay);
if (overlay->layer_id != i)
reassociate = TRUE;
}
else {
overlay = overlay_rectangle_new(rect, context, i);
if (!overlay) {
GST_WARNING("could not create VA overlay rectangle");
goto error;
}
reassociate = TRUE;
}
g_ptr_array_add(next_overlay, overlay);
}
overlay_clear(curr_overlay);
context->overlay_id ^= 1;
if (reassociate && !overlay_reassociate(next_overlay))
return FALSE;
return TRUE;
error:
gst_vaapi_context_clear_overlay(context);
return FALSE;
}