|
1 /* GStreamer |
|
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> |
|
3 * |
|
4 * This library is free software; you can redistribute it and/or |
|
5 * modify it under the terms of the GNU Library General Public |
|
6 * License as published by the Free Software Foundation; either |
|
7 * version 2 of the License, or (at your option) any later version. |
|
8 * |
|
9 * This library is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
12 * Library General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU Library General Public |
|
15 * License along with this library; if not, write to the |
|
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
17 * Boston, MA 02111-1307, USA. |
|
18 */ |
|
19 /** |
|
20 * SECTION:element-mulawdec |
|
21 * |
|
22 * This element decodes mulaw audio. Mulaw coding is also known as G.711. |
|
23 */ |
|
24 |
|
25 #ifdef HAVE_CONFIG_H |
|
26 #include "config.h" |
|
27 #endif |
|
28 #include <gst/gst.h> |
|
29 #include "mulaw-decode.h" |
|
30 #include "mulaw-conversion.h" |
|
31 |
|
32 extern GstStaticPadTemplate mulaw_dec_src_factory; |
|
33 extern GstStaticPadTemplate mulaw_dec_sink_factory; |
|
34 |
|
35 /* Stereo signals and args */ |
|
36 enum |
|
37 { |
|
38 /* FILL ME */ |
|
39 LAST_SIGNAL |
|
40 }; |
|
41 |
|
42 enum |
|
43 { |
|
44 ARG_0 |
|
45 }; |
|
46 |
|
47 static void gst_mulawdec_class_init (GstMuLawDecClass * klass); |
|
48 static void gst_mulawdec_base_init (GstMuLawDecClass * klass); |
|
49 static void gst_mulawdec_init (GstMuLawDec * mulawdec); |
|
50 static GstStateChangeReturn |
|
51 gst_mulawdec_change_state (GstElement * element, GstStateChange transition); |
|
52 |
|
53 static GstFlowReturn gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer); |
|
54 |
|
55 static GstElementClass *parent_class = NULL; |
|
56 |
|
57 static gboolean |
|
58 mulawdec_sink_setcaps (GstPad * pad, GstCaps * caps) |
|
59 { |
|
60 GstMuLawDec *mulawdec; |
|
61 GstStructure *structure; |
|
62 int rate, channels; |
|
63 gboolean ret; |
|
64 GstCaps *outcaps; |
|
65 |
|
66 mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); |
|
67 |
|
68 structure = gst_caps_get_structure (caps, 0); |
|
69 ret = gst_structure_get_int (structure, "rate", &rate); |
|
70 ret = ret && gst_structure_get_int (structure, "channels", &channels); |
|
71 if (!ret) |
|
72 return FALSE; |
|
73 |
|
74 outcaps = gst_caps_new_simple ("audio/x-raw-int", |
|
75 "width", G_TYPE_INT, 16, |
|
76 "depth", G_TYPE_INT, 16, |
|
77 "endianness", G_TYPE_INT, G_BYTE_ORDER, |
|
78 "signed", G_TYPE_BOOLEAN, TRUE, |
|
79 "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, NULL); |
|
80 ret = gst_pad_set_caps (mulawdec->srcpad, outcaps); |
|
81 gst_caps_unref (outcaps); |
|
82 |
|
83 if (ret) { |
|
84 GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels); |
|
85 mulawdec->rate = rate; |
|
86 mulawdec->channels = channels; |
|
87 } |
|
88 return ret; |
|
89 } |
|
90 |
|
91 static GstCaps * |
|
92 mulawdec_getcaps (GstPad * pad) |
|
93 { |
|
94 GstMuLawDec *mulawdec; |
|
95 GstPad *otherpad; |
|
96 GstCaps *othercaps, *result; |
|
97 const GstCaps *templ; |
|
98 gchar *name; |
|
99 gint i; |
|
100 |
|
101 mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); |
|
102 |
|
103 /* figure out the name of the caps we are going to return */ |
|
104 if (pad == mulawdec->srcpad) { |
|
105 name = "audio/x-raw-int"; |
|
106 otherpad = mulawdec->sinkpad; |
|
107 } else { |
|
108 name = "audio/x-mulaw"; |
|
109 otherpad = mulawdec->srcpad; |
|
110 } |
|
111 /* get caps from the peer, this can return NULL when there is no peer */ |
|
112 othercaps = gst_pad_peer_get_caps (otherpad); |
|
113 |
|
114 /* get the template caps to make sure we return something acceptable */ |
|
115 templ = gst_pad_get_pad_template_caps (pad); |
|
116 |
|
117 if (othercaps) { |
|
118 /* there was a peer */ |
|
119 othercaps = gst_caps_make_writable (othercaps); |
|
120 |
|
121 /* go through the caps and remove the fields we don't want */ |
|
122 for (i = 0; i < gst_caps_get_size (othercaps); i++) { |
|
123 GstStructure *structure; |
|
124 |
|
125 structure = gst_caps_get_structure (othercaps, i); |
|
126 |
|
127 /* adjust the name */ |
|
128 gst_structure_set_name (structure, name); |
|
129 |
|
130 if (pad == mulawdec->sinkpad) { |
|
131 /* remove the fields we don't want */ |
|
132 gst_structure_remove_fields (structure, "width", "depth", "endianness", |
|
133 "signed", NULL); |
|
134 } else { |
|
135 /* add fixed fields */ |
|
136 gst_structure_set (structure, "width", G_TYPE_INT, 16, |
|
137 "depth", G_TYPE_INT, 16, |
|
138 "endianness", G_TYPE_INT, G_BYTE_ORDER, |
|
139 "signed", G_TYPE_BOOLEAN, TRUE, NULL); |
|
140 } |
|
141 } |
|
142 /* filter against the allowed caps of the pad to return our result */ |
|
143 result = gst_caps_intersect (othercaps, templ); |
|
144 gst_caps_unref (othercaps); |
|
145 } else { |
|
146 /* there was no peer, return the template caps */ |
|
147 result = gst_caps_copy (templ); |
|
148 } |
|
149 return result; |
|
150 } |
|
151 |
|
152 GType |
|
153 gst_mulawdec_get_type (void) |
|
154 { |
|
155 static GType mulawdec_type = 0; |
|
156 |
|
157 if (!mulawdec_type) { |
|
158 static const GTypeInfo mulawdec_info = { |
|
159 sizeof (GstMuLawDecClass), |
|
160 (GBaseInitFunc) gst_mulawdec_base_init, |
|
161 NULL, |
|
162 (GClassInitFunc) gst_mulawdec_class_init, |
|
163 NULL, |
|
164 NULL, |
|
165 sizeof (GstMuLawDec), |
|
166 0, |
|
167 (GInstanceInitFunc) gst_mulawdec_init, |
|
168 }; |
|
169 |
|
170 mulawdec_type = |
|
171 g_type_register_static (GST_TYPE_ELEMENT, "GstMuLawDec", &mulawdec_info, |
|
172 0); |
|
173 } |
|
174 return mulawdec_type; |
|
175 } |
|
176 |
|
177 static void |
|
178 gst_mulawdec_base_init (GstMuLawDecClass * klass) |
|
179 { |
|
180 GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
|
181 const GstElementDetails mulawdec_details = |
|
182 GST_ELEMENT_DETAILS ("Mu Law audio decoder", |
|
183 "Codec/Decoder/Audio", |
|
184 "Convert 8bit mu law to 16bit PCM", |
|
185 "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); |
|
186 |
|
187 gst_element_class_add_pad_template (element_class, |
|
188 gst_static_pad_template_get (&mulaw_dec_src_factory)); |
|
189 gst_element_class_add_pad_template (element_class, |
|
190 gst_static_pad_template_get (&mulaw_dec_sink_factory)); |
|
191 gst_element_class_set_details (element_class, &mulawdec_details); |
|
192 } |
|
193 |
|
194 static void |
|
195 gst_mulawdec_class_init (GstMuLawDecClass * klass) |
|
196 { |
|
197 GstElementClass *element_class = (GstElementClass *) klass; |
|
198 |
|
199 parent_class = g_type_class_peek_parent (klass); |
|
200 |
|
201 element_class->change_state = GST_DEBUG_FUNCPTR (gst_mulawdec_change_state); |
|
202 } |
|
203 |
|
204 static void |
|
205 gst_mulawdec_init (GstMuLawDec * mulawdec) |
|
206 { |
|
207 mulawdec->sinkpad = |
|
208 gst_pad_new_from_static_template (&mulaw_dec_sink_factory, "sink"); |
|
209 gst_pad_set_setcaps_function (mulawdec->sinkpad, mulawdec_sink_setcaps); |
|
210 gst_pad_set_getcaps_function (mulawdec->sinkpad, mulawdec_getcaps); |
|
211 gst_pad_set_chain_function (mulawdec->sinkpad, gst_mulawdec_chain); |
|
212 gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->sinkpad); |
|
213 |
|
214 mulawdec->srcpad = |
|
215 gst_pad_new_from_static_template (&mulaw_dec_src_factory, "src"); |
|
216 gst_pad_use_fixed_caps (mulawdec->srcpad); |
|
217 gst_pad_set_getcaps_function (mulawdec->srcpad, mulawdec_getcaps); |
|
218 gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->srcpad); |
|
219 } |
|
220 |
|
221 static GstFlowReturn |
|
222 gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer) |
|
223 { |
|
224 GstMuLawDec *mulawdec; |
|
225 gint16 *linear_data; |
|
226 guint8 *mulaw_data; |
|
227 guint mulaw_size; |
|
228 GstBuffer *outbuf; |
|
229 GstFlowReturn ret; |
|
230 |
|
231 mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); |
|
232 |
|
233 if (G_UNLIKELY (mulawdec->rate == 0)) |
|
234 goto not_negotiated; |
|
235 |
|
236 mulaw_data = (guint8 *) GST_BUFFER_DATA (buffer); |
|
237 mulaw_size = GST_BUFFER_SIZE (buffer); |
|
238 |
|
239 ret = |
|
240 gst_pad_alloc_buffer_and_set_caps (mulawdec->srcpad, |
|
241 GST_BUFFER_OFFSET_NONE, mulaw_size * 2, GST_PAD_CAPS (mulawdec->srcpad), |
|
242 &outbuf); |
|
243 if (ret != GST_FLOW_OK) |
|
244 goto alloc_failed; |
|
245 |
|
246 linear_data = (gint16 *) GST_BUFFER_DATA (outbuf); |
|
247 |
|
248 /* copy discont flag */ |
|
249 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) |
|
250 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); |
|
251 |
|
252 GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); |
|
253 if (GST_BUFFER_DURATION (outbuf) == GST_CLOCK_TIME_NONE) |
|
254 GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND, |
|
255 mulaw_size * 2, 2 * mulawdec->rate * mulawdec->channels); |
|
256 else |
|
257 GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer); |
|
258 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawdec->srcpad)); |
|
259 |
|
260 mulaw_decode (mulaw_data, linear_data, mulaw_size); |
|
261 |
|
262 gst_buffer_unref (buffer); |
|
263 |
|
264 ret = gst_pad_push (mulawdec->srcpad, outbuf); |
|
265 |
|
266 return ret; |
|
267 |
|
268 /* ERRORS */ |
|
269 not_negotiated: |
|
270 { |
|
271 GST_WARNING_OBJECT (mulawdec, "no input format set: not-negotiated"); |
|
272 gst_buffer_unref (buffer); |
|
273 return GST_FLOW_NOT_NEGOTIATED; |
|
274 } |
|
275 alloc_failed: |
|
276 { |
|
277 GST_DEBUG_OBJECT (mulawdec, "pad alloc failed, flow: %s", |
|
278 gst_flow_get_name (ret)); |
|
279 gst_buffer_unref (buffer); |
|
280 return ret; |
|
281 } |
|
282 } |
|
283 |
|
284 static GstStateChangeReturn |
|
285 gst_mulawdec_change_state (GstElement * element, GstStateChange transition) |
|
286 { |
|
287 GstStateChangeReturn ret; |
|
288 GstMuLawDec *dec = GST_MULAWDEC (element); |
|
289 |
|
290 switch (transition) { |
|
291 default: |
|
292 break; |
|
293 } |
|
294 |
|
295 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); |
|
296 if (ret != GST_STATE_CHANGE_SUCCESS) |
|
297 return ret; |
|
298 |
|
299 switch (transition) { |
|
300 case GST_STATE_CHANGE_PAUSED_TO_READY: |
|
301 dec->rate = 0; |
|
302 dec->channels = 0; |
|
303 break; |
|
304 default: |
|
305 break; |
|
306 } |
|
307 |
|
308 return ret; |
|
309 } |