fix descriptions and license blocks cut and paste anyone ?
[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 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 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gst/rtp/gstrtpbuffer.h>
25
26 #include <string.h>
27 #include "gstrtpamrdepay.h"
28
29 /* references:
30  *
31  * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
32  * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive Multi-Rate
33  * Wideband (AMR-WB) Audio Codecs.
34  */
35
36 /* elementfactory information */
37 static const GstElementDetails gst_rtp_amrdepay_details =
38 GST_ELEMENT_DETAILS ("RTP packet parser",
39     "Codec/Depayr/Network",
40     "Extracts AMR audio from RTP packets (RFC 3267)",
41     "Wim Taymans <wim@fluendo.com>");
42
43 /* RtpAMRDepay signals and args */
44 enum
45 {
46   /* FILL ME */
47   LAST_SIGNAL
48 };
49
50 enum
51 {
52   ARG_0,
53   ARG_FREQUENCY
54 };
55
56 /* input is an RTP packet
57  *
58  * params see RFC 3267, section 8.1
59  */
60 static GstStaticPadTemplate gst_rtp_amr_depay_sink_template =
61 GST_STATIC_PAD_TEMPLATE ("sink",
62     GST_PAD_SINK,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS ("application/x-rtp, "
65         "media = (string) \"audio\", "
66         "clock-rate = (int) 8000, "
67         "encoding-name = (string) \"AMR\", "
68         "encoding-params = (string) \"1\", "
69         "octet-align = (string) \"1\", "
70         "crc = (string) { \"0\", \"1\" }, "
71         "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
72         /* following options are not needed for a decoder
73          *
74          "mode-set = (int) [ 0, 7 ], "
75          "mode-change-period = (int) [ 1, MAX ], "
76          "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
77          "maxptime = (int) [ 20, MAX ], "
78          "ptime = (int) [ 20, MAX ]"
79          */
80     )
81     );
82
83 static GstStaticPadTemplate gst_rtp_amr_depay_src_template =
84 GST_STATIC_PAD_TEMPLATE ("src",
85     GST_PAD_SRC,
86     GST_PAD_ALWAYS,
87     GST_STATIC_CAPS ("audio/AMR, " "channels = (int) 1," "rate = (int) 8000")
88     );
89
90 static void gst_rtp_amr_depay_class_init (GstRtpAMRDepayClass * klass);
91 static void gst_rtp_amr_depay_base_init (GstRtpAMRDepayClass * klass);
92 static void gst_rtp_amr_depay_init (GstRtpAMRDepay * rtpamrdepay);
93
94 static gboolean gst_rtp_amr_depay_sink_setcaps (GstPad * pad, GstCaps * caps);
95 static GstFlowReturn gst_rtp_amr_depay_chain (GstPad * pad, GstBuffer * buffer);
96
97 static void gst_rtp_amr_depay_set_property (GObject * object, guint prop_id,
98     const GValue * value, GParamSpec * pspec);
99 static void gst_rtp_amr_depay_get_property (GObject * object, guint prop_id,
100     GValue * value, GParamSpec * pspec);
101
102 static GstStateChangeReturn gst_rtp_amr_depay_change_state (GstElement *
103     element, GstStateChange transition);
104
105 static GstElementClass *parent_class = NULL;
106
107 static GType
108 gst_rtp_amr_depay_get_type (void)
109 {
110   static GType rtpamrdepay_type = 0;
111
112   if (!rtpamrdepay_type) {
113     static const GTypeInfo rtpamrdepay_info = {
114       sizeof (GstRtpAMRDepayClass),
115       (GBaseInitFunc) gst_rtp_amr_depay_base_init,
116       NULL,
117       (GClassInitFunc) gst_rtp_amr_depay_class_init,
118       NULL,
119       NULL,
120       sizeof (GstRtpAMRDepay),
121       0,
122       (GInstanceInitFunc) gst_rtp_amr_depay_init,
123     };
124
125     rtpamrdepay_type =
126         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMRDepay",
127         &rtpamrdepay_info, 0);
128   }
129   return rtpamrdepay_type;
130 }
131
132 static void
133 gst_rtp_amr_depay_base_init (GstRtpAMRDepayClass * klass)
134 {
135   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
136
137   gst_element_class_add_pad_template (element_class,
138       gst_static_pad_template_get (&gst_rtp_amr_depay_src_template));
139   gst_element_class_add_pad_template (element_class,
140       gst_static_pad_template_get (&gst_rtp_amr_depay_sink_template));
141
142   gst_element_class_set_details (element_class, &gst_rtp_amrdepay_details);
143 }
144
145 static void
146 gst_rtp_amr_depay_class_init (GstRtpAMRDepayClass * klass)
147 {
148   GObjectClass *gobject_class;
149   GstElementClass *gstelement_class;
150
151   gobject_class = (GObjectClass *) klass;
152   gstelement_class = (GstElementClass *) klass;
153
154   parent_class = g_type_class_peek_parent (klass);
155
156   gobject_class->set_property = gst_rtp_amr_depay_set_property;
157   gobject_class->get_property = gst_rtp_amr_depay_get_property;
158
159   gstelement_class->change_state = gst_rtp_amr_depay_change_state;
160 }
161
162 static void
163 gst_rtp_amr_depay_init (GstRtpAMRDepay * rtpamrdepay)
164 {
165   rtpamrdepay->srcpad =
166       gst_pad_new_from_static_template (&gst_rtp_amr_depay_src_template, "src");
167
168   gst_element_add_pad (GST_ELEMENT (rtpamrdepay), rtpamrdepay->srcpad);
169
170   rtpamrdepay->sinkpad =
171       gst_pad_new_from_static_template (&gst_rtp_amr_depay_sink_template,
172       "sink");
173   gst_pad_set_setcaps_function (rtpamrdepay->sinkpad,
174       gst_rtp_amr_depay_sink_setcaps);
175   gst_pad_set_chain_function (rtpamrdepay->sinkpad, gst_rtp_amr_depay_chain);
176   gst_element_add_pad (GST_ELEMENT (rtpamrdepay), rtpamrdepay->sinkpad);
177 }
178
179 static gboolean
180 gst_rtp_amr_depay_sink_setcaps (GstPad * pad, GstCaps * caps)
181 {
182   GstStructure *structure;
183   GstCaps *srccaps;
184   GstRtpAMRDepay *rtpamrdepay;
185   const gchar *params;
186   const gchar *str;
187
188   rtpamrdepay = GST_RTP_AMR_DEPAY (GST_OBJECT_PARENT (pad));
189
190   structure = gst_caps_get_structure (caps, 0);
191
192   if (!(str = gst_structure_get_string (structure, "octet-align")))
193     rtpamrdepay->octet_align = FALSE;
194   else
195     rtpamrdepay->octet_align = (atoi (str) == 1);
196
197   if (!(str = gst_structure_get_string (structure, "crc")))
198     rtpamrdepay->crc = FALSE;
199   else
200     rtpamrdepay->crc = (atoi (str) == 1);
201
202   if (rtpamrdepay->crc) {
203     /* crc mode implies octet aligned mode */
204     rtpamrdepay->octet_align = TRUE;
205   }
206
207   if (!(str = gst_structure_get_string (structure, "robust-sorting")))
208     rtpamrdepay->robust_sorting = FALSE;
209   else
210     rtpamrdepay->robust_sorting = (atoi (str) == 1);
211
212   if (rtpamrdepay->robust_sorting) {
213     /* robust_sorting mode implies octet aligned mode */
214     rtpamrdepay->octet_align = TRUE;
215   }
216
217   if (!(str = gst_structure_get_string (structure, "interleaving")))
218     rtpamrdepay->interleaving = FALSE;
219   else
220     rtpamrdepay->interleaving = (atoi (str) == 1);
221
222   if (rtpamrdepay->interleaving) {
223     /* interleaving mode implies octet aligned mode */
224     rtpamrdepay->octet_align = TRUE;
225   }
226
227   if (!(params = gst_structure_get_string (structure, "encoding-params")))
228     rtpamrdepay->channels = 1;
229   else {
230     rtpamrdepay->channels = atoi (params);
231   }
232
233   if (!gst_structure_get_int (structure, "clock-rate", &rtpamrdepay->rate))
234     rtpamrdepay->rate = 8000;
235
236   /* we require 1 channel, 8000 Hz, octet aligned, no CRC,
237    * no robust sorting, no interleaving for now */
238   if (rtpamrdepay->channels != 1)
239     return FALSE;
240   if (rtpamrdepay->rate != 8000)
241     return FALSE;
242   if (rtpamrdepay->octet_align != TRUE)
243     return FALSE;
244   if (rtpamrdepay->robust_sorting != FALSE)
245     return FALSE;
246   if (rtpamrdepay->interleaving != FALSE)
247     return FALSE;
248
249   srccaps = gst_caps_new_simple ("audio/AMR",
250       "channels", G_TYPE_INT, rtpamrdepay->channels,
251       "rate", G_TYPE_INT, rtpamrdepay->rate, NULL);
252   gst_pad_set_caps (rtpamrdepay->srcpad, srccaps);
253   gst_caps_unref (srccaps);
254
255   rtpamrdepay->negotiated = TRUE;
256
257   return TRUE;
258 }
259
260 /* -1 is invalid */
261 static gint frame_size[16] = {
262   12, 13, 15, 17, 19, 20, 26, 31,
263   5, -1, -1, -1, -1, -1, -1, 0
264 };
265
266 static GstFlowReturn
267 gst_rtp_amr_depay_chain (GstPad * pad, GstBuffer * buf)
268 {
269   GstRtpAMRDepay *rtpamrdepay;
270   GstBuffer *outbuf;
271   GstFlowReturn ret;
272
273   rtpamrdepay = GST_RTP_AMR_DEPAY (GST_OBJECT_PARENT (pad));
274
275   if (!rtpamrdepay->negotiated)
276     goto not_negotiated;
277
278   if (!gst_rtp_buffer_validate (buf)) {
279     GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
280         (NULL), ("AMR RTP packet did not validate"));
281     goto bad_packet;
282   }
283
284   /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
285    * no robust sorting, no interleaving data is to be depayloaded */
286   {
287     gint payload_len;
288     guint8 *payload, *p, *dp;
289     guint32 timestamp;
290     guint8 CMR;
291     gint i, num_packets, num_nonempty_packets;
292     gint amr_len;
293     gint ILL, ILP;
294
295     payload_len = gst_rtp_buffer_get_payload_len (buf);
296
297     /* need at least 2 bytes for the header */
298     if (payload_len < 2) {
299       GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
300           (NULL), ("AMR RTP payload too small (%d)", payload_len));
301       goto bad_packet;
302     }
303
304     payload = gst_rtp_buffer_get_payload (buf);
305
306     /* depay CMR. The CMR is used by the sender to request
307      * a new encoding mode.
308      *
309      *  0 1 2 3 4 5 6 7 
310      * +-+-+-+-+-+-+-+-+
311      * | CMR   |R|R|R|R|
312      * +-+-+-+-+-+-+-+-+
313      */
314     CMR = (payload[0] & 0xf0) >> 4;
315
316     /* strip CMR header now, pack FT and the data for the decoder */
317     payload_len -= 1;
318     payload += 1;
319
320     GST_DEBUG_OBJECT (rtpamrdepay, "payload len %d", payload_len);
321
322     if (rtpamrdepay->interleaving) {
323       ILL = (payload[0] & 0xf0) >> 4;
324       ILP = (payload[0] & 0x0f);
325
326       payload_len -= 1;
327       payload += 1;
328
329       if (ILP > ILL) {
330         GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
331             (NULL), ("AMR RTP wrong interleaving"));
332         goto bad_packet;
333       }
334     }
335
336     /* 
337      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
338      * +-+-+-+-+-+-+-+-+..
339      * |F|  FT   |Q|P|P| more FT..
340      * +-+-+-+-+-+-+-+-+..
341      */
342     /* count number of packets by counting the FTs. Also
343      * count number of amr data bytes and number of non-empty
344      * packets (this is also the number of CRCs if present). */
345     amr_len = 0;
346     num_nonempty_packets = 0;
347     num_packets = 0;
348     for (i = 0; i < payload_len; i++) {
349       gint fr_size;
350       guint8 FT;
351
352       FT = (payload[i] & 0x78) >> 3;
353
354       fr_size = frame_size[FT];
355       GST_DEBUG_OBJECT (rtpamrdepay, "frame size %d", fr_size);
356       if (fr_size == -1) {
357         GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
358             (NULL), ("AMR RTP frame size == -1"));
359         goto bad_packet;
360       }
361
362       if (fr_size > 0) {
363         amr_len += fr_size;
364         num_nonempty_packets++;
365       }
366       num_packets++;
367
368       if ((payload[i] & 0x80) == 0)
369         break;
370     }
371
372     if (rtpamrdepay->crc) {
373       /* data len + CRC len + header bytes should be smaller than payload_len */
374       if (num_packets + num_nonempty_packets + amr_len > payload_len) {
375         GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
376             (NULL), ("AMR RTP wrong length 1"));
377         goto bad_packet;
378       }
379     } else {
380       /* data len + header bytes should be smaller than payload_len */
381       if (num_packets + amr_len > payload_len) {
382         GST_ELEMENT_WARNING (rtpamrdepay, STREAM, DECODE,
383             (NULL), ("AMR RTP wrong length 2"));
384         goto bad_packet;
385       }
386     }
387
388     timestamp = gst_rtp_buffer_get_timestamp (buf);
389
390     outbuf = gst_buffer_new_and_alloc (payload_len);
391     GST_BUFFER_TIMESTAMP (outbuf) =
392         gst_util_uint64_scale_int (timestamp, GST_SECOND, rtpamrdepay->rate);
393
394     /* point to destination */
395     p = GST_BUFFER_DATA (outbuf);
396     /* point to first data packet */
397     dp = payload + num_packets;
398     if (rtpamrdepay->crc) {
399       /* skip CRC if present */
400       dp += num_nonempty_packets;
401     }
402
403     for (i = 0; i < num_packets; i++) {
404       gint fr_size;
405
406       /* copy FT, clear F bit */
407       *p++ = payload[i] & 0x7f;
408
409       fr_size = frame_size[(payload[i] & 0x78) >> 3];
410       if (fr_size > 0) {
411         /* copy data packet, FIXME, calc CRC here. */
412         memcpy (p, dp, fr_size);
413
414         p += fr_size;
415         dp += fr_size;
416       }
417     }
418     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdepay->srcpad));
419
420     GST_DEBUG ("gst_rtp_amr_depay_chain: pushing buffer of size %d",
421         GST_BUFFER_SIZE (outbuf));
422     ret = gst_pad_push (rtpamrdepay->srcpad, outbuf);
423
424     gst_buffer_unref (buf);
425   }
426
427   return ret;
428
429   /* ERRORS */
430 not_negotiated:
431   {
432     GST_ELEMENT_ERROR (rtpamrdepay, STREAM, NOT_IMPLEMENTED,
433         (NULL), ("not negotiated"));
434     gst_buffer_unref (buf);
435     return GST_FLOW_NOT_NEGOTIATED;
436   }
437 bad_packet:
438   {
439     gst_buffer_unref (buf);
440     /* no fatal error */
441     return GST_FLOW_OK;
442   }
443 }
444
445 static void
446 gst_rtp_amr_depay_set_property (GObject * object, guint prop_id,
447     const GValue * value, GParamSpec * pspec)
448 {
449   GstRtpAMRDepay *rtpamrdepay;
450
451   rtpamrdepay = GST_RTP_AMR_DEPAY (object);
452
453   switch (prop_id) {
454     default:
455       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
456       break;
457   }
458 }
459
460 static void
461 gst_rtp_amr_depay_get_property (GObject * object, guint prop_id, GValue * value,
462     GParamSpec * pspec)
463 {
464   GstRtpAMRDepay *rtpamrdepay;
465
466   rtpamrdepay = GST_RTP_AMR_DEPAY (object);
467
468   switch (prop_id) {
469     default:
470       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
471       break;
472   }
473 }
474
475 static GstStateChangeReturn
476 gst_rtp_amr_depay_change_state (GstElement * element, GstStateChange transition)
477 {
478   GstRtpAMRDepay *rtpamrdepay;
479   GstStateChangeReturn ret;
480
481   rtpamrdepay = GST_RTP_AMR_DEPAY (element);
482
483   switch (transition) {
484     case GST_STATE_CHANGE_NULL_TO_READY:
485       break;
486     case GST_STATE_CHANGE_READY_TO_PAUSED:
487       break;
488     default:
489       break;
490   }
491
492   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
493
494   switch (transition) {
495     case GST_STATE_CHANGE_READY_TO_NULL:
496       break;
497     default:
498       break;
499   }
500   return ret;
501 }
502
503 gboolean
504 gst_rtp_amr_depay_plugin_init (GstPlugin * plugin)
505 {
506   return gst_element_register (plugin, "rtpamrdepay",
507       GST_RANK_NONE, GST_TYPE_RTP_AMR_DEPAY);
508 }