gst/rtp/gstrtpamrdec.c: Handle multiple AMr packets per payload. Handle CRC and parse ILL/ILP.

Original commit message from CVS:
* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_sink_setcaps),
(gst_rtpamrdec_chain):
Handle multiple AMr packets per payload. Handle CRC and
parse ILL/ILP.

* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_setcaps):
Make caps params strings for easy SDP mapping.

* gst/rtp/gstrtpdec.c: (gst_rtpdec_init), (gst_rtpdec_getcaps):
Handle capsnego better.

* gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps):
* gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_new_caps):
Generate and parse config string in the caps.
This commit is contained in:
Wim Taymans 2005-09-21 17:50:29 +00:00
parent 9dd3929730
commit a297069e16
11 changed files with 373 additions and 108 deletions

View file

@ -1,3 +1,20 @@
2005-09-21 Wim Taymans <wim@fluendo.com>
* gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_sink_setcaps),
(gst_rtpamrdec_chain):
Handle multiple AMr packets per payload. Handle CRC and
parse ILL/ILP.
* gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_setcaps):
Make caps params strings for easy SDP mapping.
* gst/rtp/gstrtpdec.c: (gst_rtpdec_init), (gst_rtpdec_getcaps):
Handle capsnego better.
* gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps):
* gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_new_caps):
Generate and parse config string in the caps.
2005-09-21 Wim Taymans <wim@fluendo.com> 2005-09-21 Wim Taymans <wim@fluendo.com>
* gst/rtp/README: * gst/rtp/README:

View file

@ -63,9 +63,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"clock-rate = (int) 8000, " "clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", " "encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", " "encoding-params = (string) \"1\", "
"octet-align = (string) 1, " "octet-align = (string) \"1\", "
"crc = (string) 0, " "crc = (string) { \"0\", \"1\" }, "
"robust-sorting = (string) 0, " "interleaving = (string) 0" "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder /* following options are not needed for a decoder
* *
"mode-set = (int) [ 0, 7 ], " "mode-set = (int) [ 0, 7 ], "
@ -238,8 +238,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return FALSE; return FALSE;
if (rtpamrdec->octet_align != TRUE) if (rtpamrdec->octet_align != TRUE)
return FALSE; return FALSE;
if (rtpamrdec->crc != FALSE)
return FALSE;
if (rtpamrdec->robust_sorting != FALSE) if (rtpamrdec->robust_sorting != FALSE)
return FALSE; return FALSE;
if (rtpamrdec->interleaving != FALSE) if (rtpamrdec->interleaving != FALSE)
@ -256,6 +254,12 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return TRUE; return TRUE;
} }
/* -1 is invalid */
static gint frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31,
5, -1, -1, -1, -1, -1, -1, 0
};
static GstFlowReturn static GstFlowReturn
gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf) gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
{ {
@ -275,9 +279,12 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
* no robust sorting, no interleaving data is to be parsed */ * no robust sorting, no interleaving data is to be parsed */
{ {
gint payload_len; gint payload_len;
guint8 *payload; guint8 *payload, *p, *dp;
guint32 timestamp; guint32 timestamp;
guint8 CMR, F, FT, Q; guint8 CMR;
gint i, num_packets, num_nonempty_packets;
gint amr_len;
gint ILL, ILP;
payload_len = gst_rtpbuffer_get_payload_len (buf); payload_len = gst_rtpbuffer_get_payload_len (buf);
@ -287,46 +294,111 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
payload = gst_rtpbuffer_get_payload (buf); payload = gst_rtpbuffer_get_payload (buf);
/* parse header /* parse CMR. The CMR is used by the sender to request
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 * a new encoding mode.
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+.. *
* | CMR |R|R|R|R|F| FT |Q|P|P| * 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+.. * +-+-+-+-+-+-+-+-+
* | CMR |R|R|R|R|
* +-+-+-+-+-+-+-+-+
*/ */
CMR = (payload[0] & 0xf0) >> 4; CMR = (payload[0] & 0xf0) >> 4;
F = (payload[1] & 0x80) >> 7;
/* we only support 1 packet per RTP packet for now */
if (F != 0)
goto one_packet_only;
FT = (payload[1] & 0x78) >> 3; /* strip CMR header now, pack FT and the data for the decoder */
Q = (payload[1] & 0x04) >> 2;
/* skip packet */
if (FT > 9 && FT < 15) {
ret = GST_FLOW_OK;
goto skip;
}
/* strip header now, leave FT in the data for the decoder */
payload_len -= 1; payload_len -= 1;
payload += 1; payload += 1;
if (rtpamrdec->interleaving) {
ILL = (payload[0] & 0xf0) >> 4;
ILP = (payload[0] & 0x0f);
payload_len -= 1;
payload += 1;
if (ILP > ILL)
goto bad_packet;
}
/*
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
* +-+-+-+-+-+-+-+-+..
* |F| FT |Q|P|P| more FT..
* +-+-+-+-+-+-+-+-+..
*/
/* count number of packets by counting the FTs. Also
* count number of amr data bytes and number of non-empty
* packets (this is also the number of CRCs if present). */
amr_len = 0;
num_nonempty_packets = 0;
num_packets = 0;
for (i = 0; i < payload_len; i++) {
gint fr_size;
guint8 FT;
FT = (payload[i] & 0x78) >> 3;
fr_size = frame_size[FT];
if (fr_size == -1)
goto bad_packet;
if (fr_size > 0) {
amr_len += fr_size;
num_nonempty_packets++;
}
num_packets++;
if ((payload[i] & 0x80) == 0)
break;
}
/* this is impossible */
if (num_packets == payload_len)
goto bad_packet;
if (rtpamrdec->crc) {
/* data len + CRC len + header bytes should be smaller than payload_len */
if (num_packets + num_nonempty_packets + amr_len > payload_len)
goto bad_packet;
} else {
/* data len + header bytes should be smaller than payload_len */
if (num_packets + amr_len > payload_len)
goto bad_packet;
}
timestamp = gst_rtpbuffer_get_timestamp (buf); timestamp = gst_rtpbuffer_get_timestamp (buf);
outbuf = gst_buffer_new_and_alloc (payload_len); outbuf = gst_buffer_new_and_alloc (payload_len);
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate; GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); /* point to destination */
p = GST_BUFFER_DATA (outbuf);
/* point to first data packet */
dp = payload + num_packets;
if (rtpamrdec->crc) {
/* skip CRC if present */
dp += num_nonempty_packets;
}
for (i = 0; i < num_packets; i++) {
gint fr_size;
fr_size = frame_size[(payload[i] & 0x78) >> 3];
if (fr_size > 0) {
/* copy FT */
*p++ = payload[i];
/* copy data packet, FIXME, calc CRC here. */
memcpy (p, dp, fr_size);
p += fr_size;
dp += fr_size;
}
}
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad)); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d", GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf)); GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf); ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
skip:
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }
@ -334,21 +406,17 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
not_negotiated: not_negotiated:
{ {
GST_DEBUG ("not_negotiated"); GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
("not negotiated"), (NULL));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
bad_packet: bad_packet:
{ {
GST_DEBUG ("Packet did not validate"); GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
("amr packet did not validate"), (NULL));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_OK;
}
one_packet_only:
{
GST_DEBUG ("One packet per RTP packet only");
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
} }
} }

