Commit 5bc71b66 authored by Wim Taymans's avatar Wim Taymans
Browse files

gst/rtp/README: Update README with new RTP variables that will be used for synchronisation.

Original commit message from CVS:
* gst/rtp/README:
Update README with new RTP variables that will be used for
synchronisation.
* gst/rtp/gstrtpvorbisdepay.c: (decode_base64),
(gst_rtp_vorbis_depay_parse_configuration),
(gst_rtp_vorbis_depay_process):
* gst/rtp/gstrtpvorbispay.c: (encode_base64),
(gst_rtp_vorbis_pay_finish_headers),
(gst_rtp_vorbis_pay_handle_buffer):
Update vorbis pay and depayloader to draft-04.
parent 3e1fd612
2007-05-11 Wim Taymans <wim@fluendo.com>
* gst/rtp/README:
Update README with new RTP variables that will be used for
synchronisation.
* gst/rtp/gstrtpvorbisdepay.c: (decode_base64),
(gst_rtp_vorbis_depay_parse_configuration),
(gst_rtp_vorbis_depay_process):
* gst/rtp/gstrtpvorbispay.c: (encode_base64),
(gst_rtp_vorbis_pay_finish_headers),
(gst_rtp_vorbis_pay_handle_buffer):
Update vorbis pay and depayloader to draft-04.
2007-05-11 Wim Taymans <wim@fluendo.com>
* gst/rtsp/rtsptransport.c:
......
common @ b5971d76
Subproject commit 1b4fb5836a9e290fe13895643d41e0166de8a94c
Subproject commit b5971d76ccd216c27e095c02c3a369a9d05cb36d
......@@ -22,16 +22,41 @@ The following fields can or must (*) be specified in the structure:
set.
* clock-rate: (int) [0 - MAXINT]
the RTP clock rate
The RTP clock rate.
ssrc: (uint) [0 - MAXINT]
The ssrc value currently in use.
The ssrc value currently in use. (default = the SSRC of the first RTP
packet)
npt-start: (uint64) [0 - MAXINT]
The Normal Play Time for clock-base. This is the position in the stream and
is between 0 and the duration of the stream. This value is expressed in
nanoseconds GstClockTime. (default = 0)
npt-stop: (uint64) [0 - MAXINT]
The last position in the stream. This value is expressed in nanoseconds
GstClockTime. (default = -1, stop unknown)
clock-base: (uint) [0 - MAXINT]
The RTP time representing time 0
The RTP time representing time npt-start. (default = rtptime of first RTP
packet).
play-speed: (gdouble) [-MIN - MAX]
The intended playback speed of the stream. The client is delivered data at
the adjusted speed. The client should adjust its playback speed with this
value and thus corresponds to the GStreamer rate field in the NEWSEGMENT
event. (default = 1.0)
play-scale: (gdouble) [-MIN - MAX]
The rate already applied to the stream. The client is delivered a stream
that is scaled by this amount. This value is used to adjust position
reporting and corresponds to the GStream applied-rate field in the
NEWSEGMENT event. (default = 1.0)
seqnum-base: (uint) [0 - MAXINT]
The RTP sequence number representing the first rtp packet
The RTP sequence number representing the first rtp packet. When this
parameter is given, all sequence numbers below this seqnum should be
ignored. (default = seqnum of first RTP packet).
encoding-name: (String) ANY
typically second part of the mime type. ex. MP4V-ES. only required if
......@@ -50,15 +75,15 @@ The following fields can or must (*) be specified in the structure:
Example:
"application/x-rtp",
"media", G_TYPE_STRING, "audio", -]
"payload", G_TYPE_INT, 96, ] - required
"clock-rate", G_TYPE_INT, 8000, -]
"encoding-name", G_TYPE_STRING, "AMR", -] - required since payload >= 96
"encoding-params", G_TYPE_STRING, "1", -] - optional param for AMR
"octet-align", G_TYPE_STRING, "1", -]
"crc", G_TYPE_STRING, "0", ]
"robust-sorting", G_TYPE_STRING, "0", ] AMR specific params.
"interleaving", G_TYPE_STRING, "0", -]
"media", G_TYPE_STRING, "audio", -.
"payload", G_TYPE_INT, 96, | - required
"clock-rate", G_TYPE_INT, 8000, -'
"encoding-name", G_TYPE_STRING, "AMR", -. - required since payload >= 96
"encoding-params", G_TYPE_STRING, "1", -' - optional param for AMR
"octet-align", G_TYPE_STRING, "1", -.
"crc", G_TYPE_STRING, "0", |
"robust-sorting", G_TYPE_STRING, "0", | AMR specific params.
"interleaving", G_TYPE_STRING, "0", -'
Mapping of caps to and from SDP fields:
......@@ -79,6 +104,18 @@ The following fields can or must (*) be specified in the structure:
always use the lowercase names so that the SDP -> caps mapping remains
possible.
Mapping of caps to NEWSEGMENT:
rate: <play-speed>
applied-rate: <play-scale>
format: GST_FORMAT_TIME
start: <clock-base> * GST_SECOND / <clock-rate>
stop: if <ntp-stop> != -1
<npt-stop> - <npt-start> + start
else
-1
time: <npt-start>
usage with UDP
--------------
......
......@@ -30,11 +30,15 @@
GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
#define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
/* references:
* http://svn.xiph.org/trunk/vorbis/doc/draft-ietf-avt-rtp-vorbis-04.txt
*/
/* elementfactory information */
static const GstElementDetails gst_rtp_vorbis_depay_details =
GST_ELEMENT_DETAILS ("RTP packet depayloader",
"Codec/Depayloader/Network",
"Extracts Vorbis Audio from RTP packets (draft-01 of RFC XXXX)",
"Extracts Vorbis Audio from RTP packets (draft-04 of RFC XXXX)",
"Wim Taymans <wim@fluendo.com>");
/* RtpVorbisDepay signals and args */
......@@ -151,28 +155,70 @@ gst_rtp_vorbis_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_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
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 (rtpvorbisdepay, "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 (rtpvorbisdepay, "config size %u", size);
......@@ -216,59 +262,73 @@ gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
for (i = 0; i < num_headers; i++) {
guint32 ident;
guint16 length;
guint8 n_headers, b;
GstRtpVorbisConfig *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 (rtpvorbisdepay, "header %d, ident 0x%08x, length %u", i,
ident, length);
GST_DEBUG_OBJECT (rtpvorbisdepay,
"header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
if (size < length + VORBIS_ID_LEN)
if (size < length)
goto too_small;
GST_DEBUG_OBJECT (rtpvorbisdepay, "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 (rtpvorbisdepay, "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 (rtpvorbisdepay, "last header size: %u", length);
h_sizes[j] = length;
GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
conf = g_new0 (GstRtpVorbisConfig, 1);
conf->ident = ident;
buf = gst_buffer_new_and_alloc (VORBIS_ID_LEN);
memcpy (GST_BUFFER_DATA (buf), data, VORBIS_ID_LEN);
conf->headers = g_list_append (conf->headers, buf);
data += VORBIS_ID_LEN;
size -= VORBIS_ID_LEN;
/* create a dummy comment */
list = gst_tag_list_new ();
buf =
gst_tag_list_to_vorbiscomment_buffer (list, (guint8 *) "\003vorbis", 7,
"Vorbis 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 (rtpvorbisdepay, "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;
}
rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
}
return TRUE;
/* ERRORS */
wrong_configuration:
{
GST_DEBUG_OBJECT (rtpvorbisdepay, "error parsing configuration");
return FALSE;
}
too_small:
{
GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
......@@ -421,6 +481,8 @@ gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
payload = gst_rtp_buffer_get_payload (buf);
free_payload = FALSE;
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
header = GST_READ_UINT32_BE (payload);
/*
* 0 1 2 3
......
......@@ -32,7 +32,7 @@ GST_DEBUG_CATEGORY_STATIC (rtpvorbispay_debug);
#define GST_CAT_DEFAULT (rtpvorbispay_debug)
/* references:
* http://svn.xiph.org/trunk/vorbis/doc/draft-ietf-avt-rtp-vorbis-01.txt
* http://svn.xiph.org/trunk/vorbis/doc/draft-ietf-avt-rtp-vorbis-04.txt
*/
/* elementfactory information */
......@@ -208,27 +208,47 @@ gst_rtp_vorbis_pay_flush_packet (GstRtpVorbisPay * rtpvorbispay)
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_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
{
GstRtpVorbisPay *rtpvorbispay = GST_RTP_VORBIS_PAY (basepayload);
GList *walk;
guint length;
guint length, size, n_headers, configlen;
gchar *cstr, *configuration;
guint8 *data;
guint8 *data, *config;
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 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
......@@ -247,35 +267,60 @@ gst_rtp_vorbis_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 = rtpvorbispay->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;
......@@ -292,12 +337,44 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
data[5] = (ident >> 8) & 0xff;
data[6] = ident & 0xff;
/* store length minus the length of the fixed vorbis header */
data[7] = ((length - 30) >> 8) & 0xff;
data[8] = (length - 30) & 0xff;
/* store length of all vorbis 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 = rtpvorbispay->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 = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
......@@ -305,10 +382,9 @@ gst_rtp_vorbis_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 */
cstr = g_strdup_printf ("%d", rtpvorbispay->channels);
......@@ -322,7 +398,6 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
NULL);
g_free (cstr);
g_free (configuration);
g_value_unset (&v);
return TRUE;
......@@ -450,12 +525,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
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) {
if (VDT != 0) {
GST_DEBUG_OBJECT (rtpvorbispay, "collecting header");
/* append header to the list of headers */
rtpvorbispay->headers = g_list_append (rtpvorbispay->headers, buffer);
......
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