3 * Copyright (C) 2017 Collabora Inc.
4 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
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.
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.
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.
23 * SECTION:element-fakevideosink
24 * @title: fakevideosink
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.
31 * ## Example launch lines
33 * gst-launch-1.0 videotestsrc ! fakevideosink
34 * gst-launch-1.0 videotestsrc ! fpsdisplaysink text-overlay=false video-sink=fakevideosink
40 #include "gstfakevideosink.h"
42 #include <gst/video/video.h>
44 #define C_FLAGS(v) ((guint) v)
47 gst_fake_video_sink_allocation_meta_flags_get_type (void)
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"},
59 if (g_once_init_enter ((gsize *) & id)) {
63 g_flags_register_static ("GstFakeVideoSinkAllocationMetaFlags", values);
65 g_once_init_leave ((gsize *) & id, _id);
74 PROP_ALLOCATION_META_FLAGS,
78 #define ALLOCATION_META_DEFAULT_FLAGS GST_ALLOCATION_FLAG_CROP_META | GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META
80 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
83 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY",
84 GST_VIDEO_FORMATS_ALL)));
86 G_DEFINE_TYPE (GstFakeVideoSink, gst_fake_video_sink, GST_TYPE_BIN);
89 gst_fake_video_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
91 GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (parent);
94 guint min_buffers = 1;
96 if (GST_QUERY_TYPE (query) != GST_QUERY_ALLOCATION)
97 return gst_pad_query_default (pad, parent, query);
99 gst_query_parse_allocation (query, &caps, NULL);
100 if (!gst_video_info_from_caps (&info, caps))
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)))
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);
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);
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);
119 GST_OBJECT_UNLOCK (self);
121 /* add here any meta API that would help support zero-copy */
126 /* TODO complete the types and make this an utility */
128 gst_fake_video_sink_proxy_properties (GstFakeVideoSink * self,
131 static gsize initialized = 0;
133 if (g_once_init_enter (&initialized)) {
134 GObjectClass *object_class;
135 GParamSpec **properties;
136 guint n_properties, i;
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),
143 * GstFakeVideoSink:allocation-meta-flags
145 * Control the behaviour of the sink allocation query handler.
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));
157 for (i = 0; i < n_properties; i++) {
158 guint property_id = i + PROP_LAST;
160 if (properties[i]->owner_type != G_OBJECT_TYPE (child) &&
161 properties[i]->owner_type != GST_TYPE_BASE_SINK)
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));
228 g_once_init_leave (&initialized, 1);
233 gst_fake_video_sink_init (GstFakeVideoSink * self)
236 GstPadTemplate *template = gst_static_pad_template_get (&sink_factory);
238 child = gst_element_factory_make ("fakesink", "sink");
240 self->allocation_meta_flags = ALLOCATION_META_DEFAULT_FLAGS;
243 GstPad *sink_pad = gst_element_get_static_pad (child, "sink");
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,
251 gst_bin_add (GST_BIN (self), child);
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);
258 gst_pad_set_query_function (ghost_pad, gst_fake_video_sink_query);
262 gst_fake_video_sink_proxy_properties (self, child);
264 g_warning ("Check your GStreamer installation, "
265 "core element 'fakesink' is missing.");
270 gst_fake_video_sink_get_property (GObject * object, guint property_id,
271 GValue * value, GParamSpec * pspec)
273 GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
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);
282 g_object_get_property (G_OBJECT (self->child), pspec->name, value);
288 gst_fake_video_sink_set_property (GObject * object, guint property_id,
289 const GValue * value, GParamSpec * pspec)
291 GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
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);
300 g_object_set_property (G_OBJECT (self->child), pspec->name, value);
306 gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
308 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
309 GObjectClass *object_class = G_OBJECT_CLASS (klass);
311 object_class->get_property = gst_fake_video_sink_get_property;
312 object_class->set_property = gst_fake_video_sink_set_property;
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>");
319 gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,