merge TYPEFIND branch. Major changes:
[platform/upstream/gst-plugins-good.git] / gst / auparse / gstauparse.c
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 /* 2001/04/03 - Updated parseau to use caps nego
21  *              Zaheer Merali <zaheer@grid9.net
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <gstauparse.h>
31
32 /* elementfactory information */
33 static GstElementDetails gst_auparse_details = {
34   ".au parser",
35   "Codec/Parser",
36   "LGPL",
37   "Parse an .au file into raw audio",
38   VERSION,
39   "Erik Walthinsen <omega@cse.ogi.edu>",
40   "(C) 1999",
41 };
42
43 GST_PAD_TEMPLATE_FACTORY (sink_factory_templ,
44   "sink",
45   GST_PAD_SINK,
46   GST_PAD_ALWAYS,
47   GST_CAPS_NEW (
48     "auparse_sink",
49     "audio/x-au",
50     NULL
51   )
52 )
53
54
55 GST_PAD_TEMPLATE_FACTORY (src_factory_templ,
56   "src",
57   GST_PAD_SRC,
58   GST_PAD_ALWAYS,
59   GST_CAPS_NEW (
60     "auparse_src",
61     "audio/x-raw-int",
62       "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
63       "signed",     GST_PROPS_LIST(
64                       GST_PROPS_BOOLEAN (FALSE),
65                       GST_PROPS_BOOLEAN (TRUE)
66                     ),
67       "width",      GST_PROPS_LIST(
68                       GST_PROPS_INT (8),
69                       GST_PROPS_INT (16)
70                     ),
71       "depth",      GST_PROPS_LIST(
72                       GST_PROPS_INT (8),
73                       GST_PROPS_INT (16)
74                     ),
75       "rate",       GST_PROPS_INT_RANGE (8000,48000),
76       "channels",   GST_PROPS_INT_RANGE (1, 2)
77   ),
78   GST_CAPS_NEW (
79     "auparse_src_alaw",
80     "audio/x-alaw",
81       "rate",       GST_PROPS_INT_RANGE (8000,48000),
82       "channels",   GST_PROPS_INT_RANGE (1, 2)
83   )
84 )
85
86 /* AuParse signals and args */
87 enum {
88   /* FILL ME */
89   LAST_SIGNAL
90 };
91
92 enum {
93   ARG_0,
94   /* FILL ME */
95 };
96
97 static void     gst_auparse_class_init          (GstAuParseClass *klass);
98 static void     gst_auparse_init                (GstAuParse *auparse);
99
100 static void     gst_auparse_chain               (GstPad *pad,GstData *_data);
101
102 static GstElementClass *parent_class = NULL;
103 /*static guint gst_auparse_signals[LAST_SIGNAL] = { 0 }; */
104
105 GType
106 gst_auparse_get_type (void) 
107 {
108   static GType auparse_type = 0;
109
110   if (!auparse_type) {
111     static const GTypeInfo auparse_info = {
112       sizeof(GstAuParseClass),      NULL,
113       NULL,
114       (GClassInitFunc) gst_auparse_class_init,
115       NULL,
116       NULL,
117       sizeof(GstAuParse),
118       0,
119       (GInstanceInitFunc) gst_auparse_init,
120     };
121     auparse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstAuParse", &auparse_info, 0);
122   }
123   return auparse_type;
124 }
125
126 static void
127 gst_auparse_class_init (GstAuParseClass *klass) 
128 {
129   GstElementClass *gstelement_class;
130
131   gstelement_class = (GstElementClass*) klass;
132
133   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
134 }
135
136 static void 
137 gst_auparse_init (GstAuParse *auparse) 
138 {
139   auparse->sinkpad = gst_pad_new_from_template (
140                   GST_PAD_TEMPLATE_GET (sink_factory_templ), "sink");
141   gst_element_add_pad (GST_ELEMENT (auparse), auparse->sinkpad);
142   gst_pad_set_chain_function (auparse->sinkpad, gst_auparse_chain);
143
144   auparse->srcpad = gst_pad_new_from_template (
145                   GST_PAD_TEMPLATE_GET (src_factory_templ), "src");
146   gst_element_add_pad (GST_ELEMENT (auparse), auparse->srcpad);
147
148   auparse->offset = 0;
149   auparse->size = 0;
150   auparse->encoding = 0;
151   auparse->frequency = 0;
152   auparse->channels = 0;
153 }
154
155 static void 
156 gst_auparse_chain (GstPad *pad, GstData *_data) 
157 {
158   GstBuffer *buf = GST_BUFFER (_data);
159   GstAuParse *auparse;
160   gchar *data;
161   glong size;
162   GstCaps* tempcaps;
163   gint law, depth;
164   gboolean sign;
165
166   g_return_if_fail (pad != NULL);
167   g_return_if_fail (GST_IS_PAD (pad));
168   g_return_if_fail (buf != NULL);
169
170   auparse = GST_AUPARSE (gst_pad_get_parent (pad));
171   
172   GST_DEBUG ("gst_auparse_chain: got buffer in '%s'",
173           gst_element_get_name (GST_ELEMENT (auparse)));
174
175   data = GST_BUFFER_DATA (buf);
176   size = GST_BUFFER_SIZE (buf);
177
178   /* if we haven't seen any data yet... */
179   if (auparse->size == 0) {
180     GstBuffer *newbuf;
181     guint32 *head = (guint32 *)data;
182
183     /* normal format is big endian (au is a Sparc format) */
184     if (GUINT32_FROM_BE (*head) == 0x2e736e64) {
185       head++;
186       auparse->le = 0;
187       auparse->offset           = GUINT32_FROM_BE (*head);
188       head++;
189       auparse->size             = GUINT32_FROM_BE (*head);
190       head++;
191       auparse->encoding         = GUINT32_FROM_BE (*head);
192       head++;
193       auparse->frequency        = GUINT32_FROM_BE (*head);
194       head++;
195       auparse->channels         = GUINT32_FROM_BE (*head);
196       head++;
197
198     /* and of course, someone had to invent a little endian
199      * version.  Used by DEC systems. */
200     } else if (GUINT32_FROM_LE (*head) == 0x0064732E) {
201       auparse->le = 1;
202       head++;
203       auparse->le = 0;
204       auparse->offset           = GUINT32_FROM_LE (*head);
205       head++;
206       auparse->size             = GUINT32_FROM_LE (*head);
207       head++;
208       auparse->encoding         = GUINT32_FROM_LE (*head);
209       head++;
210       auparse->frequency        = GUINT32_FROM_LE (*head);
211       head++;
212       auparse->channels         = GUINT32_FROM_LE (*head);
213       head++;
214
215     } else {
216       g_warning ("help, dunno what I'm looking at!\n");
217       gst_buffer_unref(buf);
218       return;
219     }
220
221     g_print ("offset %ld, size %ld, encoding %ld, frequency %ld, channels %ld\n",
222              auparse->offset,auparse->size,auparse->encoding,
223              auparse->frequency,auparse->channels);
224     GST_DEBUG ("offset %ld, size %ld, encoding %ld, frequency %ld, channels %ld",
225              auparse->offset,auparse->size,auparse->encoding,
226              auparse->frequency,auparse->channels);
227     
228     switch (auparse->encoding) {
229       case 1:
230         law = 1;
231         depth = 8;
232         sign = FALSE;
233         break;
234       case 2:
235         law = 0;
236         depth = 8;
237         sign = FALSE;
238         break;
239       case 3:
240         law = 0;
241         depth = 16;
242         sign = TRUE;
243         break;
244       default:
245         g_warning ("help!, dont know how to deal with this format yet\n");
246         return;
247     }
248
249     if (law) {
250       tempcaps = GST_CAPS_NEW ("auparse_src",
251                                "audio/x-alaw",
252                                  "rate",     GST_PROPS_INT (auparse->frequency),
253                                  "channels", GST_PROPS_INT (auparse->channels));
254     } else {
255       tempcaps = GST_CAPS_NEW ("auparse_src",
256                                "audio/x-raw-int",
257                                  "endianness", GST_PROPS_INT (G_BIG_ENDIAN),
258                                  "rate",       GST_PROPS_INT (auparse->frequency),
259                                  "channels",   GST_PROPS_INT (auparse->channels),
260                                  "depth",      GST_PROPS_INT (depth),
261                                  "width",      GST_PROPS_INT (depth),
262                                  "signed",     GST_PROPS_BOOLEAN (sign));
263     }
264
265     if (gst_pad_try_set_caps (auparse->srcpad, tempcaps) <= 0) {
266       gst_buffer_unref (buf);
267       gst_element_error (GST_ELEMENT (auparse), "could not set audio caps");
268       return;
269     }
270
271     newbuf = gst_buffer_new ();
272     GST_BUFFER_DATA (newbuf) = (gpointer) malloc (size-(auparse->offset));
273     memcpy (GST_BUFFER_DATA (newbuf), data+24, size-(auparse->offset));
274     GST_BUFFER_SIZE (newbuf) = size-(auparse->offset);
275
276     gst_buffer_unref (buf);
277
278     gst_pad_push (auparse->srcpad, GST_DATA (newbuf));
279     return;
280   }
281
282   gst_pad_push (auparse->srcpad, GST_DATA (buf));
283 }
284
285
286 static gboolean
287 plugin_init (GModule *module, GstPlugin *plugin)
288 {
289   GstElementFactory *factory;
290
291   /* create the plugin structure */
292   /* create an elementfactory for the auparse element and list it */
293   factory = gst_element_factory_new ("auparse", GST_TYPE_AUPARSE,
294                                     &gst_auparse_details);
295   g_return_val_if_fail (factory != NULL, FALSE);
296   gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_SECONDARY);
297
298   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_factory_templ));
299   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_factory_templ));
300
301   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
302
303   return TRUE;
304 }
305
306 GstPluginDesc plugin_desc = {
307   GST_VERSION_MAJOR,
308   GST_VERSION_MINOR,
309   "auparse",
310   plugin_init
311 };
312