h264decoder: Enable low-latency bumping in case of pic_order_cnt_type 2
[platform/upstream/gstreamer.git] / subprojects / gst-editing-services / 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 (GESSource * source);
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   gint width, height, fps_n, fps_d;
95   GstCaps *caps;
96   GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (element);
97
98
99   if (!parent)
100     goto done;
101
102   g_assert (self->priv->capsfilter);
103   /* Setting the parent ourself as we need it to get the natural size */
104   element->parent = parent;
105   if (!ges_video_source_get_natural_size (GES_VIDEO_SOURCE (self), &width,
106           &height)) {
107     width = DEFAULT_WIDTH;
108     height = DEFAULT_HEIGHT;
109   }
110
111   if (!ges_timeline_element_get_natural_framerate (parent, &fps_n, &fps_d)) {
112     fps_n = DEFAULT_FRAMERATE_N;
113     fps_d = DEFAULT_FRAMERATE_D;
114   }
115
116   caps = gst_caps_new_simple ("video/x-raw",
117       "width", G_TYPE_INT, width,
118       "height", G_TYPE_INT, height,
119       "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
120   g_object_set (self->priv->capsfilter, "caps", caps, NULL);
121   gst_caps_unref (caps);
122
123 done:
124   return
125       GES_TIMELINE_ELEMENT_CLASS
126       (ges_video_test_source_parent_class)->set_parent (element, parent);
127 }
128
129 static gboolean
130 _get_natural_framerate (GESTimelineElement * element, gint * fps_n,
131     gint * fps_d)
132 {
133   gboolean res = FALSE;
134   GESTimelineElement *parent = GES_TIMELINE_ELEMENT_PARENT (element);
135
136   if (parent) {
137     GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (parent));
138
139     if (asset) {
140       res =
141           ges_clip_asset_get_natural_framerate (GES_CLIP_ASSET (asset), fps_n,
142           fps_d);
143     }
144   }
145
146   if (!res) {
147     *fps_n = DEFAULT_FRAMERATE_N;
148     *fps_d = DEFAULT_FRAMERATE_D;
149   }
150
151   return TRUE;
152 }
153
154 static void
155 dispose (GObject * object)
156 {
157   G_OBJECT_CLASS (ges_video_test_source_parent_class)->dispose (object);
158 }
159
160 static void
161 ges_video_test_source_class_init (GESVideoTestSourceClass * klass)
162 {
163   GObjectClass *object_class = G_OBJECT_CLASS (klass);
164   GESVideoSourceClass *vsource_class = GES_VIDEO_SOURCE_CLASS (klass);
165   GESSourceClass *source_class = GES_SOURCE_CLASS (klass);
166
167   source_class->create_source = ges_video_test_source_create_source;
168   vsource_class->ABI.abi.get_natural_size = get_natural_size;
169
170   object_class->dispose = dispose;
171
172   GES_TIMELINE_ELEMENT_CLASS (klass)->set_parent = _set_parent;
173   GES_TIMELINE_ELEMENT_CLASS (klass)->get_natural_framerate =
174       _get_natural_framerate;
175 }
176
177 static void
178 ges_video_test_source_init (GESVideoTestSource * self)
179 {
180   self->priv = ges_video_test_source_get_instance_private (self);
181
182   self->priv->pattern = DEFAULT_VPATTERN;
183 }
184
185 static GstStructure *
186 ges_video_test_source_get_config (GESVideoTestSource * self)
187 {
188   GESAsset *asset = ges_extractable_get_asset (GES_EXTRACTABLE (self));
189   if (asset)
190     return ges_video_test_source_asset_get_config (asset);
191
192   return NULL;
193 }
194
195 static GstElement *
196 ges_video_test_source_create_overlay (GESVideoTestSource * self)
197 {
198   const gchar *bindesc = NULL;
199   GstStructure *config = ges_video_test_source_get_config (self);
200
201   if (!config)
202     return NULL;
203
204   if (gst_structure_has_name (config, "time-overlay")) {
205     gboolean disable_timecodestamper;
206
207     if (gst_structure_get_boolean (config, "disable-timecodestamper",
208             &disable_timecodestamper))
209       bindesc = "timeoverlay";
210     else
211       bindesc = "timecodestamper ! timeoverlay";
212   }
213   gst_structure_free (config);
214
215   if (!bindesc)
216     return NULL;
217
218   return gst_parse_bin_from_description (bindesc, TRUE, NULL);
219 }
220
221 static GstElement *
222 ges_video_test_source_create_source (GESSource * source)
223 {
224   GstCaps *caps;
225   gint pattern;
226   GstElement *testsrc, *res;
227   GstElement *overlay;
228   const gchar *props[] =
229       { "pattern", "background-color", "foreground-color", NULL };
230   GPtrArray *elements;
231   GESVideoTestSource *self = GES_VIDEO_TEST_SOURCE (source);
232   GESTrackElement *element = GES_TRACK_ELEMENT (source);
233
234   g_assert (!GES_TIMELINE_ELEMENT_PARENT (source));
235   testsrc = gst_element_factory_make ("videotestsrc", NULL);
236   self->priv->capsfilter = gst_element_factory_make ("capsfilter", NULL);
237   pattern = self->priv->pattern;
238
239   g_object_set (testsrc, "pattern", pattern, NULL);
240
241   elements = g_ptr_array_new ();
242   g_ptr_array_add (elements, self->priv->capsfilter);
243   caps = gst_caps_new_simple ("video/x-raw",
244       "width", G_TYPE_INT, DEFAULT_WIDTH,
245       "height", G_TYPE_INT, DEFAULT_HEIGHT,
246       "framerate", GST_TYPE_FRACTION, DEFAULT_FRAMERATE_N, DEFAULT_FRAMERATE_D,
247       NULL);
248   g_object_set (self->priv->capsfilter, "caps", caps, NULL);
249   gst_caps_unref (caps);
250
251   overlay = ges_video_test_source_create_overlay (self);
252   if (overlay) {
253     const gchar *overlay_props[] =
254         { "time-mode", "text-y", "text-x", "text-width", "test-height",
255       "halignment", "valignment", "font-desc", NULL
256     };
257
258     ges_track_element_add_children_props (element, overlay, NULL,
259         NULL, overlay_props);
260     g_ptr_array_add (elements, overlay);
261   }
262
263   ges_track_element_add_children_props (element, testsrc, NULL, NULL, props);
264
265   res = ges_source_create_topbin (GES_SOURCE (element), "videotestsrc", testsrc,
266       elements);
267
268   return res;
269 }
270
271 /**
272  * ges_video_test_source_set_pattern:
273  * @self: a #GESVideoTestSource
274  * @pattern: a #GESVideoTestPattern
275  *
276  * Sets the source to use the given @pattern.
277  */
278 void
279 ges_video_test_source_set_pattern (GESVideoTestSource
280     * self, GESVideoTestPattern pattern)
281 {
282   GstElement *element =
283       ges_track_element_get_element (GES_TRACK_ELEMENT (self));
284
285   self->priv->pattern = pattern;
286
287   if (element) {
288     GValue val = { 0 };
289
290     g_value_init (&val, GES_VIDEO_TEST_PATTERN_TYPE);
291     g_value_set_enum (&val, pattern);
292     ges_track_element_set_child_property (GES_TRACK_ELEMENT (self), "pattern",
293         &val);
294   }
295 }
296
297 /**
298  * ges_video_test_source_get_pattern:
299  * @source: a #GESVideoTestPattern
300  *
301  * Get the video pattern used by the @source.
302  *
303  * Returns: The video pattern used by the @source.
304  */
305 GESVideoTestPattern
306 ges_video_test_source_get_pattern (GESVideoTestSource * source)
307 {
308   GValue val = { 0 };
309
310   ges_track_element_get_child_property (GES_TRACK_ELEMENT (source), "pattern",
311       &val);
312   return g_value_get_enum (&val);
313 }
314
315 /**
316  * ges_video_test_source_new:
317  *
318  * Creates a new #GESVideoTestSource.
319  *
320  * Returns: (transfer floating) (nullable): The newly created
321  * #GESVideoTestSource, or %NULL if there was an error.
322  */
323 GESVideoTestSource *
324 ges_video_test_source_new (void)
325 {
326   GESVideoTestSource *res;
327   GESAsset *asset = ges_asset_request (GES_TYPE_VIDEO_TEST_SOURCE, NULL, NULL);
328
329   res = GES_VIDEO_TEST_SOURCE (ges_asset_extract (asset, NULL));
330   gst_object_unref (asset);
331
332   return res;
333 }