Commit 4da361f9 authored by Wim Taymans's avatar Wim Taymans
Browse files

gst/rtp/: Update theora pay/depayloader in a similar to vorbis.

Original commit message from CVS:
* gst/rtp/gstrtptheoradepay.c: (decode_base64),
(gst_rtp_theora_depay_parse_configuration):
* gst/rtp/gstrtptheorapay.c: (encode_base64),
(gst_rtp_theora_pay_finish_headers),
(gst_rtp_theora_pay_handle_buffer):
Update theora pay/depayloader in a similar to vorbis.
* gst/rtp/gstrtpvorbisdepay.c:
(gst_rtp_vorbis_depay_parse_configuration):
Update docs.
parent 789ef040
2007-05-14 Wim Taymans <wim@fluendo.com>
* gst/rtp/gstrtptheoradepay.c: (decode_base64),
(gst_rtp_theora_depay_parse_configuration):
* gst/rtp/gstrtptheorapay.c: (encode_base64),
(gst_rtp_theora_pay_finish_headers),
(gst_rtp_theora_pay_handle_buffer):
Update theora pay/depayloader in a similar to vorbis.
* gst/rtp/gstrtpvorbisdepay.c:
(gst_rtp_vorbis_depay_parse_configuration):
Update docs.
2007-05-14 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_send):
......
......@@ -59,7 +59,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"THEORA\""
/* All required parameters
*
* "encoding-params = (string) <num channels>"
* "sampling = (string) { "YCbCr-4:2:0", "YCbCr-4:2:2", "YCbCr-4:4:4" } "
* "width = (string) [1, 1048561] (multiples of 16) "
* "height = (string) [1, 1048561] (multiples of 16) "
* "delivery-method = (string) { inline, in_band, out_band/<specific_name> } "
* "configuration = (string) ANY"
*/
......@@ -77,9 +79,6 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("video/x-theora")
);
/* 42 bytes for the theora identification packet length */
#define THEORA_ID_LEN 42
GST_BOILERPLATE (GstRtpTheoraDepay, gst_rtp_theora_depay, GstBaseRTPDepayload,
GST_TYPE_BASE_RTP_DEPAYLOAD);
......@@ -151,28 +150,70 @@ gst_rtp_theora_depay_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
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,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 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, 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, 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, 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, 64, 64, 64, 64, 64
};
static guint
decode_base64 (const gchar * in, guint8 * out)
{
guint8 v1, v2;
guint len = 0;
v1 = a2bin[(gint) * in];
while (v1 <= 63) {
/* read 4 bytes, write 3 bytes, invalid base64 are zeroes */
v2 = a2bin[(gint) * ++in];
*out++ = (v1 << 2) | ((v2 & 0x3f) >> 4);
v1 = (v2 > 63 ? 64 : a2bin[(gint) * ++in]);
*out++ = (v2 << 4) | ((v1 & 0x3f) >> 2);
v2 = (v1 > 63 ? 64 : a2bin[(gint) * ++in]);
*out++ = (v1 << 6) | (v2 & 0x3f);
v1 = (v2 > 63 ? 64 : a2bin[(gint) * ++in]);
len += 3;
}
/* move to '\0' */
while (*in != '\0')
in++;
/* subtract padding */
while (len > 0 && *--in == '=')
len--;
return len;
}
static gboolean
gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
const gchar * configuration)
{
GValue v = { 0 };
GstBuffer *buf;
guint32 num_headers;
guint8 *data;
guint size;
gint i;
/* deserialize base16 to buffer */
g_value_init (&v, GST_TYPE_BUFFER);
if (!gst_value_deserialize (&v, configuration))
goto wrong_configuration;
gint i, j;
buf = gst_value_get_buffer (&v);
gst_buffer_ref (buf);
g_value_unset (&v);
/* deserialize base64 to buffer */
size = strlen (configuration);
GST_DEBUG_OBJECT (rtptheoradepay, "base64 config size %u", size);
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
data = g_malloc (size);
size = decode_base64 (configuration, data);
GST_DEBUG_OBJECT (rtptheoradepay, "config size %u", size);
......@@ -201,74 +242,96 @@ gst_rtp_theora_depay_parse_configuration (GstRtpTheoraDepay * rtptheoradepay,
/* 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 | ..
* | Ident | length ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | n. of headers | length1 | length2 ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | Identification Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. length | Identification Header ..
* .. | Comment Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Identification Header |
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Comment Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Setup Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Setup Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
for (i = 0; i < num_headers; i++) {
guint32 ident;
guint16 length;
guint8 n_headers, b;
GstRtpTheoraConfig *conf;
GstTagList *list;
guint *h_sizes;
if (size < 5)
if (size < 6)
goto too_small;
ident = (data[0] << 16) | (data[1] << 8) | data[2];
length = (data[3] << 8) | data[4];
size -= 5;
data += 5;
n_headers = data[5];
size -= 6;
data += 6;
GST_DEBUG_OBJECT (rtptheoradepay, "header %d, ident %08x, length %u", i,
ident, length);
GST_DEBUG_OBJECT (rtptheoradepay,
"header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
if (size < length + THEORA_ID_LEN)
if (size < length)
goto too_small;
GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
/* read header sizes we read 2 sizes, the third size (for which we allocate
* space) must be derived from the total packed header length. */
h_sizes = g_newa (guint, n_headers + 1);
for (j = 0; j < n_headers; j++) {
guint h_size;
h_size = 0;
do {
if (size < 1)
goto too_small;
b = *data++;
size--;
h_size = (h_size << 7) | (b & 0x7f);
} while (b & 0x80);
GST_DEBUG_OBJECT (rtptheoradepay, "headers %d: size: %u", j, h_size);
h_sizes[j] = h_size;
length -= h_size;
}
/* last header length is the remaining space */
GST_DEBUG_OBJECT (rtptheoradepay, "last header size: %u", length);
h_sizes[j] = length;
GST_DEBUG_OBJECT (rtptheoradepay, "preparing headers");
conf = g_new0 (GstRtpTheoraConfig, 1);
conf->ident = ident;
buf = gst_buffer_new_and_alloc (THEORA_ID_LEN);
memcpy (GST_BUFFER_DATA (buf), data, THEORA_ID_LEN);
conf->headers = g_list_append (conf->headers, buf);
data += THEORA_ID_LEN;
size -= THEORA_ID_LEN;
/* create a dummy comment */
list = gst_tag_list_new ();
buf =
gst_tag_list_to_vorbiscomment_buffer (list, (guint8 *) "\201theora", 7,
"Theora RTP depayloader");
conf->headers = g_list_append (conf->headers, buf);
gst_tag_list_free (list);
buf = gst_buffer_new_and_alloc (length);
memcpy (GST_BUFFER_DATA (buf), data, length);
conf->headers = g_list_append (conf->headers, buf);
data += length;
size -= length;
for (j = 0; j <= n_headers; j++) {
guint h_size;
h_size = h_sizes[j];
if (size < h_size)
goto too_small;
GST_DEBUG_OBJECT (rtptheoradepay, "reading header %d, size %u", j,
h_size);
buf = gst_buffer_new_and_alloc (h_size);
memcpy (GST_BUFFER_DATA (buf), data, h_size);
conf->headers = g_list_append (conf->headers, buf);
data += h_size;
size -= h_size;
}
rtptheoradepay->configs = g_list_append (rtptheoradepay->configs, conf);
}
return TRUE;
/* ERRORS */
wrong_configuration:
{
GST_DEBUG_OBJECT (rtptheoradepay, "error parsing configuration");
return FALSE;
}
too_small:
{
GST_DEBUG_OBJECT (rtptheoradepay, "configuration too small");
......
......@@ -212,31 +212,46 @@ gst_rtp_theora_pay_flush_packet (GstRtpTheoraPay * rtptheorapay)
return ret;
}
static gchar *
encode_base64 (const guint8 * in, guint size, guint * len)
{
gchar *ret, *d;
static const gchar *v =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
*len = ((size + 2) / 3) * 4;
d = ret = (gchar *) g_malloc (*len + 1);
for (; size; in += 3) { /* process tuplets */
*d++ = v[in[0] >> 2]; /* byte 1: high 6 bits (1) */
/* byte 2: low 2 bits (1), high 4 bits (2) */
*d++ = v[((in[0] << 4) + (--size ? (in[1] >> 4) : 0)) & 0x3f];
/* byte 3: low 4 bits (2), high 2 bits (3) */
*d++ = size ? v[((in[1] << 2) + (--size ? (in[2] >> 6) : 0)) & 0x3f] : '=';
/* byte 4: low 6 bits (3) */
*d++ = size ? v[in[2] & 0x3f] : '=';
if (size)
size--; /* count third character if processed */
}
*d = '\0'; /* tie off string */
return ret; /* return the resulting string */
}
static gboolean
gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload)
{
GstRtpTheoraPay *rtptheorapay = GST_RTP_THEORA_PAY (basepayload);
GList *walk;
guint length;
gchar *configuration;
gchar *wstr, *hstr;
guint8 *data;
guint length, size, n_headers, configlen;
gchar *wstr, *hstr, *configuration;
guint8 *data, *config;
guint32 ident;
GValue v = { 0 };
GstBuffer *config;
GST_DEBUG_OBJECT (rtptheorapay, "finish headers");
if (!rtptheorapay->headers)
goto no_headers;
/* we need exactly 2 header packets */
if (g_list_length (rtptheorapay->headers) != 2) {
GST_DEBUG_OBJECT (rtptheorapay, "We need 2 headers but have %d",
g_list_length (rtptheorapay->headers));
goto no_headers;
}
/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Number of packed headers |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
......@@ -255,35 +270,60 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload)
* 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 | ..
* | Ident | length ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | n. of headers | length1 | length2 ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | Identification Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | Comment Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. length | Identification Header ..
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Identification Header |
* .. Comment Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Setup Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Setup Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
/* count the size of the headers first */
/* we need 4 bytes for the number of headers (which is always 1), 3 bytes for
* the ident, 2 bytes for length, 1 byte for n. of headers. */
size = 4 + 3 + 2 + 1;
/* count the size of the headers first and update the hash */
length = 0;
n_headers = 0;
ident = fnv1_hash_32_new ();
for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
ident =
fnv1_hash_32_update (ident, GST_BUFFER_DATA (buf),
guint bsize;
bsize = GST_BUFFER_SIZE (buf);
length += bsize;
n_headers++;
/* count number of bytes needed for length fields, we don't need this for
* the last header. */
if (g_list_next (walk)) {
do {
size++;
bsize >>= 7;
} while (bsize);
}
/* update hash */
ident = fnv1_hash_32_update (ident, GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
length += GST_BUFFER_SIZE (buf);
}
/* total config length is 4 bytes header number + size of the
* headers + 2 bytes length + 3 bytes for the ident */
config = gst_buffer_new_and_alloc (length + 4 + 2 + 3);
data = GST_BUFFER_DATA (config);
/* packet length is header size + packet length */
configlen = size + length;
config = data = g_malloc (configlen);
/* number of packed headers, we only pack 1 header */
data[0] = 0;
......@@ -293,18 +333,51 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload)
ident = fnv1_hash_32_to_24 (ident);
rtptheorapay->payload_ident = ident;
GST_DEBUG_OBJECT (rtptheorapay, "ident 0x%08x", ident);
/* take lower 3 bytes */
data[4] = (ident >> 16) & 0xff;
data[5] = (ident >> 8) & 0xff;
data[6] = ident & 0xff;
/* store length minus the length of the fixed theora header */
data[7] = ((length - THEORA_ID_LEN) >> 8) & 0xff;
data[8] = (length - THEORA_ID_LEN) & 0xff;
/* store length of all theora headers */
data[7] = ((length) >> 8) & 0xff;
data[8] = (length) & 0xff;
/* store number of headers minus one. */
data[9] = n_headers - 1;
data += 10;
/* store length for each header */
for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
guint bsize, size, temp;
/* only need to store the length when it's not the last header */
if (!g_list_next (walk))
break;
bsize = GST_BUFFER_SIZE (buf);
/* calc size */
size = 0;
do {
size++;
bsize >>= 7;
} while (bsize);
temp = size;
bsize = GST_BUFFER_SIZE (buf);
/* write the size backwards */
while (size) {
size--;
data[size] = bsize & 0x7f;
bsize >>= 7;
}
data += temp;
}
/* copy header data */
data += 9;
for (walk = rtptheorapay->headers; walk; walk = g_list_next (walk)) {
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
......@@ -312,10 +385,9 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload)
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);
/* serialize to base64 */
configuration = encode_base64 (config, configlen, &size);
g_free (config);
/* configure payloader settings */
wstr = g_strdup_printf ("%d", rtptheorapay->width);
......@@ -333,7 +405,6 @@ gst_rtp_theora_pay_finish_headers (GstBaseRTPPayload * basepayload)
g_free (wstr);
g_free (hstr);
g_free (configuration);
g_value_unset (&v);
return TRUE;
......@@ -454,12 +525,7 @@ gst_rtp_theora_pay_handle_buffer (GstBaseRTPPayload * basepayload,
if (rtptheorapay->need_headers) {
/* we need to collect the headers and construct a config string from them */
if (TDT == 2) {
GST_DEBUG_OBJECT (rtptheorapay,
"discard comment packet while collecting headers");
ret = GST_FLOW_OK;
goto done;
} else if (TDT != 0) {
if (TDT != 0) {
GST_DEBUG_OBJECT (rtptheorapay, "collecting header, buffer %p", buffer);
/* append header to the list of headers */
rtptheorapay->headers = g_list_append (rtptheorapay->headers, buffer);
......
......@@ -81,9 +81,6 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("audio/x-vorbis")
);
/* 30 bytes for the vorbis identification packet length */
#define VORBIS_ID_LEN 30
GST_BOILERPLATE (GstRtpVorbisDepay, gst_rtp_vorbis_depay, GstBaseRTPDepayload,
GST_TYPE_BASE_RTP_DEPAYLOAD);
......@@ -247,17 +244,26 @@ gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
/* 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 | ..
* | Ident | length ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | n. of headers | length1 | length2 ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. | Identification Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. length | Identification Header ..
* .. | Comment Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Identification Header |
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Comment Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Setup Header ..
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .................................................................
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* .. Setup Header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
for (i = 0; i < num_headers; i++) {
guint32 ident;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment