]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gst-plugins-ugly0-10.git/blob - ext/amrnb/amrnbparse.c
Ported to 0.9 (faad, amrnb, mpeg2dec)
[glsdk/gst-plugins-ugly0-10.git] / ext / amrnb / amrnbparse.c
1 /* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin
2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
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  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <string.h>
26 #include "amrnbparse.h"
28 GST_DEBUG_CATEGORY_STATIC (amrnbparse_debug);
29 #define GST_CAT_DEFAULT amrnbparse_debug
31 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
32     GST_PAD_SRC,
33     GST_PAD_ALWAYS,
34     GST_STATIC_CAPS ("audio/x-amr-nb, "
35         "rate = (int) 8000, " "channels = (int) 1")
36     );
38 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
39     GST_PAD_SINK,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS ("audio/x-amr-nb-sh")
42     );
44 static const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5,
45   0, 0, 0, 0, 0, 0, 0
46 };
48 static void gst_amrnbparse_base_init (GstAmrnbParseClass * klass);
49 static void gst_amrnbparse_class_init (GstAmrnbParseClass * klass);
50 static void gst_amrnbparse_init (GstAmrnbParse * amrnbparse);
52 //static const GstFormat *gst_amrnbparse_formats (GstPad * pad);
53 static const GstQueryType *gst_amrnbparse_querytypes (GstPad * pad);
54 static gboolean gst_amrnbparse_query (GstPad * pad, GstQuery * query);
56 static gboolean gst_amrnbparse_event (GstPad * pad, GstEvent * event);
57 static GstFlowReturn gst_amrnbparse_chain (GstPad * pad, GstBuffer * buffer);
58 static void gst_amrnbparse_loop (GstPad * pad);
59 static gboolean gst_amrnbparse_sink_activate (GstPad * sinkpad);
60 static GstElementStateReturn gst_amrnbparse_state_change (GstElement * element);
62 static GstElementClass *parent_class = NULL;
64 GType
65 gst_amrnbparse_get_type (void)
66 {
67   static GType amrnbparse_type = 0;
69   if (!amrnbparse_type) {
70     static const GTypeInfo amrnbparse_info = {
71       sizeof (GstAmrnbParseClass),
72       (GBaseInitFunc) gst_amrnbparse_base_init,
73       NULL,
74       (GClassInitFunc) gst_amrnbparse_class_init,
75       NULL,
76       NULL,
77       sizeof (GstAmrnbParse),
78       0,
79       (GInstanceInitFunc) gst_amrnbparse_init,
80     };
82     amrnbparse_type = g_type_register_static (GST_TYPE_ELEMENT,
83         "GstAmrnbParse", &amrnbparse_info, 0);
84   }
86   return amrnbparse_type;
87 }
89 static void
90 gst_amrnbparse_base_init (GstAmrnbParseClass * klass)
91 {
92   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
93   GstElementDetails gst_amrnbparse_details = {
94     "AMR-NB parser",
95     "Codec/Parser/Audio",
96     "Adaptive Multi-Rate Narrow-Band audio parser",
97     "Ronald Bultje <rbultje@ronald.bitfreak.net>"
98   };
100   gst_element_class_add_pad_template (element_class,
101       gst_static_pad_template_get (&sink_template));
102   gst_element_class_add_pad_template (element_class,
103       gst_static_pad_template_get (&src_template));
105   gst_element_class_set_details (element_class, &gst_amrnbparse_details);
108 static void
109 gst_amrnbparse_class_init (GstAmrnbParseClass * klass)
111   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
113   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
115   element_class->change_state = gst_amrnbparse_state_change;
117   GST_DEBUG_CATEGORY_INIT (amrnbparse_debug,
118       "amrnbparse", 0, "AMR-NB stream parsing");
121 static void
122 gst_amrnbparse_init (GstAmrnbParse * amrnbparse)
124   /* create the sink pad */
125   amrnbparse->sinkpad =
126       gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
127       "sink");
128   gst_pad_set_chain_function (amrnbparse->sinkpad,
129       GST_DEBUG_FUNCPTR (gst_amrnbparse_chain));
130   gst_pad_set_event_function (amrnbparse->sinkpad,
131       GST_DEBUG_FUNCPTR (gst_amrnbparse_event));
132 /*  gst_pad_set_loop_function (amrnbparse->sinkpad,
133       GST_DEBUG_FUNCPTR (gst_amrnbparse_loop));
134 */
135   gst_pad_set_activate_function (amrnbparse->sinkpad,
136       gst_amrnbparse_sink_activate);
137   gst_element_add_pad (GST_ELEMENT (amrnbparse), amrnbparse->sinkpad);
139   /* create the src pad */
140   amrnbparse->srcpad =
141       gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
142       "src");
143   gst_pad_set_query_function (amrnbparse->srcpad,
144       GST_DEBUG_FUNCPTR (gst_amrnbparse_query));
145   gst_pad_set_query_type_function (amrnbparse->srcpad,
146       GST_DEBUG_FUNCPTR (gst_amrnbparse_querytypes));
147   gst_element_add_pad (GST_ELEMENT (amrnbparse), amrnbparse->srcpad);
149   amrnbparse->adapter = gst_adapter_new ();
151   /* init rest */
152   amrnbparse->ts = 0;
155 /*
156  * Position querying.
157  */
159 #if 0
160 static const GstFormat *
161 gst_amrnbparse_formats (GstPad * pad)
163   static const GstFormat list[] = {
164     GST_FORMAT_TIME,
165     0
166   };
168   return list;
170 #endif
172 static const GstQueryType *
173 gst_amrnbparse_querytypes (GstPad * pad)
175   static const GstQueryType list[] = {
176     GST_QUERY_POSITION,
177     0
178   };
180   return list;
183 static gboolean
184 gst_amrnbparse_query (GstPad * pad, GstQuery * query)
186   GstAmrnbParse *amrnbparse;
187   gboolean res = TRUE;
189   amrnbparse = GST_AMRNBPARSE (GST_PAD_PARENT (pad));
191   switch (GST_QUERY_TYPE (query)) {
192     case GST_QUERY_POSITION:
193     {
194       GstFormat format;
195       gint64 cur, tot;
196       GstPad *peer;
198       gst_query_parse_position (query, &format, NULL, NULL);
200       if (format != GST_FORMAT_TIME)
201         return FALSE;
203       tot = -1;
205       peer = gst_pad_get_peer (amrnbparse->sinkpad);
206       if (peer) {
207         GstFormat pformat;
208         gint64 pcur, ptot;
210         pformat = GST_FORMAT_BYTES;
211         res = gst_pad_query_position (peer, &pformat, &pcur, &ptot);
212         gst_object_unref (GST_OBJECT (peer));
213         if (res) {
214           tot = amrnbparse->ts * ((gdouble) ptot / pcur);
215         }
216       }
217       cur = amrnbparse->ts;
219       gst_query_set_position (query, GST_FORMAT_TIME, cur, tot);
220       res = TRUE;
221       break;
222     }
223     default:
224       res = FALSE;
225       break;
226   }
227   return res;
231 /*
232  * Data reading.
233  */
234 static gboolean
235 gst_amrnbparse_event (GstPad * pad, GstEvent * event)
237   GstAmrnbParse *amrnbparse;
238   gboolean res;
240   amrnbparse = GST_AMRNBPARSE (GST_PAD_PARENT (pad));
242   GST_LOG ("handling event %d", GST_EVENT_TYPE (event));
244   switch (GST_EVENT_TYPE (event)) {
245     case GST_EVENT_EOS:
246     case GST_EVENT_DISCONTINUOUS:
247     default:
248       break;
249   }
251   res = gst_pad_event_default (amrnbparse->sinkpad, event);
253   return res;
256 /* streaming mode */
257 static GstFlowReturn
258 gst_amrnbparse_chain (GstPad * pad, GstBuffer * buffer)
260   GstAmrnbParse *amrnbparse;
261   GstFlowReturn res;
262   gint block, mode;
263   const guint8 *data;
264   GstBuffer *out;
266   amrnbparse = GST_AMRNBPARSE (GST_PAD_PARENT (pad));
268   gst_adapter_push (amrnbparse->adapter, buffer);
270   res = GST_FLOW_OK;
272   /* init */
273   if (amrnbparse->need_header) {
275     if (gst_adapter_available (amrnbparse->adapter) < 6)
276       goto done;
278     data = gst_adapter_peek (amrnbparse->adapter, 6);
279     if (memcmp (data, "#!AMR\n", 6) != 0)
280       goto done;
282     gst_adapter_flush (amrnbparse->adapter, 6);
284     amrnbparse->need_header = FALSE;
285   }
287   while (TRUE) {
288     if (gst_adapter_available (amrnbparse->adapter) < 1)
289       break;
290     data = gst_adapter_peek (amrnbparse->adapter, 1);
292     /* get size */
293     mode = (data[0] >> 3) & 0x0F;
294     block = block_size[mode] + 1;       /* add one for the mode */
296     if (gst_adapter_available (amrnbparse->adapter) < block)
297       break;
299     out = gst_buffer_new_and_alloc (block);
301     data = gst_adapter_peek (amrnbparse->adapter, block);
302     memcpy (GST_BUFFER_DATA (out), data, block);
304     /* output */
305     GST_BUFFER_DURATION (out) = GST_SECOND * 160 / 8000;
306     GST_BUFFER_TIMESTAMP (out) = amrnbparse->ts;
307     amrnbparse->ts += GST_BUFFER_DURATION (out);
308     gst_buffer_set_caps (out,
309         (GstCaps *) gst_pad_get_pad_template_caps (amrnbparse->srcpad));
311     GST_DEBUG ("Pushing %d bytes of data", block);
312     res = gst_pad_push (amrnbparse->srcpad, out);
314     gst_adapter_flush (amrnbparse->adapter, block);
315   }
316 done:
318   return res;
321 static gboolean
322 gst_amrnbparse_read_header (GstAmrnbParse * amrnbparse)
324   GstBuffer *buffer;
325   GstFlowReturn ret;
326   gint8 *data;
327   gint size;
329   ret =
330       gst_pad_pull_range (amrnbparse->sinkpad, amrnbparse->offset, 6, &buffer);
331   if (ret != GST_FLOW_OK)
332     return FALSE;
334   data = GST_BUFFER_DATA (buffer);
335   size = GST_BUFFER_SIZE (buffer);
336   if (size < 6)
337     goto not_enough;
339   if (memcmp (data, "#!AMR\n", 6))
340     goto no_header;
342   amrnbparse->offset += 6;
344   return TRUE;
346 not_enough:
347   {
348     gst_buffer_unref (buffer);
349     return FALSE;
350   }
351 no_header:
352   {
353     gst_buffer_unref (buffer);
354     return FALSE;
355   }
358 /* random access mode, could just read a fixed size buffer and push it to
359  * the chain function but we don't... */
360 static void
361 gst_amrnbparse_loop (GstPad * pad)
363   GstAmrnbParse *amrnbparse;
364   GstBuffer *buffer;
365   guint8 *data;
366   gint size;
367   gint block, mode;
368   GstFlowReturn ret;
370   amrnbparse = GST_AMRNBPARSE (GST_PAD_PARENT (pad));
372   /* init */
373   if (amrnbparse->need_header) {
374     gboolean got_header;
376     got_header = gst_amrnbparse_read_header (amrnbparse);
377     if (!got_header) {
378       GST_LOG_OBJECT (amrnbparse, "could not read header");
379       goto need_pause;
380     }
381     amrnbparse->need_header = FALSE;
382   }
384   ret =
385       gst_pad_pull_range (amrnbparse->sinkpad, amrnbparse->offset, 1, &buffer);
386   if (ret != GST_FLOW_OK)
387     goto need_pause;
389   data = GST_BUFFER_DATA (buffer);
390   size = GST_BUFFER_SIZE (buffer);
392   /* EOS */
393   if (size < 1)
394     goto eos;
396   /* get size */
397   mode = (data[0] >> 3) & 0x0F;
398   block = block_size[mode] + 1; /* add one for the mode */
400   gst_buffer_unref (buffer);
402   ret =
403       gst_pad_pull_range (amrnbparse->sinkpad, amrnbparse->offset, block,
404       &buffer);
405   if (ret != GST_FLOW_OK)
406     goto need_pause;
408   amrnbparse->offset += block;
410   /* output */
411   GST_BUFFER_DURATION (buffer) = GST_SECOND * 160 / 8000;
412   GST_BUFFER_TIMESTAMP (buffer) = amrnbparse->ts;
413   amrnbparse->ts += GST_BUFFER_DURATION (buffer);
414   gst_buffer_set_caps (buffer,
415       (GstCaps *) gst_pad_get_pad_template_caps (amrnbparse->srcpad));
417   GST_DEBUG ("Pushing %d bytes of data", block);
418   ret = gst_pad_push (amrnbparse->srcpad, buffer);
419   if (ret != GST_FLOW_OK)
420     goto need_pause;
422   return;
424 need_pause:
425   {
426     GST_LOG_OBJECT (amrnbparse, "pausing task");
427     gst_pad_pause_task (pad);
428     return;
429   }
430 eos:
431   {
432     GST_LOG_OBJECT (amrnbparse, "pausing task");
433     gst_pad_push_event (amrnbparse->srcpad, gst_event_new (GST_EVENT_EOS));
434     gst_pad_pause_task (pad);
435     return;
436   }
439 static gboolean
440 gst_amrnbparse_sink_activate (GstPad * sinkpad)
442   gboolean result = FALSE;
443   GstAmrnbParse *amrnbparse;
444   GstActivateMode mode;
446   amrnbparse = GST_AMRNBPARSE (GST_OBJECT_PARENT (sinkpad));
448   GST_LOCK (sinkpad);
449   mode = GST_PAD_ACTIVATE_MODE (sinkpad);
450   GST_UNLOCK (sinkpad);
452   switch (mode) {
453     case GST_ACTIVATE_PUSH:
454       amrnbparse->seekable = FALSE;
455       result = TRUE;
456       break;
457     case GST_ACTIVATE_PULL:
458       /*gst_pad_peer_set_active (sinkpad, mode); */
460       amrnbparse->need_header = TRUE;
461       amrnbparse->seekable = TRUE;
462       amrnbparse->ts = 0;
464       result = gst_pad_start_task (sinkpad,
465           (GstTaskFunction) gst_amrnbparse_loop, sinkpad);
466       break;
467     case GST_ACTIVATE_NONE:
468       /* step 1, unblock clock sync (if any) */
470       /* step 2, make sure streaming finishes */
471       result = gst_pad_stop_task (sinkpad);
472       break;
473   }
474   return result;
477 static GstElementStateReturn
478 gst_amrnbparse_state_change (GstElement * element)
480   GstAmrnbParse *amrnbparse;
481   gint transition;
482   GstElementStateReturn ret;
484   amrnbparse = GST_AMRNBPARSE (element);
485   transition = GST_STATE_TRANSITION (element);
487   switch (transition) {
488     case GST_STATE_NULL_TO_READY:
489       break;
490     case GST_STATE_READY_TO_PAUSED:
491       break;
492     default:
493       break;
494   }
496   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
498   switch (transition) {
499     case GST_STATE_PAUSED_TO_READY:
500       break;
501     case GST_STATE_READY_TO_NULL:
502       break;
503     default:
504       break;
505   }
507   return ret;