Search
SailfishOS Open Build Service
>
Projects
>
home:abranson
:
branches:nemo:devel:hw:native-common
>
gstreamer1.0-plugins-base
> _service:tar_git:0002-splitencodebin-Add-new-element.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File _service:tar_git:0002-splitencodebin-Add-new-element.patch of Package gstreamer1.0-plugins-base
From e517c267a55d615130b10ca1d41d428a7a8c350d Wed, 17 Apr 2019 15:12:00 +0200 From: Jan Schmidt <jan@centricular.com> Date: Mon, 13 Aug 2018 15:10:49 +0200 Subject: [PATCH] splitencodebin: Add new element A new element which is a copy of encodebin that doesn't have a source pad - instead it outputs to splitmuxsink or other app-provided renderer bin Modify encodebasebin to be cleverer about which sink pads to link to on the renderer - inspecting actual runtime caps and not just pad templates, since splitmuxsink necessarily publishes ANY pad templates and only knows actual caps at runtime. https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/issues/304 diff --git a/gst/encoding/Makefile.am b/gst/encoding/Makefile.am index 7100749..95ff04d 100644 --- a/gst/encoding/Makefile.am +++ b/gst/encoding/Makefile.am @@ -3,6 +3,7 @@ libgstencoding_la_SOURCES = \ gstencodebasebin.c \ gstencodebin.c \ + gstsplitencodebin.c \ gstsmartencoder.c \ gststreamcombiner.c \ gststreamsplitter.c \ @@ -17,6 +18,7 @@ noinst_HEADERS = \ gstencodebasebin.h \ gstencodebin.h \ + gstsplitencodebin.h \ gststreamcombiner.h \ gststreamsplitter.h \ gstsmartencoder.h \ diff --git a/gst/encoding/gstencodebasebin.c b/gst/encoding/gstencodebasebin.c index 2154d64..60fcbf4 100644 --- a/gst/encoding/gstencodebasebin.c +++ b/gst/encoding/gstencodebasebin.c @@ -918,14 +918,71 @@ return ret; } -/* FIXME : Improve algorithm for finding compatible muxer sink pad */ +static GstPad * +get_compatible_pad_from_template (GstEncodeBaseBin * ebin, GstElement * element, + GstPadTemplate * compattempl) +{ + /* Iterate over pad templates, looking for compatible candidates, + * then get a pad and check actual caps compatibility + */ + GstPad *result = NULL; + GList *padlist; + GstElementClass *class; + gboolean compatible; + + class = GST_ELEMENT_GET_CLASS (element); + padlist = gst_element_class_get_pad_template_list (class); + + GST_LOG_OBJECT (ebin, "Looking for pad in element %" GST_PTR_FORMAT + " compatible with caps %" GST_PTR_FORMAT, + element, GST_PAD_TEMPLATE_CAPS (compattempl)); + while (padlist) { + GstPadTemplate *padtempl = (GstPadTemplate *) padlist->data; + if (padtempl->direction != compattempl->direction) { + /* Check compatibility with the template */ + compatible = gst_caps_can_intersect (GST_PAD_TEMPLATE_CAPS (compattempl), + GST_PAD_TEMPLATE_CAPS (padtempl)); + if (compatible) { + /* Succeeded, check compatibility with the actual pad */ + GstPad *tmp = gst_element_get_pad_from_template (element, padtempl); + GstCaps *caps; + + if (tmp == NULL) + goto next; /* This pad isn't available */ + + caps = gst_pad_query_caps (tmp, NULL); + + GST_LOG_OBJECT (ebin, + "Pad %" GST_PTR_FORMAT " gave caps %" GST_PTR_FORMAT, tmp, caps); + compatible = + gst_caps_can_intersect (GST_PAD_TEMPLATE_CAPS (compattempl), caps); + gst_caps_unref (caps); + if (compatible) { + GST_LOG_OBJECT (ebin, "Found compatible pad %" GST_PTR_FORMAT, tmp); + result = tmp; + break; + } + GST_LOG_OBJECT (ebin, "Pad %" GST_PTR_FORMAT " not compatible", tmp); + /* Not compatible, release the pad and look at other templates */ + if (GST_PAD_TEMPLATE_PRESENCE (padtempl) == GST_PAD_REQUEST) + gst_element_release_request_pad (element, tmp); + gst_object_unref (tmp); + } + } + + next: + padlist = g_list_next (padlist); + } + + return result; +} + static inline GstPad * get_compatible_muxer_sink_pad (GstEncodeBaseBin * ebin, GstElement * encoder, GstCaps * sinkcaps) { GstPad *sinkpad; GstPadTemplate *srctempl = NULL; - GstPadTemplate *sinktempl; if (encoder) { GstPad *srcpad; @@ -938,25 +995,25 @@ GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad)); gst_object_unref (srcpad); - sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl); - gst_object_unref (srctempl); } else { srctempl = gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS, sinkcaps); g_assert (srctempl != NULL); - sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl); - gst_object_unref (srctempl); } - if (G_UNLIKELY (sinktempl == NULL)) - goto no_template; + sinkpad = get_compatible_pad_from_template (ebin, ebin->muxer, srctempl); + g_object_unref (srctempl); - sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl); + if (G_UNLIKELY (sinkpad == NULL)) + goto no_pad; + + GST_DEBUG_OBJECT (ebin, "Found muxer sink pad %" GST_PTR_FORMAT " for caps %" + GST_PTR_FORMAT, sinkpad, sinkcaps); return sinkpad; -no_template: +no_pad: { GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer"); return NULL; @@ -1707,6 +1764,7 @@ const GList *tmp; GstCaps *format; const gchar *preset, *preset_name; + GstEncodeBaseBinClass *klass = GST_ENCODE_BASE_BIN_GET_CLASS (ebin); format = gst_encoding_profile_get_format (ebin->profile); preset = gst_encoding_profile_get_preset (ebin->profile); @@ -1766,6 +1824,11 @@ break; } + /* If the wrap_muxer callback is set, then call it to + * allow the sub-class to configure a renderer */ + if (muxer && klass->wrap_muxer) + muxer = klass->wrap_muxer (ebin, muxer); + gst_plugin_feature_list_free (muxers); beach: @@ -1796,18 +1859,23 @@ ebin->muxer = muxer; gst_bin_add ((GstBin *) ebin, muxer); - /* 2. Ghost the muxer source pad */ + /* If the encodebin has a sourcepad, ghost the muxer + * output. The splitmux encodebin wraps the muxer and outputs + * to a filesink internally, so has no source pad */ + if (ebin->srcpad) { + /* 2. Ghost the muxer source pad */ - /* FIXME : We should figure out if it's a static/request/dyamic pad, - * but for the time being let's assume it's a static pad :) */ - muxerpad = gst_element_get_static_pad (muxer, "src"); - if (G_UNLIKELY (muxerpad == NULL)) - goto no_muxer_pad; + /* FIXME : We should figure out if it's a static/request/dynamic pad, + * but for the time being let's assume it's a static pad :) */ + muxerpad = gst_element_get_static_pad (muxer, "src"); + if (G_UNLIKELY (muxerpad == NULL)) + goto no_muxer_pad; - if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad)) - goto no_muxer_ghost_pad; + if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad)) + goto no_muxer_ghost_pad; - gst_object_unref (muxerpad); + gst_object_unref (muxerpad); + } /* 3. Activate fixed presence streams */ profiles = gst_encoding_container_profile_get_profiles @@ -1948,8 +2016,10 @@ /* streamcombiner - parser - capsfilter */ if (sgroup->parser) { gst_element_set_state (sgroup->parser, GST_STATE_NULL); - gst_element_unlink (sgroup->parser, sgroup->outfilter); - gst_element_unlink (sgroup->combiner, sgroup->parser); + if (sgroup->outfilter) + gst_element_unlink (sgroup->parser, sgroup->outfilter); + if (sgroup->combiner) + gst_element_unlink (sgroup->combiner, sgroup->parser); gst_bin_remove ((GstBin *) ebin, sgroup->parser); } diff --git a/gst/encoding/gstencodebasebin.h b/gst/encoding/gstencodebasebin.h index 78ce3d9..61ea6bc 100644 --- a/gst/encoding/gstencodebasebin.h +++ b/gst/encoding/gstencodebasebin.h @@ -29,6 +29,8 @@ #define GST_ENCODE_BASE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ENCODE_BASE_BIN,GstEncodeBaseBinClass)) #define GST_IS_ENCODE_BASE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ENCODE_BASE_BIN)) #define GST_IS_ENCODE_BASE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ENCODE_BASE_BIN)) +#define GST_ENCODE_BASE_BIN_GET_CLASS(klass) \ + (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_ENCODE_BASE_BIN, GstEncodeBaseBinClass)) typedef struct _GstEncodeBaseBin GstEncodeBaseBin; typedef struct _GstEncodeBaseBinClass GstEncodeBaseBinClass; @@ -87,8 +89,11 @@ GstPad *(*request_pad) (GstEncodeBaseBin * encodebin, GstCaps * caps); GstPad *(*request_profile_pad) (GstEncodeBaseBin * encodebin, const gchar * profilename); + + /* Virtual method */ + GstElement *(*wrap_muxer) (GstEncodeBaseBin * encodebin, GstElement *e); }; GType gst_encode_base_bin_get_type(void); -#endif /* __GST_ENCODEBIN_H__ */ +#endif /* __GST_ENCODEBASEBIN_H__ */ diff --git a/gst/encoding/gstsplitencodebin.c b/gst/encoding/gstsplitencodebin.c new file mode 100644 index 0000000..6269969 --- /dev/null +++ b/gst/encoding/gstsplitencodebin.c @@ -0,0 +1,166 @@ +/* GStreamer encoding bin + * Copyright (C) 2016 Jan Schmidt <jan@centricular.com> + * (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk> + * (C) 2009 Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include "gstencodebasebin.h" +#include "gstsplitencodebin.h" + +/** + * SECTION:element-splitencodebin + * + * SplitEncodeBin provides a bin for encoding/muxing various streams according to + * a specified #GstEncodingProfile. It differs from the standard EncodeBin in that + * it uses a renderer element to write directly to a file or other location, + * instead of producing output on a src pad. + * + * Based on the profile that was set (via the #GstSplitEncodeBin:profile property), + * EncodeBin will internally select and configure the required elements + * (encoders, muxers, but also audio and video converters) so that you can + * provide it raw or pre-encoded streams of data in input and have your + * encoded/muxed/converted stream in output. + * + */ + +enum +{ + PROP_0, + PROP_RENDERER +}; + +G_DEFINE_TYPE (GstSplitEncodeBin, gst_split_encode_bin, + GST_TYPE_ENCODE_BASE_BIN); + +static void gst_splitencodebin_dispose (GObject * object); +static GstElement *wrap_muxer (GstEncodeBaseBin * encodebin, GstElement * e); +static void +gst_splitencodebin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void +gst_splitencodebin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_split_encode_bin_class_init (GstSplitEncodeBinClass * klass) +{ + GObjectClass *gobject_klass = (GObjectClass *) klass; + GstElementClass *gstelement_klass = (GstElementClass *) klass; + GstEncodeBaseBinClass *basebin_klass = (GstEncodeBaseBinClass *) (klass); + + gobject_klass->dispose = gst_splitencodebin_dispose; + gobject_klass->set_property = gst_splitencodebin_set_property; + gobject_klass->get_property = gst_splitencodebin_get_property; + + gst_element_class_set_static_metadata (gstelement_klass, + "Split Encoder Bin", + "Generic/Bin/Encoder", + "Convenience encoding/muxing element", + "Jan Schmidt <jan@centricular.com>"); + + basebin_klass->wrap_muxer = wrap_muxer; + + g_object_class_install_property (gobject_klass, PROP_RENDERER, + g_param_spec_object ("renderer", "Renderer", + "The renderer element to use (NULL = default splitmuxsink)", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +gst_split_encode_bin_init (GstSplitEncodeBin * encode_bin) +{ +} + +static void +gst_splitencodebin_dispose (GObject * object) +{ + GstSplitEncodeBin *sebin = GST_SPLIT_ENCODE_BIN (object); + if (sebin->provided_renderer) { + gst_object_unref (sebin->provided_renderer); + sebin->provided_renderer = NULL; + } +} + +static GstElement * +wrap_muxer (GstEncodeBaseBin * encodebin, GstElement * e) +{ + GstSplitEncodeBin *sebin = GST_SPLIT_ENCODE_BIN (encodebin); + GstElement *renderer; + + /* If there's an app provided renderer, use that */ + if (sebin->provided_renderer) + renderer = gst_object_ref (sebin->provided_renderer); + else + renderer = gst_element_factory_make ("splitmuxsink", NULL); + + if (renderer == NULL) + goto fail; + + g_object_set (renderer, "muxer", e, NULL); + + return renderer; + +fail: + GST_ELEMENT_ERROR (encodebin, CORE, MISSING_PLUGIN, + ("Failed to create splitmuxsink element"), (NULL)); + return NULL; +} + +static void +gst_splitencodebin_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstSplitEncodeBin *sebin = GST_SPLIT_ENCODE_BIN (object); + + switch (prop_id) { + case PROP_RENDERER: + GST_OBJECT_LOCK (sebin); + if (sebin->provided_renderer) + gst_object_unref (sebin->provided_renderer); + sebin->provided_renderer = g_value_get_object (value); + gst_object_ref_sink (sebin->provided_renderer); + GST_OBJECT_UNLOCK (sebin); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_splitencodebin_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstSplitEncodeBin *sebin = GST_SPLIT_ENCODE_BIN (object); + + switch (prop_id) { + case PROP_RENDERER: + GST_OBJECT_LOCK (sebin); + g_value_set_object (value, sebin->provided_renderer); + GST_OBJECT_UNLOCK (sebin); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/encoding/gstsplitencodebin.h b/gst/encoding/gstsplitencodebin.h new file mode 100644 index 0000000..2b35feb --- /dev/null +++ b/gst/encoding/gstsplitencodebin.h @@ -0,0 +1,52 @@ +/* GStreamer splitmux encoding bin + * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk> + * (C) 2009 Nokia Corporation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_SPLITENCODEBIN_H__ +#define __GST_SPLITENCODEBIN_H__ + +#include <gst/gst.h> +#include <gst/pbutils/pbutils.h> + +#include "gstencodebasebin.h" + +#define GST_TYPE_SPLIT_ENCODE_BIN (gst_split_encode_bin_get_type()) +#define GST_SPLIT_ENCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SPLIT_ENCODE_BIN,GstSplitEncodeBin)) +#define GST_SPLIT_ENCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SPLIT_ENCODE_BIN,GstSplitEncodeBinClass)) +#define GST_IS_SPLIT_ENCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SPLIT_ENCODE_BIN)) +#define GST_IS_SPLIT_ENCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SPLIT_ENCODE_BIN)) + +typedef struct _GstSplitEncodeBin GstSplitEncodeBin; +typedef struct _GstSplitEncodeBinClass GstSplitEncodeBinClass; + +struct _GstSplitEncodeBin +{ + GstEncodeBaseBin parent; + + GstElement *provided_renderer; +}; + +struct _GstSplitEncodeBinClass +{ + GstEncodeBaseBinClass parent; +}; + +GType gst_split_encode_bin_get_type(void); + +#endif /* __GST_SPLITENCODEBIN_H__ */ diff --git a/gst/encoding/meson.build b/gst/encoding/meson.build index aef4607..9380ef6 100644 --- a/gst/encoding/meson.build +++ b/gst/encoding/meson.build @@ -1,5 +1,6 @@ encoding_sources = ['gstencodebasebin.c', 'gstencodebin.c', + 'gstsplitencodebin.c', 'gstsmartencoder.c', 'gststreamcombiner.c', 'gststreamsplitter.c', diff --git a/gst/encoding/plugin.c b/gst/encoding/plugin.c index a333cc4..a95039a 100644 --- a/gst/encoding/plugin.c +++ b/gst/encoding/plugin.c @@ -26,6 +26,7 @@ #include <gst/gst-i18n-plugin.h> #include "gstencodebin.h" +#include "gstsplitencodebin.h" static gboolean plugin_init (GstPlugin * plugin) @@ -41,6 +42,9 @@ res = gst_element_register (plugin, "encodebin", GST_RANK_NONE, GST_TYPE_ENCODE_BIN); + res = gst_element_register (plugin, "splitencodebin", GST_RANK_NONE, + GST_TYPE_SPLIT_ENCODE_BIN); + return res; } diff --git a/tests/examples/encoding/encoding.c b/tests/examples/encoding/encoding.c index a7f80af..ffc71bd 100644 --- a/tests/examples/encoding/encoding.c +++ b/tests/examples/encoding/encoding.c @@ -33,6 +33,9 @@ #include "gstcapslist.h" static gboolean silent = FALSE; +static gboolean splitencode = FALSE; +static GstClockTime split_max_size_time = 0; +static guint64 split_max_size_bytes = 0; static void list_codecs (void) @@ -277,6 +280,7 @@ GstElement *src; GstElement *ebin; GstElement *sink; + GstElement *splitmux = NULL; GstBus *bus; GstCaps *profilecaps, *rescaps; GMainLoop *mainloop; @@ -305,7 +309,38 @@ /* Set properties */ g_object_set (src, "uri", uri, "caps", rescaps, NULL); - ebin = gst_element_factory_make ("encodebin", NULL); + { + const gchar *ebin_element; + if (splitencode) { + ebin_element = "splitencodebin"; + } else { + ebin_element = "encodebin"; + } + + ebin = gst_element_factory_make (ebin_element, NULL); + if (G_UNLIKELY (ebin == NULL)) { + g_print ("Can't create element '%s'. Please check your installation\n", + ebin_element); + return; + } + } + + if (splitencode) { + gchar *loc = gst_uri_get_location (outputuri); + + splitmux = gst_element_factory_make ("splitmuxsink", NULL); + if (G_UNLIKELY (splitmux == NULL)) { + g_print ("Can't create element '%s'. Please check your installation\n", + "splitmux"); + return; + } + g_object_set (splitmux, "max-size-time", split_max_size_time, + "max-size-bytes", split_max_size_bytes, + "location", loc, "sink", sink, NULL); + g_object_set (ebin, "renderer", splitmux, NULL); + g_free (loc); + } + g_object_set (ebin, "profile", prof, NULL); g_signal_connect (src, "autoplug-continue", G_CALLBACK (autoplug_continue_cb), @@ -314,9 +349,12 @@ pipeline = gst_pipeline_new ("encoding-pipeline"); - gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL); - - gst_element_link (ebin, sink); + if (splitencode) { + gst_bin_add_many (GST_BIN (pipeline), src, ebin, NULL); + } else { + gst_bin_add_many (GST_BIN (pipeline), src, ebin, sink, NULL); + gst_element_link (ebin, sink); + } mainloop = g_main_loop_new (NULL, FALSE); @@ -384,6 +422,12 @@ "encode to all matching format/codec that aren't specified", NULL}, {"list-codecs", 'l', 0, G_OPTION_ARG_NONE, &listcodecs, "list all available codecs and container formats", NULL}, + {"split-encode", 'e', 0, G_OPTION_ARG_NONE, &splitencode, + "Use splitencodebin to output via splitmuxsink", NULL}, + {"split-max-size-time", 't', 0, G_OPTION_ARG_INT64, &split_max_size_time, + "Maximum time per fragment when performing split-encode", NULL}, + {"split-max-size-bytes", 'b', 0, G_OPTION_ARG_INT64, &split_max_size_bytes, + "Maximum bytes per fragment when performing split-encode", NULL}, {NULL} }; GOptionContext *ctx;