rtp: Update codes based on 1.18.4 02/248402/4 accepted/tizen/unified/20210428.040408 submit/tizen/20210423.074026 submit/tizen/20210423.074051
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 25 Nov 2020 09:44:39 +0000 (18:44 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 22 Apr 2021 08:14:40 +0000 (08:14 +0000)
Use #ifndef/#endif directives with TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
to avoid build breaks from the gstreamer core not updated.
It can be removed when the gtreamer core is updated to 1.18 or higher version.

Change-Id: I2a3a7103fb74f2a7530f5696fef3a48bbbc23b0c
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
77 files changed:
gst/rtp/Makefile.am
gst/rtp/README
gst/rtp/gstbuffermemory.c [new file with mode: 0644]
gst/rtp/gstbuffermemory.h [new file with mode: 0644]
gst/rtp/gstrtp.c
gst/rtp/gstrtpL16depay.c
gst/rtp/gstrtpL16pay.c
gst/rtp/gstrtpL24depay.c
gst/rtp/gstrtpL24pay.c
gst/rtp/gstrtpL8depay.c
gst/rtp/gstrtpL8pay.c
gst/rtp/gstrtpac3depay.c
gst/rtp/gstrtpac3pay.c
gst/rtp/gstrtpamrdepay.c
gst/rtp/gstrtpamrpay.c
gst/rtp/gstrtpbvdepay.c
gst/rtp/gstrtpbvpay.c
gst/rtp/gstrtpceltpay.c
gst/rtp/gstrtpdvdepay.c
gst/rtp/gstrtpdvpay.c
gst/rtp/gstrtpg723pay.c
gst/rtp/gstrtpg726pay.c
gst/rtp/gstrtpg729pay.c
gst/rtp/gstrtpgsmpay.c
gst/rtp/gstrtpgstdepay.c
gst/rtp/gstrtpgstdepay.h
gst/rtp/gstrtpgstpay.c
gst/rtp/gstrtph261depay.c
gst/rtp/gstrtph261pay.c
gst/rtp/gstrtph263pay.c
gst/rtp/gstrtph263ppay.c
gst/rtp/gstrtph264depay.c
gst/rtp/gstrtph264depay.h
gst/rtp/gstrtph264pay.c
gst/rtp/gstrtph264pay.h
gst/rtp/gstrtph265depay.c
gst/rtp/gstrtph265depay.h
gst/rtp/gstrtph265pay.c
gst/rtp/gstrtph265pay.h
gst/rtp/gstrtpilbcdepay.c
gst/rtp/gstrtpj2kdepay.c
gst/rtp/gstrtpj2kpay.c
gst/rtp/gstrtpjpegdepay.c
gst/rtp/gstrtpjpegpay.c
gst/rtp/gstrtpklvdepay.c
gst/rtp/gstrtpklvpay.c
gst/rtp/gstrtpmp2tpay.c
gst/rtp/gstrtpmp4adepay.c
gst/rtp/gstrtpmp4apay.c
gst/rtp/gstrtpmp4gdepay.c
gst/rtp/gstrtpmp4gdepay.h
gst/rtp/gstrtpmp4gpay.c
gst/rtp/gstrtpmp4vpay.c
gst/rtp/gstrtpmp4vpay.h
gst/rtp/gstrtpmpapay.c
gst/rtp/gstrtpopuspay.c
gst/rtp/gstrtpreddec.c
gst/rtp/gstrtpredenc.c
gst/rtp/gstrtpsbcpay.c
gst/rtp/gstrtpspeexpay.c
gst/rtp/gstrtpstreamdepay.c
gst/rtp/gstrtpstreampay.c
gst/rtp/gstrtptheoradepay.c
gst/rtp/gstrtpulpfecdec.c
gst/rtp/gstrtpulpfecenc.c
gst/rtp/gstrtputils.c
gst/rtp/gstrtpvorbisdepay.c
gst/rtp/gstrtpvorbispay.c
gst/rtp/gstrtpvp8depay.c
gst/rtp/gstrtpvp8depay.h
gst/rtp/gstrtpvp8pay.c
gst/rtp/gstrtpvp9pay.c
gst/rtp/gstrtpvrawdepay.c
gst/rtp/meson.build
gst/rtp/rtpstorage.c
gst/rtp/rtpulpfeccommon.c
gst/rtp/rtpulpfeccommon.h

index 2e3b866..872856d 100644 (file)
@@ -102,7 +102,8 @@ libgstrtp_la_SOURCES = \
        gstrtpreddec.c \
        rtpstorage.c \
        rtpstoragestream.c \
-       gstrtpstorage.c
+       gstrtpstorage.c \
+       gstbuffermemory.c
 
 libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \
        $(GST_CFLAGS) -Dvp8_norm=gst_rtpvp8_vp8_norm \
@@ -222,7 +223,7 @@ noinst_HEADERS =                    \
        rtpredcommon.h \
        rtpstorage.h \
        rtpstoragestream.h \
-       rtpulpfeccommon.h
-
+       rtpulpfeccommon.h \
+       gstbuffermemory.h
 
 EXTRA_DIST = dboolhuff.LICENSE
index 11bd90d..a518598 100644 (file)
@@ -17,7 +17,7 @@ The following fields can or must (*) be specified in the structure:
 
  * payload: (int) [0, 127]
      For audio and video, these will normally be a media payload type as 
-     defined in the RTP Audio/Video Profile. For dynamicaly allocated 
+     defined in the RTP Audio/Video Profile. For dynamically allocated 
      payload types, this value will be >= 96 and the encoding-name must be
      set.
 
@@ -296,7 +296,7 @@ Some gst-launch-1.0 lines:
 
  The receiver now displays an h263 image. Since there is no jitterbuffer in the
  pipeline, frames will be displayed at the time when they are received. This can
- result in jerky playback in the case of high network jitter or currupted video
+ result in jerky playback in the case of high network jitter or corrupted video
  when packets are dropped or reordered.
 
  Stream a quicktime file with mpeg4 video and AAC audio on port 5000 and port
@@ -342,7 +342,7 @@ Some gst-launch-1.0 lines:
  recommended to use a gstrtpjitterbuffer after the udpsrc elements. 
  
  Even when sync is enabled, the two different streams will not play synchronised
- against eachother because the receiver does not have enough information to
+ against each other because the receiver does not have enough information to
  perform this task. For this you need to add the rtpbin element in both the
  sender and receiver pipeline and use additional sources and sinks to transmit
  RTCP packets used for inter-stream synchronisation.
diff --git a/gst/rtp/gstbuffermemory.c b/gst/rtp/gstbuffermemory.c
new file mode 100644 (file)
index 0000000..d6fd647
--- /dev/null
@@ -0,0 +1,120 @@
+/* GStreamer
+ * Copyright (C) 2020 Ognyan Tonchev <ognyan at axis dot com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gstbuffermemory.h"
+
+gboolean
+gst_buffer_memory_map (GstBuffer * buffer, GstBufferMemoryMap * map)
+{
+  GstMemory *mem;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+  g_return_val_if_fail (map != NULL, FALSE);
+
+  if (gst_buffer_n_memory (buffer) == 0) {
+    GST_DEBUG ("no memory blocks in buffer");
+    return FALSE;
+  }
+
+  mem = gst_buffer_get_memory (buffer, 0);
+
+  if (!gst_memory_map (mem, &map->map, GST_MAP_READ)) {
+    GST_ERROR ("failed to map memory");
+    gst_memory_unref (mem);
+    return FALSE;
+  }
+
+  map->buf = buffer;
+  map->mem = mem;
+  map->data = map->map.data;
+  map->size = map->map.size;
+  map->index = 0;
+  map->total_size = gst_buffer_get_size (buffer);
+  map->offset = 0;
+
+  return TRUE;
+}
+
+static gboolean
+buffer_memory_map_next (GstBufferMemoryMap * map)
+{
+  if (!map->mem)
+    return FALSE;
+
+  gst_memory_unmap (map->mem, &map->map);
+  gst_memory_unref (map->mem);
+  map->mem = NULL;
+  map->data = NULL;
+  map->size = 0;
+
+  map->index++;
+
+  if (map->index >= gst_buffer_n_memory (map->buf)) {
+    GST_DEBUG ("no more memory blocks in buffer");
+    return FALSE;
+  }
+
+  map->mem = gst_buffer_get_memory (map->buf, map->index);
+
+  if (!gst_memory_map (map->mem, &map->map, GST_MAP_READ)) {
+    GST_ERROR ("failed to map memory");
+    gst_memory_unref (map->mem);
+    map->mem = NULL;
+    return FALSE;
+  }
+
+  map->data = map->map.data;
+  map->size = map->map.size;
+
+  return TRUE;
+}
+
+gboolean
+gst_buffer_memory_advance_bytes (GstBufferMemoryMap * map, gsize size)
+{
+  gsize offset = size;
+
+  g_return_val_if_fail (map != NULL, FALSE);
+
+  map->offset += size;
+
+  while (offset >= map->size) {
+    offset -= map->size;
+    GST_DEBUG ("switching memory");
+    if (!buffer_memory_map_next (map))
+      return FALSE;
+  }
+
+  map->data += offset;
+  map->size -= offset;
+
+  return TRUE;
+}
+
+void
+gst_buffer_memory_unmap (GstBufferMemoryMap * map)
+{
+  g_return_if_fail (map != NULL);
+
+  if (map->mem) {
+    gst_memory_unmap (map->mem, &map->map);
+    gst_memory_unref (map->mem);
+    map->mem = NULL;
+  }
+}
diff --git a/gst/rtp/gstbuffermemory.h b/gst/rtp/gstbuffermemory.h
new file mode 100644 (file)
index 0000000..3b78429
--- /dev/null
@@ -0,0 +1,66 @@
+/* GStreamer
+ * Copyright (C) 2020 Ognyan Tonchev <ognyan at axis dot com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_BUFFER_MEMORY_H__
+#define __GST_BUFFER_MEMORY_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+struct _GstBufferMemoryMap
+{
+  /* private datas */
+
+  GstBuffer *buf;
+  GstMemory *mem;
+  GstMapInfo map;
+  guint index;
+  gsize total_size;
+
+  /* public datas */
+
+  /* data of the currently mapped memory */
+  const guint8 *data;
+  guint offset;
+
+  /* size of the currently mapped memory */
+  gsize size;
+
+  /* When advancing through the data with gst_buffer_memory_advance_bytes ()
+   * the data field is also advanced and the size field decreased with the
+   * corresponding number of bytes. If all the bytes from the currently mapped
+   * GstMemory have been consumed then a new GstMemory will be mapped and data
+   * and size fileds will be updated.
+   * */
+};
+typedef struct _GstBufferMemoryMap GstBufferMemoryMap;
+
+G_GNUC_INTERNAL
+gboolean gst_buffer_memory_map (GstBuffer * buffer, GstBufferMemoryMap * map);
+
+G_GNUC_INTERNAL
+gboolean gst_buffer_memory_advance_bytes (GstBufferMemoryMap * map, gsize size);
+
+G_GNUC_INTERNAL
+void gst_buffer_memory_unmap (GstBufferMemoryMap * map);
+
+G_END_DECLS
+
+#endif /* __GST_BUFFER_MEMORY_H__ */
index b0ab055..b2a6706 100644 (file)
 #include "gstrtpreddec.h"
 #include "gstrtpulpfecdec.h"
 #include "gstrtpulpfecenc.h"
-#include "gstrtpreddec.h"
-#include "gstrtpredenc.h"
 #include "gstrtpstorage.h"
 
 static gboolean
@@ -411,14 +409,6 @@ plugin_init (GstPlugin * plugin)
           GST_TYPE_RTP_ULPFEC_ENC))
     return FALSE;
 
-  if (!gst_element_register (plugin, "rtpreddec", GST_RANK_NONE,
-          GST_TYPE_RTP_RED_DEC))
-    return FALSE;
-
-  if (!gst_element_register (plugin, "rtpredenc", GST_RANK_NONE,
-          GST_TYPE_RTP_RED_ENC))
-    return FALSE;
-
   if (!gst_element_register (plugin, "rtpstorage", GST_RANK_NONE,
           GST_TYPE_RTP_STORAGE))
     return FALSE;
index 3695da9..f054a24 100644 (file)
 
 /**
  * SECTION:element-rtpL16depay
+ * @title: rtpL16depay
  * @see_also: rtpL16pay
  *
  * Extract raw audio from RTP packets according to RFC 3551.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL16depay ! pulsesink
  * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
  * the rtpL16pay example to create the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -209,6 +209,7 @@ gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
             GST_STR_NULL (channel_order), channels));
     /* create default NONE layout */
     gst_rtp_channels_create_default (channels, info->position);
+    info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
   }
 
   srccaps = gst_audio_info_to_caps (info);
@@ -279,12 +280,14 @@ wrong_payload_size:
   {
     GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE,
         ("Wrong Payload Size."), (NULL));
+    gst_buffer_unref (outbuf);
     return NULL;
   }
 reorder_failed:
   {
     GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE,
         ("Channel reordering failed."), (NULL));
+    gst_buffer_unref (outbuf);
     return NULL;
   }
 }
index 4783a65..7e358d3 100644 (file)
 
 /**
  * SECTION:element-rtpL16pay
+ * @title: rtpL16pay
  * @see_also: rtpL16depay
  *
  * Payload raw audio into RTP packets according to RFC 3551.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL16pay ! udpsink
  * ]| This example pipeline will payload raw audio. Refer to
  * the rtpL16depay example to depayload and play the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index 8b28ee8..448dac0 100644 (file)
 
 /**
  * SECTION:element-rtpL24depay
+ * @title: rtpL24depay
  * @see_also: rtpL24pay
  *
  * Extract raw audio from RTP packets according to RFC 3190, section 4.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L24, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL24depay ! pulsesink
  * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
  * the rtpL24pay example to create the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -187,6 +187,7 @@ gst_rtp_L24_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
             GST_STR_NULL (channel_order), channels));
     /* create default NONE layout */
     gst_rtp_channels_create_default (channels, info->position);
+    info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
   }
 
   srccaps = gst_audio_info_to_caps (info);
index 936bd44..d2ad725 100644 (file)
 
 /**
  * SECTION:element-rtpL24pay
+ * @title: rtpL24pay
  * @see_also: rtpL24depay
  *
  * Payload raw 24-bit audio into RTP packets according to RFC 3190, section 4.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3190.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 -v audiotestsrc ! audioconvert ! rtpL24pay ! udpsink
  * ]| This example pipeline will payload raw audio. Refer to
  * the rtpL24depay example to depayload and play the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index 5b9520a..121a749 100644 (file)
  * Extract raw audio from RTP packets according to RFC 3551.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
+ *
  * |[
  * gst-launch udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L8, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL8depay ! pulsesink
  * ]| This example pipeline will depayload an RTP raw audio stream. Refer to
  * the rtpL8pay example to create the RTP stream.
- * </refsect2>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -187,6 +186,7 @@ gst_rtp_L8_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
             GST_STR_NULL (channel_order), channels));
     /* create default NONE layout */
     gst_rtp_channels_create_default (channels, info->position);
+    info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
   }
 
   srccaps = gst_audio_info_to_caps (info);
index cf2a3b9..6662cda 100644 (file)
  * Payload raw audio into RTP packets according to RFC 3551.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
+ *
  * |[
  * gst-launch -v audiotestsrc ! audioconvert ! rtpL8pay ! udpsink
  * ]| This example pipeline will payload raw audio. Refer to
  * the rtpL8depay example to depayload and play the RTP stream.
- * </refsect2>
  */
 
 #ifdef HAVE_CONFIG_H
index ec2b3ba..54339f3 100644 (file)
 
 /**
  * SECTION:element-rtpac3depay
+ * @title: rtpac3depay
  * @see_also: rtpac3pay
  *
  * Extract AC3 audio from RTP packets according to RFC 4184.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)AC3, payload=(int)96' ! rtpac3depay ! a52dec ! pulsesink
  * ]| This example pipeline will depayload and decode an RTP AC3 stream. Refer to
  * the rtpac3pay example to create the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index 7c797b7..1fecced 100644 (file)
 
 /**
  * SECTION:element-rtpac3pay
+ * @title: rtpac3pay
  * @see_also: rtpac3depay
  *
  * Payload AC3 audio into RTP packets according to RFC 4184.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc4184.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 -v audiotestsrc ! avenc_ac3 ! rtpac3pay ! udpsink
  * ]| This example pipeline will encode and payload AC3 stream. Refer to
  * the rtpac3depay example to depayload and decode the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -274,7 +274,9 @@ gst_rtp_ac3_pay_flush (GstRtpAC3Pay * rtpac3pay)
     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
 
     /* create buffer to hold the payload */
-    outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (rtpac3pay), 2, 0, 0);
 
     if (FT == 0) {
       /* check if it all fits */
index 7a7c797..de02758 100644 (file)
 
 /**
  * SECTION:element-rtpamrdepay
+ * @title: rtpamrdepay
  * @see_also: rtpamrpay
  *
  * Extract AMR audio from RTP packets according to RFC 3267.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)8000, encoding-name=(string)AMR, encoding-params=(string)1, octet-align=(string)1, payload=(int)96' ! rtpamrdepay ! amrnbdec ! pulsesink
  * ]| This example pipeline will depayload and decode an RTP AMR stream. Refer to
  * the rtpamrpay example to create the RTP stream.
- * </refsect2>
+ *
  */
 
 /*
index 5e70f0a..828a718 100644 (file)
 
 /**
  * SECTION:element-rtpamrpay
+ * @title: rtpamrpay
  * @see_also: rtpamrdepay
  *
  * Payload AMR audio into RTP packets according to RFC 3267.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc3267.txt
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 -v audiotestsrc ! amrnbenc ! rtpamrpay ! udpsink
  * ]| This example pipeline will encode and payload an AMR stream. Refer to
  * the rtpamrdepay example to depayload and decode the RTP stream.
- * </refsect2>
+ *
  */
 
 /* references:
@@ -312,7 +312,9 @@ gst_rtp_amr_pay_handle_buffer (GstRTPBasePayload * basepayload,
     goto too_big;
 
   /* now alloc output buffer */
-  outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+  outbuf =
+      gst_rtp_base_payload_allocate_output_buffer (basepayload, payload_len, 0,
+      0);
 
   gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
index a0faf83..625bb37 100644 (file)
@@ -19,6 +19,7 @@
 
 /**
  * SECTION:element-rtpbvdepay
+ * @title: rtpbvdepay
  * @see_also: rtpbvpay
  *
  * Extract BroadcomVoice audio from RTP packets according to RFC 4298.
index e202015..a396d26 100644 (file)
@@ -19,6 +19,7 @@
 
 /**
  * SECTION:element-rtpbvpay
+ * @title: rtpbvpay
  * @see_also: rtpbvdepay
  *
  * Payload BroadcomVoice audio into RTP packets according to RFC 4298.
index c498897..a29d23b 100644 (file)
@@ -332,7 +332,9 @@ gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay)
       payload_len, GST_TIME_ARGS (rtpceltpay->qduration));
 
   /* get a big enough packet for the sizes + payloads */
-  outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+  outbuf =
+      gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+      (rtpceltpay), payload_len, 0, 0);
 
   GST_BUFFER_DURATION (outbuf) = duration;
 
index 0235b71..12297f0 100644 (file)
@@ -288,7 +288,7 @@ foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
 
 /* Process one RTP packet. Accumulate RTP payload in the proper place in a DV
  * frame, and return that frame if we detect a new frame, or NULL otherwise.
- * We assume a DV frame is 144000 bytes. That should accomodate PAL as well as
+ * We assume a DV frame is 144000 bytes. That should accommodate PAL as well as
  * NTSC.
  */
 static GstBuffer *
index 4408806..ac8579b 100644 (file)
@@ -132,6 +132,10 @@ gst_rtp_dv_pay_class_init (GstRTPDVPayClass * klass)
 
   gstrtpbasepayload_class->set_caps = gst_rtp_dv_pay_setcaps;
   gstrtpbasepayload_class->handle_buffer = gst_rtp_dv_pay_handle_buffer;
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_DV_PAY_MODE, 0);
+#endif
 }
 
 static void
index cb6dff5..18e294a 100644 (file)
@@ -144,8 +144,9 @@ gst_rtp_g723_pay_flush (GstRTPG723Pay * pay)
 
   avail = gst_adapter_available (pay->adapter);
 
-  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
-
+  outbuf =
+      gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD (pay),
+      0, 0, 0);
   gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
   GST_BUFFER_PTS (outbuf) = pay->timestamp;
