• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Vivia Nikolaidou <vivia@toolsonair.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:element-errorignore
23  * @title: errorignore
24  *
25  * Passes through all packets, until it encounters GST_FLOW_ERROR or
26  * GST_FLOW_NOT_NEGOTIATED (configurable). At that point it will unref the
27  * buffers and return GST_FLOW_OK (configurable) - until the next
28  * READY_TO_PAUSED, RECONFIGURE or FLUSH_STOP.
29  *
30  * ## Example launch line
31  * |[
32  * gst-launch-1.0 videotestsrc ! errorignore ! autovideosink
33  * ]|
34  *
35  */
36 
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40 
41 #include "gstdebugutilsbadelements.h"
42 #include "gsterrorignore.h"
43 
44 #define GST_CAT_DEFAULT gst_error_ignore_debug
45 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
46 
47 enum
48 {
49   PROP_0,
50   PROP_IGNORE_ERROR,
51   PROP_IGNORE_NOTLINKED,
52   PROP_IGNORE_NOTNEGOTIATED,
53   PROP_IGNORE_EOS,
54   PROP_CONVERT_TO
55 };
56 
57 static void gst_error_ignore_set_property (GObject * object, guint prop_id,
58     const GValue * value, GParamSpec * pspec);
59 static void gst_error_ignore_get_property (GObject * object, guint prop_id,
60     GValue * value, GParamSpec * pspec);
61 
62 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
63     GST_PAD_SINK,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS_ANY);
66 
67 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
68     GST_PAD_SRC,
69     GST_PAD_ALWAYS,
70     GST_STATIC_CAPS_ANY);
71 
72 #define parent_class gst_error_ignore_parent_class
73 G_DEFINE_TYPE (GstErrorIgnore, gst_error_ignore, GST_TYPE_ELEMENT);
74 GST_ELEMENT_REGISTER_DEFINE (errorignore, "errorignore",
75     GST_RANK_NONE, gst_error_ignore_get_type ());
76 
77 static GstFlowReturn gst_error_ignore_sink_chain (GstPad * pad,
78     GstObject * parent, GstBuffer * inbuf);
79 static gboolean gst_error_ignore_sink_event (GstPad * pad, GstObject * parent,
80     GstEvent * event);
81 static GstStateChangeReturn gst_error_ignore_change_state (GstElement * element,
82     GstStateChange transition);
83 
84 static void
gst_error_ignore_class_init(GstErrorIgnoreClass * klass)85 gst_error_ignore_class_init (GstErrorIgnoreClass * klass)
86 {
87   GstElementClass *gstelement_class;
88   GObjectClass *object_class = G_OBJECT_CLASS (klass);
89 
90   GST_DEBUG_CATEGORY_INIT (gst_error_ignore_debug, "errorignore", 0,
91       "Convert some GstFlowReturn types into others");
92 
93   gstelement_class = (GstElementClass *) klass;
94 
95   gst_element_class_set_static_metadata (gstelement_class,
96       "Convert some GstFlowReturn types into others", "Generic",
97       "Pass through all packets but ignore some GstFlowReturn types",
98       "Vivia Nikolaidou <vivia@toolsonair.com>");
99 
100   gst_element_class_add_static_pad_template (gstelement_class, &src_template);
101   gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
102 
103   gstelement_class->change_state = gst_error_ignore_change_state;
104 
105   /* define virtual function pointers */
106   object_class->set_property = gst_error_ignore_set_property;
107   object_class->get_property = gst_error_ignore_get_property;
108 
109   /* define properties */
110   g_object_class_install_property (object_class, PROP_IGNORE_ERROR,
111       g_param_spec_boolean ("ignore-error", "Ignore GST_FLOW_ERROR",
112           "Whether to ignore GST_FLOW_ERROR",
113           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114 
115   g_object_class_install_property (object_class, PROP_IGNORE_NOTLINKED,
116       g_param_spec_boolean ("ignore-notlinked", "Ignore GST_FLOW_NOT_LINKED",
117           "Whether to ignore GST_FLOW_NOT_LINKED",
118           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
119 
120   g_object_class_install_property (object_class, PROP_IGNORE_NOTNEGOTIATED,
121       g_param_spec_boolean ("ignore-notnegotiated",
122           "Ignore GST_FLOW_NOT_NEGOTIATED",
123           "Whether to ignore GST_FLOW_NOT_NEGOTIATED",
124           TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125 
126   /**
127    * GstErrorIgnore:ignore-eos:
128    *
129    * Since: 1.20
130    */
131   g_object_class_install_property (object_class, PROP_IGNORE_EOS,
132       g_param_spec_boolean ("ignore-eos",
133           "Ignore GST_FLOW_EOS", "Whether to ignore GST_FLOW_EOS",
134           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
135 
136   g_object_class_install_property (object_class, PROP_CONVERT_TO,
137       g_param_spec_enum ("convert-to", "GstFlowReturn to convert to",
138           "Which GstFlowReturn value we should convert to when ignoring",
139           GST_TYPE_FLOW_RETURN,
140           GST_FLOW_NOT_LINKED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
141 }
142 
143 static void
gst_error_ignore_init(GstErrorIgnore * self)144 gst_error_ignore_init (GstErrorIgnore * self)
145 {
146   self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
147   gst_pad_set_chain_function (self->sinkpad,
148       GST_DEBUG_FUNCPTR (gst_error_ignore_sink_chain));
149   gst_pad_set_event_function (self->sinkpad,
150       GST_DEBUG_FUNCPTR (gst_error_ignore_sink_event));
151   GST_PAD_SET_PROXY_ALLOCATION (self->sinkpad);
152   GST_PAD_SET_PROXY_CAPS (self->sinkpad);
153   GST_PAD_SET_PROXY_SCHEDULING (self->sinkpad);
154   gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
155 
156   self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
157   gst_pad_use_fixed_caps (self->srcpad);
158   GST_PAD_SET_PROXY_ALLOCATION (self->srcpad);
159   GST_PAD_SET_PROXY_CAPS (self->srcpad);
160   GST_PAD_SET_PROXY_SCHEDULING (self->srcpad);
161   gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
162 
163   self->keep_pushing = TRUE;
164   self->ignore_error = TRUE;
165   self->ignore_notlinked = FALSE;
166   self->ignore_notnegotiated = TRUE;
167   self->ignore_eos = FALSE;
168   self->convert_to = GST_FLOW_NOT_LINKED;
169 }
170 
171 static void
gst_error_ignore_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)172 gst_error_ignore_set_property (GObject * object, guint prop_id,
173     const GValue * value, GParamSpec * pspec)
174 {
175   GstErrorIgnore *self = GST_ERROR_IGNORE (object);
176 
177   switch (prop_id) {
178     case PROP_IGNORE_ERROR:
179       self->ignore_error = g_value_get_boolean (value);
180       break;
181     case PROP_IGNORE_NOTLINKED:
182       self->ignore_notlinked = g_value_get_boolean (value);
183       break;
184     case PROP_IGNORE_NOTNEGOTIATED:
185       self->ignore_notnegotiated = g_value_get_boolean (value);
186       break;
187     case PROP_IGNORE_EOS:
188       self->ignore_eos = g_value_get_boolean (value);
189       break;
190     case PROP_CONVERT_TO:
191       self->convert_to = g_value_get_enum (value);
192       break;
193     default:
194       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195       break;
196   }
197 }
198 
199 static void
gst_error_ignore_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)200 gst_error_ignore_get_property (GObject * object, guint prop_id, GValue * value,
201     GParamSpec * pspec)
202 {
203   GstErrorIgnore *self = GST_ERROR_IGNORE (object);
204 
205   switch (prop_id) {
206     case PROP_IGNORE_ERROR:
207       g_value_set_boolean (value, self->ignore_error);
208       break;
209     case PROP_IGNORE_NOTLINKED:
210       g_value_set_boolean (value, self->ignore_notlinked);
211       break;
212     case PROP_IGNORE_NOTNEGOTIATED:
213       g_value_set_boolean (value, self->ignore_notnegotiated);
214       break;
215     case PROP_IGNORE_EOS:
216       g_value_set_boolean (value, self->ignore_eos);
217       break;
218     case PROP_CONVERT_TO:
219       g_value_set_enum (value, self->convert_to);
220       break;
221     default:
222       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
223       break;
224   }
225 }
226 
227 static gboolean
gst_error_ignore_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)228 gst_error_ignore_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
229 {
230   GstErrorIgnore *self = GST_ERROR_IGNORE (parent);
231   gboolean ret;
232 
233   GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
234 
235   switch (GST_EVENT_TYPE (event)) {
236     case GST_EVENT_CAPS:
237     case GST_EVENT_FLUSH_STOP:
238       self->keep_pushing = TRUE;
239       /* fall through */
240     default:
241       ret = gst_pad_event_default (pad, parent, event);
242       break;
243   }
244 
245   return ret;
246 }
247 
248 static GstFlowReturn
gst_error_ignore_sink_chain(GstPad * pad,GstObject * parent,GstBuffer * inbuf)249 gst_error_ignore_sink_chain (GstPad * pad, GstObject * parent,
250     GstBuffer * inbuf)
251 {
252   GstErrorIgnore *self = GST_ERROR_IGNORE (parent);
253   GstFlowReturn ret = GST_FLOW_OK;
254 
255   if (gst_pad_check_reconfigure (pad))
256     self->keep_pushing = TRUE;
257 
258   if (self->keep_pushing) {
259     ret = gst_pad_push (self->srcpad, inbuf);
260     self->keep_pushing = (ret == GST_FLOW_OK);
261   } else {
262     gst_buffer_unref (inbuf);
263   }
264 
265   if ((ret == GST_FLOW_ERROR && self->ignore_error) ||
266       (ret == GST_FLOW_NOT_LINKED && self->ignore_notlinked) ||
267       (ret == GST_FLOW_EOS && self->ignore_eos) ||
268       (ret == GST_FLOW_NOT_NEGOTIATED && self->ignore_notnegotiated))
269     return self->convert_to;
270   else
271     return ret;
272 }
273 
274 static GstStateChangeReturn
gst_error_ignore_change_state(GstElement * element,GstStateChange transition)275 gst_error_ignore_change_state (GstElement * element, GstStateChange transition)
276 {
277   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
278   GstErrorIgnore *self = GST_ERROR_IGNORE (element);
279 
280   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
281   if (ret == GST_STATE_CHANGE_FAILURE)
282     return ret;
283 
284   switch (transition) {
285     case GST_STATE_CHANGE_READY_TO_PAUSED:
286       self->keep_pushing = TRUE;
287       break;
288     default:
289       break;
290   }
291 
292   return ret;
293 }
294