MSDK: Improve the GstContext setting logic.
authorHe Junyan <junyan.he@intel.com>
Tue, 17 Aug 2021 13:51:58 +0000 (21:51 +0800)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 11 Feb 2022 07:13:45 +0000 (07:13 +0000)
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>

subprojects/gst-plugins-bad/sys/msdk/gstmsdkcontextutil.c
subprojects/gst-plugins-bad/sys/msdk/gstmsdkcontextutil.h
subprojects/gst-plugins-bad/sys/msdk/gstmsdkdec.c
subprojects/gst-plugins-bad/sys/msdk/gstmsdkenc.c
subprojects/gst-plugins-bad/sys/msdk/gstmsdkvpp.c

index 0cd24eb..4ec9faa 100644 (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;
 }
index 4792006..58ea749 100644 (file)
@@ -47,10 +47,14 @@ 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
 
index b31258e..4ea8222 100644 (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);
index b58f2d3..d7546a4 100644 (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);
index 50687e2..8f1e5e4 100644 (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);