ges: Add a timeoverlay to video test sources

This is often very useful to have a timeoverlay inside test sources.
We do not want to use it as an effect as segments are not the sames
in GES when it comes to nleoperations.
This commit is contained in:
Thibault Saunier 2020-02-21 17:17:10 -03:00
parent 66fb647183
commit 2cbc1f14df
2 changed files with 224 additions and 6 deletions

View file

@ -99,8 +99,10 @@ ges_source_create_topbin (const gchar * bin_name, GstElement * sub_element,
if (prev) {
if (!gst_element_link_pads_full (prev, "src", element, "sink",
GST_PAD_LINK_CHECK_NOTHING)) {
g_error ("Could not link %s and %s",
GST_OBJECT_NAME (prev), GST_OBJECT_NAME (element));
if (!gst_element_link (prev, element)) {
g_error ("Could not link %s and %s",
GST_OBJECT_NAME (prev), GST_OBJECT_NAME (element));
}
}
}
prev = element;

View file

@ -21,7 +21,8 @@
/**
* SECTION:gesvideotestsource
* @title: GESVideoTestSource
* @short_description: produce solid colors and patterns
* @short_description: produce solid colors and patterns, possibly with a time
* overlay.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
@ -36,6 +37,15 @@
struct _GESVideoTestSourcePrivate
{
GESVideoTestPattern pattern;
gboolean use_overlay;
GstElement *overlay;
GstPad *is_passthrough_pad;
GstPad *os_passthrough_pad;
GstPad *is_overlay_pad;
GstPad *os_overlay_pad;
};
G_DEFINE_TYPE_WITH_PRIVATE (GESVideoTestSource, ges_video_test_source,
@ -52,13 +62,146 @@ get_natural_size (GESVideoSource * source, gint * width, gint * height)
return TRUE;
}
enum
{
PROP_0,
PROP_USE_TIME_OVERLAY,
PROP_LAST
};
static GParamSpec *properties[PROP_LAST];
static void
get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
switch (property_id) {
case PROP_USE_TIME_OVERLAY:
g_value_set_boolean (value, self->priv->use_overlay);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
switch (property_id) {
case PROP_USE_TIME_OVERLAY:
{
GstElement *os, *is;
gboolean used_overlay = self->priv->use_overlay;
if (!self->priv->overlay) {
GST_ERROR_OBJECT (object, "Overlaying is disabled, you are probably"
"missing some GStreamer plugin");
return;
}
self->priv->use_overlay = g_value_get_boolean (value);
if (used_overlay == self->priv->use_overlay)
return;
is = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
priv->is_overlay_pad)));
if (!is)
return;
os = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
priv->os_overlay_pad)));
if (!os) {
gst_object_unref (is);
return;
}
g_object_set (is, "active-pad",
self->priv->use_overlay ? self->priv->is_overlay_pad : self->
priv->is_passthrough_pad, NULL);
g_object_set (os, "active-pad",
self->priv->use_overlay ? self->priv->os_overlay_pad : self->
priv->os_passthrough_pad, NULL);
gst_object_unref (is);
gst_object_unref (os);
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
_set_child_property (GESTimelineElement * self, GObject * child,
GParamSpec * pspec, GValue * value)
{
GstElementFactory *f =
GST_IS_ELEMENT (child) ? gst_element_get_factory (GST_ELEMENT (child)) :
NULL;
if (!f || g_strcmp0 (GST_OBJECT_NAME (f), "timeoverlay"))
goto done;
GST_INFO_OBJECT (self, "Activating time overlay as time mode is being set");
g_object_set (self, "use-time-overlay", TRUE, NULL);
done:
GES_TIMELINE_ELEMENT_CLASS (ges_video_test_source_parent_class)
->set_child_property (self, child, pspec, value);
}
static void
dispose (GObject * object)
{
GESVideoTestSourcePrivate *priv = GES_VIDEO_TEST_SOURCE (object)->priv;
gst_clear_object (&priv->is_overlay_pad);
gst_clear_object (&priv->is_passthrough_pad);
gst_clear_object (&priv->os_overlay_pad);
gst_clear_object (&priv->os_passthrough_pad);
G_OBJECT_CLASS (ges_video_test_source_parent_class)->dispose (object);
}
static void
ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_CLASS (klass);
source_class->create_source = ges_video_test_source_create_source;
source_class->ABI.abi.get_natural_size = get_natural_size;
/**
* GESVideoTestSource:use-overlay:
*
* Whether to overlay the test video source with a clock time.
* This property is also registered as a child property for the video
* test source, so you can set it like any other child property.
*
* The properties of the corresponding #timeoverlay are also registered
* as children properties. If you set any child property from the underlying
* `timeoverlay`, this property will be set to %TRUE by default.
*/
properties[PROP_USE_TIME_OVERLAY] =
g_param_spec_boolean ("use-time-overlay", "Use-time-overlay",
"Use time overlay, setting a child property corresponding to GstTimeOverlay will switch this on"
" by default.", FALSE, G_PARAM_READWRITE);
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
GES_TIMELINE_ELEMENT_CLASS (klass)->set_child_property = _set_child_property;
g_object_class_install_properties (object_class, PROP_LAST, properties);
}
static void
@ -69,18 +212,77 @@ ges_video_test_source_init (GESVideoTestSource * self)
self->priv->pattern = DEFAULT_VPATTERN;
}
#define CREATE_ELEMENT(var, ename) \
if (!(var = gst_element_factory_make(ename, NULL))) { \
GST_ERROR_OBJECT(self, "Could not create %s", ename); \
goto done; \
} \
gst_object_ref(var);
static GstElement *
ges_video_test_source_create_source (GESTrackElement * self)
ges_video_test_source_create_overlay (GESVideoTestSource * self)
{
GstElement *bin = NULL, *os = NULL, *is = NULL, *toverlay = NULL, *tcstamper =
NULL;
GstPad *tmppad;
CREATE_ELEMENT (os, "output-selector");
CREATE_ELEMENT (is, "input-selector");
CREATE_ELEMENT (tcstamper, "timecodestamper");
CREATE_ELEMENT (toverlay, "timeoverlay");
bin = gst_bin_new (NULL);
gst_bin_add_many (GST_BIN (bin), os, is, tcstamper, toverlay, NULL);
self->priv->os_passthrough_pad = gst_element_get_request_pad (os, "src_%u");
self->priv->is_passthrough_pad = gst_element_get_request_pad (is, "sink_%u");
gst_pad_link_full (self->priv->os_passthrough_pad,
self->priv->is_passthrough_pad, GST_PAD_LINK_CHECK_NOTHING);
gst_element_link (tcstamper, toverlay);
self->priv->os_overlay_pad = gst_element_get_request_pad (os, "src_%u");
tmppad = gst_element_get_static_pad (tcstamper, "sink");
gst_pad_link_full (self->priv->os_overlay_pad, tmppad,
GST_PAD_LINK_CHECK_NOTHING);
gst_object_unref (tmppad);
tmppad = gst_element_get_static_pad (toverlay, "src");
self->priv->is_overlay_pad = gst_element_get_request_pad (is, "sink_%u");
gst_pad_link_full (tmppad, self->priv->is_overlay_pad,
GST_PAD_LINK_CHECK_NOTHING);
gst_object_unref (tmppad);
tmppad = gst_element_get_static_pad (os, "sink");
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", tmppad));
gst_object_unref (tmppad);
tmppad = gst_element_get_static_pad (is, "src");
gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", tmppad));
gst_object_unref (tmppad);
done:
gst_clear_object (&os);
gst_clear_object (&is);
gst_clear_object (&tcstamper);
gst_clear_object (&toverlay);
return bin;
}
static GstElement *
ges_video_test_source_create_source (GESTrackElement * element)
{
GstCaps *caps;
gint pattern;
GstElement *testsrc, *capsfilter, *res;
const gchar *props[] = { "pattern", NULL };
GPtrArray *elements;
GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
testsrc = gst_element_factory_make ("videotestsrc", NULL);
capsfilter = gst_element_factory_make ("capsfilter", NULL);
pattern = ((GESVideoTestSource *) self)->priv->pattern;
pattern = self->priv->pattern;
g_object_set (testsrc, "pattern", pattern, NULL);
@ -94,7 +296,21 @@ ges_video_test_source_create_source (GESTrackElement * self)
g_object_set (capsfilter, "caps", caps, NULL);
gst_caps_unref (caps);
ges_track_element_add_children_props (self, testsrc, NULL, NULL, props);
self->priv->overlay = ges_video_test_source_create_overlay (self);
if (self->priv->overlay) {
const gchar *overlay_props[] =
{ "time-mode", "text-y", "text-x", "text-width", "test-height",
"halignment", "valignment", "font-desc", NULL
};
ges_track_element_add_children_props (element, self->priv->overlay, NULL,
NULL, overlay_props);
ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (self),
properties[PROP_USE_TIME_OVERLAY], G_OBJECT (self));
g_ptr_array_add (elements, self->priv->overlay);
}
ges_track_element_add_children_props (element, testsrc, NULL, NULL, props);
res = ges_source_create_topbin ("videotestsrc", testsrc, elements);
g_ptr_array_free (elements, TRUE);