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