mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
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:
parent
7b10c2afce
commit
00b0444618
2 changed files with 121 additions and 3 deletions
|
@ -114,6 +114,63 @@ gst_flac_calculate_crc8 (const guint8 * data, guint length)
|
||||||
return crc;
|
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",
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
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_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_start (GstBaseParse * parse);
|
||||||
static gboolean gst_flac_parse_stop (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);
|
GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
|
||||||
|
|
||||||
gobject_class->finalize = gst_flac_parse_finalize;
|
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->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
|
||||||
baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
|
baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
|
||||||
|
@ -180,6 +249,39 @@ gst_flac_parse_class_init (GstFlacParseClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_flac_parse_init (GstFlacParse * flacparse, GstFlacParseClass * klass)
|
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
|
static void
|
||||||
|
@ -659,9 +761,22 @@ gst_flac_parse_get_frame_size (GstFlacParse * flacparse, GstBuffer * buffer,
|
||||||
/* zero padding to byte alignment */
|
/* zero padding to byte alignment */
|
||||||
gst_bit_reader_skip_to_byte (&reader);
|
gst_bit_reader_skip_to_byte (&reader);
|
||||||
|
|
||||||
/* Skip crc-16 for the complete frame */
|
if (flacparse->check_frame_checksums) {
|
||||||
if (!gst_bit_reader_skip (&reader, 16))
|
guint16 actual_crc16, expected_crc16;
|
||||||
goto need_more_data;
|
|
||||||
|
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;
|
*framesize_ret = gst_bit_reader_get_pos (&reader) / 8;
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,9 @@ typedef struct {
|
||||||
struct _GstFlacParse {
|
struct _GstFlacParse {
|
||||||
GstBaseParse parent;
|
GstBaseParse parent;
|
||||||
|
|
||||||
|
/* Properties */
|
||||||
|
gboolean check_frame_checksums;
|
||||||
|
|
||||||
GstFlacParseState state;
|
GstFlacParseState state;
|
||||||
|
|
||||||
gint64 upstream_length;
|
gint64 upstream_length;
|
||||||
|
|
Loading…
Reference in a new issue