1 /* GStreamer Editing Services
2 * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
3 * 2010 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
22 * SECTION:gesvideotestsource
23 * @title: GESVideoTestSource
24 * @short_description: produce solid colors and patterns, possibly with a time
31 #include "ges-internal.h"
32 #include "ges-track-element.h"
33 #include "ges-video-test-source.h"
35 #define DEFAULT_VPATTERN GES_VIDEO_TEST_PATTERN_SMPTE
37 struct _GESVideoTestSourcePrivate
39 GESVideoTestPattern pattern;
43 GstPad *is_passthrough_pad;
44 GstPad *os_passthrough_pad;
45 GstPad *is_overlay_pad;
46 GstPad *os_overlay_pad;
48 GstElement *capsfilter;
51 G_DEFINE_TYPE_WITH_PRIVATE (GESVideoTestSource, ges_video_test_source,
52 GES_TYPE_VIDEO_SOURCE);
54 static GstElement *ges_video_test_source_create_source (GESTrackElement * self);
57 get_natural_size (GESVideoSource * source, gint * width, gint * height)
60 GESTimelineElement *parent = GES_TIMELINE_ELEMENT_PARENT (source);
63 GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (parent));
66 res = ges_test_clip_asset_get_natural_size (asset, width, height);
70 *width = DEFAULT_WIDTH;
71 *height = DEFAULT_HEIGHT;
80 PROP_USE_TIME_OVERLAY,
84 static GParamSpec *properties[PROP_LAST];
87 get_property (GObject * object, guint property_id,
88 GValue * value, GParamSpec * pspec)
90 GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
92 switch (property_id) {
93 case PROP_USE_TIME_OVERLAY:
94 g_value_set_boolean (value, self->priv->use_overlay);
97 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
102 set_property (GObject * object, guint property_id,
103 const GValue * value, GParamSpec * pspec)
105 GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (object);
107 switch (property_id) {
108 case PROP_USE_TIME_OVERLAY:
111 gboolean used_overlay = self->priv->use_overlay;
113 if (!self->priv->overlay) {
114 GST_ERROR_OBJECT (object, "Overlaying is disabled, you are probably"
115 "missing some GStreamer plugin");
119 self->priv->use_overlay = g_value_get_boolean (value);
120 if (used_overlay == self->priv->use_overlay)
123 is = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
124 priv->is_overlay_pad)));
129 os = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (self->
130 priv->os_overlay_pad)));
132 gst_object_unref (is);
136 g_object_set (is, "active-pad",
137 self->priv->use_overlay ? self->priv->is_overlay_pad : self->
138 priv->is_passthrough_pad, NULL);
139 g_object_set (os, "active-pad",
140 self->priv->use_overlay ? self->priv->os_overlay_pad : self->
141 priv->os_passthrough_pad, NULL);
143 gst_object_unref (is);
144 gst_object_unref (os);
149 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154 _set_child_property (GESTimelineElement * self, GObject * child,
155 GParamSpec * pspec, GValue * value)
157 GstElementFactory *f =
158 GST_IS_ELEMENT (child) ? gst_element_get_factory (GST_ELEMENT (child)) :
161 if (!f || g_strcmp0 (GST_OBJECT_NAME (f), "timeoverlay"))
164 GST_INFO_OBJECT (self, "Activating time overlay as time mode is being set");
165 g_object_set (self, "use-time-overlay", TRUE, NULL);
168 GES_TIMELINE_ELEMENT_CLASS (ges_video_test_source_parent_class)
169 ->set_child_property (self, child, pspec, value);
173 _set_parent (GESTimelineElement * element, GESTimelineElement * parent)
175 GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
179 gint width, height, fps_n, fps_d;
182 g_assert (self->priv->capsfilter);
183 /* Setting the parent ourself as we need it to get the natural size */
184 element->parent = parent;
185 if (!ges_video_source_get_natural_size (GES_VIDEO_SOURCE (self), &width,
187 width = DEFAULT_WIDTH;
188 height = DEFAULT_HEIGHT;
190 if (!ges_timeline_element_get_natural_framerate (parent, &fps_n, &fps_d)) {
191 fps_n = DEFAULT_FRAMERATE_N;
192 fps_d = DEFAULT_FRAMERATE_D;
195 caps = gst_caps_new_simple ("video/x-raw",
196 "width", G_TYPE_INT, width,
197 "height", G_TYPE_INT, height,
198 "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
199 g_object_set (self->priv->capsfilter, "caps", caps, NULL);
200 gst_caps_unref (caps);
207 _get_natural_framerate (GESTimelineElement * element, gint * fps_n,
210 gboolean res = FALSE;
211 GESTimelineElement *parent = GES_TIMELINE_ELEMENT_PARENT (element);
214 GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (parent));
218 ges_clip_asset_get_natural_framerate (GES_CLIP_ASSET (asset), fps_n,
224 *fps_n = DEFAULT_FRAMERATE_N;
225 *fps_d = DEFAULT_FRAMERATE_D;
232 dispose (GObject * object)
234 GESVideoTestSourcePrivate *priv = GES_VIDEO_TEST_SOURCE (object)->priv;
236 gst_clear_object (&priv->is_overlay_pad);
237 gst_clear_object (&priv->is_passthrough_pad);
238 gst_clear_object (&priv->os_overlay_pad);
239 gst_clear_object (&priv->os_passthrough_pad);
241 G_OBJECT_CLASS (ges_video_test_source_parent_class)->dispose (object);
245 ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
247 GObjectClass *object_class = G_OBJECT_CLASS (klass);
248 GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_CLASS (klass);
250 source_class->create_source = ges_video_test_source_create_source;
251 source_class->ABI.abi.get_natural_size = get_natural_size;
254 * GESVideoTestSource:use-overlay:
256 * Whether to overlay the test video source with a clock time.
257 * This property is also registered as a child property for the video
258 * test source, so you can set it like any other child property.
260 * The properties of the corresponding #timeoverlay are also registered
261 * as children properties. If you set any child property from the underlying
262 * `timeoverlay`, this property will be set to %TRUE by default.
264 properties[PROP_USE_TIME_OVERLAY] =
265 g_param_spec_boolean ("use-time-overlay", "Use-time-overlay",
266 "Use time overlay, setting a child property corresponding to"
267 "GstTimeOverlay will switch this on by default.", FALSE,
270 object_class->get_property = get_property;
271 object_class->set_property = set_property;
272 object_class->dispose = dispose;
274 GES_TIMELINE_ELEMENT_CLASS (klass)->set_child_property = _set_child_property;
275 GES_TIMELINE_ELEMENT_CLASS (klass)->set_parent = _set_parent;
276 GES_TIMELINE_ELEMENT_CLASS (klass)->get_natural_framerate =
277 _get_natural_framerate;
279 g_object_class_install_properties (object_class, PROP_LAST, properties);
283 ges_video_test_source_init (GESVideoTestSource * self)
285 self->priv = ges_video_test_source_get_instance_private (self);
287 self->priv->pattern = DEFAULT_VPATTERN;
290 #define CREATE_ELEMENT(var, ename) \
291 if (!(var = gst_element_factory_make(ename, NULL))) { \
292 GST_ERROR_OBJECT(self, "Could not create %s", ename); \
298 ges_video_test_source_create_overlay (GESVideoTestSource * self)
300 GstElement *bin = NULL, *os = NULL, *is = NULL, *toverlay = NULL, *tcstamper =
304 CREATE_ELEMENT (os, "output-selector");
305 CREATE_ELEMENT (is, "input-selector");
306 CREATE_ELEMENT (tcstamper, "timecodestamper");
307 CREATE_ELEMENT (toverlay, "timeoverlay");
309 bin = gst_bin_new (NULL);
311 gst_bin_add_many (GST_BIN (bin), os, is, tcstamper, toverlay, NULL);
312 self->priv->os_passthrough_pad = gst_element_get_request_pad (os, "src_%u");
313 self->priv->is_passthrough_pad = gst_element_get_request_pad (is, "sink_%u");
315 gst_pad_link_full (self->priv->os_passthrough_pad,
316 self->priv->is_passthrough_pad, GST_PAD_LINK_CHECK_NOTHING);
317 gst_element_link (tcstamper, toverlay);
319 self->priv->os_overlay_pad = gst_element_get_request_pad (os, "src_%u");
320 tmppad = gst_element_get_static_pad (tcstamper, "sink");
321 gst_pad_link_full (self->priv->os_overlay_pad, tmppad,
322 GST_PAD_LINK_CHECK_NOTHING);
323 gst_object_unref (tmppad);
325 tmppad = gst_element_get_static_pad (toverlay, "src");
326 self->priv->is_overlay_pad = gst_element_get_request_pad (is, "sink_%u");
327 gst_pad_link_full (tmppad, self->priv->is_overlay_pad,
328 GST_PAD_LINK_CHECK_NOTHING);
329 gst_object_unref (tmppad);
331 tmppad = gst_element_get_static_pad (os, "sink");
332 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("sink", tmppad));
333 gst_object_unref (tmppad);
335 tmppad = gst_element_get_static_pad (is, "src");
336 gst_element_add_pad (GST_ELEMENT (bin), gst_ghost_pad_new ("src", tmppad));
337 gst_object_unref (tmppad);
340 gst_clear_object (&os);
341 gst_clear_object (&is);
342 gst_clear_object (&tcstamper);
343 gst_clear_object (&toverlay);
349 ges_video_test_source_create_source (GESTrackElement * element)
353 GstElement *testsrc, *res;
354 const gchar *props[] =
355 { "pattern", "background-color", "foreground-color", NULL };
357 GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
359 g_assert (!GES_TIMELINE_ELEMENT_PARENT (element));
360 testsrc = gst_element_factory_make ("videotestsrc", NULL);
361 self->priv->capsfilter = gst_element_factory_make ("capsfilter", NULL);
362 pattern = self->priv->pattern;
364 g_object_set (testsrc, "pattern", pattern, NULL);
366 elements = g_ptr_array_new ();
367 g_ptr_array_add (elements, self->priv->capsfilter);
368 caps = gst_caps_new_simple ("video/x-raw",
369 "width", G_TYPE_INT, DEFAULT_WIDTH,
370 "height", G_TYPE_INT, DEFAULT_HEIGHT,
371 "framerate", GST_TYPE_FRACTION, DEFAULT_FRAMERATE_N, DEFAULT_FRAMERATE_D,
373 g_object_set (self->priv->capsfilter, "caps", caps, NULL);
374 gst_caps_unref (caps);
376 self->priv->overlay = ges_video_test_source_create_overlay (self);
377 if (self->priv->overlay) {
378 const gchar *overlay_props[] =
379 { "time-mode", "text-y", "text-x", "text-width", "test-height",
380 "halignment", "valignment", "font-desc", NULL
383 ges_track_element_add_children_props (element, self->priv->overlay, NULL,
384 NULL, overlay_props);
385 ges_timeline_element_add_child_property (GES_TIMELINE_ELEMENT (self),
386 properties[PROP_USE_TIME_OVERLAY], G_OBJECT (self));
387 g_ptr_array_add (elements, self->priv->overlay);
390 ges_track_element_add_children_props (element, testsrc, NULL, NULL, props);
392 res = ges_source_create_topbin ("videotestsrc", testsrc, elements);
393 g_ptr_array_free (elements, TRUE);
399 * ges_video_test_source_set_pattern:
400 * @self: a #GESVideoTestSource
401 * @pattern: a #GESVideoTestPattern
403 * Sets the source to use the given @pattern.
406 ges_video_test_source_set_pattern (GESVideoTestSource
407 * self, GESVideoTestPattern pattern)
409 GstElement *element =
410 ges_track_element_get_element (GES_TRACK_ELEMENT (self));
412 self->priv->pattern = pattern;
417 g_value_init (&val, GES_VIDEO_TEST_PATTERN_TYPE);
418 g_value_set_enum (&val, pattern);
419 ges_track_element_set_child_property (GES_TRACK_ELEMENT (self), "pattern",
425 * ges_video_test_source_get_pattern:
426 * @source: a #GESVideoTestPattern
428 * Get the video pattern used by the @source.
430 * Returns: The video pattern used by the @source.
433 ges_video_test_source_get_pattern (GESVideoTestSource * source)
437 ges_track_element_get_child_property (GES_TRACK_ELEMENT (source), "pattern",
439 return g_value_get_enum (&val);
442 /* ges_video_test_source_new:
444 * Creates a new #GESVideoTestSource.
446 * Returns: (transfer floating) (nullable): The newly created
447 * #GESVideoTestSource, or %NULL if there was an error.
450 ges_video_test_source_new (void)
452 GESVideoTestSource *res;
453 GESAsset *asset = ges_asset_request (GES_TYPE_VIDEO_TEST_SOURCE, NULL, NULL);
455 res = GES_VIDEO_TEST_SOURCE (ges_asset_extract (asset, NULL));
456 gst_object_unref (asset);