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