gst/rtp/gstrtpamrdec.c: Fix up amr depayloader a bit.
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpamrdepay.c
1 /* GStreamer
2  * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
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 
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 #endif
18
19 #include <gst/rtp/gstrtpbuffer.h>
20
21 #include <string.h>
22 #include "gstrtpamrdec.h"
23
24 /* elementfactory information */
25 static GstElementDetails gst_rtp_amrdec_details = {
26   "RTP packet parser",
27   "Codec/Parser/Network",
28   "Extracts MPEG audio from RTP packets",
29   "Wim Taymans <wim@fluendo.com>"
30 };
31
32 /* RtpAMRDec signals and args */
33 enum
34 {
35   /* FILL ME */
36   LAST_SIGNAL
37 };
38
39 enum
40 {
41   ARG_0,
42   ARG_FREQUENCY
43 };
44
45 static GstStaticPadTemplate gst_rtpamrdec_src_template =
46 GST_STATIC_PAD_TEMPLATE ("src",
47     GST_PAD_SRC,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("audio/x-amr-nb")
50     );
51
52 static GstStaticPadTemplate gst_rtpamrdec_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("application/x-rtp")
57     );
58
59
60 static void gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass);
61 static void gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass);
62 static void gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec);
63
64 static GstFlowReturn gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buffer);
65
66 static void gst_rtpamrdec_set_property (GObject * object, guint prop_id,
67     const GValue * value, GParamSpec * pspec);
68 static void gst_rtpamrdec_get_property (GObject * object, guint prop_id,
69     GValue * value, GParamSpec * pspec);
70
71 static GstElementStateReturn gst_rtpamrdec_change_state (GstElement * element);
72
73 static GstElementClass *parent_class = NULL;
74
75 static GType
76 gst_rtpamrdec_get_type (void)
77 {
78   static GType rtpamrdec_type = 0;
79
80   if (!rtpamrdec_type) {
81     static const GTypeInfo rtpamrdec_info = {
82       sizeof (GstRtpAMRDecClass),
83       (GBaseInitFunc) gst_rtpamrdec_base_init,
84       NULL,
85       (GClassInitFunc) gst_rtpamrdec_class_init,
86       NULL,
87       NULL,
88       sizeof (GstRtpAMRDec),
89       0,
90       (GInstanceInitFunc) gst_rtpamrdec_init,
91     };
92
93     rtpamrdec_type =
94         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMRDec",
95         &rtpamrdec_info, 0);
96   }
97   return rtpamrdec_type;
98 }
99
100 static void
101 gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass)
102 {
103   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
104
105   gst_element_class_add_pad_template (element_class,
106       gst_static_pad_template_get (&gst_rtpamrdec_src_template));
107   gst_element_class_add_pad_template (element_class,
108       gst_static_pad_template_get (&gst_rtpamrdec_sink_template));
109
110   gst_element_class_set_details (element_class, &gst_rtp_amrdec_details);
111 }
112
113 static void
114 gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
115 {
116   GObjectClass *gobject_class;
117   GstElementClass *gstelement_class;
118
119   gobject_class = (GObjectClass *) klass;
120   gstelement_class = (GstElementClass *) klass;
121
122   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
123
124   gobject_class->set_property = gst_rtpamrdec_set_property;
125   gobject_class->get_property = gst_rtpamrdec_get_property;
126
127   gstelement_class->change_state = gst_rtpamrdec_change_state;
128 }
129
130 static void
131 gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
132 {
133   GstCaps *caps;
134
135   rtpamrdec->srcpad =
136       gst_pad_new_from_template (gst_static_pad_template_get
137       (&gst_rtpamrdec_src_template), "src");
138   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
139
140   caps = gst_caps_new_simple ("audio/x-amr-nb",
141       "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
142
143   gst_pad_set_caps (rtpamrdec->srcpad, caps);
144
145   rtpamrdec->sinkpad =
146       gst_pad_new_from_template (gst_static_pad_template_get
147       (&gst_rtpamrdec_sink_template), "sink");
148   gst_pad_set_chain_function (rtpamrdec->sinkpad, gst_rtpamrdec_chain);
149   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->sinkpad);
150 }
151
152 static GstFlowReturn
153 gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
154 {
155   GstRtpAMRDec *rtpamrdec;
156   GstBuffer *outbuf;
157   GstFlowReturn ret;
158
159   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
160
161   if (!gst_rtpbuffer_validate (buf))
162     goto bad_packet;
163
164   {
165     gint payload_len;
166     guint8 *payload;
167     guint32 timestamp;
168
169     payload_len = gst_rtpbuffer_get_payload_len (buf);
170     payload = gst_rtpbuffer_get_payload (buf);
171
172     /* strip off header */
173     payload_len -= 2;
174     payload += 2;
175
176     timestamp = gst_rtpbuffer_get_timestamp (buf);
177
178     outbuf = gst_buffer_new_and_alloc (payload_len);
179
180     //GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 90000;
181
182     memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
183
184     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
185
186     GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
187         GST_BUFFER_SIZE (outbuf));
188
189     gst_buffer_unref (buf);
190
191     ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
192   }
193
194   return ret;
195
196 bad_packet:
197   {
198     GST_DEBUG ("Packet did not validate");
199     gst_buffer_unref (buf);
200     return GST_FLOW_ERROR;
201   }
202 }
203
204 static void
205 gst_rtpamrdec_set_property (GObject * object, guint prop_id,
206     const GValue * value, GParamSpec * pspec)
207 {
208   GstRtpAMRDec *rtpamrdec;
209
210   rtpamrdec = GST_RTP_AMR_DEC (object);
211
212   switch (prop_id) {
213     default:
214       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215       break;
216   }
217 }
218
219 static void
220 gst_rtpamrdec_get_property (GObject * object, guint prop_id, GValue * value,
221     GParamSpec * pspec)
222 {
223   GstRtpAMRDec *rtpamrdec;
224
225   rtpamrdec = GST_RTP_AMR_DEC (object);
226
227   switch (prop_id) {
228     default:
229       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230       break;
231   }
232 }
233
234 static GstElementStateReturn
235 gst_rtpamrdec_change_state (GstElement * element)
236 {
237   GstRtpAMRDec *rtpamrdec;
238   gint transition;
239   GstElementStateReturn ret;
240
241   rtpamrdec = GST_RTP_AMR_DEC (element);
242   transition = GST_STATE_TRANSITION (element);
243
244   switch (transition) {
245     case GST_STATE_NULL_TO_READY:
246       break;
247     default:
248       break;
249   }
250
251   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
252
253   switch (transition) {
254     case GST_STATE_READY_TO_NULL:
255       break;
256     default:
257       break;
258   }
259   return ret;
260 }
261
262 gboolean
263 gst_rtpamrdec_plugin_init (GstPlugin * plugin)
264 {
265   return gst_element_register (plugin, "rtpamrdec",
266       GST_RANK_NONE, GST_TYPE_RTP_AMR_DEC);
267 }