gst/rtp/gstrtph264depay.*: Add experimental support for outputting quicktime-like...
authorWim Taymans <wim.taymans@gmail.com>
Tue, 20 May 2008 11:33:05 +0000 (11:33 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 20 May 2008 11:33:05 +0000 (11:33 +0000)
Original commit message from CVS:
* gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
(gst_rtp_h264_depay_init), (gst_rtp_h264_depay_set_property),
(gst_rtp_h264_depay_get_property), (gst_rtp_h264_depay_setcaps),
(gst_rtp_h264_depay_process):
* gst/rtp/gstrtph264depay.h:
Add experimental support for outputting quicktime-like AVC output in
addition to the existing bytestream output.
* gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type),
(gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init),
(gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_payload_nal),
(gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property),
(gst_rtp_h264_pay_get_property):
* gst/rtp/gstrtph264pay.h:
Make the parsing mode configurable, for some inputs we don't need to
scan every byte for start codes.
Only set the marker bit on ACCESS units.

ChangeLog
gst/rtp/gstrtph264depay.c
gst/rtp/gstrtph264depay.h
gst/rtp/gstrtph264pay.c
gst/rtp/gstrtph264pay.h

index 930511d..ff8d36c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2008-05-20  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * gst/rtp/gstrtph264depay.c: (gst_rtp_h264_depay_class_init),
+       (gst_rtp_h264_depay_init), (gst_rtp_h264_depay_set_property),
+       (gst_rtp_h264_depay_get_property), (gst_rtp_h264_depay_setcaps),
+       (gst_rtp_h264_depay_process):
+       * gst/rtp/gstrtph264depay.h:
+       Add experimental support for outputting quicktime-like AVC output in
+       addition to the existing bytestream output.
+
+       * gst/rtp/gstrtph264pay.c: (gst_h264_scan_mode_get_type),
+       (gst_rtp_h264_pay_class_init), (gst_rtp_h264_pay_init),
+       (gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_payload_nal),
+       (gst_rtp_h264_pay_handle_buffer), (gst_rtp_h264_pay_set_property),
+       (gst_rtp_h264_pay_get_property):
+       * gst/rtp/gstrtph264pay.h:
+       Make the parsing mode configurable, for some inputs we don't need to
+       scan every byte for start codes.
+       Only set the marker bit on ACCESS units.
+
 2008-05-20  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * gst/equalizer/gstiirequalizer.c:
index 9b798a3..dc4ed83 100644 (file)
 GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
 #define GST_CAT_DEFAULT (rtph264depay_debug)
 
+#define DEFAULT_BYTE_STREAM    TRUE
+
+enum
+{
+  PROP_0,
+  PROP_BYTE_STREAM,
+  PROP_LAST
+};
+
+
 /* 3 zero bytes syncword */
 static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
 
@@ -77,6 +87,10 @@ GST_BOILERPLATE (GstRtpH264Depay, gst_rtp_h264_depay, GstBaseRTPDepayload,
     GST_TYPE_BASE_RTP_DEPAYLOAD);
 
 static void gst_rtp_h264_depay_finalize (GObject * object);
+static void gst_rtp_h264_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h264_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
 
 static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement *
     element, GstStateChange transition);
@@ -112,6 +126,14 @@ gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
 
   gobject_class->finalize = gst_rtp_h264_depay_finalize;
 
+  gobject_class->set_property = gst_rtp_h264_depay_set_property;
+  gobject_class->get_property = gst_rtp_h264_depay_get_property;
+
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BYTE_STREAM,
+      g_param_spec_boolean ("byte-stream", "Byte Stream",
+          "Generate byte stream format of NALU", DEFAULT_BYTE_STREAM,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gstelement_class->change_state = gst_rtp_h264_depay_change_state;
 
   gstbasertpdepayload_class->process = gst_rtp_h264_depay_process;
@@ -126,6 +148,7 @@ gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay,
     GstRtpH264DepayClass * klass)
 {
   rtph264depay->adapter = gst_adapter_new ();
+  rtph264depay->byte_stream = DEFAULT_BYTE_STREAM;
 }
 
 static void
