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