flacparse: Optionally check the overall frame checksums too before accepting a frame...
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 26 Mar 2010 17:58:35 +0000 (18:58 +0100)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Fri, 8 Apr 2011 17:07:06 +0000 (18:07 +0100)
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.

gst/audioparsers/gstflacparse.c
gst/audioparsers/gstflacparse.h

index ba9d7c4e673899a64f43ca52d776ee5662a371bc..0670fc05a46a7f0d2b6807ffef488a83978f68c1 100644 (file)
@@ -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;
 
index af57ba78633e32233b5e82bcf5618956d5fe3230..4730e235ce52030754418ff971943e84067e4b48 100644 (file)
@@ -54,6 +54,9 @@ typedef struct {
 struct _GstFlacParse {
   GstBaseParse parent;
 
+  /* Properties */
+  gboolean check_frame_checksums;
+
   GstFlacParseState state;
 
   gint64 upstream_length;