|
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-mulawenc |
|
21 * |
|
22 * This element encode 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-encode.h" |
|
30 #include "mulaw-conversion.h" |
|
31 |
|
32 extern GstStaticPadTemplate mulaw_enc_src_factory; |
|
33 extern GstStaticPadTemplate mulaw_enc_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_mulawenc_class_init (GstMuLawEncClass * klass); |
|
48 static void gst_mulawenc_base_init (GstMuLawEncClass * klass); |
|
49 static void gst_mulawenc_init (GstMuLawEnc * mulawenc); |
|
50 |
|
51 static GstFlowReturn gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer); |
|
52 |
|
53 static GstElementClass *parent_class = NULL; |
|
54 |
|
55 /*static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; */ |
|
56 |
|
57 static GstCaps * |
|
58 mulawenc_getcaps (GstPad * pad) |
|
59 { |
|
60 GstMuLawEnc *mulawenc; |
|
61 GstPad *otherpad; |
|
62 GstCaps *othercaps, *result; |
|
63 const GstCaps *templ; |
|
64 gchar *name; |
|
65 gint i; |
|
66 |
|
67 mulawenc = GST_MULAWENC (GST_PAD_PARENT (pad)); |
|
68 |
|
69 /* figure out the name of the caps we are going to return */ |
|
70 if (pad == mulawenc->srcpad) { |
|
71 name = "audio/x-mulaw"; |
|
72 otherpad = mulawenc->sinkpad; |
|
73 } else { |
|
74 name = "audio/x-raw-int"; |
|
75 otherpad = mulawenc->srcpad; |
|
76 } |
|
77 /* get caps from the peer, this can return NULL when there is no peer */ |
|
78 othercaps = gst_pad_peer_get_caps (otherpad); |
|
79 |
|
80 /* get the template caps to make sure we return something acceptable */ |
|
81 templ = gst_pad_get_pad_template_caps (pad); |
|
82 |
|
83 if (othercaps) { |
|
84 /* there was a peer */ |
|
85 othercaps = gst_caps_make_writable (othercaps); |
|
86 |
|
87 /* go through the caps and remove the fields we don't want */ |
|
88 for (i = 0; i < gst_caps_get_size (othercaps); i++) { |
|
89 GstStructure *structure; |
|
90 |
|
91 structure = gst_caps_get_structure (othercaps, i); |
|
92 |
|
93 /* adjust the name */ |
|
94 gst_structure_set_name (structure, name); |
|
95 |
|
96 if (pad == mulawenc->srcpad) { |
|
97 /* remove the fields we don't want */ |
|
98 gst_structure_remove_fields (structure, "width", "depth", "endianness", |
|
99 "signed", NULL); |
|
100 } else { |
|
101 /* add fixed fields */ |
|
102 gst_structure_set (structure, "width", G_TYPE_INT, 16, |
|
103 "depth", G_TYPE_INT, 16, |
|
104 "endianness", G_TYPE_INT, G_BYTE_ORDER, |
|
105 "signed", G_TYPE_BOOLEAN, TRUE, NULL); |
|
106 } |
|
107 } |
|
108 /* filter against the allowed caps of the pad to return our result */ |
|
109 result = gst_caps_intersect (othercaps, templ); |
|
110 gst_caps_unref (othercaps); |
|
111 } else { |
|
112 /* there was no peer, return the template caps */ |
|
113 result = gst_caps_copy (templ); |
|
114 } |
|
115 return result; |
|
116 } |
|
117 |
|
118 static gboolean |
|
119 mulawenc_setcaps (GstPad * pad, GstCaps * caps) |
|
120 { |
|
121 GstMuLawEnc *mulawenc; |
|
122 GstPad *otherpad; |
|
123 GstStructure *structure; |
|
124 GstCaps *base_caps; |
|
125 |
|
126 mulawenc = GST_MULAWENC (gst_pad_get_parent (pad)); |
|
127 |
|
128 structure = gst_caps_get_structure (caps, 0); |
|
129 gst_structure_get_int (structure, "channels", &mulawenc->channels); |
|
130 gst_structure_get_int (structure, "rate", &mulawenc->rate); |
|
131 |
|
132 if (pad == mulawenc->sinkpad) { |
|
133 otherpad = mulawenc->srcpad; |
|
134 } else { |
|
135 otherpad = mulawenc->sinkpad; |
|
136 } |
|
137 base_caps = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad)); |
|
138 |
|
139 structure = gst_caps_get_structure (base_caps, 0); |
|
140 gst_structure_set (structure, "rate", G_TYPE_INT, mulawenc->rate, NULL); |
|
141 gst_structure_set (structure, "channels", G_TYPE_INT, mulawenc->channels, |
|
142 NULL); |
|
143 |
|
144 gst_pad_set_caps (otherpad, base_caps); |
|
145 |
|
146 gst_object_unref (mulawenc); |
|
147 gst_caps_unref (base_caps); |
|
148 |
|
149 return TRUE; |
|
150 } |
|
151 |
|
152 GType |
|
153 gst_mulawenc_get_type (void) |
|
154 { |
|
155 static GType mulawenc_type = 0; |
|
156 |
|
157 if (!mulawenc_type) { |
|
158 static const GTypeInfo mulawenc_info = { |
|
159 sizeof (GstMuLawEncClass), |
|
160 (GBaseInitFunc) gst_mulawenc_base_init, |
|
161 NULL, |
|
162 (GClassInitFunc) gst_mulawenc_class_init, |
|
163 NULL, |
|
164 NULL, |
|
165 sizeof (GstMuLawEnc), |
|
166 0, |
|
167 (GInstanceInitFunc) gst_mulawenc_init, |
|
168 }; |
|
169 |
|
170 mulawenc_type = |
|
171 g_type_register_static (GST_TYPE_ELEMENT, "GstMuLawEnc", &mulawenc_info, |
|
172 0); |
|
173 } |
|
174 return mulawenc_type; |
|
175 } |
|
176 |
|
177 static void |
|
178 gst_mulawenc_base_init (GstMuLawEncClass * klass) |
|
179 { |
|
180 GstElementClass *element_class = GST_ELEMENT_CLASS (klass); |
|
181 const GstElementDetails mulawenc_details = |
|
182 GST_ELEMENT_DETAILS ("Mu Law audio encoder", |
|
183 "Codec/Encoder/Audio", |
|
184 "Convert 16bit PCM to 8bit mu law", |
|
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_enc_src_factory)); |
|
189 gst_element_class_add_pad_template (element_class, |
|
190 gst_static_pad_template_get (&mulaw_enc_sink_factory)); |
|
191 gst_element_class_set_details (element_class, &mulawenc_details); |
|
192 } |
|
193 |
|
194 static void |
|
195 gst_mulawenc_class_init (GstMuLawEncClass * klass) |
|
196 { |
|
197 parent_class = g_type_class_peek_parent (klass); |
|
198 } |
|
199 |
|
200 static void |
|
201 gst_mulawenc_init (GstMuLawEnc * mulawenc) |
|
202 { |
|
203 mulawenc->sinkpad = |
|
204 gst_pad_new_from_static_template (&mulaw_enc_sink_factory, "sink"); |
|
205 gst_pad_set_setcaps_function (mulawenc->sinkpad, mulawenc_setcaps); |
|
206 gst_pad_set_getcaps_function (mulawenc->sinkpad, mulawenc_getcaps); |
|
207 gst_pad_set_chain_function (mulawenc->sinkpad, gst_mulawenc_chain); |
|
208 gst_element_add_pad (GST_ELEMENT (mulawenc), mulawenc->sinkpad); |
|
209 |
|
210 mulawenc->srcpad = |
|
211 gst_pad_new_from_static_template (&mulaw_enc_src_factory, "src"); |
|
212 gst_pad_set_setcaps_function (mulawenc->srcpad, mulawenc_setcaps); |
|
213 gst_pad_set_getcaps_function (mulawenc->srcpad, mulawenc_getcaps); |
|
214 gst_pad_use_fixed_caps (mulawenc->srcpad); |
|
215 gst_element_add_pad (GST_ELEMENT (mulawenc), mulawenc->srcpad); |
|
216 |
|
217 /* init rest */ |
|
218 mulawenc->channels = 0; |
|
219 mulawenc->rate = 0; |
|
220 } |
|
221 |
|
222 static GstFlowReturn |
|
223 gst_mulawenc_chain (GstPad * pad, GstBuffer * buffer) |
|
224 { |
|
225 GstMuLawEnc *mulawenc; |
|
226 gint16 *linear_data; |
|
227 guint linear_size; |
|
228 guint8 *mulaw_data; |
|
229 guint mulaw_size; |
|
230 GstBuffer *outbuf; |
|
231 GstFlowReturn ret; |
|
232 GstClockTime timestamp, duration; |
|
233 |
|
234 mulawenc = GST_MULAWENC (gst_pad_get_parent (pad)); |
|
235 |
|
236 if (!mulawenc->rate || !mulawenc->channels) |
|
237 goto not_negotiated; |
|
238 |
|
239 linear_data = (gint16 *) GST_BUFFER_DATA (buffer); |
|
240 linear_size = GST_BUFFER_SIZE (buffer); |
|
241 |
|
242 mulaw_size = linear_size / 2; |
|
243 |
|
244 timestamp = GST_BUFFER_TIMESTAMP (buffer); |
|
245 duration = GST_BUFFER_DURATION (buffer); |
|
246 |
|
247 ret = gst_pad_alloc_buffer_and_set_caps (mulawenc->srcpad, |
|
248 GST_BUFFER_OFFSET_NONE, mulaw_size, GST_PAD_CAPS (mulawenc->srcpad), |
|
249 &outbuf); |
|
250 if (ret != GST_FLOW_OK) |
|
251 goto alloc_failed; |
|
252 |
|
253 if (duration == -1) { |
|
254 duration = gst_util_uint64_scale_int (mulaw_size, |
|
255 GST_SECOND, mulawenc->rate * mulawenc->channels); |
|
256 } |
|
257 |
|
258 if (GST_BUFFER_SIZE (outbuf) < mulaw_size) { |
|
259 /* pad-alloc can suggest a smaller size */ |
|
260 gst_buffer_unref (outbuf); |
|
261 outbuf = gst_buffer_new_and_alloc (mulaw_size); |
|
262 } |
|
263 |
|
264 mulaw_data = (guint8 *) GST_BUFFER_DATA (outbuf); |
|
265 |
|
266 /* copy discont flag */ |
|
267 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) |
|
268 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); |
|
269 |
|
270 GST_BUFFER_TIMESTAMP (outbuf) = timestamp; |
|
271 GST_BUFFER_DURATION (outbuf) = duration; |
|
272 |
|
273 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (mulawenc->srcpad)); |
|
274 |
|
275 mulaw_encode (linear_data, mulaw_data, mulaw_size); |
|
276 |
|
277 gst_buffer_unref (buffer); |
|
278 |
|
279 ret = gst_pad_push (mulawenc->srcpad, outbuf); |
|
280 |
|
281 done: |
|
282 gst_object_unref (mulawenc); |
|
283 |
|
284 return ret; |
|
285 |
|
286 not_negotiated: |
|
287 { |
|
288 GST_DEBUG_OBJECT (mulawenc, "no format negotiated"); |
|
289 ret = GST_FLOW_NOT_NEGOTIATED; |
|
290 gst_buffer_unref (buffer); |
|
291 goto done; |
|
292 } |
|
293 alloc_failed: |
|
294 { |
|
295 GST_DEBUG_OBJECT (mulawenc, "pad alloc failed"); |
|
296 gst_buffer_unref (buffer); |
|
297 goto done; |
|
298 } |
|
299 } |