index 0716e51..d251b49 100644 (file)
@@ -220,7 +220,7 @@ gst_rtp_g726_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
     encoding_name =
         g_strdup (gst_structure_get_string (structure, "encoding-name"));
 
-    /* if we managed to negotiate to AAL2, we definatly are going to do AAL2
+    /* if we managed to negotiate to AAL2, we definitely are going to do AAL2
      * encoding. Else we only encode AAL2 when explicitly set by the
      * property. */
     if (g_str_has_prefix (encoding_name, "AAL2-"))
index 378fa64..7809780 100644 (file)
@@ -167,7 +167,9 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay, GstBuffer * buf)
       payload_len, GST_TIME_ARGS (rtpg729pay->next_ts));
 
   /* create buffer to hold the payload */
-  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+  outbuf =
+      gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+      (rtpg729pay), 0, 0, 0);
 
   gst_rtp_buffer_map (outbuf, GST_MAP_READWRITE, &rtp);
 
index aa239a8..25fa0fa 100644 (file)
@@ -145,7 +145,7 @@ gst_rtp_gsm_pay_handle_buffer (GstRTPBasePayload * basepayload,
   if (payload_len > GST_RTP_BASE_PAYLOAD_MTU (rtpgsmpay))
     goto too_big;
 
-  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+  outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
 
   /* copy timestamp and duration */
   GST_BUFFER_PTS (outbuf) = timestamp;
index 489f6a8..0f08177 100644 (file)
@@ -116,31 +116,13 @@ gst_rtp_gst_depay_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
-static gboolean
-store_cache (GstRtpGSTDepay * rtpgstdepay, guint CV, GstCaps * caps)
-{
-  gboolean changed = FALSE;
-
-  if (caps && rtpgstdepay->CV_cache[CV])
-    changed = !gst_caps_is_strictly_equal (caps, rtpgstdepay->CV_cache[CV]);
-
-  if (rtpgstdepay->CV_cache[CV])
-    gst_caps_unref (rtpgstdepay->CV_cache[CV]);
-  rtpgstdepay->CV_cache[CV] = caps;
-
-  return changed;
-}
-
 static void
 gst_rtp_gst_depay_reset (GstRtpGSTDepay * rtpgstdepay, gboolean full)
 {
-  guint i;
-
   gst_adapter_clear (rtpgstdepay->adapter);
   if (full) {
     rtpgstdepay->current_CV = 0;
-    for (i = 0; i < 8; i++)
-      store_cache (rtpgstdepay, i, NULL);
+    gst_caps_replace (&rtpgstdepay->current_caps, NULL);
     g_free (rtpgstdepay->stream_id);
     rtpgstdepay->stream_id = NULL;
     if (rtpgstdepay->tags)
@@ -189,14 +171,14 @@ gst_rtp_gst_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
     }
     /* store in cache */
     rtpgstdepay->current_CV = CV;
-    gst_caps_ref (outcaps);
-    store_cache (rtpgstdepay, CV, outcaps);
+    gst_caps_replace (&rtpgstdepay->current_caps, outcaps);
 
     res = gst_pad_set_caps (depayload->srcpad, outcaps);
     gst_caps_unref (outcaps);
   } else {
     GST_WARNING_OBJECT (depayload, "no caps given");
     rtpgstdepay->current_CV = -1;
+    gst_caps_replace (&rtpgstdepay->current_caps, NULL);
     res = TRUE;
   }
 
@@ -471,8 +453,12 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
       GST_DEBUG_OBJECT (rtpgstdepay,
           "inline caps %u, length %u, %" GST_PTR_FORMAT, CV, size, outcaps);
 
-      if (store_cache (rtpgstdepay, CV, outcaps))
+      if (!rtpgstdepay->current_caps
+          || !gst_caps_is_strictly_equal (rtpgstdepay->current_caps, outcaps))
         gst_pad_set_caps (depayload->srcpad, outcaps);
+      gst_caps_replace (&rtpgstdepay->current_caps, outcaps);
+      gst_caps_unref (outcaps);
+      rtpgstdepay->current_CV = CV;
 
       /* skip caps */
       offset += size;
@@ -512,17 +498,9 @@ gst_rtp_gst_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
 
       /* see what caps we need */
       if (CV != rtpgstdepay->current_CV) {
-        /* we need to switch caps, check if we have the caps */
-        if ((outcaps = rtpgstdepay->CV_cache[CV]) == NULL)
-          goto missing_caps;
-
-        GST_DEBUG_OBJECT (rtpgstdepay,
-            "need caps switch from %u to %u, %" GST_PTR_FORMAT,
-            rtpgstdepay->current_CV, CV, outcaps);
-
-        /* and set caps */
-        if (gst_pad_set_caps (depayload->srcpad, outcaps))
-          rtpgstdepay->current_CV = CV;
+        /* we need to switch caps but didn't receive the new caps yet */
+        gst_caps_replace (&rtpgstdepay->current_caps, NULL);
+        goto missing_caps;
       }
 
       if (payload[0] & 0x8)
index 4b8f2c6..9ea9ec6 100644 (file)
@@ -46,7 +46,7 @@ struct _GstRtpGSTDepay
 
   GstAdapter *adapter;
   guint current_CV;
-  GstCaps *CV_cache[8];
+  GstCaps *current_caps;
 
   GstTagList *tags;
   gchar *stream_id;
index c1aa439..15b281b 100644 (file)
@@ -289,7 +289,7 @@ gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
     GstBuffer *paybuf;
 
 
-    /* this will be the total lenght of the packet */
+    /* this will be the total length of the packet */
     packet_len = gst_rtp_buffer_calc_packet_len (8 + avail, 0, 0);
 
     /* fill one MTU or all available bytes */
@@ -299,7 +299,9 @@ gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
 
     /* create buffer to hold the header */
-    outbuf = gst_rtp_buffer_new_allocate (8, 0, 0);
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (rtpgstpay), 8, 0, 0);
 
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
     payload = gst_rtp_buffer_get_payload (&rtp);
@@ -421,8 +423,17 @@ gst_rtp_gst_pay_send_caps (GstRtpGSTPay * rtpgstpay, guint8 cv, GstCaps * caps)
   guint capslen;
   GstBuffer *outbuf;
 
-  if (rtpgstpay->flags & (1 << 7))
+  if (rtpgstpay->flags == ((1 << 7) | (cv << 4))) {
+    /* If caps for the current CV are pending in the adapter already, do
+     * nothing at all here
+     */
     return;
+  } else if (rtpgstpay->flags & (1 << 7)) {
+    /* Create a new standalone caps packet if caps were already pending.
+     * The next caps are going to be merged with the following buffer or
+     * sent standalone if another event is sent first */
+    gst_rtp_gst_pay_create_from_adapter (rtpgstpay, GST_CLOCK_TIME_NONE);
+  }
 
   capsstr = gst_caps_to_string (caps);
   capslen = strlen (capsstr);
index 5d37229..164d2f0 100644 (file)
@@ -20,6 +20,7 @@
 
 /**
  * SECTION:element-rtph261depay
+ * @title: rtph261depay
  * @see_also: rtph261pay
  *
  * Extract encoded H.261 video frames from RTP packets according to RFC 4587.
  * aggregates the extracted stream until a complete frame is received before
  * it pushes it downstream.
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, payload=31' ! rtph261depay ! avdec_h261 ! autovideosink
  * ]| This example pipeline will depayload and decode an RTP H.261 video stream.
  * Refer to the rtph261pay example to create the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index b592d11..9b8c0d9 100644 (file)
@@ -20,6 +20,7 @@
 
 /**
  * SECTION:element-rtph261pay
+ * @title: rtph261pay
  * @see_also: rtph261depay
  *
  * Payload encoded H.261 video frames into RTP packets according to RFC 4587.
  * encoder does not produce a continuous bit-stream but the decoder requires
  * it.
  *
- * <refsect2>
- * <title>Example launch line</title>
+ * ## Example launch line
  * |[
  * gst-launch-1.0 videotestsrc ! avenc_h261 ! rtph261pay ! udpsink
  * ]| This will encode a test video and payload it. Refer to the rtph261depay
  * example to depayload and play the RTP stream.
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -773,7 +773,7 @@ find_gob (GstRtpH261Pay * pay, const guint8 * data, guint size, guint pos)
   return ret;
 }
 
-/* Scans after all GOB start codes and initalizes the GOB structure with start
+/* Scans after all GOB start codes and initializes the GOB structure with start
  * and end positions. */
 static ParseReturn
 gst_rtp_h261_pay_init_gobs (GstRtpH261Pay * pay, Gob * gobs, gint num_gobs,
@@ -947,7 +947,7 @@ gst_rtp_h261_pay_shift_buffer (GstRtpH261Pay * pay, const guint8 * data,
     gsize size, gint offset, gsize * newsize)
 {
   /* In order to read variable length codes at the very end of the buffer
-   * wihout peeking into possibly unallocated data, we pad with extra 0's
+   * without peeking into possibly unallocated data, we pad with extra 0's
    * which will generate an invalid code at the end of the buffer. */
   guint pad = 4;
   gsize allocsize = size + pad;
index 4163bcd..a8def87 100644 (file)
@@ -1708,7 +1708,7 @@ gst_rtp_h263_pay_flush (GstRtpH263Pay * rtph263pay)
 
     GST_DEBUG_OBJECT (rtph263pay, "Frame too large for MTU");
     /*
-     * Let's go trough all the data and fragment it untill end is reached
+     * Let's go trough all the data and fragment it until end is reached
      */
 
     gst_rtp_h263_pay_boundry_init (&bound, NULL, rtph263pay->data - 1, 0, 0);
index a73f00e..6bb9e4a 100644 (file)
@@ -151,6 +151,10 @@ gst_rtp_h263p_pay_class_init (GstRtpH263PPayClass * klass)
 
   GST_DEBUG_CATEGORY_INIT (rtph263ppay_debug, "rtph263ppay",
       0, "rtph263ppay (RFC 4629)");
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_FRAGMENTATION_MODE, 0);
+#endif
 }
 
 static void
@@ -680,7 +684,7 @@ gst_rtp_h263p_pay_flush (GstRtpH263PPay * rtph263ppay)
    *  This algorithm separates large frames at synchronisation points (Segments)
    *  (See RFC 4629 section 6). It would be interesting to have a property such as network
    *  quality to select between both packetization methods */
-  /* TODO Add VRC supprt (See RFC 4629 section 5.2) */
+  /* TODO Add VRC support (See RFC 4629 section 5.2) */
 
   while (avail > 0) {
     guint towrite;
index 275a9a0..cc92c9a 100644 (file)
@@ -59,7 +59,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"video\", "
         "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
-        /** optional parameters **/
+    /* optional parameters */
     /* "profile-level-id = (string) ANY, " */
     /* "max-mbps = (string) ANY, " */
     /* "max-fs = (string) ANY, " */
@@ -1035,6 +1035,7 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
     gst_adapter_clear (rtph264depay->adapter);
     rtph264depay->wait_start = TRUE;
     rtph264depay->current_fu_type = 0;
+    rtph264depay->last_fu_seqnum = 0;
   }
 
   {
@@ -1114,7 +1115,7 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
            */
           nalu_size = (payload[0] << 8) | payload[1];
 
-          /* dont include nalu_size */
+          /* don't include nalu_size */
           if (nalu_size > (payload_len - 2))
             nalu_size = payload_len - 2;
 
@@ -1194,6 +1195,7 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
 
           rtph264depay->current_fu_type = nal_unit_type;
           rtph264depay->fu_timestamp = timestamp;
+          rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);
 
           rtph264depay->wait_start = FALSE;
 
@@ -1221,6 +1223,25 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
           /* and assemble in the adapter */
           gst_adapter_push (rtph264depay->adapter, outbuf);
         } else {
+          if (rtph264depay->current_fu_type == 0) {
+            /* previous FU packet missing start bit? */
+            GST_WARNING_OBJECT (rtph264depay, "missing FU start bit on an "
+                "earlier packet. Dropping.");
+            gst_adapter_clear (rtph264depay->adapter);
+            return NULL;
+          }
+          if (gst_rtp_buffer_compare_seqnum (rtph264depay->last_fu_seqnum,
+                  gst_rtp_buffer_get_seq (rtp)) != 1) {
+            /* jump in sequence numbers within an FU is cause for discarding */
+            GST_WARNING_OBJECT (rtph264depay, "Jump in sequence numbers from "
+                "%u to %u within Fragmentation Unit. Data was lost, dropping "
+                "stored.", rtph264depay->last_fu_seqnum,
+                gst_rtp_buffer_get_seq (rtp));
+            gst_adapter_clear (rtph264depay->adapter);
+            return NULL;
+          }
+          rtph264depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);
+
           /* strip off FU indicator and FU header bytes */
           payload += 2;
           payload_len -= 2;
index ba41312..2cb2167 100644 (file)
@@ -59,6 +59,7 @@ struct _GstRtpH264Depay
 
   /* Work around broken payloaders wrt. FU-A & FU-B */
   guint8 current_fu_type;
+  guint16 last_fu_seqnum;
   GstClockTime fu_timestamp;
   gboolean fu_marker;
 
index 4f6a04a..57d7bf4 100644 (file)
 
 #include "gstrtph264pay.h"
 #include "gstrtputils.h"
+#include "gstbuffermemory.h"
 
 
-#define IDR_TYPE_ID  5
-#define SPS_TYPE_ID  7
-#define PPS_TYPE_ID  8
+#define IDR_TYPE_ID    5
+#define SPS_TYPE_ID    7
+#define PPS_TYPE_ID    8
+#define AUD_TYPE_ID    9
+#define STAP_A_TYPE_ID 24
+#define FU_A_TYPE_ID   28
 
 GST_DEBUG_CATEGORY_STATIC (rtph264pay_debug);
 #define GST_CAT_DEFAULT (rtph264pay_debug)
 
+#define GST_TYPE_RTP_H264_AGGREGATE_MODE \
+  (gst_rtp_h264_aggregate_mode_get_type ())
+
+
+static GType
+gst_rtp_h264_aggregate_mode_get_type (void)
+{
+  static GType type = 0;
+  static const GEnumValue values[] = {
+    {GST_RTP_H264_AGGREGATE_NONE, "Do not aggregate NAL units", "none"},
+    {GST_RTP_H264_AGGREGATE_ZERO_LATENCY,
+        "Aggregate NAL units until a VCL unit is included", "zero-latency"},
+    {GST_RTP_H264_AGGREGATE_MAX_STAP,
+        "Aggregate all NAL units with the same timestamp (adds one frame of"
+          " latency)", "max-stap"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRtpH264AggregateMode", values);
+  }
+  return type;
+}
+
+
+
 /* references:
- *
+*
  * RFC 3984
  */
 
@@ -68,13 +98,15 @@ GST_STATIC_PAD_TEMPLATE ("src",
     );
 
 #define DEFAULT_SPROP_PARAMETER_SETS    NULL
-#define DEFAULT_CONFIG_INTERVAL                      0
+#define DEFAULT_CONFIG_INTERVAL         0
+#define DEFAULT_AGGREGATE_MODE          GST_RTP_H264_AGGREGATE_NONE
 
 enum
 {
   PROP_0,
   PROP_SPROP_PARAMETER_SETS,
-  PROP_CONFIG_INTERVAL
+  PROP_CONFIG_INTERVAL,
+  PROP_AGGREGATE_MODE,
 };
 
 static void gst_rtp_h264_pay_finalize (GObject * object);
@@ -94,6 +126,10 @@ static gboolean gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload,
     GstEvent * event);
 static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement *
     element, GstStateChange transition);
+static gboolean gst_rtp_h264_pay_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static void gst_rtp_h264_pay_reset_bundle (GstRtpH264Pay * rtph264pay);
 
 #define gst_rtp_h264_pay_parent_class parent_class
 G_DEFINE_TYPE (GstRtpH264Pay, gst_rtp_h264_pay, GST_TYPE_RTP_BASE_PAYLOAD);
@@ -131,6 +167,29 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
       );
 
+  /**
+   * GstRtpH264Pay:aggregate-mode
+   *
+   * Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets.
+   *
+   * This can potentially reduce RTP packetization overhead but not all
+   * RTP implementations handle it correctly.
+   *
+   * For best compatibility, it is recommended to set this to "none" (the
+   * default) for RTSP and for WebRTC to "zero-latency".
+   *
+   * Since: 1.18
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_AGGREGATE_MODE,
+      g_param_spec_enum ("aggregate-mode",
+          "Attempt to use aggregate packets",
+          "Bundle suitable SPS/PPS NAL units into STAP-A "
+          "aggregate packets",
+          GST_TYPE_RTP_H264_AGGREGATE_MODE,
+          DEFAULT_AGGREGATE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
   gobject_class->finalize = gst_rtp_h264_pay_finalize;
 
   gst_element_class_add_static_pad_template (gstelement_class,
@@ -153,6 +212,9 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
 
   GST_DEBUG_CATEGORY_INIT (rtph264pay_debug, "rtph264pay", 0,
       "H264 RTP Payloader");
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_RTP_H264_AGGREGATE_MODE, 0);
+#endif
 }
 
 static void
@@ -166,10 +228,14 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
       (GDestroyNotify) gst_buffer_unref);
   rtph264pay->last_spspps = -1;
   rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
+  rtph264pay->aggregate_mode = DEFAULT_AGGREGATE_MODE;
   rtph264pay->delta_unit = FALSE;
   rtph264pay->discont = FALSE;
 
   rtph264pay->adapter = gst_adapter_new ();
+
+  gst_pad_set_query_function (GST_RTP_BASE_PAYLOAD_SRCPAD (rtph264pay),
+      gst_rtp_h264_pay_src_query);
 }
 
 static void
@@ -194,6 +260,7 @@ gst_rtp_h264_pay_finalize (GObject * object)
   g_free (rtph264pay->sprop_parameter_sets);
 
   g_object_unref (rtph264pay->adapter);
+  gst_rtp_h264_pay_reset_bundle (rtph264pay);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -353,6 +420,42 @@ done:
   return caps;
 }
 
+static gboolean
+gst_rtp_h264_pay_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (parent);
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) {
+    gboolean retval;
+    gboolean live;
+    GstClockTime min_latency, max_latency;
+
+    retval = gst_pad_query_default (pad, parent, query);
+    if (!retval)
+      return retval;
+
+    if (rtph264pay->stream_format == GST_H264_STREAM_FORMAT_UNKNOWN ||
+        rtph264pay->alignment == GST_H264_ALIGNMENT_UNKNOWN)
+      return FALSE;
+
+    gst_query_parse_latency (query, &live, &min_latency, &max_latency);
+
+    if (rtph264pay->aggregate_mode == GST_RTP_H264_AGGREGATE_MAX_STAP &&
+        rtph264pay->alignment != GST_H264_ALIGNMENT_AU && rtph264pay->fps_num) {
+      GstClockTime one_frame = gst_util_uint64_scale_int (GST_SECOND,
+          rtph264pay->fps_denum, rtph264pay->fps_num);
+
+      min_latency += one_frame;
+      max_latency += one_frame;
+      gst_query_set_latency (query, live, min_latency, max_latency);
+    }
+    return TRUE;
+  }
+
+  return gst_pad_query_default (pad, parent, query);
+}
+
+
 /* take the currently configured SPS and PPS lists and set them on the caps as
  * sprop-parameter-sets */
 static gboolean
@@ -459,6 +562,10 @@ gst_rtp_h264_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
       rtph264pay->stream_format = GST_H264_STREAM_FORMAT_BYTESTREAM;
   }
 
+  if (!gst_structure_get_fraction (str, "framerate", &rtph264pay->fps_num,
+          &rtph264pay->fps_denum))
+    rtph264pay->fps_num = rtph264pay->fps_denum = 0;
+
   /* packetized AVC video has a codec_data */
   if ((value = gst_structure_get_value (str, "codec_data"))) {
     guint num_sps, num_pps;
@@ -732,9 +839,25 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
     gboolean delta_unit, gboolean discont);
 
 static GstFlowReturn
+gst_rtp_h264_pay_payload_nal_single (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont);
+
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal_fragment (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont, guint8 nal_header);
+
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont, guint8 nal_header);
+
+static GstFlowReturn
 gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