View file

@ -63,9 +63,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"clock-rate = (int) 8000, " "clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", " "encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", " "encoding-params = (string) \"1\", "
"octet-align = (string) 1, " "octet-align = (string) \"1\", "
"crc = (string) 0, " "crc = (string) { \"0\", \"1\" }, "
"robust-sorting = (string) 0, " "interleaving = (string) 0" "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder /* following options are not needed for a decoder
* *
"mode-set = (int) [ 0, 7 ], " "mode-set = (int) [ 0, 7 ], "
@ -238,8 +238,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return FALSE; return FALSE;
if (rtpamrdec->octet_align != TRUE) if (rtpamrdec->octet_align != TRUE)
return FALSE; return FALSE;
if (rtpamrdec->crc != FALSE)
return FALSE;
if (rtpamrdec->robust_sorting != FALSE) if (rtpamrdec->robust_sorting != FALSE)
return FALSE; return FALSE;
if (rtpamrdec->interleaving != FALSE) if (rtpamrdec->interleaving != FALSE)
@ -256,6 +254,12 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return TRUE; return TRUE;
} }
/* -1 is invalid */
static gint frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31,
5, -1, -1, -1, -1, -1, -1, 0
};
static GstFlowReturn static GstFlowReturn
gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf) gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
{ {
@ -275,9 +279,12 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
* no robust sorting, no interleaving data is to be parsed */ * no robust sorting, no interleaving data is to be parsed */
{ {
gint payload_len; gint payload_len;
guint8 *payload; guint8 *payload, *p, *dp;
guint32 timestamp; guint32 timestamp;
guint8 CMR, F, FT, Q; guint8 CMR;
gint i, num_packets, num_nonempty_packets;
gint amr_len;
gint ILL, ILP;
payload_len = gst_rtpbuffer_get_payload_len (buf); payload_len = gst_rtpbuffer_get_payload_len (buf);
@ -287,46 +294,111 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
payload = gst_rtpbuffer_get_payload (buf); payload = gst_rtpbuffer_get_payload (buf);
/* parse header /* parse CMR. The CMR is used by the sender to request
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 * a new encoding mode.
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+.. *
* | CMR |R|R|R|R|F| FT |Q|P|P| * 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+.. * +-+-+-+-+-+-+-+-+
* | CMR |R|R|R|R|
* +-+-+-+-+-+-+-+-+
*/ */
CMR = (payload[0] & 0xf0) >> 4; CMR = (payload[0] & 0xf0) >> 4;
F = (payload[1] & 0x80) >> 7;
/* we only support 1 packet per RTP packet for now */
if (F != 0)
goto one_packet_only;
FT = (payload[1] & 0x78) >> 3; /* strip CMR header now, pack FT and the data for the decoder */
Q = (payload[1] & 0x04) >> 2;
/* skip packet */
if (FT > 9 && FT < 15) {
ret = GST_FLOW_OK;
goto skip;
}
/* strip header now, leave FT in the data for the decoder */
payload_len -= 1; payload_len -= 1;
payload += 1; payload += 1;
if (rtpamrdec->interleaving) {
ILL = (payload[0] & 0xf0) >> 4;
ILP = (payload[0] & 0x0f);
payload_len -= 1;
payload += 1;
if (ILP > ILL)
goto bad_packet;
}
/*
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
* +-+-+-+-+-+-+-+-+..
* |F| FT |Q|P|P| more FT..
* +-+-+-+-+-+-+-+-+..
*/
/* count number of packets by counting the FTs. Also
* count number of amr data bytes and number of non-empty
* packets (this is also the number of CRCs if present). */
amr_len = 0;
num_nonempty_packets = 0;
num_packets = 0;
for (i = 0; i < payload_len; i++) {
gint fr_size;
guint8 FT;
FT = (payload[i] & 0x78) >> 3;
fr_size = frame_size[FT];
if (fr_size == -1)
goto bad_packet;
if (fr_size > 0) {
amr_len += fr_size;
num_nonempty_packets++;
}
num_packets++;
if ((payload[i] & 0x80) == 0)
break;
}
/* this is impossible */
if (num_packets == payload_len)
goto bad_packet;
if (rtpamrdec->crc) {
/* data len + CRC len + header bytes should be smaller than payload_len */
if (num_packets + num_nonempty_packets + amr_len > payload_len)
goto bad_packet;
} else {
/* data len + header bytes should be smaller than payload_len */
if (num_packets + amr_len > payload_len)
goto bad_packet;
}
timestamp = gst_rtpbuffer_get_timestamp (buf); timestamp = gst_rtpbuffer_get_timestamp (buf);
outbuf = gst_buffer_new_and_alloc (payload_len); outbuf = gst_buffer_new_and_alloc (payload_len);
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate; GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len); /* point to destination */
p = GST_BUFFER_DATA (outbuf);
/* point to first data packet */
dp = payload + num_packets;
if (rtpamrdec->crc) {
/* skip CRC if present */
dp += num_nonempty_packets;
}
for (i = 0; i < num_packets; i++) {
gint fr_size;
fr_size = frame_size[(payload[i] & 0x78) >> 3];
if (fr_size > 0) {
/* copy FT */
*p++ = payload[i];
/* copy data packet, FIXME, calc CRC here. */
memcpy (p, dp, fr_size);
p += fr_size;
dp += fr_size;
}
}
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad)); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d", GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf)); GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf); ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
skip:
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }
@ -334,21 +406,17 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
not_negotiated: not_negotiated:
{ {
GST_DEBUG ("not_negotiated"); GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
("not negotiated"), (NULL));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
bad_packet: bad_packet:
{ {
GST_DEBUG ("Packet did not validate"); GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
("amr packet did not validate"), (NULL));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_OK;
}
one_packet_only:
{
GST_DEBUG ("One packet per RTP packet only");
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
} }
} }

