rtp: Update codes based on 1.18.4
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpmp4gpay.c
index cd988c8..532e2de 100644 (file)
@@ -13,8 +13,8 @@
  *
  * 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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -27,6 +27,7 @@
 #include <gst/rtp/gstrtpbuffer.h>
 
 #include "gstrtpmp4gpay.h"
+#include "gstrtputils.h"
 
 GST_DEBUG_CATEGORY_STATIC (rtpmp4gpay_debug);
 #define GST_CAT_DEFAULT (rtpmp4gpay_debug)
@@ -78,53 +79,52 @@ static void gst_rtp_mp4g_pay_finalize (GObject * object);
 static GstStateChangeReturn gst_rtp_mp4g_pay_change_state (GstElement * element,
     GstStateChange transition);
 
-static gboolean gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload,
+static gboolean gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload,
     GstCaps * caps);
-static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload *
+static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload *
     payload, GstBuffer * buffer);
+static gboolean gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload,
+    GstEvent * event);
 
-GST_BOILERPLATE (GstRtpMP4GPay, gst_rtp_mp4g_pay, GstBaseRTPPayload,
-    GST_TYPE_BASE_RTP_PAYLOAD)
-
-     static void gst_rtp_mp4g_pay_base_init (gpointer klass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&gst_rtp_mp4g_pay_src_template));
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&gst_rtp_mp4g_pay_sink_template));
-
-  gst_element_class_set_details_simple (element_class, "RTP MPEG4 ES payloader",
-      "Codec/Payloader/Network",
-      "Payload MPEG4 elementary streams as RTP packets (RFC 3640)",
-      "Wim Taymans <wim.taymans@gmail.com>");
-}
+#define gst_rtp_mp4g_pay_parent_class parent_class
+G_DEFINE_TYPE (GstRtpMP4GPay, gst_rtp_mp4g_pay, GST_TYPE_RTP_BASE_PAYLOAD);
 
 static void
 gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
-  GstBaseRTPPayloadClass *gstbasertppayload_class;
+  GstRTPBasePayloadClass *gstrtpbasepayload_class;
 
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
-  gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
+  gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
 
   gobject_class->finalize = gst_rtp_mp4g_pay_finalize;
 
   gstelement_class->change_state = gst_rtp_mp4g_pay_change_state;
 
-  gstbasertppayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
-  gstbasertppayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
+  gstrtpbasepayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
+  gstrtpbasepayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
+  gstrtpbasepayload_class->sink_event = gst_rtp_mp4g_pay_sink_event;
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_pay_src_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_rtp_mp4g_pay_sink_template);
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "RTP MPEG4 ES payloader",
+      "Codec/Payloader/Network/RTP",
+      "Payload MPEG4 elementary streams as RTP packets (RFC 3640)",
+      "Wim Taymans <wim.taymans@gmail.com>");
 
   GST_DEBUG_CATEGORY_INIT (rtpmp4gpay_debug, "rtpmp4gpay", 0,
       "MP4-generic RTP Payloader");
 }
 
 static void
-gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay, GstRtpMP4GPayClass * klass)
+gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay)
 {
   rtpmp4gpay->adapter = gst_adapter_new ();
 }
@@ -135,6 +135,12 @@ gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay)
   GST_DEBUG_OBJECT (rtpmp4gpay, "reset");
 
   gst_adapter_clear (rtpmp4gpay->adapter);
+}
+
+static void
+gst_rtp_mp4g_pay_cleanup (GstRtpMP4GPay * rtpmp4gpay)
+{
+  gst_rtp_mp4g_pay_reset (rtpmp4gpay);
 
   g_free (rtpmp4gpay->params);
   rtpmp4gpay->params = NULL;
@@ -150,7 +156,6 @@ gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay)
   rtpmp4gpay->mode = NULL;
 
   rtpmp4gpay->frame_len = 0;
-  rtpmp4gpay->offset = 0;
 }
 
 static void
@@ -160,7 +165,7 @@ gst_rtp_mp4g_pay_finalize (GObject * object)
 
   rtpmp4gpay = GST_RTP_MP4G_PAY (object);
 
-  gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+  gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
 
   g_object_unref (rtpmp4gpay->adapter);
   rtpmp4gpay->adapter = NULL;
