2f8faceaa725619c3df61650774079c21dec4c79
[platform/upstream/gst-editing-services.git] / ges / ges-video-test-source.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
3  *               2010 Nokia Corporation
4  * Copyright (C) 2020 Igalia S.L
5  *     Author: 2020 Thibault Saunier <tsaunier@igalia.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:gesvideotestsource
25  * @title: GESVideoTestSource
26  * @short_description: produce solid colors and patterns, possibly with a time
27  * overlay.
28  */
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include "ges-internal.h"
34 #include "ges-track-element.h"
35 #include "ges-video-test-source.h"
36
37 #define DEFAULT_VPATTERN GES_VIDEO_TEST_PATTERN_SMPTE
38
39 struct _GESVideoTestSourcePrivate
40 {
41   GESVideoTestPattern pattern;
42
43   GstElement *capsfilter;
44 };
45
46 static void
47 ges_extractable_interface_init (GESExtractableInterface * iface)
48 {
49   iface->check_id = ges_test_source_asset_check_id;
50   iface->asset_type = GES_TYPE_TRACK_ELEMENT_ASSET;
51 }
52
53 static GstStructure *
54 ges_video_test_source_asset_get_config (GESAsset * asset)
55 {
56   const gchar *id = ges_asset_get_id (asset);
57   if (g_strcmp0 (id, g_type_name (ges_asset_get_extractable_type (asset))))
58     return gst_structure_from_string (ges_asset_get_id (asset), NULL);
59
60   return NULL;
61 }
62
63 G_DEFINE_TYPE_WITH_CODE (GESVideoTestSource, ges_video_test_source,
64     GES_TYPE_VIDEO_SOURCE, G_ADD_PRIVATE (GESVideoTestSource)
65     G_IMPLEMENT_INTERFACE (GES_TYPE_EXTRACTABLE,
66         ges_extractable_interface_init));
67
68 static GstElement *ges_video_test_source_create_source (GESTrackElement * self);
69
70 static gboolean
71 get_natural_size (GESVideoSource * source, gint * width, gint * height)
72 {
73   gboolean res = FALSE;
74   GESTimelineElement *parent = GES_TIMELINE_ELEMENT_PARENT (source);
75
76   if (parent) {
77     GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (parent));
78
79     if (asset)
80       res = ges_test_clip_asset_get_natural_size (asset, width, height);
81   }
82
83   if (!res) {
84     *width = DEFAULT_WIDTH;
85     *height = DEFAULT_HEIGHT;
86   }
87
88   return TRUE;
89 }
90
91 static gboolean
92 _set_parent (GESTimelineElement * element, GESTimelineElement * parent)
93 {
94   GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
95
96
97   if (parent) {
98     gint width, height, fps_n, fps_d;
99     GstCaps *caps;
100
101     g_assert (self->priv->capsfilter);
102     /* Setting the parent ourself as we need it to get the natural size */
103     element->parent = parent;
104     if (!ges_video_source_get_natural_size (GES_VIDEO_SOURCE (self), &width,
105             &height)) {
106       width = DEFAULT_WIDTH;
107       height = DEFAULT_HEIGHT;
108     }
109     if (!ges_timeline_element_get_natural_framerate (parent, &fps_n, &fps_d)) {
110       fps_n = DEFAULT_FRAMERATE_N;
111       fps_d = DEFAULT_FRAMERATE_D;
112     }
113
114     caps = gst_caps_new_simple ("video/x-raw",
115         "width", G_TYPE_INT, width,
116         "height", G_TYPE_INT, height,
117         "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
118     g_object_set (self->priv->capsfilter, "caps", caps, NULL);
119     gst_caps_unref (caps);
120   }
121
122   return TRUE;
123 }
124
125 static gboolean
126 _get_natural_framerate (GESTimelineElement * element, gint * fps_n,
127     gint * fps_d)
128 {
129   gboolean res = FALSE;
130   GESTimelineElement *parent = GES_TIMELINE_ELEMENT_PARENT (element);
131
132   if (parent) {
133     GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (parent));
134
135     if (asset) {
136       res =
137           ges_clip_asset_get_natural_framerate (GES_CLIP_ASSET (asset), fps_n,
138           fps_d);
139     }
140   }
141
142   if (!res) {
143     *fps_n = DEFAULT_FRAMERATE_N;
144     *fps_d = DEFAULT_FRAMERATE_D;
145   }
146
147   return TRUE;
148 }
149
150 static void
151 dispose (GObject * object)
152 {
153   G_OBJECT_CLASS (ges_video_test_source_parent_class)->dispose (object);
154 }
155
156 static void
157 ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
158 {
159   GObjectClass *object_class = G_OBJECT_CLASS (klass);
160   GESVideoSourceClass *source_class = GES_VIDEO_SOURCE_CLASS (klass);
161
162   source_class->create_source = ges_video_test_source_create_source;
163   source_class->ABI.abi.get_natural_size = get_natural_size;
164
165   object_class->dispose = dispose;
166
167   GES_TIMELINE_ELEMENT_CLASS (klass)->set_parent = _set_parent;
168   GES_TIMELINE_ELEMENT_CLASS (klass)->get_natural_framerate =
169       _get_natural_framerate;
170 }
171
172 static void
173 ges_video_test_source_init (GESVideoTestSource * self)
174 {
175   self->priv = ges_video_test_source_get_instance_private (self);
176
177   self->priv->pattern = DEFAULT_VPATTERN;
178 }
179
180 static GstStructure *
181 ges_video_test_source_get_config (GESVideoTestSource * self)
182 {
183   GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
184   if (asset)
185     return ges_video_test_source_asset_get_config (asset);
186
187   return NULL;
188 }
189
190 static GstElement *
191 ges_video_test_source_create_overlay (GESVideoTestSource * self)
192 {
193   const gchar *bindesc = NULL;
194   GstStructure *config = ges_video_test_source_get_config (self);
195
196   if (!config)
197     return NULL;
198
199   if (gst_structure_has_name (config, "time-overlay")) {
200     gboolean disable_timecodestamper;
201
202     if (gst_structure_get_boolean (config, "disable-timecodestamper",
203             &disable_timecodestamper))
204       bindesc = "timeoverlay";
205     else
206       bindesc = "timecodestamper ! timeoverlay";
207   }
208   gst_structure_free (config);
209
210   if (!bindesc)
211     return NULL;
212
213   return gst_parse_bin_from_description (bindesc, TRUE, NULL);
214 }
215
216 static GstElement *
217 ges_video_test_source_create_source (GESTrackElement * element)
218 {
219   GstCaps *caps;
220   gint pattern;
221   GstElement *testsrc, *res;
222   GstElement *overlay;
223   const gchar *props[] =
224       { "pattern", "background-color", "foreground-color", NULL };
225   GPtrArray *elements;
226   GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
227
228   g_assert (!GES_TIMELINE_ELEMENT_PARENT (element));
229   testsrc = gst_element_factory_make ("videotestsrc", NULL);
230   self->priv->capsfilter = gst_element_factory_make ("capsfilter", NULL);
231   pattern = self->priv->pattern;
232
233   g_object_set (testsrc, "pattern", pattern, NULL);
234
235   elements = g_ptr_array_new ();
236   g_ptr_array_add (elements, self->priv->capsfilter);
237   caps = gst_caps_new_simple ("video/x-raw",
238       "width", G_TYPE_INT, DEFAULT_WIDTH,
239       "height", G_TYPE_INT, DEFAULT_HEIGHT,
240       "framerate", GST_TYPE_FRACTION, DEFAULT_FRAMERATE_N, DEFAULT_FRAMERATE_D,
241       NULL);
242   g_object_set (self->priv->capsfilter, "caps", caps, NULL);
243   gst_caps_unref (caps);
244
245   overlay = ges_video_test_source_create_overlay (self);
246   if (overlay) {
247     const gchar *overlay_props[] =
248         { "time-mode", "text-y", "text-x", "text-width", "test-height",
249       "halignment", "valignment", "font-desc", NULL
250     };
251
252     ges_track_element_add_children_props (element, overlay, NULL,
253         NULL, overlay_props);
254     g_ptr_array_add (elements, overlay);
255   }
256
257   ges_track_element_add_children_props (element, testsrc, NULL, NULL, props);
258
259   res = ges_source_create_topbin (GES_SOURCE (element), "videotestsrc", testsrc,
260       elements);
261
262   return res;
263 }
264
265 /**
266  * ges_video_test_source_set_pattern:
267  * @self: a #GESVideoTestSource
268  * @pattern: a #GESVideoTestPattern
269  *
270  * Sets the source to use the given @pattern.
271  */
272 void
273 ges_video_test_source_set_pattern (GESVideoTestSource
274     * self, GESVideoTestPattern pattern)
275 {
276   GstElement *element =
277       ges_track_element_get_element (GES_TRACK_ELEMENT (self));
278
279   self->priv->pattern = pattern;
280
281   if (element) {
282     GValue val = { 0 };
283
284     g_value_init (&val, GES_VIDEO_TEST_PATTERN_TYPE);
285     g_value_set_enum (&val, pattern);
286     ges_track_element_set_child_property (GES_TRACK_ELEMENT (self), "pattern",
287         &val);
288   }
289 }
290
291 /**
292  * ges_video_test_source_get_pattern:
293  * @source: a #GESVideoTestPattern
294  *
295  * Get the video pattern used by the @source.
296  *
297  * Returns: The video pattern used by the @source.
298  */
299 GESVideoTestPattern
300 ges_video_test_source_get_pattern (GESVideoTestSource * source)
301 {
302   GValue val = { 0 };
303
304   ges_track_element_get_child_property (GES_TRACK_ELEMENT (source), "pattern",
305       &val);
306   return g_value_get_enum (&val);
307 }
308
309 /**
310  * ges_video_test_source_new:
311  *
312  * Creates a new #GESVideoTestSource.
313  *
314  * Returns: (transfer floating) (nullable): The newly created
315  * #GESVideoTestSource, or %NULL if there was an error.
316  */
317 GESVideoTestSource *
318 ges_video_test_source_new (void)
319 {
320   GESVideoTestSource *res;
321   GESAsset *asset = ges_asset_request (GES_TYPE_VIDEO_TEST_SOURCE, NULL, NULL);
322
323   res = GES_VIDEO_TEST_SOURCE (ges_asset_extract (asset, NULL));
324   gst_object_unref (asset);
325
326   return res;
327 }