upload tizen1.0 source
[framework/multimedia/gst-plugins-good0.10.git] / gst / rtp / gstrtpmparobustdepay.c
1 /* GStreamer
2  * Copyright (C) <2010> Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
3  * Copyright (C) <2010> Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24
25 #include <gst/rtp/gstrtpbuffer.h>
26
27 #include <stdio.h>
28 #include <string.h>
29 #include "gstrtpmparobustdepay.h"
30
31 GST_DEBUG_CATEGORY_STATIC (rtpmparobustdepay_debug);
32 #define GST_CAT_DEFAULT (rtpmparobustdepay_debug)
33
34 static GstStaticPadTemplate gst_rtp_mpa_robust_depay_src_template =
35 GST_STATIC_PAD_TEMPLATE ("src",
36     GST_PAD_SRC,
37     GST_PAD_ALWAYS,
38     GST_STATIC_CAPS ("audio/mpeg, " "mpegversion = (int) 1")
39     );
40
41 static GstStaticPadTemplate gst_rtp_mpa_robust_depay_sink_template =
42     GST_STATIC_PAD_TEMPLATE ("sink",
43     GST_PAD_SINK,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS ("application/x-rtp, "
46         "media = (string) \"audio\", "
47         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
48         "clock-rate = (int) 90000, "
49         "encoding-name = (string) \"MPA-ROBUST\" " "; "
50         /* draft versions appear still in use out there */
51         "application/x-rtp, "
52         "media = (string) \"audio\", "
53         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
54         "clock-rate = (int) [1, MAX], "
55         "encoding-name = (string) { \"X-MP3-DRAFT-00\", \"X-MP3-DRAFT-01\", "
56         " \"X-MP3-DRAFT-02\", \"X-MP3-DRAFT-03\", \"X-MP3-DRAFT-04\", "
57         " \"X-MP3-DRAFT-05\", \"X-MP3-DRAFT-06\" }")
58     );
59
60 typedef struct _GstADUFrame
61 {
62   guint32 header;
63   gint size;
64   gint side_info;
65   gint data_size;
66   gint layer;
67   gint backpointer;
68
69   GstBuffer *buffer;
70 } GstADUFrame;
71
72 GST_BOILERPLATE (GstRtpMPARobustDepay, gst_rtp_mpa_robust_depay,
73     GstBaseRTPDepayload, GST_TYPE_BASE_RTP_DEPAYLOAD);
74
75 static GstStateChangeReturn gst_rtp_mpa_robust_change_state (GstElement *
76     element, GstStateChange transition);
77
78 static gboolean gst_rtp_mpa_robust_depay_setcaps (GstBaseRTPDepayload *
79     depayload, GstCaps * caps);
80 static GstBuffer *gst_rtp_mpa_robust_depay_process (GstBaseRTPDepayload *
81     depayload, GstBuffer * buf);
82
83 static void
84 gst_rtp_mpa_robust_depay_base_init (gpointer klass)
85 {
86   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
87
88   gst_element_class_add_pad_template (element_class,
89       gst_static_pad_template_get (&gst_rtp_mpa_robust_depay_src_template));
90   gst_element_class_add_pad_template (element_class,
91       gst_static_pad_template_get (&gst_rtp_mpa_robust_depay_sink_template));
92
93   gst_element_class_set_details_simple (element_class,
94       "RTP MPEG audio depayloader", "Codec/Depayloader/Network/RTP",
95       "Extracts MPEG audio from RTP packets (RFC 5219)",
96       "Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>");
97 }
98
99 static void
100 gst_rtp_mpa_robust_depay_finalize (GObject * object)
101 {
102   GstRtpMPARobustDepay *rtpmpadepay;
103
104   rtpmpadepay = (GstRtpMPARobustDepay *) object;
105
106   g_object_unref (rtpmpadepay->adapter);
107   g_queue_free (rtpmpadepay->adu_frames);
108
109   G_OBJECT_CLASS (parent_class)->finalize (object);
110 }
111
112
113 static void
114 gst_rtp_mpa_robust_depay_class_init (GstRtpMPARobustDepayClass * klass)
115 {
116   GObjectClass *gobject_class;
117   GstElementClass *gstelement_class;
118   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
119
120   gobject_class = (GObjectClass *) klass;
121   gstelement_class = (GstElementClass *) klass;
122   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
123
124   gobject_class->finalize = gst_rtp_mpa_robust_depay_finalize;
125
126   gstelement_class->change_state =
127       GST_DEBUG_FUNCPTR (gst_rtp_mpa_robust_change_state);
128
129   gstbasertpdepayload_class->set_caps = gst_rtp_mpa_robust_depay_setcaps;
130   gstbasertpdepayload_class->process = gst_rtp_mpa_robust_depay_process;
131
132   GST_DEBUG_CATEGORY_INIT (rtpmparobustdepay_debug, "rtpmparobustdepay", 0,
133       "Robust MPEG Audio RTP Depayloader");
134 }
135
136 static void
137 gst_rtp_mpa_robust_depay_init (GstRtpMPARobustDepay * rtpmpadepay,
138     GstRtpMPARobustDepayClass * klass)
139 {
140   rtpmpadepay->adapter = gst_adapter_new ();
141   rtpmpadepay->adu_frames = g_queue_new ();
142 }
143
144 static gboolean
145 gst_rtp_mpa_robust_depay_setcaps (GstBaseRTPDepayload * depayload,
146     GstCaps * caps)
147 {
148   GstRtpMPARobustDepay *rtpmpadepay;
149   GstStructure *structure;
150   GstCaps *outcaps;
151   gint clock_rate, draft;
152   gboolean res;
153   const gchar *encoding;
154
155   rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
156
157   structure = gst_caps_get_structure (caps, 0);
158
159   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
160     clock_rate = 90000;
161   depayload->clock_rate = clock_rate;
162
163   rtpmpadepay->has_descriptor = TRUE;
164   if ((encoding = gst_structure_get_string (structure, "encoding-name"))) {
165     if (sscanf (encoding, "X-MP3-DRAFT-%d", &draft) && (draft == 0))
166       rtpmpadepay->has_descriptor = FALSE;
167   }
168
169   outcaps =
170       gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, NULL);
171   res = gst_pad_set_caps (depayload->srcpad, outcaps);
172   gst_caps_unref (outcaps);
173
174   return res;
175 }
176
177 /* thanks again go to mp3parse ... */
178
179 static const guint mp3types_bitrates[2][3][16] = {
180   {
181         {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448,},
182         {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384,},
183         {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,}
184       },
185   {
186         {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256,},
187         {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,},
188         {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160,}
189       },
190 };
191
192 static const guint mp3types_freqs[3][3] = { {44100, 48000, 32000},
193 {22050, 24000, 16000},
194 {11025, 12000, 8000}
195 };
196
197 static inline guint
198 mp3_type_frame_length_from_header (GstElement * mp3parse, guint32 header,
199     guint * put_version, guint * put_layer, guint * put_channels,
200     guint * put_bitrate, guint * put_samplerate, guint * put_mode,
201     guint * put_crc)
202 {
203   guint length;
204   gulong mode, samplerate, bitrate, layer, channels, padding, crc;
205   gulong version;
206   gint lsf, mpg25;
207
208   if (header & (1 << 20)) {
209     lsf = (header & (1 << 19)) ? 0 : 1;
210     mpg25 = 0;
211   } else {
212     lsf = 1;
213     mpg25 = 1;
214   }
215
216   version = 1 + lsf + mpg25;
217
218   layer = 4 - ((header >> 17) & 0x3);
219
220   crc = (header >> 16) & 0x1;
221
222   bitrate = (header >> 12) & 0xF;
223   bitrate = mp3types_bitrates[lsf][layer - 1][bitrate] * 1000;
224   /* The caller has ensured we have a valid header, so bitrate can't be
225      zero here. */
226   if (bitrate == 0) {
227     GST_DEBUG_OBJECT (mp3parse, "invalid bitrate");
228     return 0;
229   }
230
231   samplerate = (header >> 10) & 0x3;
232   samplerate = mp3types_freqs[lsf + mpg25][samplerate];
233
234   padding = (header >> 9) & 0x1;
235
236   mode = (header >> 6) & 0x3;
237   channels = (mode == 3) ? 1 : 2;
238
239   switch (layer) {
240     case 1:
241       length = 4 * ((bitrate * 12) / samplerate + padding);
242       break;
243     case 2:
244       length = (bitrate * 144) / samplerate + padding;
245       break;
246     default:
247     case 3:
248       length = (bitrate * 144) / (samplerate << lsf) + padding;
249       break;
250   }
251
252   GST_LOG_OBJECT (mp3parse, "Calculated mp3 frame length of %u bytes", length);
253   GST_LOG_OBJECT (mp3parse, "samplerate = %lu, bitrate = %lu, version = %lu, "
254       "layer = %lu, channels = %lu, mode = %lu", samplerate, bitrate, version,
255       layer, channels, mode);
256
257   if (put_version)
258     *put_version = version;
259   if (put_layer)
260     *put_layer = layer;
261   if (put_channels)
262     *put_channels = channels;
263   if (put_bitrate)
264     *put_bitrate = bitrate;
265   if (put_samplerate)
266     *put_samplerate = samplerate;
267   if (put_mode)
268     *put_mode = mode;
269   if (put_crc)
270     *put_crc = crc;
271
272   GST_LOG_OBJECT (mp3parse, "size = %u", length);
273   return length;
274 }
275
276 /* generate empty/silent/dummy frame that mimics @frame,
277  * except for rate, where maximum possible is selected */
278 static GstADUFrame *
279 gst_rtp_mpa_robust_depay_generate_dummy_frame (GstRtpMPARobustDepay *
280     rtpmpadepay, GstADUFrame * frame)
281 {
282   GstADUFrame *dummy;
283
284   dummy = g_slice_dup (GstADUFrame, frame);
285
286   /* go for maximum bitrate */
287   dummy->header = (frame->header & ~(0xf << 12)) | (0xe << 12);
288   dummy->size =
289       mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
290       dummy->header, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
291   dummy->data_size = dummy->size - dummy->side_info;
292   dummy->backpointer = 0;
293
294   dummy->buffer = gst_buffer_new_and_alloc (dummy->side_info + 4);
295   memset (GST_BUFFER_DATA (dummy->buffer), 0, dummy->side_info + 4);
296   GST_WRITE_UINT32_BE (GST_BUFFER_DATA (dummy->buffer), dummy->header);
297   GST_BUFFER_TIMESTAMP (dummy->buffer) = GST_BUFFER_TIMESTAMP (frame->buffer);
298
299   return dummy;
300 }
301
302 /* validates and parses @buf, and queues for further transformation if valid,
303  * otherwise discards @buf
304  * Takes ownership of @buf. */
305 static gboolean
306 gst_rtp_mpa_robust_depay_queue_frame (GstRtpMPARobustDepay * rtpmpadepay,
307     GstBuffer * buf)
308 {
309   GstADUFrame *frame = NULL;
310   guint version, layer, channels, size;
311   guint crc;
312
313   g_return_val_if_fail (buf != NULL, FALSE);
314
315   if (GST_BUFFER_SIZE (buf) < 6) {
316     goto corrupt_frame;
317   }
318
319   frame = g_slice_new0 (GstADUFrame);
320   frame->header = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf));
321
322   size = mp3_type_frame_length_from_header (GST_ELEMENT_CAST (rtpmpadepay),
323       frame->header, &version, &layer, &channels, NULL, NULL, NULL, &crc);
324   if (!size)
325     goto corrupt_frame;
326
327   frame->size = size;
328   frame->layer = layer;
329   if (version == 1 && channels == 2)
330     frame->side_info = 32;
331   else if ((version == 1 && channels == 1) || (version >= 2 && channels == 2))
332     frame->side_info = 17;
333   else if (version >= 2 && channels == 1)
334     frame->side_info = 9;
335   else {
336     g_assert_not_reached ();
337     goto corrupt_frame;
338   }
339
340   /* backpointer */
341   if (layer == 3) {
342     frame->backpointer = GST_READ_UINT16_BE (GST_BUFFER_DATA (buf) + 4);
343     frame->backpointer >>= 7;
344     GST_LOG_OBJECT (rtpmpadepay, "backpointer: %d", frame->backpointer);
345   }
346
347   if (!crc)
348     frame->side_info += 2;
349
350   GST_LOG_OBJECT (rtpmpadepay, "side info: %d", frame->side_info);
351   frame->data_size = frame->size - 4 - frame->side_info;
352
353   /* some size validation checks */
354   if (4 + frame->side_info > GST_BUFFER_SIZE (buf))
355     goto corrupt_frame;
356
357   /* ADU data would then extend past MP3 frame,
358    * even using past byte reservoir */
359   if (-frame->backpointer + (gint) (GST_BUFFER_SIZE (buf)) > frame->size)
360     goto corrupt_frame;
361
362   /* ok, take buffer and queue */
363   frame->buffer = buf;
364   g_queue_push_tail (rtpmpadepay->adu_frames, frame);
365
366   return TRUE;
367
368   /* ERRORS */
369 corrupt_frame:
370   {
371     GST_DEBUG_OBJECT (rtpmpadepay, "frame is corrupt");
372     gst_buffer_unref (buf);
373     if (frame)
374       g_slice_free (GstADUFrame, frame);
375     return FALSE;
376   }
377 }
378
379 static inline void
380 gst_rtp_mpa_robust_depay_free_frame (GstADUFrame * frame)
381 {
382   if (frame->buffer)
383     gst_buffer_unref (frame->buffer);
384   g_slice_free (GstADUFrame, frame);
385 }
386
387 static inline void
388 gst_rtp_mpa_robust_depay_dequeue_frame (GstRtpMPARobustDepay * rtpmpadepay)
389 {
390   GstADUFrame *head;
391
392   GST_LOG_OBJECT (rtpmpadepay, "dequeueing ADU frame");
393
394   if (rtpmpadepay->adu_frames->head == rtpmpadepay->cur_adu_frame)
395     rtpmpadepay->cur_adu_frame = NULL;
396
397   head = g_queue_pop_head (rtpmpadepay->adu_frames);
398   g_assert (head->buffer);
399   gst_rtp_mpa_robust_depay_free_frame (head);
400
401   return;
402 }
403
404 /* returns TRUE if at least one new ADU frame was enqueued for MP3 conversion.
405  * Takes ownership of @buf. */
406 static gboolean
407 gst_rtp_mpa_robust_depay_deinterleave (GstRtpMPARobustDepay * rtpmpadepay,
408     GstBuffer * buf)
409 {
410   gboolean ret = FALSE;
411   guint8 *data;
412   guint val, iindex, icc;
413
414   data = GST_BUFFER_DATA (buf);
415   val = GST_READ_UINT16_BE (data) >> 5;
416   iindex = val >> 3;
417   icc = val & 0x7;
418
419   GST_LOG_OBJECT (rtpmpadepay, "sync: 0x%x, index: %u, cycle count: %u",
420       val, iindex, icc);
421
422   /* basic case; no interleaving ever seen */
423   if (val == 0x7ff && rtpmpadepay->last_icc < 0) {
424     ret = gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay, buf);
425   } else {
426     if (G_UNLIKELY (rtpmpadepay->last_icc < 0)) {
427       rtpmpadepay->last_icc = icc;
428       rtpmpadepay->last_ii = iindex;
429     }
430     if (icc != rtpmpadepay->last_icc || iindex == rtpmpadepay->last_ii) {
431       gint i;
432
433       for (i = 0; i < 256; ++i) {
434         if (rtpmpadepay->deinter[i] != NULL) {
435           ret |= gst_rtp_mpa_robust_depay_queue_frame (rtpmpadepay,
436               rtpmpadepay->deinter[i]);
437           rtpmpadepay->deinter[i] = NULL;
438         }
439       }
440     }
441     /* rewrite buffer sync header */
442     val = GST_READ_UINT16_BE (buf);
443     val = (0x7ff << 5) | val;
444     GST_WRITE_UINT16_BE (buf, val);
445     /* store and keep track of last indices */
446     rtpmpadepay->last_icc = icc;
447     rtpmpadepay->last_ii = iindex;
448     rtpmpadepay->deinter[iindex] = buf;
449   }
450
451   return ret;
452 }
453
454 /* Head ADU frame corresponds to mp3_frame (i.e. in header in side-info) that
455  * is currently being written
456  * cur_adu_frame refers to ADU frame whose data should be bytewritten next
457  * (possibly starting from offset rather than start 0) (and is typicall tail
458  * at time of last push round).
459  * If at start, position where it should start writing depends on (data) sizes
460  * of previous mp3 frames (corresponding to foregoing ADU frames) kept in size,
461  * and its backpointer */
462 static GstFlowReturn
463 gst_rtp_mpa_robust_depay_push_mp3_frames (GstRtpMPARobustDepay * rtpmpadepay)
464 {
465   GstBuffer *buf;
466   GstADUFrame *frame, *head;
467   gint av;
468   GstFlowReturn ret = GST_FLOW_OK;
469
470   while (1) {
471
472     if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame)) {
473       rtpmpadepay->cur_adu_frame = rtpmpadepay->adu_frames->head;
474       rtpmpadepay->offset = 0;
475       rtpmpadepay->size = 0;
476     }
477
478     if (G_UNLIKELY (!rtpmpadepay->cur_adu_frame))
479       break;
480
481     frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
482     head = (GstADUFrame *) rtpmpadepay->adu_frames->head->data;
483
484     /* special case: non-layer III are sent straight through */
485     if (G_UNLIKELY (frame->layer != 3)) {
486       GST_DEBUG_OBJECT (rtpmpadepay, "layer %d frame, sending as-is",
487           frame->layer);
488       gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpmpadepay),
489           frame->buffer);
490       frame->buffer = NULL;
491       /* and remove it from any further consideration */
492       g_slice_free (GstADUFrame, frame);
493       g_queue_delete_link (rtpmpadepay->adu_frames, rtpmpadepay->cur_adu_frame);
494       rtpmpadepay->cur_adu_frame = NULL;
495       continue;
496     }
497
498     if (rtpmpadepay->offset == GST_BUFFER_SIZE (frame->buffer)) {
499       if (g_list_next (rtpmpadepay->cur_adu_frame)) {
500         GST_LOG_OBJECT (rtpmpadepay,
501             "moving to next ADU frame, size %d, side_info %d",
502             frame->size, frame->side_info);
503         rtpmpadepay->size += frame->data_size;
504         rtpmpadepay->cur_adu_frame = g_list_next (rtpmpadepay->cur_adu_frame);
505         frame = (GstADUFrame *) rtpmpadepay->cur_adu_frame->data;
506         rtpmpadepay->offset = 0;
507         /* layer I and II packets have no bitreservoir and must be sent as-is;
508          * so flush any pending frame */
509         if (G_UNLIKELY (frame->layer != 3 && rtpmpadepay->mp3_frame))
510           goto flush;
511       } else {
512         break;
513       }
514     }
515
516     if (G_UNLIKELY (!rtpmpadepay->mp3_frame)) {
517       GST_LOG_OBJECT (rtpmpadepay,
518           "setting up new MP3 frame of size %d, side_info %d",
519           head->size, head->side_info);
520       rtpmpadepay->mp3_frame = gst_byte_writer_new_with_size (head->size, TRUE);
521       /* 0-fill possible gaps */
522       gst_byte_writer_fill (rtpmpadepay->mp3_frame, 0, head->size);
523       gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, 0);
524       /* bytewriter corresponds to head frame,
525        * i.e. the header and the side info must match */
526       gst_byte_writer_put_data (rtpmpadepay->mp3_frame,
527           GST_BUFFER_DATA (head->buffer), 4 + head->side_info);
528     }
529
530     buf = frame->buffer;
531     av = gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame);
532     GST_LOG_OBJECT (rtpmpadepay, "current mp3 frame remaining: %d", av);
533     GST_LOG_OBJECT (rtpmpadepay, "accumulated ADU frame data_size: %d",
534         rtpmpadepay->size);
535
536     if (rtpmpadepay->offset) {
537       /* no need to position, simply append */
538       g_assert (GST_BUFFER_SIZE (buf) > rtpmpadepay->offset);
539       av = MIN (av, GST_BUFFER_SIZE (buf) - rtpmpadepay->offset);
540       GST_LOG_OBJECT (rtpmpadepay,
541           "appending %d bytes from ADU frame at offset %d", av,
542           rtpmpadepay->offset);
543       gst_byte_writer_put_data (rtpmpadepay->mp3_frame,
544           GST_BUFFER_DATA (buf) + rtpmpadepay->offset, av);
545       rtpmpadepay->offset += av;
546     } else {
547       gint pos, tpos;
548
549       /* position writing according to ADU frame backpointer */
550       pos = gst_byte_writer_get_pos (rtpmpadepay->mp3_frame);
551       tpos = rtpmpadepay->size - frame->backpointer + 4 + head->side_info;
552       GST_LOG_OBJECT (rtpmpadepay, "current MP3 frame at position %d, "
553           "starting new ADU frame data at offset %d", pos, tpos);
554       if (tpos < pos) {
555         GstADUFrame *dummy;
556
557         /* try to insert as few frames as possible,
558          * so go for a reasonably large dummy frame size */
559         GST_LOG_OBJECT (rtpmpadepay,
560             "overlapping previous data; inserting dummy frame");
561         dummy =
562             gst_rtp_mpa_robust_depay_generate_dummy_frame (rtpmpadepay, frame);
563         g_queue_insert_before (rtpmpadepay->adu_frames,
564             rtpmpadepay->cur_adu_frame, dummy);
565         /* offset is known to be zero, so we can shift current one */
566         rtpmpadepay->cur_adu_frame = rtpmpadepay->cur_adu_frame->prev;
567         if (!rtpmpadepay->size) {
568           g_assert (rtpmpadepay->cur_adu_frame ==
569               rtpmpadepay->adu_frames->head);
570           GST_LOG_OBJECT (rtpmpadepay, "... which is new head frame");
571           gst_byte_writer_free (rtpmpadepay->mp3_frame);
572           rtpmpadepay->mp3_frame = NULL;
573         }
574         /* ... and continue adding that empty one immediately,
575          * and then see if that provided enough extra space */
576         continue;
577       } else if (tpos >= pos + av) {
578         /* ADU frame no longer needs current MP3 frame; move to its end */
579         GST_LOG_OBJECT (rtpmpadepay, "passed current MP3 frame");
580         gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, pos + av);
581       } else {
582         /* position and append */
583         GST_LOG_OBJECT (rtpmpadepay, "adding to current MP3 frame");
584         gst_byte_writer_set_pos (rtpmpadepay->mp3_frame, tpos);
585         av = MIN (av, GST_BUFFER_SIZE (buf) - 4 - frame->side_info);
586         gst_byte_writer_put_data (rtpmpadepay->mp3_frame,
587             GST_BUFFER_DATA (buf) + 4 + frame->side_info, av);
588         rtpmpadepay->offset += av + 4 + frame->side_info;
589       }
590     }
591
592     /* if mp3 frame filled, send on its way */
593     if (gst_byte_writer_get_remaining (rtpmpadepay->mp3_frame) == 0) {
594     flush:
595       buf = gst_byte_writer_free_and_get_buffer (rtpmpadepay->mp3_frame);
596       rtpmpadepay->mp3_frame = NULL;
597       GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_TIMESTAMP (head->buffer);
598       /* no longer need head ADU frame header and side info */
599       /* NOTE maybe head == current, then size and offset go off a bit,
600        * but current gets reset to NULL, and then also offset and size */
601       rtpmpadepay->size -= head->data_size;
602       gst_rtp_mpa_robust_depay_dequeue_frame (rtpmpadepay);
603       /* send */
604       ret = gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpmpadepay),
605           buf);
606     }
607   }
608
609   return ret;
610 }
611
612 /* process ADU frame @buf through:
613  * - deinterleaving
614  * - converting to MP3 frames
615  * Takes ownership of @buf.
616  */
617 static GstFlowReturn
618 gst_rtp_mpa_robust_depay_submit_adu (GstRtpMPARobustDepay * rtpmpadepay,
619     GstBuffer * buf)
620 {
621   if (gst_rtp_mpa_robust_depay_deinterleave (rtpmpadepay, buf))
622     return gst_rtp_mpa_robust_depay_push_mp3_frames (rtpmpadepay);
623
624   return GST_FLOW_OK;
625 }
626
627 static GstBuffer *
628 gst_rtp_mpa_robust_depay_process (GstBaseRTPDepayload * depayload,
629     GstBuffer * buf)
630 {
631   GstRtpMPARobustDepay *rtpmpadepay;
632   gint payload_len, offset;
633   guint8 *payload;
634   gboolean cont, dtype;
635   guint av, size;
636   GstClockTime timestamp;
637
638   rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (depayload);
639
640   payload_len = gst_rtp_buffer_get_payload_len (buf);
641   timestamp = GST_BUFFER_TIMESTAMP (buf);
642
643   if (payload_len <= 1)
644     goto short_read;
645
646   payload = gst_rtp_buffer_get_payload (buf);
647   offset = 0;
648   GST_LOG_OBJECT (rtpmpadepay, "payload_len: %d", payload_len);
649
650   /* strip off descriptor
651    *
652    *  0                   1
653    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
654    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
655    * |C|T|            ADU size         |
656    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
657    *
658    * C: if 1, data is continuation
659    * T: if 1, size is 14 bits, otherwise 6 bits
660    * ADU size: size of following packet (not including descriptor)
661    */
662   while (payload_len) {
663     if (G_LIKELY (rtpmpadepay->has_descriptor)) {
664       cont = !!(payload[offset] & 0x80);
665       dtype = !!(payload[offset] & 0x40);
666       if (dtype) {
667         size = (payload[offset] & 0x3f) << 8 | payload[offset + 1];
668         payload_len--;
669         offset++;
670       } else if (payload_len >= 2) {
671         size = (payload[offset] & 0x3f);
672         payload_len -= 2;
673         offset += 2;
674       } else {
675         goto short_read;
676       }
677     } else {
678       cont = FALSE;
679       dtype = -1;
680       size = payload_len;
681     }
682
683     GST_LOG_OBJECT (rtpmpadepay, "offset %d has cont: %d, dtype: %d, size: %d",
684         offset, cont, dtype, size);
685
686     buf = gst_rtp_buffer_get_payload_subbuffer (buf, offset,
687         MIN (size, payload_len));
688
689     if (cont) {
690       av = gst_adapter_available (rtpmpadepay->adapter);
691       if (G_UNLIKELY (!av)) {
692         GST_DEBUG_OBJECT (rtpmpadepay,
693             "discarding continuation fragment without prior fragment");
694         gst_buffer_unref (buf);
695       } else {
696         av += GST_BUFFER_SIZE (buf);
697         gst_adapter_push (rtpmpadepay->adapter, buf);
698         if (av == size) {
699           timestamp = gst_adapter_prev_timestamp (rtpmpadepay->adapter, NULL);
700           buf = gst_adapter_take_buffer (rtpmpadepay->adapter, size);
701           GST_BUFFER_TIMESTAMP (buf) = timestamp;
702           gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
703         } else if (av > size) {
704           GST_DEBUG_OBJECT (rtpmpadepay,
705               "assembled ADU size %d larger than expected %d; discarding",
706               av, size);
707           gst_adapter_clear (rtpmpadepay->adapter);
708         }
709       }
710       size = payload_len;
711     } else {
712       /* not continuation, first fragment or whole ADU */
713       if (payload_len == size) {
714         /* whole ADU */
715         GST_BUFFER_TIMESTAMP (buf) = timestamp;
716         gst_rtp_mpa_robust_depay_submit_adu (rtpmpadepay, buf);
717       } else if (payload_len < size) {
718         /* first fragment */
719         gst_adapter_push (rtpmpadepay->adapter, buf);
720         size = payload_len;
721       }
722     }
723
724     offset += size;
725     payload_len -= size;
726
727     /* timestamp applies to first payload, no idea for subsequent ones */
728     timestamp = GST_CLOCK_TIME_NONE;
729   }
730
731   return NULL;
732
733   /* ERRORS */
734 short_read:
735   {
736     GST_ELEMENT_WARNING (rtpmpadepay, STREAM, DECODE,
737         (NULL), ("Packet contains invalid data"));
738     return NULL;
739   }
740 }
741
742 static GstStateChangeReturn
743 gst_rtp_mpa_robust_change_state (GstElement * element,
744     GstStateChange transition)
745 {
746   GstStateChangeReturn ret;
747   GstRtpMPARobustDepay *rtpmpadepay;
748
749   rtpmpadepay = GST_RTP_MPA_ROBUST_DEPAY (element);
750
751   switch (transition) {
752     case GST_STATE_CHANGE_READY_TO_PAUSED:
753       rtpmpadepay->last_ii = -1;
754       rtpmpadepay->last_icc = -1;
755       rtpmpadepay->size = 0;
756       rtpmpadepay->offset = 0;
757     default:
758       break;
759   }
760
761   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
762   if (ret != GST_STATE_CHANGE_SUCCESS)
763     return ret;
764
765   switch (transition) {
766     case GST_STATE_CHANGE_PAUSED_TO_READY:
767     {
768       gint i;
769
770       gst_adapter_clear (rtpmpadepay->adapter);
771       for (i = 0; i < G_N_ELEMENTS (rtpmpadepay->deinter); i++) {
772         gst_buffer_replace (&rtpmpadepay->deinter[i], NULL);
773       }
774       rtpmpadepay->cur_adu_frame = NULL;
775       g_queue_foreach (rtpmpadepay->adu_frames,
776           (GFunc) gst_rtp_mpa_robust_depay_free_frame, NULL);
777       g_queue_clear (rtpmpadepay->adu_frames);
778       break;
779     }
780     default:
781       break;
782   }
783
784   return ret;
785 }
786
787 gboolean
788 gst_rtp_mpa_robust_depay_plugin_init (GstPlugin * plugin)
789 {
790   return gst_element_register (plugin, "rtpmparobustdepay",
791       GST_RANK_SECONDARY, GST_TYPE_RTP_MPA_ROBUST_DEPAY);
792 }