Merge remote-tracking branch 'gst-rtsp-server/tizen_gst_1.19.2' into tizen_gst_1...
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / 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., 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 <gst/rtp/gstrtpbuffer.h>
28 #include <gst/pbutils/pbutils.h>
29 #include <gst/video/video.h>
30
31 /* Included to not duplicate gst_rtp_h264_add_sps_pps () */
32 #include "gstrtph264depay.h"
33
34 #include "gstrtpelements.h"
35 #include "gstrtph264pay.h"
36 #include "gstrtputils.h"
37 #include "gstbuffermemory.h"
38
39
40 #define IDR_TYPE_ID    5
41 #define SPS_TYPE_ID    7
42 #define PPS_TYPE_ID    8
43 #define AUD_TYPE_ID    9
44 #define STAP_A_TYPE_ID 24
45 #define FU_A_TYPE_ID   28
46
47 GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug);
48 #define GST_CAT_DEFAULT (rtph264pay_debug)
49
50 #define GST_TYPE_RTP_H264_AGGREGATE_MODE \
51   (gst_rtp_h264_aggregate_mode_get_type ())
52
53
54 static GType
55 gst_rtp_h264_aggregate_mode_get_type (void)
56 {
57   static GType type = 0;
58   static const GEnumValue values[] = {
59     {GST_RTP_H264_AGGREGATE_NONE, "Do not aggregate NAL units", "none"},
60     {GST_RTP_H264_AGGREGATE_ZERO_LATENCY,
61         "Aggregate NAL units until a VCL unit is included", "zero-latency"},
62     {GST_RTP_H264_AGGREGATE_MAX_STAP,
63         "Aggregate all NAL units with the same timestamp (adds one frame of"
64           " latency)", "max-stap"},
65     {0, NULL, NULL},
66   };
67
68   if (!type) {
69     type = g_enum_register_static ("GstRtpH264AggregateMode", values);
70   }
71   return type;
72 }
73
74
75
76 /* references:
77 *
78  * RFC 3984
79  */
80
81 static GstStaticPadTemplate gst_rtp_h264_pay_sink_template =
82     GST_STATIC_PAD_TEMPLATE ("sink",
83     GST_PAD_SINK,
84     GST_PAD_ALWAYS,
85     GST_STATIC_CAPS ("video/x-h264, "
86         "stream-format = (string) avc, alignment = (string) au;"
87         "video/x-h264, "
88         "stream-format = (string) byte-stream, alignment = (string) { nal, au }")
89     );
90
91 static GstStaticPadTemplate gst_rtp_h264_pay_src_template =
92 GST_STATIC_PAD_TEMPLATE ("src",
93     GST_PAD_SRC,
94     GST_PAD_ALWAYS,
95     GST_STATIC_CAPS ("application/x-rtp, "
96         "media = (string) \"video\", "
97         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
98         "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
99     );
100
101 #define DEFAULT_SPROP_PARAMETER_SETS    NULL
102 #define DEFAULT_CONFIG_INTERVAL         0
103 #define DEFAULT_AGGREGATE_MODE          GST_RTP_H264_AGGREGATE_NONE
104
105 enum
106 {
107   PROP_0,
108   PROP_SPROP_PARAMETER_SETS,
109   PROP_CONFIG_INTERVAL,
110   PROP_AGGREGATE_MODE,
111 };
112
113 static void gst_rtp_h264_pay_finalize (GObject * object);
114
115 static void gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
116     const GValue * value, GParamSpec * pspec);
117 static void gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
118     GValue * value, GParamSpec * pspec);
119
120 static GstCaps *gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload,
121     GstPad * pad, GstCaps * filter);
122 static gboolean gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload,
123     GstCaps * caps);
124 static GstFlowReturn gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * pad,
125     GstBuffer * buffer);
126 static gboolean gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload,
127     GstEvent * event);
128 static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement *
129     element, GstStateChange transition);
130 static gboolean gst_rtp_h264_pay_src_query (GstPad * pad, GstObject * parent,
131     GstQuery * query);
132
133 static void gst_rtp_h264_pay_reset_bundle (GstRtpH264Pay * rtph264pay);
134
135 #define gst_rtp_h264_pay_parent_class parent_class
136 G_DEFINE_TYPE (GstRtpH264Pay, gst_rtp_h264_pay, GST_TYPE_RTP_BASE_PAYLOAD);
137 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (rtph264pay, "rtph264pay",
138     GST_RANK_SECONDARY, GST_TYPE_RTP_H264_PAY, rtp_element_init (plugin));
139
140 static void
141 gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
142 {
143   GObjectClass *gobject_class;
144   GstElementClass *gstelement_class;
145   GstRTPBasePayloadClass *gstrtpbasepayload_class;
146
147   gobject_class = (GObjectClass *) klass;
148   gstelement_class = (GstElementClass *) klass;
149   gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
150
151   gobject_class->set_property = gst_rtp_h264_pay_set_property;
152   gobject_class->get_property = gst_rtp_h264_pay_get_property;
153
154   g_object_class_install_property (G_OBJECT_CLASS (klass),
155       PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
156           "sprop-parameter-sets",
157           "The base64 sprop-parameter-sets to set in out caps (set to NULL to "
158           "extract from stream)",
159           DEFAULT_SPROP_PARAMETER_SETS,
160           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
161
162   g_object_class_install_property (G_OBJECT_CLASS (klass),
163       PROP_CONFIG_INTERVAL,
164       g_param_spec_int ("config-interval",
165           "SPS PPS Send Interval",
166           "Send SPS and PPS Insertion Interval in seconds (sprop parameter sets "
167           "will be multiplexed in the data stream when detected.) "
168           "(0 = disabled, -1 = send with every IDR frame)",
169           -1, 3600, DEFAULT_CONFIG_INTERVAL,
170           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
171       );
172
173   /**
174    * GstRtpH264Pay:aggregate-mode
175    *
176    * Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets.
177    *
178    * This can potentially reduce RTP packetization overhead but not all
179    * RTP implementations handle it correctly.
180    *
181    * For best compatibility, it is recommended to set this to "none" (the
182    * default) for RTSP and for WebRTC to "zero-latency".
183    *
184    * Since: 1.18
185    */
186   g_object_class_install_property (G_OBJECT_CLASS (klass),
187       PROP_AGGREGATE_MODE,
188       g_param_spec_enum ("aggregate-mode",
189           "Attempt to use aggregate packets",
190           "Bundle suitable SPS/PPS NAL units into STAP-A "
191           "aggregate packets",
192           GST_TYPE_RTP_H264_AGGREGATE_MODE,
193           DEFAULT_AGGREGATE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
194       );
195
196   gobject_class->finalize = gst_rtp_h264_pay_finalize;
197
198   gst_element_class_add_static_pad_template (gstelement_class,
199       &gst_rtp_h264_pay_src_template);
200   gst_element_class_add_static_pad_template (gstelement_class,
201       &gst_rtp_h264_pay_sink_template);
202
203   gst_element_class_set_static_metadata (gstelement_class, "RTP H264 payloader",
204       "Codec/Payloader/Network/RTP",
205       "Payload-encode H264 video into RTP packets (RFC 3984)",
206       "Laurent Glayal <spglegle@yahoo.fr>");
207
208   gstelement_class->change_state =
209       GST_DEBUG_FUNCPTR (gst_rtp_h264_pay_change_state);
210
211   gstrtpbasepayload_class->get_caps = gst_rtp_h264_pay_getcaps;
212   gstrtpbasepayload_class->set_caps = gst_rtp_h264_pay_setcaps;
213   gstrtpbasepayload_class->handle_buffer = gst_rtp_h264_pay_handle_buffer;
214   gstrtpbasepayload_class->sink_event = gst_rtp_h264_pay_sink_event;
215
216   GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0,
217       "H264 RTP Payloader");
218
219   gst_type_mark_as_plugin_api (GST_TYPE_RTP_H264_AGGREGATE_MODE, 0);
220 }
221
222 static void
223 gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
224 {
225   rtph264pay->queue = g_array_new (FALSE, FALSE, sizeof (guint));
226   rtph264pay->profile = 0;
227   rtph264pay->sps = g_ptr_array_new_with_free_func (
228       (GDestroyNotify) gst_buffer_unref);
229   rtph264pay->pps = g_ptr_array_new_with_free_func (
230       (GDestroyNotify) gst_buffer_unref);
231   rtph264pay->last_spspps = -1;
232   rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
233   rtph264pay->aggregate_mode = DEFAULT_AGGREGATE_MODE;
234   rtph264pay->delta_unit = FALSE;
235   rtph264pay->discont = FALSE;
236
237   rtph264pay->adapter = gst_adapter_new ();
238
239   gst_pad_set_query_function (GST_RTP_BASE_PAYLOAD_SRCPAD (rtph264pay),
240       gst_rtp_h264_pay_src_query);
241 }
242
243 static void
244 gst_rtp_h264_pay_clear_sps_pps (GstRtpH264Pay * rtph264pay)
245 {
246   g_ptr_array_set_size (rtph264pay->sps, 0);
247   g_ptr_array_set_size (rtph264pay->pps, 0);
248 }
249
250 static void
251 gst_rtp_h264_pay_finalize (GObject * object)
252 {
253   GstRtpH264Pay *rtph264pay;
254
255   rtph264pay = GST_RTP_H264_PAY (object);
256
257   g_array_free (rtph264pay->queue, TRUE);
258
259   g_ptr_array_free (rtph264pay->sps, TRUE);
260   g_ptr_array_free (rtph264pay->pps, TRUE);
261
262   g_free (rtph264pay->sprop_parameter_sets);
263
264   g_object_unref (rtph264pay->adapter);
265   gst_rtp_h264_pay_reset_bundle (rtph264pay);
266
267   G_OBJECT_CLASS (parent_class)->finalize (object);
268 }
269
270 static const gchar all_levels[][4] = {
271   "1",
272   "1b",
273   "1.1",
274   "1.2",
275   "1.3",
276   "2",
277   "2.1",
278   "2.2",
279   "3",
280   "3.1",
281   "3.2",
282   "4",
283   "4.1",
284   "4.2",
285   "5",
286   "5.1"
287 };
288
289 static GstCaps *
290 gst_rtp_h264_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
291     GstCaps * filter)
292 {
293   GstCaps *template_caps;
294   GstCaps *allowed_caps;
295   GstCaps *caps, *icaps;
296   gboolean append_unrestricted;
297   guint i;
298
299   allowed_caps =
300       gst_pad_peer_query_caps (GST_RTP_BASE_PAYLOAD_SRCPAD (payload), NULL);
301
302   if (allowed_caps == NULL)
303     return NULL;
304
305   template_caps =
306       gst_static_pad_template_get_caps (&gst_rtp_h264_pay_sink_template);
307
308   if (gst_caps_is_any (allowed_caps)) {
309     caps = gst_caps_ref (template_caps);
310     goto done;
311   }
312
313   if (gst_caps_is_empty (allowed_caps)) {
314     caps = gst_caps_ref (allowed_caps);
315     goto done;
316   }
317
318   caps = gst_caps_new_empty ();
319
320   append_unrestricted = FALSE;
321   for (i = 0; i < gst_caps_get_size (allowed_caps); i++) {
322     GstStructure *s = gst_caps_get_structure (allowed_caps, i);
323     GstStructure *new_s = gst_structure_new_empty ("video/x-h264");
324     const gchar *profile_level_id;
325
326     profile_level_id = gst_structure_get_string (s, "profile-level-id");
327
328     if (profile_level_id && strlen (profile_level_id) == 6) {
329       const gchar *profile;
330       const gchar *level;
331       long int spsint;
332       guint8 sps[3];
333
334       spsint = strtol (profile_level_id, NULL, 16);
335       sps[0] = spsint >> 16;
336       sps[1] = spsint >> 8;
337       sps[2] = spsint;
338
339       profile = gst_codec_utils_h264_get_profile (sps, 3);
340       level = gst_codec_utils_h264_get_level (sps, 3);
341
342       if (profile && level) {
343         GST_LOG_OBJECT (payload, "In caps, have profile %s and level %s",
344             profile, level);
345
346         if (!strcmp (profile, "constrained-baseline"))
347           gst_structure_set (new_s, "profile", G_TYPE_STRING, profile, NULL);
348         else {
349           GValue val = { 0, };
350           GValue profiles = { 0, };
351
352           g_value_init (&profiles, GST_TYPE_LIST);
353           g_value_init (&val, G_TYPE_STRING);
354
355           g_value_set_static_string (&val, profile);
356           gst_value_list_append_value (&profiles, &val);
357
358           g_value_set_static_string (&val, "constrained-baseline");
359           gst_value_list_append_value (&profiles, &val);
360
361           gst_structure_take_value (new_s, "profile", &profiles);
362         }
363
364         if (!strcmp (level, "1"))
365           gst_structure_set (new_s, "level", G_TYPE_STRING, level, NULL);
366         else {
367           GValue levels = { 0, };
368           GValue val = { 0, };
369           int j;
370
371           g_value_init (&levels, GST_TYPE_LIST);
372           g_value_init (&val, G_TYPE_STRING);
373
374           for (j = 0; j < G_N_ELEMENTS (all_levels); j++) {
375             g_value_set_static_string (&val, all_levels[j]);
376             gst_value_list_prepend_value (&levels, &val);
377             if (!strcmp (level, all_levels[j]))
378               break;
379           }
380           gst_structure_take_value (new_s, "level", &levels);
381         }
382       } else {
383         /* Invalid profile-level-id means baseline */
384
385         gst_structure_set (new_s,
386             "profile", G_TYPE_STRING, "constrained-baseline", NULL);
387       }
388     } else {
389       /* No profile-level-id means baseline or unrestricted */
390
391       gst_structure_set (new_s,
392           "profile", G_TYPE_STRING, "constrained-baseline", NULL);
393       append_unrestricted = TRUE;
394     }
395
396     caps = gst_caps_merge_structure (caps, new_s);
397   }
398
399   if (append_unrestricted) {
400     caps =
401         gst_caps_merge_structure (caps, gst_structure_new ("video/x-h264", NULL,
402             NULL));
403   }
404
405   icaps = gst_caps_intersect (caps, template_caps);
406   gst_caps_unref (caps);
407   caps = icaps;
408
409 done:
410   if (filter) {
411     GST_DEBUG_OBJECT (payload, "Intersect %" GST_PTR_FORMAT " and filter %"
412         GST_PTR_FORMAT, caps, filter);
413     icaps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
414     gst_caps_unref (caps);
415     caps = icaps;
416   }
417
418   gst_caps_unref (template_caps);
419   gst_caps_unref (allowed_caps);
420
421   GST_LOG_OBJECT (payload, "returning caps %" GST_PTR_FORMAT, caps);
422   return caps;
423 }
424
425 static gboolean
426 gst_rtp_h264_pay_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
427 {
428   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (parent);
429
430   if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) {
431     gboolean retval;
432     gboolean live;
433     GstClockTime min_latency, max_latency;
434
435     retval = gst_pad_query_default (pad, parent, query);
436     if (!retval)
437       return retval;
438
439     if (rtph264pay->stream_format == GST_H264_STREAM_FORMAT_UNKNOWN ||
440         rtph264pay->alignment == GST_H264_ALIGNMENT_UNKNOWN)
441       return FALSE;
442
443     gst_query_parse_latency (query, &live, &min_latency, &max_latency);
444
445     if (rtph264pay->aggregate_mode == GST_RTP_H264_AGGREGATE_MAX_STAP &&
446         rtph264pay->alignment != GST_H264_ALIGNMENT_AU && rtph264pay->fps_num) {
447       GstClockTime one_frame = gst_util_uint64_scale_int (GST_SECOND,
448           rtph264pay->fps_denum, rtph264pay->fps_num);
449
450       min_latency += one_frame;
451       max_latency += one_frame;
452       gst_query_set_latency (query, live, min_latency, max_latency);
453     }
454     return TRUE;
455   }
456
457   return gst_pad_query_default (pad, parent, query);
458 }
459
460
461 /* take the currently configured SPS and PPS lists and set them on the caps as
462  * sprop-parameter-sets */
463 static gboolean
464 gst_rtp_h264_pay_set_sps_pps (GstRTPBasePayload * basepayload)
465 {
466   GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
467   gchar *profile;
468   gchar *set;
469   GString *sprops;
470   guint count;
471   gboolean res;
472   GstMapInfo map;
473   guint i;
474
475   sprops = g_string_new ("");
476   count = 0;
477
478   /* build the sprop-parameter-sets */
479   for (i = 0; i < payloader->sps->len; i++) {
480     GstBuffer *sps_buf =
481         GST_BUFFER_CAST (g_ptr_array_index (payloader->sps, i));
482
483     gst_buffer_map (sps_buf, &map, GST_MAP_READ);
484     set = g_base64_encode (map.data, map.size);
485     gst_buffer_unmap (sps_buf, &map);
486
487     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
488     g_free (set);
489     count++;
490   }
491   for (i = 0; i < payloader->pps->len; i++) {
492     GstBuffer *pps_buf =
493         GST_BUFFER_CAST (g_ptr_array_index (payloader->pps, i));
494
495     gst_buffer_map (pps_buf, &map, GST_MAP_READ);
496     set = g_base64_encode (map.data, map.size);
497     gst_buffer_unmap (pps_buf, &map);
498
499     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
500     g_free (set);
501     count++;
502   }
503
504   if (G_LIKELY (count)) {
505     if (payloader->profile != 0) {
506       /* profile is 24 bit. Force it to respect the limit */
507       profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
508       /* combine into output caps */
509       res = gst_rtp_base_payload_set_outcaps (basepayload,
510           "packetization-mode", G_TYPE_STRING, "1",
511           "profile-level-id", G_TYPE_STRING, profile,
512           "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
513       g_free (profile);
514     } else {
515       res = gst_rtp_base_payload_set_outcaps (basepayload,
516           "packetization-mode", G_TYPE_STRING, "1",
517           "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
518     }
519
520   } else {
521     res = gst_rtp_base_payload_set_outcaps (basepayload, NULL);
522   }
523   g_string_free (sprops, TRUE);
524
525   return res;
526 }
527
528
529 static gboolean
530 gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
531 {
532   GstRtpH264Pay *rtph264pay;
533   GstStructure *str;
534   const GValue *value;
535   GstMapInfo map;
536   guint8 *data;
537   gsize size;
538   GstBuffer *buffer;
539   const gchar *alignment, *stream_format;
540
541   rtph264pay = GST_RTP_H264_PAY (basepayload);
542
543   str = gst_caps_get_structure (caps, 0);
544
545   /* we can only set the output caps when we found the sprops and profile
546    * NALs */
547   gst_rtp_base_payload_set_options (basepayload, "video", TRUE, "H264", 90000);
548
549   rtph264pay->alignment = GST_H264_ALIGNMENT_UNKNOWN;
550   alignment = gst_structure_get_string (str, "alignment");
551   if (alignment) {
552     if (g_str_equal (alignment, "au"))
553       rtph264pay->alignment = GST_H264_ALIGNMENT_AU;
554     if (g_str_equal (alignment, "nal"))
555       rtph264pay->alignment = GST_H264_ALIGNMENT_NAL;
556   }
557
558   rtph264pay->stream_format = GST_H264_STREAM_FORMAT_UNKNOWN;
559   stream_format = gst_structure_get_string (str, "stream-format");
560   if (stream_format) {
561     if (g_str_equal (stream_format, "avc"))
562       rtph264pay->stream_format = GST_H264_STREAM_FORMAT_AVC;
563     if (g_str_equal (stream_format, "byte-stream"))
564       rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM;
565   }
566
567   if (!gst_structure_get_fraction (str, "framerate", &rtph264pay->fps_num,
568           &rtph264pay->fps_denum))
569     rtph264pay->fps_num = rtph264pay->fps_denum = 0;
570
571   /* packetized AVC video has a codec_data */
572   if ((value = gst_structure_get_value (str, "codec_data"))) {
573     guint num_sps, num_pps;
574     gint i, nal_size;
575
576     GST_DEBUG_OBJECT (rtph264pay, "have packetized h264");
577
578     buffer = gst_value_get_buffer (value);
579
580     gst_buffer_map (buffer, &map, GST_MAP_READ);
581     data = map.data;
582     size = map.size;
583
584     /* parse the avcC data */
585     if (size < 7)
586       goto avcc_too_small;
587     /* parse the version, this must be 1 */
588     if (data[0] != 1)
589       goto wrong_version;
590
591     /* AVCProfileIndication */
592     /* profile_compat */
593     /* AVCLevelIndication */
594     rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
595     GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
596
597     /* 6 bits reserved | 2 bits lengthSizeMinusOne */
598     /* this is the number of bytes in front of the NAL units to mark their
599      * length */
600     rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
601     GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
602     /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
603     num_sps = data[5] & 0x1f;
604     GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps);
605
606     data += 6;
607     size -= 6;
608
609     /* create the sprop-parameter-sets */
610     for (i = 0; i < num_sps; i++) {
611       GstBuffer *sps_buf;
612
613       if (size < 2)
614         goto avcc_error;
615
616       nal_size = (data[0] << 8) | data[1];
617       data += 2;
618       size -= 2;
619
620       GST_LOG_OBJECT (rtph264pay, "SPS %d size %d", i, nal_size);
621
622       if (size < nal_size)
623         goto avcc_error;
624
625       /* make a buffer out of it and add to SPS list */
626       sps_buf = gst_buffer_new_and_alloc (nal_size);
627       gst_buffer_fill (sps_buf, 0, data, nal_size);
628       gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
629           rtph264pay->pps, sps_buf);
630       data += nal_size;
631       size -= nal_size;
632     }
633     if (size < 1)
634       goto avcc_error;
635
636     /* 8 bits numOfPictureParameterSets */
637     num_pps = data[0];
638     data += 1;
639     size -= 1;
640
641     GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps);
642     for (i = 0; i < num_pps; i++) {
643       GstBuffer *pps_buf;
644
645       if (size < 2)
646         goto avcc_error;
647
648       nal_size = (data[0] << 8) | data[1];
649       data += 2;
650       size -= 2;
651
652       GST_LOG_OBJECT (rtph264pay, "PPS %d size %d", i, nal_size);
653
654       if (size < nal_size)
655         goto avcc_error;
656
657       /* make a buffer out of it and add to PPS list */
658       pps_buf = gst_buffer_new_and_alloc (nal_size);
659       gst_buffer_fill (pps_buf, 0, data, nal_size);
660       gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
661           rtph264pay->pps, pps_buf);
662
663       data += nal_size;
664       size -= nal_size;
665     }
666
667     /* and update the caps with the collected data */
668     if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
669       goto set_sps_pps_failed;
670
671     gst_buffer_unmap (buffer, &map);
672   } else {
673     GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
674   }
675
676   return TRUE;
677
678 avcc_too_small:
679   {
680     GST_ERROR_OBJECT (rtph264pay, "avcC size %" G_GSIZE_FORMAT " < 7", size);
681     goto error;
682   }
683 wrong_version:
684   {
685     GST_ERROR_OBJECT (rtph264pay, "wrong avcC version");
686     goto error;
687   }
688 avcc_error:
689   {
690     GST_ERROR_OBJECT (rtph264pay, "avcC too small ");
691     goto error;
692   }
693 set_sps_pps_failed:
694   {
695     GST_ERROR_OBJECT (rtph264pay, "failed to set sps/pps");
696     goto error;
697   }
698 error:
699   {
700     gst_buffer_unmap (buffer, &map);
701     return FALSE;
702   }
703 }
704
705 static void
706 gst_rtp_h264_pay_parse_sprop_parameter_sets (GstRtpH264Pay * rtph264pay)
707 {
708   const gchar *ps;
709   gchar **params;
710   guint len;
711   gint i;
712   GstBuffer *buf;
713
714   ps = rtph264pay->sprop_parameter_sets;
715   if (ps == NULL)
716     return;
717
718   gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
719
720   params = g_strsplit (ps, ",", 0);
721   len = g_strv_length (params);
722
723   GST_DEBUG_OBJECT (rtph264pay, "we have %d params", len);
724
725   for (i = 0; params[i]; i++) {
726     gsize nal_len;
727     GstMapInfo map;
728     guint8 *nalp;
729     guint save = 0;
730     gint state = 0;
731
732     nal_len = strlen (params[i]);
733     buf = gst_buffer_new_and_alloc (nal_len);
734
735     gst_buffer_map (buf, &map, GST_MAP_WRITE);
736     nalp = map.data;
737     nal_len = g_base64_decode_step (params[i], nal_len, nalp, &state, &save);
738     gst_buffer_unmap (buf, &map);
739     gst_buffer_resize (buf, 0, nal_len);
740
741     if (!nal_len) {
742       gst_buffer_unref (buf);
743       continue;
744     }
745
746     gst_rtp_h264_add_sps_pps (GST_ELEMENT (rtph264pay), rtph264pay->sps,
747         rtph264pay->pps, buf);
748   }
749   g_strfreev (params);
750 }
751
752 static guint
753 next_start_code (const guint8 * data, guint size)
754 {
755   /* Boyer-Moore string matching algorithm, in a degenerative
756    * sense because our search 'alphabet' is binary - 0 & 1 only.
757    * This allow us to simplify the general BM algorithm to a very
758    * simple form. */
759   /* assume 1 is in the 3th byte */
760   guint offset = 2;
761
762   while (offset < size) {
763     if (1 == data[offset]) {
764       unsigned int shift = offset;
765
766       if (0 == data[--shift]) {
767         if (0 == data[--shift]) {
768           return shift;
769         }
770       }
771       /* The jump is always 3 because of the 1 previously matched.
772        * All the 0's must be after this '1' matched at offset */
773       offset += 3;
774     } else if (0 == data[offset]) {
775       /* maybe next byte is 1? */
776       offset++;
777     } else {
778       /* can jump 3 bytes forward */
779       offset += 3;
780     }
781     /* at each iteration, we rescan in a backward manner until
782      * we match 0.0.1 in reverse order. Since our search string
783      * has only 2 'alpabets' (i.e. 0 & 1), we know that any
784      * mismatch will force us to shift a fixed number of steps */
785   }
786   GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
787
788   return size;
789 }
790
791 static gboolean
792 gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
793     const guint8 * data, guint size, GstClockTime dts, GstClockTime pts)
794 {
795   guint8 header, type;
796   gboolean updated;
797
798   /* default is no update */
799   updated = FALSE;
800
801   GST_DEBUG ("NAL payload len=%u", size);
802
803   header = data[0];
804   type = header & 0x1f;
805
806   /* We record the timestamp of the last SPS/PPS so
807    * that we can insert them at regular intervals and when needed. */
808   if (SPS_TYPE_ID == type || PPS_TYPE_ID == type) {
809     GstBuffer *nal;
810
811     /* trailing 0x0 are not part of the SPS/PPS */
812     while (size > 0 && data[size - 1] == 0x0)
813       size--;
814
815     /* encode the entire SPS NAL in base64 */
816     GST_DEBUG ("Found %s %x %x %x Len=%u", type == SPS_TYPE_ID ? "SPS" : "PPS",
817         (header >> 7), (header >> 5) & 3, type, size);
818
819     nal = gst_buffer_new_allocate (NULL, size, NULL);
820     gst_buffer_fill (nal, 0, data, size);
821
822     updated = gst_rtp_h264_add_sps_pps (GST_ELEMENT (payloader),
823         payloader->sps, payloader->pps, nal);
824
825     /* remember when we last saw SPS */
826     if (pts != -1)
827       payloader->last_spspps =
828           gst_segment_to_running_time (&GST_RTP_BASE_PAYLOAD_CAST
829           (payloader)->segment, GST_FORMAT_TIME, pts);
830   } else {
831     GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
832         (header >> 5) & 3, type, size);
833   }
834
835   return updated;
836 }
837
838 static GstFlowReturn
839 gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
840     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
841     gboolean delta_unit, gboolean discont);
842
843 static GstFlowReturn
844 gst_rtp_h264_pay_payload_nal_single (GstRTPBasePayload * basepayload,
845     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
846     gboolean delta_unit, gboolean discont);
847
848 static GstFlowReturn
849 gst_rtp_h264_pay_payload_nal_fragment (GstRTPBasePayload * basepayload,
850     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
851     gboolean delta_unit, gboolean discont, guint8 nal_header);
852
853 static GstFlowReturn
854 gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload,
855     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
856     gboolean delta_unit, gboolean discont, guint8 nal_header);
857
858 static GstFlowReturn
859 gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
860     GstClockTime dts, GstClockTime pts, gboolean delta_unit, gboolean discont)
861 {
862   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (basepayload);
863   GstFlowReturn ret = GST_FLOW_OK;
864   gboolean sent_all_sps_pps = TRUE;
865   guint i;
866
867   for (i = 0; i < rtph264pay->sps->len; i++) {
868     GstBuffer *sps_buf =
869         GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->sps, i));
870
871     GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
872     /* resend SPS */
873     ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
874         dts, pts, FALSE, delta_unit, discont);
875     /* Not critical here; but throw a warning */
876     if (ret != GST_FLOW_OK) {
877       sent_all_sps_pps = FALSE;
878       GST_WARNING_OBJECT (basepayload, "Problem pushing SPS");
879     }
880   }
881   for (i = 0; i < rtph264pay->pps->len; i++) {
882     GstBuffer *pps_buf =
883         GST_BUFFER_CAST (g_ptr_array_index (rtph264pay->pps, i));
884
885     GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
886     /* resend PPS */
887     ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
888         dts, pts, FALSE, TRUE, FALSE);
889     /* Not critical here; but throw a warning */
890     if (ret != GST_FLOW_OK) {
891       sent_all_sps_pps = FALSE;
892       GST_WARNING_OBJECT (basepayload, "Problem pushing PPS");
893     }
894   }
895
896   if (pts != -1 && sent_all_sps_pps)
897     rtph264pay->last_spspps =
898         gst_segment_to_running_time (&basepayload->segment, GST_FORMAT_TIME,
899         pts);
900
901   return ret;
902 }
903
904 /* @delta_unit: if %FALSE the first packet sent won't have the
905  * GST_BUFFER_FLAG_DELTA_UNIT flag.
906  * @discont: if %TRUE the first packet sent will have the
907  * GST_BUFFER_FLAG_DISCONT flag.
908  */
909 static GstFlowReturn
910 gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
911     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
912     gboolean delta_unit, gboolean discont)
913 {
914   GstRtpH264Pay *rtph264pay;
915   guint8 nal_header, nal_type;
916   gboolean send_spspps;
917   guint size;
918
919   rtph264pay = GST_RTP_H264_PAY (basepayload);
920   size = gst_buffer_get_size (paybuf);
921
922   gst_buffer_extract (paybuf, 0, &nal_header, 1);
923   nal_type = nal_header & 0x1f;
924
925   /* These payload type are reserved for STAP-A, STAP-B, MTAP16, and MTAP24
926    * as internally used NAL types */
927   switch (nal_type) {
928     case 24:
929     case 25:
930     case 26:
931     case 27:
932       GST_WARNING_OBJECT (rtph264pay, "Ignoring reserved NAL TYPE=%d",
933           nal_type);
934       gst_buffer_unref (paybuf);
935       return GST_FLOW_OK;
936     default:
937       break;
938   }
939
940   GST_DEBUG_OBJECT (rtph264pay,
941       "payloading NAL Unit: datasize=%u type=%d pts=%" GST_TIME_FORMAT,
942       size, nal_type, GST_TIME_ARGS (pts));
943
944   /* should set src caps before pushing stuff,
945    * and if we did not see enough SPS/PPS, that may not be the case */
946   if (G_UNLIKELY (!gst_pad_has_current_caps (GST_RTP_BASE_PAYLOAD_SRCPAD
947               (basepayload))))
948     gst_rtp_h264_pay_set_sps_pps (basepayload);
949
950   send_spspps = FALSE;
951
952   /* check if we need to emit an SPS/PPS now */
953   if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
954     if (rtph264pay->last_spspps != -1) {
955       guint64 diff;
956       GstClockTime running_time =
957           gst_segment_to_running_time (&basepayload->segment, GST_FORMAT_TIME,
958           pts);
959
960       GST_LOG_OBJECT (rtph264pay,
961           "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
962           GST_TIME_ARGS (running_time),
963           GST_TIME_ARGS (rtph264pay->last_spspps));
964
965       /* calculate diff between last SPS/PPS in milliseconds */
966       if (running_time > rtph264pay->last_spspps)
967         diff = running_time - rtph264pay->last_spspps;
968       else
969         diff = 0;
970
971       GST_DEBUG_OBJECT (rtph264pay,
972           "interval since last SPS/PPS %" GST_TIME_FORMAT,
973           GST_TIME_ARGS (diff));
974
975       /* bigger than interval, queue SPS/PPS */
976       if (GST_TIME_AS_SECONDS (diff) >= rtph264pay->spspps_interval) {
977         GST_DEBUG_OBJECT (rtph264pay, "time to send SPS/PPS");
978         send_spspps = TRUE;
979       }
980     } else {
981       /* no know previous SPS/PPS time, send now */
982       GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
983       send_spspps = TRUE;
984     }
985   } else if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval == -1) {
986     GST_DEBUG_OBJECT (rtph264pay, "sending SPS/PPS before current IDR frame");
987     /* send SPS/PPS before every IDR frame */
988     send_spspps = TRUE;
989   }
990
991   if (send_spspps || rtph264pay->send_spspps) {
992     /* we need to send SPS/PPS now first. FIXME, don't use the pts for
993      * checking when we need to send SPS/PPS but convert to running_time first. */
994     GstFlowReturn ret;
995
996     rtph264pay->send_spspps = FALSE;
997
998     ret = gst_rtp_h264_pay_send_sps_pps (basepayload, dts, pts, delta_unit,
999         discont);
1000     if (ret != GST_FLOW_OK) {
1001       gst_buffer_unref (paybuf);
1002       return ret;
1003     }
1004
1005     delta_unit = TRUE;
1006     discont = FALSE;
1007   }
1008
1009   if (rtph264pay->aggregate_mode != GST_RTP_H264_AGGREGATE_NONE)
1010     return gst_rtp_h264_pay_payload_nal_bundle (basepayload, paybuf, dts, pts,
1011         end_of_au, delta_unit, discont, nal_header);
1012
1013   return gst_rtp_h264_pay_payload_nal_fragment (basepayload, paybuf, dts, pts,
1014       end_of_au, delta_unit, discont, nal_header);
1015 }
1016
1017 static GstFlowReturn
1018 gst_rtp_h264_pay_payload_nal_fragment (GstRTPBasePayload * basepayload,
1019     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
1020     gboolean delta_unit, gboolean discont, guint8 nal_header)
1021 {
1022   GstRtpH264Pay *rtph264pay;
1023   guint mtu, size, max_fragment_size, max_fragments, ii, pos;
1024   GstBuffer *outbuf;
1025   guint8 *payload;
1026   GstBufferList *list = NULL;
1027   GstRTPBuffer rtp = { NULL };
1028
1029   rtph264pay = GST_RTP_H264_PAY (basepayload);
1030   mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
1031   size = gst_buffer_get_size (paybuf);
1032
1033   if (gst_rtp_buffer_calc_packet_len (size, 0, 0) <= mtu) {
1034     /* We don't need to fragment this packet */
1035     GST_DEBUG_OBJECT (rtph264pay,
1036         "sending NAL Unit: datasize=%u mtu=%u", size, mtu);
1037     return gst_rtp_h264_pay_payload_nal_single (basepayload, paybuf, dts, pts,
1038         end_of_au, delta_unit, discont);
1039   }
1040
1041   GST_DEBUG_OBJECT (basepayload,
1042       "using FU-A fragmentation for NAL Unit: datasize=%u mtu=%u", size, mtu);
1043
1044   /* We keep 2 bytes for FU indicator and FU Header */
1045   max_fragment_size = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
1046   max_fragments = (size + max_fragment_size - 2) / max_fragment_size;
1047   list = gst_buffer_list_new_sized (max_fragments);
1048
1049   /* Start at the NALU payload */
1050   for (pos = 1, ii = 0; pos < size; pos += max_fragment_size, ii++) {
1051     guint remaining, fragment_size;
1052     gboolean first_fragment, last_fragment;
1053
1054     remaining = size - pos;
1055     fragment_size = MIN (remaining, max_fragment_size);
1056     first_fragment = (pos == 1);
1057     last_fragment = (remaining <= max_fragment_size);
1058
1059     GST_DEBUG_OBJECT (basepayload,
1060         "creating FU-A packet %u/%u, size %u",
1061         ii + 1, max_fragments, fragment_size);
1062
1063     /* use buffer lists
1064      * create buffer without payload containing only the RTP header
1065      * (memory block at index 0) */
1066     outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 2, 0, 0);
1067
1068     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
1069
1070     GST_BUFFER_DTS (outbuf) = dts;
1071     GST_BUFFER_PTS (outbuf) = pts;
1072     payload = gst_rtp_buffer_get_payload (&rtp);
1073
1074     /* If it's the last fragment and the end of this au, mark the end of
1075      * slice */
1076     gst_rtp_buffer_set_marker (&rtp, last_fragment && end_of_au);
1077
1078     /* FU indicator */
1079     payload[0] = (nal_header & 0x60) | FU_A_TYPE_ID;
1080
1081     /* FU Header */
1082     payload[1] = (first_fragment << 7) | (last_fragment << 6) |
1083         (nal_header & 0x1f);
1084
1085     gst_rtp_buffer_unmap (&rtp);
1086
1087     /* insert payload memory block */
1088     gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
1089     gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
1090         fragment_size);
1091
1092     if (!delta_unit)
1093       /* Only the first packet sent should not have the flag */
1094       delta_unit = TRUE;
1095     else
1096       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1097
1098     if (discont) {
1099       GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1100       /* Only the first packet sent should have the flag */
1101       discont = FALSE;
1102     }
1103
1104     /* add the buffer to the buffer list */
1105     gst_buffer_list_add (list, outbuf);
1106   }
1107
1108   GST_DEBUG_OBJECT (rtph264pay,
1109       "sending FU-A fragments: n=%u datasize=%u mtu=%u", ii, size, mtu);
1110
1111   gst_buffer_unref (paybuf);
1112   return gst_rtp_base_payload_push_list (basepayload, list);
1113 }
1114
1115 static GstFlowReturn
1116 gst_rtp_h264_pay_payload_nal_single (GstRTPBasePayload * basepayload,
1117     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
1118     gboolean delta_unit, gboolean discont)
1119 {
1120   GstRtpH264Pay *rtph264pay;
1121   GstBuffer *outbuf;
1122   GstRTPBuffer rtp = { NULL };
1123
1124   rtph264pay = GST_RTP_H264_PAY (basepayload);
1125
1126   /* create buffer without payload containing only the RTP header
1127    * (memory block at index 0) */
1128   outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
1129
1130   gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
1131
1132   /* Mark the end of a frame */
1133   gst_rtp_buffer_set_marker (&rtp, end_of_au);
1134
1135   /* timestamp the outbuffer */
1136   GST_BUFFER_PTS (outbuf) = pts;
1137   GST_BUFFER_DTS (outbuf) = dts;
1138
1139   if (delta_unit)
1140     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
1141
1142   if (discont)
1143     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
1144
1145   gst_rtp_buffer_unmap (&rtp);
1146
1147   /* insert payload memory block */
1148   gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
1149   outbuf = gst_buffer_append (outbuf, paybuf);
1150
1151   /* push the buffer to the next element */
1152   return gst_rtp_base_payload_push (basepayload, outbuf);
1153 }
1154
1155 static void
1156 gst_rtp_h264_pay_reset_bundle (GstRtpH264Pay * rtph264pay)
1157 {
1158   g_clear_pointer (&rtph264pay->bundle, gst_buffer_list_unref);
1159   rtph264pay->bundle_size = 0;
1160   rtph264pay->bundle_contains_vcl = FALSE;
1161 }
1162
1163 static GstFlowReturn
1164 gst_rtp_h264_pay_send_bundle (GstRtpH264Pay * rtph264pay, gboolean end_of_au)
1165 {
1166   GstRTPBasePayload *basepayload;
1167   GstBufferList *bundle;
1168   guint length, bundle_size;
1169   GstBuffer *first, *outbuf;
1170   GstClockTime dts, pts;
1171   gboolean delta, discont;
1172
1173   bundle_size = rtph264pay->bundle_size;
1174
1175   if (bundle_size == 0) {
1176     GST_DEBUG_OBJECT (rtph264pay, "no bundle, nothing to send");
1177     return GST_FLOW_OK;
1178   }
1179
1180   basepayload = GST_RTP_BASE_PAYLOAD (rtph264pay);
1181   bundle = rtph264pay->bundle;
1182   length = gst_buffer_list_length (bundle);
1183
1184   first = gst_buffer_list_get (bundle, 0);
1185   dts = GST_BUFFER_DTS (first);
1186   pts = GST_BUFFER_PTS (first);
1187   delta = GST_BUFFER_FLAG_IS_SET (first, GST_BUFFER_FLAG_DELTA_UNIT);
1188   discont = GST_BUFFER_FLAG_IS_SET (first, GST_BUFFER_FLAG_DISCONT);
1189
1190   if (length == 1) {
1191     /* Push unaggregated NALU */
1192     outbuf = gst_buffer_ref (first);
1193
1194     GST_DEBUG_OBJECT (rtph264pay,
1195         "sending NAL Unit unaggregated: datasize=%u", bundle_size - 2);
1196   } else {
1197     guint8 stap_header;
1198     guint i;
1199
1200     outbuf = gst_buffer_new_allocate (NULL, sizeof stap_header, NULL);
1201     stap_header = STAP_A_TYPE_ID;
1202
1203     for (i = 0; i < length; i++) {
1204       GstBuffer *buf = gst_buffer_list_get (bundle, i);
1205       guint8 nal_header;
1206       GstMemory *size_header;
1207       GstMapInfo map;
1208
1209       gst_buffer_extract (buf, 0, &nal_header, sizeof nal_header);
1210
1211       /* Propagate F bit */
1212       if ((nal_header & 0x80))
1213         stap_header |= 0x80;
1214
1215       /* Select highest nal_ref_idc */
1216       if ((nal_header & 0x60) > (stap_header & 0x60))
1217         stap_header = (stap_header & 0x9f) | (nal_header & 0x60);
1218
1219       /* append NALU size */
1220       size_header = gst_allocator_alloc (NULL, 2, NULL);
1221       gst_memory_map (size_header, &map, GST_MAP_WRITE);
1222       GST_WRITE_UINT16_BE (map.data, gst_buffer_get_size (buf));
1223       gst_memory_unmap (size_header, &map);
1224       gst_buffer_append_memory (outbuf, size_header);
1225
1226       /* append NALU data */
1227       outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buf));
1228     }
1229
1230     gst_buffer_fill (outbuf, 0, &stap_header, sizeof stap_header);
1231
1232     GST_DEBUG_OBJECT (rtph264pay,
1233         "sending STAP-A bundle: n=%u header=%02x datasize=%u",
1234         length, stap_header, bundle_size);
1235   }
1236
1237   gst_rtp_h264_pay_reset_bundle (rtph264pay);
1238   return gst_rtp_h264_pay_payload_nal_single (basepayload, outbuf, dts, pts,
1239       end_of_au, delta, discont);
1240 }
1241
1242 static gboolean
1243 gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload,
1244     GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
1245     gboolean delta_unit, gboolean discont, guint8 nal_header)
1246 {
1247   GstRtpH264Pay *rtph264pay;
1248   GstFlowReturn ret;
1249   guint mtu, pay_size, bundle_size;
1250   GstBufferList *bundle;
1251   guint8 nal_type;
1252   gboolean start_of_au;
1253
1254   rtph264pay = GST_RTP_H264_PAY (basepayload);
1255   nal_type = nal_header & 0x1f;
1256   mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
1257   pay_size = 2 + gst_buffer_get_size (paybuf);
1258   bundle = rtph264pay->bundle;
1259   start_of_au = FALSE;
1260
1261   if (bundle) {
1262     GstBuffer *first = gst_buffer_list_get (bundle, 0);
1263
1264     if (nal_type == AUD_TYPE_ID) {
1265       GST_DEBUG_OBJECT (rtph264pay, "found access delimiter");
1266       start_of_au = TRUE;
1267     } else if (discont) {
1268       GST_DEBUG_OBJECT (rtph264pay, "found discont");
1269       start_of_au = TRUE;
1270     } else if (GST_BUFFER_PTS (first) != pts || GST_BUFFER_DTS (first) != dts) {
1271       GST_DEBUG_OBJECT (rtph264pay, "found timestamp mismatch");
1272       start_of_au = TRUE;
1273     }
1274   }
1275
1276   if (start_of_au) {
1277     GST_DEBUG_OBJECT (rtph264pay, "sending bundle before start of AU");
1278
1279     ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
1280     if (ret != GST_FLOW_OK)
1281       goto out;
1282
1283     bundle = NULL;
1284   }
1285
1286   bundle_size = 1 + pay_size;
1287
1288   if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
1289     GST_DEBUG_OBJECT (rtph264pay, "NAL Unit cannot fit in a bundle");
1290
1291     ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
1292     if (ret != GST_FLOW_OK)
1293       goto out;
1294
1295     return gst_rtp_h264_pay_payload_nal_fragment (basepayload, paybuf, dts, pts,
1296         end_of_au, delta_unit, discont, nal_header);
1297   }
1298
1299   bundle_size = rtph264pay->bundle_size + pay_size;
1300
1301   if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
1302     GST_DEBUG_OBJECT (rtph264pay,
1303         "bundle overflows, sending: bundlesize=%u datasize=2+%u mtu=%u",
1304         rtph264pay->bundle_size, pay_size - 2, mtu);
1305
1306     ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
1307     if (ret != GST_FLOW_OK)
1308       goto out;
1309
1310     bundle = NULL;
1311   }
1312
1313   if (!bundle) {
1314     GST_DEBUG_OBJECT (rtph264pay, "creating new STAP-A aggregate");
1315     bundle = rtph264pay->bundle = gst_buffer_list_new ();
1316     bundle_size = rtph264pay->bundle_size = 1;
1317     rtph264pay->bundle_contains_vcl = FALSE;
1318   }
1319
1320   GST_DEBUG_OBJECT (rtph264pay,
1321       "bundling NAL Unit: bundlesize=%u datasize=2+%u mtu=%u",
1322       rtph264pay->bundle_size, pay_size - 2, mtu);
1323
1324   paybuf = gst_buffer_make_writable (paybuf);
1325   GST_BUFFER_PTS (paybuf) = pts;
1326   GST_BUFFER_DTS (paybuf) = dts;
1327
1328   if (delta_unit)
1329     GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
1330   else
1331     GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
1332
1333   if (discont)
1334     GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DISCONT);
1335   else
1336     GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DISCONT);
1337
1338   gst_buffer_list_add (bundle, gst_buffer_ref (paybuf));
1339   rtph264pay->bundle_size += pay_size;
1340   ret = GST_FLOW_OK;
1341
1342   if ((nal_type >= 1 && nal_type <= 5) || nal_type == 14 ||
1343       (nal_type >= 20 && nal_type <= 23))
1344     rtph264pay->bundle_contains_vcl = TRUE;
1345
1346   if (end_of_au) {
1347     GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end of AU");
1348     ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
1349   }
1350
1351 out:
1352   gst_buffer_unref (paybuf);
1353   return ret;
1354 }
1355
1356 static GstFlowReturn
1357 gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
1358     GstBuffer * buffer)
1359 {
1360   GstRtpH264Pay *rtph264pay;
1361   GstFlowReturn ret;
1362   gsize size;
1363   guint nal_len, i;
1364   const guint8 *data;
1365   GstClockTime dts, pts;
1366   GArray *nal_queue;
1367   gboolean avc;
1368   GstBuffer *paybuf = NULL;
1369   gsize skip;
1370   gboolean delayed_not_delta_unit = FALSE;
1371   gboolean delayed_discont = FALSE;
1372   gboolean marker = FALSE;
1373   gboolean draining = (buffer == NULL);
1374
1375   rtph264pay = GST_RTP_H264_PAY (basepayload);
1376
1377   /* the input buffer contains one or more NAL units */
1378
1379   avc = rtph264pay->stream_format == GST_H264_STREAM_FORMAT_AVC;
1380
1381   if (avc) {
1382     /* In AVC mode, there is no adapter, so nothing to drain */
1383     if (draining)
1384       return GST_FLOW_OK;
1385   } else {
1386     if (buffer) {
1387       if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
1388         if (gst_adapter_available (rtph264pay->adapter) == 0)
1389           rtph264pay->delta_unit = FALSE;
1390         else
1391           /* This buffer contains a key frame but the adapter isn't empty. So
1392            * we'll purge it first by sending a first packet and then the second
1393            * one won't have the DELTA_UNIT flag. */
1394           delayed_not_delta_unit = TRUE;
1395       }
1396
1397       if (GST_BUFFER_IS_DISCONT (buffer)) {
1398         if (gst_adapter_available (rtph264pay->adapter) == 0)
1399           rtph264pay->discont = TRUE;
1400         else
1401           /* This buffer has the DISCONT flag but the adapter isn't empty. So
1402            * we'll purge it first by sending a first packet and then the second
1403            * one will have the DISCONT flag set. */
1404           delayed_discont = TRUE;
1405       }
1406
1407       marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
1408       gst_adapter_push (rtph264pay->adapter, buffer);
1409       buffer = NULL;
1410     }
1411
1412     /* We want to use the first TS used to construct the following NAL */
1413     dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL);
1414     pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL);
1415
1416     size = gst_adapter_available (rtph264pay->adapter);
1417     /* Nothing to do here if the adapter is empty, e.g. on EOS */
1418     if (size == 0)
1419       return GST_FLOW_OK;
1420     data = gst_adapter_map (rtph264pay->adapter, size);
1421     GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
1422   }
1423
1424   ret = GST_FLOW_OK;
1425
1426   /* now loop over all NAL units and put them in a packet */
1427   if (avc) {
1428     GstBufferMemoryMap memory;
1429     gsize remaining_buffer_size;
1430     guint nal_length_size;
1431     gsize offset = 0;
1432
1433     gst_buffer_memory_map (buffer, &memory);
1434     remaining_buffer_size = gst_buffer_get_size (buffer);
1435
1436     pts = GST_BUFFER_PTS (buffer);
1437     dts = GST_BUFFER_DTS (buffer);
1438     rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
1439         GST_BUFFER_FLAG_DELTA_UNIT);
1440     rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
1441     marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
1442     GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes",
1443         remaining_buffer_size);
1444
1445     nal_length_size = rtph264pay->nal_length_size;
1446
1447     while (remaining_buffer_size > nal_length_size) {
1448       gint i;
1449       gboolean end_of_au = FALSE;
1450
1451       nal_len = 0;
1452       for (i = 0; i < nal_length_size; i++) {
1453         nal_len = (nal_len << 8) + *memory.data;
1454         if (!gst_buffer_memory_advance_bytes (&memory, 1))
1455           break;
1456       }
1457
1458       offset += nal_length_size;
1459       remaining_buffer_size -= nal_length_size;
1460
1461       if (remaining_buffer_size >= nal_len) {
1462         GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
1463       } else {
1464         nal_len = remaining_buffer_size;
1465         GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
1466             nal_len);
1467       }
1468
1469       /* If we're at the end of the buffer, then we're at the end of the
1470        * access unit
1471        */
1472       if (remaining_buffer_size - nal_len <= nal_length_size) {
1473         if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU || marker)
1474           end_of_au = TRUE;
1475       }
1476
1477       paybuf = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset,
1478           nal_len);
1479       ret =
1480           gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
1481           end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
1482
1483       if (!rtph264pay->delta_unit)
1484         /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
1485         rtph264pay->delta_unit = TRUE;
1486
1487       if (rtph264pay->discont)
1488         /* Only the first outgoing packet have the DISCONT flag */
1489         rtph264pay->discont = FALSE;
1490
1491       if (ret != GST_FLOW_OK)
1492         break;
1493
1494       /* Skip current nal. If it is split over multiple GstMemory
1495        * advance_bytes () will switch to the correct GstMemory. The payloader
1496        * does not access those bytes directly but uses gst_buffer_copy_region ()
1497        * to create a sub-buffer referencing the nal instead */
1498       if (!gst_buffer_memory_advance_bytes (&memory, nal_len))
1499         break;
1500
1501       offset += nal_len;
1502       remaining_buffer_size -= nal_len;
1503     }
1504
1505     gst_buffer_memory_unmap (&memory);
1506     gst_buffer_unref (buffer);
1507   } else {
1508     guint next;
1509     gboolean update = FALSE;
1510
1511     /* get offset of first start code */
1512     next = next_start_code (data, size);
1513
1514     /* skip to start code, if no start code is found, next will be size and we
1515      * will not collect data. */
1516     data += next;
1517     size -= next;
1518     nal_queue = rtph264pay->queue;
1519     skip = next;
1520
1521     /* array must be empty when we get here */
1522     g_assert (nal_queue->len == 0);
1523
1524     GST_DEBUG_OBJECT (basepayload,
1525         "found first start at %u, bytes left %" G_GSIZE_FORMAT, next, size);
1526
1527     /* first pass to locate NALs and parse SPS/PPS */
1528     while (size > 4) {
1529       /* skip start code */
1530       data += 3;
1531       size -= 3;
1532
1533       /* use next_start_code() to scan buffer.
1534        * next_start_code() returns the offset in data,
1535        * starting from zero to the first byte of 0.0.0.1
1536        * If no start code is found, it returns the value of the
1537        * 'size' parameter.
1538        * data is unchanged by the call to next_start_code()
1539        */
1540       next = next_start_code (data, size);
1541
1542       /* nal or au aligned input needs no delaying until next time */
1543       if (next == size && !draining &&
1544           rtph264pay->alignment == GST_H264_ALIGNMENT_UNKNOWN) {
1545         /* Didn't find the start of next NAL and it's not EOS,
1546          * handle it next time */
1547         break;
1548       }
1549
1550       /* nal length is distance to next start code */
1551       nal_len = next;
1552
1553       GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
1554           nal_len);
1555
1556       if (rtph264pay->sprop_parameter_sets != NULL) {
1557         /* explicitly set profile and sprop, use those */
1558         if (rtph264pay->update_caps) {
1559           if (!gst_rtp_base_payload_set_outcaps (basepayload,
1560                   "sprop-parameter-sets", G_TYPE_STRING,
1561                   rtph264pay->sprop_parameter_sets, NULL))
1562             goto caps_rejected;
1563
1564           /* parse SPS and PPS from provided parameter set (for insertion) */
1565           gst_rtp_h264_pay_parse_sprop_parameter_sets (rtph264pay);
1566
1567           rtph264pay->update_caps = FALSE;
1568
1569           GST_DEBUG ("outcaps update: sprop-parameter-sets=%s",
1570               rtph264pay->sprop_parameter_sets);
1571         }
1572       } else {
1573         /* We know our stream is a valid H264 NAL packet,
1574          * go parse it for SPS/PPS to enrich the caps */
1575         /* order: make sure to check nal */
1576         update =
1577             gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len, dts, pts)
1578             || update;
1579       }
1580       /* move to next NAL packet */
1581       data += nal_len;
1582       size -= nal_len;
1583
1584       g_array_append_val (nal_queue, nal_len);
1585     }
1586
1587     /* if has new SPS & PPS, update the output caps */
1588     if (G_UNLIKELY (update))
1589       if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
1590         goto caps_rejected;
1591
1592     /* second pass to payload and push */
1593
1594     if (nal_queue->len != 0)
1595       gst_adapter_flush (rtph264pay->adapter, skip);
1596
1597     for (i = 0; i < nal_queue->len; i++) {
1598       guint size;
1599       gboolean end_of_au = FALSE;
1600
1601       nal_len = g_array_index (nal_queue, guint, i);
1602       /* skip start code */
1603       gst_adapter_flush (rtph264pay->adapter, 3);
1604
1605       /* Trim the end unless we're the last NAL in the stream.
1606        * In case we're not at the end of the buffer we know the next block
1607        * starts with 0x000001 so all the 0x00 bytes at the end of this one are
1608        * trailing 0x0 that can be discarded */
1609       size = nal_len;
1610       data = gst_adapter_map (rtph264pay->adapter, size);
1611       if (i + 1 != nal_queue->len || !draining)
1612         for (; size > 1 && data[size - 1] == 0x0; size--)
1613           /* skip */ ;
1614
1615
1616       /* If it's the last nal unit we have in non-bytestream mode, we can
1617        * assume it's the end of an access-unit
1618        *
1619        * FIXME: We need to wait until the next packet or EOS to
1620        * actually payload the NAL so we can know if the current NAL is
1621        * the last one of an access unit or not if we are in bytestream mode
1622        */
1623       if (i == nal_queue->len - 1) {
1624         if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU ||
1625             marker || draining)
1626           end_of_au = TRUE;
1627       }
1628       paybuf = gst_adapter_take_buffer (rtph264pay->adapter, size);
1629       g_assert (paybuf);
1630
1631       /* put the data in one or more RTP packets */
1632       ret =
1633           gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
1634           end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
1635
1636       if (delayed_not_delta_unit) {
1637         rtph264pay->delta_unit = FALSE;
1638         delayed_not_delta_unit = FALSE;
1639       } else {
1640         /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
1641         rtph264pay->delta_unit = TRUE;
1642       }
1643
1644       if (delayed_discont) {
1645         rtph264pay->discont = TRUE;
1646         delayed_discont = FALSE;
1647       } else {
1648         /* Only the first outgoing packet have the DISCONT flag */
1649         rtph264pay->discont = FALSE;
1650       }
1651
1652       if (ret != GST_FLOW_OK) {
1653         break;
1654       }
1655
1656       /* move to next NAL packet */
1657       /* Skips the trailing zeros */
1658       gst_adapter_flush (rtph264pay->adapter, nal_len - size);
1659     }
1660     g_array_set_size (nal_queue, 0);
1661   }
1662
1663   if (ret == GST_FLOW_OK && rtph264pay->bundle_size > 0 &&
1664       rtph264pay->aggregate_mode == GST_RTP_H264_AGGREGATE_ZERO_LATENCY &&
1665       rtph264pay->bundle_contains_vcl) {
1666     GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end incoming packet");
1667     ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
1668   }
1669
1670
1671 done:
1672   if (!avc) {
1673     gst_adapter_unmap (rtph264pay->adapter);
1674   }
1675
1676   return ret;
1677
1678 caps_rejected:
1679   {
1680     GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
1681     g_array_set_size (nal_queue, 0);
1682     ret = GST_FLOW_NOT_NEGOTIATED;
1683     goto done;
1684   }
1685 }
1686
1687 static gboolean
1688 gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
1689 {
1690   gboolean res;
1691   const GstStructure *s;
1692   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (payload);
1693   GstFlowReturn ret = GST_FLOW_OK;
1694
1695   switch (GST_EVENT_TYPE (event)) {
1696     case GST_EVENT_FLUSH_STOP:
1697       gst_adapter_clear (rtph264pay->adapter);
1698       gst_rtp_h264_pay_reset_bundle (rtph264pay);
1699       break;
1700     case GST_EVENT_CUSTOM_DOWNSTREAM:
1701       s = gst_event_get_structure (event);
1702       if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1703         gboolean resend_codec_data;
1704
1705         if (gst_structure_get_boolean (s, "all-headers",
1706                 &resend_codec_data) && resend_codec_data)
1707           rtph264pay->send_spspps = TRUE;
1708       }
1709       break;
1710     case GST_EVENT_EOS:
1711     {
1712       /* call handle_buffer with NULL to flush last NAL from adapter
1713        * in byte-stream mode
1714        */
1715       gst_rtp_h264_pay_handle_buffer (payload, NULL);
1716       ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
1717       break;
1718     }
1719     case GST_EVENT_STREAM_START:
1720       GST_DEBUG_OBJECT (rtph264pay, "New stream detected => Clear SPS and PPS");
1721       gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
1722       ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
1723       break;
1724     default:
1725       break;
1726   }
1727
1728   if (ret != GST_FLOW_OK)
1729     return FALSE;
1730
1731   res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
1732
1733   return res;
1734 }
1735
1736 static GstStateChangeReturn
1737 gst_rtp_h264_pay_change_state (GstElement * element, GstStateChange transition)
1738 {
1739   GstStateChangeReturn ret;
1740   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (element);
1741
1742   switch (transition) {
1743     case GST_STATE_CHANGE_READY_TO_PAUSED:
1744       rtph264pay->send_spspps = FALSE;
1745       gst_adapter_clear (rtph264pay->adapter);
1746       gst_rtp_h264_pay_reset_bundle (rtph264pay);
1747       break;
1748     default:
1749       break;
1750   }
1751
1752   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1753
1754   switch (transition) {
1755     case GST_STATE_CHANGE_PAUSED_TO_READY:
1756       rtph264pay->last_spspps = -1;
1757       gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
1758       break;
1759     default:
1760       break;
1761   }
1762
1763   return ret;
1764 }
1765
1766 static void
1767 gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
1768     const GValue * value, GParamSpec * pspec)
1769 {
1770   GstRtpH264Pay *rtph264pay;
1771
1772   rtph264pay = GST_RTP_H264_PAY (object);
1773
1774   switch (prop_id) {
1775     case PROP_SPROP_PARAMETER_SETS:
1776       g_free (rtph264pay->sprop_parameter_sets);
1777       rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
1778       rtph264pay->update_caps = TRUE;
1779       break;
1780     case PROP_CONFIG_INTERVAL:
1781       rtph264pay->spspps_interval = g_value_get_int (value);
1782       break;
1783     case PROP_AGGREGATE_MODE:
1784       rtph264pay->aggregate_mode = g_value_get_enum (value);
1785       break;
1786     default:
1787       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1788       break;
1789   }
1790 }
1791
1792 static void
1793 gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
1794     GValue * value, GParamSpec * pspec)
1795 {
1796   GstRtpH264Pay *rtph264pay;
1797
1798   rtph264pay = GST_RTP_H264_PAY (object);
1799
1800   switch (prop_id) {
1801     case PROP_SPROP_PARAMETER_SETS:
1802       g_value_set_string (value, rtph264pay->sprop_parameter_sets);
1803       break;
1804     case PROP_CONFIG_INTERVAL:
1805       g_value_set_int (value, rtph264pay->spspps_interval);
1806       break;
1807     case PROP_AGGREGATE_MODE:
1808       g_value_set_enum (value, rtph264pay->aggregate_mode);
1809       break;
1810     default:
1811       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1812       break;
1813   }
1814 }