[totem/wip/hadess/screenshot-again] gst: Use playbin's convert-frame feature again




commit fc514e1adb883b2a61e1f19446b2e4bba58490a7
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Mar 10 10:34:29 2022 +0100

    gst: Use playbin's convert-frame feature again
    
    Now that GStreamer support for processing GL memory has been merged.
    
    See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1916
    
    FIXME: Needs gst req bump

 src/gst/totem-gst-pixbuf-helpers.c | 289 +------------------------------------
 1 file changed, 2 insertions(+), 287 deletions(-)
---
diff --git a/src/gst/totem-gst-pixbuf-helpers.c b/src/gst/totem-gst-pixbuf-helpers.c
index 8744a85dd..d5d2b8832 100644
--- a/src/gst/totem-gst-pixbuf-helpers.c
+++ b/src/gst/totem-gst-pixbuf-helpers.c
@@ -47,290 +47,12 @@ destroy_pixbuf (guchar *pix, gpointer data)
   gst_sample_unref (GST_SAMPLE (data));
 }
 
-static gboolean
-caps_are_raw (const GstCaps * caps)
-{
-  guint i, len;
-
-  len = gst_caps_get_size (caps);
-
-  for (i = 0; i < len; i++) {
-    GstStructure *st = gst_caps_get_structure (caps, i);
-    if (gst_structure_has_name (st, "video/x-raw"))
-      return TRUE;
-  }
-
-  return FALSE;
-}
-
-static gboolean
-create_element (const gchar * factory_name, GstElement ** element,
-    GError ** err)
-{
-  *element = gst_element_factory_make (factory_name, NULL);
-  if (*element)
-    return TRUE;
-
-  if (err && *err == NULL) {
-    *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN,
-        "cannot create element '%s' - please check your GStreamer installation",
-        factory_name);
-  }
-
-  return FALSE;
-}
-
-static GstElement *
-build_convert_frame_pipeline (FrameCaptureType capture_type,
-    GstElement ** src_element,
-    GstElement ** sink_element, const GstCaps * from_caps,
-    const GstCaps * to_caps, GError ** err)
-{
-  GstElement *csp = NULL, *vscale = NULL;
-  GstElement *src = NULL, *sink = NULL, *dl = NULL, *pipeline;
-  GError *error = NULL;
-  gboolean ret;
-
-  if (!caps_are_raw (to_caps))
-    goto no_pipeline;
-
-  /* videoscale is here to correct for the pixel-aspect-ratio for us */
-  GST_DEBUG ("creating elements");
-  if (!create_element ("appsrc", &src, &error) ||
-      !create_element ("appsink", &sink, &error))
-    goto no_elements;
-  if (capture_type == FRAME_CAPTURE_TYPE_RAW) {
-      if (!create_element ("videoconvert", &csp, &error) ||
-          !create_element ("videoscale", &vscale, &error))
-        goto no_elements;
-   } else {
-     if (!create_element ("glcolorconvert", &csp, &error) ||
-         !create_element ("glcolorscale", &vscale, &error) ||
-         !create_element ("gldownload", &dl, &error))
-       goto no_elements;
-   }
-
-  pipeline = gst_pipeline_new ("videoconvert-pipeline");
-  if (pipeline == NULL)
-    goto no_pipeline;
-
-  /* Add black borders if necessary to keep the DAR */
-  if (g_object_class_find_property (G_OBJECT_GET_CLASS (vscale), "add-borders"))
-    g_object_set (vscale, "add-borders", TRUE, NULL);
-
-  GST_DEBUG ("adding elements");
-  gst_bin_add_many (GST_BIN (pipeline), src, csp, vscale, sink, dl, NULL);
-
-  /* set caps */
-  g_object_set (src, "caps", from_caps, NULL);
-  g_object_set (sink, "caps", to_caps, NULL);
-
-  if (dl)
-    ret = gst_element_link_many (src, csp, vscale, dl, sink, NULL);
-  else
-    ret = gst_element_link_many (src, csp, vscale, sink, NULL);
-  if (!ret)
-    goto link_failed;
-
-  g_object_set (src, "emit-signals", TRUE, NULL);
-  g_object_set (sink, "emit-signals", TRUE, NULL);
-
-  *src_element = src;
-  *sink_element = sink;
-
-  return pipeline;
-  /* ERRORS */
-no_elements:
-  {
-    if (src)
-      gst_object_unref (src);
-    if (csp)
-      gst_object_unref (csp);
-    if (vscale)
-      gst_object_unref (vscale);
-    if (dl)
-      gst_object_unref (dl);
-    if (sink)
-      gst_object_unref (sink);
-    GST_ERROR ("Could not convert video frame: %s", error->message);
-    if (err)
-      *err = error;
-    else
-      g_error_free (error);
-    return NULL;
-  }
-no_pipeline:
-  {
-    gst_object_unref (src);
-    gst_object_unref (csp);
-    gst_object_unref (vscale);
-    g_clear_pointer (&dl, gst_object_unref);
-    gst_object_unref (sink);
-
-    GST_ERROR ("Could not convert video frame: no pipeline (unknown error)");
-    if (err)
-      *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
-          "Could not convert video frame: no pipeline (unknown error)");
-    return NULL;
-  }
-link_failed:
-  {
-    gst_object_unref (pipeline);
-
-    GST_ERROR ("Could not convert video frame: failed to link elements");
-    if (err)
-      *err = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_NEGOTIATION,
-          "Could not convert video frame: failed to link elements");
-    return NULL;
-  }
-}
-
-/**
- * totem_gst_video_convert_sample:
- * @capture_type: capture type
- * @sample: a #GstSample
- * @to_caps: the #GstCaps to convert to
- * @timeout: the maximum amount of time allowed for the processing.
- * @error: pointer to a #GError. Can be %NULL.
- *
- * Converts a raw video buffer into the specified output caps.
- *
- * The output caps can be any raw video formats or any image formats (jpeg, png, ...).
- *
- * The width, height and pixel-aspect-ratio can also be specified in the output caps.
- *
- * Returns: The converted #GstSample, or %NULL if an error happened (in which case @err
- * will point to the #GError).
- */
-static GstSample *
-totem_gst_video_convert_sample (FrameCaptureType capture_type,
-                               GstSample * sample, const GstCaps * to_caps,
-                               GstClockTime timeout, GError ** error)
-{
-  GstMessage *msg;
-  GstBuffer *buf;
-  GstSample *result = NULL;
-  GError *err = NULL;
-  GstBus *bus;
-  GstCaps *from_caps, *to_caps_copy = NULL;
-  GstFlowReturn ret;
-  GstElement *pipeline, *src, *sink;
-  guint i, n;
-
-  g_return_val_if_fail (sample != NULL, NULL);
-  g_return_val_if_fail (to_caps != NULL, NULL);
-
-  buf = gst_sample_get_buffer (sample);
-  g_return_val_if_fail (buf != NULL, NULL);
-
-  from_caps = gst_sample_get_caps (sample);
-  g_return_val_if_fail (from_caps != NULL, NULL);
-
-  to_caps_copy = gst_caps_new_empty ();
-  n = gst_caps_get_size (to_caps);
-  for (i = 0; i < n; i++) {
-    GstStructure *s = gst_caps_get_structure (to_caps, i);
-
-    s = gst_structure_copy (s);
-    gst_structure_remove_field (s, "framerate");
-    gst_caps_append_structure (to_caps_copy, s);
-  }
-
-  pipeline =
-      build_convert_frame_pipeline (capture_type, &src, &sink, from_caps,
-      to_caps_copy, &err);
-  if (!pipeline)
-    goto no_pipeline;
-
-  /* now set the pipeline to the paused state, after we push the buffer into
-   * appsrc, this should preroll the converted buffer in appsink */
-  GST_DEBUG ("running conversion pipeline to caps %" GST_PTR_FORMAT,
-      to_caps_copy);
-  if (gst_element_set_state (pipeline,
-          GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
-    goto state_change_failed;
-
-  /* feed buffer in appsrc */
-  GST_DEBUG ("feeding buffer %p, size %" G_GSIZE_FORMAT ", caps %"
-      GST_PTR_FORMAT, buf, gst_buffer_get_size (buf), from_caps);
-  g_signal_emit_by_name (src, "push-buffer", buf, &ret);
-
-  /* now see what happens. We either got an error somewhere or the pipeline
-   * prerolled */
-  bus = gst_element_get_bus (pipeline);
-  msg = gst_bus_timed_pop_filtered (bus,
-      timeout, GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE);
-
-  if (msg) {
-    switch (GST_MESSAGE_TYPE (msg)) {
-      case GST_MESSAGE_ASYNC_DONE:
-      {
-        /* we're prerolled, get the frame from appsink */
-        g_signal_emit_by_name (sink, "pull-preroll", &result);
-
-        if (result) {
-          GST_DEBUG ("conversion successful: result = %p", result);
-        } else {
-          GST_ERROR ("prerolled but no result frame?!");
-        }
-        break;
-      }
-      case GST_MESSAGE_ERROR:{
-        gchar *dbg = NULL;
-
-        gst_message_parse_error (msg, &err, &dbg);
-        if (err) {
-          GST_ERROR ("Could not convert video frame: %s", err->message);
-          GST_DEBUG ("%s [debug: %s]", err->message, GST_STR_NULL (dbg));
-          if (error)
-            *error = err;
-          else
-            g_error_free (err);
-        }
-        g_free (dbg);
-        break;
-      }
-      default:{
-        g_return_val_if_reached (NULL);
-      }
-    }
-    gst_message_unref (msg);
-  } else {
-    GST_ERROR ("Could not convert video frame: timeout during conversion");
-    if (error)
-      *error = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
-          "Could not convert video frame: timeout during conversion");
-  }
-
-  gst_element_set_state (pipeline, GST_STATE_NULL);
-  gst_object_unref (bus);
-  gst_object_unref (pipeline);
-  gst_caps_unref (to_caps_copy);
-
-  return result;
-
-  /* ERRORS */
-no_pipeline:
-state_change_failed:
-  {
-    gst_caps_unref (to_caps_copy);
-
-    if (error)
-      *error = err;
-    else
-      g_error_free (err);
-
-    return NULL;
-  }
-}
-
 GdkPixbuf *
 totem_gst_playbin_get_frame (GstElement *play, GError **error)
 {
   FrameCaptureType capture_type;
   GstStructure *s;
   GstSample *sample = NULL;
-  GstSample *last_sample = NULL;
   guint bpp;
   GdkPixbuf *pixbuf = NULL;
   GstCaps *to_caps, *sample_caps;
@@ -359,19 +81,12 @@ totem_gst_playbin_get_frame (GstElement *play, GError **error)
       NULL);
 
   /* get frame */
-  g_object_get (G_OBJECT (play), "sample", &last_sample, NULL);
-  if (!last_sample) {
-    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                         "Failed to retrieve video frame");
-    return NULL;
-  }
-  sample = totem_gst_video_convert_sample (capture_type, last_sample, to_caps, 25 * GST_SECOND, error);
-  gst_sample_unref (last_sample);
+  g_signal_emit_by_name (play, "convert-sample", to_caps, &sample);
   gst_caps_unref (to_caps);
 
   if (!sample) {
     g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                         "Failed to convert video frame");
+                         "Failed to retrieve or convert video frame");
     return NULL;
   }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]