gst/rtp/gstrtpvorbispay.*: Generate a valid configuration string in the caps based on the vorbis headers.

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.
This commit is contained in:
Christian Schaller 2006-11-06 20:52:10 +00:00
parent d162a33c42
commit 53ddac062d
3 changed files with 166 additions and 12 deletions

View file

@ -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):

View 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;
}
@ -204,13 +206,126 @@ gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay)
return ret;
}
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;
}
}

View 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