summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2010-03-26 18:58:35 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2010-03-26 18:58:35 +0100
commit09223cc719f70c6a81385da27e38b28c43ceda9b (patch)
tree905bdaf326a1028fc5a970f57eabe1ac547327c8
parent9fa738d36b8281cc16f245cd6cc61e59a55daef7 (diff)
flacparse: Optionally check the overall frame checksums too before accepting a frame as valid
This is optional because it's a quite expensive operation and it's very unlikely that a non-frame is detected as frame after the header CRC check and checking all bits for valid values. The overall frame checksums are mainly useful to detect inconsistencies in the encoded payload.
-rw-r--r--gst/audioparsers/gstflacparse.c121
-rw-r--r--gst/audioparsers/gstflacparse.h3
2 files changed, 121 insertions, 3 deletions
diff --git a/gst/audioparsers/gstflacparse.c b/gst/audioparsers/gstflacparse.c
index ba9d7c4e6..0670fc05a 100644
--- a/gst/audioparsers/gstflacparse.c
+++ b/gst/audioparsers/gstflacparse.c
@@ -114,6 +114,63 @@ gst_flac_calculate_crc8 (const guint8 * data, guint length)
return crc;
}
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+static const guint16 crc16_table[256] = {
+ 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+ 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+ 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+ 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+ 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+ 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+ 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+ 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+ 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+ 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+ 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+ 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+ 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+ 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+ 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+ 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+ 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
+};
+
+static guint16
+gst_flac_calculate_crc16 (const guint8 * data, guint length)
+{
+ guint16 crc = 0;
+
+ while (length--) {
+ crc = ((crc << 8) ^ crc16_table[(crc >> 8) ^ *data]) & 0xffff;
+ data++;
+ }
+
+ return crc;
+}
+
+enum
+{
+ PROP_0,
+ PROP_CHECK_FRAME_CHECKSUMS
+};
+
+#define DEFAULT_CHECK_FRAME_CHECKSUMS FALSE
+
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
@@ -128,6 +185,10 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
);
static void gst_flac_parse_finalize (GObject * object);
+static void gst_flac_parse_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_flac_parse_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
static gboolean gst_flac_parse_start (GstBaseParse * parse);
static gboolean gst_flac_parse_stop (GstBaseParse * parse);
@@ -167,6 +228,14 @@ gst_flac_parse_class_init (GstFlacParseClass * klass)
GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
gobject_class->finalize = gst_flac_parse_finalize;
+ gobject_class->set_property = gst_flac_parse_set_property;
+ gobject_class->get_property = gst_flac_parse_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_CHECK_FRAME_CHECKSUMS,
+ g_param_spec_boolean ("check-frame-checksums", "Check Frame Checksums",
+ "Check the overall checksums of every frame",
+ DEFAULT_CHECK_FRAME_CHECKSUMS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
baseparse_class->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
@@ -180,6 +249,39 @@ gst_flac_parse_class_init (GstFlacParseClass * klass)
static void
gst_flac_parse_init (GstFlacParse * flacparse, GstFlacParseClass * klass)
{
+ flacparse->check_frame_checksums = DEFAULT_CHECK_FRAME_CHECKSUMS;
+}
+
+static void
+gst_flac_parse_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstFlacParse *flacparse = GST_FLAC_PARSE (object);
+
+ switch (prop_id) {
+ case PROP_CHECK_FRAME_CHECKSUMS:
+ flacparse->check_frame_checksums = g_value_get_boolean (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_flac_parse_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstFlacParse *flacparse = GST_FLAC_PARSE (object);
+
+ switch (prop_id) {
+ case PROP_CHECK_FRAME_CHECKSUMS:
+ g_value_set_boolean (value, flacparse->check_frame_checksums);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
static void
@@ -659,9 +761,22 @@ gst_flac_parse_get_frame_size (GstFlacParse * flacparse, GstBuffer * buffer,
/* zero padding to byte alignment */
gst_bit_reader_skip_to_byte (&reader);
- /* Skip crc-16 for the complete frame */
- if (!gst_bit_reader_skip (&reader, 16))
- goto need_more_data;
+ if (flacparse->check_frame_checksums) {
+ guint16 actual_crc16, expected_crc16;
+
+ if (!gst_bit_reader_get_bits_uint16 (&reader, &expected_crc16, 16))
+ goto need_more_data;
+
+ actual_crc16 =
+ gst_flac_calculate_crc16 (GST_BUFFER_DATA (buffer),
+ (gst_bit_reader_get_pos (&reader) / 8) - 2);
+ if (actual_crc16 != expected_crc16)
+ goto error;
+ } else {
+ /* Skip crc-16 for the complete frame */
+ if (!gst_bit_reader_skip (&reader, 16))
+ goto need_more_data;
+ }
*framesize_ret = gst_bit_reader_get_pos (&reader) / 8;
diff --git a/gst/audioparsers/gstflacparse.h b/gst/audioparsers/gstflacparse.h
index af57ba786..4730e235c 100644
--- a/gst/audioparsers/gstflacparse.h
+++ b/gst/audioparsers/gstflacparse.h
@@ -54,6 +54,9 @@ typedef struct {
struct _GstFlacParse {
GstBaseParse parent;
+ /* Properties */
+ gboolean check_frame_checksums;
+
GstFlacParseState state;
gint64 upstream_length;