summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2022-03-10 10:34:29 +0100
committerBastien Nocera <hadess@hadess.net>2022-07-16 12:05:00 +0200
commit2b61f7eb860acc584d5d3b872b9089a3d222276b (patch)
tree3639dd6feba3524c63959c51ef8d72d9f6804570
parent7c721d0eba8e968b718f4e18bf17f391cd074fb6 (diff)
downloadtotem-wip/hadess/screenshot-again.tar.gz
gst: Use playbin's convert-frame feature againwip/hadess/screenshot-again
Now that GStreamer support for processing GL memory has been merged. See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1916
-rw-r--r--meson.build8
-rw-r--r--src/gst/totem-gst-pixbuf-helpers.c289
2 files changed, 6 insertions, 291 deletions
diff --git a/meson.build b/meson.build
index 9a579988a..f64cfc4cc 100644
--- a/meson.build
+++ b/meson.build
@@ -126,7 +126,7 @@ add_project_arguments(common_flags, language: 'c')
glib_req_version = '>= 2.72.0'
gtk_req_version = '>= 3.22.0'
hdy_req_version = '>= 1.5.0'
-gst_req_version = '>= 1.6.0'
+gst_req_version = '>= 1.21.1'
grilo_req_version = '>= 0.3.0'
peas_req_version = '>= 1.1.0'
totem_plparser_req_version = '>= 3.26.5'
@@ -144,9 +144,9 @@ else
endif
hdy_dep = dependency('libhandy-1', version: hdy_req_version)
gst_dep = dependency('gstreamer-1.0', version: gst_req_version)
-gst_tag_dep = dependency('gstreamer-tag-1.0', version: '>= 0.11.93')
-gst_video_dep = dependency('gstreamer-video-1.0')
-gst_pbutils_dep = dependency('gstreamer-pbutils-1.0')
+gst_tag_dep = dependency('gstreamer-tag-1.0', version: gst_req_version)
+gst_video_dep = dependency('gstreamer-video-1.0', version: gst_req_version)
+gst_pbutils_dep = dependency('gstreamer-pbutils-1.0', version: gst_req_version)
peas_dep = dependency('libpeas-1.0', version: peas_req_version)
peas_gtk_dep = dependency('libpeas-gtk-1.0', version: peas_req_version)
totem_plparser_dep = dependency('totem-plparser', version: totem_plparser_req_version)
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;
}