gstpay: send caps inline

Place the capsversion on the outgoing caps so that they end up in
an SDP as well. Receivers need to know what capsversion a particular
caps is for to be able to match the caps to the CV in the RTP packets.
Place the caps inside the RTP packet whenever the caps change.

Based on patch by Andrzej Bieniek <andrzej.bieniek@pure.com>

Conflicts:
	gst/rtp/gstrtpgstpay.c
	gst/rtp/gstrtpgstpay.h
This commit is contained in:
Wim Taymans 2012-11-01 10:52:25 +00:00
parent 3b1931a039
commit 936c3819b5
2 changed files with 114 additions and 10 deletions

View file

@ -68,6 +68,8 @@ GST_STATIC_PAD_TEMPLATE ("src",
"clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"") "clock-rate = (int) 90000, " "encoding-name = (string) \"X-GST\"")
); );
static void gst_rtp_gst_pay_finalize (GObject * obj);
static gboolean gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload, static gboolean gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload,
GstCaps * caps); GstCaps * caps);
static GstFlowReturn gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * payload, static GstFlowReturn gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * payload,
@ -79,12 +81,16 @@ G_DEFINE_TYPE (GstRtpGSTPay, gst_rtp_gst_pay, GST_TYPE_RTP_BASE_PAYLOAD);
static void static void
gst_rtp_gst_pay_class_init (GstRtpGSTPayClass * klass) gst_rtp_gst_pay_class_init (GstRtpGSTPayClass * klass)
{ {
GObjectClass *gobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
GstRTPBasePayloadClass *gstrtpbasepayload_class; GstRTPBasePayloadClass *gstrtpbasepayload_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass; gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
gobject_class->finalize = gst_rtp_gst_pay_finalize;
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_rtp_gst_pay_src_template)); gst_static_pad_template_get (&gst_rtp_gst_pay_src_template));
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
@ -107,22 +113,48 @@ gst_rtp_gst_pay_init (GstRtpGSTPay * rtpgstpay)
{ {
} }
static void
gst_rtp_gst_pay_finalize (GObject * obj)
{
GstRtpGSTPay *rtpgstpay;
rtpgstpay = GST_RTP_GST_PAY (obj);
g_free (rtpgstpay->capsstr);
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
static gboolean static gboolean
gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps) gst_rtp_gst_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
{ {
GstRtpGSTPay *rtpgstpay;
gboolean res; gboolean res;
gchar *capsstr, *capsenc; gchar *capsenc, *capsver;
capsstr = gst_caps_to_string (caps); rtpgstpay = GST_RTP_GST_PAY (payload);
capsenc = g_base64_encode ((guchar *) capsstr, strlen (capsstr));
g_free (capsstr); g_free (rtpgstpay->capsstr);
rtpgstpay->capsstr = gst_caps_to_string (caps);
rtpgstpay->capslen = strlen (rtpgstpay->capsstr);
rtpgstpay->current_CV = rtpgstpay->next_CV;
/* encode without 0 byte */
capsenc = g_base64_encode ((guchar *) rtpgstpay->capsstr, rtpgstpay->capslen);
GST_DEBUG_OBJECT (payload, "caps=%s, caps(base64)=%s",
rtpgstpay->capsstr, capsenc);
/* for 0 byte */
rtpgstpay->capslen++;
capsver = g_strdup_printf ("%d", rtpgstpay->current_CV);
gst_rtp_base_payload_set_options (payload, "application", TRUE, "X-GST", gst_rtp_base_payload_set_options (payload, "application", TRUE, "X-GST",
90000); 90000);
res = res =
gst_rtp_base_payload_set_outcaps (payload, "caps", G_TYPE_STRING, capsenc, gst_rtp_base_payload_set_outcaps (payload, "caps", G_TYPE_STRING, capsenc,
NULL); "capsversion", G_TYPE_STRING, capsver, NULL);
g_free (capsenc); g_free (capsenc);
g_free (capsver);
return res; return res;
} }
@ -140,6 +172,9 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
GstClockTime timestamp; GstClockTime timestamp;
guint32 frag_offset; guint32 frag_offset;
guint flags; guint flags;
gchar *capsstr;
guint capslen;
guint capslen_prefix_len;
rtpgstpay = GST_RTP_GST_PAY (basepayload); rtpgstpay = GST_RTP_GST_PAY (basepayload);
@ -153,6 +188,22 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT))
flags |= (1 << 3); flags |= (1 << 3);
capsstr = rtpgstpay->capsstr;
capslen = rtpgstpay->capslen;
if (capslen) {
/* start of buffer, calculate length */
capslen_prefix_len = 1;
while (capslen >> (7 * capslen_prefix_len))
capslen_prefix_len++;
GST_DEBUG_OBJECT (rtpgstpay, "sending inline caps");
rtpgstpay->next_CV++;
} else {
capslen_prefix_len = 0;
}
flags |= (rtpgstpay->current_CV << 4);
/* /*
* 0 1 2 3 * 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 * 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
@ -166,6 +217,8 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
ptr = map.data; ptr = map.data;
left = map.size; left = map.size;
GST_DEBUG_OBJECT (basepayload, "buffer size=%u", left);
while (left > 0) { while (left > 0) {
guint towrite; guint towrite;
guint8 *payload; guint8 *payload;
@ -174,7 +227,9 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
GstRTPBuffer rtp = { NULL }; GstRTPBuffer rtp = { NULL };
/* this will be the total lenght of the packet */ /* this will be the total lenght of the packet */
packet_len = gst_rtp_buffer_calc_packet_len (8 + left, 0, 0); packet_len =
gst_rtp_buffer_calc_packet_len (8 + capslen + capslen_prefix_len + left,
0, 0);
/* fill one MTU or all available bytes */ /* fill one MTU or all available bytes */
towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay)); towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay));
@ -188,6 +243,12 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp); gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
payload = gst_rtp_buffer_get_payload (&rtp); payload = gst_rtp_buffer_get_payload (&rtp);
if (capslen > 0)
flags |= (1 << 7);
GST_DEBUG_OBJECT (basepayload, "new packet len %u, frag %u", packet_len,
frag_offset);
payload[0] = flags; payload[0] = flags;
payload[1] = payload[2] = payload[3] = 0; payload[1] = payload[2] = payload[3] = 0;
payload[4] = frag_offset >> 24; payload[4] = frag_offset >> 24;
@ -198,11 +259,49 @@ gst_rtp_gst_pay_handle_buffer (GstRTPBasePayload * basepayload,
payload += 8; payload += 8;
payload_len -= 8; payload_len -= 8;
memcpy (payload, ptr, payload_len); if (capslen) {
guint tocopy;
ptr += payload_len; /* we need to write caps */
left -= payload_len; if (frag_offset == 0) {
frag_offset += payload_len; /* write caps length */
while (capslen_prefix_len) {
capslen_prefix_len--;
*payload++ = ((capslen_prefix_len > 0) ? 0x80 : 0) |
((capslen >> (7 * capslen_prefix_len)) & 0x7f);
payload_len--;
frag_offset++;
}
}
tocopy = MIN (payload_len, capslen);
GST_DEBUG_OBJECT (basepayload, "copy %u bytes from caps to payload",
tocopy);
memcpy (payload, capsstr, tocopy);
capsstr += tocopy;
capslen -= tocopy;
payload += tocopy;
payload_len -= tocopy;
frag_offset += tocopy;
if (capslen == 0) {
rtpgstpay->capslen = 0;
g_free (rtpgstpay->capsstr);
rtpgstpay->capsstr = NULL;
}
}
if (capslen == 0) {
/* no more caps, continue with data */
GST_DEBUG_OBJECT (basepayload, "copy %u bytes from buffer to payload",
payload_len);
memcpy (payload, ptr, payload_len);
ptr += payload_len;
left -= payload_len;
frag_offset += payload_len;
}
if (left == 0) if (left == 0)
gst_rtp_buffer_set_marker (&rtp, TRUE); gst_rtp_buffer_set_marker (&rtp, TRUE);

View file

@ -42,6 +42,11 @@ typedef struct _GstRtpGSTPayClass GstRtpGSTPayClass;
struct _GstRtpGSTPay struct _GstRtpGSTPay
{ {
GstRTPBasePayload payload; GstRTPBasePayload payload;
gchar *capsstr;
guint capslen;
guint8 current_CV; /* CV field of incoming caps*/
guint8 next_CV;
}; };
struct _GstRtpGSTPayClass struct _GstRtpGSTPayClass