flacparse: Don't parse the complete FLAC frames but only look for valid frame headers

Thanks to Felipe Contreras for the suggestion. This is partially
based on his patches and makes flacparse more than 3.5 times faster.

Looking for valid frame headers is unlikely to give false positives
because every frame header is at least 9 bytes long, contains a
14 bit sync code and a 8 bit checksum over the first 8 bytes.

Fixes bug #631200.
This commit is contained in:
Sebastian Dröge 2010-10-07 23:28:08 +02:00
parent 1617616516
commit 64407ca94b
2 changed files with 256 additions and 454 deletions

View file

@ -323,7 +323,6 @@ gst_flac_parse_start (GstBaseParse * parse)
flacparse->bps = 0; flacparse->bps = 0;
flacparse->total_samples = 0; flacparse->total_samples = 0;
flacparse->requested_frame_size = 0;
flacparse->offset = GST_CLOCK_TIME_NONE; flacparse->offset = GST_CLOCK_TIME_NONE;
flacparse->blocking_strategy = 0; flacparse->blocking_strategy = 0;
flacparse->block_size = 0; flacparse->block_size = 0;
@ -352,492 +351,311 @@ gst_flac_parse_stop (GstBaseParse * parse)
return TRUE; return TRUE;
} }
static gint typedef enum
gst_flac_parse_get_frame_size (GstFlacParse * flacparse, GstBuffer * buffer,
guint * framesize_ret)
{ {
GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer); FRAME_HEADER_VALID,
guint16 samplerate = 0; FRAME_HEADER_INVALID,
FRAME_HEADER_MORE_DATA
} FrameHeaderCheckReturn;
static FrameHeaderCheckReturn
gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse,
const guint8 * data, guint size, gboolean set, guint16 * block_size_ret)
{
GstBitReader reader = GST_BIT_READER_INIT (data, size);
guint8 blocking_strategy;
guint16 block_size;
guint32 samplerate = 0;
guint64 sample_number;
guint8 channels, bps;
guint8 tmp = 0; guint8 tmp = 0;
gint i;
guint8 channel_assignment = 0;
guint8 actual_crc, expected_crc = 0; guint8 actual_crc, expected_crc = 0;
/* Skip 14 bit sync code */ /* Skip 14 bit sync code */
if (!gst_bit_reader_skip (&reader, 14)) gst_bit_reader_skip_unchecked (&reader, 14);
goto need_more_data;
/* Must be 0 */ /* Must be 0 */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1)) if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
goto need_more_data;
else if (tmp != 0)
goto error; goto error;
/* 0 == fixed block size, 1 == variable block size */ /* 0 == fixed block size, 1 == variable block size */
if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->blocking_strategy, blocking_strategy = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1);
1))
goto need_more_data;
/* block size index, calculation of the real blocksize below */ /* block size index, calculation of the real blocksize below */
if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->block_size, 4)) block_size = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
goto need_more_data; if (block_size == 0)
else if (flacparse->block_size == 0)
goto error; goto error;
/* sample rate index, calculation of the real samplerate below */ /* sample rate index, calculation of the real samplerate below */
if (!gst_bit_reader_get_bits_uint16 (&reader, &samplerate, 4)) samplerate = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
goto need_more_data; if (samplerate == 0x0f)
else if (samplerate == 0x0f)
goto error; goto error;
/* channel assignment */ /* channel assignment */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 4)) { channels = gst_bit_reader_get_bits_uint8_unchecked (&reader, 4);
goto need_more_data; if (channels < 8) {
} else if (tmp < 8) { channels++;
if (flacparse->channels && tmp + 1 != flacparse->channels) } else if (channels <= 10) {
goto error; channels = 2;
else } else if (channels > 10) {
flacparse->channels = tmp + 1;
} else if (tmp <= 10) {
if (flacparse->channels && 2 != flacparse->channels)
goto error;
else
flacparse->channels = 2;
if (tmp == 8)
channel_assignment = 1; /* left-side */
else if (tmp == 9)
channel_assignment = 2; /* right-side */
else
channel_assignment = 3; /* mid-side */
} else if (tmp > 10) {
goto error; goto error;
} }
if (flacparse->channels && flacparse->channels != channels)
goto error;
/* bits per sample */ /* bits per sample */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 3)) { bps = gst_bit_reader_get_bits_uint8_unchecked (&reader, 3);
goto need_more_data; if (bps == 0x03 || bps == 0x07) {
} else if (tmp == 0x03 || tmp == 0x07) {
goto error; goto error;
} else if (tmp == 0 && flacparse->bps == 0) { } else if (bps == 0 && flacparse->bps == 0) {
goto need_streaminfo; goto need_streaminfo;
} else if (tmp == 0x01 && flacparse->bps != 8) { } else if (tmp == 0x01) {
if (flacparse->bps && flacparse->bps != 8) bps = 8;
goto error; } else if (bps == 0x02) {
else bps = 12;
flacparse->bps = 8; } else if (bps == 0x04) {
} else if (tmp == 0x02 && flacparse->bps != 12) { bps = 16;
if (flacparse->bps && flacparse->bps != 12) } else if (bps == 0x05) {
goto error; bps = 20;
else } else if (bps == 0x06) {
flacparse->bps = 12; bps = 24;
} else if (tmp == 0x04 && flacparse->bps != 16) {
if (flacparse->bps && flacparse->bps != 16)
goto error;
else
flacparse->bps = 16;
} else if (tmp == 0x05 && flacparse->bps != 20) {
if (flacparse->bps && flacparse->bps != 20)
goto error;
else
flacparse->bps = 20;
} else if (tmp == 0x06 && flacparse->bps != 24) {
if (flacparse->bps && flacparse->bps != 24)
goto error;
else
flacparse->bps = 24;
} }
if (flacparse->bps && bps != flacparse->bps)
goto error;
/* reserved, must be 0 */ /* reserved, must be 0 */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1)) if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
goto need_more_data;
else if (tmp != 0)
goto error; goto error;
/* read "utf8" encoded sample/frame number */ /* read "utf8" encoded sample/frame number */
{ {
guint len = 0; gint len = 0;
tmp = 1; len = gst_bit_reader_get_bits_uint8_unchecked (&reader, 8);
while (tmp != 0) {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1))
goto need_more_data;
else if (tmp == 1)
len++;
}
if (len == 1)
goto error;
flacparse->sample_number = 0; /* This is slightly faster than a loop */
if (len == 0) { if (!(len & 0x80)) {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 7)) sample_number = len;
goto need_more_data; len = 0;
flacparse->sample_number = tmp; } else if ((len & 0xc0) && !(len & 0x20)) {
} else if ((flacparse->blocking_strategy == 0 && len > 6) || sample_number = len & 0x1f;
(flacparse->blocking_strategy == 1 && len > 7)) { len = 1;
goto error; } else if ((len & 0xe0) && !(len & 0x10)) {
sample_number = len & 0x0f;
len = 2;
} else if ((len & 0xf0) && !(len & 0x08)) {
sample_number = len & 0x07;
len = 3;
} else if ((len & 0xf8) && !(len & 0x04)) {
sample_number = len & 0x03;
len = 4;
} else if ((len & 0xfc) && !(len & 0x02)) {
sample_number = len & 0x01;
len = 5;
} else if ((len & 0xfe) && !(len & 0x01)) {
sample_number = len & 0x0;
len = 6;
} else { } else {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 8 - len - 1)) goto error;
}
if ((blocking_strategy == 0 && len > 5) ||
(blocking_strategy == 1 && len > 6))
goto error;
while (len > 0) {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 8))
goto need_more_data; goto need_more_data;
flacparse->sample_number = tmp; if ((tmp & 0xc0) != 0x80)
len -= 1; goto error;
while (len > 0) { sample_number <<= 6;
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 2)) sample_number |= (tmp & 0x3f);
goto need_more_data; len--;
else if (tmp != 0x02)
goto error;
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 6))
goto need_more_data;
flacparse->sample_number <<= 6;
flacparse->sample_number |= tmp;
len--;
}
} }
} }
/* calculate real blocksize from the blocksize index */ /* calculate real blocksize from the blocksize index */
if (flacparse->block_size == 1) if (block_size == 1)
flacparse->block_size = 192; block_size = 192;
else if (flacparse->block_size <= 5) else if (block_size <= 5)
flacparse->block_size = 576 * (1 << (flacparse->block_size - 2)); block_size = 576 * (1 << (block_size - 2));
else if (flacparse->block_size <= 15) else if (block_size <= 15)
flacparse->block_size = 256 * (1 << (flacparse->block_size - 8)); block_size = 256 * (1 << (block_size - 8));
else if (flacparse->block_size == 6) { else if (block_size == 6) {
if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->block_size, 8)) if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 8))
goto need_more_data; goto need_more_data;
flacparse->block_size++; block_size++;
} else if (flacparse->block_size == 7) { } else if (block_size == 7) {
if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->block_size, 16)) if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 16))
goto need_more_data; goto need_more_data;
flacparse->block_size++; block_size++;
} }
/* calculate the real samplerate from the samplerate index */ /* calculate the real samplerate from the samplerate index */
if (samplerate == 0 && flacparse->samplerate == 0) { if (samplerate == 0 && flacparse->samplerate == 0) {
goto need_streaminfo; goto need_streaminfo;
} else if (samplerate == 1) { } else if (samplerate == 1) {
if (flacparse->samplerate == 0) samplerate = 88200;
flacparse->samplerate = 88200;
else if (flacparse->samplerate != 88200)
goto error;
} else if (samplerate == 2) { } else if (samplerate == 2) {
if (flacparse->samplerate == 0) samplerate = 176400;
flacparse->samplerate = 176400;
else if (flacparse->samplerate != 176400)
goto error;
} else if (samplerate == 3) { } else if (samplerate == 3) {
if (flacparse->samplerate == 0) samplerate = 192000;
flacparse->samplerate = 192000;
else if (flacparse->samplerate != 192000)
goto error;
} else if (samplerate == 4) { } else if (samplerate == 4) {
if (flacparse->samplerate == 0) samplerate = 8000;
flacparse->samplerate = 8000;
else if (flacparse->samplerate != 8000)
goto error;
} else if (samplerate == 5) { } else if (samplerate == 5) {
if (flacparse->samplerate == 0) samplerate = 16000;
flacparse->samplerate = 16000;
else if (flacparse->samplerate != 16000)
goto error;
} else if (samplerate == 6) { } else if (samplerate == 6) {
if (flacparse->samplerate == 0) samplerate = 22050;
flacparse->samplerate = 22050;
else if (flacparse->samplerate != 22050)
goto error;
} else if (samplerate == 7) { } else if (samplerate == 7) {
if (flacparse->samplerate == 0) samplerate = 24000;
flacparse->samplerate = 24000;
else if (flacparse->samplerate != 24000)
goto error;
} else if (samplerate == 8) { } else if (samplerate == 8) {
if (flacparse->samplerate == 0) samplerate = 32000;
flacparse->samplerate = 32000;
else if (flacparse->samplerate != 32000)
goto error;
} else if (samplerate == 9) { } else if (samplerate == 9) {
if (flacparse->samplerate == 0) samplerate = 44100;
flacparse->samplerate = 44100;
else if (flacparse->samplerate != 44100)
goto error;
} else if (samplerate == 10) { } else if (samplerate == 10) {
if (flacparse->samplerate == 0) samplerate = 48000;
flacparse->samplerate = 48000;
else if (flacparse->samplerate != 48000)
goto error;
} else if (samplerate == 11) { } else if (samplerate == 11) {
if (flacparse->samplerate == 0) samplerate = 96000;
flacparse->samplerate = 96000;
else if (flacparse->samplerate != 96000)
goto error;
} else if (samplerate == 12) { } else if (samplerate == 12) {
if (!gst_bit_reader_get_bits_uint16 (&reader, &samplerate, 8)) if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 8))
goto need_more_data; goto need_more_data;
samplerate *= 1000; samplerate *= 1000;
if (flacparse->samplerate == 0)
flacparse->samplerate = samplerate;
else if (flacparse->samplerate != samplerate)
goto error;
} else if (samplerate == 13) { } else if (samplerate == 13) {
if (!gst_bit_reader_get_bits_uint16 (&reader, &samplerate, 16)) if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
goto need_more_data; goto need_more_data;
if (flacparse->samplerate == 0)
flacparse->samplerate = samplerate;
else if (flacparse->samplerate != samplerate)
goto error;
} else if (samplerate == 14) { } else if (samplerate == 14) {
if (!gst_bit_reader_get_bits_uint16 (&reader, &samplerate, 16)) if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
goto need_more_data; goto need_more_data;
samplerate *= 10; samplerate *= 10;
if (flacparse->samplerate == 0)
flacparse->samplerate = samplerate;
else if (flacparse->samplerate != samplerate)
goto error;
} }
if (flacparse->samplerate && flacparse->samplerate != samplerate)
goto error;
/* check crc-8 for the header */ /* check crc-8 for the header */
if (!gst_bit_reader_get_bits_uint8 (&reader, &expected_crc, 8)) if (!gst_bit_reader_get_bits_uint8 (&reader, &expected_crc, 8))
goto need_more_data; goto need_more_data;
actual_crc = actual_crc =
gst_flac_calculate_crc8 (GST_BUFFER_DATA (buffer), gst_flac_calculate_crc8 (data,
(gst_bit_reader_get_pos (&reader) / 8) - 1); (gst_bit_reader_get_pos (&reader) / 8) - 1);
if (actual_crc != expected_crc) if (actual_crc != expected_crc)
goto error; goto error;
/* parse subframes, one subframe per channel */ if (set) {
for (i = 0; i < flacparse->channels; i++) { flacparse->block_size = block_size;
guint8 sf_type; if (!flacparse->samplerate)
guint8 cur_bps; flacparse->samplerate = samplerate;
if (!flacparse->bps)
flacparse->bps = bps;
if (!flacparse->blocking_strategy)
flacparse->blocking_strategy = blocking_strategy;
if (!flacparse->channels)
flacparse->channels = channels;
if (!flacparse->sample_number)
flacparse->sample_number = sample_number;
cur_bps = flacparse->bps; GST_DEBUG_OBJECT (flacparse,
"Parsed frame at offset %" G_GUINT64_FORMAT ":\n" "Block size: %u\n"
/* for mid/side, left/side, right/side the "difference" channel "Sample/Frame number: %" G_GUINT64_FORMAT, flacparse->offset,
* needs and additional bit */ flacparse->block_size, flacparse->sample_number);
if (i == 0 && channel_assignment == 2)
cur_bps++;
else if (i == 1 && (channel_assignment == 1 || channel_assignment == 3))
cur_bps++;
/* must be 0 */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1))
goto need_more_data;
else if (tmp != 0)
goto error;
/* sub frame type */
if (!gst_bit_reader_get_bits_uint8 (&reader, &sf_type, 6))
goto need_more_data;
else if (((sf_type & 0xfe) == 0x02) ||
((sf_type & 0xfc) == 0x04) ||
((sf_type & 0xf8) == 0x08 && (sf_type & 0x07) > 4) ||
((sf_type & 0xf0) == 0x10))
goto error;
/* wasted bits per sample, if 1 the value follows unary coded */
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1)) {
goto need_more_data;
} else if (tmp != 0) {
guint wasted = 1;
tmp = 0;
while (tmp == 0) {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1))
goto need_more_data;
else
wasted++;
}
cur_bps -= wasted;
}
/* subframe type: constant */
if (sf_type == 0x00) {
if (!gst_bit_reader_skip (&reader, cur_bps))
goto need_more_data;
/* subframe type: verbatim */
} else if (sf_type == 0x01) {
if (!gst_bit_reader_skip (&reader, cur_bps * flacparse->block_size))
goto need_more_data;
/* subframe type: LPC or fixed */
} else {
guint8 residual_type;
guint order = 0;
guint16 partition_order = 0;
guint j;
/* Skip warm-up samples for fixed subframe and calculate order */
if ((sf_type & 0xf8) == 0x08) {
order = sf_type & 0x07;
g_assert (order <= 4);
if (!gst_bit_reader_skip (&reader, cur_bps * order))
goto need_more_data;
/* Skip warm-up samples for LPC subframe, get parameters and calculate order */
} else if ((sf_type & 0xe0) == 0x20) {
guint8 prec;
order = (sf_type & 0x1f) + 1;
/* warm-up samples */
if (!gst_bit_reader_skip (&reader, cur_bps * order))
goto need_more_data;
/* LPC coefficient precision */
if (!gst_bit_reader_get_bits_uint8 (&reader, &prec, 4))
goto need_more_data;
else if (prec == 0x0f)
goto error;
prec++;
/* LPC coefficient shift */
if (!gst_bit_reader_skip (&reader, 5))
goto need_more_data;
/* LPC coefficients */
if (!gst_bit_reader_skip (&reader, order * prec))
goto need_more_data;
} else {
g_assert_not_reached ();
}
/* residual type: 0 == rice, 1 == rice2 */
if (!gst_bit_reader_get_bits_uint8 (&reader, &residual_type, 2))
goto need_more_data;
if (residual_type & 0x02)
goto error;
/* partition order */
if (!gst_bit_reader_get_bits_uint16 (&reader, &partition_order, 4))
goto need_more_data;
partition_order = 1 << partition_order;
/* 2^partition_order partitions */
for (j = 0; j < partition_order; j++) {
guint samples;
guint8 rice_parameter;
/* calculate number of samples for the current partition */
if (partition_order == 1) {
samples = flacparse->block_size - order;
} else if (j != 0) {
samples = flacparse->block_size / partition_order;
} else {
samples = flacparse->block_size / partition_order - order;
}
/* rice parameter */
if (!gst_bit_reader_get_bits_uint8 (&reader, &rice_parameter,
(residual_type == 0) ? 4 : 5))
goto need_more_data;
/* if rice parameter has all bits set the samples follow unencoded with the number of bits
* per sample in the following 5 bits */
if ((residual_type == 0 && rice_parameter == 0x0f)
|| (residual_type == 1 && rice_parameter == 0x1f)) {
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 5))
goto need_more_data;
if (!gst_bit_reader_skip (&reader, tmp * samples))
goto need_more_data;
} else {
guint k;
/* read the rice encoded samples */
for (k = 0; k < samples; k++) {
tmp = 0;
while (tmp == 0)
if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 1))
goto need_more_data;
if (!gst_bit_reader_skip (&reader, rice_parameter))
goto need_more_data;
}
}
}
}
} }
/* zero padding to byte alignment */ if (block_size_ret)
gst_bit_reader_skip_to_byte (&reader); *block_size_ret = block_size;
if (flacparse->check_frame_checksums) { return FRAME_HEADER_VALID;
guint16 actual_crc16, expected_crc16 = 0;
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;
GST_DEBUG_OBJECT (flacparse, "Parsed frame at offset %" G_GUINT64_FORMAT ":\n"
"Frame size: %u\n"
"Block size: %u\n"
"Sample/Frame number: %" G_GUINT64_FORMAT,
flacparse->offset, *framesize_ret,
flacparse->block_size, flacparse->sample_number);
return 0;
need_more_data:
{
gint max;
/* not enough, if that was all available, give up on frame */
if (G_UNLIKELY (gst_base_parse_get_drain (GST_BASE_PARSE_CAST (flacparse))))
goto eos;
/* otherwise, ask for some more */
max = flacparse->max_framesize;
if (!max)
max = 1 << 24;
flacparse->requested_frame_size
= MIN (GST_BUFFER_SIZE (buffer) + 4096, max);
if (flacparse->requested_frame_size > GST_BUFFER_SIZE (buffer)) {
GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes",
flacparse->requested_frame_size);
return flacparse->requested_frame_size;
} else {
GST_DEBUG_OBJECT (flacparse, "Giving up on invalid frame (%d bytes)",
GST_BUFFER_SIZE (buffer));
return -1;
}
}
need_streaminfo: need_streaminfo:
{ GST_ERROR_OBJECT (flacparse, "Need STREAMINFO");
GST_ERROR_OBJECT (flacparse, "Need STREAMINFO"); return FRAME_HEADER_INVALID;
return -2;
}
eos:
{
GST_WARNING_OBJECT (flacparse, "EOS");
return -1;
}
error: error:
{ return FRAME_HEADER_INVALID;
GST_WARNING_OBJECT (flacparse, "Invalid frame");
return -1; need_more_data:
} return FRAME_HEADER_MORE_DATA;
} }
static gboolean static gboolean
gst_flac_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer, gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, GstBuffer * buffer,
guint * framesize, gint * skipsize) guint * ret)
{
const guint8 *data;
guint max, size, remaining;
guint i, search_start, search_end;
FrameHeaderCheckReturn header_ret;
guint16 block_size;
data = GST_BUFFER_DATA (buffer);
size = GST_BUFFER_SIZE (buffer);
if (size <= flacparse->min_framesize)
goto need_more;
header_ret =
gst_flac_parse_frame_header_is_valid (flacparse, data, size, TRUE,
&block_size);
if (header_ret == FRAME_HEADER_INVALID) {
*ret = 0;
return FALSE;
} else if (header_ret == FRAME_HEADER_MORE_DATA) {
goto need_more;
}
search_start = MAX (2, flacparse->min_framesize);
search_end = MIN (size, flacparse->max_framesize + 9 + 2);
search_end -= 2;
remaining = size;
for (i = search_start; i < search_end; i++, remaining--) {
if ((GST_READ_UINT16_BE (data + i) & 0xfffe) == 0xfff8) {
header_ret =
gst_flac_parse_frame_header_is_valid (flacparse, data + i, remaining,
FALSE, NULL);
if (header_ret == FRAME_HEADER_VALID) {
if (flacparse->check_frame_checksums) {
guint16 actual_crc = gst_flac_calculate_crc16 (data, i - 2);
guint16 expected_crc = GST_READ_UINT16_BE (data + i - 2);
if (actual_crc != expected_crc)
continue;
}
*ret = i;
flacparse->block_size = block_size;
return TRUE;
} else if (header_ret == FRAME_HEADER_MORE_DATA) {
goto need_more;
}
}
}
/* For the last frame check the CRC16 instead of the following
* header, which does not exist */
if (G_UNLIKELY (gst_base_parse_get_drain (GST_BASE_PARSE (flacparse)))) {
guint16 actual_crc = gst_flac_calculate_crc16 (data, size - 2);
guint16 expected_crc = GST_READ_UINT16_BE (data + size - 2);
if (actual_crc == expected_crc) {
*ret = size;
flacparse->block_size = block_size;
return TRUE;
}
}
need_more:
max = flacparse->max_framesize + 16;
if (max == 16)
max = 1 << 24;
*ret = MIN (size + 4096, max);
return FALSE;
}
static gboolean
gst_flac_parse_check_valid_frame (GstBaseParse * parse,
GstBuffer * buffer, guint * framesize, gint * skipsize)
{ {
GstFlacParse *flacparse = GST_FLAC_PARSE (parse); GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
const guint8 *data = GST_BUFFER_DATA (buffer); const guint8 *data = GST_BUFFER_DATA (buffer);
@ -853,8 +671,7 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer,
} else if (data[0] == 0xff && (data[1] >> 2) == 0x3e) { } else if (data[0] == 0xff && (data[1] >> 2) == 0x3e) {
GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC"); GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC");
/* Minimal size of a frame header */ /* Minimal size of a frame header */
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 16); gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 9);
flacparse->requested_frame_size = 16;
flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS; flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS;
*skipsize = 0; *skipsize = 0;
return FALSE; return FALSE;
@ -869,8 +686,9 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer,
*framesize = size; *framesize = size;
return TRUE; return TRUE;
} else { } else {
if (data[0] == 0xff && (data[1] >> 2) == 0x3e) { if ((GST_READ_UINT16_BE (data) & 0xfffe) == 0xfff8) {
gint ret = 0; gboolean ret;
guint next;
flacparse->offset = GST_BUFFER_OFFSET (buffer); flacparse->offset = GST_BUFFER_OFFSET (buffer);
flacparse->blocking_strategy = 0; flacparse->blocking_strategy = 0;
@ -878,49 +696,36 @@ gst_flac_parse_check_valid_frame (GstBaseParse * parse, GstBuffer * buffer,
flacparse->sample_number = 0; flacparse->sample_number = 0;
GST_DEBUG_OBJECT (flacparse, "Found sync code"); GST_DEBUG_OBJECT (flacparse, "Found sync code");
ret = gst_flac_parse_get_frame_size (flacparse, buffer, framesize); ret = gst_flac_parse_frame_is_valid (flacparse, buffer, &next);
if (ret == 0) { if (ret) {
ret = *framesize; *framesize = next;
/* if not in sync, also check for next frame header */
if (!gst_base_parse_get_sync (parse) &&
!gst_base_parse_get_drain (parse)) {
GST_DEBUG_OBJECT (flacparse, "Resyncing; checking next sync code");
if (GST_BUFFER_SIZE (buffer) >= ret + 2) {
if (data[ret] == 0xff && (data[ret + 1] >> 2) == 0x3e) {
GST_DEBUG_OBJECT (flacparse, "Found next sync code");
return TRUE;
} else {
GST_DEBUG_OBJECT (flacparse,
"No next sync code, rejecting frame");
return FALSE;
}
} else {
/* request more data for next sync */
GST_DEBUG_OBJECT (flacparse, "... but not enough data");
ret += 2;
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), ret);
flacparse->requested_frame_size = ret;
return FALSE;
}
}
return TRUE; return TRUE;
} else if (ret == -1) { } else {
return FALSE; /* If we're at EOS and the frame was not valid, drop it! */
} else if (ret == -2) { if (G_UNLIKELY (gst_base_parse_get_drain (parse))) {
GST_ELEMENT_ERROR (flacparse, STREAM, FORMAT, (NULL), GST_WARNING_OBJECT (flacparse, "EOS");
("Need STREAMINFO for parsing")); return FALSE;
return FALSE; }
} else if (ret > 0) {
*skipsize = 0; if (next == 0) {
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), ret); } else if (next > GST_BUFFER_SIZE (buffer)) {
flacparse->requested_frame_size = ret; GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next);
return FALSE; *skipsize = 0;
gst_base_parse_set_min_frame_size (parse, next);
return FALSE;
} else {
GST_ERROR_OBJECT (flacparse,
"Giving up on invalid frame (%d bytes)",
GST_BUFFER_SIZE (buffer));
return FALSE;
}
} }
} else { } else {
GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer); GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
gint off; gint off;
off = gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000, off =
gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000,
0, GST_BUFFER_SIZE (buffer)); 0, GST_BUFFER_SIZE (buffer));
if (off > 0) { if (off > 0) {
@ -1286,13 +1091,13 @@ gst_flac_parse_generate_headers (GstFlacParse * flacparse)
header[0] = 0x84; /* is_last = 1; type = 4; */ header[0] = 0x84; /* is_last = 1; type = 4; */
vorbiscomment = vorbiscomment =
gst_tag_list_to_vorbiscomment_buffer (taglist, header, sizeof (header), gst_tag_list_to_vorbiscomment_buffer (taglist, header,
NULL); sizeof (header), NULL);
gst_tag_list_free (taglist); gst_tag_list_free (taglist);
/* Get rid of framing bit */ /* Get rid of framing bit */
if (GST_BUFFER_DATA (vorbiscomment)[GST_BUFFER_SIZE (vorbiscomment) - 1] == if (GST_BUFFER_DATA (vorbiscomment)[GST_BUFFER_SIZE (vorbiscomment) -
1) { 1] == 1) {
GstBuffer *sub; GstBuffer *sub;
sub = sub =
@ -1384,9 +1189,8 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
/* Minimal size of a frame header */ /* Minimal size of a frame header */
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (16, gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
flacparse->min_framesize)); flacparse->min_framesize));
flacparse->requested_frame_size = MAX (16, flacparse->min_framesize);
flacparse->state = GST_FLAC_PARSE_STATE_DATA; flacparse->state = GST_FLAC_PARSE_STATE_DATA;
/* DROPPED because we pushed all headers manually already */ /* DROPPED because we pushed all headers manually already */
@ -1398,12 +1202,13 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
} }
} else { } else {
if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) { if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) {
gint ret; FrameHeaderCheckReturn ret;
guint framesize;
flacparse->offset = GST_BUFFER_OFFSET (buffer); flacparse->offset = GST_BUFFER_OFFSET (buffer);
ret = gst_flac_parse_get_frame_size (flacparse, buffer, &framesize); ret =
if (ret != 0) { gst_flac_parse_frame_header_is_valid (flacparse,
GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE, NULL);
if (ret != FRAME_HEADER_VALID) {
GST_ERROR_OBJECT (flacparse, GST_ERROR_OBJECT (flacparse,
"Baseclass didn't provide a complete frame"); "Baseclass didn't provide a complete frame");
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
@ -1455,9 +1260,8 @@ gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer); GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
/* Minimal size of a frame header */ /* Minimal size of a frame header */
gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (16, gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
flacparse->min_framesize)); flacparse->min_framesize));
flacparse->requested_frame_size = MAX (16, flacparse->min_framesize);
flacparse->offset = -1; flacparse->offset = -1;
flacparse->blocking_strategy = 0; flacparse->blocking_strategy = 0;

View file

@ -69,8 +69,6 @@ struct _GstFlacParse {
guint8 bps; guint8 bps;
guint64 total_samples; guint64 total_samples;
guint requested_frame_size;
/* Current frame */ /* Current frame */
guint64 offset; guint64 offset;
guint8 blocking_strategy; guint8 blocking_strategy;