All plugins updated for element state changes.
[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 /* references:
25  *
26  * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File Storage Format 
27  *   for the Adaptive Multi-Rate (AMR) and Adaptive Multi-Rate Wideband (AMR-WB) Audio 
28  *   Codecs.
29  */
30
31 /* elementfactory information */
32 static GstElementDetails gst_rtp_amrdec_details = {
33   "RTP packet parser",
34   "Codec/Parser/Network",
35   "Extracts MPEG audio from RTP packets",
36   "Wim Taymans <wim@fluendo.com>"
37 };
38
39 /* RtpAMRDec signals and args */
40 enum
41 {
42   /* FILL ME */
43   LAST_SIGNAL
44 };
45
46 enum
47 {
48   ARG_0,
49   ARG_FREQUENCY
50 };
51
52 /* input is an RTP packet 
53  *
54  * params see RFC 3267, section 8.1
55  */
56 static GstStaticPadTemplate gst_rtpamrdec_sink_template =
57 GST_STATIC_PAD_TEMPLATE ("sink",
58     GST_PAD_SINK,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("application/x-rtp, "
61         "octet-align = (boolean) TRUE, "
62         "crc = (boolean) FALSE, "
63         "robust-sorting = (boolean) FALSE, "
64         "interleaving = (boolean) FALSE, "
65         "channels = (int) 1, " "rate = (int) 8000"
66         /* following options are not needed for a decoder 
67          *
68          "mode-set = (int) [ 0, 7 ], "
69          "mode-change-period = (int) [ 1, MAX ], "
70          "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
71          "maxptime = (int) [ 20, MAX ], "
72          "ptime = (int) [ 20, MAX ]"
73          */
74     )
75     );
76
77 static GstStaticPadTemplate gst_rtpamrdec_src_template =
78 GST_STATIC_PAD_TEMPLATE ("src",
79     GST_PAD_SRC,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000")
82     );
83
84 static void gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass);
85 static void gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass);
86 static void gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec);
87
88 static gboolean gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps);
89 static GstFlowReturn gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buffer);
90
91 static void gst_rtpamrdec_set_property (GObject * object, guint prop_id,
92     const GValue * value, GParamSpec * pspec);
93 static void gst_rtpamrdec_get_property (GObject * object, guint prop_id,
94     GValue * value, GParamSpec * pspec);
95
96 static GstStateChangeReturn gst_rtpamrdec_change_state (GstElement * element,
97     GstStateChange transition);
98
99 static GstElementClass *parent_class = NULL;
100
101 static GType
102 gst_rtpamrdec_get_type (void)
103 {
104   static GType rtpamrdec_type = 0;
105
106   if (!rtpamrdec_type) {
107     static const GTypeInfo rtpamrdec_info = {
108       sizeof (GstRtpAMRDecClass),
109       (GBaseInitFunc) gst_rtpamrdec_base_init,
110       NULL,
111       (GClassInitFunc) gst_rtpamrdec_class_init,
112       NULL,
113       NULL,
114       sizeof (GstRtpAMRDec),
115       0,
116       (GInstanceInitFunc) gst_rtpamrdec_init,
117     };
118
119     rtpamrdec_type =
120         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMRDec",
121         &rtpamrdec_info, 0);
122   }
123   return rtpamrdec_type;
124 }
125
126 static void
127 gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass)
128 {
129   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
130
131   gst_element_class_add_pad_template (element_class,
132       gst_static_pad_template_get (&gst_rtpamrdec_src_template));
133   gst_element_class_add_pad_template (element_class,
134       gst_static_pad_template_get (&gst_rtpamrdec_sink_template));
135
136   gst_element_class_set_details (element_class, &gst_rtp_amrdec_details);
137 }
138
139 static void
140 gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
141 {
142   GObjectClass *gobject_class;
143   GstElementClass *gstelement_class;
144
145   gobject_class = (GObjectClass *) klass;
146   gstelement_class = (GstElementClass *) klass;
147
148   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
149
150   gobject_class->set_property = gst_rtpamrdec_set_property;
151   gobject_class->get_property = gst_rtpamrdec_get_property;
152
153   gstelement_class->change_state = gst_rtpamrdec_change_state;
154 }
155
156 static void
157 gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
158 {
159   GstCaps *srccaps;
160
161   rtpamrdec->srcpad =
162       gst_pad_new_from_template (gst_static_pad_template_get
163       (&gst_rtpamrdec_src_template), "src");
164
165   /* FIXME */
166   srccaps = gst_caps_new_simple ("audio/AMR",
167       "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
168   gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
169   gst_caps_unref (srccaps);
170
171   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
172
173   rtpamrdec->sinkpad =
174       gst_pad_new_from_template (gst_static_pad_template_get
175       (&gst_rtpamrdec_sink_template), "sink");
176   gst_pad_set_setcaps_function (rtpamrdec->sinkpad, gst_rtpamrdec_sink_setcaps);
177   gst_pad_set_chain_function (rtpamrdec->sinkpad, gst_rtpamrdec_chain);
178   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->sinkpad);
179 }
180
181 static gboolean
182 gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
183 {
184   GstStructure *structure;
185   GstCaps *srccaps;
186   GstRtpAMRDec *rtpamrdec;
187
188   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
189
190   structure = gst_caps_get_structure (caps, 0);
191
192   if (!gst_structure_get_boolean (structure, "octet-align",
193           &rtpamrdec->octet_align))
194     rtpamrdec->octet_align = FALSE;
195
196   /* FIXME, force octect align for now until all elements negotiate 
197    * correctly*/
198   rtpamrdec->octet_align = TRUE;
199
200   if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
201     rtpamrdec->crc = FALSE;
202
203   if (rtpamrdec->crc) {
204     /* crc mode implies octet aligned mode */
205     rtpamrdec->octet_align = TRUE;
206   }
207
208   if (!gst_structure_get_boolean (structure, "robust-sorting",
209           &rtpamrdec->robust_sorting))
210     rtpamrdec->robust_sorting = FALSE;
211
212   if (rtpamrdec->robust_sorting) {
213     /* robust_sorting mode implies octet aligned mode */
214     rtpamrdec->octet_align = TRUE;
215   }
216
217   if (!gst_structure_get_boolean (structure, "interleaving",
218           &rtpamrdec->interleaving))
219     rtpamrdec->interleaving = FALSE;
220
221   if (rtpamrdec->interleaving) {
222     /* interleaving mode implies octet aligned mode */
223     rtpamrdec->octet_align = TRUE;
224   }
225
226   if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
227     rtpamrdec->channels = 1;
228   if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
229     rtpamrdec->rate = 8000;
230
231   /* we require 1 channel, 8000 Hz, octet aligned, no CRC, 
232    * no robust sorting, no interleaving for now */
233   if (rtpamrdec->channels != 1)
234     return FALSE;
235   if (rtpamrdec->rate != 8000)
236     return FALSE;
237   if (rtpamrdec->octet_align != TRUE)
238     return FALSE;
239   if (rtpamrdec->crc != FALSE)
240     return FALSE;
241   if (rtpamrdec->robust_sorting != FALSE)
242     return FALSE;
243   if (rtpamrdec->interleaving != FALSE)
244     return FALSE;
245
246   srccaps = gst_caps_new_simple ("audio/AMR",
247       "channels", G_TYPE_INT, rtpamrdec->channels,
248       "rate", G_TYPE_INT, rtpamrdec->rate, NULL);
249   gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
250   gst_caps_unref (srccaps);
251
252   rtpamrdec->negotiated = TRUE;
253
254   return TRUE;
255 }
256
257 static GstFlowReturn
258 gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
259 {
260   GstRtpAMRDec *rtpamrdec;
261   GstBuffer *outbuf;
262   GstFlowReturn ret;
263
264   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
265
266   if (!rtpamrdec->negotiated)
267     goto not_negotiated;
268
269   if (!gst_rtpbuffer_validate (buf))
270     goto bad_packet;
271
272   /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
273    * no robust sorting, no interleaving data is to be parsed */
274   {
275     gint payload_len;
276     guint8 *payload;
277     guint32 timestamp;
278     guint8 CMR, F, FT, Q;
279
280     payload_len = gst_rtpbuffer_get_payload_len (buf);
281
282     /* need at least 2 bytes for the header */
283     if (payload_len < 2)
284       goto bad_packet;
285
286     payload = gst_rtpbuffer_get_payload (buf);
287
288     /* parse header 
289      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
290      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
291      * | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
292      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
293      */
294     CMR = (payload[0] & 0xf0) >> 4;
295     F = (payload[1] & 0x80) >> 7;
296     /* we only support 1 packet per RTP packet for now */
297     if (F != 0)
298       goto one_packet_only;
299
300     FT = (payload[1] & 0x78) >> 3;
301     Q = (payload[1] & 0x04) >> 2;
302
303     /* skip packet */
304     if (FT > 9 && FT < 15) {
305       ret = GST_FLOW_OK;
306       goto skip;
307     }
308
309     /* strip header now, leave FT in the data for the decoder */
310     payload_len -= 1;
311     payload += 1;
312
313     timestamp = gst_rtpbuffer_get_timestamp (buf);
314
315     outbuf = gst_buffer_new_and_alloc (payload_len);
316
317     GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
318
319     memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
320
321     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
322
323     GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
324         GST_BUFFER_SIZE (outbuf));
325     ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
326
327   skip:
328     gst_buffer_unref (buf);
329   }
330
331   return ret;
332
333 not_negotiated:
334   {
335     GST_DEBUG ("not_negotiated");
336     gst_buffer_unref (buf);
337     return GST_FLOW_NOT_NEGOTIATED;
338   }
339 bad_packet:
340   {
341     GST_DEBUG ("Packet did not validate");
342     gst_buffer_unref (buf);
343     return GST_FLOW_ERROR;
344   }
345 one_packet_only:
346   {
347     GST_DEBUG ("One packet per RTP packet only");
348     gst_buffer_unref (buf);
349     return GST_FLOW_ERROR;
350   }
351 }
352
353 static void
354 gst_rtpamrdec_set_property (GObject * object, guint prop_id,
355     const GValue * value, GParamSpec * pspec)
356 {
357   GstRtpAMRDec *rtpamrdec;
358
359   rtpamrdec = GST_RTP_AMR_DEC (object);
360
361   switch (prop_id) {
362     default:
363       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
364       break;
365   }
366 }
367
368 static void
369 gst_rtpamrdec_get_property (GObject * object, guint prop_id, GValue * value,
370     GParamSpec * pspec)
371 {
372   GstRtpAMRDec *rtpamrdec;
373
374   rtpamrdec = GST_RTP_AMR_DEC (object);
375
376   switch (prop_id) {
377     default:
378       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
379       break;
380   }
381 }
382
383 static GstStateChangeReturn
384 gst_rtpamrdec_change_state (GstElement * element, GstStateChange transition)
385 {
386   GstRtpAMRDec *rtpamrdec;
387   GstStateChangeReturn ret;
388
389   rtpamrdec = GST_RTP_AMR_DEC (element);
390
391   switch (transition) {
392     case GST_STATE_CHANGE_NULL_TO_READY:
393       break;
394     case GST_STATE_CHANGE_READY_TO_PAUSED:
395       /* FIXME, don't require negotiation until all elements
396        * do */
397       rtpamrdec->negotiated = TRUE;
398       break;
399     default:
400       break;
401   }
402
403   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
404
405   switch (transition) {
406     case GST_STATE_CHANGE_READY_TO_NULL:
407       break;
408     default:
409       break;
410   }
411   return ret;
412 }
413
414 gboolean
415 gst_rtpamrdec_plugin_init (GstPlugin * plugin)
416 {
417   return gst_element_register (plugin, "rtpamrdec",
418       GST_RANK_NONE, GST_TYPE_RTP_AMR_DEC);
419 }