gst/rtp/Makefile.am: We depend on gsttag to generate the vorbis comments.

Original commit message from CVS:
* gst/rtp/Makefile.am:
We depend on gsttag to generate the vorbis comments.
* gst/rtp/gstrtpvorbisdepay.c:
(gst_rtp_vorbis_depay_parse_configuration),
(gst_rtp_vorbis_depay_setcaps),
(gst_rtp_vorbis_depay_switch_codebook),
(gst_rtp_vorbis_depay_process):
* gst/rtp/gstrtpvorbisdepay.h:
Parse configuration string in the depayloader.
Implement selecting and switching to a new codebook.
Receiving vorbis over RTP now works.
* gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_reset_packet),
(gst_rtp_vorbis_pay_init_packet),
(gst_rtp_vorbis_pay_finish_headers),
(gst_rtp_vorbis_pay_handle_buffer):
* gst/rtp/gstrtpvorbispay.h:
Set timestamps on outgoing buffers and RTP packets.
Fix configuration string, prepend number of Packet headers.
Fix encoding of ident string.
Add delivery-method to caps.
Streaming vorbis over RTP now works.
This commit is contained in:
Christian Schaller 2006-11-07 01:43:06 +00:00
parent 53ddac062d
commit e0e75f715e
6 changed files with 302 additions and 23 deletions

View file

@ -1,3 +1,29 @@
2006-11-06 Wim Taymans <wim@fluendo.com>
* gst/rtp/Makefile.am:
We depend on gsttag to generate the vorbis comments.
* gst/rtp/gstrtpvorbisdepay.c:
(gst_rtp_vorbis_depay_parse_configuration),
(gst_rtp_vorbis_depay_setcaps),
(gst_rtp_vorbis_depay_switch_codebook),
(gst_rtp_vorbis_depay_process):
* gst/rtp/gstrtpvorbisdepay.h:
Parse configuration string in the depayloader.
Implement selecting and switching to a new codebook.
Receiving vorbis over RTP now works.
* gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_reset_packet),
(gst_rtp_vorbis_pay_init_packet),
(gst_rtp_vorbis_pay_finish_headers),
(gst_rtp_vorbis_pay_handle_buffer):
* gst/rtp/gstrtpvorbispay.h:
Set timestamps on outgoing buffers and RTP packets.
Fix configuration string, prepend number of Packet headers.
Fix encoding of ident string.
Add delivery-method to caps.
Streaming vorbis over RTP now works.
2006-11-06 Wim Taymans <wim@fluendo.com>
* gst/rtp/gstrtpvorbispay.c: (gst_rtp_vorbis_pay_setcaps),

View file

@ -41,6 +41,7 @@ endif
libgstrtp_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
libgstrtp_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) \
-lgsttag-@GST_MAJORMINOR@ \
-lgstrtp-@GST_MAJORMINOR@ $(WINSOCK2_LIBS)
libgstrtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)

View file

