MSDK: Improve the GstContext setting logic.

We now can use the gst va lib's display to create our MSDK context,
and use its helper functions to simplify our code. The improved logic
is like this:
1. Every MSDK element should use gst_msdk_context_find() to find a MSDK
context from neighbour. If valid, reuse it.
2. Use gst_msdk_ensure_new_context(). It will first query neighbours
about the GstVaDisplay, if found(e.g. some VA element is connected),
use gst_msdk_context_from_external_display() to create a MSDK context.
3. Then, creating the MSDK context from scratch. It creates both the
display and MSDK context.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1087>
This commit is contained in:
He Junyan 2021-08-17 21:51:58 +08:00 committed by GStreamer Marge Bot
parent a905e7474b
commit 85664b5af6
5 changed files with 123 additions and 117 deletions

View file

@ -31,6 +31,8 @@
*/
#include "gstmsdkcontextutil.h"
#include <gst/va/gstvadisplay.h>
#include <gst/va/gstvautils.h>
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
@ -47,113 +49,15 @@ _init_context_debug (void)
#endif
}
static gboolean
context_pad_query (const GValue * item, GValue * value, gpointer user_data)
{
GstPad *const pad = g_value_get_object (item);
GstQuery *const query = user_data;
if (gst_pad_peer_query (pad, query)) {
g_value_set_boolean (value, TRUE);
return FALSE;
}
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed");
return TRUE;
}
static gboolean
_gst_context_run_query (GstElement * element, GstQuery * query,
GstPadDirection direction)
{
GstIteratorFoldFunction const func = context_pad_query;
GstIterator *it;
GValue res = { 0 };
g_value_init (&res, G_TYPE_BOOLEAN);
g_value_set_boolean (&res, FALSE);
/* Ask neighbour */
if (direction == GST_PAD_SRC)
it = gst_element_iterate_src_pads (element);
else
it = gst_element_iterate_sink_pads (element);
while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
return g_value_get_boolean (&res);
}
static gboolean
_gst_context_get_from_query (GstElement * element, GstQuery * query,
GstPadDirection direction)
{
GstContext *ctxt;
if (!_gst_context_run_query (element, query, direction))
return FALSE;
gst_query_parse_context (query, &ctxt);
if (!ctxt)
return FALSE;
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%" GST_PTR_FORMAT ") in %s query", ctxt,
direction == GST_PAD_SRC ? "downstream" : "upstream");
gst_element_set_context (element, ctxt);
return TRUE;
}
static void
_gst_context_query (GstElement * element, const gchar * context_type)
{
GstQuery *query;
GstMessage *msg;
/* 2) Query downstream with GST_QUERY_CONTEXT for the context and
check if downstream already has a context of the specific
type */
/* 3) Query upstream with GST_QUERY_CONTEXT for the context and
check if upstream already has a context of the specific
type */
query = gst_query_new_context (context_type);
if (_gst_context_get_from_query (element, query, GST_PAD_SRC))
goto found;
if (_gst_context_get_from_query (element, query, GST_PAD_SINK))
goto found;
/* 4) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
the required context types and afterwards check if an
usable context was set now as in 1). The message could
be handled by the parent bins of the element and the
application. */
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting `need-context' message");
msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type);
if (!gst_element_post_message (element, msg))
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached");
/* Whomever responds to the need-context message performs a
GstElement::set_context() with the required context in which the
element is required to update the display_ptr */
found:
gst_query_unref (query);
}
/* Find whether the other elements already have a msdk context. */
gboolean
gst_msdk_context_find (GstElement * element, GstMsdkContext ** context_ptr)
{
_init_context_debug ();
g_return_val_if_fail (element != NULL, FALSE);
g_return_val_if_fail (context_ptr != NULL, FALSE);
_init_context_debug ();
/* 1) Check if the element already has a context of the specific type. */
if (*context_ptr) {
GST_LOG_OBJECT (element, "already have a context %" GST_PTR_FORMAT,
@ -162,10 +66,12 @@ gst_msdk_context_find (GstElement * element, GstMsdkContext ** context_ptr)
}
/* This may indirectly set *context_ptr, see function body */
_gst_context_query (element, GST_MSDK_CONTEXT_TYPE_NAME);
gst_va_context_query (element, GST_MSDK_CONTEXT_TYPE_NAME);
if (*context_ptr)
if (*context_ptr) {
GST_LOG_OBJECT (element, "found a context %" GST_PTR_FORMAT, *context_ptr);
return TRUE;
}
return *context_ptr != NULL;
}
@ -177,6 +83,8 @@ gst_msdk_context_get_context (GstContext * context,
const GstStructure *structure;
const gchar *type;
_init_context_debug ();
g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
type = gst_context_get_context_type (context);
@ -203,34 +111,110 @@ gst_msdk_context_propagate (GstElement * element, GstMsdkContext * msdk_context)
gst_structure_set (structure, GST_MSDK_CONTEXT_TYPE_NAME,
GST_TYPE_MSDK_CONTEXT, msdk_context, NULL);
gst_element_set_context (element, context);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting `have-context' message with MSDK context %" GST_PTR_FORMAT,
msdk_context);
msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
if (!gst_element_post_message (element, msg)) {
if (!gst_element_post_message (element, msg))
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached");
}
}
/* When we can not find a suitable context from others, we ensure to create
a new context. */
gboolean
gst_msdk_context_ensure_context (GstElement * element, gboolean hardware,
GstMsdkContextJobType job)
gst_msdk_ensure_new_context (GstElement * element, gboolean hardware,
GstMsdkContextJobType job, GstMsdkContext ** context_ptr)
{
GstMsdkContext *msdk_context;
gboolean propagate_display = FALSE;
gboolean ret = FALSE;
g_return_val_if_fail (element, FALSE);
g_return_val_if_fail (context_ptr, FALSE);
_init_context_debug ();
/* 1) Already have. */
if (g_atomic_pointer_get (context_ptr))
return TRUE;
#ifndef _WIN32
/* 2) Query the neighbour the VA display. If already a valid VA display,
using it by gst_msdk_context_from_external_display() in set_context(). */
gst_va_context_query (element, GST_VA_DISPLAY_HANDLE_CONTEXT_TYPE_STR);
msdk_context = g_atomic_pointer_get (context_ptr);
if (msdk_context) {
gst_object_ref (msdk_context);
propagate_display = FALSE;
ret = TRUE;
goto done;
}
#endif
/* 3) Create a MSDK context from scratch. */
msdk_context = gst_msdk_context_new (hardware, job);
if (!msdk_context) {
GST_ERROR_OBJECT (element, "Context creation failed");
return FALSE;
}
propagate_display = TRUE;
ret = TRUE;
GST_INFO_OBJECT (element, "New MSDK Context %p", msdk_context);
gst_object_replace ((GstObject **) context_ptr, (GstObject *) msdk_context);
done:
if (propagate_display) {
#ifndef _WIN32
GstVaDisplay *display =
(GstVaDisplay *) gst_msdk_context_get_display (msdk_context);
gst_va_element_propagate_display_context (element, display);
gst_clear_object (&display);
#endif
}
gst_msdk_context_propagate (element, msdk_context);
gst_object_unref (msdk_context);
return TRUE;
return ret;
}
gboolean
gst_msdk_context_from_external_display (GstContext * context, gboolean hardware,
GstMsdkContextJobType job_type, GstMsdkContext ** msdk_context)
{
#ifndef _WIN32
GstObject *va_display = NULL;
const gchar *type;
const GstStructure *s;
GstMsdkContext *ctx = NULL;
_init_context_debug ();
type = gst_context_get_context_type (context);
if (g_strcmp0 (type, GST_VA_DISPLAY_HANDLE_CONTEXT_TYPE_STR))
return FALSE;
s = gst_context_get_structure (context);
if (gst_structure_get (s, "gst-display", GST_TYPE_OBJECT, &va_display, NULL)) {
if (GST_IS_VA_DISPLAY (va_display)) {
/* TODO: Need to check whether the display is the DEV we want. */
ctx =
gst_msdk_context_new_with_va_display (va_display, hardware, job_type);
if (ctx)
*msdk_context = ctx;
}
/* let's try other fields */
gst_clear_object (&va_display);
}
if (ctx)
return TRUE;
#endif
return FALSE;
}