View file

@ -54,13 +54,13 @@ GST_STATIC_PAD_TEMPLATE ("src",
"clock-rate = (int) 8000, " "clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", " "encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", " "encoding-params = (string) \"1\", "
"octet-align = (boolean) TRUE, " "octet-align = (string) \"1\", "
"crc = (boolean) FALSE, " "crc = (string) \"0\", "
"robust-sorting = (boolean) FALSE, " "robust-sorting = (string) \"0\", "
"interleaving = (boolean) FALSE, " "interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], " "mode-set = (int) [ 0, 7 ], "
"mode-change-period = (int) [ 1, MAX ], " "mode-change-period = (int) [ 1, MAX ], "
"mode-change-neighbor = (boolean) { TRUE, FALSE }, " "mode-change-neighbor = (string) { \"0\", \"1\" }, "
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]") "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
); );
@ -144,11 +144,14 @@ gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000); gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload, gst_basertppayload_set_outcaps (basepayload,
"encoding-params", G_TYPE_STRING, "1", "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
"octet-align", G_TYPE_BOOLEAN, TRUE, /* don't set the defaults
"crc", G_TYPE_BOOLEAN, FALSE, *
"robust-sorting", G_TYPE_BOOLEAN, FALSE, * "crc", G_TYPE_STRING, "0",
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL); * "robust-sorting", G_TYPE_STRING, "0",
* "interleaving", G_TYPE_STRING, "0",
*/
NULL);
return TRUE; return TRUE;
} }

