Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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         } else {
355           /* Invalid profile-level-id means baseline */
356
357           gst_structure_set (new_s,
358               "profile", G_TYPE_STRING, "constrained-baseline", NULL);
359         }
360       } else {
361         /* No profile-level-id also means baseline */
362
363         gst_structure_set (new_s,
364             "profile", G_TYPE_STRING, "constrained-baseline", NULL);
365       }
366
367       gst_caps_merge_structure (caps, new_s);
368     }
369
370     gst_caps_unref (allowed_caps);
371     return caps;
372   }
373
374 any:
375   return gst_caps_new_simple ("video/x-h264", NULL);
376 }
377
378 /* take the currently configured SPS and PPS lists and set them on the caps as
379  * sprop-parameter-sets */
380 static gboolean
381 gst_rtp_h264_pay_set_sps_pps (GstBaseRTPPayload * basepayload)
382 {
383   GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
384   gchar *profile;
385   gchar *set;
386   GList *walk;
387   GString *sprops;
388   guint count;
389   gboolean res;
390
391   sprops = g_string_new ("");
392   count = 0;
393
394   /* build the sprop-parameter-sets */
395   for (walk = payloader->sps; walk; walk = g_list_next (walk)) {
396     GstBuffer *sps_buf = GST_BUFFER_CAST (walk->data);
397
398     set =
399         g_base64_encode (GST_BUFFER_DATA (sps_buf), GST_BUFFER_SIZE (sps_buf));
400     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
401     g_free (set);
402     count++;
403   }
404   for (walk = payloader->pps; walk; walk = g_list_next (walk)) {
405     GstBuffer *pps_buf = GST_BUFFER_CAST (walk->data);
406
407     set =
408         g_base64_encode (GST_BUFFER_DATA (pps_buf), GST_BUFFER_SIZE (pps_buf));
409     g_string_append_printf (sprops, "%s%s", count ? "," : "", set);
410     g_free (set);
411     count++;
412   }
413
414   /* profile is 24 bit. Force it to respect the limit */
415   profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
416   /* combine into output caps */
417   res = gst_basertppayload_set_outcaps (basepayload,
418       "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL);
419   g_string_free (sprops, TRUE);
420   g_free (profile);
421
422   return res;
423 }
424
425 static gboolean
426 gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
427 {
428   GstRtpH264Pay *rtph264pay;
429   GstStructure *str;
430   const GValue *value;
431   guint8 *data;
432   guint size;
433   const gchar *alignment;
434
435   rtph264pay = GST_RTP_H264_PAY (basepayload);
436
437   str = gst_caps_get_structure (caps, 0);
438
439   /* we can only set the output caps when we found the sprops and profile
440    * NALs */
441   gst_basertppayload_set_options (basepayload, "video", TRUE, "H264", 90000);
442
443   alignment = gst_structure_get_string (str, "alignment");
444   if (alignment && !strcmp (alignment, "au"))
445     rtph264pay->au_alignment = TRUE;
446   else
447     rtph264pay->au_alignment = FALSE;
448
449   /* packetized AVC video has a codec_data */
450   if ((value = gst_structure_get_value (str, "codec_data"))) {
451     GstBuffer *buffer;
452     guint num_sps, num_pps;
453     gint i, nal_size;
454
455     GST_DEBUG_OBJECT (rtph264pay, "have packetized h264");
456     rtph264pay->packetized = TRUE;
457
458     buffer = gst_value_get_buffer (value);
459     data = GST_BUFFER_DATA (buffer);
460     size = GST_BUFFER_SIZE (buffer);
461
462     /* parse the avcC data */
463     if (size < 7)
464       goto avcc_too_small;
465     /* parse the version, this must be 1 */
466     if (data[0] != 1)
467       goto wrong_version;
468
469     /* AVCProfileIndication */
470     /* profile_compat */
471     /* AVCLevelIndication */
472     rtph264pay->profile = (data[1] << 16) | (data[2] << 8) | data[3];
473     GST_DEBUG_OBJECT (rtph264pay, "profile %06x", rtph264pay->profile);
474
475     /* 6 bits reserved | 2 bits lengthSizeMinusOne */
476     /* this is the number of bytes in front of the NAL units to mark their
477      * length */
478     rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
479     GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
480     /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
481     num_sps = data[5] & 0x1f;
482     GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps);
483
484     data += 6;
485     size -= 6;
486
487     /* create the sprop-parameter-sets */
488     for (i = 0; i < num_sps; i++) {
489       GstBuffer *sps_buf;
490
491       if (size < 2)
492         goto avcc_error;
493
494       nal_size = (data[0] << 8) | data[1];
495       data += 2;
496       size -= 2;
497
498       GST_LOG_OBJECT (rtph264pay, "SPS %d size %d", i, nal_size);
499
500       if (size < nal_size)
501         goto avcc_error;
502
503       /* make a buffer out of it and add to SPS list */
504       sps_buf = gst_buffer_new_and_alloc (nal_size);
505       memcpy (GST_BUFFER_DATA (sps_buf), data, nal_size);
506       rtph264pay->sps = g_list_append (rtph264pay->sps, sps_buf);
507
508       data += nal_size;
509       size -= nal_size;
510     }
511     if (size < 1)
512       goto avcc_error;
513
514     /* 8 bits numOfPictureParameterSets */
515     num_pps = data[0];
516     data += 1;
517     size -= 1;
518
519     GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps);
520     for (i = 0; i < num_pps; i++) {
521       GstBuffer *pps_buf;
522
523       if (size < 2)
524         goto avcc_error;
525
526       nal_size = (data[0] << 8) | data[1];
527       data += 2;
528       size -= 2;
529
530       GST_LOG_OBJECT (rtph264pay, "PPS %d size %d", i, nal_size);
531
532       if (size < nal_size)
533         goto avcc_error;
534
535       /* make a buffer out of it and add to PPS list */
536       pps_buf = gst_buffer_new_and_alloc (nal_size);
537       memcpy (GST_BUFFER_DATA (pps_buf), data, nal_size);
538       rtph264pay->pps = g_list_append (rtph264pay->pps, pps_buf);
539
540       data += nal_size;
541       size -= nal_size;
542     }
543     /* and update the caps with the collected data */
544     if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
545       return FALSE;
546   } else {
547     GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264");
548     rtph264pay->packetized = FALSE;
549   }
550
551   return TRUE;
552
553 avcc_too_small:
554   {
555     GST_ERROR_OBJECT (rtph264pay, "avcC size %u < 7", size);
556     return FALSE;
557   }
558 wrong_version:
559   {
560     GST_ERROR_OBJECT (rtph264pay, "wrong avcC version");
561     return FALSE;
562   }
563 avcc_error:
564   {
565     GST_ERROR_OBJECT (rtph264pay, "avcC too small ");
566     return FALSE;
567   }
568 }
569
570 static void
571 gst_rtp_h264_pay_parse_sprop_parameter_sets (GstRtpH264Pay * rtph264pay)
572 {
573   const gchar *ps;
574   gchar **params;
575   guint len, num_sps, num_pps;
576   gint i;
577   GstBuffer *buf;
578
579   ps = rtph264pay->sprop_parameter_sets;
580   if (ps == NULL)
581     return;
582
583   gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
584
585   params = g_strsplit (ps, ",", 0);
586   len = g_strv_length (params);
587
588   GST_DEBUG_OBJECT (rtph264pay, "we have %d params", len);
589
590   num_sps = num_pps = 0;
591
592   for (i = 0; params[i]; i++) {
593     gsize nal_len;
594     guint8 *nalp;
595     guint save = 0;
596     gint state = 0;
597
598     nal_len = strlen (params[i]);
599     buf = gst_buffer_new_and_alloc (nal_len);
600     nalp = GST_BUFFER_DATA (buf);
601
602     nal_len = g_base64_decode_step (params[i], nal_len, nalp, &state, &save);
603     GST_BUFFER_SIZE (buf) = nal_len;
604
605     if (!nal_len) {
606       gst_buffer_unref (buf);
607       continue;
608     }
609
610     /* append to the right list */
611     if ((nalp[0] & 0x1f) == 7) {
612       GST_DEBUG_OBJECT (rtph264pay, "adding param %d as SPS %d", i, num_sps);
613       rtph264pay->sps = g_list_append (rtph264pay->sps, buf);
614       num_sps++;
615     } else {
616       GST_DEBUG_OBJECT (rtph264pay, "adding param %d as PPS %d", i, num_pps);
617       rtph264pay->pps = g_list_append (rtph264pay->pps, buf);
618       num_pps++;
619     }
620   }
621   g_strfreev (params);
622 }
623
624 static guint
625 next_start_code (const guint8 * data, guint size)
626 {
627   /* Boyer-Moore string matching algorithm, in a degenerative
628    * sense because our search 'alphabet' is binary - 0 & 1 only.
629    * This allow us to simplify the general BM algorithm to a very
630    * simple form. */
631   /* assume 1 is in the 3th byte */
632   guint offset = 2;
633
634   while (offset < size) {
635     if (1 == data[offset]) {
636       unsigned int shift = offset;
637
638       if (0 == data[--shift]) {
639         if (0 == data[--shift]) {
640           return shift;
641         }
642       }
643       /* The jump is always 3 because of the 1 previously matched.
644        * All the 0's must be after this '1' matched at offset */
645       offset += 3;
646     } else if (0 == data[offset]) {
647       /* maybe next byte is 1? */
648       offset++;
649     } else {
650       /* can jump 3 bytes forward */
651       offset += 3;
652     }
653     /* at each iteration, we rescan in a backward manner until
654      * we match 0.0.1 in reverse order. Since our search string
655      * has only 2 'alpabets' (i.e. 0 & 1), we know that any
656      * mismatch will force us to shift a fixed number of steps */
657   }
658   GST_DEBUG ("Cannot find next NAL start code. returning %u", size);
659
660   return size;
661 }
662
663 static gboolean
664 gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
665     const guint8 * data, guint size, GstClockTime timestamp)
666 {
667   const guint8 *sps = NULL, *pps = NULL;
668   guint sps_len = 0, pps_len = 0;
669   guint8 header, type;
670   guint len;
671   gboolean updated;
672
673   /* default is no update */
674   updated = FALSE;
675
676   GST_DEBUG ("NAL payload len=%u", size);
677
678   len = size;
679   header = data[0];
680   type = header & 0x1f;
681
682   /* keep sps & pps separately so that we can update either one 
683    * independently. We also record the timestamp of the last SPS/PPS so 
684    * that we can insert them at regular intervals and when needed. */
685   if (SPS_TYPE_ID == type) {
686     /* encode the entire SPS NAL in base64 */
687     GST_DEBUG ("Found SPS %x %x %x Len=%u", (header >> 7),
688         (header >> 5) & 3, type, len);
689
690     sps = data;
691     sps_len = len;
692     /* remember when we last saw SPS */
693     if (timestamp != -1)
694       payloader->last_spspps = timestamp;
695   } else if (PPS_TYPE_ID == type) {
696     /* encoder the entire PPS NAL in base64 */
697     GST_DEBUG ("Found PPS %x %x %x Len = %u",
698         (header >> 7), (header >> 5) & 3, type, len);
699
700     pps = data;
701     pps_len = len;
702     /* remember when we last saw PPS */
703     if (timestamp != -1)
704       payloader->last_spspps = timestamp;
705   } else {
706     GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
707         (header >> 5) & 3, type, len);
708   }
709
710   /* If we encountered an SPS and/or a PPS, check if it's the
711    * same as the one we have. If not, update our version and
712    * set updated to TRUE
713    */
714   if (sps_len > 0) {
715     GstBuffer *sps_buf;
716
717     if (payloader->sps != NULL) {
718       sps_buf = GST_BUFFER_CAST (payloader->sps->data);
719
720       if ((GST_BUFFER_SIZE (sps_buf) != sps_len)
721           || memcmp (GST_BUFFER_DATA (sps_buf), sps, sps_len)) {
722         /* something changed, update */
723         payloader->profile = (sps[1] << 16) + (sps[2] << 8) + sps[3];
724         GST_DEBUG ("Profile level IDC = %06x", payloader->profile);
725         updated = TRUE;
726       }
727     } else {
728       /* no previous SPS, update */
729       updated = TRUE;
730     }
731
732     if (updated) {
733       sps_buf = gst_buffer_new_and_alloc (sps_len);
734       memcpy (GST_BUFFER_DATA (sps_buf), sps, sps_len);
735
736       if (payloader->sps) {
737         /* replace old buffer */
738         gst_buffer_unref (payloader->sps->data);
739         payloader->sps->data = sps_buf;
740       } else {
741         /* add new buffer */
742         payloader->sps = g_list_prepend (payloader->sps, sps_buf);
743       }
744     }
745   }
746
747   if (pps_len > 0) {
748     GstBuffer *pps_buf;
749
750     if (payloader->pps != NULL) {
751       pps_buf = GST_BUFFER_CAST (payloader->pps->data);
752
753       if ((GST_BUFFER_SIZE (pps_buf) != pps_len)
754           || memcmp (GST_BUFFER_DATA (pps_buf), pps, pps_len)) {
755         /* something changed, update */
756         updated = TRUE;
757       }
758     } else {
759       /* no previous SPS, update */
760       updated = TRUE;
761     }
762
763     if (updated) {
764       pps_buf = gst_buffer_new_and_alloc (pps_len);
765       memcpy (GST_BUFFER_DATA (pps_buf), pps, pps_len);
766
767       if (payloader->pps) {
768         /* replace old buffer */
769         gst_buffer_unref (payloader->pps->data);
770         payloader->pps->data = pps_buf;
771       } else {
772         /* add new buffer */
773         payloader->pps = g_list_prepend (payloader->pps, pps_buf);
774       }
775     }
776   }
777   return updated;
778 }
779
780 static GstFlowReturn
781 gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
782     const guint8 * data, guint size, GstClockTime timestamp,
783     GstBuffer * buffer_orig, gboolean end_of_au);
784
785 static GstFlowReturn
786 gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
787     GstRtpH264Pay * rtph264pay, GstClockTime timestamp)
788 {
789   GstFlowReturn ret = GST_FLOW_OK;
790   GList *walk;
791
792   for (walk = rtph264pay->sps; walk; walk = g_list_next (walk)) {
793     GstBuffer *sps_buf = GST_BUFFER_CAST (walk->data);
794
795     GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
796     /* resend SPS */
797     ret = gst_rtp_h264_pay_payload_nal (basepayload,
798         GST_BUFFER_DATA (sps_buf), GST_BUFFER_SIZE (sps_buf), timestamp,
799         sps_buf, FALSE);
800     /* Not critical here; but throw a warning */
801     if (ret != GST_FLOW_OK)
802       GST_WARNING ("Problem pushing SPS");
803   }
804   for (walk = rtph264pay->pps; walk; walk = g_list_next (walk)) {
805     GstBuffer *pps_buf = GST_BUFFER_CAST (walk->data);
806
807     GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
808     /* resend PPS */
809     ret = gst_rtp_h264_pay_payload_nal (basepayload,
810         GST_BUFFER_DATA (pps_buf), GST_BUFFER_SIZE (pps_buf), timestamp,
811         pps_buf, FALSE);
812     /* Not critical here; but throw a warning */
813     if (ret != GST_FLOW_OK)
814       GST_WARNING ("Problem pushing PPS");
815   }
816
817   if (timestamp != -1)
818     rtph264pay->last_spspps = timestamp;
819
820   return ret;
821 }
822
823 static GstFlowReturn
824 gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
825     const guint8 * data, guint size, GstClockTime timestamp,
826     GstBuffer * buffer_orig, gboolean end_of_au)
827 {
828   GstRtpH264Pay *rtph264pay;
829   GstFlowReturn ret;
830   guint8 nalType;
831   guint packet_len, payload_len, mtu;
832   GstBuffer *outbuf;
833   guint8 *payload;
834   GstBufferList *list = NULL;
835   GstBufferListIterator *it = NULL;
836   gboolean send_spspps;
837
838   rtph264pay = GST_RTP_H264_PAY (basepayload);
839   mtu = GST_BASE_RTP_PAYLOAD_MTU (rtph264pay);
840
841   nalType = data[0] & 0x1f;
842   GST_DEBUG_OBJECT (rtph264pay, "Processing Buffer with NAL TYPE=%d", nalType);
843
844   send_spspps = FALSE;
845
846   /* check if we need to emit an SPS/PPS now */
847   if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
848     if (rtph264pay->last_spspps != -1) {
849       guint64 diff;
850
851       GST_LOG_OBJECT (rtph264pay,
852           "now %" GST_TIME_FORMAT ", last SPS/PPS %" GST_TIME_FORMAT,
853           GST_TIME_ARGS (timestamp), GST_TIME_ARGS (rtph264pay->last_spspps));
854
855       /* calculate diff between last SPS/PPS in milliseconds */
856       if (timestamp > rtph264pay->last_spspps)
857         diff = timestamp - rtph264pay->last_spspps;
858       else
859         diff = 0;
860
861       GST_DEBUG_OBJECT (rtph264pay,
862           "interval since last SPS/PPS %" GST_TIME_FORMAT,
863           GST_TIME_ARGS (diff));
864
865       /* bigger than interval, queue SPS/PPS */
866       if (GST_TIME_AS_SECONDS (diff) >= rtph264pay->spspps_interval) {
867         GST_DEBUG_OBJECT (rtph264pay, "time to send SPS/PPS");
868         send_spspps = TRUE;
869       }
870     } else {
871       /* no know previous SPS/PPS time, send now */
872       GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
873       send_spspps = TRUE;
874     }
875   }
876
877   if (send_spspps || rtph264pay->send_spspps) {
878     /* we need to send SPS/PPS now first. FIXME, don't use the timestamp for
879      * checking when we need to send SPS/PPS but convert to running_time first. */
880     rtph264pay->send_spspps = FALSE;
881     ret = gst_rtp_h264_pay_send_sps_pps (basepayload, rtph264pay, timestamp);
882     if (ret != GST_FLOW_OK)
883       return ret;
884   }
885
886   packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
887
888   if (packet_len < mtu) {
889     GST_DEBUG_OBJECT (basepayload,
890         "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
891     /* will fit in one packet */
892
893     if (rtph264pay->buffer_list) {
894       /* use buffer lists
895        * first create buffer without payload containing only the RTP header
896        * and then another buffer containing the payload. both buffers will
897        * be then added to the list */
898       outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
899     } else {
900       /* use the old-fashioned way with a single buffer and memcpy */
901       outbuf = gst_rtp_buffer_new_allocate (size, 0, 0);
902     }
903
904     /* only set the marker bit on packets containing access units */
905     if (IS_ACCESS_UNIT (nalType) && end_of_au) {
906       gst_rtp_buffer_set_marker (outbuf, 1);
907     }
908
909     /* timestamp the outbuffer */
910     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
911
912     if (rtph264pay->buffer_list) {
913       GstBuffer *paybuf;
914
915       /* create another buffer with the payload. */
916       if (buffer_orig)
917         paybuf = gst_buffer_create_sub (buffer_orig, data -
918             GST_BUFFER_DATA (buffer_orig), size);
919       else {
920         paybuf = gst_buffer_new_and_alloc (size);
921         memcpy (GST_BUFFER_DATA (paybuf), data, size);
922       }
923
924       list = gst_buffer_list_new ();
925       it = gst_buffer_list_iterate (list);
926
927       /* add both buffers to the buffer list */
928       gst_buffer_list_iterator_add_group (it);
929       gst_buffer_list_iterator_add (it, outbuf);
930       gst_buffer_list_iterator_add (it, paybuf);
931
932       gst_buffer_list_iterator_free (it);
933
934       /* push the list to the next element in the pipe */
935       ret = gst_basertppayload_push_list (basepayload, list);
936     } else {
937       payload = gst_rtp_buffer_get_payload (outbuf);
938       GST_DEBUG_OBJECT (basepayload, "Copying %d bytes to outbuf", size);
939       memcpy (payload, data, size);
940
941       ret = gst_basertppayload_push (basepayload, outbuf);
942     }
943   } else {
944     /* fragmentation Units FU-A */
945     guint8 nalHeader;
946     guint limitedSize;
947     int ii = 0, start = 1, end = 0, pos = 0;
948
949     GST_DEBUG_OBJECT (basepayload,
950         "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
951
952     nalHeader = *data;
953     pos++;
954     size--;
955
956     ret = GST_FLOW_OK;
957
958     GST_DEBUG_OBJECT (basepayload, "Using FU-A fragmentation for data size=%d",
959         size);
960
961     /* We keep 2 bytes for FU indicator and FU Header */
962     payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
963
964     if (rtph264pay->buffer_list) {
965       list = gst_buffer_list_new ();
966       it = gst_buffer_list_iterate (list);
967     }
968
969     while (end == 0) {
970       limitedSize = size < payload_len ? size : payload_len;
971       GST_DEBUG_OBJECT (basepayload,
972           "Inside  FU-A fragmentation limitedSize=%d iteration=%d", limitedSize,
973           ii);
974
975       if (rtph264pay->buffer_list) {
976         /* use buffer lists
977          * first create buffer without payload containing only the RTP header
978          * and then another buffer containing the payload. both buffers will
979          * be then added to the list */
980         outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
981       } else {
982         /* use the old-fashioned way with a single buffer and memcpy
983          * first create buffer to hold the payload */
984         outbuf = gst_rtp_buffer_new_allocate (limitedSize + 2, 0, 0);
985       }
986
987       GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
988       payload = gst_rtp_buffer_get_payload (outbuf);
989
990       if (limitedSize == size) {
991         GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
992         end = 1;
993       }
994       if (IS_ACCESS_UNIT (nalType)) {
995         gst_rtp_buffer_set_marker (outbuf, end && end_of_au);
996       }
997
998       /* FU indicator */
999       payload[0] = (nalHeader & 0x60) | 28;
1000
1001       /* FU Header */
1002       payload[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
1003
1004       if (rtph264pay->buffer_list) {
1005         GstBuffer *paybuf;
1006
1007         /* create another buffer to hold the payload */
1008         if (buffer_orig)
1009           paybuf = gst_buffer_create_sub (buffer_orig, data -
1010               GST_BUFFER_DATA (buffer_orig) + pos, limitedSize);
1011         else {
1012           paybuf = gst_buffer_new_and_alloc (limitedSize);
1013           memcpy (GST_BUFFER_DATA (paybuf), data + pos, limitedSize);
1014         }
1015
1016         /* create a new group to hold the header and the payload */
1017         gst_buffer_list_iterator_add_group (it);
1018
1019         /* add both buffers to the buffer list */
1020         gst_buffer_list_iterator_add (it, outbuf);
1021         gst_buffer_list_iterator_add (it, paybuf);
1022
1023       } else {
1024         memcpy (&payload[2], data + pos, limitedSize);
1025         GST_DEBUG_OBJECT (basepayload,
1026             "recorded %d payload bytes into packet iteration=%d",
1027             limitedSize + 2, ii);
1028
1029         ret = gst_basertppayload_push (basepayload, outbuf);
1030         if (ret != GST_FLOW_OK)
1031           break;
1032       }
1033
1034       size -= limitedSize;
1035       pos += limitedSize;
1036       ii++;
1037       start = 0;
1038     }
1039
1040     if (rtph264pay->buffer_list) {
1041       /* free iterator and push the whole buffer list at once */
1042       gst_buffer_list_iterator_free (it);
1043       ret = gst_basertppayload_push_list (basepayload, list);
1044     }
1045   }
1046   return ret;
1047 }
1048
1049 static GstFlowReturn
1050 gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
1051     GstBuffer * buffer)
1052 {
1053   GstRtpH264Pay *rtph264pay;
1054   GstFlowReturn ret;
1055   guint size, nal_len, i;
1056   const guint8 *data, *nal_data;
1057   GstClockTime timestamp;
1058   GArray *nal_queue;
1059   guint pushed = 0;
1060
1061   rtph264pay = GST_RTP_H264_PAY (basepayload);
1062
1063   /* the input buffer contains one or more NAL units */
1064
1065   if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM) {
1066     timestamp = gst_adapter_prev_timestamp (rtph264pay->adapter, NULL);
1067     gst_adapter_push (rtph264pay->adapter, buffer);
1068     size = gst_adapter_available (rtph264pay->adapter);
1069     data = gst_adapter_peek (rtph264pay->adapter, size);
1070     GST_DEBUG_OBJECT (basepayload, "got %d bytes (%d)", size,
1071         GST_BUFFER_SIZE (buffer));
1072
1073     if (!GST_CLOCK_TIME_IS_VALID (timestamp))
1074       timestamp = GST_BUFFER_TIMESTAMP (buffer);
1075   } else {
1076     size = GST_BUFFER_SIZE (buffer);
1077     data = GST_BUFFER_DATA (buffer);
1078     timestamp = GST_BUFFER_TIMESTAMP (buffer);
1079     GST_DEBUG_OBJECT (basepayload, "got %d bytes", size);
1080   }
1081
1082   ret = GST_FLOW_OK;
1083
1084   /* now loop over all NAL units and put them in a packet
1085    * FIXME, we should really try to pack multiple NAL units into one RTP packet
1086    * if we can, especially for the config packets that wont't cause decoder 
1087    * latency. */
1088   if (rtph264pay->packetized) {
1089     guint nal_length_size;
1090
1091     nal_length_size = rtph264pay->nal_length_size;
1092
1093     while (size > nal_length_size) {
1094       gint i;
1095       gboolean end_of_au = FALSE;
1096
1097       nal_len = 0;
1098       for (i = 0; i < nal_length_size; i++) {
1099         nal_len = ((nal_len << 8) + data[i]);
1100       }
1101
1102       /* skip the length bytes, make sure we don't run past the buffer size */
1103       data += nal_length_size;
1104       size -= nal_length_size;
1105
1106       if (size >= nal_len) {
1107         GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
1108       } else {
1109         nal_len = size;
1110         GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
1111             nal_len);
1112       }
1113
1114       /* If we're at the end of the buffer, then we're at the end of the
1115        * access unit
1116        */
1117       if (rtph264pay->au_alignment && size - nal_len <= nal_length_size) {
1118         end_of_au = TRUE;
1119       }
1120
1121       ret =
1122           gst_rtp_h264_pay_payload_nal (basepayload, data, nal_len, timestamp,
1123           buffer, end_of_au);
1124       if (ret != GST_FLOW_OK)
1125         break;
1126
1127       data += nal_len;
1128       size -= nal_len;
1129     }
1130   } else {
1131     guint next;
1132     gboolean update = FALSE;
1133
1134     /* get offset of first start code */
1135     next = next_start_code (data, size);
1136
1137     /* skip to start code, if no start code is found, next will be size and we
1138      * will not collect data. */
1139     data += next;
1140     size -= next;
1141     nal_data = data;
1142     nal_queue = rtph264pay->queue;
1143
1144     /* array must be empty when we get here */
1145     g_assert (nal_queue->len == 0);
1146
1147     GST_DEBUG_OBJECT (basepayload, "found first start at %u, bytes left %u",
1148         next, size);
1149
1150     /* first pass to locate NALs and parse SPS/PPS */
1151     while (size > 4) {
1152       /* skip start code */
1153       data += 3;
1154       size -= 3;
1155
1156       if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_SINGLE_NAL) {
1157         /* we are told that there is only a single NAL in this packet so that we
1158          * can avoid scanning for the next NAL. */
1159         next = size;
1160       } else {
1161         /* use next_start_code() to scan buffer.
1162          * next_start_code() returns the offset in data, 
1163          * starting from zero to the first byte of 0.0.0.1
1164          * If no start code is found, it returns the value of the 
1165          * 'size' parameter. 
1166          * data is unchanged by the call to next_start_code()
1167          */
1168         next = next_start_code (data, size);
1169
1170         if (next == size
1171             && rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM) {
1172           /* Didn't find the start of next NAL, handle it next time */
1173           break;
1174         }
1175       }
1176
1177       /* nal length is distance to next start code */
1178       nal_len = next;
1179
1180       GST_DEBUG_OBJECT (basepayload, "found next start at %u of size %u", next,
1181           nal_len);
1182
1183       if (rtph264pay->sprop_parameter_sets != NULL) {
1184         /* explicitly set profile and sprop, use those */
1185         if (rtph264pay->update_caps) {
1186           if (!gst_basertppayload_set_outcaps (basepayload,
1187                   "sprop-parameter-sets", G_TYPE_STRING,
1188                   rtph264pay->sprop_parameter_sets, NULL))
1189             goto caps_rejected;
1190
1191           /* parse SPS and PPS from provided parameter set (for insertion) */
1192           gst_rtp_h264_pay_parse_sprop_parameter_sets (rtph264pay);
1193
1194           rtph264pay->update_caps = FALSE;
1195
1196           GST_DEBUG ("outcaps update: sprop-parameter-sets=%s",
1197               rtph264pay->sprop_parameter_sets);
1198         }
1199       } else {
1200         /* We know our stream is a valid H264 NAL packet,
1201          * go parse it for SPS/PPS to enrich the caps */
1202         /* order: make sure to check nal */
1203         update =
1204             gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len, timestamp)
1205             || update;
1206       }
1207       /* move to next NAL packet */
1208       data += nal_len;
1209       size -= nal_len;
1210
1211       g_array_append_val (nal_queue, nal_len);
1212     }
1213
1214     /* if has new SPS & PPS, update the output caps */
1215     if (G_UNLIKELY (update))
1216       if (!gst_rtp_h264_pay_set_sps_pps (basepayload))
1217         goto caps_rejected;
1218
1219     /* second pass to payload and push */
1220     data = nal_data;
1221     pushed = 0;
1222
1223     for (i = 0; i < nal_queue->len; i++) {
1224       guint size;
1225       gboolean end_of_au = FALSE;
1226
1227       nal_len = g_array_index (nal_queue, guint, i);
1228       /* skip start code */
1229       data += 3;
1230
1231       /* Trim the end unless we're the last NAL in the buffer.
1232        * In case we're not at the end of the buffer we know the next block
1233        * starts with 0x000001 so all the 0x00 bytes at the end of this one are
1234        * trailing 0x0 that can be discarded */
1235       size = nal_len;
1236       if (i + 1 != nal_queue->len
1237           || rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM)
1238         for (; size > 1 && data[size - 1] == 0x0; size--)
1239           /* skip */ ;
1240
1241       /* If it's the last nal unit we have in non-bytestream mode, we can
1242        * assume it's the end of an access-unit
1243        *
1244        * FIXME: We need to wait until the next packet or EOS to
1245        * actually payload the NAL so we can know if the current NAL is
1246        * the last one of an access unit or not if we are in bytestream mode
1247        */
1248       if (rtph264pay->au_alignment &&
1249           rtph264pay->scan_mode != GST_H264_SCAN_MODE_BYTESTREAM &&
1250           i == nal_queue->len - 1)
1251         end_of_au = TRUE;
1252
1253       /* put the data in one or more RTP packets */
1254       ret =
1255           gst_rtp_h264_pay_payload_nal (basepayload, data, size, timestamp,
1256           buffer, end_of_au);
1257       if (ret != GST_FLOW_OK) {
1258         break;
1259       }
1260
1261       /* move to next NAL packet */
1262       data += nal_len;
1263       size -= nal_len;
1264       pushed += nal_len + 3;
1265     }
1266     g_array_set_size (nal_queue, 0);
1267   }
1268
1269   if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_BYTESTREAM)
1270     gst_adapter_flush (rtph264pay->adapter, pushed);
1271   else
1272     gst_buffer_unref (buffer);
1273
1274   return ret;
1275
1276 caps_rejected:
1277   {
1278     GST_WARNING_OBJECT (basepayload, "Could not set outcaps");
1279     g_array_set_size (nal_queue, 0);
1280     gst_buffer_unref (buffer);
1281     return GST_FLOW_NOT_NEGOTIATED;
1282   }
1283 }
1284
1285 static gboolean
1286 gst_rtp_h264_pay_handle_event (GstPad * pad, GstEvent * event)
1287 {
1288   const GstStructure *s;
1289   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (GST_PAD_PARENT (pad));
1290
1291   switch (GST_EVENT_TYPE (event)) {
1292     case GST_EVENT_FLUSH_STOP:
1293       gst_adapter_clear (rtph264pay->adapter);
1294       break;
1295     case GST_EVENT_CUSTOM_DOWNSTREAM:
1296       s = gst_event_get_structure (event);
1297       if (gst_structure_has_name (s, "GstForceKeyUnit")) {
1298         gboolean resend_codec_data;
1299
1300         if (gst_structure_get_boolean (s, "all-headers",
1301                 &resend_codec_data) && resend_codec_data)
1302           rtph264pay->send_spspps = TRUE;
1303       }
1304       break;
1305     default:
1306       break;
1307   }
1308
1309   return FALSE;
1310 }
1311
1312 static GstStateChangeReturn
1313 gst_basertppayload_change_state (GstElement * element,
1314     GstStateChange transition)
1315 {
1316   GstStateChangeReturn ret;
1317   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (element);
1318
1319   switch (transition) {
1320     case GST_STATE_CHANGE_READY_TO_PAUSED:
1321       rtph264pay->send_spspps = FALSE;
1322       gst_adapter_clear (rtph264pay->adapter);
1323       break;
1324     default:
1325       break;
1326   }
1327
1328   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1329
1330   return ret;
1331 }
1332
1333 static void
1334 gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
1335     const GValue * value, GParamSpec * pspec)
1336 {
1337   GstRtpH264Pay *rtph264pay;
1338
1339   rtph264pay = GST_RTP_H264_PAY (object);
1340
1341   switch (prop_id) {
1342     case PROP_PROFILE_LEVEL_ID:
1343       break;
1344     case PROP_SPROP_PARAMETER_SETS:
1345       g_free (rtph264pay->sprop_parameter_sets);
1346       rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
1347       rtph264pay->update_caps = TRUE;
1348       break;
1349     case PROP_SCAN_MODE:
1350       rtph264pay->scan_mode = g_value_get_enum (value);
1351       break;
1352     case PROP_BUFFER_LIST:
1353       rtph264pay->buffer_list = g_value_get_boolean (value);
1354       break;
1355     case PROP_CONFIG_INTERVAL:
1356       rtph264pay->spspps_interval = g_value_get_uint (value);
1357       break;
1358     default:
1359       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1360       break;
1361   }
1362 }
1363
1364 static void
1365 gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
1366     GValue * value, GParamSpec * pspec)
1367 {
1368   GstRtpH264Pay *rtph264pay;
1369
1370   rtph264pay = GST_RTP_H264_PAY (object);
1371
1372   switch (prop_id) {
1373     case PROP_PROFILE_LEVEL_ID:
1374       break;
1375     case PROP_SPROP_PARAMETER_SETS:
1376       g_value_set_string (value, rtph264pay->sprop_parameter_sets);
1377       break;
1378     case PROP_SCAN_MODE:
1379       g_value_set_enum (value, rtph264pay->scan_mode);
1380       break;
1381     case PROP_BUFFER_LIST:
1382       g_value_set_boolean (value, rtph264pay->buffer_list);
1383       break;
1384     case PROP_CONFIG_INTERVAL:
1385       g_value_set_uint (value, rtph264pay->spspps_interval);
1386       break;
1387     default:
1388       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1389       break;
1390   }
1391 }
1392
1393 gboolean
1394 gst_rtp_h264_pay_plugin_init (GstPlugin * plugin)
1395 {
1396   return gst_element_register (plugin, "rtph264pay",
1397       GST_RANK_SECONDARY, GST_TYPE_RTP_H264_PAY);
1398 }