View file

@ -46,11 +46,15 @@ G_BEGIN_DECLS
gboolean
gst_msdk_context_find (GstElement * element, GstMsdkContext ** context_ptr);
gboolean
gst_msdk_ensure_new_context (GstElement * element, gboolean hardware, GstMsdkContextJobType job, GstMsdkContext ** context_ptr);
gboolean
gst_msdk_context_get_context (GstContext * context, GstMsdkContext ** msdk_context);
gboolean
gst_msdk_context_ensure_context (GstElement * element, gboolean hardware, GstMsdkContextJobType job);
gst_msdk_context_from_external_display (GstContext * context, gboolean hardware,
GstMsdkContextJobType job_type, GstMsdkContext ** msdk_context);
G_END_DECLS

View file

@ -312,6 +312,12 @@ gst_msdkdec_set_context (GstElement * element, GstContext * context)
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
} else if (gst_msdk_context_from_external_display (context,
thiz->hardware, 0 /* GST_MSDK_JOB_DECODER will be set later */ ,
&msdk_context)) {
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
}
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
@ -829,8 +835,8 @@ gst_msdkdec_start (GstVideoDecoder * decoder)
GstMsdkDec *thiz = GST_MSDKDEC (decoder);
if (!gst_msdkdec_context_prepare (thiz)) {
if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_DECODER))
if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_DECODER, &thiz->context))
return FALSE;
GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
thiz->context);

View file

@ -138,6 +138,12 @@ gst_msdkenc_set_context (GstElement * element, GstContext * context)
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
} else if (gst_msdk_context_from_external_display (context,
thiz->hardware, 0 /* GST_MSDK_JOB_ENCODER will be set later */ ,
&msdk_context)) {
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
}
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
@ -1887,8 +1893,8 @@ gst_msdkenc_start (GstVideoEncoder * encoder)
GstMsdkEnc *thiz = GST_MSDKENC (encoder);
if (!gst_msdkenc_context_prepare (thiz)) {
if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_ENCODER))
if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_ENCODER, &thiz->context))
return FALSE;
GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
thiz->context);

View file

@ -339,8 +339,8 @@ ensure_context (GstBaseTransform * trans)
GstMsdkVPP *thiz = GST_MSDKVPP (trans);
if (!gst_msdkvpp_context_prepare (thiz)) {
if (!gst_msdk_context_ensure_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_VPP))
if (!gst_msdk_ensure_new_context (GST_ELEMENT_CAST (thiz),
thiz->hardware, GST_MSDK_JOB_VPP, &thiz->context))
return FALSE;
GST_INFO_OBJECT (thiz, "Creating new context %" GST_PTR_FORMAT,
thiz->context);
@ -1648,6 +1648,12 @@ gst_msdkvpp_set_context (GstElement * element, GstContext * context)
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
} else if (gst_msdk_context_from_external_display (context,
thiz->hardware, 0 /* GST_MSDK_JOB_VPP will be set later */ ,
&msdk_context)) {
gst_object_replace ((GstObject **) & thiz->context,
(GstObject *) msdk_context);
gst_object_unref (msdk_context);
}
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);