rtph264pay: Only set the marker bit on the last NALU of a multi-NALU access unit
authorOlivier CrĂȘte <olivier.crete@collabora.com>
Tue, 19 Jul 2011 00:27:38 +0000 (20:27 -0400)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Thu, 21 Jul 2011 15:11:06 +0000 (17:11 +0200)
An access unit could contain multiple NAL units, in that case, only the last
RTP packet of the last NALU should have its marker bit set.

https://bugzilla.gnome.org/show_bug.cgi?id=654850

gst/rtp/gstrtph264pay.c
gst/rtp/gstrtph264pay.h

index 5f574a4..738e938 100644 (file)
@@ -420,6 +420,7 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
   const GValue *value;
   guint8 *data;
   guint size;
+  const gchar *alignment;
 
   rtph264pay = GST_RTP_H264_PAY (basepayload);
 
@@ -429,6 +430,12 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
    * NALs */
   gst_basertppayload_set_options (basepayload, "video", TRUE, "H264", 90000);
 
+  alignment = gst_structure_get_string (str, "alignment");
+  if (alignment && !strcmp (alignment, "au"))
+    rtph264pay->au_alignment = TRUE;
+  else
+    rtph264pay->au_alignment = FALSE;
+
   /* packetized AVC video has a codec_data */
   if ((value = gst_structure_get_value (str, "codec_data"))) {
     GstBuffer *buffer;
@@ -763,7 +770,7 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
 static GstFlowReturn
 gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
     const guint8 * data, guint size, GstClockTime timestamp,
-    GstBuffer * buffer_orig);
+    GstBuffer * buffer_orig, gboolean end_of_au);
 
 static GstFlowReturn
 gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
@@ -779,7 +786,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
     /* resend SPS */
     ret = gst_rtp_h264_pay_payload_nal (basepayload,
         GST_BUFFER_DATA (sps_buf), GST_BUFFER_SIZE (sps_buf), timestamp,
-        sps_buf);
+        sps_buf, FALSE);
     /* Not critical here; but throw a warning */
     if (ret != GST_FLOW_OK)
       GST_WARNING ("Problem pushing SPS");
@@ -791,7 +798,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
     /* resend PPS */
     ret = gst_rtp_h264_pay_payload_nal (basepayload,
         GST_BUFFER_DATA (pps_buf), GST_BUFFER_SIZE (pps_buf), timestamp,
-        pps_buf);
+        pps_buf, FALSE);
     /* Not critical here; but throw a warning */
     if (ret != GST_FLOW_OK)
       GST_WARNING ("Problem pushing PPS");
@@ -806,7 +813,7 @@ gst_rtp_h264_pay_send_sps_pps (GstBaseRTPPayload * basepayload,
 static GstFlowReturn
 gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
     const guint8 * data, guint size, GstClockTime timestamp,
-    GstBuffer * buffer_orig)
+    GstBuffer * buffer_orig, gboolean end_of_au)
 {
   GstRtpH264Pay *rtph264pay;
   GstFlowReturn ret;
@@ -885,7 +892,7 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
     }
 
     /* only set the marker bit on packets containing access units */
-    if (IS_ACCESS_UNIT (nalType)) {
+    if (IS_ACCESS_UNIT (nalType) && end_of_au) {
       gst_rtp_buffer_set_marker (outbuf, 1);
     }
 
@@ -975,7 +982,7 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload,
         end = 1;
       }
       if (IS_ACCESS_UNIT (nalType)) {
-        gst_rtp_buffer_set_marker (outbuf, end);
+        gst_rtp_buffer_set_marker (outbuf, end && end_of_au);
       }
 
       /* FU indicator */
@@ -1075,6 +1082,7 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
 
     while (size > nal_length_size) {
       gint i;
+      gboolean end_of_au = FALSE;
 
       nal_len = 0;
       for (i = 0; i < nal_length_size; i++) {
@@ -1093,9 +1101,16 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
             nal_len);
       }
 
+      /* If we're at the end of the buffer, then we're at the end of the
+       * access unit
+       */
+      if (rtph264pay->au_alignment && size - nal_len <= nal_length_size) {
+        end_of_au = TRUE;
+      }
+
       ret =
           gst_rtp_h264_pay_payload_nal (basepayload, data, nal_len, timestamp,
-          buffer);
+          buffer, end_of_au);
       if (ret != GST_FLOW_OK)
         break;
 
@@ -1197,6 +1212,7 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
 
     for (i = 0; i < nal_queue->len; i++) {
       guint size;
+      gboolean end_of_au = FALSE;
 
       nal_len = g_array_index (nal_queue, guint, i);
       /* skip start code */
@@ -1212,10 +1228,22 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
         for (; size > 1 && data[size - 1] == 0x0; size--)
           /* skip */ ;
 
+      /* If it's the last nal unit we have in non-bytestream mode, we can
+       * assume it's the end of an access-unit
+       *
+       * FIXME: We need to wait until the next packet or EOS to
+       * actually payload the NAL so we can know if the current NAL is
+       * the last one of an access unit or not if we are in bytestream mode
+       */
+      if (rtph264pay->au_alignment &&
+          rtph264pay->scan_mode != GST_H264_SCAN_MODE_BYTESTREAM &&
+          i == nal_queue->len - 1)
+        end_of_au = TRUE;
+
       /* put the data in one or more RTP packets */
       ret =
           gst_rtp_h264_pay_payload_nal (basepayload, data, size, timestamp,
-          buffer);
+          buffer, end_of_au);
       if (ret != GST_FLOW_OK) {
         break;
       }
index 19e5aaa..6303e30 100644 (file)
@@ -55,6 +55,7 @@ struct _GstRtpH264Pay
   GList *sps, *pps;
 
   gboolean packetized;
+  gboolean au_alignment;
   guint nal_length_size;
   GArray *queue;