View file

@ -54,13 +54,13 @@ GST_STATIC_PAD_TEMPLATE ("src",
"clock-rate = (int) 8000, " "clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", " "encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", " "encoding-params = (string) \"1\", "
"octet-align = (boolean) TRUE, " "octet-align = (string) \"1\", "
"crc = (boolean) FALSE, " "crc = (string) \"0\", "
"robust-sorting = (boolean) FALSE, " "robust-sorting = (string) \"0\", "
"interleaving = (boolean) FALSE, " "interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], " "mode-set = (int) [ 0, 7 ], "
"mode-change-period = (int) [ 1, MAX ], " "mode-change-period = (int) [ 1, MAX ], "
"mode-change-neighbor = (boolean) { TRUE, FALSE }, " "mode-change-neighbor = (string) { \"0\", \"1\" }, "
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]") "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
); );
@ -144,11 +144,14 @@ gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000); gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload, gst_basertppayload_set_outcaps (basepayload,
"encoding-params", G_TYPE_STRING, "1", "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
"octet-align", G_TYPE_BOOLEAN, TRUE, /* don't set the defaults
"crc", G_TYPE_BOOLEAN, FALSE, *
"robust-sorting", G_TYPE_BOOLEAN, FALSE, * "crc", G_TYPE_STRING, "0",
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL); * "robust-sorting", G_TYPE_STRING, "0",
* "interleaving", G_TYPE_STRING, "0",
*/
NULL);
return TRUE; return TRUE;
} }

View file

@ -74,6 +74,7 @@ GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
static void gst_rtpdec_class_init (gpointer g_class); static void gst_rtpdec_class_init (gpointer g_class);
static void gst_rtpdec_init (GstRTPDec * rtpdec); static void gst_rtpdec_init (GstRTPDec * rtpdec);
static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
@ -153,6 +154,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_sink_rtp_template), "sinkrtp"); (&gst_rtpdec_sink_rtp_template), "sinkrtp");
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp); gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
/* the input rtcp pad */ /* the input rtcp pad */
@ -166,6 +168,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
rtpdec->src_rtp = rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_src_rtp_template), "srcrtp"); (&gst_rtpdec_src_rtp_template), "srcrtp");
gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
/* the output rtcp pad */ /* the output rtcp pad */
@ -175,6 +178,19 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
} }
static GstCaps *
gst_rtpdec_getcaps (GstPad * pad)
{
GstRTPDec *src;
GstPad *other;
src = GST_RTPDEC (GST_PAD_PARENT (pad));
other = pad == src->src_rtp ? src->sink_rtp : src->src_rtp;
return gst_pad_peer_get_caps (other);
}
static GstFlowReturn static GstFlowReturn
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer) gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{ {

View file

@ -74,6 +74,7 @@ GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
static void gst_rtpdec_class_init (gpointer g_class); static void gst_rtpdec_class_init (gpointer g_class);
static void gst_rtpdec_init (GstRTPDec * rtpdec); static void gst_rtpdec_init (GstRTPDec * rtpdec);
static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer); static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
@ -153,6 +154,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_sink_rtp_template), "sinkrtp"); (&gst_rtpdec_sink_rtp_template), "sinkrtp");
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp); gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
/* the input rtcp pad */ /* the input rtcp pad */
@ -166,6 +168,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
rtpdec->src_rtp = rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_src_rtp_template), "srcrtp"); (&gst_rtpdec_src_rtp_template), "srcrtp");
gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
/* the output rtcp pad */ /* the output rtcp pad */
@ -175,6 +178,19 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp); gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
} }
static GstCaps *
gst_rtpdec_getcaps (GstPad * pad)
{
GstRTPDec *src;
GstPad *other;
src = GST_RTPDEC (GST_PAD_PARENT (pad));
other = pad == src->src_rtp ? src->sink_rtp : src->src_rtp;
return gst_pad_peer_get_caps (other);
}
static GstFlowReturn static GstFlowReturn
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer) gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{ {

View file

@ -161,6 +161,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
GstStructure *structure; GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec; GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps; GstCaps *srccaps;
const gchar *str;
rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad)); rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad));
@ -175,6 +176,29 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps); gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps);
gst_caps_unref (srccaps); gst_caps_unref (srccaps);
if ((str = gst_structure_get_string (structure, "config"))) {
GValue v = { 0 };
g_print ("config=%s\n", str);
g_value_init (&v, GST_TYPE_BUFFER);
if (gst_value_deserialize (&v, str)) {
GstBuffer *buffer;
buffer = gst_value_get_buffer (&v);
gst_buffer_ref (buffer);
g_value_unset (&v);
g_print ("buf=%p\n", buffer);
gst_buffer_set_caps (buffer, GST_PAD_CAPS (rtpmp4vdec->srcpad));
gst_pad_push (rtpmp4vdec->srcpad, buffer);
} else {
g_warning ("cannot convert config to buffer");
}
}
return TRUE; return TRUE;
} }