@@ -143,6 +166,42 @@ gst_rtp_h264_depay_finalize (GObject * object)
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+static void
+gst_rtp_h264_depay_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRtpH264Depay *rtph264depay;
+
+  rtph264depay = GST_RTP_H264_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_BYTE_STREAM:
+      rtph264depay->byte_stream = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rtp_h264_depay_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstRtpH264Depay *rtph264depay;
+
+  rtph264depay = GST_RTP_H264_DEPAY (object);
+
+  switch (prop_id) {
+    case PROP_BYTE_STREAM:
+      g_value_set_boolean (value, rtph264depay->byte_stream);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
 static const guint8 a2bin[256] = {
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
@@ -198,6 +257,9 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
   gint clock_rate = 90000;
   GstStructure *structure = gst_caps_get_structure (caps, 0);
   GstRtpH264Depay *rtph264depay;
+  const gchar *ps, *profile;
+  GstBuffer *codec_data;
+  guint8 *b64;
 
   rtph264depay = GST_RTP_H264_DEPAY (depayload);
 
@@ -206,16 +268,18 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
 
   srccaps = gst_caps_new_simple ("video/x-h264", NULL);
 
-  if (gst_structure_has_field (structure, "sprop-parameter-sets")) {
-    const gchar *ps;
+  /* Base64 encoded, comma separated config NALs */
+  ps = gst_structure_get_string (structure, "sprop-parameter-sets");
+  /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */
+  profile = gst_structure_get_string (structure, "profile-level-id");
+
+  if (rtph264depay->byte_stream && ps != NULL) {
+    /* for bytestream we only need the parameter sets but we don't error out
+     * when they are not there, we assume they are in the stream. */
     gchar **params;
     guint len, total;
     gint i;
-    GstBuffer *codec_data;
-    guint8 *b64;
 
-    /* Base64 encoded, comma separated config NALs */
-    ps = gst_structure_get_string (structure, "sprop-parameter-sets");
     params = g_strsplit (ps, ",", 0);
 
     /* count total number of bytes in base64. Also include the sync bytes in
@@ -246,14 +310,106 @@ gst_rtp_h264_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
     if (rtph264depay->codec_data)
       gst_buffer_unref (rtph264depay->codec_data);
     rtph264depay->codec_data = codec_data;
+  } else if (!rtph264depay->byte_stream) {
+    gchar **params;
+    guint8 **sps, **pps;
+    guint len, num_sps, num_pps;
+    gint i;
+    guint8 *data;
+    guint32 profile_id;
+
+    if (ps == NULL || profile == NULL)
+      goto incomplete_caps;
+
+    params = g_strsplit (ps, ",", 0);
+    len = g_strv_length (params);
+
+    GST_DEBUG_OBJECT (depayload, "we have %d params", len);
+
+    sps = g_new0 (guint8 *, len + 1);
+    pps = g_new0 (guint8 *, len + 1);
+    num_sps = num_pps = 0;
+
+    /* start with 7 bytes header */
+    len = 7;
+    for (i = 0; params[i]; i++) {
+      gint nal_len;
+      guint8 *nalp;
+
+      nal_len = strlen (params[i]);
+      nalp = g_malloc (nal_len + 2);
+      nal_len = decode_base64 (params[i], nalp + 2);
+      nalp[0] = (nal_len >> 8) & 0xff;
+      nalp[1] = nal_len & 0xff;
+      len += nal_len + 2;
+
+      /* copy to the right list */
+      if ((nalp[2] & 0x1f) == 7) {
+        GST_DEBUG_OBJECT (depayload, "adding param %d as SPS %d", i, num_sps);
+        sps[num_sps++] = nalp;
+      } else {
+        GST_DEBUG_OBJECT (depayload, "adding param %d as PPS %d", i, num_pps);
+        pps[num_pps++] = nalp;
+      }
+    }
+    g_strfreev (params);
+
+    codec_data = gst_buffer_new_and_alloc (len);
+    data = GST_BUFFER_DATA (codec_data);
+
+    /* 8 bits version == 1 */
+    *data++ = 1;
+    /* hex: AVCProfileIndication:8 | profile_compat:8 | AVCLevelIndication:8 */
+    sscanf (profile, "%6x", &profile_id);
+    *data++ = (profile_id >> 16) & 0xff;
+    *data++ = (profile_id >> 8) & 0xff;
+    *data++ = profile_id & 0xff;
+    /* 6 bits reserved | 2 bits lengthSizeMinusOn */
+    *data++ = 0xff;
+    /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
+    *data++ = 0xe0 | (num_sps & 0x1f);
+
+    /* copy all SPS */
+    for (i = 0; sps[i]; i++) {
+      len = ((sps[i][0] << 8) | sps[i][1]) + 2;
+      GST_DEBUG_OBJECT (depayload, "copy SPS %d of length %d", i, len);
+      memcpy (data, sps[i], len);
+      g_free (sps[i]);
+      data += len;
+    }
+    g_free (sps);
+    /* 8 bits numOfPictureParameterSets */
+    *data++ = num_pps;
+    /* copy all PPS */
+    for (i = 0; pps[i]; i++) {
+      len = ((pps[i][0] << 8) | pps[i][1]) + 2;
+      GST_DEBUG_OBJECT (depayload, "copy PPS %d of length %d", i, len);
+      memcpy (data, pps[i], len);
+      g_free (pps[i]);
+      data += len;
+    }
+    g_free (pps);
+    GST_BUFFER_SIZE (codec_data) = data - GST_BUFFER_DATA (codec_data);
+
+    gst_caps_set_simple (srccaps,
+        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
   }
 
   gst_pad_set_caps (depayload->srcpad, srccaps);
   gst_caps_unref (srccaps);
 
   return TRUE;
+
+  /* ERRORS */
+incomplete_caps:
+  {
+    GST_DEBUG_OBJECT (depayload, "we have incomplete caps");
+    return FALSE;
+  }
 }
 
+/* FIXME, non-bytestream handling is freaking out ffmpeg. Apparently we need to
+ * group all NAL units belonging to one frame together */
 static GstBuffer *
 gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 {
@@ -337,17 +493,24 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
            */
           nalu_size = (payload[0] << 8) | payload[1];
 
-          /* strip NALU size */
-          payload += 2;
-          payload_len -= 2;
-
           if (nalu_size > payload_len)
             nalu_size = payload_len;
 
           outsize = nalu_size + sizeof (sync_bytes);
           outbuf = gst_buffer_new_and_alloc (outsize);
           outdata = GST_BUFFER_DATA (outbuf);
-          memcpy (outdata, sync_bytes, sizeof (sync_bytes));
+          if (rtph264depay->byte_stream) {
+            memcpy (outdata, sync_bytes, sizeof (sync_bytes));
+          } else {
+            outdata[0] = outdata[1] = 0;
+            outdata[2] = payload[0];
+            outdata[3] = payload[1];
+          }
+
+          /* strip NALU size */
+          payload += 2;
+          payload_len -= 2;
+
           outdata += sizeof (sync_bytes);
           memcpy (outdata, payload, nalu_size);
 
@@ -414,7 +577,6 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
           outsize = nalu_size + sizeof (sync_bytes);
           outbuf = gst_buffer_new_and_alloc (outsize);
           outdata = GST_BUFFER_DATA (outbuf);
-          memcpy (outdata, sync_bytes, sizeof (sync_bytes));
           outdata += sizeof (sync_bytes);
           memcpy (outdata, payload, nalu_size);
           outdata[0] = nal_header;
@@ -445,7 +607,17 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
           outsize = gst_adapter_available (rtph264depay->adapter);
           outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
+          outdata = GST_BUFFER_DATA (outbuf);
 
+          if (rtph264depay->byte_stream) {
+            memcpy (outdata, sync_bytes, sizeof (sync_bytes));
+          } else {
+            outsize -= 4;
+            outdata[0] = (outsize >> 24);
+            outdata[1] = (outsize >> 16);
+            outdata[2] = (outsize >> 8);
+            outdata[3] = (outsize);
+          }
           gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad));
 
           /* push codec_data first */
@@ -469,7 +641,13 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
         outsize = nalu_size + sizeof (sync_bytes);
         outbuf = gst_buffer_new_and_alloc (outsize);
         outdata = GST_BUFFER_DATA (outbuf);
-        memcpy (outdata, sync_bytes, sizeof (sync_bytes));
+        if (rtph264depay->byte_stream) {
+          memcpy (outdata, sync_bytes, sizeof (sync_bytes));
+        } else {
+          outdata[0] = outdata[1] = 0;
+          outdata[2] = nalu_size >> 8;
+          outdata[3] = nalu_size & 0xff;
+        }
         outdata += sizeof (sync_bytes);
         memcpy (outdata, payload, nalu_size);
 
index 41c4fc0..d701ecf 100644 (file)
@@ -44,9 +44,12 @@ struct _GstRtpH264Depay
 {
   GstBaseRTPDepayload depayload;
 
+  gboolean    byte_stream;
+
   GstBuffer  *codec_data;
   GstAdapter *adapter;
   gboolean    wait_start;
+
 };
 
 struct _GstRtpH264DepayClass
index f638b17..4c014b9 100644 (file)
@@ -64,16 +64,46 @@ GST_STATIC_PAD_TEMPLATE ("src",
         "clock-rate = (int) 90000, " "encoding-name = (string) \"H264\"")
     );
 
+#define GST_TYPE_H264_SCAN_MODE (gst_h264_scan_mode_get_type())
+static GType
+gst_h264_scan_mode_get_type (void)
+{
+  static GType h264_scan_mode_type = 0;
+  static const GEnumValue h264_scan_modes[] = {
+    {GST_H264_SCAN_MODE_BYTESTREAM,
+          "Scan complete bytestream for NALUs (not implemented)",
+        "bytestream"},
+    {GST_H264_SCAN_MODE_MULTI_NAL, "Buffers contain multiple complete NALUs",
+        "multiple"},
+    {GST_H264_SCAN_MODE_SINLE_NAL, "Buffers contain a single complete NALU",
+        "single"},
+    {0, NULL, NULL},
+  };
+
+  if (!h264_scan_mode_type) {
+    h264_scan_mode_type =
+        g_enum_register_static ("GstH264PayScanMode", h264_scan_modes);
+  }
+  return h264_scan_mode_type;
+}
+
 #define DEFAULT_PROFILE_LEVEL_ID        NULL
 #define DEFAULT_SPROP_PARAMETER_SETS    NULL
+#define DEFAULT_SPROP_PARAMETER_SETS    NULL
+#define DEFAULT_SCAN_MODE               GST_H264_SCAN_MODE_MULTI_NAL
 
 enum
 {
-  ARG_0,
-  ARG_PROFILE_LEVEL_ID,
-  ARG_SPROP_PARAMETER_SETS
+  PROP_0,
+  PROP_PROFILE_LEVEL_ID,
+  PROP_SPROP_PARAMETER_SETS,
+  PROP_SCAN_MODE,
+  PROP_LAST
 };
 
+
+#define IS_ACCESS_UNIT(x) (((x) > 0x00) && ((x) < 0x06))
+
 static void gst_rtp_h264_pay_finalize (GObject * object);
 
 static GstStateChangeReturn gst_rtp_h264_pay_change_state (GstElement * element,
@@ -119,19 +149,29 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
   gobject_class->set_property = gst_rtp_h264_pay_set_property;
   gobject_class->get_property = gst_rtp_h264_pay_get_property;
 
-  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PROFILE_LEVEL_ID,
-      g_param_spec_string ("profile-level-id", "profile-level-id",
-          "The base64 profile-level-id to set in out caps (set to NULL to extract from stream)",
+  g_object_class_install_property (G_OBJECT_CLASS (klass),
+      PROP_PROFILE_LEVEL_ID, g_param_spec_string ("profile-level-id",
+          "profile-level-id",
+          "The base64 profile-level-id to set in out caps (set to NULL to "
+          "extract from stream)",
           DEFAULT_PROFILE_LEVEL_ID,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   g_object_class_install_property (G_OBJECT_CLASS (klass),
-      ARG_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
+      PROP_SPROP_PARAMETER_SETS, g_param_spec_string ("sprop-parameter-sets",
           "sprop-parameter-sets",
-          "The base64 sprop-parameter-sets to set in out caps (set to NULL to extract from stream)",
+          "The base64 sprop-parameter-sets to set in out caps (set to NULL to "
+          "extract from stream)",
           DEFAULT_SPROP_PARAMETER_SETS,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SCAN_MODE,
+      g_param_spec_enum ("scan-mode", "Scan Mode",
+          "How to scan the input buffers for NAL units. Performance can be "
+          "increased when certain assumptions are made about the input buffers",
+          GST_TYPE_H264_SCAN_MODE, DEFAULT_SCAN_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gobject_class->finalize = gst_rtp_h264_pay_finalize;
 
   gstelement_class->change_state = gst_rtp_h264_pay_change_state;
@@ -149,6 +189,7 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay, GstRtpH264PayClass * klass)
   rtph264pay->profile = 0;
   rtph264pay->sps = NULL;
   rtph264pay->pps = NULL;
+  rtph264pay->scan_mode = GST_H264_SCAN_MODE_MULTI_NAL;
 }
 
 static void
@@ -239,6 +280,8 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
     GST_DEBUG_OBJECT (rtph264pay, "profile %06x", profile);
 
     /* 6 bits reserved | 2 bits lengthSizeMinusOne */
+    /* this is the number of bytes in front of the NAL units to mark their
+     * length */
     rtph264pay->nal_length_size = (data[4] & 0x03) + 1;
     GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size);
     /* 3 bits reserved | 5 bits numOfSequenceParameterSets */
@@ -277,6 +320,7 @@ gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
     if (size < 1)
       goto avcc_error;
 
+    /* 8 bits numOfPictureParameterSets */
     num_pps = data[0];
     data += 1;
     size -= 1;
@@ -579,7 +623,10 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload, guint8 * data,
     outbuf = gst_rtp_buffer_new_allocate (size, 0, 0);
 
     GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
-    gst_rtp_buffer_set_marker (outbuf, 1);
+    /* only set the marker bit on packets containing access units */
+    if (IS_ACCESS_UNIT (nalType)) {
+      gst_rtp_buffer_set_marker (outbuf, 1);
+    }
 
     payload = gst_rtp_buffer_get_payload (outbuf);
     GST_DEBUG_OBJECT (basepayload, "Copying %d bytes to outbuf", size);
@@ -621,7 +668,9 @@ gst_rtp_h264_pay_payload_nal (GstBaseRTPPayload * basepayload, guint8 * data,
         GST_DEBUG_OBJECT (basepayload, "end size=%d iteration=%d", size, ii);
         end = 1;
       }
-      gst_rtp_buffer_set_marker (outbuf, end);
+      if (IS_ACCESS_UNIT (nalType)) {
+        gst_rtp_buffer_set_marker (outbuf, end);
+      }
 
       /* FU indicator */
       payload[0] = (nalHeader & 0x60) | 28;
@@ -723,14 +772,20 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
       data += 4;
       size -= 4;
 
-      /* use next_start_code() to scan buffer.
-       * 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. 
-       * data is unchanged by the call to next_start_code()
-       */
-      next = next_start_code (data, size);
+      if (rtph264pay->scan_mode == GST_H264_SCAN_MODE_SINLE_NAL) {
+        /* we are told that there is only a single NAL in this packet so that we
+         * can avoid scanning for the next NAL. */
+        next = size;
+      } else {
+        /* use next_start_code() to scan buffer.
+         * 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. 
+         * data is unchanged by the call to next_start_code()
+         */
+        next = next_start_code (data, size);
+      }
 
       /* nal length is distance to next start code */
       nal_len = next;
@@ -804,15 +859,21 @@ gst_rtp_h264_pay_set_property (GObject * object, guint prop_id,
   rtph264pay = GST_RTP_H264_PAY (object);
 
   switch (prop_id) {
-    case ARG_PROFILE_LEVEL_ID:
+    case PROP_PROFILE_LEVEL_ID:
+      g_free (rtph264pay->profile_level_id);
       rtph264pay->profile_level_id = g_value_dup_string (value);
       rtph264pay->update_caps = TRUE;
       break;
-    case ARG_SPROP_PARAMETER_SETS:
+    case PROP_SPROP_PARAMETER_SETS:
+      g_free (rtph264pay->sprop_parameter_sets);
       rtph264pay->sprop_parameter_sets = g_value_dup_string (value);
       rtph264pay->update_caps = TRUE;
       break;
+    case PROP_SCAN_MODE:
+      rtph264pay->scan_mode = g_value_get_enum (value);
+      break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
@@ -826,13 +887,17 @@ gst_rtp_h264_pay_get_property (GObject * object, guint prop_id,
   rtph264pay = GST_RTP_H264_PAY (object);
 
   switch (prop_id) {
-    case ARG_PROFILE_LEVEL_ID:
+    case PROP_PROFILE_LEVEL_ID:
       g_value_set_string (value, rtph264pay->profile_level_id);
       break;
-    case ARG_SPROP_PARAMETER_SETS:
+    case PROP_SPROP_PARAMETER_SETS:
       g_value_set_string (value, rtph264pay->sprop_parameter_sets);
       break;
+    case PROP_SCAN_MODE:
+      g_value_set_enum (value, rtph264pay->scan_mode);
+      break;
     default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
index b0ac096..f48fb98 100644 (file)
@@ -36,6 +36,13 @@ G_BEGIN_DECLS
 #define GST_IS_RTP_H264_PAY_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_H264_PAY))
 
+typedef enum
+{
+  GST_H264_SCAN_MODE_BYTESTREAM,
+  GST_H264_SCAN_MODE_MULTI_NAL,
+  GST_H264_SCAN_MODE_SINLE_NAL
+} GstH264ScanMode;
+
 typedef struct _GstRtpH264Pay GstRtpH264Pay;
 typedef struct _GstRtpH264PayClass GstRtpH264PayClass;
 
@@ -53,6 +60,7 @@ struct _GstRtpH264Pay
   gchar *profile_level_id;
   gchar *sprop_parameter_sets;
   gboolean update_caps;
+  GstH264ScanMode scan_mode;
 };
 
 struct _GstRtpH264PayClass