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.
This commit is contained in:
Sebastian Dröge 2010-03-26 18:58:35 +01:00 committed by Tim-Philipp Müller
parent 7b10c2afce
commit 00b0444618
2 changed files with 121 additions and 3 deletions

View 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;

View file

@ -54,6 +54,9 @@ typedef struct {
struct _GstFlacParse {
GstBaseParse parent;
/* Properties */
gboolean check_frame_checksums;
GstFlacParseState state;
gint64 upstream_length;