rtph264pay: use buffer lists
[platform/upstream/gstreamer.git] / gst / rtp / gstrtph264pay.c
1 /* ex: set tabstop=2 shiftwidth=2 expandtab: */
2 /* GStreamer
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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 <gst/rtp/gstrtpbuffer.h>
28 #include <gst/pbutils/pbutils.h>
29
30 #include "gstrtph264pay.h"
31
32
33 #define IDR_TYPE_ID  5
34 #define SPS_TYPE_ID  7
35 #define PPS_TYPE_ID  8
36
37 GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug);
38 #define GST_CAT_DEFAULT (rtph264pay_debug)
39
40 /* references:
41  *
42  * RFC 3984
43  */
44
45 static GstStaticPadTemplate gst_rtp_h264_pay_sink_template =
46     GST_STATIC_PAD_TEMPLATE ("sink",
47     GST_PAD_SINK,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("video/x-h264, "
50         "stream-format = (string) avc, alignment = (string) au;"
51         "video/x-h264, "
52         "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
53     );
54
55 static GstStaticPadTemplate gst_rtp_h264_pay_src_template =
56 GST_STATIC_PAD_TEMPLATE ("src",
57     GST_PAD_SRC,
58     GST_PAD_ALWAYS,
59     GST_STATIC_CAPS ("application/x-rtp, "
60         "media = (string) \"video\", "
61         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
62         "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
63     );
64
65 #define DEFAULT_SPROP_PARAMETER_SETS    NULL
66 #define DEFAULT_CONFIG_INTERVAL               0
67
68 enum
69 {
70   PROP_0,
71   PROP_SPROP_PARAMETER_SETS,
72   PROP_CONFIG_INTERVAL,
73   PROP_LAST
74 };
75
76 #define IS_ACCESS_UNIT(x) (((x) > 0x00) && ((x) < 0x06))
77
78 static void gst_rtp_h264_pay_finalize (GObject * object);
79
80 static void gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
81     const GValue * value, GParamSpec * pspec);
82 static void gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
83     GValue * value, GParamSpec * pspec);
84
85 static GstCaps *gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload,
86     GstPad * pad, GstCaps * filter);
87 static gboolean gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload,
88     GstCaps * caps);
89 static GstFlowReturn gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * pad,
90     GstBuffer * buffer);
91 static gboolean gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload,
92     GstEvent * event);
93 static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement *
94     element, GstStateChange transition);
95
96 #define gst_rtp_h264_pay_parent_class parent_class
97 G_DEFINE_TYPE (GstRtpH264Pay, gst_rtp_h264_pay, GST_TYPE_RTP_BASE_PAYLOAD);
98
99 static void
100 gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
101 {
102   GObjectClass *gobject_class;
103   GstElementClass *gstelement_class;
104   GstRTPBasePayloadClass *gstrtpbasepayload_class;
105
106   gobject_class = (GObjectClass *) klass;
107   gstelement_class = (GstElementClass *) klass;
108   gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
109
110   gobject_class->set_property = gst_rtp_h264_pay_set_property;
111   gobject_class->get_property = gst_rtp_h264_pay_get_property;
112
113   g_object_class_install_property (G_OBJECT_CLASS (klass),
114       PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
115           "sprop-parameter-sets",
116           "The base64 sprop-parameter-sets to set in out caps (set to NULL to "
117           "extract from stream)",
118           DEFAULT_SPROP_PARAMETER_SETS,
119           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
120
121   g_object_class_install_property (G_OBJECT_CLASS (klass),
122       PROP_CONFIG_INTERVAL,
123       g_param_spec_uint ("config-interval",
124           "SPS PPS Send Interval",
125           "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets "
126           "will be multiplexed in the data stream when detected.) (0 = disabled)",
127           0, 3600, DEFAULT_CONFIG_INTERVAL,
128           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
129       );
130
131   gobject_class->finalize = gst_rtp_h264_pay_finalize;
132
133   gst_element_class_add_pad_template (gstelement_class,
134       gst_static_pad_template_get (&gst_rtp_h264_pay_src_template));
135   gst_element_class_add_pad_template (gstelement_class,
136       gst_static_pad_template_get (&gst_rtp_h264_pay_sink_template));
137
138   gst_element_class_set_static_metadata (gstelement_class, "RTP H264 payloader",
139       "Codec/Payloader/Network/RTP",
140       "Payload-encode H264 video into RTP packets (RFC 3984)",
141       "Laurent Glayal <spglegle@yahoo.fr>");
142
143   gstelement_class->change_state =
144       GST_DEBUG_FUNCPTR (gst_rtp_h264_pay_change_state);
145
146   gstrtpbasepayload_class->get_caps = gst_rtp_h264_pay_getcaps;
147   gstrtpbasepayload_class->set_caps = gst_rtp_h264_pay_setcaps;
148   gstrtpbasepayload_class->handle_buffer = gst_rtp_h264_pay_handle_buffer;
149   gstrtpbasepayload_class->sink_event = gst_rtp_h264_pay_sink_event;
150
151   GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0,
152       "H264 RTP Payloader");
153 }
154
155 static void
156 gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
157 {
158   rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
159   rtph264pay->profile = 0;
160   rtph264pay->sps = NULL;
161   rtph264pay->pps = NULL;
162   rtph264pay->last_spspps = -1;
163   rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
164
165   rtph264pay->adapter = gst_adapter_new ();
166 }
167
168 static void
169 gst_rtp_h264_pay_clear_sps_pps (GstRtpH264Pay * rtph264pay)
170 {
171   g_list_foreach (rtph264pay->sps, (GFunc) gst_mini_object_unref, NULL);
172   g_list_free (rtph264pay->sps);
173   rtph264pay->sps = NULL;
174   g_list_foreach (rtph264pay->pps, (GFunc) gst_mini_object_unref, NULL);
175   g_list_free (rtph264pay->pps);
176   rtph264pay->pps = NULL;
177 }
178
179 static void
180 gst_rtp_h264_pay_finalize (GObject * object)
181 {
182   GstRtpH264Pay *rtph264pay;
183
184   rtph264pay = GST_RTP_H264_PAY (object);
185
186   g_array_free (rtph264pay->queue, TRUE);
187
188   gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
189
190   g_free (rtph264pay->sprop_parameter_sets);
191
192   g_object_unref (rtph264pay->adapter);
193
194   G_OBJECT_CLASS (parent_class)->finalize (object);
195 }
196
197 static const gchar all_levels[][4] = {
198   "1",
199   "1b",
200   "1.1",
201   "1.2",
202   "1.3",
203   "2",
204   "2.1",
205   "2.2",
206   "3",
207   "3.1",
208   "3.2",
209   "4",
210   "4.1",
211   "4.2",
212   "5",
213   "5.1"
214 };
215
216 static GstCaps *
217 gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
218     GstCaps * filter)
219 {
220   GstCaps *template_caps;
221   GstCaps *allowed_caps;
222   GstCaps *caps, *icaps;
223   gboolean append_unrestricted;
224   guint i;
225
226   allowed_caps =
227       gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), filter);
228
229   if (allowed_caps == NULL)
230     return NULL;
231
232   template_caps =
233       gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template);
234
235   if (gst_caps_is_any (allowed_caps)) {
236     caps = gst_caps_ref (template_caps);
237     goto done;
238   }
239
240   if (gst_caps_is_empty (allowed_caps)) {
241     caps = gst_caps_ref (allowed_caps);
242     goto done;
243   }
244
245   caps = gst_caps_new_empty ();
246
247   append_unrestricted = FALSE;
248   for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
249     GstStructure *s = gst_caps_get_structure (allowed_caps, i);
250     GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
251     const gchar *profile_level_id;
252
253     profile_level_id = gst_structure_get_string (s, "profile-level-id");
254
255     if (profile_level_id && strlen (profile_level_id) == 6) {
256       const gchar *profile;
257       const gchar *level;
258       long int spsint;
259       guint8 sps[3];
260
261       spsint = strtol (profile_level_id, NULL, 16);
262       sps[0] = spsint >> 16;
263       sps[1] = spsint >> 8;
264       sps[2] = spsint;
265
266       profile = gst_codec_utils_h264_get_profile (sps, 3);
267       level = gst_codec_utils_h264_get_level (sps, 3);
268
269       if (profile && level) {
270         GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
271             profile, level);
272
273         if (!strcmp (profile, "constrained-baseline"))
274           gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
275         else {
276           GValue val = { 0, };
277           GValue profiles = { 0, };
278
279           g_value_init (&profiles, GST_TYPE_LIST);
280           g_value_init (&val, G_TYPE_STRING);
281
282           g_value_set_static_string (&val, profile);
283           gst_value_list_append_value (&profiles, &val);
284
285           g_value_set_static_string (&val, "constrained-baseline");
286           gst_value_list_append_value (&profiles, &val);
287
288           gst_structure_take_value (new_s, "profile", &profiles);
289         }
290
291         if (!strcmp (level, "1"))
292           gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
293         else {
294           GValue levels = { 0, };
295           GValue val = { 0, };
296           int j;
297
298           g_value_init (&levels, GST_TYPE_LIST);
299           g_value_init (&val, G_TYPE_STRING);
300
301           for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
302             g_value_set_static_string (&val, all_levels[j]);
303             gst_value_list_prepend_value (&levels, &val);
304             if (!strcmp (level, all_levels[j]))
305               break;
306           }
307           gst_structure_take_value (new_s, "level", &levels);
308         }
309       } else {
310         /* Invalid profile-level-id means baseline */
311
312         gst_structure_set (new_s,
313             "profile", G_TYPE_STRING, "constrained-baseline", NULL);
314       }
315     } else {
316       /* No profile-level-id means baseline or unrestricted */
317
318       gst_structure_set (new_s,
319           "profile", G_TYPE_STRING, "constrained-baseline", NULL);
320       append_unrestricted = TRUE;
321     }
322
323     caps = gst_caps_merge_structure (caps, new_s);
324   }
325
326   if (append_unrestricted) {
327     caps =
328         gst_caps_merge_structure (caps, gst_structure_new ("video/x-h264", NULL,
329             NULL));
330   }
331
332   icaps = gst_caps_intersect (caps, template_caps);
333   gst_caps_unref (caps);
334   caps = icaps;
335
336 done:
337
338   gst_caps_unref (template_caps);
339   gst_caps_unref (allowed_caps);
340
341   GST_LOG_OBJECT (payload, "returning caps %" GST_PTR_FORMAT, caps);
342   return caps;
343 }
344
345 /* take the currently configured SPS and PPS lists and set them on the caps as
346  * sprop-parameter-sets */
347 static gboolean
348 gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
349 {
350   GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
351   gchar *profile;
352   gchar *set;
353   GList *walk;
354   GString *sprops;
355   guint count;
356   gboolean res;
357   GstMapInfo map;
358
359   sprops = g_string_new ("");
360   count = 0;
361
362   /* build the sprop-parameter-sets */
363   for (walk = payloader->sps; walk; walk = g_list_next (walk)) {
364     GstBuffer *sps_buf = GST_BUFFER_CAST (walk->data);
365
366     gst_buffer_map (sps_buf, &map, GST_MAP_READ);
367     set = g_base64_encode (map.data, map.size);
368     gst_buffer_unmap (sps_buf, &map);
369
370     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
371     g_free (set);
372     count++;
373   }
374   for (walk = payloader->pps; walk; walk = g_list_next (walk)) {
375     GstBuffer *pps_buf = GST_BUFFER_CAST (walk->data);
376
377     gst_buffer_map (pps_buf, &map, GST_MAP_READ);
378     set = g_base64_encode (map.data, map.size);
379     gst_buffer_unmap (pps_buf, &map);
380
381     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
382     g_free (set);
383     count++;
384   }
385
386   if (G_LIKELY (count)) {
387     /* profile is 24 bit. Force it to respect the limit */
388     profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
389     /* combine into output caps */
390     res = gst_rtp_base_payload_set_outcaps (basepayload,
391         "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
392     g_free (profile);
393   } else {
394     res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
395   }
396   g_string_free (sprops, TRUE);
397
398   return res;
399 }
400
401 static gboolean
402 gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
403 {
404   GstRtpH264Pay *rtph264pay;
405   GstStructure *str;
406   const GValue *value;
407   GstMapInfo map;
408   guint8 *data;
409   gsize size;
410   GstBuffer *buffer;
411   const gchar *alignment, *stream_format;
412
413   rtph264pay = GST_RTP_H264_PAY (basepayload);
414
415   str = gst_caps_get_structure (caps, 0);
416
417   /* we can only set the output caps when we found the sprops and profile
418    * NALs */
419   gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "H264", 90000);
420
421   rtph264pay->alignment = GST_H264_ALIGNMENT_UNKNOWN;
422   alignment = gst_structure_get_string (str, "alignment");
423   if (alignment) {
424     if (g_str_equal (alignment, "au"))
425       rtph264pay->alignment = GST_H264_ALIGNMENT_AU;
426     if (g_str_equal (alignment, "nal"))
427       rtph264pay->alignment = GST_H264_ALIGNMENT_NAL;
428   }
429
430   rtph264pay->stream_format = GST_H264_STREAM_FORMAT_UNKNOWN;
431   stream_format = gst_structure_get_string (str, "stream-format");
432   if (stream_format) {
433     if (g_str_equal (stream_format, "avc"))
434       rtph264pay->stream_format = GST_H264_STREAM_FORMAT_AVC;
435     if (g_str_equal (stream_format, "bytestream"))
436       rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM;
437   }
438
439   /* packetized AVC video has a codec_data */
440   if ((value = gst_structure_get_value (str, "codec_data"))) {
441     guint num_sps, num_pps;
442     gint i, nal_size;
443
444     GST_DEBUG_OBJECT (rtph264pay, "have packetized h264");
445
446     buffer = gst_value_get_buffer (value);
447
448     gst_buffer_map (buffer, &map, GST_MAP_READ);
449     data = map.data;
450     size = map.size;
451
452     /* parse the avcC data */
453     if (size < 7)
454       goto avcc_too_small;
455     /* parse the version, this must be 1 */
456     if (data[0] != 1)
457       goto wrong_version;
458
459     /* AVCProfileIndication */
460     /* profile_compat */
461     /* AVCLevelIndication */
462     rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
463     GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
464
465     /* 6 bits reserved | 2 bits lengthSizeMinusOne */
466     /* this is the number of bytes in front of the NAL units to mark their
467      * length */
468     rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
469     GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
470     /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
471     num_sps = data[5] & 0x1f;
472     GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps);
473
474     data += 6;
475     size -= 6;
476
477     /* create the sprop-parameter-sets */
478     for (i = 0; i < num_sps; i++) {
479       GstBuffer *sps_buf;
480
481       if (size < 2)
482         goto avcc_error;
483
484       nal_size = (data[0] << 8) | data[1];
485       data += 2;
486       size -= 2;
487
488       GST_LOG_OBJECT (rtph264pay, "SPS %d size %d", i, nal_size);
489
490       if (size < nal_size)
491         goto avcc_error;
492
493       /* make a buffer out of it and add to SPS list */
494       sps_buf = gst_buffer_new_and_alloc (nal_size);
495       gst_buffer_fill (sps_buf, 0, data, nal_size);
496       rtph264pay->sps = g_list_append (rtph264pay->sps, sps_buf);
497
498       data += nal_size;
499       size -= nal_size;
500     }
501     if (size < 1)
502       goto avcc_error;
503
504     /* 8 bits numOfPictureParameterSets */
505     num_pps = data[0];
506     data += 1;
507     size -= 1;
508
509     GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps);
510     for (i = 0; i < num_pps; i++) {
511       GstBuffer *pps_buf;
512
513       if (size < 2)
514         goto avcc_error;
515
516       nal_size = (data[0] << 8) | data[1];
517       data += 2;
518       size -= 2;
519
520       GST_LOG_OBJECT (rtph264pay, "PPS %d size %d", i, nal_size);
521
522       if (size < nal_size)
523         goto avcc_error;
524
525       /* make a buffer out of it and add to PPS list */
526       pps_buf = gst_buffer_new_and_alloc (nal_size);
527       gst_buffer_fill (pps_buf, 0, data, nal_size);
528       rtph264pay->pps = g_list_append (rtph264pay->pps, pps_buf);
529
530       data += nal_size;
531       size -= nal_size;
532     }
533     gst_buffer_unmap (buffer, &map);
534     /* and update the caps with the collected data */
535     if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
536       goto set_sps_pps_failed;
537   } else {
538     GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
539   }
540
541   return TRUE;
542
543 avcc_too_small:
544   {
545     GST_ERROR_OBJECT (rtph264pay, "avcC size %" G_GSIZE_FORMAT " < 7", size);
546     goto error;
547   }
548 wrong_version:
549   {
550     GST_ERROR_OBJECT (rtph264pay, "wrong avcC version");
551     goto error;
552   }
553 avcc_error:
554   {
555     GST_ERROR_OBJECT (rtph264pay, "avcC too small ");
556     goto error;
557   }
558 set_sps_pps_failed:
559   {
560     GST_ERROR_OBJECT (rtph264pay, "failed to set sps/pps");
561     goto error;
562   }
563 error:
564   {
565     gst_buffer_unmap (buffer, &map);
566     return FALSE;
567   }
568 }
569
570 static void
571 gst_rtp_h264_pay_parse_sprop_parameter_sets (GstRtpH264Pay * rtph264pay)
572 {
573   const gchar *ps;
574   gchar **params;
575   guint len, num_sps, num_pps;
576   gint i;
577   GstBuffer *buf;
578
579   ps = rtph264pay->sprop_parameter_sets;
580   if (ps == NULL)
581     return;
582
583   gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
584
585   params = g_strsplit (ps, ",", 0);
586   len = g_strv_length (params);
587
588   GST_DEBUG_OBJECT (rtph264pay, "we have %d params", len);
589
590   num_sps = num_pps = 0;
591
592   for (i = 0; params[i]; i++) {
593     gsize nal_len;
594     GstMapInfo map;
595     guint8 *nalp;
596     guint save = 0;
597     gint state = 0;
598     guint8 nal_type;
599
600     nal_len = strlen (params[i]);
601     buf = gst_buffer_new_and_alloc (nal_len);
602
603     gst_buffer_map (buf, &map, GST_MAP_WRITE);
604     nalp = map.data;
605     nal_len = g_base64_decode_step (params[i], nal_len, nalp, &state, &save);
606     nal_type = nalp[0];
607     gst_buffer_unmap (buf, &map);
608     gst_buffer_resize (buf, 0, nal_len);
609
610     if (!nal_len) {
611       gst_buffer_unref (buf);
612       continue;
613     }
614
615     /* append to the right list */
616     if ((nal_type & 0x1f) == 7) {
617       GST_DEBUG_OBJECT (rtph264pay, "adding param %d as SPS %d", i, num_sps);
618       rtph264pay->sps = g_list_append (rtph264pay->sps, buf);
619       num_sps++;
620     } else {
621       GST_DEBUG_OBJECT (rtph264pay, "adding param %d as PPS %d", i, num_pps);
622       rtph264pay->pps = g_list_append (rtph264pay->pps, buf);
623       num_pps++;
624     }
625   }
626   g_strfreev (params);
627 }
628
629 static guint
630 next_start_code (const guint8 * data, guint size)
631 {
632   /* Boyer-Moore string matching algorithm, in a degenerative
633    * sense because our search 'alphabet' is binary - 0 & 1 only.
634    * This allow us to simplify the general BM algorithm to a very
635    * simple form. */
636   /* assume 1 is in the 3th byte */
637   guint offset = 2;
638
639   while (offset < size) {
640     if (1 == data[offset]) {
641       unsigned int shift = offset;
642
643       if (0 == data[--shift]) {
644         if (0 == data[--shift]) {
645           return shift;
646         }
647       }
648       /* The jump is always 3 because of the 1 previously matched.
649        * All the 0's must be after this '1' matched at offset */
650       offset += 3;
651     } else if (0 == data[offset]) {
652       /* maybe next byte is 1? */
653       offset++;
654     } else {
655       /* can jump 3 bytes forward */
656       offset += 3;
657     }
658     /* at each iteration, we rescan in a backward manner until
659      * we match 0.0.1 in reverse order. Since our search string
660      * has only 2 'alpabets' (i.e. 0 & 1), we know that any
661      * mismatch will force us to shift a fixed number of steps */
662   }
663   GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
664
665   return size;
666 }
667
668 static gboolean
669 gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
670     const guint8 * data, guint size, GstClockTime dts, GstClockTime pts)
671 {
672   const guint8 *sps = NULL, *pps = NULL;
673   guint sps_len = 0, pps_len = 0;
674   guint8 header, type;
675   guint len;
676   gboolean updated;
677
678   /* default is no update */
679   updated = FALSE;
680
681   GST_DEBUG ("NAL payload len=%u", size);
682
683   len = size;
684   header = data[0];
685   type = header & 0x1f;
686
687   /* keep sps & pps separately so that we can update either one 
688    * independently. We also record the timestamp of the last SPS/PPS so 
689    * that we can insert them at regular intervals and when needed. */
690   if (SPS_TYPE_ID == type) {
691     /* encode the entire SPS NAL in base64 */
692     GST_DEBUG ("Found SPS %x %x %x Len=%u", (header >> 7),
693         (header >> 5) & 3, type, len);
694
695     sps = data;
696     sps_len = len;
697     /* remember when we last saw SPS */
698     if (pts != -1)
699       payloader->last_spspps = pts;
700   } else if (PPS_TYPE_ID == type) {
701     /* encoder the entire PPS NAL in base64 */
702     GST_DEBUG ("Found PPS %x %x %x Len = %u",
703         (header >> 7), (header >> 5) & 3, type, len);
704
705     pps = data;
706     pps_len = len;
707     /* remember when we last saw PPS */
708     if (pts != -1)
709       payloader->last_spspps = pts;
710   } else {
711     GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
712         (header >> 5) & 3, type, len);
713   }
714
715   /* If we encountered an SPS and/or a PPS, check if it's the
716    * same as the one we have. If not, update our version and
717    * set updated to TRUE
718    */
719   if (sps_len > 0) {
720     GstBuffer *sps_buf;
721
722     if (payloader->sps != NULL) {
723       sps_buf = GST_BUFFER_CAST (payloader->sps->data);
724
725       if (gst_buffer_memcmp (sps_buf, 0, sps, sps_len)) {
726         /* something changed, update */
727         payloader->profile = (sps[1] << 16) + (sps[2] << 8) + sps[3];
728         GST_DEBUG ("Profile level IDC = %06x", payloader->profile);
729         updated = TRUE;
730       }
731     } else {
732       /* no previous SPS, update */
733       updated = TRUE;
734     }
735
736     if (updated) {
737       sps_buf = gst_buffer_new_and_alloc (sps_len);
738       gst_buffer_fill (sps_buf, 0, sps, sps_len);
739
740       if (payloader->sps) {
741         /* replace old buffer */
742         gst_buffer_unref (payloader->sps->data);
743         payloader->sps->data = sps_buf;
744       } else {
745         /* add new buffer */
746         payloader->sps = g_list_prepend (payloader->sps, sps_buf);
747       }
748     }
749   }
750
751   if (pps_len > 0) {
752     GstBuffer *pps_buf;
753
754     if (payloader->pps != NULL) {
755       pps_buf = GST_BUFFER_CAST (payloader->pps->data);
756
757       if (gst_buffer_memcmp (pps_buf, 0, pps, pps_len)) {
758         /* something changed, update */
759         updated = TRUE;
760       }
761     } else {
762       /* no previous SPS, update */
763       updated = TRUE;
764     }
765
766     if (updated) {
767       pps_buf = gst_buffer_new_and_alloc (pps_len);
768       gst_buffer_fill (pps_buf, 0, pps, pps_len);
769
770       if (payloader->pps) {
771         /* replace old buffer */
772         gst_buffer_unref (payloader->pps->data);
773         payloader->pps->data = pps_buf;
774       } else {
775         /* add new buffer */
776         payloader->pps = g_list_prepend (payloader->pps, pps_buf);
777       }
778     }
779   }
780   return updated;
781 }
782
783 static GstFlowReturn
784 gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
785     const guint8 * data, guint size, GstClockTime dts, GstClockTime pts,
786     gboolean end_of_au);
787
788 static GstFlowReturn
789 gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
790     GstRtpH264Pay * rtph264pay, GstClockTime dts, GstClockTime pts)
791 {
792   GstFlowReturn ret = GST_FLOW_OK;
793   GList *walk;
794   GstMapInfo map;
795
796   for (walk = rtph264pay->sps; walk; walk = g_list_next (walk)) {
797     GstBuffer *sps_buf = GST_BUFFER_CAST (walk->data);
798
799     GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
800     /* resend SPS */
801     gst_buffer_map (sps_buf, &map, GST_MAP_READ);
802     ret = gst_rtp_h264_pay_payload_nal (basepayload,
803         map.data, map.size, dts, pts, FALSE);
804     gst_buffer_unmap (sps_buf, &map);
805     /* Not critical here; but throw a warning */
806     if (ret != GST_FLOW_OK)
807       GST_WARNING ("Problem pushing SPS");
808   }
809   for (walk = rtph264pay->pps; walk; walk = g_list_next (walk)) {
810     GstBuffer *pps_buf = GST_BUFFER_CAST (walk->data);
811
812     GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
813     /* resend PPS */
814     gst_buffer_map (pps_buf, &map, GST_MAP_READ);
815     ret = gst_rtp_h264_pay_payload_nal (basepayload,
816         map.data, map.size, dts, pts, FALSE);
817     gst_buffer_unmap (pps_buf, &map);
818     /* Not critical here; but throw a warning */
819     if (ret != GST_FLOW_OK)
820       GST_WARNING ("Problem pushing PPS");
821   }
822
823   if (pts != -1)
824     rtph264pay->last_spspps = pts;
825
826   return ret;
827 }
828
829 static GstFlowReturn
830 gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
831     const guint8 * data, guint size, GstClockTime dts, GstClockTime pts,
832     gboolean end_of_au)
833 {
834   GstRtpH264Pay *rtph264pay;
835   GstFlowReturn ret;
836   guint8 nalType;
837   guint packet_len, payload_len, mtu;
838   GstBuffer *outbuf;
839   guint8 *payload;
840   GstBufferList *list = NULL;
841   gboolean send_spspps;
842   GstRTPBuffer rtp = { NULL };
843
844   rtph264pay = GST_RTP_H264_PAY (basepayload);
845   mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
846
847   nalType = data[0] & 0x1f;
848   GST_DEBUG_OBJECT (rtph264pay, "Processing Buffer with NAL TYPE=%d", nalType);
849
850   /* should set src caps before pushing stuff,
851    * and if we did not see enough SPS/PPS, that may not be the case */
852   if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
853               (basepayload))))
854     gst_rtp_h264_pay_set_sps_pps (basepayload);
855
856   send_spspps = FALSE;
857
858   /* check if we need to emit an SPS/PPS now */
859   if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
860     if (rtph264pay->last_spspps != -1) {
861       guint64 diff;
862
863       GST_LOG_OBJECT (rtph264pay,
864           "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
865           GST_TIME_ARGS (pts), GST_TIME_ARGS (rtph264pay->last_spspps));
866
867       /* calculate diff between last SPS/PPS in milliseconds */
868       if (pts > rtph264pay->last_spspps)
869         diff = pts - rtph264pay->last_spspps;
870       else
871         diff = 0;
872
873       GST_DEBUG_OBJECT (rtph264pay,
874           "interval since last SPS/PPS %" GST_TIME_FORMAT,
875           GST_TIME_ARGS (diff));
876
877       /* bigger than interval, queue SPS/PPS */
878       if (GST_TIME_AS_SECONDS (diff) >= rtph264pay->spspps_interval) {
879         GST_DEBUG_OBJECT (rtph264pay, "time to send SPS/PPS");
880         send_spspps = TRUE;
881       }
882     } else {
883       /* no know previous SPS/PPS time, send now */
884       GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
885       send_spspps = TRUE;
886     }
887   }
888
889   if (send_spspps || rtph264pay->send_spspps) {
890     /* we need to send SPS/PPS now first. FIXME, don't use the pts for
891      * checking when we need to send SPS/PPS but convert to running_time first. */
892     rtph264pay->send_spspps = FALSE;
893     ret = gst_rtp_h264_pay_send_sps_pps (basepayload, rtph264pay, dts, pts);
894     if (ret != GST_FLOW_OK)
895       return ret;
896   }
897
898   packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
899
900   if (packet_len < mtu) {
901     GST_DEBUG_OBJECT (basepayload,
902         "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
903     /* will fit in one packet */
904
905     /* use buffer lists
906      * create buffer without payload containing only the RTP header
907      * (memory block at index 0) */
908     outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
909
910     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
911
912     /* only set the marker bit on packets containing access units */
913     if (IS_ACCESS_UNIT (nalType) && end_of_au) {
914       gst_rtp_buffer_set_marker (&rtp, 1);
915     }
916
917     /* timestamp the outbuffer */
918     GST_BUFFER_PTS (outbuf) = pts;
919     GST_BUFFER_DTS (outbuf) = dts;
920
921     /* insert payload memory block */
922     gst_buffer_append_memory (outbuf,
923         gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, (guint8*) data,
924           size, 0, size, NULL, NULL));
925
926     list = gst_buffer_list_new ();
927
928     /* add the buffer to the buffer list */
929     gst_buffer_list_add (list, outbuf);
930
931     gst_rtp_buffer_unmap (&rtp);
932
933     /* push the list to the next element in the pipe */
934     ret = gst_rtp_base_payload_push_list (basepayload, list);
935   } else {
936     /* fragmentation Units FU-A */
937     guint8 nalHeader;
938     guint limitedSize;
939     int ii = 0, start = 1, end = 0, pos = 0;
940
941     GST_DEBUG_OBJECT (basepayload,
942         "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
943
944     nalHeader = *data;
945     pos++;
946     size--;
947
948     ret = GST_FLOW_OK;
949
950     GST_DEBUG_OBJECT (basepayload, "Using FU-A fragmentation for data size=%d",
951         size);
952
953     /* We keep 2 bytes for FU indicator and FU Header */
954     payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
955
956     list = gst_buffer_list_new ();
957
958     while (end == 0) {
959       limitedSize = size < payload_len ? size : payload_len;
960       GST_DEBUG_OBJECT (basepayload,
961           "Inside  FU-A fragmentation limitedSize=%d iteration=%d", limitedSize,
962           ii);
963
964       /* use buffer lists
965        * create buffer without payload containing only the RTP header
966        * (memory block at index 0) */
967       outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
968
969       gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
970
971       GST_BUFFER_DTS (outbuf) = dts;
972       GST_BUFFER_PTS (outbuf) = pts;
973       payload = gst_rtp_buffer_get_payload (&rtp);
974
975       if (limitedSize == size) {
976         GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
977         end = 1;
978       }
979       if (IS_ACCESS_UNIT (nalType)) {
980         gst_rtp_buffer_set_marker (&rtp, end && end_of_au);
981       }
982
983       /* FU indicator */
984       payload[0] = (nalHeader & 0x60) | 28;
985
986       /* FU Header */
987       payload[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
988
989       /* insert payload memory block */
990       gst_buffer_append_memory (outbuf,
991           gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, (guint8 *) data + pos,
992             limitedSize, 0, limitedSize, NULL, NULL));
993
994       /* add the buffer to the buffer list */
995       gst_buffer_list_add (list, outbuf);
996
997       gst_rtp_buffer_unmap (&rtp);
998
999       size -= limitedSize;
1000       pos += limitedSize;
1001       ii++;
1002       start = 0;
1003     }
1004
1005     ret = gst_rtp_base_payload_push_list (basepayload, list);
1006   }
1007   return ret;
1008 }
1009
1010 static GstFlowReturn
1011 gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
1012     GstBuffer * buffer)
1013 {
1014   GstRtpH264Pay *rtph264pay;
1015   GstFlowReturn ret;
1016   gsize size;
1017   guint nal_len, i;
1018   GstMapInfo map;
1019   const guint8 *data, *nal_data;
1020   GstClockTime dts, pts;
1021   GArray *nal_queue;
1022   guint pushed = 0;
1023   gboolean avc;
1024
1025   rtph264pay = GST_RTP_H264_PAY (basepayload);
1026
1027   /* the input buffer contains one or more NAL units */
1028
1029   avc = rtph264pay->stream_format = GST_H264_STREAM_FORMAT_AVC;
1030
1031   if (avc) {
1032     gst_buffer_map (buffer, &map, GST_MAP_READ);
1033     data = map.data;
1034     size = map.size;
1035     pts = GST_BUFFER_PTS (buffer);
1036     dts = GST_BUFFER_DTS (buffer);
1037     GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
1038   } else {
1039     dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL);
1040     pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL);
1041     gst_adapter_push (rtph264pay->adapter, buffer);
1042     size = gst_adapter_available (rtph264pay->adapter);
1043     data = gst_adapter_map (rtph264pay->adapter, size);
1044     GST_DEBUG_OBJECT (basepayload,
1045         "got %" G_GSIZE_FORMAT " bytes (%" G_GSIZE_FORMAT ")", size,
1046         gst_buffer_get_size (buffer));
1047
1048     if (!GST_CLOCK_TIME_IS_VALID (dts))
1049       dts = GST_BUFFER_DTS (buffer);
1050     if (!GST_CLOCK_TIME_IS_VALID (pts))
1051       pts = GST_BUFFER_PTS (buffer);
1052   }
1053
1054   ret = GST_FLOW_OK;
1055
1056   /* now loop over all NAL units and put them in a packet
1057    * FIXME, we should really try to pack multiple NAL units into one RTP packet
1058    * if we can, especially for the config packets that wont't cause decoder 
1059    * latency. */
1060   if (avc) {
1061     guint nal_length_size;
1062
1063     nal_length_size = rtph264pay->nal_length_size;
1064
1065     while (size > nal_length_size) {
1066       gint i;
1067       gboolean end_of_au = FALSE;
1068
1069       nal_len = 0;
1070       for (i = 0; i < nal_length_size; i++) {
1071         nal_len = ((nal_len << 8) + data[i]);
1072       }
1073
1074       /* skip the length bytes, make sure we don't run past the buffer size */
1075       data += nal_length_size;
1076       size -= nal_length_size;
1077
1078       if (size >= nal_len) {
1079         GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
1080       } else {
1081         nal_len = size;
1082         GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
1083             nal_len);
1084       }
1085
1086       /* If we're at the end of the buffer, then we're at the end of the
1087        * access unit
1088        */
1089       if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU
1090           && size - nal_len <= nal_length_size) {
1091         end_of_au = TRUE;
1092       }
1093
1094       ret =
1095           gst_rtp_h264_pay_payload_nal (basepayload, data, nal_len, dts, pts,
1096           end_of_au);
1097       if (ret != GST_FLOW_OK)
1098         break;
1099
1100       data += nal_len;
1101       size -= nal_len;
1102     }
1103   } else {
1104     guint next;
1105     gboolean update = FALSE;
1106
1107     /* get offset of first start code */
1108     next = next_start_code (data, size);
1109
1110     /* skip to start code, if no start code is found, next will be size and we
1111      * will not collect data. */
1112     data += next;
1113     size -= next;
1114     nal_data = data;
1115     nal_queue = rtph264pay->queue;
1116
1117     /* array must be empty when we get here */
1118     g_assert (nal_queue->len == 0);
1119
1120     GST_DEBUG_OBJECT (basepayload,
1121         "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
1122
1123     /* first pass to locate NALs and parse SPS/PPS */
1124     while (size > 4) {
1125       /* skip start code */
1126       data += 3;
1127       size -= 3;
1128
1129       /* use next_start_code() to scan buffer.
1130        * next_start_code() returns the offset in data, 
1131        * starting from zero to the first byte of 0.0.0.1
1132        * If no start code is found, it returns the value of the 
1133        * 'size' parameter. 
1134        * data is unchanged by the call to next_start_code()
1135        */
1136       next = next_start_code (data, size);
1137
1138       if (next == size) {
1139         /* Didn't find the start of next NAL, handle it next time */
1140         break;
1141       }
1142
1143       /* nal length is distance to next start code */
1144       nal_len = next;
1145
1146       GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
1147           nal_len);
1148
1149       if (rtph264pay->sprop_parameter_sets != NULL) {
1150         /* explicitly set profile and sprop, use those */
1151         if (rtph264pay->update_caps) {
1152           if (!gst_rtp_base_payload_set_outcaps (basepayload,
1153                   "sprop-parameter-sets", G_TYPE_STRING,
1154                   rtph264pay->sprop_parameter_sets, NULL))
1155             goto caps_rejected;
1156
1157           /* parse SPS and PPS from provided parameter set (for insertion) */
1158           gst_rtp_h264_pay_parse_sprop_parameter_sets (rtph264pay);
1159
1160           rtph264pay->update_caps = FALSE;
1161
1162           GST_DEBUG ("outcaps update: sprop-parameter-sets=%s",
1163               rtph264pay->sprop_parameter_sets);
1164         }
1165       } else {
1166         /* We know our stream is a valid H264 NAL packet,
1167          * go parse it for SPS/PPS to enrich the caps */
1168         /* order: make sure to check nal */
1169         update =
1170             gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len, dts, pts)
1171             || update;
1172       }
1173       /* move to next NAL packet */
1174       data += nal_len;
1175       size -= nal_len;
1176
1177       g_array_append_val (nal_queue, nal_len);
1178     }
1179
1180     /* if has new SPS & PPS, update the output caps */
1181     if (G_UNLIKELY (update))
1182       if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
1183         goto caps_rejected;
1184
1185     /* second pass to payload and push */
1186     data = nal_data;
1187     pushed = 0;
1188
1189     for (i = 0; i < nal_queue->len; i++) {
1190       guint size;
1191       gboolean end_of_au = FALSE;
1192
1193       nal_len = g_array_index (nal_queue, guint, i);
1194       /* skip start code */
1195       data += 3;
1196
1197       /* Trim the end unless we're the last NAL in the buffer.
1198        * In case we're not at the end of the buffer we know the next block
1199        * starts with 0x000001 so all the 0x00 bytes at the end of this one are
1200        * trailing 0x0 that can be discarded */
1201       size = nal_len;
1202       if (i + 1 != nal_queue->len)
1203         for (; size > 1 && data[size - 1] == 0x0; size--)
1204           /* skip */ ;
1205
1206       /* If it's the last nal unit we have in non-bytestream mode, we can
1207        * assume it's the end of an access-unit
1208        *
1209        * FIXME: We need to wait until the next packet or EOS to
1210        * actually payload the NAL so we can know if the current NAL is
1211        * the last one of an access unit or not if we are in bytestream mode
1212        */
1213       if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU &&
1214           i == nal_queue->len - 1)
1215         end_of_au = TRUE;
1216
1217       /* put the data in one or more RTP packets */
1218       ret =
1219           gst_rtp_h264_pay_payload_nal (basepayload, data, size, dts, pts,
1220           end_of_au);
1221       if (ret != GST_FLOW_OK) {
1222         break;
1223       }
1224
1225       /* move to next NAL packet */
1226       data += nal_len;
1227       size -= nal_len;
1228       pushed += nal_len + 3;
1229     }
1230     g_array_set_size (nal_queue, 0);
1231   }
1232
1233 done:
1234   if (avc) {
1235     gst_buffer_unmap (buffer, &map);
1236     gst_buffer_unref (buffer);
1237   } else {
1238     gst_adapter_unmap (rtph264pay->adapter);
1239     gst_adapter_flush (rtph264pay->adapter, pushed);
1240   }
1241
1242   return ret;
1243
1244 caps_rejected:
1245   {
1246     GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
1247     g_array_set_size (nal_queue, 0);
1248     ret = GST_FLOW_NOT_NEGOTIATED;
1249     goto done;
1250   }
1251 }
1252
1253 static gboolean
1254 gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
1255 {
1256   gboolean res;
1257   const GstStructure *s;
1258   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (payload);
1259
1260   switch (GST_EVENT_TYPE (event)) {
1261     case GST_EVENT_FLUSH_STOP:
1262       gst_adapter_clear (rtph264pay->adapter);
1263       break;
1264     case GST_EVENT_CUSTOM_DOWNSTREAM:
1265       s = gst_event_get_structure (event);
1266       if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1267         gboolean resend_codec_data;
1268
1269         if (gst_structure_get_boolean (s, "all-headers",
1270                 &resend_codec_data) && resend_codec_data)
1271           rtph264pay->send_spspps = TRUE;
1272       }
1273       break;
1274     default:
1275       break;
1276   }
1277
1278   res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
1279
1280   return res;
1281 }
1282
1283 static GstStateChangeReturn
1284 gst_rtp_h264_pay_change_state (GstElement * element, GstStateChange transition)
1285 {
1286   GstStateChangeReturn ret;
1287   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (element);
1288
1289   switch (transition) {
1290     case GST_STATE_CHANGE_READY_TO_PAUSED:
1291       rtph264pay->send_spspps = FALSE;
1292       gst_adapter_clear (rtph264pay->adapter);
1293       break;
1294     default:
1295       break;
1296   }
1297
1298   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1299
1300   return ret;
1301 }
1302
1303 static void
1304 gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
1305     const GValue * value, GParamSpec * pspec)
1306 {
1307   GstRtpH264Pay *rtph264pay;
1308
1309   rtph264pay = GST_RTP_H264_PAY (object);
1310
1311   switch (prop_id) {
1312     case PROP_SPROP_PARAMETER_SETS:
1313       g_free (rtph264pay->sprop_parameter_sets);
1314       rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
1315       rtph264pay->update_caps = TRUE;
1316       break;
1317     case PROP_CONFIG_INTERVAL:
1318       rtph264pay->spspps_interval = g_value_get_uint (value);
1319       break;
1320     default:
1321       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1322       break;
1323   }
1324 }
1325
1326 static void
1327 gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
1328     GValue * value, GParamSpec * pspec)
1329 {
1330   GstRtpH264Pay *rtph264pay;
1331
1332   rtph264pay = GST_RTP_H264_PAY (object);
1333
1334   switch (prop_id) {
1335     case PROP_SPROP_PARAMETER_SETS:
1336       g_value_set_string (value, rtph264pay->sprop_parameter_sets);
1337       break;
1338     case PROP_CONFIG_INTERVAL:
1339       g_value_set_uint (value, rtph264pay->spspps_interval);
1340       break;
1341     default:
1342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1343       break;
1344   }
1345 }
1346
1347 gboolean
1348 gst_rtp_h264_pay_plugin_init (GstPlugin * plugin)
1349 {
1350   return gst_element_register (plugin, "rtph264pay",
1351       GST_RANK_SECONDARY, GST_TYPE_RTP_H264_PAY);
1352 }