gst/rtp/: Small updates, RFC reference to payload encoders.
[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 GstElementStateReturn gst_rtpamrdec_change_state (GstElement * element);
97
98 static GstElementClass *parent_class = NULL;
99
100 static GType
101 gst_rtpamrdec_get_type (void)
102 {
103   static GType rtpamrdec_type = 0;
104
105   if (!rtpamrdec_type) {
106     static const GTypeInfo rtpamrdec_info = {
107       sizeof (GstRtpAMRDecClass),
108       (GBaseInitFunc) gst_rtpamrdec_base_init,
109       NULL,
110       (GClassInitFunc) gst_rtpamrdec_class_init,
111       NULL,
112       NULL,
113       sizeof (GstRtpAMRDec),
114       0,
115       (GInstanceInitFunc) gst_rtpamrdec_init,
116     };
117
118     rtpamrdec_type =
119         g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMRDec",
120         &rtpamrdec_info, 0);
121   }
122   return rtpamrdec_type;
123 }
124
125 static void
126 gst_rtpamrdec_base_init (GstRtpAMRDecClass * klass)
127 {
128   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
129
130   gst_element_class_add_pad_template (element_class,
131       gst_static_pad_template_get (&gst_rtpamrdec_src_template));
132   gst_element_class_add_pad_template (element_class,
133       gst_static_pad_template_get (&gst_rtpamrdec_sink_template));
134
135   gst_element_class_set_details (element_class, &gst_rtp_amrdec_details);
136 }
137
138 static void
139 gst_rtpamrdec_class_init (GstRtpAMRDecClass * klass)
140 {
141   GObjectClass *gobject_class;
142   GstElementClass *gstelement_class;
143
144   gobject_class = (GObjectClass *) klass;
145   gstelement_class = (GstElementClass *) klass;
146
147   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
148
149   gobject_class->set_property = gst_rtpamrdec_set_property;
150   gobject_class->get_property = gst_rtpamrdec_get_property;
151
152   gstelement_class->change_state = gst_rtpamrdec_change_state;
153 }
154
155 static void
156 gst_rtpamrdec_init (GstRtpAMRDec * rtpamrdec)
157 {
158   GstCaps *srccaps;
159
160   rtpamrdec->srcpad =
161       gst_pad_new_from_template (gst_static_pad_template_get
162       (&gst_rtpamrdec_src_template), "src");
163
164   /* FIXME */
165   srccaps = gst_caps_new_simple ("audio/AMR",
166       "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
167   gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
168   gst_caps_unref (srccaps);
169
170   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->srcpad);
171
172   rtpamrdec->sinkpad =
173       gst_pad_new_from_template (gst_static_pad_template_get
174       (&gst_rtpamrdec_sink_template), "sink");
175   gst_pad_set_setcaps_function (rtpamrdec->sinkpad, gst_rtpamrdec_sink_setcaps);
176   gst_pad_set_chain_function (rtpamrdec->sinkpad, gst_rtpamrdec_chain);
177   gst_element_add_pad (GST_ELEMENT (rtpamrdec), rtpamrdec->sinkpad);
178 }
179
180 static gboolean
181 gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
182 {
183   GstStructure *structure;
184   GstCaps *srccaps;
185   GstRtpAMRDec *rtpamrdec;
186
187   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
188
189   structure = gst_caps_get_structure (caps, 0);
190
191   if (!gst_structure_get_boolean (structure, "octet-align",
192           &rtpamrdec->octet_align))
193     rtpamrdec->octet_align = FALSE;
194
195   /* FIXME, force octect align for now until all elements negotiate 
196    * correctly*/
197   rtpamrdec->octet_align = TRUE;
198
199   if (!gst_structure_get_boolean (structure, "crc", &rtpamrdec->crc))
200     rtpamrdec->crc = FALSE;
201
202   if (rtpamrdec->crc) {
203     /* crc mode implies octet aligned mode */
204     rtpamrdec->octet_align = TRUE;
205   }
206
207   if (!gst_structure_get_boolean (structure, "robust-sorting",
208           &rtpamrdec->robust_sorting))
209     rtpamrdec->robust_sorting = FALSE;
210
211   if (rtpamrdec->robust_sorting) {
212     /* robust_sorting mode implies octet aligned mode */
213     rtpamrdec->octet_align = TRUE;
214   }
215
216   if (!gst_structure_get_boolean (structure, "interleaving",
217           &rtpamrdec->interleaving))
218     rtpamrdec->interleaving = FALSE;
219
220   if (rtpamrdec->interleaving) {
221     /* interleaving mode implies octet aligned mode */
222     rtpamrdec->octet_align = TRUE;
223   }
224
225   if (!gst_structure_get_int (structure, "channels", &rtpamrdec->channels))
226     rtpamrdec->channels = 1;
227   if (!gst_structure_get_int (structure, "rate", &rtpamrdec->rate))
228     rtpamrdec->rate = 8000;
229
230   /* we require 1 channel, 8000 Hz, octet aligned, no CRC, 
231    * no robust sorting, no interleaving for now */
232   if (rtpamrdec->channels != 1)
233     return FALSE;
234   if (rtpamrdec->rate != 8000)
235     return FALSE;
236   if (rtpamrdec->octet_align != TRUE)
237     return FALSE;
238   if (rtpamrdec->crc != FALSE)
239     return FALSE;
240   if (rtpamrdec->robust_sorting != FALSE)
241     return FALSE;
242   if (rtpamrdec->interleaving != FALSE)
243     return FALSE;
244
245   srccaps = gst_caps_new_simple ("audio/AMR",
246       "channels", G_TYPE_INT, rtpamrdec->channels,
247       "rate", G_TYPE_INT, rtpamrdec->rate, NULL);
248   gst_pad_set_caps (rtpamrdec->srcpad, srccaps);
249   gst_caps_unref (srccaps);
250
251   rtpamrdec->negotiated = TRUE;
252
253   return TRUE;
254 }
255
256 static GstFlowReturn
257 gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
258 {
259   GstRtpAMRDec *rtpamrdec;
260   GstBuffer *outbuf;
261   GstFlowReturn ret;
262
263   rtpamrdec = GST_RTP_AMR_DEC (GST_OBJECT_PARENT (pad));
264
265   if (!rtpamrdec->negotiated)
266     goto not_negotiated;
267
268   if (!gst_rtpbuffer_validate (buf))
269     goto bad_packet;
270
271   /* when we get here, 1 channel, 8000 Hz, octet aligned, no CRC, 
272    * no robust sorting, no interleaving data is to be parsed */
273   {
274     gint payload_len;
275     guint8 *payload;
276     guint32 timestamp;
277     guint8 CMR, F, FT, Q;
278
279     payload_len = gst_rtpbuffer_get_payload_len (buf);
280
281     /* need at least 2 bytes for the header */
282     if (payload_len < 2)
283       goto bad_packet;
284
285     payload = gst_rtpbuffer_get_payload (buf);
286
287     /* parse header 
288      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 
289      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
290      * | CMR=6 |R|R|R|R|0|FT#1=5 |Q|P|P|
291      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
292      */
293     CMR = (payload[0] & 0xf0) >> 4;
294     F = (payload[1] & 0x80) >> 7;
295     /* we only support 1 packet per RTP packet for now */
296     if (F != 0)
297       goto one_packet_only;
298
299     FT = (payload[1] & 0x78) >> 3;
300     Q = (payload[1] & 0x04) >> 2;
301
302     /* skip packet */
303     if (FT > 9 && FT < 15) {
304       ret = GST_FLOW_OK;
305       goto skip;
306     }
307
308     /* strip header now, leave FT in the data for the decoder */
309     payload_len -= 1;
310     payload += 1;
311
312     timestamp = gst_rtpbuffer_get_timestamp (buf);
313
314     outbuf = gst_buffer_new_and_alloc (payload_len);
315
316     GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / 8000;
317
318     memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
319
320     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
321
322     GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
323         GST_BUFFER_SIZE (outbuf));
324     ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
325
326   skip:
327     gst_buffer_unref (buf);
328   }
329
330   return ret;
331
332 not_negotiated:
333   {
334     GST_DEBUG ("not_negotiated");
335     gst_buffer_unref (buf);
336     return GST_FLOW_NOT_NEGOTIATED;
337   }
338 bad_packet:
339   {
340     GST_DEBUG ("Packet did not validate");
341     gst_buffer_unref (buf);
342     return GST_FLOW_ERROR;
343   }
344 one_packet_only:
345   {
346     GST_DEBUG ("One packet per RTP packet only");
347     gst_buffer_unref (buf);
348     return GST_FLOW_ERROR;
349   }
350 }
351
352 static void
353 gst_rtpamrdec_set_property (GObject * object, guint prop_id,
354     const GValue * value, GParamSpec * pspec)
355 {
356   GstRtpAMRDec *rtpamrdec;
357
358   rtpamrdec = GST_RTP_AMR_DEC (object);
359
360   switch (prop_id) {
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363       break;
364   }
365 }
366
367 static void
368 gst_rtpamrdec_get_property (GObject * object, guint prop_id, GValue * value,
369     GParamSpec * pspec)
370 {
371   GstRtpAMRDec *rtpamrdec;
372
373   rtpamrdec = GST_RTP_AMR_DEC (object);
374
375   switch (prop_id) {
376     default:
377       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
378       break;
379   }
380 }
381
382 static GstElementStateReturn
383 gst_rtpamrdec_change_state (GstElement * element)
384 {
385   GstRtpAMRDec *rtpamrdec;
386   gint transition;
387   GstElementStateReturn ret;
388
389   rtpamrdec = GST_RTP_AMR_DEC (element);
390   transition = GST_STATE_TRANSITION (element);
391
392   switch (transition) {
393     case GST_STATE_NULL_TO_READY:
394       break;
395     case GST_STATE_READY_TO_PAUSED:
396       /* FIXME, don't require negotiation until all elements
397        * do */
398       rtpamrdec->negotiated = TRUE;
399       break;
400     default:
401       break;
402   }
403
404   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
405
406   switch (transition) {
407     case GST_STATE_READY_TO_NULL:
408       break;
409     default:
410       break;
411   }
412   return ret;
413 }
414
415 gboolean
416 gst_rtpamrdec_plugin_init (GstPlugin * plugin)
417 {
418   return gst_element_register (plugin, "rtpamrdec",
419       GST_RANK_NONE, GST_TYPE_RTP_AMR_DEC);
420 }