gstreamer/gst-libs/gst/vaapi/gstvaapicontext.c

1015 lines
28 KiB
C

/*
* gstvaapicontext.c - VA context abstraction
*
* Copyright (C) 2010-2011 Splitted-Desktop Systems
* Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
* Copyright (C) 2011-2014 Intel Corporation
* Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
*
* 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;
GstVideoInfo vi;
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) {
gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
cip->width, cip->height);
context->surfaces_pool =
gst_vaapi_surface_pool_new (GST_VAAPI_OBJECT_DISPLAY (context), &vi);
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;
guint va_rate_control;
VAConfigAttrib attribs[2];
guint num_attribs;
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);
num_attribs = 0;
attribs[num_attribs++].type = VAConfigAttribRTFormat;
if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE)
attribs[num_attribs++].type = VAConfigAttribRateControl;
GST_VAAPI_DISPLAY_LOCK (display);
status = vaGetConfigAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
va_profile, va_entrypoint, attribs, num_attribs);
GST_VAAPI_DISPLAY_UNLOCK (display);
if (!vaapi_check_status (status, "vaGetConfigAttributes()"))
goto end;
if (!(attribs[0].value & VA_RT_FORMAT_YUV420))
goto end;
if (cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE) {
va_rate_control = from_GstVaapiRateControl (cip->rc_mode);
if (va_rate_control == VA_RC_NONE)
attribs[1].value = VA_RC_NONE;
if ((attribs[1].value & va_rate_control) != va_rate_control) {
GST_ERROR ("unsupported %s rate control",
string_of_VARateControl (va_rate_control));
goto end;
}
attribs[1].value = va_rate_control;
}
GST_VAAPI_DISPLAY_LOCK (display);
status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
va_profile, va_entrypoint, attribs, num_attribs, &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.rc_mode = GST_VAAPI_RATECONTROL_NONE;
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.rc_mode = GST_VAAPI_RATECONTROL_NONE;
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, rc_mode_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 (new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE) {
rc_mode_changed = cip->rc_mode != cip->rc_mode;
if (rc_mode_changed) {
gst_vaapi_context_destroy (context);
cip->rc_mode = new_cip->rc_mode;
}
}
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;
}
/**
* gst_vaapi_context_get_attribute:
* @context: a #GstVaapiContext
* @type: a VA config attribute type
* @out_value_ptr: return location for the config attribute value
*
* Determines the value for the VA config attribute @type.
*
* Note: this function only returns success if the VA driver does
* actually know about this config attribute type and that it returned
* a valid value for it.
*
* Return value: %TRUE if the VA driver knows about the requested
* config attribute and returned a valid value, %FALSE otherwise
*/
gboolean
gst_vaapi_context_get_attribute (GstVaapiContext * context,
VAConfigAttribType type, guint * out_value_ptr)
{
VAConfigAttrib attrib;
VAStatus status;
g_return_val_if_fail (context != NULL, FALSE);
GST_VAAPI_OBJECT_LOCK_DISPLAY (context);
attrib.type = type;
status = vaGetConfigAttributes (GST_VAAPI_OBJECT_VADISPLAY (context),
gst_vaapi_profile_get_va_profile (context->info.profile),
gst_vaapi_entrypoint_get_va_entrypoint (context->info.entrypoint),
&attrib, 1);
GST_VAAPI_OBJECT_UNLOCK_DISPLAY (context);
if (!vaapi_check_status (status, "vaGetConfiAttributes()"))
return FALSE;
if (out_value_ptr)
*out_value_ptr = attrib.value;
return TRUE;
}