@ -21,6 +21,7 @@
# include "config.h"
#endif
#include <gst/tag/tag.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <string.h>
@ -75,6 +76,9 @@ 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);
@ -146,21 +150,172 @@ gst_rtp_vorbis_depay_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
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;
buf = gst_value_get_buffer (&v);
gst_buffer_ref (buf);
g_value_unset (&v);
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %u", size);
/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Number of packed headers |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Packed header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Packed header |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | .... |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
if (size < 4)
goto too_small;
num_headers = GST_READ_UINT32_BE (data);
size -= 4;
data += 4;
GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
/* 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 |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
for (i = 0; i < num_headers; i++) {
guint32 ident;
guint16 length;
GstRtpVorbisConfig *conf;
GstTagList *list;
if (size < 5)
goto too_small;
ident = (data[0] << 16) | (data[1] << 8) | data[2];
length = (data[3] << 8) | data[4];
size -= 5;
data += 5;
GST_DEBUG_OBJECT (rtpvorbisdepay, "header %d, ident %08x, length %u", i,
ident, length);
if (size < length + VORBIS_ID_LEN)
goto too_small;
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;
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");
return FALSE;
}
}
static gboolean
gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
{
GstStructure *structure;
GstRtpVorbisDepay *rtpvorbisdepay;
GstCaps *srccaps;
const gchar *delivery_method;
const gchar *configuration;
gint clock_rate;
rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
structure = gst_caps_get_structure (caps, 0);
/* get clockrate */
if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
goto no_rate;
/* see how the configuration parameters will be transmitted */
delivery_method = gst_structure_get_string (structure, "delivery-method");
if (delivery_method == NULL)
goto no_delivery_method;
if (g_strcasecmp (delivery_method, "inline")) {
/* configure string is in the caps */
} else if (g_strcasecmp (delivery_method, "in_band")) {
/* headers will (also) be transmitted in the RTP packets */
} else if (g_str_has_prefix (delivery_method, "out_band/")) {
/* some other method of header delivery. */
goto unsupported_delivery_method;
} else
goto unsupported_delivery_method;
/* read and parse configuration string */
configuration = gst_structure_get_string (structure, "configuration");
if (configuration == NULL)
goto no_configuration;
if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, configuration))
goto invalid_configuration;
/* caps seem good, configure element */
depayload->clock_rate = clock_rate;
@ -171,6 +326,28 @@ gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
return TRUE;
/* ERRORS */
unsupported_delivery_method:
{
GST_ERROR_OBJECT (rtpvorbisdepay,
"unsupported delivery-method \"%s\" specified", delivery_method);
return FALSE;
}
no_delivery_method:
{
GST_ERROR_OBJECT (rtpvorbisdepay, "no delivery-method specified");
return FALSE;
}
no_configuration:
{
GST_ERROR_OBJECT (rtpvorbisdepay, "no configuration specified");
return FALSE;
}
invalid_configuration:
{
GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
return FALSE;
}
no_rate:
{
GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
@ -178,6 +355,41 @@ no_rate:
}
}
static gboolean
gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
guint32 ident)
{
GList *walk;
gboolean res = FALSE;
for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
if (conf->ident == ident) {
GList *headers;
/* FIXME, remove pads, create new pad.. */
/* push out all the headers */
for (headers = conf->headers; headers; headers = g_list_next (headers)) {
GstBuffer *header = GST_BUFFER_CAST (headers->data);
gst_buffer_ref (header);
gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpvorbisdepay),
header);
}
/* remember the current config */
rtpvorbisdepay->config = conf;
res = TRUE;
}
}
if (!res) {
/* we don't know about the headers, figure out an alternative method for
* getting the codebooks. FIXME, fail for now. */
}
return res;
}
static GstBuffer *
gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{
@ -228,7 +440,21 @@ gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
packets = (header & 0xf);
if (VDT == 0) {
/* FIXME, if we have a raw payload, we need the codebook for the ident */
gboolean do_switch = FALSE;
/* we have a raw payload, find the codebook for the ident */
if (!rtpvorbisdepay->config) {
/* we don't have an active codebook, find the codebook and
* activate it */
do_switch = TRUE;
} else if (rtpvorbisdepay->config->ident != ident) {
/* codebook changed */
do_switch = TRUE;
}
if (do_switch) {
if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
goto switch_failed;
}
}
/* skip header */
@ -352,13 +578,19 @@ no_output:
bad_packet:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
("Packet did not validate"), (NULL));
(NULL), ("Packet did not validate"));
return NULL;
}
switch_failed:
{
GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
(NULL), ("Could not switch codebooks"));
return NULL;
}
packet_short:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
("Packet was too short (%d < 4)", payload_len), (NULL));
(NULL), ("Packet was too short (%d < 4)", payload_len));
return NULL;
}
ignore_reserved:
@ -369,7 +601,7 @@ ignore_reserved:
length_short:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
("Packet contains invalid data"), (NULL));
(NULL), ("Packet contains invalid data"));
return NULL;
}
}

View file

@ -40,12 +40,20 @@ G_BEGIN_DECLS
typedef struct _GstRtpVorbisDepay GstRtpVorbisDepay;
typedef struct _GstRtpVorbisDepayClass GstRtpVorbisDepayClass;
typedef struct _GstRtpVorbisConfig {
guint32 ident;
GList *headers;
} GstRtpVorbisConfig;
struct _GstRtpVorbisDepay
{
GstBaseRTPDepayload parent;
GstAdapter *adapter;
gboolean assembling;
GList *configs;
GstRtpVorbisConfig *config;
GstAdapter *adapter;
gboolean assembling;
};
struct _GstRtpVorbisDepayClass

View file