-    GstRtpH264Pay * rtph264pay, GstClockTime dts, GstClockTime pts)
+    GstClockTime dts, GstClockTime pts, gboolean delta_unit, gboolean discont)
 {
+  GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (basepayload);
   GstFlowReturn ret = GST_FLOW_OK;
   gboolean sent_all_sps_pps = TRUE;
   guint i;
@@ -746,7 +869,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
     GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
     /* resend SPS */
     ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
-        dts, pts, FALSE, FALSE, FALSE);
+        dts, pts, FALSE, delta_unit, discont);
     /* Not critical here; but throw a warning */
     if (ret != GST_FLOW_OK) {
       sent_all_sps_pps = FALSE;
@@ -760,7 +883,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
     GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
     /* resend PPS */
     ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
-        dts, pts, FALSE, FALSE, FALSE);
+        dts, pts, FALSE, TRUE, FALSE);
     /* Not critical here; but throw a warning */
     if (ret != GST_FLOW_OK) {
       sent_all_sps_pps = FALSE;
@@ -787,31 +910,25 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
     gboolean delta_unit, gboolean discont)
 {
   GstRtpH264Pay *rtph264pay;
-  GstFlowReturn ret;
-  guint8 nalHeader;
-  guint8 nalType;
-  guint packet_len, payload_len, mtu;
-  GstBuffer *outbuf;
-  guint8 *payload;
-  GstBufferList *list = NULL;
+  guint8 nal_header, nal_type;
   gboolean send_spspps;
-  GstRTPBuffer rtp = { NULL };
-  guint size = gst_buffer_get_size (paybuf);
+  guint size;
 
   rtph264pay = GST_RTP_H264_PAY (basepayload);
-  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
+  size = gst_buffer_get_size (paybuf);
 
-  gst_buffer_extract (paybuf, 0, &nalHeader, 1);
-  nalType = nalHeader & 0x1f;
+  gst_buffer_extract (paybuf, 0, &nal_header, 1);
+  nal_type = nal_header & 0x1f;
 
   /* These payload type are reserved for STAP-A, STAP-B, MTAP16, and MTAP24
    * as internally used NAL types */
-  switch (nalType) {
+  switch (nal_type) {
     case 24:
     case 25:
     case 26:
     case 27:
-      GST_WARNING_OBJECT (rtph264pay, "Ignoring reserved NAL TYPE=%d", nalType);
+      GST_WARNING_OBJECT (rtph264pay, "Ignoring reserved NAL TYPE=%d",
+          nal_type);
       gst_buffer_unref (paybuf);
       return GST_FLOW_OK;
     default:
@@ -819,8 +936,8 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
   }
 
   GST_DEBUG_OBJECT (rtph264pay,
-      "Processing Buffer with NAL TYPE=%d %" GST_TIME_FORMAT,
-      nalType, GST_TIME_ARGS (pts));
+      "payloading NAL Unit: datasize=%u type=%d pts=%" GST_TIME_FORMAT,
+      size, nal_type, GST_TIME_ARGS (pts));
 
   /* should set src caps before pushing stuff,
    * and if we did not see enough SPS/PPS, that may not be the case */
@@ -831,7 +948,7 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
   send_spspps = FALSE;
 
   /* check if we need to emit an SPS/PPS now */
-  if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
+  if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval > 0) {
     if (rtph264pay->last_spspps != -1) {
       guint64 diff;
       GstClockTime running_time =
@@ -863,7 +980,7 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
       GST_DEBUG_OBJECT (rtph264pay, "no previous SPS/PPS time, send now");
       send_spspps = TRUE;
     }
-  } else if (nalType == IDR_TYPE_ID && rtph264pay->spspps_interval == -1) {
+  } else if (nal_type == IDR_TYPE_ID && rtph264pay->spspps_interval == -1) {
     GST_DEBUG_OBJECT (rtph264pay, "sending SPS/PPS before current IDR frame");
     /* send SPS/PPS before every IDR frame */
     send_spspps = TRUE;
@@ -872,33 +989,103 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
   if (send_spspps || rtph264pay->send_spspps) {
     /* we need to send SPS/PPS now first. FIXME, don't use the pts for
      * checking when we need to send SPS/PPS but convert to running_time first. */
+    GstFlowReturn ret;
+
     rtph264pay->send_spspps = FALSE;
-    ret = gst_rtp_h264_pay_send_sps_pps (basepayload, rtph264pay, dts, pts);
+
+    ret = gst_rtp_h264_pay_send_sps_pps (basepayload, dts, pts, delta_unit,
+        discont);
     if (ret != GST_FLOW_OK) {
       gst_buffer_unref (paybuf);
       return ret;
     }
+
+    delta_unit = TRUE;
+    discont = FALSE;
+  }
+
+  if (rtph264pay->aggregate_mode != GST_RTP_H264_AGGREGATE_NONE)
+    return gst_rtp_h264_pay_payload_nal_bundle (basepayload, paybuf, dts, pts,
+        end_of_au, delta_unit, discont, nal_header);
+
+  return gst_rtp_h264_pay_payload_nal_fragment (basepayload, paybuf, dts, pts,
+      end_of_au, delta_unit, discont, nal_header);
+}
+
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal_fragment (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont, guint8 nal_header)
+{
+  GstRtpH264Pay *rtph264pay;
+  guint mtu, size, max_fragment_size, max_fragments, ii, pos;
+  GstBuffer *outbuf;
+  guint8 *payload;
+  GstBufferList *list = NULL;
+  GstRTPBuffer rtp = { NULL };
+
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
+  size = gst_buffer_get_size (paybuf);
+
+  if (gst_rtp_buffer_calc_packet_len (size, 0, 0) <= mtu) {
+    /* We don't need to fragment this packet */
+    GST_DEBUG_OBJECT (rtph264pay,
+        "sending NAL Unit: datasize=%u mtu=%u", size, mtu);
+    return gst_rtp_h264_pay_payload_nal_single (basepayload, paybuf, dts, pts,
+        end_of_au, delta_unit, discont);
   }
 
-  packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+  GST_DEBUG_OBJECT (basepayload,
+      "using FU-A fragmentation for NAL Unit: datasize=%u mtu=%u", size, mtu);
+
+  /* We keep 2 bytes for FU indicator and FU Header */
+  max_fragment_size = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+  max_fragments = (size + max_fragment_size - 2) / max_fragment_size;
+  list = gst_buffer_list_new_sized (max_fragments);
+
+  /* Start at the NALU payload */
+  for (pos = 1, ii = 0; pos < size; pos += max_fragment_size, ii++) {
+    guint remaining, fragment_size;
+    gboolean first_fragment, last_fragment;
+
+    remaining = size - pos;
+    fragment_size = MIN (remaining, max_fragment_size);
+    first_fragment = (pos == 1);
+    last_fragment = (remaining <= max_fragment_size);
 
-  if (packet_len < mtu) {
-    /* will fit in one packet */
     GST_DEBUG_OBJECT (basepayload,
-        "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
+        "creating FU-A packet %u/%u, size %u",
+        ii + 1, max_fragments, fragment_size);
 
-    /* create buffer without payload containing only the RTP header
+    /* use buffer lists
+     * create buffer without payload containing only the RTP header
      * (memory block at index 0) */
-    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+    outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
 
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
-    /* Mark the end of a frame */
-    gst_rtp_buffer_set_marker (&rtp, end_of_au);
-
-    /* timestamp the outbuffer */
-    GST_BUFFER_PTS (outbuf) = pts;
     GST_BUFFER_DTS (outbuf) = dts;
+    GST_BUFFER_PTS (outbuf) = pts;
+    payload = gst_rtp_buffer_get_payload (&rtp);
+
+    /* If it's the last fragment and the end of this au, mark the end of
+     * slice */
+    gst_rtp_buffer_set_marker (&rtp, last_fragment && end_of_au);
+
+    /* FU indicator */
+    payload[0] = (nal_header & 0x60) | FU_A_TYPE_ID;
+
+    /* FU Header */
+    payload[1] = (first_fragment << 7) | (last_fragment << 6) |
+        (nal_header & 0x1f);
+
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* insert payload memory block */
+    gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
+    gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
+        fragment_size);
 
     if (!delta_unit)
       /* Only the first packet sent should not have the flag */
@@ -912,99 +1099,255 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
       discont = FALSE;
     }
 
-    gst_rtp_buffer_unmap (&rtp);
+    /* add the buffer to the buffer list */
+    gst_buffer_list_add (list, outbuf);
+  }
 
-    /* insert payload memory block */
-    gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
-    outbuf = gst_buffer_append (outbuf, paybuf);
+  GST_DEBUG_OBJECT (rtph264pay,
+      "sending FU-A fragments: n=%u datasize=%u mtu=%u", ii, size, mtu);
 
-    /* push the buffer to the next element */
-    ret = gst_rtp_base_payload_push (basepayload, outbuf);
-  } else {
-    /* fragmentation Units FU-A */
-    guint limitedSize;
-    int ii = 0, start = 1, end = 0, pos = 0;
+  gst_buffer_unref (paybuf);
+  return gst_rtp_base_payload_push_list (basepayload, list);
+}
 
-    GST_DEBUG_OBJECT (basepayload,
-        "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
+static GstFlowReturn
+gst_rtp_h264_pay_payload_nal_single (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont)
+{
+  GstRtpH264Pay *rtph264pay;
+  GstBuffer *outbuf;
+  GstRTPBuffer rtp = { NULL };
+
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
 
-    pos++;
-    size--;
+  /* create buffer without payload containing only the RTP header
+   * (memory block at index 0) */
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
 
-    ret = GST_FLOW_OK;
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
-    GST_DEBUG_OBJECT (basepayload, "Using FU-A fragmentation for data size=%d",
-        size);
+  /* Mark the end of a frame */
+  gst_rtp_buffer_set_marker (&rtp, end_of_au);
 
-    /* We keep 2 bytes for FU indicator and FU Header */
-    payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
+  /* timestamp the outbuffer */
+  GST_BUFFER_PTS (outbuf) = pts;
+  GST_BUFFER_DTS (outbuf) = dts;
 
-    list = gst_buffer_list_new_sized ((size / payload_len) + 1);
+  if (delta_unit)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
 
-    while (end == 0) {
-      limitedSize = size < payload_len ? size : payload_len;
-      GST_DEBUG_OBJECT (basepayload,
-          "Inside  FU-A fragmentation limitedSize=%d iteration=%d", limitedSize,
-          ii);
+  if (discont)
+    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
 
-      /* use buffer lists
-       * create buffer without payload containing only the RTP header
-       * (memory block at index 0) */
-      outbuf = gst_rtp_buffer_new_allocate (2, 0, 0);
+  gst_rtp_buffer_unmap (&rtp);
 
-      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+  /* insert payload memory block */
+  gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
+  outbuf = gst_buffer_append (outbuf, paybuf);
 
-      GST_BUFFER_DTS (outbuf) = dts;
-      GST_BUFFER_PTS (outbuf) = pts;
-      payload = gst_rtp_buffer_get_payload (&rtp);
+  /* push the buffer to the next element */
+  return gst_rtp_base_payload_push (basepayload, outbuf);
+}
 
-      if (limitedSize == size) {
-        GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
-        end = 1;
-      }
+static void
+gst_rtp_h264_pay_reset_bundle (GstRtpH264Pay * rtph264pay)
+{
+  g_clear_pointer (&rtph264pay->bundle, gst_buffer_list_unref);
+  rtph264pay->bundle_size = 0;
+  rtph264pay->bundle_contains_vcl = FALSE;
+}
 
-      /* If it's the last fragment and the end of this au, mark the end of
-       * slice */
-      gst_rtp_buffer_set_marker (&rtp, end && end_of_au);
+static GstFlowReturn
+gst_rtp_h264_pay_send_bundle (GstRtpH264Pay * rtph264pay, gboolean end_of_au)
+{
+  GstRTPBasePayload *basepayload;
+  GstBufferList *bundle;
+  guint length, bundle_size;
+  GstBuffer *first, *outbuf;
+  GstClockTime dts, pts;
+  gboolean delta, discont;
 
-      /* FU indicator */
-      payload[0] = (nalHeader & 0x60) | 28;
+  bundle_size = rtph264pay->bundle_size;
 
-      /* FU Header */
-      payload[1] = (start << 7) | (end << 6) | (nalHeader & 0x1f);
+  if (bundle_size == 0) {
+    GST_DEBUG_OBJECT (rtph264pay, "no bundle, nothing to send");
+    return GST_FLOW_OK;
+  }
 
-      gst_rtp_buffer_unmap (&rtp);
+  basepayload = GST_RTP_BASE_PAYLOAD (rtph264pay);
+  bundle = rtph264pay->bundle;
+  length = gst_buffer_list_length (bundle);
 
-      /* insert payload memory block */
-      gst_rtp_copy_video_meta (rtph264pay, outbuf, paybuf);
-      gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
-          limitedSize);
+  first = gst_buffer_list_get (bundle, 0);
+  dts = GST_BUFFER_DTS (first);
+  pts = GST_BUFFER_PTS (first);
+  delta = GST_BUFFER_FLAG_IS_SET (first, GST_BUFFER_FLAG_DELTA_UNIT);
+  discont = GST_BUFFER_FLAG_IS_SET (first, GST_BUFFER_FLAG_DISCONT);
 
-      if (!delta_unit)
-        /* Only the first packet sent should not have the flag */
-        delta_unit = TRUE;
-      else
-        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+  if (length == 1) {
+    /* Push unaggregated NALU */
+    outbuf = gst_buffer_ref (first);
 
-      if (discont) {
-        GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
-        /* Only the first packet sent should have the flag */
-        discont = FALSE;
-      }
+    GST_DEBUG_OBJECT (rtph264pay,
+        "sending NAL Unit unaggregated: datasize=%u", bundle_size - 2);
+  } else {
+    guint8 stap_header;
+    guint i;
+
+    outbuf = gst_buffer_new_allocate (NULL, sizeof stap_header, NULL);
+    stap_header = STAP_A_TYPE_ID;
+
+    for (i = 0; i < length; i++) {
+      GstBuffer *buf = gst_buffer_list_get (bundle, i);
+      guint8 nal_header;
+      GstMemory *size_header;
+      GstMapInfo map;
+
+      gst_buffer_extract (buf, 0, &nal_header, sizeof nal_header);
+
+      /* Propagate F bit */
+      if ((nal_header & 0x80))
+        stap_header |= 0x80;
+
+      /* Select highest nal_ref_idc */
+      if ((nal_header & 0x60) > (stap_header & 0x60))
+        stap_header = (stap_header & 0x9f) | (nal_header & 0x60);
+
+      /* append NALU size */
+      size_header = gst_allocator_alloc (NULL, 2, NULL);
+      gst_memory_map (size_header, &map, GST_MAP_WRITE);
+      GST_WRITE_UINT16_BE (map.data, gst_buffer_get_size (buf));
+      gst_memory_unmap (size_header, &map);
+      gst_buffer_append_memory (outbuf, size_header);
+
+      /* append NALU data */
+      outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buf));
+    }
+
+    gst_buffer_fill (outbuf, 0, &stap_header, sizeof stap_header);
+
+    GST_DEBUG_OBJECT (rtph264pay,
+        "sending STAP-A bundle: n=%u header=%02x datasize=%u",
+        length, stap_header, bundle_size);
+  }
 
-      /* add the buffer to the buffer list */
-      gst_buffer_list_add (list, outbuf);
+  gst_rtp_h264_pay_reset_bundle (rtph264pay);
+  return gst_rtp_h264_pay_payload_nal_single (basepayload, outbuf, dts, pts,
+      end_of_au, delta, discont);
+}
 
+static gboolean
+gst_rtp_h264_pay_payload_nal_bundle (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+    gboolean delta_unit, gboolean discont, guint8 nal_header)
+{
+  GstRtpH264Pay *rtph264pay;
+  GstFlowReturn ret;
+  guint mtu, pay_size, bundle_size;
+  GstBufferList *bundle;
+  guint8 nal_type;
+  gboolean start_of_au;
 
-      size -= limitedSize;
-      pos += limitedSize;
-      ii++;
-      start = 0;
+  rtph264pay = GST_RTP_H264_PAY (basepayload);
+  nal_type = nal_header & 0x1f;
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph264pay);
+  pay_size = 2 + gst_buffer_get_size (paybuf);
+  bundle = rtph264pay->bundle;
+  start_of_au = FALSE;
+
+  if (bundle) {
+    GstBuffer *first = gst_buffer_list_get (bundle, 0);
+
+    if (nal_type == AUD_TYPE_ID) {
+      GST_DEBUG_OBJECT (rtph264pay, "found access delimiter");
+      start_of_au = TRUE;
+    } else if (discont) {
+      GST_DEBUG_OBJECT (rtph264pay, "found discont");
+      start_of_au = TRUE;
+    } else if (GST_BUFFER_PTS (first) != pts || GST_BUFFER_DTS (first) != dts) {
+      GST_DEBUG_OBJECT (rtph264pay, "found timestamp mismatch");
+      start_of_au = TRUE;
     }
+  }
+
+  if (start_of_au) {
+    GST_DEBUG_OBJECT (rtph264pay, "sending bundle before start of AU");
+
+    ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    bundle = NULL;
+  }
+
+  bundle_size = 1 + pay_size;
+
+  if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
+    GST_DEBUG_OBJECT (rtph264pay, "NAL Unit cannot fit in a bundle");
+
+    ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    return gst_rtp_h264_pay_payload_nal_fragment (basepayload, paybuf, dts, pts,
+        end_of_au, delta_unit, discont, nal_header);
+  }
 
-    ret = gst_rtp_base_payload_push_list (basepayload, list);
-    gst_buffer_unref (paybuf);
+  bundle_size = rtph264pay->bundle_size + pay_size;
+
+  if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
+    GST_DEBUG_OBJECT (rtph264pay,
+        "bundle overflows, sending: bundlesize=%u datasize=2+%u mtu=%u",
+        rtph264pay->bundle_size, pay_size - 2, mtu);
+
+    ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    bundle = NULL;
   }
+
+  if (!bundle) {
+    GST_DEBUG_OBJECT (rtph264pay, "creating new STAP-A aggregate");
+    bundle = rtph264pay->bundle = gst_buffer_list_new ();
+    bundle_size = rtph264pay->bundle_size = 1;
+    rtph264pay->bundle_contains_vcl = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (rtph264pay,
+      "bundling NAL Unit: bundlesize=%u datasize=2+%u mtu=%u",
+      rtph264pay->bundle_size, pay_size - 2, mtu);
+
+  paybuf = gst_buffer_make_writable (paybuf);
+  GST_BUFFER_PTS (paybuf) = pts;
+  GST_BUFFER_DTS (paybuf) = dts;
+
+  if (delta_unit)
+    GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
+  else
+    GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+  if (discont)
+    GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DISCONT);
+  else
+    GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DISCONT);
+
+  gst_buffer_list_add (bundle, gst_buffer_ref (paybuf));
+  rtph264pay->bundle_size += pay_size;
+  ret = GST_FLOW_OK;
+
+  if ((nal_type >= 1 && nal_type <= 5) || nal_type == 14 ||
+      (nal_type >= 20 && nal_type <= 23))
+    rtph264pay->bundle_contains_vcl = TRUE;
+
+  if (end_of_au) {
+    GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end of AU");
+    ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
+  }
+
+out:
+  gst_buffer_unref (paybuf);
   return ret;
 }
 
@@ -1016,7 +1359,6 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
   GstFlowReturn ret;
   gsize size;
   guint nal_len, i;
-  GstMapInfo map;
   const guint8 *data;
   GstClockTime dts, pts;
   GArray *nal_queue;
