6efdb64fdd97b82accb14cef32fe080b87a26507
[platform/upstream/gst-plugins-good.git] / gst / law / alaw-encode.c
1 /* GStreamer
2  * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
3  * PCM - A-Law conversion
4  *   Copyright (C) 2000 by Abramo Bagnara <abramo@alsa-project.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <gst/gst.h>
26 #include "alaw-encode.h"
27
28 extern GstPadTemplate *alawenc_src_template, *alawenc_sink_template;
29
30 /* elementfactory information */
31 static GstElementDetails alawenc_details = {
32   "PCM to A Law conversion",
33   "Codec/Encoder/Audio",
34   "Convert 16bit PCM to 8bit A law",
35   "Zaheer Merali <zaheer@bellworldwide.net>"
36 };
37
38 /* Stereo signals and args */
39 enum {
40   /* FILL ME */
41   LAST_SIGNAL
42 };
43
44 enum {
45   ARG_0
46 };
47
48 static void             gst_alawenc_class_init          (GstALawEncClass *klass);
49 static void             gst_alawenc_base_init           (GstALawEncClass *klass);
50 static void             gst_alawenc_init                        (GstALawEnc *alawenc);
51
52 static void             gst_alawenc_set_property                        (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
53 static void             gst_alawenc_get_property                        (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
54
55 static void             gst_alawenc_chain                       (GstPad *pad, GstData *_data);
56
57 /*
58  * s16_to_alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
59  *
60  * s16_to_alaw() accepts an 16-bit integer and encodes it as A-law data.
61  *
62  *              Linear Input Code       Compressed Code
63  *      ------------------------        ---------------
64  *      0000000wxyza                    000wxyz
65  *      0000001wxyza                    001wxyz
66  *      000001wxyzab                    010wxyz
67  *      00001wxyzabc                    011wxyz
68  *      0001wxyzabcd                    100wxyz
69  *      001wxyzabcde                    101wxyz
70  *      01wxyzabcdef                    110wxyz
71  *      1wxyzabcdefg                    111wxyz
72  *
73  * For further information see John C. Bellamy's Digital Telephony, 1982,
74  * John Wiley & Sons, pps 98-111 and 472-476.
75  */
76
77 static inline gint val_seg(gint val)
78 {
79         gint r = 1;
80         val >>= 8;
81         if (val & 0xf0) {
82                 val >>= 4;
83                 r += 4;
84         }
85         if (val & 0x0c) {
86                 val >>= 2;
87                 r += 2;
88         }
89         if (val & 0x02)
90                 r += 1;
91         return r;
92 }
93
94 static guint8 s16_to_alaw(gint pcm_val)
95 {
96         gint            seg;
97         guint8  mask;
98         guint8  aval;
99
100         if (pcm_val >= 0) {
101                 mask = 0xD5;
102         } else {
103                 mask = 0x55;
104                 pcm_val = -pcm_val;
105                 if (pcm_val > 0x7fff)
106                         pcm_val = 0x7fff;
107         }
108
109         if (pcm_val < 256)
110                 aval = pcm_val >> 4;
111         else {
112                 /* Convert the scaled magnitude to segment number. */
113                 seg = val_seg(pcm_val);
114                 aval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0x0f);
115         }
116         return aval ^ mask;
117 }
118
119 static GstElementClass *parent_class = NULL;
120 /*static guint gst_stereo_signals[LAST_SIGNAL] = { 0 }; */
121
122 static GstPadLinkReturn
123 alawenc_link (GstPad *pad, const GstCaps *caps)
124 {
125   GstCaps* tempcaps;
126   gint rate, channels;
127   GstStructure *structure;
128   gboolean ret;
129   
130   GstALawEnc* alawenc = GST_ALAWENC (GST_OBJECT_PARENT (pad));
131   
132   structure = gst_caps_get_structure (caps, 0);
133
134   ret = gst_structure_get_int (structure, "rate", &rate);
135   ret &= gst_structure_get_int (structure, "channels", &channels);
136
137   if (!ret) return GST_PAD_LINK_REFUSED;
138   
139   tempcaps = gst_caps_new_simple ("audio/x-alaw",
140       "depth",    G_TYPE_INT, 8,
141       "width",    G_TYPE_INT, 8,
142       "signed",   G_TYPE_BOOLEAN, FALSE,
143       "rate",     G_TYPE_INT, rate,
144       "channels", G_TYPE_INT, channels,
145       NULL);
146   
147   return gst_pad_try_set_caps (alawenc->srcpad, tempcaps);
148 }               
149
150 GType
151 gst_alawenc_get_type(void) {
152   static GType alawenc_type = 0;
153
154   if (!alawenc_type) {
155     static const GTypeInfo alawenc_info = {
156       sizeof(GstALawEncClass),
157       (GBaseInitFunc)gst_alawenc_base_init,
158       NULL,
159       (GClassInitFunc)gst_alawenc_class_init,
160       NULL,
161       NULL,
162       sizeof(GstALawEnc),
163       0,
164       (GInstanceInitFunc)gst_alawenc_init,
165     };
166     alawenc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstALawEnc", &alawenc_info, 0);
167   }
168   return alawenc_type;
169 }
170
171 static void
172 gst_alawenc_base_init (GstALawEncClass *klass)
173 {
174   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
175
176   gst_element_class_add_pad_template (element_class, alawenc_src_template);
177   gst_element_class_add_pad_template (element_class, alawenc_sink_template);
178   gst_element_class_set_details (element_class, &alawenc_details);
179 }
180
181 static void
182 gst_alawenc_class_init (GstALawEncClass *klass)
183 {
184   GObjectClass *gobject_class;
185   GstElementClass *gstelement_class;
186
187   gobject_class = (GObjectClass*)klass;
188   gstelement_class = (GstElementClass*)klass;
189
190   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
191
192   gobject_class->set_property = gst_alawenc_set_property;
193   gobject_class->get_property = gst_alawenc_get_property;
194 }
195
196 static void
197 gst_alawenc_init (GstALawEnc *alawenc)
198 {
199   alawenc->sinkpad = gst_pad_new_from_template(alawenc_sink_template,"sink");
200   alawenc->srcpad = gst_pad_new_from_template(alawenc_src_template,"src");
201   gst_pad_set_link_function (alawenc->sinkpad, alawenc_link);
202
203   gst_element_add_pad(GST_ELEMENT(alawenc),alawenc->sinkpad);
204   gst_pad_set_chain_function(alawenc->sinkpad,gst_alawenc_chain);
205   gst_element_add_pad(GST_ELEMENT(alawenc),alawenc->srcpad);
206 }
207
208 static void
209 gst_alawenc_chain (GstPad *pad,GstData *_data)
210 {
211   GstBuffer *buf = GST_BUFFER (_data);
212   GstALawEnc *alawenc;
213   gint16 *linear_data;
214   guint8 *alaw_data;
215   GstBuffer* outbuf;
216   gint i;
217
218   g_return_if_fail(pad != NULL);
219   g_return_if_fail(GST_IS_PAD(pad));
220   g_return_if_fail(buf != NULL);
221
222   alawenc = GST_ALAWENC(GST_OBJECT_PARENT (pad));
223   g_return_if_fail(alawenc != NULL);
224   g_return_if_fail(GST_IS_ALAWENC(alawenc));
225
226   linear_data = (gint16 *)GST_BUFFER_DATA(buf);
227   outbuf=gst_buffer_new();
228   GST_BUFFER_DATA(outbuf) = (gchar*)g_new(guint8,GST_BUFFER_SIZE(buf)/2);
229   GST_BUFFER_SIZE(outbuf) = GST_BUFFER_SIZE(buf)/2;
230
231   
232   alaw_data = (guint8*)GST_BUFFER_DATA(outbuf);
233   for (i = 0; i < GST_BUFFER_SIZE(outbuf); i++) {
234     *alaw_data = s16_to_alaw (*linear_data);
235     alaw_data++;
236     linear_data++;
237   }
238   gst_buffer_unref(buf);
239   gst_pad_push(alawenc->srcpad,GST_DATA (outbuf));
240 }
241
242 static void
243 gst_alawenc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
244 {
245   GstALawEnc *alawenc;
246
247   /* it's not null if we got it, but it might not be ours */
248   g_return_if_fail(GST_IS_ALAWENC(object));
249   alawenc = GST_ALAWENC(object);
250
251   switch (prop_id) {
252     default:
253       break;
254   }
255 }
256
257 static void
258 gst_alawenc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
259 {
260   GstALawEnc *alawenc;
261
262   /* it's not null if we got it, but it might not be ours */
263   g_return_if_fail(GST_IS_ALAWENC(object));
264   alawenc = GST_ALAWENC(object);
265
266   switch (prop_id) {
267     default:
268       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
269       break;
270   }
271 }