@@ -177,17 +182,15 @@ static gboolean
 gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
     GstBuffer * buffer)
 {
-  guint8 *data;
-  guint size;
-  guint8 objectType;
-  guint8 samplingIdx;
-  guint8 channelCfg;
+  GstMapInfo map;
+  guint8 objectType = 0;
+  guint8 samplingIdx = 0;
+  guint8 channelCfg = 0;
   GstBitReader br;
 
-  data = GST_BUFFER_DATA (buffer);
-  size = GST_BUFFER_SIZE (buffer);
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
 
-  gst_bit_reader_init (&br, data, size);
+  gst_bit_reader_init (&br, map.data, map.size);
 
   /* any object type is fine, we need to copy it to the profile-level-id field. */
   if (!gst_bit_reader_get_bits_uint8 (&br, &objectType, 5))
@@ -208,7 +211,7 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
 
   /* rtp rate depends on sampling rate of the audio */
   if (samplingIdx == 15) {
-    guint32 rate;
+    guint32 rate = 0;
 
     /* index of 15 means we get the rate in the next 24 bits */
     if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
@@ -230,7 +233,7 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
     case 6:
     case 7:
     {
-      guint8 frameLenFlag;
+      guint8 frameLenFlag = 0;
 
       if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
         if (frameLenFlag)
@@ -258,6 +261,7 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
       objectType, samplingIdx, rtpmp4gpay->rate, channelCfg,
       rtpmp4gpay->frame_len);
 
+  gst_buffer_unmap (buffer, &map);
   return TRUE;
 
   /* ERROR */
@@ -265,24 +269,28 @@ too_short:
   {
     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
         (NULL), ("config string too short"));
+    gst_buffer_unmap (buffer, &map);
     return FALSE;
   }
 invalid_object:
   {
     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
         (NULL), ("invalid object type"));
+    gst_buffer_unmap (buffer, &map);
     return FALSE;
   }
 wrong_freq:
   {
     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
         (NULL), ("unsupported frequency index %d", samplingIdx));
+    gst_buffer_unmap (buffer, &map);
     return FALSE;
   }
 wrong_channels:
   {
     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
         (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
+    gst_buffer_unmap (buffer, &map);
     return FALSE;
   }
 }
@@ -293,22 +301,20 @@ static gboolean
 gst_rtp_mp4g_pay_parse_video_config (GstRtpMP4GPay * rtpmp4gpay,
     GstBuffer * buffer)
 {
-  guint8 *data;
-  guint size;
+  GstMapInfo map;
   guint32 code;
 
-  data = GST_BUFFER_DATA (buffer);
-  size = GST_BUFFER_SIZE (buffer);
+  gst_buffer_map (buffer, &map, GST_MAP_READ);
 
-  if (size < 5)
+  if (map.size < 5)
     goto too_short;
 
-  code = GST_READ_UINT32_BE (data);
+  code = GST_READ_UINT32_BE (map.data);
 
   g_free (rtpmp4gpay->profile);
   if (code == VOS_STARTCODE) {
     /* get profile */
-    rtpmp4gpay->profile = g_strdup_printf ("%d", (gint) data[4]);
+    rtpmp4gpay->profile = g_strdup_printf ("%d", (gint) map.data[4]);
   } else {
     GST_ELEMENT_WARNING (rtpmp4gpay, STREAM, FORMAT,
         (NULL), ("profile not found in config string, assuming \'1\'"));
@@ -326,6 +332,8 @@ gst_rtp_mp4g_pay_parse_video_config (GstRtpMP4GPay * rtpmp4gpay,
 
   GST_LOG_OBJECT (rtpmp4gpay, "profile %s", rtpmp4gpay->profile);
 
+  gst_buffer_unmap (buffer, &map);
+
   return TRUE;
 
   /* ERROR */
@@ -333,6 +341,7 @@ too_short:
   {
     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
         (NULL), ("config string too short"));
+    gst_buffer_unmap (buffer, &map);
     return FALSE;
   }
 }
@@ -360,10 +369,10 @@ gst_rtp_mp4g_pay_new_caps (GstRtpMP4GPay * rtpmp4gpay)
 
   /* hmm, silly */
   if (rtpmp4gpay->params) {
-    res = gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4gpay),
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
         "encoding-params", G_TYPE_STRING, rtpmp4gpay->params, MP4GCAPS);
   } else {
-    res = gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4gpay),
+    res = gst_rtp_base_payload_set_outcaps (GST_RTP_BASE_PAYLOAD (rtpmp4gpay),
         MP4GCAPS);
   }
 
@@ -375,7 +384,7 @@ gst_rtp_mp4g_pay_new_caps (GstRtpMP4GPay * rtpmp4gpay)
 }
 
 static gboolean
-gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
+gst_rtp_mp4g_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
 {
   GstRtpMP4GPay *rtpmp4gpay;
   GstStructure *structure;
@@ -422,7 +431,7 @@ gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
   if (media_type == NULL)
     goto config_failed;
 
-  gst_basertppayload_set_options (payload, media_type, TRUE, "MPEG4-GENERIC",
+  gst_rtp_base_payload_set_options (payload, media_type, TRUE, "MPEG4-GENERIC",
       rtpmp4gpay->rate);
 
   res = gst_rtp_mp4g_pay_new_caps (rtpmp4gpay);
@@ -443,11 +452,8 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
   guint avail, total;
   GstBuffer *outbuf;
   GstFlowReturn ret;
-  gboolean fragmented;
   guint mtu;
 
-  fragmented = FALSE;
-
   /* the data available in the adapter is either smaller
    * than the MTU or bigger. In the case it is smaller, the complete
    * adapter contents can be put in one packet. In the case the
@@ -456,15 +462,17 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
   total = avail = gst_adapter_available (rtpmp4gpay->adapter);
 
   ret = GST_FLOW_OK;
-  mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpmp4gpay);
+  mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4gpay);
 
   while (avail > 0) {
     guint towrite;
     guint8 *payload;
     guint payload_len;
     guint packet_len;
+    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
@@ -479,10 +487,13 @@ 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 (payload_len + 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 */
-    payload = gst_rtp_buffer_get_payload (outbuf);
+    payload = gst_rtp_buffer_get_payload (&rtp);
 
     /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
      * |AU-headers-length|AU-header|AU-header|      |AU-header|padding|
@@ -518,25 +529,29 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
     payload[2] = (total & 0x1fe0) >> 5;
     payload[3] = (total & 0x1f) << 3;   /* we use 13 bits for the size, 3 bits index */
 
-    /* copy stuff from adapter to payload */
-    gst_adapter_copy (rtpmp4gpay->adapter, &payload[4], 0, payload_len);
-    gst_adapter_flush (rtpmp4gpay->adapter, payload_len);
-
     /* marker only if the packet is complete */
-    gst_rtp_buffer_set_marker (outbuf, avail <= payload_len);
+    gst_rtp_buffer_set_marker (&rtp, avail <= payload_len);
+
+    gst_rtp_buffer_unmap (&rtp);
 
-    GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_timestamp;
+    paybuf = gst_adapter_take_buffer_fast (rtpmp4gpay->adapter, payload_len);
+    gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpmp4gpay), outbuf, paybuf, 0);
+    outbuf = gst_buffer_append (outbuf, paybuf);
+
+    GST_BUFFER_PTS (outbuf) = rtpmp4gpay->first_timestamp;
     GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration;
 
-    if (rtpmp4gpay->frame_len) {
-      GST_BUFFER_OFFSET (outbuf) = rtpmp4gpay->offset;
-      rtpmp4gpay->offset += rtpmp4gpay->frame_len;
+    GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET_NONE;
+
+    if (rtpmp4gpay->discont) {
+      GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+      /* Only the first outputted buffer has the DISCONT flag */
+      rtpmp4gpay->discont = FALSE;
     }
 
-    ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4gpay), outbuf);
+    ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4gpay), outbuf);
 
     avail -= payload_len;
-    fragmented = TRUE;
   }
 
   return ret;
@@ -545,15 +560,16 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
 /* we expect buffers as exactly one complete AU
  */
 static GstFlowReturn
-gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * basepayload,
+gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload * basepayload,
     GstBuffer * buffer)
 {
   GstRtpMP4GPay *rtpmp4gpay;
 
   rtpmp4gpay = GST_RTP_MP4G_PAY (basepayload);
 
-  rtpmp4gpay->first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+  rtpmp4gpay->first_timestamp = GST_BUFFER_PTS (buffer);
   rtpmp4gpay->first_duration = GST_BUFFER_DURATION (buffer);
+  rtpmp4gpay->discont = GST_BUFFER_IS_DISCONT (buffer);
 
   /* we always encode and flush a full AU */
   gst_adapter_push (rtpmp4gpay->adapter, buffer);
@@ -561,6 +577,33 @@ gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * basepayload,
   return gst_rtp_mp4g_pay_flush (rtpmp4gpay);
 }
 
+static gboolean
+gst_rtp_mp4g_pay_sink_event (GstRTPBasePayload * payload, GstEvent * event)
+{
+  GstRtpMP4GPay *rtpmp4gpay;
+
+  rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
+
+  GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_SEGMENT:
+    case GST_EVENT_EOS:
+      /* This flush call makes sure that the last buffer is always pushed
+       * to the base payloader */
+      gst_rtp_mp4g_pay_flush (rtpmp4gpay);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+      break;
+    default:
+      break;
+  }
+
+  /* let parent handle event too */
+  return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (payload, event);
+}
+
 static GstStateChangeReturn
 gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
 {
@@ -571,7 +614,7 @@ gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
 
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_rtp_mp4g_pay_reset (rtpmp4gpay);
+      gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
       break;
     default:
       break;
@@ -579,6 +622,14 @@ gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
 
   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_rtp_mp4g_pay_cleanup (rtpmp4gpay);
+      break;
+    default:
+      break;
+  }
+
   return ret;
 }
 
@@ -586,5 +637,5 @@ gboolean
 gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin)
 {
   return gst_element_register (plugin, "rtpmp4gpay",
-      GST_RANK_NONE, GST_TYPE_RTP_MP4G_PAY);
+      GST_RANK_SECONDARY, GST_TYPE_RTP_MP4G_PAY);
 }