View file

@ -161,6 +161,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
GstStructure *structure; GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec; GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps; GstCaps *srccaps;
const gchar *str;
rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad)); rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad));
@ -175,6 +176,29 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps); gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps);
gst_caps_unref (srccaps); gst_caps_unref (srccaps);
if ((str = gst_structure_get_string (structure, "config"))) {
GValue v = { 0 };
g_print ("config=%s\n", str);
g_value_init (&v, GST_TYPE_BUFFER);
if (gst_value_deserialize (&v, str)) {
GstBuffer *buffer;
buffer = gst_value_get_buffer (&v);
gst_buffer_ref (buffer);
g_value_unset (&v);
g_print ("buf=%p\n", buffer);
gst_buffer_set_caps (buffer, GST_PAD_CAPS (rtpmp4vdec->srcpad));
gst_pad_push (rtpmp4vdec->srcpad, buffer);
} else {
g_warning ("cannot convert config to buffer");
}
}
return TRUE; return TRUE;
} }

View file

@ -45,11 +45,11 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("application/x-rtp, " GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"video\", " "media = (string) \"video\", "
"payload = (int) [ 96, 255 ], " "payload = (int) [ 96, 255 ], "
"clock-rate = (int) [1, MAX ], " "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
"encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]" /* two string params
/* All optional parameters
* *
* "config=" "profile-level-id = (string) [1,MAX]"
"config = (string) [1,MAX]"
*/ */
) )
); );
@ -148,9 +148,22 @@ gst_rtpmp4venc_finalize (GObject * object)
static void static void
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc) gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
{ {
gchar *profile, *config;
GValue v = { 0 };
profile = g_strdup_printf ("%d", rtpmp4venc->profile);
g_value_init (&v, GST_TYPE_BUFFER);
gst_value_set_buffer (&v, rtpmp4venc->config);
config = gst_value_serialize (&v);
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc), gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile, "profile-level-id", G_TYPE_STRING, profile,
"config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL); "config", G_TYPE_STRING, config, NULL);
g_value_unset (&v);
g_free (profile);
g_free (config);
} }
static gboolean static gboolean

View file

@ -45,11 +45,11 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS ("application/x-rtp, " GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"video\", " "media = (string) \"video\", "
"payload = (int) [ 96, 255 ], " "payload = (int) [ 96, 255 ], "
"clock-rate = (int) [1, MAX ], " "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
"encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]" /* two string params
/* All optional parameters
* *
* "config=" "profile-level-id = (string) [1,MAX]"
"config = (string) [1,MAX]"
*/ */
) )
); );
@ -148,9 +148,22 @@ gst_rtpmp4venc_finalize (GObject * object)
static void static void
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc) gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
{ {
gchar *profile, *config;
GValue v = { 0 };
profile = g_strdup_printf ("%d", rtpmp4venc->profile);
g_value_init (&v, GST_TYPE_BUFFER);
gst_value_set_buffer (&v, rtpmp4venc->config);
config = gst_value_serialize (&v);
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc), gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
"profile-level-id", G_TYPE_INT, rtpmp4venc->profile, "profile-level-id", G_TYPE_STRING, profile,
"config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL); "config", G_TYPE_STRING, config, NULL);
g_value_unset (&v);
g_free (profile);
g_free (config);
} }
static gboolean static gboolean