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