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 "gsterrorignore.h"
42
43 #define GST_CAT_DEFAULT gst_error_ignore_debug
44 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
45
46 enum
47 {
48 PROP_0,
49 PROP_IGNORE_ERROR,
50 PROP_IGNORE_NOTLINKED,
51 PROP_IGNORE_NOTNEGOTIATED,
52 PROP_CONVERT_TO
53 };
54
55 static void gst_error_ignore_set_property (GObject * object, guint prop_id,
56 const GValue * value, GParamSpec * pspec);
57 static void gst_error_ignore_get_property (GObject * object, guint prop_id,
58 GValue * value, GParamSpec * pspec);
59
60 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
61 GST_PAD_SINK,
62 GST_PAD_ALWAYS,
63 GST_STATIC_CAPS_ANY);
64
65 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
66 GST_PAD_SRC,
67 GST_PAD_ALWAYS,
68 GST_STATIC_CAPS_ANY);
69
70 #define parent_class gst_error_ignore_parent_class
71 G_DEFINE_TYPE (GstErrorIgnore, gst_error_ignore, GST_TYPE_ELEMENT);
72
73 static GstFlowReturn gst_error_ignore_sink_chain (GstPad * pad,
74 GstObject * parent, GstBuffer * inbuf);
75 static gboolean gst_error_ignore_sink_event (GstPad * pad, GstObject * parent,
76 GstEvent * event);
77 static GstStateChangeReturn gst_error_ignore_change_state (GstElement * element,
78 GstStateChange transition);
79
80 static void
gst_error_ignore_class_init(GstErrorIgnoreClass * klass)81 gst_error_ignore_class_init (GstErrorIgnoreClass * klass)
82 {
83 GstElementClass *gstelement_class;
84 GObjectClass *object_class = G_OBJECT_CLASS (klass);
85
86 GST_DEBUG_CATEGORY_INIT (gst_error_ignore_debug, "errorignore", 0,
87 "Convert some GstFlowReturn types into others");
88
89 gstelement_class = (GstElementClass *) klass;
90
91 gst_element_class_set_static_metadata (gstelement_class,
92 "Convert some GstFlowReturn types into others", "Generic",
93 "Pass through all packets but ignore some GstFlowReturn types",
94 "Vivia Nikolaidou <vivia@toolsonair.com>");
95
96 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
97 gst_element_class_add_static_pad_template (gstelement_class, &sink_template);
98
99 gstelement_class->change_state = gst_error_ignore_change_state;
100
101 /* define virtual function pointers */
102 object_class->set_property = gst_error_ignore_set_property;
103 object_class->get_property = gst_error_ignore_get_property;
104
105 /* define properties */
106 g_object_class_install_property (object_class, PROP_IGNORE_ERROR,
107 g_param_spec_boolean ("ignore-error", "Ignore GST_FLOW_ERROR",
108 "Whether to ignore GST_FLOW_ERROR",
109 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110
111 g_object_class_install_property (object_class, PROP_IGNORE_NOTLINKED,
112 g_param_spec_boolean ("ignore-notlinked", "Ignore GST_FLOW_NOT_LINKED",
113 "Whether to ignore GST_FLOW_NOT_LINKED",
114 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
115
116 g_object_class_install_property (object_class, PROP_IGNORE_NOTNEGOTIATED,
117 g_param_spec_boolean ("ignore-notnegotiated",
118 "Ignore GST_FLOW_NOT_NEGOTIATED",
119 "Whether to ignore GST_FLOW_NOT_NEGOTIATED",
120 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
121
122 g_object_class_install_property (object_class, PROP_CONVERT_TO,
123 g_param_spec_enum ("convert-to", "GstFlowReturn to convert to",
124 "Which GstFlowReturn value we should convert to when ignoring",
125 GST_TYPE_FLOW_RETURN,
126 GST_FLOW_NOT_LINKED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127 }
128
129 static void
gst_error_ignore_init(GstErrorIgnore * self)130 gst_error_ignore_init (GstErrorIgnore * self)
131 {
132 self->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
133 gst_pad_set_chain_function (self->sinkpad,
134 GST_DEBUG_FUNCPTR (gst_error_ignore_sink_chain));
135 gst_pad_set_event_function (self->sinkpad,
136 GST_DEBUG_FUNCPTR (gst_error_ignore_sink_event));
137 GST_PAD_SET_PROXY_ALLOCATION (self->sinkpad);
138 GST_PAD_SET_PROXY_CAPS (self->sinkpad);
139 GST_PAD_SET_PROXY_SCHEDULING (self->sinkpad);
140 gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
141
142 self->srcpad = gst_pad_new_from_static_template (&src_template, "src");
143 gst_pad_use_fixed_caps (self->srcpad);
144 GST_PAD_SET_PROXY_ALLOCATION (self->srcpad);
145 GST_PAD_SET_PROXY_CAPS (self->srcpad);
146 GST_PAD_SET_PROXY_SCHEDULING (self->srcpad);
147 gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
148
149 self->keep_pushing = TRUE;
150 self->ignore_error = TRUE;
151 self->ignore_notlinked = FALSE;
152 self->ignore_notnegotiated = TRUE;
153 self->convert_to = GST_FLOW_NOT_LINKED;
154 }
155
156 static void
gst_error_ignore_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)157 gst_error_ignore_set_property (GObject * object, guint prop_id,
158 const GValue * value, GParamSpec * pspec)
159 {
160 GstErrorIgnore *self = GST_ERROR_IGNORE (object);
161
162 switch (prop_id) {
163 case PROP_IGNORE_ERROR:
164 self->ignore_error = g_value_get_boolean (value);
165 break;
166 case PROP_IGNORE_NOTLINKED:
167 self->ignore_notlinked = g_value_get_boolean (value);
168 break;
169 case PROP_IGNORE_NOTNEGOTIATED:
170 self->ignore_notnegotiated = g_value_get_boolean (value);
171 break;
172 case PROP_CONVERT_TO:
173 self->convert_to = g_value_get_enum (value);
174 break;
175 default:
176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
177 break;
178 }
179 }
180
181 static void
gst_error_ignore_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)182 gst_error_ignore_get_property (GObject * object, guint prop_id, GValue * value,
183 GParamSpec * pspec)
184 {
185 GstErrorIgnore *self = GST_ERROR_IGNORE (object);
186
187 switch (prop_id) {
188 case PROP_IGNORE_ERROR:
189 g_value_set_boolean (value, self->ignore_error);
190 break;
191 case PROP_IGNORE_NOTLINKED:
192 g_value_set_boolean (value, self->ignore_notlinked);
193 break;
194 case PROP_IGNORE_NOTNEGOTIATED:
195 g_value_set_boolean (value, self->ignore_notnegotiated);
196 break;
197 case PROP_CONVERT_TO:
198 g_value_set_enum (value, self->convert_to);
199 break;
200 default:
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202 break;
203 }
204 }
205
206 static gboolean
gst_error_ignore_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)207 gst_error_ignore_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
208 {
209 GstErrorIgnore *self = GST_ERROR_IGNORE (parent);
210 gboolean ret;
211
212 GST_LOG_OBJECT (pad, "Got %s event", GST_EVENT_TYPE_NAME (event));
213
214 switch (GST_EVENT_TYPE (event)) {
215 case GST_EVENT_FLUSH_STOP:
216 self->keep_pushing = TRUE;
217 /* fall through */
218 default:
219 ret = gst_pad_event_default (pad, parent, event);
220 break;
221 }
222
223 return ret;
224 }
225
226 static GstFlowReturn
gst_error_ignore_sink_chain(GstPad * pad,GstObject * parent,GstBuffer * inbuf)227 gst_error_ignore_sink_chain (GstPad * pad, GstObject * parent,
228 GstBuffer * inbuf)
229 {
230 GstErrorIgnore *self = GST_ERROR_IGNORE (parent);
231 GstFlowReturn ret = GST_FLOW_OK;
232
233 if (gst_pad_check_reconfigure (pad))
234 self->keep_pushing = TRUE;
235
236 if (self->keep_pushing) {
237 ret = gst_pad_push (self->srcpad, inbuf);
238 self->keep_pushing = (ret == GST_FLOW_OK);
239 } else {
240 gst_buffer_unref (inbuf);
241 }
242
243 if ((ret == GST_FLOW_ERROR && self->ignore_error) ||
244 (ret == GST_FLOW_NOT_LINKED && self->ignore_notlinked) ||
245 (ret == GST_FLOW_NOT_NEGOTIATED && self->ignore_notnegotiated))
246 return self->convert_to;
247 else
248 return ret;
249 }
250
251 static GstStateChangeReturn
gst_error_ignore_change_state(GstElement * element,GstStateChange transition)252 gst_error_ignore_change_state (GstElement * element, GstStateChange transition)
253 {
254 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
255 GstErrorIgnore *self = GST_ERROR_IGNORE (element);
256
257 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
258 if (ret == GST_STATE_CHANGE_FAILURE)
259 return ret;
260
261 switch (transition) {
262 case GST_STATE_CHANGE_READY_TO_PAUSED:
263 self->keep_pushing = TRUE;
264 break;
265 default:
266 break;
267 }
268
269 return ret;
270 }
271