summaryrefslogtreecommitdiff
path: root/libavcodec/dca_parser.c
diff options
context:
space:
mode:
authorfoo86 <foobaz86@gmail.com>2016-05-13 12:48:28 +0300
committerJames Almer <jamrial@gmail.com>2016-05-20 16:36:08 -0300
commita0349ae27c127df8c72de1c30dc4090360ec7ef4 (patch)
tree4ecb10d8a87fe525fd850b70ee3b5b9c8620fc8e /libavcodec/dca_parser.c
parent39f7620d76c7a133535ed7a535f7a74fefa6e435 (diff)
downloadffmpeg-a0349ae27c127df8c72de1c30dc4090360ec7ef4.tar.gz
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>
Diffstat (limited to 'libavcodec/dca_parser.c')
-rw-r--r--libavcodec/dca_parser.c94
1 files changed, 80 insertions, 14 deletions
diff --git a/libavcodec/dca_parser.c b/libavcodec/dca_parser.c
index bde7dfe885..0b09ba5000 100644
--- a/libavcodec/dca_parser.c
+++ b/libavcodec/dca_parser.c
@@ -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);