• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gstdebugutilsbadelements.h"
41 #include "gstfakevideosink.h"
42 #include "gstfakesinkutils.h"
43 
44 #include <gst/video/video.h>
45 
46 #define C_FLAGS(v) ((guint) v)
47 
48 GType
gst_fake_video_sink_allocation_meta_flags_get_type(void)49 gst_fake_video_sink_allocation_meta_flags_get_type (void)
50 {
51   static const GFlagsValue values[] = {
52     {C_FLAGS (GST_ALLOCATION_FLAG_CROP_META),
53         "Expose the crop meta as supported", "crop"},
54     {C_FLAGS (GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META),
55           "Expose the overlay composition meta as supported",
56         "overlay-composition"},
57     {0, NULL, NULL}
58   };
59   static GType id = 0;
60 
61   if (g_once_init_enter ((gsize *) & id)) {
62     GType _id;
63 
64     _id =
65         g_flags_register_static ("GstFakeVideoSinkAllocationMetaFlags", values);
66 
67     g_once_init_leave ((gsize *) & id, _id);
68   }
69 
70   return id;
71 }
72 
73 enum
74 {
75   PROP_0,
76   PROP_ALLOCATION_META_FLAGS,
77   PROP_LAST
78 };
79 
80 #define ALLOCATION_META_DEFAULT_FLAGS GST_ALLOCATION_FLAG_CROP_META | GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META
81 
82 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
83     GST_PAD_SINK,
84     GST_PAD_ALWAYS,
85     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES ("ANY",
86             GST_VIDEO_FORMATS_ALL)));
87 
88 G_DEFINE_TYPE (GstFakeVideoSink, gst_fake_video_sink, GST_TYPE_BIN);
89 GST_ELEMENT_REGISTER_DEFINE (fakevideosink, "fakevideosink",
90     GST_RANK_NONE, gst_fake_video_sink_get_type ());
91 
92 static gboolean
gst_fake_video_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)93 gst_fake_video_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
94 {
95   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (parent);
96   GstCaps *caps;
97   GstVideoInfo info;
98   guint min_buffers = 1;
99 
100   if (GST_QUERY_TYPE (query) != GST_QUERY_ALLOCATION)
101     return gst_pad_query_default (pad, parent, query);
102 
103   gst_query_parse_allocation (query, &caps, NULL);
104   if (!gst_video_info_from_caps (&info, caps))
105     return FALSE;
106 
107   /* Request an extra buffer if we are keeping a ref on the last rendered buffer */
108   if (gst_base_sink_is_last_sample_enabled (GST_BASE_SINK (self->child)))
109     min_buffers++;
110 
111   gst_query_add_allocation_pool (query, NULL, info.size, min_buffers, 0);
112   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
113 
114   GST_OBJECT_LOCK (self);
115   if (self->allocation_meta_flags & GST_ALLOCATION_FLAG_CROP_META)
116     gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
117 
118   if (self->allocation_meta_flags &
119       GST_ALLOCATION_FLAG_OVERLAY_COMPOSITION_META)
120     gst_query_add_allocation_meta (query,
121         GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
122 
123   GST_OBJECT_UNLOCK (self);
124 
125   /* add here any meta API that would help support zero-copy */
126 
127   return TRUE;
128 }
129 
130 static void
gst_fake_video_sink_proxy_properties(GstFakeVideoSink * self,GstElement * child)131 gst_fake_video_sink_proxy_properties (GstFakeVideoSink * self,
132     GstElement * child)
133 {
134   static gsize initialized = 0;
135 
136   if (g_once_init_enter (&initialized)) {
137     gst_fake_sink_proxy_properties (GST_ELEMENT_CAST (self), child, PROP_LAST);
138     g_once_init_leave (&initialized, 1);
139   }
140 }
141 
142 static void
gst_fake_video_sink_init(GstFakeVideoSink * self)143 gst_fake_video_sink_init (GstFakeVideoSink * self)
144 {
145   GstElement *child;
146   GstPadTemplate *template = gst_static_pad_template_get (&sink_factory);
147 
148   child = gst_element_factory_make ("fakesink", "sink");
149 
150   self->allocation_meta_flags = ALLOCATION_META_DEFAULT_FLAGS;
151 
152   if (child) {
153     GstPad *sink_pad = gst_element_get_static_pad (child, "sink");
154     GstPad *ghost_pad;
155 
156     /* mimic GstVideoSink base class */
157     g_object_set (child, "max-lateness", 5 * GST_MSECOND,
158         "processing-deadline", 15 * GST_MSECOND, "qos", TRUE, "sync", TRUE,
159         NULL);
160 
161     gst_bin_add (GST_BIN (self), child);
162 
163     ghost_pad = gst_ghost_pad_new_from_template ("sink", sink_pad, template);
164     gst_object_unref (template);
165     gst_element_add_pad (GST_ELEMENT (self), ghost_pad);
166     gst_object_unref (sink_pad);
167 
168     gst_pad_set_query_function (ghost_pad, gst_fake_video_sink_query);
169 
170     self->child = child;
171 
172     gst_fake_video_sink_proxy_properties (self, child);
173   } else {
174     g_warning ("Check your GStreamer installation, "
175         "core element 'fakesink' is missing.");
176   }
177 }
178 
179 static void
gst_fake_video_sink_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)180 gst_fake_video_sink_get_property (GObject * object, guint property_id,
181     GValue * value, GParamSpec * pspec)
182 {
183   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
184 
185   switch (property_id) {
186     case PROP_ALLOCATION_META_FLAGS:
187       GST_OBJECT_LOCK (self);
188       g_value_set_flags (value, self->allocation_meta_flags);
189       GST_OBJECT_UNLOCK (self);
190       break;
191     default:
192       g_object_get_property (G_OBJECT (self->child), pspec->name, value);
193       break;
194   }
195 }
196 
197 static void
gst_fake_video_sink_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)198 gst_fake_video_sink_set_property (GObject * object, guint property_id,
199     const GValue * value, GParamSpec * pspec)
200 {
201   GstFakeVideoSink *self = GST_FAKE_VIDEO_SINK (object);
202 
203   switch (property_id) {
204     case PROP_ALLOCATION_META_FLAGS:
205       GST_OBJECT_LOCK (self);
206       self->allocation_meta_flags = g_value_get_flags (value);
207       GST_OBJECT_UNLOCK (self);
208       break;
209     default:
210       g_object_set_property (G_OBJECT (self->child), pspec->name, value);
211       break;
212   }
213 }
214 
215 static void
gst_fake_video_sink_class_init(GstFakeVideoSinkClass * klass)216 gst_fake_video_sink_class_init (GstFakeVideoSinkClass * klass)
217 {
218   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
219   GObjectClass *object_class = G_OBJECT_CLASS (klass);
220 
221   object_class->get_property = gst_fake_video_sink_get_property;
222   object_class->set_property = gst_fake_video_sink_set_property;
223 
224   gst_element_class_add_static_pad_template (element_class, &sink_factory);
225   gst_element_class_set_static_metadata (element_class, "Fake Video Sink",
226       "Video/Sink", "Fake video display that allows zero-copy",
227       "Nicolas Dufresne <nicolas.dufresne@collabora.com>");
228 
229   /**
230    * GstFakeVideoSink:allocation-meta-flags
231    *
232    * Control the behaviour of the sink allocation query handler.
233    *
234    * Since: 1.18
235    */
236   g_object_class_install_property (object_class, PROP_ALLOCATION_META_FLAGS,
237       g_param_spec_flags ("allocation-meta-flags", "Flags",
238           "Flags to control behaviour",
239           GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
240           ALLOCATION_META_DEFAULT_FLAGS,
241           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
242 
243   gst_type_mark_as_plugin_api (GST_TYPE_FAKE_VIDEO_SINK_ALLOCATION_META_FLAGS,
244       0);
245 }
246