@ -139,14 +139,14 @@ gst_rtp_vorbis_pay_reset_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT)
payload_len = gst_rtp_buffer_get_payload_len (rtpvorbispay->packet);
rtpvorbispay->payload_left = payload_len - 4;
rtpvorbispay->payload_duration = 0;
rtpvorbispay->payload_ident = 0;
rtpvorbispay->payload_F = 0;
rtpvorbispay->payload_VDT = VDT;
rtpvorbispay->payload_pkts = 0;
}
static void
gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT)
gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT,
GstClockTime timestamp)
{
GST_DEBUG_OBJECT (rtpvorbispay, "starting new packet, VDT: %d", VDT);
@ -158,6 +158,7 @@ gst_rtp_vorbis_pay_init_packet (GstRtpVorbisPay * rtpvorbispay, guint8 VDT)
gst_rtp_buffer_new_allocate_len (GST_BASE_RTP_PAYLOAD_MTU
(rtpvorbispay), 0, 0);
gst_rtp_vorbis_pay_reset_packet (rtpvorbispay, VDT);
GST_BUFFER_TIMESTAMP (rtpvorbispay->packet) = timestamp;
}
static GstFlowReturn
@ -266,24 +267,31 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
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);
/* 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);
/* number of packed headers, we only pack 1 header */
data[0] = 0;
data[1] = 0;
data[2] = 0;
data[3] = 1;
/* we generate a random ident for this configuration */
ident = g_random_int ();
ident = rtpvorbispay->payload_ident = g_random_int ();
/* take lower 3 bytes */
data[0] = ident & 0xff;
data[1] = (ident >> 8) & 0xff;
data[2] = (ident >> 16) & 0xff;
data[4] = (ident >> 16) & 0xff;
data[5] = (ident >> 8) & 0xff;
data[6] = ident & 0xff;
data[3] = (length >> 8) & 0xff;
data[4] = length & 0xff;
/* store length minus the length of the fixed vorbis header */
data[7] = ((length - 30) >> 8) & 0xff;
data[8] = (length - 30) & 0xff;
/* copy header data */
data += 5;
data += 9;
for (walk = rtpvorbispay->headers; walk; walk = g_list_next (walk)) {
GstBuffer *buf = GST_BUFFER_CAST (walk->data);
@ -302,7 +310,8 @@ gst_rtp_vorbis_pay_finish_headers (GstBaseRTPPayload * basepayload)
rtpvorbispay->rate);
gst_basertppayload_set_outcaps (basepayload, "encoding-params", G_TYPE_STRING,
cstr, "configuration", G_TYPE_STRING, configuration,
/* don't set the defaults
"delivery-method", G_TYPE_STRING, "inline",
/* don't set the other defaults
*/
NULL);
g_free (cstr);
@ -393,7 +402,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
guint size, newsize;
guint8 *data;
guint packet_len;
GstClockTime duration, newduration;
GstClockTime duration, newduration, timestamp;
gboolean flush;
guint8 VDT;
guint plen;
@ -405,6 +414,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
size = GST_BUFFER_SIZE (buffer);
data = GST_BUFFER_DATA (buffer);
duration = GST_BUFFER_DURATION (buffer);
timestamp = GST_BUFFER_TIMESTAMP (buffer);
GST_DEBUG_OBJECT (rtpvorbispay, "size %u, duration %" GST_TIME_FORMAT,
size, GST_TIME_ARGS (duration));
@ -471,8 +481,9 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
ret = gst_rtp_vorbis_pay_flush_packet (rtpvorbispay);
/* create new packet if we must */
if (!rtpvorbispay->packet)
gst_rtp_vorbis_pay_init_packet (rtpvorbispay, VDT);
if (!rtpvorbispay->packet) {
gst_rtp_vorbis_pay_init_packet (rtpvorbispay, VDT, timestamp);
}
payload = gst_rtp_buffer_get_payload (rtpvorbispay->packet);
ppos = payload + rtpvorbispay->payload_pos;
@ -521,7 +532,7 @@ gst_rtp_vorbis_pay_handle_buffer (GstBaseRTPPayload * basepayload,
if (size > 0) {
/* start new packet and get pointers. VDT stays the same. */
gst_rtp_vorbis_pay_init_packet (rtpvorbispay,
rtpvorbispay->payload_VDT);
rtpvorbispay->payload_VDT, timestamp);
payload = gst_rtp_buffer_get_payload (rtpvorbispay->packet);
ppos = payload + rtpvorbispay->payload_pos;
}

View file

@ -56,6 +56,7 @@ struct _GstRtpVorbisPay
guint8 payload_F;
guint8 payload_VDT;
guint payload_pkts;
GstClockTime payload_timestamp;
GstClockTime payload_duration;
gint rate;