489f6a8bc8decd27e433aed1d06f0d9914363fa5
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpgstdepay.c
1 /* GStreamer
2  * Copyright (C) <2010> Wim Taymans <wim.taymans@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include "gstrtpgstdepay.h"
28 #include "gstrtputils.h"
29
30 #include <gst/video/video.h>
31
32 GST_DEBUG_CATEGORY_STATIC (rtpgstdepay_debug);
33 #define GST_CAT_DEFAULT (rtpgstdepay_debug)
34
35 static GstStaticPadTemplate gst_rtp_gst_depay_src_template =
36 GST_STATIC_PAD_TEMPLATE ("src",
37     GST_PAD_SRC,
38     GST_PAD_ALWAYS,
39     GST_STATIC_CAPS_ANY);
40
41 static GstStaticPadTemplate gst_rtp_gst_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) \"application\", "
47         "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
48     );
49
50 #define gst_rtp_gst_depay_parent_class parent_class
51 G_DEFINE_TYPE (GstRtpGSTDepay, gst_rtp_gst_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
52
53 static void gst_rtp_gst_depay_finalize (GObject * object);
54
55 static gboolean gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay,
56     GstEvent * event);
57 static GstStateChangeReturn gst_rtp_gst_depay_change_state (GstElement *
58     element, GstStateChange transition);
59
60 static void gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean
61     full);
62 static gboolean gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload,
63     GstCaps * caps);
64 static GstBuffer *gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload,
65     GstRTPBuffer * rtp);
66
67 static void
68 gst_rtp_gst_depay_class_init (GstRtpGSTDepayClass * klass)
69 {
70   GObjectClass *gobject_class;
71   GstElementClass *gstelement_class;
72   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
73
74   GST_DEBUG_CATEGORY_INIT (rtpgstdepay_debug, "rtpgstdepay", 0,
75       "Gstreamer RTP Depayloader");
76
77   gobject_class = (GObjectClass *) klass;
78   gstelement_class = (GstElementClass *) klass;
79   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
80
81   gobject_class->finalize = gst_rtp_gst_depay_finalize;
82
83   gstelement_class->change_state = gst_rtp_gst_depay_change_state;
84
85   gst_element_class_add_static_pad_template (gstelement_class,
86       &gst_rtp_gst_depay_src_template);
87   gst_element_class_add_static_pad_template (gstelement_class,
88       &gst_rtp_gst_depay_sink_template);
89
90   gst_element_class_set_static_metadata (gstelement_class,
91       "GStreamer depayloader", "Codec/Depayloader/Network",
92       "Extracts GStreamer buffers from RTP packets",
93       "Wim Taymans <wim.taymans@gmail.com>");
94
95   gstrtpbasedepayload_class->handle_event = gst_rtp_gst_depay_handle_event;
96   gstrtpbasedepayload_class->set_caps = gst_rtp_gst_depay_setcaps;
97   gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_gst_depay_process;
98 }
99
100 static void
101 gst_rtp_gst_depay_init (GstRtpGSTDepay * rtpgstdepay)
102 {
103   rtpgstdepay->adapter = gst_adapter_new ();
104 }
105
106 static void
107 gst_rtp_gst_depay_finalize (GObject * object)
108 {
109   GstRtpGSTDepay *rtpgstdepay;
110
111   rtpgstdepay = GST_RTP_GST_DEPAY (object);
112
113   gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
114   g_object_unref (rtpgstdepay->adapter);
115
116   G_OBJECT_CLASS (parent_class)->finalize (object);
117 }
118
119 static gboolean
120 store_cache (GstRtpGSTDepay * rtpgstdepay, guint CV, GstCaps * caps)
121 {
122   gboolean changed = FALSE;
123
124   if (caps && rtpgstdepay->CV_cache[CV])
125     changed = !gst_caps_is_strictly_equal (caps, rtpgstdepay->CV_cache[CV]);
126
127   if (rtpgstdepay->CV_cache[CV])
128     gst_caps_unref (rtpgstdepay->CV_cache[CV]);
129   rtpgstdepay->CV_cache[CV] = caps;
130
131   return changed;
132 }
133
134 static void
135 gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean full)
136 {
137   guint i;
138
139   gst_adapter_clear (rtpgstdepay->adapter);
140   if (full) {
141     rtpgstdepay->current_CV = 0;
142     for (i = 0; i < 8; i++)
143       store_cache (rtpgstdepay, i, NULL);
144     g_free (rtpgstdepay->stream_id);
145     rtpgstdepay->stream_id = NULL;
146     if (rtpgstdepay->tags)
147       gst_tag_list_unref (rtpgstdepay->tags);
148     rtpgstdepay->tags = NULL;
149   }
150 }
151
152 static gboolean
153 gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
154 {
155   GstRtpGSTDepay *rtpgstdepay;
156   GstStructure *structure;
157   gint clock_rate;
158   gboolean res;
159   const gchar *capsenc;
160
161   rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
162
163   structure = gst_caps_get_structure (caps, 0);
164
165   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
166     clock_rate = 90000;
167   depayload->clock_rate = clock_rate;
168
169   capsenc = gst_structure_get_string (structure, "caps");
170   if (capsenc) {
171     GstCaps *outcaps;
172     gsize out_len;
173     gchar *capsstr;
174     const gchar *capsver;
175     guint CV;
176
177     /* decode caps */
178     capsstr = (gchar *) g_base64_decode (capsenc, &out_len);
179     outcaps = gst_caps_from_string (capsstr);
180     g_free (capsstr);
181
182     /* parse version */
183     capsver = gst_structure_get_string (structure, "capsversion");
184     if (capsver) {
185       CV = atoi (capsver);
186     } else {
187       /* no version, assume 0 */
188       CV = 0;
189     }
190     /* store in cache */
191     rtpgstdepay->current_CV = CV;
192     gst_caps_ref (outcaps);
193     store_cache (rtpgstdepay, CV, outcaps);
194
195     res = gst_pad_set_caps (depayload->srcpad, outcaps);
196     gst_caps_unref (outcaps);
197   } else {
198     GST_WARNING_OBJECT (depayload, "no caps given");
199     rtpgstdepay->current_CV = -1;
200     res = TRUE;
201   }
202
203   return res;
204 }
205
206 static gboolean
207 read_length (GstRtpGSTDepay * rtpgstdepay, guint8 * data, guint size,
208     guint * length, guint * skip)
209 {
210   guint b, len, offset;
211
212   /* start reading the length, we need this to skip to the data later */
213   len = offset = 0;
214   do {
215     if (offset >= size)
216       return FALSE;
217     b = data[offset++];
218     len = (len << 7) | (b & 0x7f);
219   } while (b & 0x80);
220
221   /* check remaining buffer size */
222   if (size - offset < len)
223     return FALSE;
224
225   *length = len;
226   *skip = offset;
227
228   return TRUE;
229 }
230
231 static GstCaps *
232 read_caps (GstRtpGSTDepay * rtpgstdepay, GstBuffer * buf, guint * skip)
233 {
234   guint offset, length;
235   GstCaps *caps;
236   GstMapInfo map;
237
238   gst_buffer_map (buf, &map, GST_MAP_READ);
239
240   GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
241
242   if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
243     goto too_small;
244
245   if (length == 0 || map.data[offset + length - 1] != '\0')
246     goto invalid_buffer;
247
248   GST_DEBUG_OBJECT (rtpgstdepay, "parsing caps %s", &map.data[offset]);
249
250   /* parse and store in cache */
251   caps = gst_caps_from_string ((gchar *) & map.data[offset]);
252   gst_buffer_unmap (buf, &map);
253
254   *skip = length + offset;
255
256   return caps;
257
258 too_small:
259   {
260     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
261         ("Buffer too small."), (NULL));
262     gst_buffer_unmap (buf, &map);
263     return NULL;
264   }
265 invalid_buffer:
266   {
267     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
268         ("caps string not 0-terminated."), (NULL));
269     gst_buffer_unmap (buf, &map);
270     return NULL;
271   }
272 }
273
274 static GstEvent *
275 read_event (GstRtpGSTDepay * rtpgstdepay, guint type,
276     GstBuffer * buf, guint * skip)
277 {
278   guint offset, length;
279   GstStructure *s;
280   GstEvent *event;
281   GstEventType etype;
282   gchar *end;
283   GstMapInfo map;
284
285   gst_buffer_map (buf, &map, GST_MAP_READ);
286
287   GST_DEBUG_OBJECT (rtpgstdepay, "buffer size %" G_GSIZE_FORMAT, map.size);
288
289   if (!read_length (rtpgstdepay, map.data, map.size, &length, &offset))
290     goto too_small;
291
292   if (length == 0)
293     goto invalid_buffer;
294   /* backward compat, old payloader did not put 0-byte at the end */
295   if (map.data[offset + length - 1] != '\0'
296       && map.data[offset + length - 1] != ';')
297     goto invalid_buffer;
298
299   GST_DEBUG_OBJECT (rtpgstdepay, "parsing event %s", &map.data[offset]);
300
301   /* parse */
302   s = gst_structure_from_string ((gchar *) & map.data[offset], &end);
303   gst_buffer_unmap (buf, &map);
304
305   if (s == NULL)
306     goto parse_failed;
307
308   switch (type) {
309     case 1:
310       etype = GST_EVENT_TAG;
311       break;
312     case 2:
313       etype = GST_EVENT_CUSTOM_DOWNSTREAM;
314       break;
315     case 3:
316       etype = GST_EVENT_CUSTOM_BOTH;
317       break;
318     case 4:
319       etype = GST_EVENT_STREAM_START;
320       break;
321     default:
322       goto unknown_event;
323   }
324   event = gst_event_new_custom (etype, s);
325
326   *skip = length + offset;
327
328   return event;
329
330 too_small:
331   {
332     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
333         ("Buffer too small."), (NULL));
334     gst_buffer_unmap (buf, &map);
335     return NULL;
336   }
337 invalid_buffer:
338   {
339     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
340         ("event string not 0-terminated."), (NULL));
341     gst_buffer_unmap (buf, &map);
342     return NULL;
343   }
344 parse_failed:
345   {
346     GST_WARNING_OBJECT (rtpgstdepay, "could not parse event");
347     return NULL;
348   }
349 unknown_event:
350   {
351     GST_DEBUG_OBJECT (rtpgstdepay, "unknown event type");
352     gst_structure_free (s);
353     return NULL;
354   }
355 }
356
357 static void
358 store_event (GstRtpGSTDepay * rtpgstdepay, GstEvent * event)
359 {
360   gboolean do_push = FALSE;
361
362   switch (GST_EVENT_TYPE (event)) {
363     case GST_EVENT_TAG:
364     {
365       GstTagList *old, *tags;
366
367       gst_event_parse_tag (event, &tags);
368
369       old = rtpgstdepay->tags;
370       if (!old || !gst_tag_list_is_equal (old, tags)) {
371         do_push = TRUE;
372         if (old)
373           gst_tag_list_unref (old);
374         rtpgstdepay->tags = gst_tag_list_ref (tags);
375       }
376       break;
377     }
378     case GST_EVENT_CUSTOM_DOWNSTREAM:
379     case GST_EVENT_CUSTOM_BOTH:
380       /* always push custom events */
381       do_push = TRUE;
382       break;
383     case GST_EVENT_STREAM_START:
384     {
385       gchar *old;
386       const gchar *stream_id = NULL;
387
388       gst_event_parse_stream_start (event, &stream_id);
389
390       old = rtpgstdepay->stream_id;
391       if (!old || g_strcmp0 (old, stream_id)) {
392         do_push = TRUE;
393         g_free (old);
394         rtpgstdepay->stream_id = g_strdup (stream_id);
395       }
396       break;
397     }
398     default:
399       /* unknown event, don't push */
400       break;
401   }
402   if (do_push)
403     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD (rtpgstdepay)->srcpad, event);
404   else
405     gst_event_unref (event);
406 }
407
408 static GstBuffer *
409 gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
410 {
411   GstRtpGSTDepay *rtpgstdepay;
412   GstBuffer *subbuf, *outbuf = NULL;
413   gint payload_len;
414   guint8 *payload;
415   guint CV, frag_offset, avail, offset;
416
417   rtpgstdepay = GST_RTP_GST_DEPAY (depayload);
418
419   payload_len = gst_rtp_buffer_get_payload_len (rtp);
420
421   if (payload_len <= 8)
422     goto empty_packet;
423
424   if (GST_BUFFER_IS_DISCONT (rtp->buffer)) {
425     GST_WARNING_OBJECT (rtpgstdepay, "DISCONT, clear adapter");
426     gst_adapter_clear (rtpgstdepay->adapter);
427   }
428
429   payload = gst_rtp_buffer_get_payload (rtp);
430
431   /* strip off header
432    *
433    *  0                   1                   2                   3
434    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
435    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
436    * |C| CV  |D|0|0|0|     ETYPE     |  MBZ                          |
437    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
438    * |                          Frag_offset                          |
439    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
440    */
441   frag_offset =
442       (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | payload[7];
443
444   avail = gst_adapter_available (rtpgstdepay->adapter);
445   if (avail != frag_offset)
446     goto wrong_frag;
447
448   /* subbuffer skipping the 8 header bytes */
449   subbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
450   gst_adapter_push (rtpgstdepay->adapter, subbuf);
451
452   offset = 0;
453   if (gst_rtp_buffer_get_marker (rtp)) {
454     guint avail;
455     GstCaps *outcaps;
456
457     /* take the buffer */
458     avail = gst_adapter_available (rtpgstdepay->adapter);
459     outbuf = gst_adapter_take_buffer (rtpgstdepay->adapter, avail);
460
461     CV = (payload[0] >> 4) & 0x7;
462
463     if (payload[0] & 0x80) {
464       guint size;
465
466       /* C bit, we have inline caps */
467       outcaps = read_caps (rtpgstdepay, outbuf, &size);
468       if (outcaps == NULL)
469         goto no_caps;
470
471       GST_DEBUG_OBJECT (rtpgstdepay,
472           "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, size, outcaps);
473
474       if (store_cache (rtpgstdepay, CV, outcaps))
475         gst_pad_set_caps (depayload->srcpad, outcaps);
476
477       /* skip caps */
478       offset += size;
479       avail -= size;
480     }
481     if (payload[1]) {
482       guint size;
483       GstEvent *event;
484
485       /* we have an event */
486       event = read_event (rtpgstdepay, payload[1], outbuf, &size);
487       if (event == NULL)
488         goto no_event;
489
490       GST_DEBUG_OBJECT (rtpgstdepay,
491           "inline event, length %u, %" GST_PTR_FORMAT, size, event);
492
493       store_event (rtpgstdepay, event);
494
495       /* no buffer after event */
496       avail = 0;
497     }
498
499     if (avail) {
500       if (offset != 0) {
501         GstBuffer *temp;
502
503         GST_DEBUG_OBJECT (rtpgstdepay, "sub buffer: offset %u, size %u", offset,
504             avail);
505
506         temp =
507             gst_buffer_copy_region (outbuf, GST_BUFFER_COPY_ALL, offset, avail);
508
509         gst_buffer_unref (outbuf);
510         outbuf = temp;
511       }
512
513       /* see what caps we need */
514       if (CV != rtpgstdepay->current_CV) {
515         /* we need to switch caps, check if we have the caps */
516         if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL)
517           goto missing_caps;
518
519         GST_DEBUG_OBJECT (rtpgstdepay,
520             "need caps switch from %u to %u, %" GST_PTR_FORMAT,
521             rtpgstdepay->current_CV, CV, outcaps);
522
523         /* and set caps */
524         if (gst_pad_set_caps (depayload->srcpad, outcaps))
525           rtpgstdepay->current_CV = CV;
526       }
527
528       if (payload[0] & 0x8)
529         GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
530     } else {
531       gst_buffer_unref (outbuf);
532       outbuf = NULL;
533     }
534   }
535
536   if (outbuf) {
537     gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpgstdepay), outbuf, 0);
538   }
539
540   return outbuf;
541
542   /* ERRORS */
543 empty_packet:
544   {
545     GST_ELEMENT_WARNING (rtpgstdepay, STREAM, DECODE,
546         ("Empty Payload."), (NULL));
547     return NULL;
548   }
549 wrong_frag:
550   {
551     gst_adapter_clear (rtpgstdepay->adapter);
552     GST_LOG_OBJECT (rtpgstdepay, "wrong fragment, skipping");
553     return NULL;
554   }
555 no_caps:
556   {
557     GST_WARNING_OBJECT (rtpgstdepay, "failed to parse caps");
558     gst_buffer_unref (outbuf);
559     return NULL;
560   }
561 no_event:
562   {
563     GST_WARNING_OBJECT (rtpgstdepay, "failed to parse event");
564     gst_buffer_unref (outbuf);
565     return NULL;
566   }
567 missing_caps:
568   {
569     GST_INFO_OBJECT (rtpgstdepay, "No caps received yet %u", CV);
570     gst_buffer_unref (outbuf);
571
572     gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (rtpgstdepay),
573         gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
574             TRUE, 0));
575
576     return NULL;
577   }
578 }
579
580 static gboolean
581 gst_rtp_gst_depay_handle_event (GstRTPBaseDepayload * depay, GstEvent * event)
582 {
583   GstRtpGSTDepay *rtpgstdepay;
584
585   rtpgstdepay = GST_RTP_GST_DEPAY (depay);
586
587   switch (GST_EVENT_TYPE (event)) {
588     case GST_EVENT_FLUSH_STOP:
589       gst_rtp_gst_depay_reset (rtpgstdepay, FALSE);
590       break;
591     default:
592       break;
593   }
594
595   return
596       GST_RTP_BASE_DEPAYLOAD_CLASS (parent_class)->handle_event (depay, event);
597 }
598
599
600 static GstStateChangeReturn
601 gst_rtp_gst_depay_change_state (GstElement * element, GstStateChange transition)
602 {
603   GstRtpGSTDepay *rtpgstdepay;
604   GstStateChangeReturn ret;
605
606   rtpgstdepay = GST_RTP_GST_DEPAY (element);
607
608   switch (transition) {
609     case GST_STATE_CHANGE_READY_TO_PAUSED:
610       gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
611       break;
612     default:
613       break;
614   }
615
616   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
617
618   switch (transition) {
619     case GST_STATE_CHANGE_PAUSED_TO_READY:
620       gst_rtp_gst_depay_reset (rtpgstdepay, TRUE);
621       break;
622     default:
623       break;
624   }
625   return ret;
626 }
627
628
629 gboolean
630 gst_rtp_gst_depay_plugin_init (GstPlugin * plugin)
631 {
632   return gst_element_register (plugin, "rtpgstdepay",
633       GST_RANK_MARGINAL, GST_TYPE_RTP_GST_DEPAY);
634 }