Commit a0349ae2 authored by foo86's avatar foo86 Committed by James Almer

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: 's avatarJames Almer <jamrial@gmail.com>
parent 39f7620d
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment