diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2005-09-21 17:50:29 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2005-09-21 17:50:29 +0000 |
commit | a297069e16a54bc5dc63ec903ec919b7f16bd632 (patch) | |
tree | 968aa948bf68a58f1a024b768baaeca1a8664989 /gst/rtp/gstrtpamrdepay.c | |
parent | 9dd3929730bc3e2656eabfd8a8edfc7a61bb0176 (diff) |
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.
Diffstat (limited to 'gst/rtp/gstrtpamrdepay.c')
-rw-r--r-- | gst/rtp/gstrtpamrdepay.c | 144 |
1 files changed, 106 insertions, 38 deletions
diff --git a/gst/rtp/gstrtpamrdepay.c b/gst/rtp/gstrtpamrdepay.c index f2136625..216c3d56 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_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; } } |