Commit a297069e authored by Wim Taymans's avatar Wim Taymans

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.
parent 9dd39297
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>
* gst/rtp/README:
......
......@@ -63,9 +63,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
"octet-align = (string) 1, "
"crc = (string) 0, "
"robust-sorting = (string) 0, " "interleaving = (string) 0"
"octet-align = (string) \"1\", "
"crc = (string) { \"0\", \"1\" }, "
"robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder
*
"mode-set = (int) [ 0, 7 ], "
......@@ -238,8 +238,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return FALSE;
if (rtpamrdec->octet_align != TRUE)
return FALSE;
if (rtpamrdec->crc != FALSE)
return FALSE;
if (rtpamrdec->robust_sorting != FALSE)
return FALSE;
if (rtpamrdec->interleaving != FALSE)
......@@ -256,6 +254,12 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
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
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 */
{
gint payload_len;
guint8 *payload;
guint8 *payload, *p, *dp;
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);
......@@ -287,46 +294,111 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
payload = gst_rtpbuffer_get_payload (buf);
/* parse header
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
* | CMR |R|R|R|R|F| FT |Q|P|P|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
/* parse CMR. The CMR is used by the sender to request
* a new encoding mode.
*
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* | CMR |R|R|R|R|
* +-+-+-+-+-+-+-+-+
*/
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;
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 */
/* strip CMR header now, pack FT and the data for the decoder */
payload_len -= 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);
outbuf = gst_buffer_new_and_alloc (payload_len);
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_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
skip:
gst_buffer_unref (buf);
}
......@@ -334,21 +406,17 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
not_negotiated:
{
GST_DEBUG ("not_negotiated");
GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
("not negotiated"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
bad_packet:
{
GST_DEBUG ("Packet did not validate");
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
one_packet_only:
{
GST_DEBUG ("One packet per RTP packet only");
GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
("amr packet did not validate"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
return GST_FLOW_OK;
}
}
......
......@@ -63,9 +63,9 @@ GST_STATIC_PAD_TEMPLATE ("sink",
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
"octet-align = (string) 1, "
"crc = (string) 0, "
"robust-sorting = (string) 0, " "interleaving = (string) 0"
"octet-align = (string) \"1\", "
"crc = (string) { \"0\", \"1\" }, "
"robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder
*
"mode-set = (int) [ 0, 7 ], "
......@@ -238,8 +238,6 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return FALSE;
if (rtpamrdec->octet_align != TRUE)
return FALSE;
if (rtpamrdec->crc != FALSE)
return FALSE;
if (rtpamrdec->robust_sorting != FALSE)
return FALSE;
if (rtpamrdec->interleaving != FALSE)
......@@ -256,6 +254,12 @@ gst_rtpamrdec_sink_setcaps (GstPad * pad, GstCaps * caps)
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
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 */
{
gint payload_len;
guint8 *payload;
guint8 *payload, *p, *dp;
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);
......@@ -287,46 +294,111 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
payload = gst_rtpbuffer_get_payload (buf);
/* parse header
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
* | CMR |R|R|R|R|F| FT |Q|P|P|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
/* parse CMR. The CMR is used by the sender to request
* a new encoding mode.
*
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* | CMR |R|R|R|R|
* +-+-+-+-+-+-+-+-+
*/
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;
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 */
/* strip CMR header now, pack FT and the data for the decoder */
payload_len -= 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);
outbuf = gst_buffer_new_and_alloc (payload_len);
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_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
skip:
gst_buffer_unref (buf);
}
......@@ -334,21 +406,17 @@ gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
not_negotiated:
{
GST_DEBUG ("not_negotiated");
GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
("not negotiated"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
bad_packet:
{
GST_DEBUG ("Packet did not validate");
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
one_packet_only:
{
GST_DEBUG ("One packet per RTP packet only");
GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
("amr packet did not validate"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
return GST_FLOW_OK;
}
}
......
......@@ -54,13 +54,13 @@ GST_STATIC_PAD_TEMPLATE ("src",
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
"octet-align = (boolean) TRUE, "
"crc = (boolean) FALSE, "
"robust-sorting = (boolean) FALSE, "
"interleaving = (boolean) FALSE, "
"octet-align = (string) \"1\", "
"crc = (string) \"0\", "
"robust-sorting = (string) \"0\", "
"interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], "
"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 ]")
);
......@@ -144,11 +144,14 @@ gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload,
"encoding-params", G_TYPE_STRING, "1",
"octet-align", G_TYPE_BOOLEAN, TRUE,
"crc", G_TYPE_BOOLEAN, FALSE,
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
"encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
/* don't set the defaults
*
* "crc", G_TYPE_STRING, "0",
* "robust-sorting", G_TYPE_STRING, "0",
* "interleaving", G_TYPE_STRING, "0",
*/
NULL);
return TRUE;
}
......
......@@ -54,13 +54,13 @@ GST_STATIC_PAD_TEMPLATE ("src",
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
"octet-align = (boolean) TRUE, "
"crc = (boolean) FALSE, "
"robust-sorting = (boolean) FALSE, "
"interleaving = (boolean) FALSE, "
"octet-align = (string) \"1\", "
"crc = (string) \"0\", "
"robust-sorting = (string) \"0\", "
"interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], "
"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 ]")
);
......@@ -144,11 +144,14 @@ gst_rtpamrenc_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload,
"encoding-params", G_TYPE_STRING, "1",
"octet-align", G_TYPE_BOOLEAN, TRUE,
"crc", G_TYPE_BOOLEAN, FALSE,
"robust-sorting", G_TYPE_BOOLEAN, FALSE,
"interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
"encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
/* don't set the defaults
*
* "crc", G_TYPE_STRING, "0",
* "robust-sorting", G_TYPE_STRING, "0",
* "interleaving", G_TYPE_STRING, "0",
*/
NULL);
return TRUE;
}
......
......@@ -74,6 +74,7 @@ GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
static void gst_rtpdec_class_init (gpointer g_class);
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_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_rtpdec_sink_rtp_template), "sinkrtp");
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);
/* the input rtcp pad */
......@@ -166,6 +168,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get
(&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);
/* the output rtcp pad */
......@@ -175,6 +178,19 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
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
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{
......
......@@ -74,6 +74,7 @@ GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
static void gst_rtpdec_class_init (gpointer g_class);
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_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_rtpdec_sink_rtp_template), "sinkrtp");
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);
/* the input rtcp pad */
......@@ -166,6 +168,7 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get
(&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);
/* the output rtcp pad */
......@@ -175,6 +178,19 @@ gst_rtpdec_init (GstRTPDec * rtpdec)
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
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{
......
......@@ -161,6 +161,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps;
const gchar *str;
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_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;
}
......
......@@ -161,6 +161,7 @@ gst_rtpmp4vdec_setcaps (GstPad * pad, GstCaps * caps)
GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps;
const gchar *str;
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_caps_unref (srccaps);