@@ -1035,19 +1377,9 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
   avc = rtph264pay->stream_format == GST_H264_STREAM_FORMAT_AVC;
 
   if (avc) {
-    /* In AVC mode, there is no adapter, so nothign to drain */
+    /* In AVC mode, there is no adapter, so nothing to drain */
     if (draining)
       return GST_FLOW_OK;
-    gst_buffer_map (buffer, &map, GST_MAP_READ);
-    data = map.data;
-    size = map.size;
-    pts = GST_BUFFER_PTS (buffer);
-    dts = GST_BUFFER_DTS (buffer);
-    rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
-        GST_BUFFER_FLAG_DELTA_UNIT);
-    rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
-    marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
-    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
   } else {
     if (buffer) {
       if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
@@ -1089,34 +1421,45 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
   ret = GST_FLOW_OK;
 
-  /* now loop over all NAL units and put them in a packet
-   * FIXME, we should really try to pack multiple NAL units into one RTP packet
-   * if we can, especially for the config packets that wont't cause decoder 
-   * latency. */
+  /* now loop over all NAL units and put them in a packet */
   if (avc) {
+    GstBufferMemoryMap memory;
+    gsize remaining_buffer_size;
     guint nal_length_size;
     gsize offset = 0;
 
+    gst_buffer_memory_map (buffer, &memory);
+    remaining_buffer_size = gst_buffer_get_size (buffer);
+
+    pts = GST_BUFFER_PTS (buffer);
+    dts = GST_BUFFER_DTS (buffer);
+    rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
+        GST_BUFFER_FLAG_DELTA_UNIT);
+    rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
+    marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
+    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes",
+        remaining_buffer_size);
+
     nal_length_size = rtph264pay->nal_length_size;
 
-    while (size > nal_length_size) {
+    while (remaining_buffer_size > nal_length_size) {
       gint i;
       gboolean end_of_au = FALSE;
 
       nal_len = 0;
       for (i = 0; i < nal_length_size; i++) {
-        nal_len = ((nal_len << 8) + data[i]);
+        nal_len = (nal_len << 8) + *memory.data;
+        if (!gst_buffer_memory_advance_bytes (&memory, 1))
+          break;
       }
 
-      /* skip the length bytes, make sure we don't run past the buffer size */
-      data += nal_length_size;
       offset += nal_length_size;
-      size -= nal_length_size;
+      remaining_buffer_size -= nal_length_size;
 
-      if (size >= nal_len) {
+      if (remaining_buffer_size >= nal_len) {
         GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
       } else {
-        nal_len = size;
+        nal_len = remaining_buffer_size;
         GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
             nal_len);
       }
@@ -1124,7 +1467,7 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
       /* If we're at the end of the buffer, then we're at the end of the
        * access unit
        */
-      if (size - nal_len <= nal_length_size) {
+      if (remaining_buffer_size - nal_len <= nal_length_size) {
         if (rtph264pay->alignment == GST_H264_ALIGNMENT_AU || marker)
           end_of_au = TRUE;
       }
@@ -1146,10 +1489,19 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
       if (ret != GST_FLOW_OK)
         break;
 
-      data += nal_len;
+      /* Skip current nal. If it is split over multiple GstMemory
+       * advance_bytes () will switch to the correct GstMemory. The payloader
+       * does not access those bytes directly but uses gst_buffer_copy_region ()
+       * to create a sub-buffer referencing the nal instead */
+      if (!gst_buffer_memory_advance_bytes (&memory, nal_len))
+        break;
+
       offset += nal_len;
-      size -= nal_len;
+      remaining_buffer_size -= nal_len;
     }
+
+    gst_buffer_memory_unmap (&memory);
+    gst_buffer_unref (buffer);
   } else {
     guint next;
     gboolean update = FALSE;
@@ -1177,10 +1529,10 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
       size -= 3;
 
       /* use next_start_code() to scan buffer.
-       * next_start_code() returns the offset in data, 
+       * next_start_code() returns the offset in data,
        * starting from zero to the first byte of 0.0.0.1
-       * If no start code is found, it returns the value of the 
-       * 'size' parameter. 
+       * If no start code is found, it returns the value of the
+       * 'size' parameter.
        * data is unchanged by the call to next_start_code()
        */
       next = next_start_code (data, size);
@@ -1306,11 +1658,16 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
     g_array_set_size (nal_queue, 0);
   }
 
+  if (ret == GST_FLOW_OK && rtph264pay->bundle_size > 0 &&
+      rtph264pay->aggregate_mode == GST_RTP_H264_AGGREGATE_ZERO_LATENCY &&
+      rtph264pay->bundle_contains_vcl) {
+    GST_DEBUG_OBJECT (rtph264pay, "sending bundle at end incoming packet");
+    ret = gst_rtp_h264_pay_send_bundle (rtph264pay, FALSE);
+  }
+
+
 done:
-  if (avc) {
-    gst_buffer_unmap (buffer, &map);
-    gst_buffer_unref (buffer);
-  } else {
+  if (!avc) {
     gst_adapter_unmap (rtph264pay->adapter);
   }
 
@@ -1331,10 +1688,12 @@ gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
   gboolean res;
   const GstStructure *s;
   GstRtpH264Pay *rtph264pay = GST_RTP_H264_PAY (payload);
+  GstFlowReturn ret = GST_FLOW_OK;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_STOP:
       gst_adapter_clear (rtph264pay->adapter);
+      gst_rtp_h264_pay_reset_bundle (rtph264pay);
       break;
     case GST_EVENT_CUSTOM_DOWNSTREAM:
       s = gst_event_get_structure (event);
@@ -1352,16 +1711,21 @@ gst_rtp_h264_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
        * in byte-stream mode
        */
       gst_rtp_h264_pay_handle_buffer (payload, NULL);
+      ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
       break;
     }
     case GST_EVENT_STREAM_START:
       GST_DEBUG_OBJECT (rtph264pay, "New stream detected => Clear SPS and PPS");
       gst_rtp_h264_pay_clear_sps_pps (rtph264pay);
+      ret = gst_rtp_h264_pay_send_bundle (rtph264pay, TRUE);
       break;
     default:
       break;
   }
 
+  if (ret != GST_FLOW_OK)
+    return FALSE;
+
   res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
 
   return res;
@@ -1377,6 +1741,7 @@ gst_rtp_h264_pay_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       rtph264pay->send_spspps = FALSE;
       gst_adapter_clear (rtph264pay->adapter);
+      gst_rtp_h264_pay_reset_bundle (rtph264pay);
       break;
     default:
       break;
@@ -1413,6 +1778,9 @@ gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
     case PROP_CONFIG_INTERVAL:
       rtph264pay->spspps_interval = g_value_get_int (value);
       break;
+    case PROP_AGGREGATE_MODE:
+      rtph264pay->aggregate_mode = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1434,6 +1802,9 @@ gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
     case PROP_CONFIG_INTERVAL:
       g_value_set_int (value, rtph264pay->spspps_interval);
       break;
+    case PROP_AGGREGATE_MODE:
+      g_value_set_enum (value, rtph264pay->aggregate_mode);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index c5a5e9f..879394b 100644 (file)
@@ -54,6 +54,13 @@ typedef enum
   GST_H264_ALIGNMENT_AU
 } GstH264Alignment;
 
+typedef enum
+{
+  GST_RTP_H264_AGGREGATE_NONE,
+  GST_RTP_H264_AGGREGATE_ZERO_LATENCY,
+  GST_RTP_H264_AGGREGATE_MAX_STAP,
+} GstRTPH264AggregateMode;
+
 struct _GstRtpH264Pay
 {
   GstRTPBasePayload payload;
@@ -75,10 +82,19 @@ struct _GstRtpH264Pay
   gboolean send_spspps;
   GstClockTime last_spspps;
 
+  gint fps_num;
+  gint fps_denum;
+
   /* TRUE if the next NALU processed should have the DELTA_UNIT flag */
   gboolean delta_unit;
   /* TRUE if the next NALU processed should have the DISCONT flag */
   gboolean discont;
+
+  /* aggregate buffers with STAP-A */
+  GstBufferList *bundle;
+  guint bundle_size;
+  gboolean bundle_contains_vcl;
+  GstRTPH264AggregateMode aggregate_mode;
 };
 
 struct _GstRtpH264PayClass
index 551e08a..38f53e4 100644 (file)
@@ -62,7 +62,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
     GST_STATIC_CAPS ("application/x-rtp, "
         "media = (string) \"video\", "
         "clock-rate = (int) 90000, " "encoding-name = (string) \"H265\"")
-        /** optional parameters **/
+    /* optional parameters */
     /* "profile-space = (int) [ 0, 3 ], " */
     /* "profile-id = (int) [ 0, 31 ], " */
     /* "tier-flag = (int) [ 0, 1 ], " */
@@ -1259,6 +1259,7 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
     gst_adapter_clear (rtph265depay->adapter);
     rtph265depay->wait_start = TRUE;
     rtph265depay->current_fu_type = 0;
+    rtph265depay->last_fu_seqnum = 0;
   }
 
   {
@@ -1367,7 +1368,7 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
 
           nalu_size = (payload[0] << 8) | payload[1];
 
-          /* dont include nalu_size */
+          /* don't include nalu_size */
           if (nalu_size > (payload_len - 2))
             nalu_size = payload_len - 2;
 
@@ -1456,6 +1457,7 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
 
           rtph265depay->current_fu_type = nal_unit_type;
           rtph265depay->fu_timestamp = timestamp;
+          rtph265depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);
 
           rtph265depay->wait_start = FALSE;
 
@@ -1493,6 +1495,24 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
           /* and assemble in the adapter */
           gst_adapter_push (rtph265depay->adapter, outbuf);
         } else {
+          if (rtph265depay->current_fu_type == 0) {
+            /* previous FU packet missing start bit? */
+            GST_WARNING_OBJECT (rtph265depay, "missing FU start bit on an "
+                "earlier packet. Dropping.");
+            gst_adapter_clear (rtph265depay->adapter);
+            return NULL;
+          }
+          if (gst_rtp_buffer_compare_seqnum (rtph265depay->last_fu_seqnum,
+                  gst_rtp_buffer_get_seq (rtp)) != 1) {
+            /* jump in sequence numbers within an FU is cause for discarding */
+            GST_WARNING_OBJECT (rtph265depay, "Jump in sequence numbers from "
+                "%u to %u within Fragmentation Unit. Data was lost, dropping "
+                "stored.", rtph265depay->last_fu_seqnum,
+                gst_rtp_buffer_get_seq (rtp));
+            gst_adapter_clear (rtph265depay->adapter);
+            return NULL;
+          }
+          rtph265depay->last_fu_seqnum = gst_rtp_buffer_get_seq (rtp);
 
           GST_DEBUG_OBJECT (rtph265depay,
               "Following part of Fragmentation Unit");
index cf17694..b3b55ee 100644 (file)
@@ -73,6 +73,7 @@ struct _GstRtpH265Depay
 
   /* Work around broken payloaders wrt. Fragmentation Units */
   guint8 current_fu_type;
+  guint16 last_fu_seqnum;
   GstClockTime fu_timestamp;
   gboolean fu_marker;
 
index d1a3a42..fdb18b5 100644 (file)
 
 #include "gstrtph265pay.h"
 #include "gstrtputils.h"
+#include "gstbuffermemory.h"
+
+#define AP_TYPE_ID  48
+#define FU_TYPE_ID  49
 
 GST_DEBUG_CATEGORY_STATIC (rtph265pay_debug);
 #define GST_CAT_DEFAULT (rtph265pay_debug)
 
+#define GST_TYPE_RTP_H265_AGGREGATE_MODE \
+  (gst_rtp_h265_aggregate_mode_get_type ())
+
+
+static GType
+gst_rtp_h265_aggregate_mode_get_type (void)
+{
+  static GType type = 0;
+  static const GEnumValue values[] = {
+    {GST_RTP_H265_AGGREGATE_NONE, "Do not aggregate NAL units", "none"},
+    {GST_RTP_H265_AGGREGATE_ZERO_LATENCY,
+          "Aggregate NAL units until a VCL or suffix unit is included",
+        "zero-latency"},
+    {GST_RTP_H265_AGGREGATE_MAX,
+        "Aggregate all NAL units with the same timestamp (adds one frame of"
+          " latency)", "max"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRtpH265AggregateMode", values);
+  }
+  return type;
+}
+
+
+
 /* references:
  *
  * Internet Draft RTP Payload Format for High Efficiency Video Coding
@@ -69,7 +100,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
         "media = (string) \"video\", "
         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
         "clock-rate = (int) 90000, " "encoding-name = (string) \"H265\"")
-                /** optional parameters **/
+    /* optional parameters */
     /* "profile-space = (int) [ 0, 3 ], " */
     /* "profile-id = (int) [ 0, 31 ], " */
     /* "tier-flag = (int) [ 0, 1 ], " */
@@ -101,12 +132,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
     /* "dec-parallel-cap = (string) ANY, " */
     );
 
-#define DEFAULT_CONFIG_INTERVAL                      0
+#define DEFAULT_CONFIG_INTERVAL         0
+#define DEFAULT_AGGREGATE_MODE          GST_RTP_H265_AGGREGATE_NONE
 
 enum
 {
   PROP_0,
-  PROP_CONFIG_INTERVAL
+  PROP_CONFIG_INTERVAL,
+  PROP_AGGREGATE_MODE,
 };
 
 static void gst_rtp_h265_pay_finalize (GObject * object);
@@ -126,6 +159,10 @@ static gboolean gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload,
     GstEvent * event);
 static GstStateChangeReturn gst_rtp_h265_pay_change_state (GstElement *
     element, GstStateChange transition);
+static gboolean gst_rtp_h265_pay_src_query (GstPad * pad, GstObject * parent,
+    GstQuery * query);
+
+static void gst_rtp_h265_pay_reset_bundle (GstRtpH265Pay * rtph265pay);
 
 #define gst_rtp_h265_pay_parent_class parent_class
 G_DEFINE_TYPE (GstRtpH265Pay, gst_rtp_h265_pay, GST_TYPE_RTP_BASE_PAYLOAD);
@@ -155,6 +192,28 @@ gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
       );
 
+  /**
+   * GstRtpH265Pay:aggregate-mode
+   *
+   * Bundle suitable SPS/PPS NAL units into STAP-A aggregate packets.
+   *
+   * This can potentially reduce RTP packetization overhead but not all
+   * RTP implementations handle it correctly.
+   *
+   * For best compatibility, it is recommended to set this to "none" (the
+   * default) for RTSP and for WebRTC to "zero-latency".
+   *
+   * Since: 1.18
+   */
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_AGGREGATE_MODE,
+      g_param_spec_enum ("aggregate-mode",
+          "Attempt to use aggregate packets",
+          "Bundle suitable SPS/PPS NAL units into aggregate packets.",
+          GST_TYPE_RTP_H265_AGGREGATE_MODE,
+          DEFAULT_AGGREGATE_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+      );
+
   gobject_class->finalize = gst_rtp_h265_pay_finalize;
 
   gst_element_class_add_static_pad_template (gstelement_class,
@@ -177,6 +236,10 @@ gst_rtp_h265_pay_class_init (GstRtpH265PayClass * klass)
 
   GST_DEBUG_CATEGORY_INIT (rtph265pay_debug, "rtph265pay", 0,
       "H265 RTP Payloader");
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_RTP_H265_AGGREGATE_MODE, 0);
+#endif
 }
 
 static void
@@ -191,8 +254,12 @@ gst_rtp_h265_pay_init (GstRtpH265Pay * rtph265pay)
       (GDestroyNotify) gst_buffer_unref);
   rtph265pay->last_vps_sps_pps = -1;
   rtph265pay->vps_sps_pps_interval = DEFAULT_CONFIG_INTERVAL;
+  rtph265pay->aggregate_mode = DEFAULT_AGGREGATE_MODE;
 
   rtph265pay->adapter = gst_adapter_new ();
+
+  gst_pad_set_query_function (GST_RTP_BASE_PAYLOAD_SRCPAD (rtph265pay),
+      gst_rtp_h265_pay_src_query);
 }
 
 static void
@@ -218,9 +285,47 @@ gst_rtp_h265_pay_finalize (GObject * object)
 
   g_object_unref (rtph265pay->adapter);
 
+  gst_rtp_h265_pay_reset_bundle (rtph265pay);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static gboolean
+gst_rtp_h265_pay_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
+{
+  GstRtpH265Pay *rtph265pay = GST_RTP_H265_PAY (parent);
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_LATENCY) {
+    gboolean retval;
+    gboolean live;
+    GstClockTime min_latency, max_latency;
+
+    retval = gst_pad_query_default (pad, parent, query);
+    if (!retval)
+      return retval;
+
+    if (rtph265pay->stream_format == GST_H265_STREAM_FORMAT_UNKNOWN ||
+        rtph265pay->alignment == GST_H265_ALIGNMENT_UNKNOWN)
+      return FALSE;
+
+    gst_query_parse_latency (query, &live, &min_latency, &max_latency);
+
+    if (rtph265pay->aggregate_mode == GST_RTP_H265_AGGREGATE_MAX &&
+        rtph265pay->alignment != GST_H265_ALIGNMENT_AU && rtph265pay->fps_num) {
+      GstClockTime one_frame = gst_util_uint64_scale_int (GST_SECOND,
+          rtph265pay->fps_denum, rtph265pay->fps_num);
+
+      min_latency += one_frame;
+      max_latency += one_frame;
+      gst_query_set_latency (query, live, min_latency, max_latency);
+    }
+    return TRUE;
+  }
+
+  return gst_pad_query_default (pad, parent, query);
+}
+
+
 static const gchar all_levels[][4] = {
   "1",
   "2",
@@ -498,6 +603,11 @@ gst_rtp_h265_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
       rtph265pay->stream_format = GST_H265_STREAM_FORMAT_BYTESTREAM;
   }
 
+  if (!gst_structure_get_fraction (str, "framerate", &rtph265pay->fps_num,
+          &rtph265pay->fps_denum))
+    rtph265pay->fps_num = rtph265pay->fps_denum = 0;
+
+
   /* packetized HEVC video has a codec_data */
   if ((value = gst_structure_get_value (str, "codec_data"))) {
     guint num_vps, num_sps, num_pps;
@@ -810,9 +920,18 @@ gst_rtp_h265_pay_decode_nal (GstRtpH265Pay * payloader,
   return updated;
 }
 
-static GstFlowReturn
-gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
-    GPtrArray * paybufs, GstClockTime dts, GstClockTime pts);
+static GstFlowReturn gst_rtp_h265_pay_payload_nal (GstRTPBasePayload *
+    basepayload, GPtrArray * paybufs, GstClockTime dts, GstClockTime pts);
+static GstFlowReturn gst_rtp_h265_pay_payload_nal_single (GstRTPBasePayload *
+    basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts,
+    gboolean marker);
+static GstFlowReturn gst_rtp_h265_pay_payload_nal_fragment (GstRTPBasePayload *
+    basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts,
+    gboolean marker, guint mtu, guint8 nal_type, const guint8 * nal_header,
+    int size);
+static GstFlowReturn gst_rtp_h265_pay_payload_nal_bundle (GstRTPBasePayload *
+    basepayload, GstBuffer * paybuf, GstClockTime dts, GstClockTime pts,
+    gboolean marker, guint8 nal_type, const guint8 * nal_header, int size);
 
 static GstFlowReturn
 gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
@@ -863,6 +982,14 @@ gst_rtp_h265_pay_send_vps_sps_pps (GstRTPBasePayload * basepayload,
   return ret;
 }
 
+static void
+gst_rtp_h265_pay_reset_bundle (GstRtpH265Pay * rtph265pay)
+{
+  g_clear_pointer (&rtph265pay->bundle, gst_buffer_list_unref);
+  rtph265pay->bundle_size = 0;
+  rtph265pay->bundle_contains_vcl_or_suffix = FALSE;
+}
+
 static GstFlowReturn
 gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
     GPtrArray * paybufs, GstClockTime dts, GstClockTime pts)
