mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
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:
parent
a905e7474b
commit
85664b5af6
5 changed files with 123 additions and 117 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue