mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 16:21:17 +00:00
6022d97edf
JPEG decoding in i965 driver is pretty much broken, and the driver is deprecated which mean authors only accept trivial fixes. Surfaces for JPEG decoder context in i965 only handle IMC3[1] color format which is not a common format in GStreamer. It can export it to I420 at mapping raw bytes, but DMABuf exporting is problematic. This patch artificially adds NV12 to the context format list when it's JPEG decoder for i965 and force the usage of old VA-API for surface creation without specifying color format. Also it artificially disables the DMABuf announcement. 1. https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#420-formats-16-bits-per-pixel Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/-/merge_requests/369>
788 lines
23 KiB
C
788 lines
23 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 "gstvaapicompat.h"
|
|
#include "gstvaapicontext.h"
|
|
#include "gstvaapidisplay_priv.h"
|
|
#include "gstvaapisurface_priv.h"
|
|
#include "gstvaapisurfacepool.h"
|
|
#include "gstvaapisurfaceproxy.h"
|
|
#include "gstvaapivideopool_priv.h"
|
|
#include "gstvaapiutils.h"
|
|
|
|
/* Define default VA surface chroma format to YUV 4:2:0 */
|
|
#define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
|
|
|
|
/* Number of scratch surfaces beyond those used as reference */
|
|
#define SCRATCH_SURFACES_COUNT (4)
|
|
|
|
/* Debug category for GstVaapiContext */
|
|
GST_DEBUG_CATEGORY (gst_debug_vaapi_context);
|
|
#define GST_CAT_DEFAULT gst_debug_vaapi_context
|
|
|
|
static void
|
|
_init_vaapi_context_debug (void)
|
|
{
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
static volatile gsize _init = 0;
|
|
|
|
if (g_once_init_enter (&_init)) {
|
|
GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_context, "vaapicontext", 0,
|
|
"VA-API context");
|
|
g_once_init_leave (&_init, 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static inline gboolean
|
|
_context_is_broken_jpeg_decoder (GstVaapiContext * context)
|
|
{
|
|
GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
|
|
return (context->info.profile == GST_VAAPI_PROFILE_JPEG_BASELINE
|
|
&& context->info.entrypoint == GST_VAAPI_ENTRYPOINT_VLD
|
|
&& gst_vaapi_display_has_driver_quirks (display,
|
|
GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS));
|
|
}
|
|
|
|
static gboolean
|
|
ensure_attributes (GstVaapiContext * context)
|
|
{
|
|
if (G_LIKELY (context->attribs))
|
|
return TRUE;
|
|
|
|
context->attribs =
|
|
gst_vaapi_config_surface_attributes_get (GST_VAAPI_CONTEXT_DISPLAY
|
|
(context), context->va_config);
|
|
|
|
if (!context->attribs)
|
|
return FALSE;
|
|
|
|
if (_context_is_broken_jpeg_decoder (context)) {
|
|
GstVideoFormat fmt = GST_VIDEO_FORMAT_NV12;
|
|
g_array_prepend_val (context->attribs->formats, fmt);
|
|
|
|
context->attribs->mem_types &= ~VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* XXX(victor): verify the preferred video format concords with the
|
|
* chroma type; otherwise it is changed for the (very arbritrary)
|
|
* preferred format from the requested context chroma type, in the
|
|
* context attributes */
|
|
static void
|
|
ensure_preferred_format (GstVaapiContext * context)
|
|
{
|
|
const GstVaapiContextInfo *const cip = &context->info;
|
|
GArray *formats;
|
|
guint i;
|
|
|
|
if (context->preferred_format != GST_VIDEO_FORMAT_UNKNOWN)
|
|
return;
|
|
|
|
if (_context_is_broken_jpeg_decoder (context))
|
|
return;
|
|
|
|
if (!ensure_attributes (context) || !context->attribs->formats)
|
|
return;
|
|
|
|
formats = context->attribs->formats;
|
|
for (i = 0; i < formats->len; i++) {
|
|
GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
|
|
if (format == gst_vaapi_video_format_from_chroma (cip->chroma_type)) {
|
|
context->preferred_format = format;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static inline gboolean
|
|
context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
|
|
guint * out_value_ptr)
|
|
{
|
|
return gst_vaapi_get_config_attribute (GST_VAAPI_CONTEXT_DISPLAY (context),
|
|
context->va_profile, context->va_entrypoint, type, out_value_ptr);
|
|
}
|
|
|
|
static void
|
|
context_destroy_surfaces (GstVaapiContext * context)
|
|
{
|
|
if (context->surfaces) {
|
|
g_ptr_array_unref (context->surfaces);
|
|
context->surfaces = NULL;
|
|
}
|
|
|
|
context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
|
|
|
|
gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
|
|
}
|
|
|
|
static void
|
|
context_destroy (GstVaapiContext * context)
|
|
{
|
|
GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
VAContextID context_id;
|
|
VAStatus status;
|
|
|
|
context_id = GST_VAAPI_CONTEXT_ID (context);
|
|
GST_DEBUG ("context 0x%08x / config 0x%08x", context_id, context->va_config);
|
|
|
|
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()"))
|
|
GST_WARNING ("failed to destroy context 0x%08x", context_id);
|
|
GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
|
|
}
|
|
|
|
if (context->va_config != VA_INVALID_ID) {
|
|
GST_VAAPI_DISPLAY_LOCK (display);
|
|
status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
|
|
context->va_config);
|
|
GST_VAAPI_DISPLAY_UNLOCK (display);
|
|
if (!vaapi_check_status (status, "vaDestroyConfig()"))
|
|
GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
|
|
context->va_config = VA_INVALID_ID;
|
|
}
|
|
|
|
if (context->attribs) {
|
|
gst_vaapi_config_surface_attributes_free (context->attribs);
|
|
context->attribs = NULL;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
context_ensure_surfaces (GstVaapiContext * context)
|
|
{
|
|
GstVaapiDisplay *display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
const GstVaapiContextInfo *const cip = &context->info;
|
|
const guint num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
|
|
GstVaapiSurface *surface;
|
|
GstVideoFormat format;
|
|
guint i, capacity;
|
|
|
|
ensure_preferred_format (context);
|
|
format = context->preferred_format;
|
|
for (i = context->surfaces->len; i < num_surfaces; i++) {
|
|
if (format != GST_VIDEO_FORMAT_UNKNOWN) {
|
|
surface = gst_vaapi_surface_new_with_format (display, format, cip->width,
|
|
cip->height, 0);
|
|
} else {
|
|
surface = gst_vaapi_surface_new (display, cip->chroma_type, cip->width,
|
|
cip->height);
|
|
}
|
|
if (!surface)
|
|
return FALSE;
|
|
g_ptr_array_add (context->surfaces, surface);
|
|
if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
|
|
return FALSE;
|
|
}
|
|
|
|
capacity = cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE ? 0 : num_surfaces;
|
|
gst_vaapi_video_pool_set_capacity (context->surfaces_pool, capacity);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
context_create_surfaces (GstVaapiContext * context)
|
|
{
|
|
const GstVaapiContextInfo *const cip = &context->info;
|
|
GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
guint num_surfaces;
|
|
|
|
num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
|
|
if (!context->surfaces) {
|
|
context->surfaces = g_ptr_array_new_full (num_surfaces,
|
|
(GDestroyNotify) gst_mini_object_unref);
|
|
if (!context->surfaces)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!context->surfaces_pool) {
|
|
context->surfaces_pool =
|
|
gst_vaapi_surface_pool_new_with_chroma_type (display, cip->chroma_type,
|
|
cip->width, cip->height, 0);
|
|
|
|
if (!context->surfaces_pool)
|
|
return FALSE;
|
|
}
|
|
return context_ensure_surfaces (context);
|
|
}
|
|
|
|
static gboolean
|
|
context_create (GstVaapiContext * context)
|
|
{
|
|
const GstVaapiContextInfo *const cip = &context->info;
|
|
GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
VAContextID context_id;
|
|
VASurfaceID surface_id;
|
|
VASurfaceID *surfaces_data = NULL;
|
|
VAStatus status;
|
|
GArray *surfaces = NULL;
|
|
gboolean success = FALSE;
|
|
guint i;
|
|
gint num_surfaces = 0;
|
|
|
|
if (!context->surfaces && !context_create_surfaces (context))
|
|
goto cleanup;
|
|
|
|
/* Create VA surfaces list for vaCreateContext() */
|
|
surfaces = g_array_sized_new (FALSE,
|
|
FALSE, sizeof (VASurfaceID), context->surfaces->len);
|
|
if (!surfaces)
|
|
goto cleanup;
|
|
|
|
for (i = 0; i < context->surfaces->len; i++) {
|
|
GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
|
|
if (!surface)
|
|
goto cleanup;
|
|
surface_id = GST_VAAPI_SURFACE_ID (surface);
|
|
g_array_append_val (surfaces, surface_id);
|
|
}
|
|
|
|
g_assert (surfaces->len == context->surfaces->len);
|
|
|
|
/* vaCreateContext() doesn't really need an array of VASurfaceIDs (see
|
|
* https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and
|
|
* https://github.com/intel/libva/issues/251); pass a dummy list of valid
|
|
* (non-null) IDs until the signature gets updated. */
|
|
if (cip->usage != GST_VAAPI_CONTEXT_USAGE_DECODE) {
|
|
surfaces_data = (VASurfaceID *) surfaces->data;
|
|
num_surfaces = surfaces->len;
|
|
}
|
|
|
|
GST_VAAPI_DISPLAY_LOCK (display);
|
|
status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
|
|
context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
|
|
surfaces_data, num_surfaces, &context_id);
|
|
GST_VAAPI_DISPLAY_UNLOCK (display);
|
|
if (!vaapi_check_status (status, "vaCreateContext()"))
|
|
goto cleanup;
|
|
|
|
GST_VAAPI_CONTEXT_ID (context) = context_id;
|
|
success = TRUE;
|
|
|
|
cleanup:
|
|
if (surfaces)
|
|
g_array_unref (surfaces);
|
|
return success;
|
|
}
|
|
|
|
static gboolean
|
|
config_create (GstVaapiContext * context)
|
|
{
|
|
const GstVaapiContextInfo *const cip = &context->info;
|
|
GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
|
|
VAConfigAttrib attribs[7], *attrib;
|
|
VAStatus status;
|
|
guint value, va_chroma_format, attrib_index;
|
|
|
|
/* Reset profile and entrypoint */
|
|
if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
|
|
|| cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
|
|
goto cleanup;
|
|
context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
|
|
context->va_entrypoint =
|
|
gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
|
|
|
|
attrib_index = 0;
|
|
attrib = &attribs[attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
|
|
/* Validate VA surface format */
|
|
va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
|
|
if (!va_chroma_format)
|
|
goto cleanup;
|
|
attrib->type = VAConfigAttribRTFormat;
|
|
if (!context_get_attribute (context, attrib->type, &value))
|
|
goto cleanup;
|
|
if (!(value & va_chroma_format)) {
|
|
GST_ERROR ("unsupported chroma format (%s)",
|
|
string_of_va_chroma_format (va_chroma_format));
|
|
goto cleanup;
|
|
}
|
|
attrib->value = va_chroma_format;
|
|
attrib = &attribs[++attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
|
|
switch (cip->usage) {
|
|
#if USE_ENCODERS
|
|
case GST_VAAPI_CONTEXT_USAGE_ENCODE:
|
|
{
|
|
const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
|
|
guint va_rate_control;
|
|
|
|
/* Rate control */
|
|
va_rate_control = from_GstVaapiRateControl (config->rc_mode);
|
|
if (va_rate_control != VA_RC_NONE) {
|
|
attrib->type = VAConfigAttribRateControl;
|
|
if (!context_get_attribute (context, attrib->type, &value))
|
|
goto cleanup;
|
|
|
|
if ((value & va_rate_control) != va_rate_control) {
|
|
GST_ERROR ("unsupported %s rate control",
|
|
string_of_VARateControl (va_rate_control));
|
|
goto cleanup;
|
|
}
|
|
attrib->value = va_rate_control;
|
|
attrib = &attribs[++attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
}
|
|
/* Packed headers */
|
|
if (config->packed_headers) {
|
|
attrib->type = VAConfigAttribEncPackedHeaders;
|
|
if (!context_get_attribute (context, attrib->type, &value))
|
|
goto cleanup;
|
|
|
|
if ((value & config->packed_headers) != config->packed_headers) {
|
|
GST_ERROR ("unsupported packed headers 0x%08x",
|
|
config->packed_headers & ~(value & config->packed_headers));
|
|
goto cleanup;
|
|
}
|
|
attrib->value = config->packed_headers;
|
|
attrib = &attribs[++attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
}
|
|
if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) {
|
|
attrib->type = VAConfigAttribEncJPEG;
|
|
if (!context_get_attribute (context, attrib->type, &value))
|
|
goto cleanup;
|
|
attrib->value = value;
|
|
attrib = &attribs[++attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
}
|
|
#if VA_CHECK_VERSION(0,39,1)
|
|
if (config->roi_capability) {
|
|
VAConfigAttribValEncROI *roi_config;
|
|
|
|
attrib->type = VAConfigAttribEncROI;
|
|
if (!context_get_attribute (context, attrib->type, &value))
|
|
goto cleanup;
|
|
roi_config = (VAConfigAttribValEncROI *) & value;
|
|
if (roi_config->bits.num_roi_regions != config->roi_num_supported) {
|
|
GST_ERROR ("Mismatched ROI support: number of regions supported: %d",
|
|
roi_config->bits.num_roi_regions);
|
|
goto cleanup;
|
|
}
|
|
if (config->rc_mode != GST_VAAPI_RATECONTROL_CQP
|
|
&& VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0) {
|
|
GST_ERROR ("Mismatched ROI support: ROI delta QP: %d",
|
|
VA_ROI_RC_QP_DELTA_SUPPORT (roi_config));
|
|
goto cleanup;
|
|
}
|
|
attrib->value = value;
|
|
attrib = &attribs[++attrib_index];
|
|
g_assert (attrib_index < G_N_ELEMENTS (attribs));
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GST_VAAPI_DISPLAY_LOCK (display);
|
|
status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
|
|
context->va_profile, context->va_entrypoint, attribs, attrib_index,
|
|
&context->va_config);
|
|
GST_VAAPI_DISPLAY_UNLOCK (display);
|
|
if (!vaapi_check_status (status, "vaCreateConfig()"))
|
|
goto cleanup;
|
|
|
|
return TRUE;
|
|
cleanup:
|
|
GST_WARNING ("Failed to create vaConfig");
|
|
return FALSE;
|
|
}
|
|
|
|
/** Updates config for encoding. Returns %TRUE if config changed */
|
|
static gboolean
|
|
context_update_config_encoder (GstVaapiContext * context,
|
|
const GstVaapiConfigInfoEncoder * new_config)
|
|
{
|
|
GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
|
|
gboolean config_changed = FALSE;
|
|
|
|
g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
|
|
|
|
if (config->rc_mode != new_config->rc_mode) {
|
|
config->rc_mode = new_config->rc_mode;
|
|
config_changed = TRUE;
|
|
}
|
|
|
|
if (config->packed_headers != new_config->packed_headers) {
|
|
config->packed_headers = new_config->packed_headers;
|
|
config_changed = TRUE;
|
|
}
|
|
|
|
if (config->roi_capability != new_config->roi_capability ||
|
|
config->roi_num_supported != new_config->roi_num_supported) {
|
|
config->roi_capability = new_config->roi_capability;
|
|
config->roi_num_supported = new_config->roi_num_supported;
|
|
config_changed = TRUE;
|
|
}
|
|
|
|
return config_changed;
|
|
}
|
|
|
|
static inline void
|
|
gst_vaapi_context_init (GstVaapiContext * context,
|
|
const GstVaapiContextInfo * new_cip)
|
|
{
|
|
GstVaapiContextInfo *const cip = &context->info;
|
|
|
|
*cip = *new_cip;
|
|
if (!cip->chroma_type)
|
|
cip->chroma_type = DEFAULT_CHROMA_TYPE;
|
|
|
|
context->va_config = VA_INVALID_ID;
|
|
context->reset_on_resize = TRUE;
|
|
|
|
context->attribs = NULL;
|
|
context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_new:
|
|
* @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 (GstVaapiDisplay * display,
|
|
const GstVaapiContextInfo * cip)
|
|
{
|
|
GstVaapiContext *context;
|
|
|
|
g_return_val_if_fail (display, NULL);
|
|
|
|
_init_vaapi_context_debug ();
|
|
|
|
if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
|
|
|| cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
|
|
return NULL;
|
|
|
|
context = g_slice_new (GstVaapiContext);
|
|
if (!context)
|
|
return NULL;
|
|
|
|
GST_VAAPI_CONTEXT_DISPLAY (context) = gst_object_ref (display);
|
|
GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
|
|
g_atomic_int_set (&context->ref_count, 1);
|
|
context->surfaces = NULL;
|
|
context->surfaces_pool = NULL;
|
|
|
|
gst_vaapi_context_init (context, cip);
|
|
|
|
if (!config_create (context))
|
|
goto error;
|
|
|
|
/* this means we don't want to create a VAcontext */
|
|
if (cip->width == 0 && cip->height == 0)
|
|
goto done;
|
|
|
|
/* this is not valid */
|
|
if (cip->width == 0 || cip->height == 0)
|
|
goto error;
|
|
|
|
if (!context_create (context))
|
|
goto error;
|
|
|
|
done:
|
|
GST_DEBUG ("context 0x%08" G_GSIZE_MODIFIER "x / config 0x%08x",
|
|
GST_VAAPI_CONTEXT_ID (context), context->va_config);
|
|
return context;
|
|
|
|
/* ERRORS */
|
|
error:
|
|
{
|
|
gst_vaapi_context_unref (context);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_reset:
|
|
* @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 (GstVaapiContext * context,
|
|
const GstVaapiContextInfo * new_cip)
|
|
{
|
|
GstVaapiContextInfo *const cip = &context->info;
|
|
gboolean reset_surfaces = FALSE, reset_config = FALSE;
|
|
gboolean grow_surfaces = FALSE;
|
|
GstVaapiChromaType chroma_type;
|
|
|
|
if (new_cip->profile == GST_VAAPI_PROFILE_UNKNOWN
|
|
|| new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
|
|
return FALSE;
|
|
|
|
chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
|
|
DEFAULT_CHROMA_TYPE;
|
|
if (cip->chroma_type != chroma_type) {
|
|
cip->chroma_type = chroma_type;
|
|
reset_surfaces = TRUE;
|
|
}
|
|
|
|
if (cip->width != new_cip->width || cip->height != new_cip->height) {
|
|
cip->width = new_cip->width;
|
|
cip->height = new_cip->height;
|
|
reset_surfaces = TRUE;
|
|
}
|
|
|
|
if (cip->profile != new_cip->profile ||
|
|
cip->entrypoint != new_cip->entrypoint) {
|
|
cip->profile = new_cip->profile;
|
|
cip->entrypoint = new_cip->entrypoint;
|
|
reset_config = TRUE;
|
|
}
|
|
|
|
if (cip->ref_frames < new_cip->ref_frames) {
|
|
cip->ref_frames = new_cip->ref_frames;
|
|
grow_surfaces = TRUE;
|
|
}
|
|
|
|
if (cip->usage != new_cip->usage) {
|
|
cip->usage = new_cip->usage;
|
|
reset_config = TRUE;
|
|
memcpy (&cip->config, &new_cip->config, sizeof (cip->config));
|
|
} else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
|
|
if (context_update_config_encoder (context, &new_cip->config.encoder))
|
|
reset_config = TRUE;
|
|
} else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
|
|
if ((reset_surfaces && context->reset_on_resize) || grow_surfaces)
|
|
reset_config = TRUE;
|
|
}
|
|
|
|
if (reset_surfaces)
|
|
context_destroy_surfaces (context);
|
|
if (reset_config)
|
|
context_destroy (context);
|
|
|
|
if (reset_config && !(config_create (context) && context_create (context)))
|
|
return FALSE;
|
|
if (reset_surfaces && !context_create_surfaces (context))
|
|
return FALSE;
|
|
else if (grow_surfaces && !context_ensure_surfaces (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_CONTEXT_ID (context);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
if (gst_vaapi_video_pool_get_capacity (context->surfaces_pool) == 0)
|
|
return G_MAXUINT;
|
|
return gst_vaapi_video_pool_get_size (context->surfaces_pool);
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_reset_on_resize:
|
|
* @context: a #GstVaapiContext
|
|
* @reset_on_resize: Should the context be reset on size change
|
|
*
|
|
* Sets whether the underlying context should be reset when a size change
|
|
* happens. The proper setting for this is codec dependent.
|
|
*/
|
|
void
|
|
gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
|
|
gboolean reset_on_resize)
|
|
{
|
|
g_return_if_fail (context != NULL);
|
|
|
|
context->reset_on_resize = reset_on_resize;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_get_surface_formats:
|
|
* @context: a #GstVaapiContext
|
|
*
|
|
* Determines the set of supported formats by the surfaces associated
|
|
* to @context. The caller owns an extra reference of the resulting
|
|
* array of #GstVideoFormat elements, so it shall be released with
|
|
* g_array_unref after usage.
|
|
*
|
|
* Return value: (transfer full): the set of target formats supported
|
|
* by the surfaces in @context.
|
|
*/
|
|
GArray *
|
|
gst_vaapi_context_get_surface_formats (GstVaapiContext * context)
|
|
{
|
|
g_return_val_if_fail (context, NULL);
|
|
|
|
if (!ensure_attributes (context))
|
|
return NULL;
|
|
|
|
if (context->attribs->formats)
|
|
return g_array_ref (context->attribs->formats);
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_get_surface_attributes:
|
|
* @context: a #GstVaapiContext
|
|
* @out_attribs: an allocated #GstVaapiConfigSurfaceAttributes
|
|
*
|
|
* Copy context's surface restrictions to @out_attribs, EXCEPT the
|
|
* color formats. Use gst_vaapi_context_get_surface_formats() to get
|
|
* them.
|
|
*
|
|
* Returns: %TRUE if the attributes were extracted and copied; %FALSE,
|
|
* otherwise
|
|
**/
|
|
gboolean
|
|
gst_vaapi_context_get_surface_attributes (GstVaapiContext * context,
|
|
GstVaapiConfigSurfaceAttributes * out_attribs)
|
|
{
|
|
g_return_val_if_fail (context, FALSE);
|
|
|
|
if (!ensure_attributes (context))
|
|
return FALSE;
|
|
|
|
if (out_attribs) {
|
|
out_attribs->min_width = context->attribs->min_width;
|
|
out_attribs->min_height = context->attribs->min_height;
|
|
out_attribs->max_width = context->attribs->max_width;
|
|
out_attribs->max_height = context->attribs->max_height;
|
|
out_attribs->mem_types = context->attribs->mem_types;
|
|
out_attribs->formats = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_ref:
|
|
* @context: a #GstVaapiContext
|
|
*
|
|
* Atomically increases the reference count of the given @context by one.
|
|
*
|
|
* Returns: The same @context argument
|
|
*/
|
|
GstVaapiContext *
|
|
gst_vaapi_context_ref (GstVaapiContext * context)
|
|
{
|
|
g_return_val_if_fail (context != NULL, NULL);
|
|
|
|
g_atomic_int_inc (&context->ref_count);
|
|
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* gst_vaapi_context_unref:
|
|
* @context: a #GstVaapiContext
|
|
*
|
|
* Atomically decreases the reference count of the @context by one. If
|
|
* the reference count reaches zero, the object will be free'd.
|
|
*/
|
|
void
|
|
gst_vaapi_context_unref (GstVaapiContext * context)
|
|
{
|
|
g_return_if_fail (context != NULL);
|
|
g_return_if_fail (context->ref_count > 0);
|
|
|
|
if (g_atomic_int_dec_and_test (&context->ref_count)) {
|
|
context_destroy (context);
|
|
context_destroy_surfaces (context);
|
|
gst_vaapi_display_replace (&context->display, NULL);
|
|
g_slice_free (GstVaapiContext, context);
|
|
}
|
|
}
|