@@ -885,15 +1012,10 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
   ret = GST_FLOW_OK;
   sent_ps = FALSE;
   for (i = 0; i < paybufs->len; i++) {
-    guint8 nalHeader[2];
-    guint8 nalType;
-    guint packet_len, payload_len;
+    guint8 nal_header[2];
+    guint8 nal_type;
     GstBuffer *paybuf;
-    GstBuffer *outbuf;
-    guint8 *payload;
-    GstBufferList *outlist = NULL;
     gboolean send_ps;
-    GstRTPBuffer rtp = { NULL };
     guint size;
     gboolean marker;
 
@@ -908,29 +1030,29 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
     marker = GST_BUFFER_FLAG_IS_SET (paybuf, GST_BUFFER_FLAG_MARKER);
 
     size = gst_buffer_get_size (paybuf);
-    gst_buffer_extract (paybuf, 0, nalHeader, 2);
-    nalType = (nalHeader[0] >> 1) & 0x3f;
+    gst_buffer_extract (paybuf, 0, nal_header, 2);
+    nal_type = (nal_header[0] >> 1) & 0x3f;
 
-    GST_DEBUG_OBJECT (rtph265pay, "Processing Buffer with NAL TYPE=%d",
-        nalType);
+    GST_DEBUG_OBJECT (rtph265pay, "payloading NAL Unit: datasize=%u type=%d"
+        " pts=%" GST_TIME_FORMAT, size, nal_type, GST_TIME_ARGS (pts));
 
     send_ps = FALSE;
 
     /* check if we need to emit an VPS/SPS/PPS now */
-    if ((nalType == GST_H265_NAL_SLICE_TRAIL_N)
-        || (nalType == GST_H265_NAL_SLICE_TRAIL_R)
-        || (nalType == GST_H265_NAL_SLICE_TSA_N)
-        || (nalType == GST_H265_NAL_SLICE_TSA_R)
-        || (nalType == GST_H265_NAL_SLICE_STSA_N)
-        || (nalType == GST_H265_NAL_SLICE_STSA_R)
-        || (nalType == GST_H265_NAL_SLICE_RASL_N)
-        || (nalType == GST_H265_NAL_SLICE_RASL_R)
-        || (nalType == GST_H265_NAL_SLICE_BLA_W_LP)
-        || (nalType == GST_H265_NAL_SLICE_BLA_W_RADL)
-        || (nalType == GST_H265_NAL_SLICE_BLA_N_LP)
-        || (nalType == GST_H265_NAL_SLICE_IDR_W_RADL)
-        || (nalType == GST_H265_NAL_SLICE_IDR_N_LP)
-        || (nalType == GST_H265_NAL_SLICE_CRA_NUT)) {
+    if ((nal_type == GST_H265_NAL_SLICE_TRAIL_N)
+        || (nal_type == GST_H265_NAL_SLICE_TRAIL_R)
+        || (nal_type == GST_H265_NAL_SLICE_TSA_N)
+        || (nal_type == GST_H265_NAL_SLICE_TSA_R)
+        || (nal_type == GST_H265_NAL_SLICE_STSA_N)
+        || (nal_type == GST_H265_NAL_SLICE_STSA_R)
+        || (nal_type == GST_H265_NAL_SLICE_RASL_N)
+        || (nal_type == GST_H265_NAL_SLICE_RASL_R)
+        || (nal_type == GST_H265_NAL_SLICE_BLA_W_LP)
+        || (nal_type == GST_H265_NAL_SLICE_BLA_W_RADL)
+        || (nal_type == GST_H265_NAL_SLICE_BLA_N_LP)
+        || (nal_type == GST_H265_NAL_SLICE_IDR_W_RADL)
+        || (nal_type == GST_H265_NAL_SLICE_IDR_N_LP)
+        || (nal_type == GST_H265_NAL_SLICE_CRA_NUT)) {
       if (rtph265pay->vps_sps_pps_interval > 0) {
         if (rtph265pay->last_vps_sps_pps != -1) {
           guint64 diff;
@@ -965,8 +1087,8 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
           send_ps = TRUE;
         }
       } else if (rtph265pay->vps_sps_pps_interval == -1
-          && (nalType == GST_H265_NAL_SLICE_IDR_W_RADL
-              || nalType == GST_H265_NAL_SLICE_IDR_N_LP)) {
+          && (nal_type == GST_H265_NAL_SLICE_IDR_W_RADL
+              || nal_type == GST_H265_NAL_SLICE_IDR_N_LP)) {
         /* send VPS/SPS/PPS before every IDR frame */
         send_ps = TRUE;
       }
@@ -987,114 +1109,328 @@ gst_rtp_h265_pay_payload_nal (GstRTPBasePayload * basepayload,
       }
     }
 
-    packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
+    if (rtph265pay->aggregate_mode != GST_RTP_H265_AGGREGATE_NONE)
+      ret = gst_rtp_h265_pay_payload_nal_bundle (basepayload, paybuf, dts, pts,
+          marker, nal_type, nal_header, size);
+    else
+      ret = gst_rtp_h265_pay_payload_nal_fragment (basepayload, paybuf, dts,
+          pts, marker, mtu, nal_type, nal_header, size);
+  }
 
-    if (packet_len < mtu) {
-      GST_DEBUG_OBJECT (rtph265pay,
-          "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
-      /* will fit in one packet */
+  g_ptr_array_free (paybufs, TRUE);
 
-      /* use buffer lists
-       * create buffer without payload containing only the RTP header
-       * (memory block at index 0) */
-      outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+  return ret;
+}
 
-      gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+static GstFlowReturn
+gst_rtp_h265_pay_payload_nal_single (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean marker)
+{
+  GstBufferList *outlist;
+  GstBuffer *outbuf;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
 
-      /* Mark the end of a frame */
-      gst_rtp_buffer_set_marker (&rtp, marker);
+  /* use buffer lists
+   * create buffer without payload containing only the RTP header
+   * (memory block at index 0) */
+  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
 
-      /* timestamp the outbuffer */
-      GST_BUFFER_PTS (outbuf) = pts;
-      GST_BUFFER_DTS (outbuf) = dts;
+  gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
-      /* insert payload memory block */
-      gst_rtp_copy_video_meta (rtph265pay, outbuf, paybuf);
-      outbuf = gst_buffer_append (outbuf, paybuf);
+  /* Mark the end of a frame */
+  gst_rtp_buffer_set_marker (&rtp, marker);
 
-      outlist = gst_buffer_list_new ();
+  /* timestamp the outbuffer */
+  GST_BUFFER_PTS (outbuf) = pts;
+  GST_BUFFER_DTS (outbuf) = dts;
 
-      /* add the buffer to the buffer list */
-      gst_buffer_list_add (outlist, outbuf);
+  /* insert payload memory block */
+  gst_rtp_copy_video_meta (basepayload, outbuf, paybuf);
+  outbuf = gst_buffer_append (outbuf, paybuf);
 
-      gst_rtp_buffer_unmap (&rtp);
+  outlist = gst_buffer_list_new ();
 
-      /* push the list to the next element in the pipe */
-      ret = gst_rtp_base_payload_push_list (basepayload, outlist);
-    } else {
-      /* fragmentation Units */
-      guint limitedSize;
-      int ii = 0, start = 1, end = 0, pos = 0;
+  /* add the buffer to the buffer list */
+  gst_buffer_list_add (outlist, outbuf);
 
-      GST_DEBUG_OBJECT (basepayload,
-          "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
+  gst_rtp_buffer_unmap (&rtp);
 
-      pos += 2;
-      size -= 2;
+  /* push the list to the next element in the pipe */
+  return gst_rtp_base_payload_push_list (basepayload, outlist);
+}
 
-      GST_DEBUG_OBJECT (basepayload, "Using FU fragmentation for data size=%d",
-          size);
+static GstFlowReturn
+gst_rtp_h265_pay_payload_nal_fragment (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean marker,
+    guint mtu, guint8 nal_type, const guint8 * nal_header, int size)
+{
+  GstRtpH265Pay *rtph265pay = (GstRtpH265Pay *) basepayload;
+  GstFlowReturn ret;
+  guint max_fragment_size, ii, pos;
+  GstBuffer *outbuf;
+  GstBufferList *outlist = NULL;
+  GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+  guint8 *payload;
+
+  if (gst_rtp_buffer_calc_packet_len (size, 0, 0) < mtu) {
+    GST_DEBUG_OBJECT (rtph265pay,
+        "NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
+    /* will fit in one packet */
+    return gst_rtp_h265_pay_payload_nal_single (basepayload, paybuf, dts, pts,
+        marker);
+  }
 
-      /* We keep 3 bytes for PayloadHdr and FU Header */
-      payload_len = gst_rtp_buffer_calc_payload_len (mtu - 3, 0, 0);
+  GST_DEBUG_OBJECT (basepayload,
+      "NAL Unit DOES NOT fit in one packet datasize=%d mtu=%d", size, mtu);
 
-      outlist = gst_buffer_list_new ();
+  GST_DEBUG_OBJECT (basepayload, "Using FU fragmentation for data size=%d",
+      size - 2);
 
-      while (end == 0) {
-        limitedSize = size < payload_len ? size : payload_len;
-        GST_DEBUG_OBJECT (basepayload,
-            "Inside  FU fragmentation limitedSize=%d iteration=%d", limitedSize,
-            ii);
+  /* We keep 3 bytes for PayloadHdr and FU Header */
+  max_fragment_size = gst_rtp_buffer_calc_payload_len (mtu - 3, 0, 0);
 
-        /* use buffer lists
-         * create buffer without payload containing only the RTP header
-         * (memory block at index 0), and with space for PayloadHdr and FU header */
-        outbuf = gst_rtp_buffer_new_allocate (3, 0, 0);
+  outlist = gst_buffer_list_new ();
 
-        gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+  for (pos = 2, ii = 0; pos < size; pos += max_fragment_size, ii++) {
+    guint remaining, fragment_size;
+    gboolean first_fragment, last_fragment;
 
-        GST_BUFFER_DTS (outbuf) = dts;
-        GST_BUFFER_PTS (outbuf) = pts;
-        payload = gst_rtp_buffer_get_payload (&rtp);
+    remaining = size - pos;
+    fragment_size = MIN (remaining, max_fragment_size);
+    first_fragment = (pos == 2);
+    last_fragment = (remaining <= max_fragment_size);
 
-        if (limitedSize == size) {
-          GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
-          end = 1;
-        }
+    GST_DEBUG_OBJECT (basepayload,
+        "Inside  FU fragmentation fragment_size=%u iteration=%d %s%s",
+        fragment_size, ii, first_fragment ? "first" : "",
+        last_fragment ? "last" : "");
 
-        /* PayloadHdr (type = 49) */
-        payload[0] = (nalHeader[0] & 0x81) | (49 << 1);
-        payload[1] = nalHeader[1];
+    /* use buffer lists
+     * create buffer without payload containing only the RTP header
+     * (memory block at index 0), and with space for PayloadHdr and FU header */
+    outbuf = gst_rtp_buffer_new_allocate (3, 0, 0);
 
-        /* If it's the last fragment and the end of this au, mark the end of
-         * slice */
-        gst_rtp_buffer_set_marker (&rtp, end && marker);
+    gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
-        /* FU Header */
-        payload[2] = (start << 7) | (end << 6) | (nalType & 0x3f);
+    GST_BUFFER_DTS (outbuf) = dts;
+    GST_BUFFER_PTS (outbuf) = pts;
+    payload = gst_rtp_buffer_get_payload (&rtp);
 
-        gst_rtp_buffer_unmap (&rtp);
+    /* PayloadHdr (type = FU_TYPE_ID (49)) */
+    payload[0] = (nal_header[0] & 0x81) | (FU_TYPE_ID << 1);
+    payload[1] = nal_header[1];
 
-        /* insert payload memory block */
-        gst_rtp_copy_video_meta (rtph265pay, outbuf, paybuf);
-        gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
-            limitedSize);
-        /* add the buffer to the buffer list */
-        gst_buffer_list_add (outlist, outbuf);
+    /* If it's the last fragment and the end of this au, mark the end of
+     * slice */
+    gst_rtp_buffer_set_marker (&rtp, last_fragment && marker);
 
-        size -= limitedSize;
-        pos += limitedSize;
-        ii++;
-        start = 0;
-      }
+    /* FU Header */
+    payload[2] = (first_fragment << 7) | (last_fragment << 6) |
+        (nal_type & 0x3f);
 
-      ret = gst_rtp_base_payload_push_list (basepayload, outlist);
-      gst_buffer_unref (paybuf);
+    gst_rtp_buffer_unmap (&rtp);
+
+    /* insert payload memory block */
+    gst_rtp_copy_video_meta (rtph265pay, outbuf, paybuf);
+    gst_buffer_copy_into (outbuf, paybuf, GST_BUFFER_COPY_MEMORY, pos,
+        fragment_size);
+    /* add the buffer to the buffer list */
+    gst_buffer_list_add (outlist, outbuf);
+  }
+
+  ret = gst_rtp_base_payload_push_list (basepayload, outlist);
+  gst_buffer_unref (paybuf);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_rtp_h265_pay_send_bundle (GstRtpH265Pay * rtph265pay, gboolean marker)
+{
+  GstRTPBasePayload *basepayload;
+  GstBufferList *bundle;
+  guint length, bundle_size;
+  GstBuffer *first, *outbuf;
+  GstClockTime dts, pts;
+
+  bundle_size = rtph265pay->bundle_size;
+
+  if (bundle_size == 0) {
+    GST_DEBUG_OBJECT (rtph265pay, "no bundle, nothing to send");
+    return GST_FLOW_OK;
+  }
+
+  basepayload = GST_RTP_BASE_PAYLOAD (rtph265pay);
+  bundle = rtph265pay->bundle;
+  length = gst_buffer_list_length (bundle);
+
+  first = gst_buffer_list_get (bundle, 0);
+  dts = GST_BUFFER_DTS (first);
+  pts = GST_BUFFER_PTS (first);
+
+  if (length == 1) {
+    /* Push unaggregated NALU */
+    outbuf = gst_buffer_ref (first);
+
+    GST_DEBUG_OBJECT (rtph265pay,
+        "sending NAL Unit unaggregated: datasize=%u", bundle_size - 2);
+  } else {
+    guint8 ap_header[2];
+    guint i;
+    guint8 layer_id = 0xFF;
+    guint8 temporal_id = 0xFF;
+
+    outbuf = gst_buffer_new_allocate (NULL, sizeof ap_header, NULL);
+
+    for (i = 0; i < length; i++) {
+      GstBuffer *buf = gst_buffer_list_get (bundle, i);
+      guint8 nal_header[2];
+      GstMemory *size_header;
+      GstMapInfo map;
+      guint8 nal_layer_id;
+      guint8 nal_temporal_id;
+
+      gst_buffer_extract (buf, 0, &nal_header, sizeof nal_header);
+
+      /* Propagate F bit */
+      if ((nal_header[0] & 0x80))
+        ap_header[0] |= 0x80;
+
+      /* Select lowest layer_id & temporal_id */
+      nal_layer_id = ((nal_header[0] & 0x01) << 5) |
+          ((nal_header[1] >> 3) & 0x1F);
+      nal_temporal_id = nal_header[1] & 0x7;
+      layer_id = MIN (layer_id, nal_layer_id);
+      temporal_id = MIN (temporal_id, nal_temporal_id);
+
+      /* append NALU size */
+      size_header = gst_allocator_alloc (NULL, 2, NULL);
+      gst_memory_map (size_header, &map, GST_MAP_WRITE);
+      GST_WRITE_UINT16_BE (map.data, gst_buffer_get_size (buf));
+      gst_memory_unmap (size_header, &map);
+      gst_buffer_append_memory (outbuf, size_header);
+
+      /* append NALU data */
+      outbuf = gst_buffer_append (outbuf, gst_buffer_ref (buf));
     }
+
+    ap_header[0] = (AP_TYPE_ID << 1) | (layer_id & 0x20);
+    ap_header[1] = ((layer_id & 0x1F) << 3) | (temporal_id & 0x07);
+
+    gst_buffer_fill (outbuf, 0, &ap_header, sizeof ap_header);
+
+    GST_DEBUG_OBJECT (rtph265pay,
+        "sending AP bundle: n=%u header=%02x%02x datasize=%u",
+        length, ap_header[0], ap_header[1], bundle_size);
   }
 
-  g_ptr_array_free (paybufs, TRUE);
+  gst_rtp_h265_pay_reset_bundle (rtph265pay);
+  return gst_rtp_h265_pay_payload_nal_single (basepayload, outbuf, dts, pts,
+      marker);
+}
+
+static gboolean
+gst_rtp_h265_pay_payload_nal_bundle (GstRTPBasePayload * basepayload,
+    GstBuffer * paybuf, GstClockTime dts, GstClockTime pts,
+    gboolean marker, guint8 nal_type, const guint8 * nal_header, int size)
+{
+  GstRtpH265Pay *rtph265pay;
+  GstFlowReturn ret;
+  guint pay_size, bundle_size;
+  GstBufferList *bundle;
+  gboolean start_of_au;
+  guint mtu;
+
+  rtph265pay = GST_RTP_H265_PAY (basepayload);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtph265pay);
+  pay_size = 2 + gst_buffer_get_size (paybuf);
+  bundle = rtph265pay->bundle;
+  start_of_au = FALSE;
+
+  if (bundle) {
+    GstBuffer *first = gst_buffer_list_get (bundle, 0);
+
+    if (nal_type == GST_H265_NAL_AUD) {
+      GST_DEBUG_OBJECT (rtph265pay, "found access delimiter");
+      start_of_au = TRUE;
+    } else if (GST_BUFFER_IS_DISCONT (paybuf)) {
+      GST_DEBUG_OBJECT (rtph265pay, "found discont");
+      start_of_au = TRUE;
+    } else if (GST_BUFFER_PTS (first) != pts || GST_BUFFER_DTS (first) != dts) {
+      GST_DEBUG_OBJECT (rtph265pay, "found timestamp mismatch");
+      start_of_au = TRUE;
+    }
+  }
+
+  if (start_of_au) {
+    GST_DEBUG_OBJECT (rtph265pay, "sending bundle before start of AU");
+
+    ret = gst_rtp_h265_pay_send_bundle (rtph265pay, TRUE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    bundle = NULL;
+  }
+
+  bundle_size = 2 + pay_size;
+
+  if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
+    GST_DEBUG_OBJECT (rtph265pay, "NAL Unit cannot fit in a bundle");
+
+    ret = gst_rtp_h265_pay_send_bundle (rtph265pay, FALSE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    return gst_rtp_h265_pay_payload_nal_fragment (basepayload, paybuf, dts, pts,
+        marker, mtu, nal_type, nal_header, size);
+  }
+
+  bundle_size = rtph265pay->bundle_size + pay_size;
+
+  if (gst_rtp_buffer_calc_packet_len (bundle_size, 0, 0) > mtu) {
+    GST_DEBUG_OBJECT (rtph265pay,
+        "bundle overflows, sending: bundlesize=%u datasize=2+%u mtu=%u",
+        rtph265pay->bundle_size, pay_size - 2, mtu);
+
+    ret = gst_rtp_h265_pay_send_bundle (rtph265pay, FALSE);
+    if (ret != GST_FLOW_OK)
+      goto out;
+
+    bundle = NULL;
+  }
+
+  if (!bundle) {
+    GST_DEBUG_OBJECT (rtph265pay, "creating new AP aggregate");
+    bundle = rtph265pay->bundle = gst_buffer_list_new ();
+    bundle_size = rtph265pay->bundle_size = 2;
+    rtph265pay->bundle_contains_vcl_or_suffix = FALSE;
+  }
+
+  GST_DEBUG_OBJECT (rtph265pay,
+      "bundling NAL Unit: bundlesize=%u datasize=2+%u mtu=%u",
+      rtph265pay->bundle_size, pay_size - 2, mtu);
+
+  paybuf = gst_buffer_make_writable (paybuf);
+  GST_BUFFER_PTS (paybuf) = pts;
+  GST_BUFFER_DTS (paybuf) = dts;
+
+  gst_buffer_list_add (bundle, gst_buffer_ref (paybuf));
+  rtph265pay->bundle_size += pay_size;
+  ret = GST_FLOW_OK;
 
+  /* In H.265, all VCL NAL units are < 32 */
+  if (nal_type < 32 || nal_type == GST_H265_NAL_EOS ||
+      nal_type == GST_H265_NAL_EOB || nal_type == GST_H265_NAL_SUFFIX_SEI ||
+      (nal_type >= 45 && nal_type <= 47) || (nal_type >= 56 && nal_type < 63))
+    rtph265pay->bundle_contains_vcl_or_suffix = TRUE;
+
+  if (marker) {
+    GST_DEBUG_OBJECT (rtph265pay, "sending bundle at marker");
+    ret = gst_rtp_h265_pay_send_bundle (rtph265pay, TRUE);
+  }
+
+out:
+  gst_buffer_unref (paybuf);
   return ret;
 }
 
@@ -1106,7 +1442,6 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
   GstFlowReturn ret;
   gsize size;
   guint nal_len, i;
-  GstMapInfo map;
   const guint8 *data;
   GstClockTime dts, pts;
   GArray *nal_queue;
@@ -1114,6 +1449,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
   GstBuffer *paybuf = NULL;
   gsize skip;
   gboolean marker = FALSE;
+  gboolean discont = FALSE;
   gboolean draining = (buffer == NULL);
 
   rtph265pay = GST_RTP_H265_PAY (basepayload);
@@ -1127,15 +1463,10 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
     /* In hevc mode, there is no adapter, so nothing to drain */
     if (draining)
       return GST_FLOW_OK;
-    gst_buffer_map (buffer, &map, GST_MAP_READ);
-    data = map.data;
-    size = map.size;
-    pts = GST_BUFFER_PTS (buffer);
-    dts = GST_BUFFER_DTS (buffer);
-    marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
-    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
   } else {
     if (buffer) {
+      if (gst_adapter_available (rtph265pay->adapter) == 0)
+        discont = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT);
       marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
       gst_adapter_push (rtph265pay->adapter, buffer);
       buffer = NULL;
@@ -1155,11 +1486,10 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
   ret = GST_FLOW_OK;
 
-  /* now loop over all NAL units and put them in a packet
-   * FIXME, we should really try to pack multiple NAL units into one RTP packet
-   * if we can, especially for the config packets that wont't cause decoder
-   * latency. */
+  /* now loop over all NAL units and put them in a packet */
   if (hevc) {
+    GstBufferMemoryMap memory;
+    gsize remaining_buffer_size;
     guint nal_length_size;
     gsize offset = 0;
     GPtrArray *paybufs;
@@ -1167,23 +1497,32 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
     paybufs = g_ptr_array_new ();
     nal_length_size = rtph265pay->nal_length_size;
 
-    while (size > nal_length_size) {
+    gst_buffer_memory_map (buffer, &memory);
+    remaining_buffer_size = gst_buffer_get_size (buffer);
+
+    pts = GST_BUFFER_PTS (buffer);
+    dts = GST_BUFFER_DTS (buffer);
+    marker = GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_MARKER);
+    GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes",
+        remaining_buffer_size);
+
+    while (remaining_buffer_size > nal_length_size) {
       gint i;
 
       nal_len = 0;
       for (i = 0; i < nal_length_size; i++) {
-        nal_len = ((nal_len << 8) + data[i]);
+        nal_len = (nal_len << 8) + *memory.data;
+        if (!gst_buffer_memory_advance_bytes (&memory, 1))
+          break;
       }
 
-      /* skip the length bytes, make sure we don't run past the buffer size */
-      data += nal_length_size;
       offset += nal_length_size;
-      size -= nal_length_size;
+      remaining_buffer_size -= nal_length_size;
 
-      if (size >= nal_len) {
+      if (remaining_buffer_size >= nal_len) {
         GST_DEBUG_OBJECT (basepayload, "got NAL of size %u", nal_len);
       } else {
-        nal_len = size;
+        nal_len = remaining_buffer_size;
         GST_DEBUG_OBJECT (basepayload, "got incomplete NAL of size %u",
             nal_len);
       }
@@ -1196,16 +1535,30 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
        * access unit
        */
       GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_MARKER);
-      if (size - nal_len <= nal_length_size) {
+      if (remaining_buffer_size - nal_len <= nal_length_size) {
         if (rtph265pay->alignment == GST_H265_ALIGNMENT_AU || marker)
           GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_MARKER);
       }
 
-      data += nal_len;
+      GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DISCONT);
+      if (discont) {
+        GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DISCONT);
+        discont = FALSE;
+      }
+
+      /* Skip current nal. If it is split over multiple GstMemory
+       * advance_bytes () will switch to the correct GstMemory. The payloader
+       * does not access those bytes directly but uses gst_buffer_copy_region ()
+       * to create a sub-buffer referencing the nal instead */
+      if (!gst_buffer_memory_advance_bytes (&memory, nal_len))
+        break;
       offset += nal_len;
-      size -= nal_len;
+      remaining_buffer_size -= nal_len;
     }
     ret = gst_rtp_h265_pay_payload_nal (basepayload, paybufs, dts, pts);
+
+    gst_buffer_memory_unmap (&memory);
+    gst_buffer_unref (buffer);
   } else {
     guint next;
     gboolean update = FALSE;
@@ -1295,7 +1648,7 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
       size = nal_len;
       data = gst_adapter_map (rtph265pay->adapter, size);
       if (i + 1 != nal_queue->len || !draining)
-        for (; size > 1 && data[size - 1] == 0x0; size--)
+        for (; size > 2 && data[size - 1] == 0x0; size--)
           /* skip */ ;
 
       paybuf = gst_adapter_take_buffer (rtph265pay->adapter, size);
@@ -1311,6 +1664,12 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
           GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_MARKER);
       }
 
