From a297069e16a54bc5dc63ec903ec919b7f16bd632 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 21 Sep 2005 17:50:29 +0000 Subject: [PATCH] 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. --- ChangeLog | 17 +++++ gst/rtp/gstrtpamrdec.c | 144 ++++++++++++++++++++++++++++---------- gst/rtp/gstrtpamrdepay.c | 144 ++++++++++++++++++++++++++++---------- gst/rtp/gstrtpamrenc.c | 23 +++--- gst/rtp/gstrtpamrpay.c | 23 +++--- gst/rtp/gstrtpdec.c | 16 +++++ gst/rtp/gstrtpdepay.c | 16 +++++ gst/rtp/gstrtpmp4vdec.c | 24 +++++++ gst/rtp/gstrtpmp4vdepay.c | 24 +++++++ gst/rtp/gstrtpmp4venc.c | 25 +++++-- gst/rtp/gstrtpmp4vpay.c | 25 +++++-- 11 files changed, 373 insertions(+), 108 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8743d9822e..53ff6408d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2005-09-21 Wim Taymans + + * 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 * gst/rtp/README: diff --git a/gst/rtp/gstrtpamrdec.c b/gst/rtp/gstrtpamrdec.c index f213662526..216c3d56ea 100644 --- a/gst/rtp/gstrtpamrdec.c +++ b/gst/rtp/gstrtpamrdec.c @@ -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_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE, + ("amr packet did not validate"), (NULL)); gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -one_packet_only: - { - GST_DEBUG ("One packet per RTP packet only"); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } } diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c index f213662526..216c3d56ea 100644 --- a/gst/rtp/gstrtpamrdepay.c +++ b/gst/rtp/gstrtpamrdepay.c @@ -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_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE, + ("amr packet did not validate"), (NULL)); gst_buffer_unref (buf); - return GST_FLOW_ERROR; - } -one_packet_only: - { - GST_DEBUG ("One packet per RTP packet only"); - gst_buffer_unref (buf); - return GST_FLOW_ERROR; + return GST_FLOW_OK; } } diff --git a/gst/rtp/gstrtpamrenc.c b/gst/rtp/gstrtpamrenc.c index 37e5dd0d6e..29cdb2b030 100644 --- a/gst/rtp/gstrtpamrenc.c +++ b/gst/rtp/gstrtpamrenc.c @@ -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; } diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c index 37e5dd0d6e..29cdb2b030 100644 --- a/gst/rtp/gstrtpamrpay.c +++ b/gst/rtp/gstrtpamrpay.c @@ -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; } diff --git a/gst/rtp/gstrtpdec.c b/gst/rtp/gstrtpdec.c index a7e7f6b833..96089c4728 100644 --- a/gst/rtp/gstrtpdec.c +++ b/gst/rtp/gstrtpdec.c @@ -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) { diff --git a/gst/rtp/gstrtpdepay.c b/gst/rtp/gstrtpdepay.c index a7e7f6b833..96089c4728 100644 --- a/gst/rtp/gstrtpdepay.c +++ b/gst/rtp/gstrtpdepay.c @@ -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) { diff --git a/gst/rtp/gstrtpmp4vdec.c b/gst/rtp/gstrtpmp4vdec.c index fba38d6bc8..0b6ae4039e 100644 --- a/gst/rtp/gstrtpmp4vdec.c +++ b/gst/rtp/gstrtpmp4vdec.c @@ -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; } diff --git a/gst/rtp/gstrtpmp4vdepay.c b/gst/rtp/gstrtpmp4vdepay.c index fba38d6bc8..0b6ae4039e 100644 --- a/gst/rtp/gstrtpmp4vdepay.c +++ b/gst/rtp/gstrtpmp4vdepay.c @@ -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; } diff --git a/gst/rtp/gstrtpmp4venc.c b/gst/rtp/gstrtpmp4venc.c index d9de14c0d5..5a5de12a86 100644 --- a/gst/rtp/gstrtpmp4venc.c +++ b/gst/rtp/gstrtpmp4venc.c @@ -45,11 +45,11 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"video\", " "payload = (int) [ 96, 255 ], " - "clock-rate = (int) [1, MAX ], " - "encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]" - /* All optional parameters + "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\"" + /* two string params * - * "config=" + "profile-level-id = (string) [1,MAX]" + "config = (string) [1,MAX]" */ ) ); @@ -148,9 +148,22 @@ gst_rtpmp4venc_finalize (GObject * object) static void 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), - "profile-level-id", G_TYPE_INT, rtpmp4venc->profile, - "config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL); + "profile-level-id", G_TYPE_STRING, profile, + "config", G_TYPE_STRING, config, NULL); + + g_value_unset (&v); + + g_free (profile); + g_free (config); } static gboolean diff --git a/gst/rtp/gstrtpmp4vpay.c b/gst/rtp/gstrtpmp4vpay.c index d9de14c0d5..5a5de12a86 100644 --- a/gst/rtp/gstrtpmp4vpay.c +++ b/gst/rtp/gstrtpmp4vpay.c @@ -45,11 +45,11 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_STATIC_CAPS ("application/x-rtp, " "media = (string) \"video\", " "payload = (int) [ 96, 255 ], " - "clock-rate = (int) [1, MAX ], " - "encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]" - /* All optional parameters + "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\"" + /* two string params * - * "config=" + "profile-level-id = (string) [1,MAX]" + "config = (string) [1,MAX]" */ ) ); @@ -148,9 +148,22 @@ gst_rtpmp4venc_finalize (GObject * object) static void 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), - "profile-level-id", G_TYPE_INT, rtpmp4venc->profile, - "config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL); + "profile-level-id", G_TYPE_STRING, profile, + "config", G_TYPE_STRING, config, NULL); + + g_value_unset (&v); + + g_free (profile); + g_free (config); } static gboolean