avcodec/dca_parser: improve frame end search

Parse core frame size directly when searching for frame end instead of
using value extracted from previous frame.

Account for unused bits when calculating sync word distance for 14-bit
streams to avoid alias sync detection.

Parse EXSS frame size and skip over EXSS frame to avoid alias sync
detection.

Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
foo86 2016-05-13 12:48:28 +03:00 committed by James Almer
parent 39f7620d76
commit a0349ae27c

View File

@ -47,6 +47,14 @@ typedef struct DCAParseContext {
#define CORE_MARKER(state) ((state >> 16) & 0xFFFFFFFF)
#define EXSS_MARKER(state) (state & 0xFFFFFFFF)
#define STATE_LE(state) (((state & 0xFF00FF00) >> 8) | ((state & 0x00FF00FF) << 8))
#define STATE_14(state) (((state & 0x3FFF0000) >> 8) | ((state & 0x00003FFF) >> 6))
#define CORE_FRAMESIZE(state) (((state >> 4) & 0x3FFF) + 1)
#define EXSS_FRAMESIZE(state) ((state & 0x2000000000) ? \
((state >> 5) & 0xFFFFF) + 1 : \
((state >> 13) & 0x0FFFF) + 1)
/**
* Find the end of the current frame in the bitstream.
* @return the position of the first byte of the next frame, or -1
@ -54,12 +62,13 @@ typedef struct DCAParseContext {
static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
int buf_size)
{
int start_found, i;
int start_found, size, i;
uint64_t state;
ParseContext *pc = &pc1->pc;
start_found = pc->frame_start_found;
state = pc->state64;
size = pc1->size;
i = 0;
if (!start_found) {
@ -80,15 +89,75 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
}
}
}
if (start_found) {
for (; i < buf_size; i++) {
pc1->size++;
size++;
state = (state << 8) | buf[i];
if (start_found == 1) {
switch (pc1->lastmarker) {
case DCA_SYNCWORD_CORE_BE:
if (size == 2) {
pc1->framesize = CORE_FRAMESIZE(state);
start_found = 2;
}
break;
case DCA_SYNCWORD_CORE_LE:
if (size == 2) {
pc1->framesize = CORE_FRAMESIZE(STATE_LE(state));
start_found = 2;
}
break;
case DCA_SYNCWORD_CORE_14B_BE:
if (size == 4) {
pc1->framesize = CORE_FRAMESIZE(STATE_14(state)) * 8 / 14 * 2;
start_found = 2;
}
break;
case DCA_SYNCWORD_CORE_14B_LE:
if (size == 4) {
pc1->framesize = CORE_FRAMESIZE(STATE_14(STATE_LE(state))) * 8 / 14 * 2;
start_found = 2;
}
break;
case DCA_SYNCWORD_SUBSTREAM:
if (size == 6) {
pc1->framesize = EXSS_FRAMESIZE(state);
start_found = 2;
}
break;
default:
av_assert0(0);
}
continue;
}
if (pc1->lastmarker == DCA_SYNCWORD_CORE_BE) {
if (pc1->framesize > size + 2)
continue;
if (start_found == 2 && IS_EXSS_MARKER(state)) {
pc1->framesize = size + 2;
start_found = 3;
continue;
}
if (start_found == 3) {
if (size == pc1->framesize + 4) {
pc1->framesize += EXSS_FRAMESIZE(state);
start_found = 4;
}
continue;
}
}
if (pc1->framesize > size)
continue;
if (IS_MARKER(state) &&
(pc1->lastmarker == CORE_MARKER(state) ||
pc1->lastmarker == DCA_SYNCWORD_SUBSTREAM)) {
if (pc1->framesize > pc1->size)
continue;
pc->frame_start_found = 0;
pc->state64 = -1;
pc1->size = 0;
@ -96,8 +165,10 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
}
}
}
pc->frame_start_found = start_found;
pc->state64 = state;
pc1->size = size;
return END_NOT_FOUND;
}
@ -110,11 +181,11 @@ static av_cold int dca_parse_init(AVCodecParserContext *s)
}
static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration,
int *sample_rate, int *framesize)
int *sample_rate)
{
GetBitContext gb;
uint8_t hdr[12 + AV_INPUT_BUFFER_PADDING_SIZE] = { 0 };
int ret, sample_blocks, sr_code;
int ret, sample_blocks;
if (buf_size < 12)
return AVERROR_INVALIDDATA;
@ -130,13 +201,8 @@ static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration,
return AVERROR_INVALIDDATA;
*duration = 256 * (sample_blocks / 8);
*framesize = get_bits(&gb, 14) + 1;
if (*framesize < 95)
return AVERROR_INVALIDDATA;
skip_bits(&gb, 6);
sr_code = get_bits(&gb, 4);
*sample_rate = avpriv_dca_sample_rates[sr_code];
skip_bits(&gb, 20);
*sample_rate = avpriv_dca_sample_rates[get_bits(&gb, 4)];
if (*sample_rate == 0)
return AVERROR_INVALIDDATA;
@ -164,7 +230,7 @@ static int dca_parse(AVCodecParserContext *s, AVCodecContext *avctx,
}
/* read the duration and sample rate from the frame header */
if (!dca_parse_params(buf, buf_size, &duration, &sample_rate, &pc1->framesize)) {
if (!dca_parse_params(buf, buf_size, &duration, &sample_rate)) {
if (!avctx->sample_rate)
avctx->sample_rate = sample_rate;
s->duration = av_rescale(duration, avctx->sample_rate, sample_rate);