+      GST_BUFFER_FLAG_UNSET (paybuf, GST_BUFFER_FLAG_DISCONT);
+      if (discont) {
+        GST_BUFFER_FLAG_SET (paybuf, GST_BUFFER_FLAG_DISCONT);
+        discont = FALSE;
+      }
+
       /* move to next NAL packet */
       /* Skips the trailing zeros */
       gst_adapter_flush (rtph265pay->adapter, nal_len - size);
@@ -1320,11 +1679,15 @@ gst_rtp_h265_pay_handle_buffer (GstRTPBasePayload * basepayload,
     g_array_set_size (nal_queue, 0);
   }
 
+  if (ret == GST_FLOW_OK && rtph265pay->bundle_size > 0 &&
+      rtph265pay->aggregate_mode == GST_RTP_H265_AGGREGATE_ZERO_LATENCY &&
+      rtph265pay->bundle_contains_vcl_or_suffix) {
+    GST_DEBUG_OBJECT (rtph265pay, "sending bundle at end incoming packet");
+    ret = gst_rtp_h265_pay_send_bundle (rtph265pay, FALSE);
+  }
+
 done:
-  if (hevc) {
-    gst_buffer_unmap (buffer, &map);
-    gst_buffer_unref (buffer);
-  } else {
+  if (!hevc) {
     gst_adapter_unmap (rtph265pay->adapter);
   }
 
@@ -1345,10 +1708,12 @@ gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
   gboolean res;
   const GstStructure *s;
   GstRtpH265Pay *rtph265pay = GST_RTP_H265_PAY (payload);
+  GstFlowReturn ret = GST_FLOW_OK;
 
   switch (GST_EVENT_TYPE (event)) {
     case GST_EVENT_FLUSH_STOP:
       gst_adapter_clear (rtph265pay->adapter);
+      gst_rtp_h265_pay_reset_bundle (rtph265pay);
       break;
     case GST_EVENT_CUSTOM_DOWNSTREAM:
       s = gst_event_get_structure (event);
@@ -1366,6 +1731,8 @@ gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
        * in byte-stream mode
        */
       gst_rtp_h265_pay_handle_buffer (payload, NULL);
+      ret = gst_rtp_h265_pay_send_bundle (rtph265pay, TRUE);
+
       break;
     }
     case GST_EVENT_STREAM_START:
@@ -1377,6 +1744,9 @@ gst_rtp_h265_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
       break;
   }
 
+  if (ret != GST_FLOW_OK)
+    return FALSE;
+
   res = GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
 
   return res;
@@ -1392,6 +1762,7 @@ gst_rtp_h265_pay_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       rtph265pay->send_vps_sps_pps = FALSE;
       gst_adapter_clear (rtph265pay->adapter);
+      gst_rtp_h265_pay_reset_bundle (rtph265pay);
       break;
     default:
       break;
@@ -1423,6 +1794,9 @@ gst_rtp_h265_pay_set_property (GObject * object, guint prop_id,
     case PROP_CONFIG_INTERVAL:
       rtph265pay->vps_sps_pps_interval = g_value_get_int (value);
       break;
+    case PROP_AGGREGATE_MODE:
+      rtph265pay->aggregate_mode = g_value_get_enum (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1441,6 +1815,9 @@ gst_rtp_h265_pay_get_property (GObject * object, guint prop_id,
     case PROP_CONFIG_INTERVAL:
       g_value_set_int (value, rtph265pay->vps_sps_pps_interval);
       break;
+    case PROP_AGGREGATE_MODE:
+      g_value_set_enum (value, rtph265pay->aggregate_mode);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index cd42fba..6d14095 100644 (file)
@@ -47,6 +47,13 @@ typedef enum
   GST_H265_ALIGNMENT_AU
 } GstH265Alignment;
 
+typedef enum
+{
+  GST_RTP_H265_AGGREGATE_NONE,
+  GST_RTP_H265_AGGREGATE_ZERO_LATENCY,
+  GST_RTP_H265_AGGREGATE_MAX,
+} GstRTPH265AggregateMode;
+
 struct _GstRtpH265Pay
 {
   GstRTPBasePayload payload;
@@ -55,6 +62,8 @@ struct _GstRtpH265Pay
 
   GstH265StreamFormat stream_format;
   GstH265Alignment alignment;
+  gint fps_num;
+  gint fps_denum;
   guint nal_length_size;
   GArray *queue;
 
@@ -63,6 +72,12 @@ struct _GstRtpH265Pay
   gint vps_sps_pps_interval;
   gboolean send_vps_sps_pps;
   GstClockTime last_vps_sps_pps;
+
+  /* aggregate buffers with AP */
+  GstBufferList *bundle;
+  guint bundle_size;
+  gboolean bundle_contains_vcl_or_suffix;
+  GstRTPH265AggregateMode aggregate_mode;
 };
 
 struct _GstRtpH265PayClass
index 26de483..587a7dc 100644 (file)
@@ -124,6 +124,10 @@ gst_rtp_ilbc_depay_class_init (GstRTPiLBCDepayClass * klass)
 
   gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_ilbc_depay_process;
   gstrtpbasedepayload_class->set_caps = gst_rtp_ilbc_depay_setcaps;
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_ILBC_MODE, 0);
+#endif
 }
 
 static void
index c30dd34..132bcf5 100644 (file)
@@ -20,6 +20,7 @@
 
  /**
  * SECTION:element-rtpj2kdepay
+ * @title: rtpj2kdepay
  *
  * Depayload an RTP-payloaded JPEG 2000 image into RTP packets according to RFC 5371
  * and RFC 5372.
index f1c6c03..9ead8a2 100644 (file)
@@ -19,6 +19,7 @@
 
  /**
  * SECTION:element-rtpj2kpay
+ * @title: rtpj2kpay
  *
  * Payload encode JPEG 2000 images into RTP packets according to RFC 5371
  * and RFC 5372.
@@ -30,7 +31,6 @@
  * codestream. A "packetization unit" is defined as either a JPEG 2000 main header,
  * a JPEG 2000 tile-part header, or a JPEG 2000 packet.
  *
- *
  */
 
 #ifdef HAVE_CONFIG_H
index 59274f1..5cd5428 100644 (file)
@@ -418,7 +418,7 @@ MakeHeaders (guint8 * p, int type, int width, int height, guint8 * qt,
   *p++ = 0x11;                  /* huffman table 1 */
   *p++ = 0;                     /* first DCT coeff */
   *p++ = 63;                    /* last DCT coeff */
-  *p++ = 0;                     /* sucessive approx. */
+  *p++ = 0;                     /* successive approx. */
 
   return (p - start);
 };
@@ -627,9 +627,10 @@ gst_rtp_jpeg_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
       GstCaps *outcaps;
 
       outcaps =
-          gst_caps_new_simple ("image/jpeg", "framerate", GST_TYPE_FRACTION,
-          rtpjpegdepay->frate_num, rtpjpegdepay->frate_denom, "width",
-          G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
+          gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
+          "framerate", GST_TYPE_FRACTION, rtpjpegdepay->frate_num,
+          rtpjpegdepay->frate_denom, "width", G_TYPE_INT, width,
+          "height", G_TYPE_INT, height, NULL);
       gst_pad_set_caps (depayload->srcpad, outcaps);
       gst_caps_unref (outcaps);
 
index fe93016..31f8efa 100644 (file)
@@ -21,6 +21,7 @@
 
 /**
  * SECTION:element-rtpjpegpay
+ * @title: rtpjpegpay
  *
  * Payload encode JPEG pictures into RTP packets according to RFC 2435.
  * For detailed information see: http://www.rfc-editor.org/rfc/rfc2435.txt
@@ -42,6 +43,7 @@
 
 #include "gstrtpjpegpay.h"
 #include "gstrtputils.h"
+#include "gstbuffermemory.h"
 
 static GstStaticPadTemplate gst_rtp_jpeg_pay_sink_template =
     GST_STATIC_PAD_TEMPLATE ("sink",
@@ -96,7 +98,7 @@ typedef enum _RtpJpegMarker RtpJpegMarker;
  * @JPEG_MARKER_DRI: Define Restart Interval marker
  * @JPEG_MARKER_H264: H264 marker
  *
- * Identifers for markers in JPEG header
+ * Identifiers for markers in JPEG header
  */
 enum _RtpJpegMarker
 {
@@ -382,45 +384,76 @@ invalid_framerate:
   }
 }
 
+/*
+ * get uint16 value from current position in mapped memory.
+ * the memory offset will be increased with 2.
+ */
 static guint
-gst_rtp_jpeg_pay_header_size (const guint8 * data, guint offset)
+parse_mem_inc_offset_guint16 (GstBufferMemoryMap * memory)
 {
-  return data[offset] << 8 | data[offset + 1];
+  guint data;
+
+  g_return_val_if_fail (memory->total_size > (memory->offset + 1), 0);
+
+  data = ((guint) * memory->data) << 8;
+  gst_buffer_memory_advance_bytes (memory, 1);
+  data = data | (*memory->data);
+  gst_buffer_memory_advance_bytes (memory, 1);
+
+  return data;
 }
 
+/*
+ * get uint8 value from current position in mapped memory.
+ * the memory offset will be increased with 1.
+ */
 static guint
-gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
-    guint offset, RtpQuantTable tables[])
+parse_mem_inc_offset_guint8 (GstBufferMemoryMap * memory)
+{
+  guint data;
+
+  g_return_val_if_fail (memory->total_size > memory->offset, 0);
+
+  data = (*memory->data);
+  gst_buffer_memory_advance_bytes (memory, 1);
+
+  return data;
+}
+
+static void
+gst_rtp_jpeg_pay_read_quant_table (GstBufferMemoryMap * memory,
+    RtpQuantTable tables[])
 {
   guint quant_size, tab_size;
   guint8 prec;
   guint8 id;
 
-  if (offset + 2 > size)
+  if (memory->total_size <= (memory->offset + 1))
     goto too_small;
 
-  quant_size = gst_rtp_jpeg_pay_header_size (data, offset);
+  quant_size = parse_mem_inc_offset_guint16 (memory);
   if (quant_size < 2)
     goto small_quant_size;
 
   /* clamp to available data */
-  if (offset + quant_size > size)
-    quant_size = size - offset;
+  if (memory->offset + quant_size > memory->total_size)
+    quant_size = memory->total_size - memory->offset;
 
-  offset += 2;
   quant_size -= 2;
 
   while (quant_size > 0) {
+    guint8 data;
     /* not enough to read the id */
-    if (offset + 1 > size)
+    if (memory->offset + 1 > memory->total_size)
       break;
 
-    id = data[offset] & 0x0f;
+    data = parse_mem_inc_offset_guint8 (memory);
+    id = data & 0x0f;
     if (id == 15)
       /* invalid id received - corrupt data */
       goto invalid_id;
 
-    prec = (data[offset] & 0xf0) >> 4;
+    prec = (data & 0xf0) >> 4;
     if (prec)
       tab_size = 128;
     else
@@ -433,25 +466,26 @@ gst_rtp_jpeg_pay_read_quant_table (const guint8 * data, guint size,
     GST_LOG ("read quant table %d, tab_size %d, prec %02x", id, tab_size, prec);
 
     tables[id].size = tab_size;
-    tables[id].data = &data[offset + 1];
+    tables[id].data = memory->data;
 
-    tab_size += 1;
-    quant_size -= tab_size;
-    offset += tab_size;
+    quant_size -= (tab_size + 1);
+    if (!gst_buffer_memory_advance_bytes (memory, tab_size)) {
+      goto too_small;
+    }
   }
 done:
-  return offset + quant_size;
+  return;
 
   /* ERRORS */
 too_small:
   {
     GST_WARNING ("not enough data");
-    return size;
+    return;
   }
 small_quant_size:
   {
     GST_WARNING ("quant_size too small (%u < 2)", quant_size);
-    return size;
+    return;
   }
 invalid_id:
   {
@@ -467,38 +501,31 @@ no_table:
 }
 
 static gboolean
-gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
-    guint size, guint * offset, CompInfo info[], RtpQuantTable tables[],
-    gulong tables_elements)
+gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory,
+    CompInfo info[], RtpQuantTable tables[], gulong tables_elements)
 {
   guint sof_size, off;
   guint width, height, infolen;
   CompInfo elem;
   gint i, j;
 
-  off = *offset;
+  off = memory->offset;
 
   /* we need at least 17 bytes for the SOF */
-  if (off + 17 > size)
+  if (off + 17 > memory->total_size)
     goto wrong_size;
 
-  sof_size = gst_rtp_jpeg_pay_header_size (data, off);
+  sof_size = parse_mem_inc_offset_guint16 (memory);
   if (sof_size < 17)
     goto wrong_length;
 
-  *offset += sof_size;
-
-  /* skip size */
-  off += 2;
-
   /* precision should be 8 */
-  if (data[off++] != 8)
+  if (parse_mem_inc_offset_guint8 (memory) != 8)
     goto bad_precision;
 
   /* read dimensions */
-  height = data[off] << 8 | data[off + 1];
-  width = data[off + 2] << 8 | data[off + 3];
-  off += 4;
+  height = parse_mem_inc_offset_guint16 (memory);
+  width = parse_mem_inc_offset_guint16 (memory);
 
   GST_LOG_OBJECT (pay, "got dimensions %ux%u", height, width);
 
@@ -524,14 +551,14 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
   }
 
   /* we only support 3 components */
-  if (data[off++] != 3)
+  if (parse_mem_inc_offset_guint8 (memory) != 3)
     goto bad_components;
 
   infolen = 0;
   for (i = 0; i < 3; i++) {
-    elem.id = data[off++];
-    elem.samp = data[off++];
-    elem.qt = data[off++];
+    elem.id = parse_mem_inc_offset_guint8 (memory);
+    elem.samp = parse_mem_inc_offset_guint8 (memory);
+    elem.qt = parse_mem_inc_offset_guint8 (memory);
     GST_LOG_OBJECT (pay, "got comp %d, samp %02x, qt %d", elem.id, elem.samp,
         elem.qt);
     /* insertion sort from the last element to the first */
@@ -564,7 +591,8 @@ gst_rtp_jpeg_pay_read_sof (GstRtpJPEGPay * pay, const guint8 * data,
 wrong_size:
   {
     GST_ELEMENT_WARNING (pay, STREAM, FORMAT,
-        ("Wrong size %u (needed %u).", size, off + 17), (NULL));
+        ("Wrong size %u (needed %u).", (guint) memory->total_size, off + 17),
+        (NULL));
     return FALSE;
   }
 wrong_length:
@@ -599,57 +627,81 @@ invalid_comp:
 }
 
 static gboolean
-gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, const guint8 * data,
-    guint size, guint * offset, RtpRestartMarkerHeader * dri)
+gst_rtp_jpeg_pay_read_dri (GstRtpJPEGPay * pay, GstBufferMemoryMap * memory,
+    RtpRestartMarkerHeader * dri)
 {
-  guint dri_size, off;
-
-  off = *offset;
+  guint dri_size, restart_interval;
 
   /* we need at least 4 bytes for the DRI */
-  if (off + 4 > size)
+  if (memory->offset + 4 > memory->total_size)
     goto wrong_size;
 
-  dri_size = gst_rtp_jpeg_pay_header_size (data, off);
+  dri_size = parse_mem_inc_offset_guint16 (memory);
   if (dri_size < 4)
     goto wrong_length;
 
-  *offset += dri_size;
-  off += 2;
-
-  dri->restart_interval = g_htons ((data[off] << 8) | (data[off + 1]));
+  restart_interval = parse_mem_inc_offset_guint16 (memory);
+  dri->restart_interval = g_htons (restart_interval);
   dri->restart_count = g_htons (0xFFFF);
+  if (!gst_buffer_memory_advance_bytes (memory, dri_size - 4)) {
+    goto wrong_size;
+  }
 
   return dri->restart_interval > 0;
 
 wrong_size:
   {
     GST_WARNING ("not enough data for DRI");
-    *offset = size;
     return FALSE;
   }
 wrong_length:
   {
     GST_WARNING ("DRI size too small (%u)", dri_size);
-    *offset += dri_size;
+    /* offset got incremented by two when dri_size was parsed. */
+    if (dri_size > 2)
+      gst_buffer_memory_advance_bytes (memory, dri_size - 2);
     return FALSE;
   }
 }
 
+static void
+gst_rtp_jpeg_pay_skipping_marker (GstBufferMemoryMap * memory)
+{
+  guint skip;
+
+  if (G_UNLIKELY (((memory->offset + 1) >= memory->total_size))) {
+    goto wrong_size;
+  }
+  skip = parse_mem_inc_offset_guint16 (memory);
+
+  if (G_UNLIKELY (((skip - 2 + memory->offset) > memory->total_size))) {
+    goto wrong_size;
+  }
+  if (skip > 2) {
+    gst_buffer_memory_advance_bytes (memory, skip - 2);
+  }
+  return;
+
+wrong_size:
+  {
+    GST_WARNING ("not enough data");
+  }
+}
+
 static RtpJpegMarker
-gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
+gst_rtp_jpeg_pay_scan_marker (GstBufferMemoryMap * memory)
 {
-  while ((data[(*offset)++] != JPEG_MARKER) && ((*offset) < size));
+  guint8 marker = parse_mem_inc_offset_guint8 (memory);
+
+  while (marker != JPEG_MARKER && ((memory->offset) < memory->total_size)) {
+    marker = parse_mem_inc_offset_guint8 (memory);
+  }
 
-  if (G_UNLIKELY ((*offset) >= size)) {
+  if (G_UNLIKELY ((memory->offset) >= memory->total_size)) {
     GST_LOG ("found EOI marker");
     return JPEG_MARKER_EOI;
   } else {
-    guint8 marker;
-
-    marker = data[*offset];
-    GST_LOG ("found 0x%02x marker at offset %u", marker, *offset);
-    (*offset)++;
+    marker = parse_mem_inc_offset_guint8 (memory);
     return marker;
   }
 }
@@ -669,9 +721,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
   RtpQuantTable tables[15] = { {0, NULL}, };
   CompInfo info[3] = { {0,}, };
   guint quant_data_size;
-  GstMapInfo map;
-  guint8 *data;
-  gsize size;
   guint mtu, max_payload_size;
   guint bytes_left;
   guint jpeg_header_size = 0;
@@ -681,19 +730,19 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
   gint i;
   GstBufferList *list = NULL;
   gboolean discont;
+  GstBufferMemoryMap memory;
 
   pay = GST_RTP_JPEG_PAY (basepayload);
   mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
 
-  gst_buffer_map (buffer, &map, GST_MAP_READ);
-  data = map.data;
-  size = map.size;
+  gst_buffer_memory_map (buffer, &memory);
+
   timestamp = GST_BUFFER_PTS (buffer);
-  offset = 0;
   discont = GST_BUFFER_IS_DISCONT (buffer);
 
   GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
-      " , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp));
+      " , timestamp %" GST_TIME_FORMAT, memory.total_size,
+      GST_TIME_ARGS (timestamp));
 
   /* parse the jpeg header for 'start of scan' and read quant tables if needed */
   sos_found = FALSE;
@@ -701,33 +750,35 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
   sof_found = FALSE;
   dri_found = FALSE;
 
-  while (!sos_found && (offset < size)) {
+  while (!sos_found && (memory.offset < memory.total_size)) {
     gint marker;
 
-    GST_LOG_OBJECT (pay, "checking from offset %u", offset);
-    switch ((marker = gst_rtp_jpeg_pay_scan_marker (data, size, &offset))) {
+    GST_LOG_OBJECT (pay, "checking from offset %u", memory.offset);
+    marker = gst_rtp_jpeg_pay_scan_marker (&memory);
+    switch (marker) {
       case JPEG_MARKER_JFIF:
       case JPEG_MARKER_CMT:
       case JPEG_MARKER_DHT:
       case JPEG_MARKER_H264:
         GST_LOG_OBJECT (pay, "skipping marker");
-        offset += gst_rtp_jpeg_pay_header_size (data, offset);
+        gst_rtp_jpeg_pay_skipping_marker (&memory);
         break;
       case JPEG_MARKER_SOF:
-        if (!gst_rtp_jpeg_pay_read_sof (pay, data, size, &offset, info, tables,
+        if (!gst_rtp_jpeg_pay_read_sof (pay, &memory, info, tables,
                 G_N_ELEMENTS (tables)))
           goto invalid_format;
         sof_found = TRUE;
         break;
       case JPEG_MARKER_DQT:
         GST_LOG ("DQT found");
-        offset = gst_rtp_jpeg_pay_read_quant_table (data, size, offset, tables);
+        gst_rtp_jpeg_pay_read_quant_table (&memory, tables);
         dqt_found = TRUE;
         break;
       case JPEG_MARKER_SOS:
         sos_found = TRUE;
         GST_LOG_OBJECT (pay, "SOS found");
-        jpeg_header_size = offset + gst_rtp_jpeg_pay_header_size (data, offset);
+        jpeg_header_size =
+            memory.offset + parse_mem_inc_offset_guint16 (&memory);
         break;
       case JPEG_MARKER_EOI:
         GST_WARNING_OBJECT (pay, "EOI reached before SOS!");
@@ -737,8 +788,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
         break;
       case JPEG_MARKER_DRI:
         GST_LOG_OBJECT (pay, "DRI found");
-        if (gst_rtp_jpeg_pay_read_dri (pay, data, size, &offset,
-                &restart_marker_header))
+        if (gst_rtp_jpeg_pay_read_dri (pay, &memory, &restart_marker_header))
           dri_found = TRUE;
         break;
       default:
@@ -746,8 +796,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
             (marker >= JPEG_MARKER_JPG0 && marker <= JPEG_MARKER_JPG13) ||
             (marker >= JPEG_MARKER_APP0 && marker <= JPEG_MARKER_APP15)) {
           GST_LOG_OBJECT (pay, "skipping marker");
-          offset += gst_rtp_jpeg_pay_header_size (data, offset);
+          gst_rtp_jpeg_pay_skipping_marker (&memory);
         } else {
+          /* no need to do anything, gst_rtp_jpeg_pay_scan_marker will go on */
           GST_FIXME_OBJECT (pay, "unhandled marker 0x%02x", marker);
         }
         break;
@@ -764,8 +815,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
   GST_LOG_OBJECT (pay, "header size %u", jpeg_header_size);
 
-  size -= jpeg_header_size;
-  data += jpeg_header_size;
   offset = 0;
 
   if (dri_found)
@@ -777,7 +826,6 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
   jpeg_header.q = pay->quant;
   jpeg_header.width = pay->width;
   jpeg_header.height = pay->height;
-
   /* collect the quant headers sizes */
   quant_header.mbz = 0;
   quant_header.precision = 0;
@@ -808,7 +856,9 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
   GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
 
-  bytes_left = sizeof (jpeg_header) + quant_data_size + size;
+  bytes_left =
+      sizeof (jpeg_header) + quant_data_size + memory.total_size -
+      jpeg_header_size;
 
   if (dri_found)
     bytes_left += sizeof (restart_marker_header);
@@ -911,14 +961,12 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
     bytes_left -= payload_size;
     offset += payload_size;
-    data += payload_size;
   }
   while (!frame_done);
-
   /* push the whole buffer list at once */
   ret = gst_rtp_base_payload_push_list (basepayload, list);
 
-  gst_buffer_unmap (buffer, &map);
+  gst_buffer_memory_unmap (&memory);
   gst_buffer_unref (buffer);
 
   return ret;
@@ -927,28 +975,28 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
 unsupported_jpeg:
   {
     GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Unsupported JPEG"), (NULL));
-    gst_buffer_unmap (buffer, &map);
+    gst_buffer_memory_unmap (&memory);
     gst_buffer_unref (buffer);
     return GST_FLOW_OK;
   }
 no_dimension:
   {
     GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("No size given"), (NULL));
-    gst_buffer_unmap (buffer, &map);
+    gst_buffer_memory_unmap (&memory);
     gst_buffer_unref (buffer);
     return GST_FLOW_OK;
   }
 invalid_format:
   {
     /* error was posted */
-    gst_buffer_unmap (buffer, &map);
+    gst_buffer_memory_unmap (&memory);
     gst_buffer_unref (buffer);
     return GST_FLOW_OK;
   }
 invalid_quant:
   {
     GST_ELEMENT_WARNING (pay, STREAM, FORMAT, ("Invalid quant tables"), (NULL));
-    gst_buffer_unmap (buffer, &map);
+    gst_buffer_memory_unmap (&memory);
     gst_buffer_unref (buffer);
     return GST_FLOW_OK;
   }
index 424f6aa..a502671 100644 (file)
 
 /**
  * SECTION:element-rtpklvdepay
+ * @title: rtpklvdepay
  * @see_also: rtpklvpay
  *
  * Extract KLV metadata from RTP packets according to RFC 6597.
  * For detailed information see: http://tools.ietf.org/html/rfc6597
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)application, clock-rate=(int)90000, encoding-name=(string)SMPTE336M' ! rtpklvdepay ! fakesink dump=true
  * ]| This example pipeline will depayload an RTP KLV stream and display
  * a hexdump of the KLV data on stdout.
- * </refsect2>
+ *
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index 5a07d2c..f24d29f 100644 (file)
 
 /**
  * SECTION:element-rtpklvpay
+ * @title: rtpklvpay
  * @see_also: rtpklvdepay
  *
  * Payloads KLV metadata into RTP packets according to RFC 6597.
  * For detailed information see: http://tools.ietf.org/html/rfc6597
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
  * |[
  * gst-launch-1.0 filesrc location=video-with-klv.ts ! tsdemux ! rtpklvpay ! udpsink
  * ]| This example pipeline will payload an RTP KLV stream extracted from an
  * MPEG-TS stream and send it via UDP to an RTP receiver.
- * </refsect2>
+ *
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
index 12f948e..8dac50b 100644 (file)
@@ -152,7 +152,9 @@ gst_rtp_mp2t_pay_flush (GstRTPMP2TPay * rtpmp2tpay)
       break;
 
     /* create buffer to hold the payload */
-    outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (rtpmp2tpay), 0, 0, 0);
 
     /* get payload */
     paybuf = gst_adapter_take_buffer_fast (rtpmp2tpay->adapter, payload_len);
index e537d25..9177d7c 100644 (file)
@@ -389,7 +389,7 @@ gst_rtp_mp4a_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
       skip += data_len;
       pos += data_len;
 
-      /* update our pointers whith what we consumed */
+      /* update our pointers with what we consumed */
       data += skip;
       avail -= skip;
 
index 2f01b21..ab1eeb5 100644 (file)
@@ -408,7 +408,8 @@ gst_rtp_mp4a_pay_handle_buffer (GstRTPBasePayload * basepayload,
         packet_len, payload_len);
 
     /* create buffer to hold the payload. */
-    outbuf = gst_rtp_buffer_new_allocate (header_len, 0, 0);
+    outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload,
+        header_len, 0, 0);
 
     /* copy payload */
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
index 5d9d2cd..a734be0 100644 (file)
@@ -53,7 +53,7 @@ GST_STATIC_PAD_TEMPLATE ("sink",
         /* "streamtype = (string) { \"4\", \"5\" }, "  Not set by Wowza    4 = video, 5 = audio */
         /* "profile-level-id = (string) [1,MAX], " */
         /* "config = (string) [1,MAX]" */
-        "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
+        "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\", \"aac-hbr\" } "
         /* Optional general parameters */
         /* "objecttype = (string) [1,MAX], " */
         /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
@@ -241,6 +241,7 @@ gst_rtp_mp4g_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
           "mpegversion", G_TYPE_INT, 4, "stream-format", G_TYPE_STRING, "raw",
           NULL);
       rtpmp4gdepay->check_adts = TRUE;
+      rtpmp4gdepay->warn_adts = TRUE;
     } else if (strcmp (str, "video") == 0) {
       srccaps = gst_caps_new_simple ("video/mpeg",
           "mpegversion", G_TYPE_INT, 4,
@@ -597,7 +598,7 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
             rtpmp4gdepay->last_AU_index = AU_index;
           }
 
-          /* keep track of the higest AU_index */
+          /* keep track of the highest AU_index */
           if (rtpmp4gdepay->max_AU_index != -1
               && rtpmp4gdepay->max_AU_index <= AU_index) {
             GST_DEBUG_OBJECT (rtpmp4gdepay, "new interleave group, flushing");
@@ -681,13 +682,17 @@ gst_rtp_mp4g_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
                     0xfffe0000, 0xfff00000, 0, 4, &v) == 0) {
               guint adts_hdr_len = (((v >> 16) & 0x1) == 0) ? 9 : 7;
               if (avail > adts_hdr_len) {
-                GST_WARNING_OBJECT (rtpmp4gdepay, "Detected ADTS header of "
-                    "%u bytes, skipping", adts_hdr_len);
+                if (rtpmp4gdepay->warn_adts) {
+                  GST_WARNING_OBJECT (rtpmp4gdepay, "Detected ADTS header of "
+                      "%u bytes, skipping", adts_hdr_len);
+                  rtpmp4gdepay->warn_adts = FALSE;
+                }
                 gst_adapter_flush (rtpmp4gdepay->adapter, adts_hdr_len);
                 avail -= adts_hdr_len;
               }
             } else {
               rtpmp4gdepay->check_adts = FALSE;
+              rtpmp4gdepay->warn_adts = TRUE;
             }
           }
 
index d4d9330..8437328 100644 (file)
@@ -68,6 +68,7 @@ struct _GstRtpMP4GDepay
   guint prev_AU_num;
 
   gboolean check_adts; /* check for ADTS headers */
+  gboolean warn_adts;  /* warn about ADTS headers */
 
   GQueue *packets;
   
index 5b7f98b..532e2de 100644 (file)
@@ -472,7 +472,7 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
     GstRTPBuffer rtp = { NULL };
     GstBuffer *paybuf;
 
-    /* this will be the total lenght of the packet */
+    /* this will be the total length of the packet */
     packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
 
     /* fill one MTU or all available bytes, we need 4 spare bytes for
@@ -487,8 +487,9 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
         packet_len, payload_len);
 
     /* create buffer to hold the payload, also make room for the 4 header bytes. */
-    outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
-
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (rtpmp4gpay), 4, 0, 0);
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
     /* copy payload */
index 362ff65..2980339 100644 (file)
@@ -107,10 +107,11 @@ gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
       "Wim Taymans <wim.taymans@gmail.com>");
 
   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CONFIG_INTERVAL,
-      g_param_spec_uint ("config-interval", "Config Send Interval",
+      g_param_spec_int ("config-interval", "Config Send Interval",
           "Send Config Insertion Interval in seconds (configuration headers "
-          "will be multiplexed in the data stream when detected.) (0 = disabled)",
-          0, 3600, DEFAULT_CONFIG_INTERVAL,
+          "will be multiplexed in the data stream when detected.) "
+          "(0 = disabled, -1 = send with every IDR frame)",
+          -1, 3600, DEFAULT_CONFIG_INTERVAL,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
       );
 
@@ -266,7 +267,7 @@ gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
     guint packet_len;
     GstRTPBuffer rtp = { NULL };
 
-    /* this will be the total lenght of the packet */
+    /* this will be the total length of the packet */
     packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
 
     /* fill one MTU or all available bytes */
@@ -412,7 +413,7 @@ gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
   return result;
 }
 
-/* we expect buffers starting on startcodes. 
+/* we expect buffers starting on startcodes.
  */
 static GstFlowReturn
 gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
@@ -429,6 +430,7 @@ gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
   GstClockTime timestamp, duration;
   gboolean vopi;
   gboolean send_config;
+  GstClockTime running_time = GST_CLOCK_TIME_NONE;
 
   ret = GST_FLOW_OK;
   send_config = FALSE;
