gst: don't use volatile to mean atomic
[platform/upstream/gstreamer.git] / gst / debugutils / gstfakevideosink.c
1 /*
2  * GStreamer
3  * Copyright (C) 2017 Collabora Inc.
4  *   Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:element-fakevideosink
24  * @title: fakevideosink
25  *
26  * This element is the same as fakesink but will pretend to support various
27  * allocation meta API like GstVideoMeta in order to prevent memory copies.
28  * This is useful for throughput testing and testing zero-copy path while
29  * creating a new pipeline.
30  *
31  * ## Example launch lines
32  * |[
33  * gst-launch-1.0 videotestsrc ! fakevideosink
34  * gst-launch-1.0 videotestsrc ! fpsdisplaysink text-overlay=false video-sink=fakevideosink
35  * ]|
36  *
37  * Since 1.14
38  */
39
40 #include "gstfakevideosink.h"
41
42 #include <gst/video/video.h>
43
44 #define C_FLAGS(v) ((guint) v)
45
46 GType
47 gst_fake_video_sink_allocation_meta_flags_get_type (void)
48 {
49   static const GFlagsValue values[] = {
50     {C_FLAGS (GST_ALLOCATION_FLAG_CROP_META),
51         "Expose the crop meta as supported", "crop"},
52     {C_FLAGS (GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META),
53           "Expose the overlay composition meta as supported",
54         "overlay-composition"},
55     {0, NULL, NULL}
56   };
57   static GType id = 0;
58
59   if (g_once_init_enter ((gsize *) & id)) {
60     GType _id;
61
62     _id =
63         g_flags_register_static ("GstFakeVideoSinkAllocationMetaFlags", values);
64
65     g_once_init_leave ((gsize *) & id, _id);
66   }
67
68   return id;
69 }
70
71 enum
72 {
73   PROP_0,
74   PROP_ALLOCATION_META_FLAGS,
75   PROP_LAST
76 };
77
78 #define ALLOCATION_META_DEFAULT_FLAGS GST_ALLOCATION_FLAG_CROP_META | GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META
79
80 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
81     GST_PAD_SINK,
82     GST_PAD_ALWAYS,
83     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY",
84             GST_VIDEO_FORMATS_ALL)));
85
86 G_DEFINE_TYPE (GstFakeVideoSink, gst_fake_video_sink, GST_TYPE_BIN);
87
88 static gboolean
89 gst_fake_video_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
90 {
91   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (parent);
92   GstCaps *caps;
93   GstVideoInfo info;
94   guint min_buffers = 1;
95
96   if (GST_QUERY_TYPE (query) != GST_QUERY_ALLOCATION)
97     return gst_pad_query_default (pad, parent, query);
98
99   gst_query_parse_allocation (query, &caps, NULL);
100   if (!gst_video_info_from_caps (&info, caps))
101     return FALSE;
102
103   /* Request an extra buffer if we are keeping a ref on the last rendered buffer */
104   if (gst_base_sink_is_last_sample_enabled (GST_BASE_SINK (self->child)))
105     min_buffers++;
106
107   gst_query_add_allocation_pool (query, NULL, info.size, min_buffers, 0);
108   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
109
110   GST_OBJECT_LOCK (self);
111   if (self->allocation_meta_flags & GST_ALLOCATION_FLAG_CROP_META)
112     gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
113
114   if (self->allocation_meta_flags &
115       GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META)
116     gst_query_add_allocation_meta (query,
117         GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
118
119   GST_OBJECT_UNLOCK (self);
120
121   /* add here any meta API that would help support zero-copy */
122
123   return TRUE;
124 }
125
126 /* TODO complete the types and make this an utility */
127 static void
128 gst_fake_video_sink_proxy_properties (GstFakeVideoSink * self,
129     GstElement * child)
130 {
131   static gsize initialized = 0;
132
133   if (g_once_init_enter (&initialized)) {
134     GObjectClass *object_class;
135     GParamSpec **properties;
136     guint n_properties, i;
137
138     object_class = G_OBJECT_CLASS (GST_FAKE_VIDEO_SINK_GET_CLASS (self));
139     properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (child),
140         &n_properties);
141
142     /**
143      * GstFakeVideoSink:allocation-meta-flags
144      *
145      * Control the behaviour of the sink allocation query handler.
146      *
147      * Since: 1.18
148      */
149     g_object_class_install_property (object_class, PROP_ALLOCATION_META_FLAGS,
150         g_param_spec_flags ("allocation-meta-flags", "Flags",
151             "Flags to control behaviour",
152             GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
153             ALLOCATION_META_DEFAULT_FLAGS,
154             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
155
156
157     for (i = 0; i < n_properties; i++) {
158       guint property_id = i + PROP_LAST;
159
160       if (properties[i]->owner_type != G_OBJECT_TYPE (child) &&
161           properties[i]->owner_type != GST_TYPE_BASE_SINK)
162         continue;
163
164       if (G_IS_PARAM_SPEC_BOOLEAN (properties[i])) {
165         GParamSpecBoolean *prop = G_PARAM_SPEC_BOOLEAN (properties[i]);
166         g_object_class_install_property (object_class, property_id,
167             g_param_spec_boolean (g_param_spec_get_name (properties[i]),
168                 g_param_spec_get_nick (properties[i]),
169                 g_param_spec_get_blurb (properties[i]),
170                 prop->default_value, properties[i]->flags));
171       } else if (G_IS_PARAM_SPEC_INT (properties[i])) {
172         GParamSpecInt *prop = G_PARAM_SPEC_INT (properties[i]);
173         g_object_class_install_property (object_class, property_id,
174             g_param_spec_int (g_param_spec_get_name (properties[i]),
175                 g_param_spec_get_nick (properties[i]),
176                 g_param_spec_get_blurb (properties[i]),
177                 prop->minimum, prop->maximum, prop->default_value,
178                 properties[i]->flags));
179       } else if (G_IS_PARAM_SPEC_UINT (properties[i])) {
180         GParamSpecUInt *prop = G_PARAM_SPEC_UINT (properties[i]);
181         g_object_class_install_property (object_class, property_id,
182             g_param_spec_uint (g_param_spec_get_name (properties[i]),
183                 g_param_spec_get_nick (properties[i]),
184                 g_param_spec_get_blurb (properties[i]),
185                 prop->minimum, prop->maximum, prop->default_value,
186                 properties[i]->flags));
187       } else if (G_IS_PARAM_SPEC_INT64 (properties[i])) {
188         GParamSpecInt64 *prop = G_PARAM_SPEC_INT64 (properties[i]);
189         g_object_class_install_property (object_class, property_id,
190             g_param_spec_int64 (g_param_spec_get_name (properties[i]),
191                 g_param_spec_get_nick (properties[i]),
192                 g_param_spec_get_blurb (properties[i]),
193                 prop->minimum, prop->maximum, prop->default_value,
194                 properties[i]->flags));
195       } else if (G_IS_PARAM_SPEC_UINT64 (properties[i])) {
196         GParamSpecUInt64 *prop = G_PARAM_SPEC_UINT64 (properties[i]);
197         g_object_class_install_property (object_class, property_id,
198             g_param_spec_uint64 (g_param_spec_get_name (properties[i]),
199                 g_param_spec_get_nick (properties[i]),
200                 g_param_spec_get_blurb (properties[i]),
201                 prop->minimum, prop->maximum, prop->default_value,
202                 properties[i]->flags));
203       } else if (G_IS_PARAM_SPEC_ENUM (properties[i])) {
204         GParamSpecEnum *prop = G_PARAM_SPEC_ENUM (properties[i]);
205         g_object_class_install_property (object_class, property_id,
206             g_param_spec_enum (g_param_spec_get_name (properties[i]),
207                 g_param_spec_get_nick (properties[i]),
208                 g_param_spec_get_blurb (properties[i]),
209                 properties[i]->value_type, prop->default_value,
210                 properties[i]->flags));
211       } else if (G_IS_PARAM_SPEC_STRING (properties[i])) {
212         GParamSpecString *prop = G_PARAM_SPEC_STRING (properties[i]);
213         g_object_class_install_property (object_class, property_id,
214             g_param_spec_string (g_param_spec_get_name (properties[i]),
215                 g_param_spec_get_nick (properties[i]),
216                 g_param_spec_get_blurb (properties[i]),
217                 prop->default_value, properties[i]->flags));
218       } else if (G_IS_PARAM_SPEC_BOXED (properties[i])) {
219         g_object_class_install_property (object_class, property_id,
220             g_param_spec_boxed (g_param_spec_get_name (properties[i]),
221                 g_param_spec_get_nick (properties[i]),
222                 g_param_spec_get_blurb (properties[i]),
223                 properties[i]->value_type, properties[i]->flags));
224       }
225     }
226
227     g_free (properties);
228     g_once_init_leave (&initialized, 1);
229   }
230 }
231
232 static void
233 gst_fake_video_sink_init (GstFakeVideoSink * self)
234 {
235   GstElement *child;
236   GstPadTemplate *template = gst_static_pad_template_get (&sink_factory);
237
238   child = gst_element_factory_make ("fakesink", "sink");
239
240   self->allocation_meta_flags = ALLOCATION_META_DEFAULT_FLAGS;
241
242   if (child) {
243     GstPad *sink_pad = gst_element_get_static_pad (child, "sink");
244     GstPad *ghost_pad;
245
246     /* mimic GstVideoSink base class */
247     g_object_set (child, "max-lateness", 5 * GST_MSECOND,
248         "processing-deadline", 15 * GST_MSECOND, "qos", TRUE, "sync", TRUE,
249         NULL);
250
251     gst_bin_add (GST_BIN (self), child);
252
253     ghost_pad = gst_ghost_pad_new_from_template ("sink", sink_pad, template);
254     gst_object_unref (template);
255     gst_element_add_pad (GST_ELEMENT (self), ghost_pad);
256     gst_object_unref (sink_pad);
257
258     gst_pad_set_query_function (ghost_pad, gst_fake_video_sink_query);
259
260     self->child = child;
261
262     gst_fake_video_sink_proxy_properties (self, child);
263   } else {
264     g_warning ("Check your GStreamer installation, "
265         "core element 'fakesink' is missing.");
266   }
267 }
268
269 static void
270 gst_fake_video_sink_get_property (GObject * object, guint property_id,
271     GValue * value, GParamSpec * pspec)
272 {
273   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
274
275   switch (property_id) {
276     case PROP_ALLOCATION_META_FLAGS:
277       GST_OBJECT_LOCK (self);
278       g_value_set_flags (value, self->allocation_meta_flags);
279       GST_OBJECT_UNLOCK (self);
280       break;
281     default:
282       g_object_get_property (G_OBJECT (self->child), pspec->name, value);
283       break;
284   }
285 }
286
287 static void
288 gst_fake_video_sink_set_property (GObject * object, guint property_id,
289     const GValue * value, GParamSpec * pspec)
290 {
291   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
292
293   switch (property_id) {
294     case PROP_ALLOCATION_META_FLAGS:
295       GST_OBJECT_LOCK (self);
296       self->allocation_meta_flags = g_value_get_flags (value);
297       GST_OBJECT_UNLOCK (self);
298       break;
299     default:
300       g_object_set_property (G_OBJECT (self->child), pspec->name, value);
301       break;
302   }
303 }
304
305 static void
306 gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
307 {
308   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
309   GObjectClass *object_class = G_OBJECT_CLASS (klass);
310
311   object_class->get_property = gst_fake_video_sink_get_property;
312   object_class->set_property = gst_fake_video_sink_set_property;
313
314   gst_element_class_add_static_pad_template (element_class, &sink_factory);
315   gst_element_class_set_static_metadata (element_class, "Fake Video Sink",
316       "Video/Sink", "Fake video display that allows zero-copy",
317       "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
318
319   gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
320       0);
321 }