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