@@ -457,8 +459,10 @@ gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
   gst_buffer_unmap (buffer, &map);
 
   if (strip) {
-    /* strip off config if requested */
-    if (!(rtpmp4vpay->config_interval > 0)) {
+    /* strip off config if requested, do not strip off if the
+     * config_interval is set to -1 */
+    if (!(rtpmp4vpay->config_interval > 0)
+        && !(rtpmp4vpay->config_interval == -1)) {
       GstBuffer *subbuf;
 
       GST_LOG_OBJECT (rtpmp4vpay, "stripping config at %d, size %d", strip,
@@ -473,7 +477,7 @@ gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
       size = gst_buffer_get_size (buffer);
     } else {
-      GstClockTime running_time =
+      running_time =
           gst_segment_to_running_time (&basepayload->segment, GST_FORMAT_TIME,
           timestamp);
 
@@ -484,7 +488,7 @@ gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
 
   /* there is a config request, see if we need to insert it */
   if (vopi && (rtpmp4vpay->config_interval > 0) && rtpmp4vpay->config) {
-    GstClockTime running_time =
+    running_time =
         gst_segment_to_running_time (&basepayload->segment, GST_FORMAT_TIME,
         timestamp);
 
@@ -516,20 +520,26 @@ gst_rtp_mp4v_pay_handle_buffer (GstRTPBasePayload * basepayload,
       GST_DEBUG_OBJECT (rtpmp4vpay, "no previous config time, send now");
       send_config = TRUE;
     }
+  }
 
-    if (send_config) {
-      /* we need to send config now first */
-      GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");
+  if (vopi && (rtpmp4vpay->config_interval == -1)) {
+    GST_DEBUG_OBJECT (rtpmp4vpay, "sending config before current IDR frame");
+    /* send config before every IDR frame */
+    send_config = TRUE;
+  }
 
-      /* insert header */
-      buffer = gst_buffer_append (gst_buffer_ref (rtpmp4vpay->config), buffer);
+  if (send_config) {
+    /* we need to send config now first */
+    GST_LOG_OBJECT (rtpmp4vpay, "inserting config in stream");
 
-      GST_BUFFER_PTS (buffer) = timestamp;
-      size = gst_buffer_get_size (buffer);
+    /* insert header */
+    buffer = gst_buffer_append (gst_buffer_ref (rtpmp4vpay->config), buffer);
 
-      if (running_time != -1) {
-        rtpmp4vpay->last_config = running_time;
-      }
+    GST_BUFFER_PTS (buffer) = timestamp;
+    size = gst_buffer_get_size (buffer);
+
+    if (running_time != -1) {
+      rtpmp4vpay->last_config = running_time;
     }
   }
 
@@ -596,7 +606,7 @@ gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_CONFIG_INTERVAL:
-      rtpmp4vpay->config_interval = g_value_get_uint (value);
+      rtpmp4vpay->config_interval = g_value_get_int (value);
       break;
     default:
       break;
@@ -613,7 +623,7 @@ gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_CONFIG_INTERVAL:
-      g_value_set_uint (value, rtpmp4vpay->config_interval);
+      g_value_set_int (value, rtpmp4vpay->config_interval);
       break;
     default:
       break;
index a974a91..26c0ba0 100644 (file)
@@ -56,7 +56,7 @@ struct _GstRtpMP4VPay
 
   /* naming might be confusing with send_config; but naming matches h264
    * payloader */
-  guint         config_interval;
+  gint         config_interval;
   GstClockTime  last_config;
 };
 
index 09fa8a8..62639f7 100644 (file)
@@ -213,7 +213,9 @@ gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay)
     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
 
     /* create buffer to hold the payload */
-    outbuf = gst_rtp_buffer_new_allocate (4, 0, 0);
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (rtpmpapay), 4, 0, 0);
 
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
 
index ba54134..871a182 100644 (file)
@@ -39,8 +39,7 @@ static GstStaticPadTemplate gst_rtp_opus_pay_sink_template =
 GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS
-    ("audio/x-opus, channels = (int) [1, 2], channel-mapping-family = (int) 0")
+    GST_STATIC_CAPS ("audio/x-opus, channel-mapping-family = (int) 0")
     );
 
 static GstStaticPadTemplate gst_rtp_opus_pay_src_template =
@@ -181,7 +180,7 @@ gst_rtp_opus_pay_handle_buffer (GstRTPBasePayload * basepayload,
   dts = GST_BUFFER_DTS (buffer);
   duration = GST_BUFFER_DURATION (buffer);
 
-  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+  outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
 
   gst_rtp_copy_audio_meta (basepayload, outbuf, buffer);
 
index c7144e6..1e47817 100644 (file)
  * When using #GstRtpBin, this element should be inserted through the
  * #GstRtpBin::request-aux-receiver signal.
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
+ *
  * |[
  * gst-launch-1.0 udpsrc port=8888 caps="application/x-rtp, payload=96, clock-rate=90000" ! rtpreddec pt=122 ! rtpstorage size-time=220000000 ! rtpssrcdemux ! application/x-rtp, payload=96, clock-rate=90000, media=video, encoding-name=H264 ! rtpjitterbuffer do-lost=1 latency=200 !  rtpulpfecdec pt=122 ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink
  * ]| This example will receive a stream with RED and ULP FEC and try to reconstruct the packets.
- * </refsect2>
  *
  * See also: #GstRtpRedEnc, #GstWebRTCBin, #GstRtpBin
  * Since: 1.14
index 78d2b97..f192b78 100644 (file)
  * When using #GstRtpBin, this element should be inserted through the
  * #GstRtpBin::request-fec-encoder signal.
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
+ *
  * |[
  * gst-launch-1.0 videotestsrc ! x264enc ! video/x-h264, profile=baseline ! rtph264pay pt=96 ! rtpulpfecenc percentage=100 pt=122 ! rtpredenc pt=122 distance=2 ! identity drop-probability=0.05 ! udpsink port=8888
  * ]| This example will send a stream with RED and ULP FEC.
- * </refsect2>
  *
  * See also: #GstRtpRedDec, #GstWebRTCBin, #GstRtpBin
  * Since: 1.14
@@ -145,7 +144,7 @@ _alloc_red_packet_and_fill_headers (GstRtpRedEnc * self,
   guint red_header_size = rtp_red_block_header_get_length (FALSE) +
       (redundant_block ? rtp_red_block_header_get_length (TRUE) : 0);
 
-  guint32 timestmap = gst_rtp_buffer_get_timestamp (inp_rtp);
+  guint32 timestamp = gst_rtp_buffer_get_timestamp (inp_rtp);
   guint csrc_count = gst_rtp_buffer_get_csrc_count (inp_rtp);
   GstBuffer *red = gst_rtp_buffer_new_allocate (red_header_size, 0, csrc_count);
   guint8 *red_block_header;
@@ -162,7 +161,7 @@ _alloc_red_packet_and_fill_headers (GstRtpRedEnc * self,
   gst_rtp_buffer_set_marker (&red_rtp, gst_rtp_buffer_get_marker (inp_rtp));
   gst_rtp_buffer_set_payload_type (&red_rtp, self->pt);
   gst_rtp_buffer_set_seq (&red_rtp, gst_rtp_buffer_get_seq (inp_rtp));
-  gst_rtp_buffer_set_timestamp (&red_rtp, timestmap);
+  gst_rtp_buffer_set_timestamp (&red_rtp, timestamp);
   gst_rtp_buffer_set_ssrc (&red_rtp, gst_rtp_buffer_get_ssrc (inp_rtp));
   for (i = 0; i != csrc_count; ++i)
     gst_rtp_buffer_set_csrc (&red_rtp, i,
@@ -174,7 +173,7 @@ _alloc_red_packet_and_fill_headers (GstRtpRedEnc * self,
     rtp_red_block_set_is_redundant (red_block_header, TRUE);
     rtp_red_block_set_payload_type (red_block_header, redundant_block->pt);
     rtp_red_block_set_timestamp_offset (red_block_header,
-        timestmap - redundant_block->timestamp);
+        timestamp - redundant_block->timestamp);
     rtp_red_block_set_payload_length (red_block_header,
         gst_buffer_get_size (redundant_block->payload));
 
index 1d2cbd4..f2cf849 100644 (file)
@@ -198,7 +198,9 @@ gst_rtp_sbc_pay_flush_buffers (GstRtpSBCPay * sbcpay)
     if (payload_length == 0)    /* Nothing to send */
       return GST_FLOW_OK;
 
-    outbuf = gst_rtp_buffer_new_allocate (RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
+    outbuf =
+        gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+        (sbcpay), RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
 
     /* get payload */
     gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
index 7816bd6..6f086b0 100644 (file)
@@ -279,8 +279,8 @@ gst_rtp_speex_pay_handle_buffer (GstRTPBasePayload * basepayload,
   duration = GST_BUFFER_DURATION (buffer);
 
   /* FIXME, only one SPEEX frame per RTP packet for now */
+  outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
 
-  outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
   /* FIXME, assert for now */
   g_assert (gst_buffer_get_size (buffer) <=
       GST_RTP_BASE_PAYLOAD_MTU (rtpspeexpay));
index 34500e9..bcaec19 100644 (file)
 
 /**
  * SECTION:element-rtpstreamdepay
+ * @title: rtpstreamdepay
  *
  * Implements stream depayloading of RTP and RTCP packets for connection-oriented
  * transport protocols according to RFC4571.
- * <refsect2>
- * <title>Example launch line</title>
+ *
+ * ## Example launch line
  * |[
  * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
  * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
  * ]|
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index 87848c4..b575822 100644 (file)
 
 /**
  * SECTION:element-rtpstreampay
+ * @title: rtpstreampay
  *
  * Implements stream payloading of RTP and RTCP packets for connection-oriented
  * transport protocols according to RFC4571.
- * <refsect2>
- * <title>Example launch line</title>
+ *
+ * ## Example launch line
  * |[
  * gst-launch-1.0 audiotestsrc ! "audio/x-raw,rate=48000" ! vorbisenc ! rtpvorbispay config-interval=1 ! rtpstreampay ! tcpserversink port=5678
  * gst-launch-1.0 tcpclientsrc port=5678 host=127.0.0.1 do-timestamp=true ! "application/x-rtp-stream,media=audio,clock-rate=48000,encoding-name=VORBIS" ! rtpstreamdepay ! rtpvorbisdepay ! decodebin ! audioconvert ! audioresample ! autoaudiosink
  * ]|
- * </refsect2>
+ *
  */
 
 #ifdef HAVE_CONFIG_H
index edc50cf..c8af974 100644 (file)
@@ -599,7 +599,7 @@ no_output:
 
   return NULL;
 
-  /* ERORRS */
+  /* ERRORS */
 switch_failed:
   {
     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
index 6248c45..709309a 100644 (file)
  * When using #GstRtpBin, this element should be inserted through the
  * #GstRtpBin::request-fec-decoder signal.
  *
- * <refsect2>
- * <title>Example pipeline</title>
+ * ## Example pipeline
+ *
  * |[
  * gst-launch-1.0 udpsrc port=8888 caps="application/x-rtp, payload=96, clock-rate=90000" ! rtpstorage size-time=220000000 ! rtpssrcdemux ! application/x-rtp, payload=96, clock-rate=90000, media=video, encoding-name=H264 ! rtpjitterbuffer do-lost=1 latency=200 !  rtpulpfecdec pt=122 ! rtph264depay ! avdec_h264 ! videoconvert ! autovideosink
  * ]| This example will receive a stream with FEC and try to reconstruct the packets.
  *
  * Example programs are available at
- * <ulink url="https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs">rtpfecserver.rs</ulink>
+ * <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs>
  * and
- * <ulink url="https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs">rtpfecclient.rs</ulink>
- *
- * </refsect2>
+ * <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs>
  *
  * See also: #GstRtpUlpFecEnc, #GstRtpBin, #GstRtpStorage
  * Since: 1.14
index 6637734..bd2df23 100644 (file)
  * When using #GstRtpBin, this element should be inserted through the
  * #GstRtpBin::request-fec-encoder signal.
  *
+ * ## Example pipeline
  *
- * <refsect2>
- * <title>Example pipeline</title>
  * |[
  * gst-launch-1.0 videotestsrc ! x264enc ! video/x-h264, profile=baseline ! rtph264pay pt=96 ! rtpulpfecenc percentage=100 pt=122 ! udpsink port=8888
  * ]| This example will receive a stream with FEC and try to reconstruct the packets.
  *
  * Example programs are available at
- * <ulink url="https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs">rtpfecserver.rs</ulink>
+ * <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecserver.rs>
  * and
- * <ulink url="https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs">rtpfecclient.rs</ulink>
- * </refsect2>
+ * <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/blob/master/examples/src/bin/rtpfecclient.rs>
  *
  * See also: #GstRtpUlpFecDec, #GstRtpBin
  * Since: 1.14
@@ -559,7 +557,7 @@ gst_rtp_ulpfec_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
 
   ret = gst_rtp_ulpfec_enc_stream_ctx_process (ctx, buffer);
 
-  /* FIXME: does not work for mulitple ssrcs */
+  /* FIXME: does not work for multiple ssrcs */
   fec->num_packets_protected = ctx->num_packets_protected;
 
   return ret;
index 044d1b3..4d86fb2 100644 (file)
@@ -39,8 +39,9 @@ foreach_metadata_copy (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
   const GstMetaInfo *info = (*meta)->info;
   const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
 
-  if (!tags || (copy_tag != 0 && g_strv_length ((gchar **) tags) == 1
-          && gst_meta_api_type_has_tag (info->api, copy_tag))) {
+  if (info->transform_func && (!tags || !tags[0] || (copy_tag != 0
+              && g_strv_length ((gchar **) tags) == 1
+              && gst_meta_api_type_has_tag (info->api, copy_tag)))) {
     GstMetaTransformCopy copy_data = { FALSE, 0, -1 };
     GST_DEBUG_OBJECT (element, "copy metadata %s", g_type_name (info->api));
     /* simply copy then */
@@ -93,7 +94,8 @@ foreach_metadata_drop (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data)
   const GstMetaInfo *info = (*meta)->info;
   const gchar *const *tags = gst_meta_api_type_get_tags (info->api);
 
-  if (!tags || (keep_tag != 0 && g_strv_length ((gchar **) tags) == 1
+  if (!tags || !tags[0] || (keep_tag != 0
+          && g_strv_length ((gchar **) tags) == 1
           && gst_meta_api_type_has_tag (info->api, keep_tag))) {
     GST_DEBUG_OBJECT (element, "keeping metadata %s", g_type_name (info->api));
   } else {
index d3618b9..556bd76 100644 (file)
@@ -630,7 +630,7 @@ no_output:
     }
     return NULL;
   }
-  /* ERORRS */
+  /* ERRORS */
 switch_failed:
   {
     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
index 9220f37..8a3c249 100644 (file)
@@ -270,14 +270,18 @@ static void
 gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
     GstClockTime timestamp)
 {
+  guint len;
+
   GST_LOG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT);
 
   gst_rtp_vorbis_pay_clear_packet (rtpvorbispay);
 
   /* new packet allocate max packet size */
-  rtpvorbispay->packet =
-      gst_rtp_buffer_new_allocate_len (GST_RTP_BASE_PAYLOAD_MTU
+  len = gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU
       (rtpvorbispay), 0, 0);
+  rtpvorbispay->packet =
+      gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD
+      (rtpvorbispay), len, 0, 0);
   gst_rtp_vorbis_pay_reset_packet (rtpvorbispay, VDT);
 
   GST_BUFFER_PTS (rtpvorbispay->packet) = timestamp;
index 6da17e2..e71baf8 100644 (file)
@@ -33,12 +33,10 @@ GST_DEBUG_CATEGORY_STATIC (gst_rtp_vp8_depay_debug);
 #define GST_CAT_DEFAULT gst_rtp_vp8_depay_debug
 
 static void gst_rtp_vp8_depay_dispose (GObject * object);
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
 static void gst_rtp_vp8_depay_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 static void gst_rtp_vp8_depay_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
-#endif
 static GstBuffer *gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depayload,
     GstRTPBuffer * rtp);
 static GstStateChangeReturn gst_rtp_vp8_depay_change_state (GstElement *
@@ -63,7 +61,6 @@ GST_STATIC_PAD_TEMPLATE ("sink",
         "media = (string) \"video\","
         "encoding-name = (string) { \"VP8\", \"VP8-DRAFT-IETF-01\" }"));
 
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
 #define DEFAULT_WAIT_FOR_KEYFRAME FALSE
 
 enum
@@ -71,16 +68,13 @@ enum
   PROP_0,
   PROP_WAIT_FOR_KEYFRAME
 };
-#endif
 
 static void
 gst_rtp_vp8_depay_init (GstRtpVP8Depay * self)
 {
   self->adapter = gst_adapter_new ();
   self->started = FALSE;
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
   self->wait_for_keyframe = DEFAULT_WAIT_FOR_KEYFRAME;
-#endif
 }
 
 static void
@@ -91,7 +85,6 @@ gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
   GstRTPBaseDepayloadClass *depay_class =
       (GstRTPBaseDepayloadClass *) (gst_rtp_vp8_depay_class);
 
-
   gst_element_class_add_static_pad_template (element_class,
       &gst_rtp_vp8_depay_sink_template);
   gst_element_class_add_static_pad_template (element_class,
@@ -103,7 +96,6 @@ gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
       "Sjoerd Simons <sjoerd@luon.net>");
 
   object_class->dispose = gst_rtp_vp8_depay_dispose;
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
   object_class->set_property = gst_rtp_vp8_depay_set_property;
   object_class->get_property = gst_rtp_vp8_depay_get_property;
 
@@ -112,7 +104,7 @@ gst_rtp_vp8_depay_class_init (GstRtpVP8DepayClass * gst_rtp_vp8_depay_class)
           "Wait for the next keyframe after packet loss",
           DEFAULT_WAIT_FOR_KEYFRAME,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-#endif
+
   element_class->change_state = gst_rtp_vp8_depay_change_state;
 
   depay_class->process_rtp_packet = gst_rtp_vp8_depay_process;
@@ -137,7 +129,6 @@ gst_rtp_vp8_depay_dispose (GObject * object)
     G_OBJECT_CLASS (gst_rtp_vp8_depay_parent_class)->dispose (object);
 }
 
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
 static void
 gst_rtp_vp8_depay_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -169,7 +160,6 @@ gst_rtp_vp8_depay_get_property (GObject * object, guint prop_id,
       break;
   }
 }
-#endif
 
 static GstBuffer *
 gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
@@ -184,10 +174,9 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
     GST_LOG_OBJECT (self, "Discontinuity, flushing adapter");
     gst_adapter_clear (self->adapter);
     self->started = FALSE;
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
+
     if (self->wait_for_keyframe)
       self->waiting_for_keyframe = TRUE;
-#endif
   }
 
   size = gst_rtp_buffer_get_payload_len (rtp);
@@ -256,11 +245,7 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
     if ((header[0] & 0x01)) {
       GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT);
 
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
       if (self->waiting_for_keyframe) {
-#else
-      if (!self->caps_sent) {
-#endif
         gst_buffer_unref (out);
         out = NULL;
         GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame");
@@ -291,16 +276,12 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp)
 
         gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps);
         gst_caps_unref (srccaps);
-#ifndef TIZEN_FEATURE_GST_UPSTREAM
-        self->caps_sent = TRUE;
-#endif
+
         self->last_width = width;
         self->last_height = height;
         self->last_profile = profile;
       }
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
       self->waiting_for_keyframe = FALSE;
-#endif
     }
 
     return out;
@@ -327,11 +308,7 @@ gst_rtp_vp8_depay_change_state (GstElement * element, GstStateChange transition)
       self->last_profile = -1;
       self->last_height = -1;
       self->last_width = -1;
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
       self->waiting_for_keyframe = TRUE;
-#else
-      self->caps_sent = FALSE;
-#endif
       break;
     default:
       break;
index 0dc5c53..cde8e5e 100644 (file)
@@ -54,17 +54,12 @@ struct _GstRtpVP8Depay
   GstAdapter *adapter;
   gboolean started;
 
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
   gboolean waiting_for_keyframe;
-#else
-  gboolean caps_sent;
-#endif
   gint last_profile;
   gint last_width;
   gint last_height;
-#ifdef TIZEN_FEATURE_GST_UPSTREAM
+
   gboolean wait_for_keyframe;
-#endif
 };
 
 GType gst_rtp_vp8_depay_get_type (void);
index 17a7788..5c53a29 100644 (file)
@@ -134,6 +134,10 @@ gst_rtp_vp8_pay_class_init (GstRtpVP8PayClass * gst_rtp_vp8_pay_class)
 
   GST_DEBUG_CATEGORY_INIT (gst_rtp_vp8_pay_debug, "rtpvp8pay", 0,
       "VP8 Video RTP Payloader");
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_RTP_VP8_PAY_PICTURE_ID_MODE, 0);
+#endif
 }
 
 static void
@@ -531,6 +535,7 @@ gst_rtp_vp8_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
       if (!gst_value_can_intersect (&default_value, value))
         encoding_name = "VP8-DRAFT-IETF-01";
     }
+    gst_caps_unref (src_caps);
   }
 
   gst_rtp_base_payload_set_options (payload, "video", TRUE,
index fd16765..5917e1a 100644 (file)
@@ -135,6 +135,10 @@ gst_rtp_vp9_pay_class_init (GstRtpVP9PayClass * gst_rtp_vp9_pay_class)
 
   GST_DEBUG_CATEGORY_INIT (gst_rtp_vp9_pay_debug, "rtpvp9pay", 0,
       "VP9 Video RTP Payloader");
+
+#ifndef TIZEN_FEATURE_GST_UPSTREAM_AVOID_BUILD_BREAK
+  gst_type_mark_as_plugin_api (GST_TYPE_RTP_VP9_PAY_PICTURE_ID_MODE, 0);
+#endif
 }
 
 static void
@@ -546,6 +550,7 @@ gst_rtp_vp9_pay_set_caps (GstRTPBasePayload * payload, GstCaps * caps)
       if (!gst_value_can_intersect (&default_value, value))
         encoding_name = "VP9-DRAFT-IETF-01";
     }
+    gst_caps_unref (src_caps);
   }
 
   gst_rtp_base_payload_set_options (payload, "video", TRUE,
index d6906dc..d679f68 100644 (file)
@@ -456,7 +456,7 @@ gst_rtp_vraw_depay_process_packet (GstRTPBaseDepayload * depayload,
       goto next;
     }
 
-    /* calculate the maximim amount of bytes we can use per line */
+    /* calculate the maximum amount of bytes we can use per line */
     if (offs + ((length / pgroup) * xinc) > width) {
       plen = ((width - offs) * pgroup) / xinc;
       GST_WARNING_OBJECT (depayload, "clipping length %d, offset %d, plen %d",
index 3cf2173..d57a195 100644 (file)
@@ -1,6 +1,7 @@
 rtp_sources = [
   'dboolhuff.c',
   'fnv1hash.c',
+  'gstbuffermemory.c',
   'gstrtp.c',
   'gstrtpchannels.c',
   'gstrtpac3depay.c',
@@ -119,3 +120,4 @@ gstrtp = library('gstrtp',
   install_dir : plugins_install_dir,
 )
 pkgconfig.generate(gstrtp, install_dir : plugins_pkgconfig_install_dir)
+plugins += [gstrtp]
index ecabffc..d83dabb 100644 (file)
@@ -67,8 +67,7 @@ rtp_storage_class_init (RtpStorageClass * klass)
 
   rtp_storage_signals[SIGNAL_PACKET_RECOVERED] =
       g_signal_new ("packet-recovered", G_TYPE_FROM_CLASS (klass),
-      G_SIGNAL_RUN_LAST, 0, NULL, NULL,
-      g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_BUFFER);
 
   gobject_class->dispose = rtp_storage_dispose;
 }
@@ -92,7 +91,7 @@ rtp_storage_get_packets_for_recovery (RtpStorage * self, gint fec_pt,
   STORAGE_UNLOCK (self);
 
   if (NULL == stream) {
-    GST_ERROR_OBJECT (self, "Cant find ssrc = 0x08%x", ssrc);
+    GST_ERROR_OBJECT (self, "Can't find ssrc = 0x08%x", ssrc);
   } else {
     STREAM_LOCK (stream);
     if (stream->queue.length > 0) {
@@ -128,7 +127,7 @@ rtp_storage_get_redundant_packet (RtpStorage * self, guint32 ssrc,
   STORAGE_UNLOCK (self);
 
   if (NULL == stream) {
-    GST_ERROR_OBJECT (self, "Cant find ssrc = 0x%x", ssrc);
+    GST_ERROR_OBJECT (self, "Can't find ssrc = 0x%x", ssrc);
   } else {
     STREAM_LOCK (stream);
     if (stream->queue.length > 0) {
index 326b5ff..7c6bf58 100644 (file)
@@ -358,7 +358,7 @@ rtp_ulpfec_map_info_map (GstBuffer * buffer, RtpUlpFecMapInfo * info)
  * @info: #RtpUlpFecMapInfo
  *
  * Unmap @info previously mapped with rtp_ulpfec_map_info_map() and unrefs the
- * buffer. For convinience can even be called even if rtp_ulpfec_map_info_map
+ * buffer. For convenience can even be called even if rtp_ulpfec_map_info_map
  * returned FALSE
  **/
 void
index 2c9d798..f44174a 100644 (file)
@@ -38,12 +38,12 @@ G_BEGIN_DECLS
 #define RTP_ULPFEC_SEQ_BASE_OFFSET_MAX(L)      (RTP_ULPFEC_PROTECTED_PACKETS_MAX(L) - 1)
 
 /**
- * RtpUlpFecMapInfo: Helper wraper around GstRTPBuffer
+ * RtpUlpFecMapInfo: Helper wrapper around GstRTPBuffer
  *
  * @rtp: mapped RTP buffer
  **/
 typedef struct {
-  // FIXME: it used to contain more fileds now we are left with only GstRTPBuffer.
+  // FIXME: it used to contain more fields now we are left with only GstRTPBuffer.
   //        it will be nice to use it directly
   GstRTPBuffer rtp;
 } RtpUlpFecMapInfo;