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