summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--gst/rtp/gstrtpmp4gdepay.c152
2 files changed, 142 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 33dec662..78922969 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-09-15 Wim Taymans <wim.taymans@collabora.co.uk>
+
+ * gst/rtp/gstrtpmp4gdepay.c: (gst_bs_parse_init),
+ (gst_bs_parse_read), (gst_rtp_mp4g_depay_process):
+ Change some of the ranges in the caps, mostly for the amount of bits we
+ can use.
+ Added a little bitstream parse and use it to parse the AU header fields.
+ Check for malformed and wrongly sized packets better.
+ Implement more header field parsing.
+ Handle the size of fragmented packets correctly.
+
2008-09-14 Edward Hervey <edward.hervey@collabora.co.uk>
Patch by: Jonathan Matthew <notverysmart@gmail.com>
diff --git a/gst/rtp/gstrtpmp4gdepay.c b/gst/rtp/gstrtpmp4gdepay.c
index 35122656..d5942440 100644
--- a/gst/rtp/gstrtpmp4gdepay.c
+++ b/gst/rtp/gstrtpmp4gdepay.c
@@ -67,16 +67,71 @@ GST_STATIC_PAD_TEMPLATE ("sink",
/* "maxdisplacement = (string) [1,MAX], " */
/* "de-interleavebuffersize = (string) [1,MAX], " */
/* Optional configuration parameters */
- /* "sizelength = (string) [1, 16], " *//* max 16 bits, should be enough... */
- /* "indexlength = (string) [1, 8], " */
- /* "indexdeltalength = (string) [1, 8], " */
- /* "ctsdeltalength = (string) [1, 64], " */
- /* "dtsdeltalength = (string) [1, 64], " */
+ /* "sizelength = (string) [1, 32], " */
+ /* "indexlength = (string) [1, 32], " */
+ /* "indexdeltalength = (string) [1, 32], " */
+ /* "ctsdeltalength = (string) [1, 32], " */
+ /* "dtsdeltalength = (string) [1, 32], " */
/* "randomaccessindication = (string) {0, 1}, " */
- /* "streamstateindication = (string) [0, 64], " */
- /* "auxiliarydatasizelength = (string) [0, 64]" */ )
+ /* "streamstateindication = (string) [0, 32], " */
+ /* "auxiliarydatasizelength = (string) [0, 32]" */ )
);
+/* simple bitstream parser */
+typedef struct
+{
+ const guint8 *data;
+ const guint8 *end;
+ gint head; /* bitpos in the cache of next bit */
+ guint64 cache; /* cached bytes */
+} GstBsParse;
+
+static void
+gst_bs_parse_init (GstBsParse * bs, const guint8 * data, guint size)
+{
+ bs->data = data;
+ bs->end = data + size;
+ bs->head = 0;
+ bs->cache = 0xffffffff;
+}
+
+static guint32
+gst_bs_parse_read (GstBsParse * bs, guint n)
+{
+ guint32 res = 0;
+ gint shift;
+
+ if (n == 0)
+ return res;
+
+ /* fill up the cache if we need to */
+ while (bs->head < n) {
+ if (bs->data >= bs->end) {
+ /* we're at the end, can't produce more than head number of bits */
+ n = bs->head;
+ break;
+ }
+ /* shift bytes in cache, moving the head bits of the cache left */
+ bs->cache = (bs->cache << 8) | *bs->data++;
+ bs->head += 8;
+ }
+
+ /* bring the required bits down and truncate */
+ if ((shift = bs->head - n) > 0)
+ res = bs->cache >> shift;
+ else
+ res = bs->cache;
+
+ /* mask out required bits */
+ if (n < 32)
+ res &= (1 << n) - 1;
+
+ bs->head = shift;
+
+ return res;
+}
+
+
GST_BOILERPLATE (GstRtpMP4GDepay, gst_rtp_mp4g_depay, GstBaseRTPDepayload,
GST_TYPE_BASE_RTP_DEPAYLOAD);
@@ -261,22 +316,25 @@ gst_rtp_mp4g_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
}
{
- gint payload_len, payload_header;
+ gint payload_len, payload_AU;
guint8 *payload;
guint32 timestamp;
guint AU_headers_len;
- guint AU_size, AU_index;
+ guint AU_size, AU_index, payload_AU_size;
gboolean M;
payload_len = gst_rtp_buffer_get_payload_len (buf);
payload = gst_rtp_buffer_get_payload (buf);
- payload_header = 0;
timestamp = gst_rtp_buffer_get_timestamp (buf);
M = gst_rtp_buffer_get_marker (buf);
if (rtpmp4gdepay->sizelength > 0) {
gint num_AU_headers, AU_headers_bytes, i;
+ GstBsParse bs;
+
+ if (payload_len < 2)
+ goto short_payload;
/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
* |AU-headers-length|AU-header|AU-header| |AU-header|padding|
@@ -295,22 +353,67 @@ gst_rtp_mp4g_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
/* skip header */
payload += 2;
- /* skip special headers */
- payload_header = 2 + AU_headers_bytes;
+ payload_len -= 2;
+
+ if (payload_len < AU_headers_bytes)
+ goto short_payload;
+
+ /* skip special headers, point to first payload AU */
+ payload_AU = 2 + AU_headers_bytes;
+ payload_AU_size = payload_len - AU_headers_bytes;
+
+ /* point the bitstream parser to the first AU header bit */
+ gst_bs_parse_init (&bs, payload, payload_len);
+
+ for (i = 0; i < num_AU_headers && payload_AU_size > 0; i++) {
+ /* parse AU header
+ * +---------------------------------------+
+ * | AU-size |
+ * +---------------------------------------+
+ * | AU-Index / AU-Index-delta |
+ * +---------------------------------------+
+ * | CTS-flag |
+ * +---------------------------------------+
+ * | CTS-delta |
+ * +---------------------------------------+
+ * | DTS-flag |
+ * +---------------------------------------+
+ * | DTS-delta |
+ * +---------------------------------------+
+ * | RAP-flag |
+ * +---------------------------------------+
+ * | Stream-state |
+ * +---------------------------------------+
+ */
+ AU_size = gst_bs_parse_read (&bs, rtpmp4gdepay->sizelength);
+ if (i == 0)
+ AU_index = gst_bs_parse_read (&bs, rtpmp4gdepay->indexlength);
+ else
+ AU_index = gst_bs_parse_read (&bs, rtpmp4gdepay->indexdeltalength);
+ if (rtpmp4gdepay->ctsdeltalength > 0) {
+ if (gst_bs_parse_read (&bs, 1))
+ gst_bs_parse_read (&bs, rtpmp4gdepay->ctsdeltalength);
+ }
+ if (rtpmp4gdepay->dtsdeltalength > 0) {
+ if (gst_bs_parse_read (&bs, 1))
+ gst_bs_parse_read (&bs, rtpmp4gdepay->dtsdeltalength);
+ }
+ if (rtpmp4gdepay->randomaccessindication)
+ gst_bs_parse_read (&bs, 1);
+ if (rtpmp4gdepay->streamstateindication > 0)
+ gst_bs_parse_read (&bs, rtpmp4gdepay->streamstateindication);
- for (i = 0; i < num_AU_headers; i++) {
- /* FIXME, use bits */
- AU_size = ((payload[0] << 8) | payload[1]) >> 3;
- AU_index = payload[1] & 0x7;
- payload += 2;
+ GST_DEBUG_OBJECT (rtpmp4gdepay, "size %d, index %d", AU_size, AU_index);
- GST_DEBUG_OBJECT (rtpmp4gdepay, "len, %d, size %d, index %d",
- AU_headers_len, AU_size, AU_index);
+ /* fragmented pakets have the AU_size set to the size of the
+ * unfragmented AU. */
+ if (AU_size > payload_AU_size)
+ AU_size = payload_AU_size;
/* collect stuff in the adapter, strip header from payload and push in
* the adapter */
outbuf =
- gst_rtp_buffer_get_payload_subbuffer (buf, payload_header, AU_size);
+ gst_rtp_buffer_get_payload_subbuffer (buf, payload_AU, AU_size);
gst_adapter_push (rtpmp4gdepay->adapter, outbuf);
if (M) {
@@ -331,7 +434,8 @@ gst_rtp_mp4g_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
else
gst_base_rtp_depayload_push (depayload, outbuf);
}
- payload_header += AU_size;
+ payload_AU += AU_size;
+ payload_AU_size -= AU_size;
}
} else {
/* push complete buffer in adapter */
@@ -363,6 +467,12 @@ bad_packet:
("Packet did not validate."), (NULL));
return NULL;
}
+short_payload:
+ {
+ GST_ELEMENT_WARNING (rtpmp4gdepay, STREAM, DECODE,
+ ("Packet payload was too short."), (NULL));
+ return NULL;
+ }
}
static GstStateChangeReturn