gst/rtp/gstrtpvorbispay.*: Generate a valid configuration string in the caps based...
authorChristian Schaller <uraeus@gnome.org>
Mon, 6 Nov 2006 20:52:10 +0000 (20:52 +0000)
committerChristian Schaller <uraeus@gnome.org>
Mon, 6 Nov 2006 20:52:10 +0000 (20:52 +0000)
Original commit message from CVS:
* gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_setcaps),
(gst_rtp_vorbis_pay_finish_headers), (gst_rtp_vorbis_pay_parse_id),
(gst_rtp_vorbis_pay_handle_buffer):
* gst/rtp/gstrtpvorbispay.h:
Generate a valid configuration string in the caps based on the
vorbis headers.

ChangeLog
gst/rtp/gstrtpvorbispay.c
gst/rtp/gstrtpvorbispay.h

index 4153b98..f22954d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2006-11-06  Wim Taymans  <wim@fluendo.com>
+
+       * gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_setcaps),
+       (gst_rtp_vorbis_pay_finish_headers), (gst_rtp_vorbis_pay_parse_id),
+       (gst_rtp_vorbis_pay_handle_buffer):
+       * gst/rtp/gstrtpvorbispay.h:
+        Generate a valid configuration string in the caps based on the
+        vorbis headers.
+
 2006-11-02  Tim-Philipp Müller  <tim at centricular dot net>
 
        * ext/cdio/gstcdio.c: (gst_cdio_get_cdtext):
index be70671..5870541 100644 (file)
@@ -123,6 +123,8 @@ gst_rtp_vorbis_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
 
   rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
 
+  rtpvorbispay->need_headers = TRUE;
+
   return TRUE;
 }
 
@@ -205,12 +207,125 @@ gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay)
 }
 
 static gboolean
+gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
+{
+  GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
+  GList *walk;
+  guint length;
+  gchar *cstr, *configuration;
+  guint8 *data;
+  guint32 ident;
+  GValue v = { 0 };
+  GstBuffer *config;
+
+  GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+
+  if (!rtpvorbispay->headers)
+    goto no_headers;
+
+  /* we need exactly 2 header packets */
+  if (g_list_length (rtpvorbispay->headers) != 2)
+    goto no_headers;
+
+  /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                     Number of packed headers                  |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Packed header                        |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          ....                                 |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   * We only construct a config containing 1 packed header like this:
+   *
+   *  0                   1                   2                   3
+   *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                   Ident                       |              ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..   length     |              Identification Header           ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                    Identification Header                     |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * |                          Setup Header                        ..
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   * ..                         Setup Header                         |
+   * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   *
+   */
+
+  /* count the size of the headers first */
+  length = 0;
+  for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+    length += GST_BUFFER_SIZE (buf);
+  }
+
+  /* total config length is the size of the headers + 2 bytes length +
+   * 3 bytes for the ident */
+  config = gst_buffer_new_and_alloc (length + 2 + 3);
+  data = GST_BUFFER_DATA (config);
+
+  /* we generate a random ident for this configuration */
+  ident = g_random_int ();
+
+  /* take lower 3 bytes */
+  data[0] = ident & 0xff;
+  data[1] = (ident >> 8) & 0xff;
+  data[2] = (ident >> 16) & 0xff;
+
+  data[3] = (length >> 8) & 0xff;
+  data[4] = length & 0xff;
+
+  /* copy header data */
+  data += 5;
+  for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
+    GstBuffer *buf = GST_BUFFER_CAST (walk->data);
+
+    memcpy (data, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
+    data += GST_BUFFER_SIZE (buf);
+  }
+
+  /* serialize buffer to base16 */
+  g_value_init (&v, GST_TYPE_BUFFER);
+  gst_value_take_buffer (&v, config);
+  configuration = gst_value_serialize (&v);
+
+  /* configure payloader settings */
+  cstr = g_strdup_printf ("%d", rtpvorbispay->channels);
+  gst_basertppayload_set_options (basepayload, "audio", TRUE, "vorbis",
+      rtpvorbispay->rate);
+  gst_basertppayload_set_outcaps (basepayload, "encoding-params", G_TYPE_STRING,
+      cstr, "configuration", G_TYPE_STRING, configuration,
+      /* don't set the defaults 
+       */
+      NULL);
+  g_free (cstr);
+  g_free (configuration);
+  g_value_unset (&v);
+
+  return TRUE;
+
+  /* ERRORS */
+no_headers:
+  {
+    GST_DEBUG_OBJECT (rtpvorbispay, "finish headers");
+    return FALSE;
+  }
+}
+
+static gboolean
 gst_rtp_vorbis_pay_parse_id (GstBaseRTPPayload * basepayload, guint8 * data,
     guint size)
 {
+  GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
   guint8 channels;
   gint32 rate, version;
-  gchar *cstr;
 
   if (G_UNLIKELY (size < 16))
     goto too_short;
@@ -229,14 +344,9 @@ gst_rtp_vorbis_pay_parse_id (GstBaseRTPPayload * basepayload, guint8 * data,
   if (G_UNLIKELY ((rate = GST_READ_UINT32_LE (data)) < 1))
     goto invalid_rate;
 
-  cstr = g_strdup_printf ("%d", channels);
-  gst_basertppayload_set_options (basepayload, "audio", TRUE, "vorbis", rate);
-  gst_basertppayload_set_outcaps (basepayload,
-      "encoding-params", G_TYPE_STRING, cstr,
-      /* don't set the defaults 
-       */
-      NULL);
-  g_free (cstr);
+  /* all fine, store the values */
+  rtpvorbispay->channels = channels;
+  rtpvorbispay->rate = rate;
 
   return TRUE;
 
@@ -313,14 +423,35 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
     } else if (data[0] == 5)
       /* setup */
       VDT = 1;
-    else if (data[0] == 3)
+    else if (data[0] == 3) {
+      /* comment */
       VDT = 2;
-    else
+    else
       goto unknown_header;
   } else
     /* data */
     VDT = 0;
 
+  if (rtpvorbispay->need_headers) {
+    /* we need to collect the headers and construct a config string from them */
+    if (VDT == 2) {
+      GST_DEBUG_OBJECT (rtpvorbispay,
+          "discard comment packet while collecting headers");
+      ret = GST_FLOW_OK;
+      goto done;
+    } else if (VDT != 0) {
+      GST_DEBUG_OBJECT (rtpvorbispay, "collecting header");
+      /* append header to the list of headers */
+      rtpvorbispay->headers = g_list_append (rtpvorbispay->headers, buffer);
+      ret = GST_FLOW_OK;
+      goto done;
+    } else {
+      if (!gst_rtp_vorbis_pay_finish_headers (basepayload))
+        goto header_error;
+      rtpvorbispay->need_headers = FALSE;
+    }
+  }
+
   /* size increases with packet length and 2 bytes size eader. */
   newduration = rtpvorbispay->payload_duration;
   if (duration != GST_CLOCK_TIME_NONE)
@@ -402,6 +533,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
         rtpvorbispay->payload_duration += duration;
     }
   }
+done:
   return ret;
 
   /* ERRORS */
@@ -418,7 +550,13 @@ parse_id_failed:
 unknown_header:
   {
     GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
-        ("Ignoring unknown header received"), (NULL));
+        (NULL), ("Ignoring unknown header received"));
+    return GST_FLOW_OK;
+  }
+header_error:
+  {
+    GST_ELEMENT_WARNING (rtpvorbispay, STREAM, DECODE,
+        (NULL), ("Error initializing header config"));
     return GST_FLOW_OK;
   }
 }
index 8899fb5..52ba0c1 100644 (file)
@@ -44,6 +44,10 @@ struct _GstRtpVorbisPay
 {
   GstBaseRTPPayload payload;
 
+  /* the headers */
+  gboolean      need_headers;
+  GList        *headers;
+
   /* queues of buffers along with some stats. */
   GstBuffer    *packet;
   guint         payload_pos;
@@ -53,6 +57,9 @@ struct _GstRtpVorbisPay
   guint8        payload_VDT;
   guint         payload_pkts;
   GstClockTime  payload_duration;
+
+  gint          rate;
+  gint          channels;
 };
 
 struct _GstRtpVorbisPayClass