FFmpeg/libavformat/dtsdec.c
foo86 3b7ec920af avformat/dtsdec: switch to common frame header parsing function
This makes probing for regular DTS more strict because more header
fields are checked and values not supported by decoder are now rejected.

Also fixes an issue original code had with 14-bit streams: 96 bits of
header were expected, however only 84 bits were converted, which was not
enough to parse LFE flag.

Signed-off-by: James Almer <jamrial@gmail.com>
2017-07-18 21:04:57 -03:00

142 lines
4.5 KiB
C

/*
* RAW DTS demuxer
* Copyright (c) 2008 Benjamin Larsson
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/crc.h"
#include "libavcodec/bytestream.h"
#include "libavcodec/dca.h"
#include "libavcodec/dca_syncwords.h"
#include "libavcodec/get_bits.h"
#include "avformat.h"
#include "rawdec.h"
static int dts_probe(AVProbeData *p)
{
const uint8_t *buf, *bufp;
uint32_t state = -1;
int markers[4*16] = {0};
int exss_markers = 0, exss_nextpos = 0;
int sum, max, pos, ret, i;
int64_t diff = 0;
uint8_t hdr[DCA_CORE_FRAME_HEADER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE] = { 0 };
for (pos = FFMIN(4096, p->buf_size); pos < p->buf_size - 2; pos += 2) {
int marker, wide_hdr, hdr_size, framesize;
DCACoreFrameHeader h;
GetBitContext gb;
bufp = buf = p->buf + pos;
state = (state << 16) | bytestream_get_be16(&bufp);
if (pos >= 4)
diff += FFABS(((int16_t)AV_RL16(buf)) - (int16_t)AV_RL16(buf-4));
/* extension substream (EXSS) */
if (state == DCA_SYNCWORD_SUBSTREAM) {
if (pos < exss_nextpos)
continue;
init_get_bits(&gb, buf - 2, 96);
skip_bits_long(&gb, 42);
wide_hdr = get_bits1(&gb);
hdr_size = get_bits(&gb, 8 + 4 * wide_hdr) + 1;
framesize = get_bits(&gb, 16 + 4 * wide_hdr) + 1;
if (hdr_size & 3 || framesize & 3)
continue;
if (hdr_size < 16 || framesize < hdr_size)
continue;
if (pos - 2 + hdr_size > p->buf_size)
continue;
if (av_crc(av_crc_get_table(AV_CRC_16_CCITT), 0xffff, buf + 3, hdr_size - 5))
continue;
if (pos == exss_nextpos)
exss_markers++;
else
exss_markers = FFMAX(1, exss_markers - 1);
exss_nextpos = pos + framesize;
continue;
}
/* regular bitstream */
if (state == DCA_SYNCWORD_CORE_BE &&
(bytestream_get_be16(&bufp) & 0xFC00) == 0xFC00)
marker = 0;
else if (state == DCA_SYNCWORD_CORE_LE &&
(bytestream_get_be16(&bufp) & 0x00FC) == 0x00FC)
marker = 1;
/* 14 bits big-endian bitstream */
else if (state == DCA_SYNCWORD_CORE_14B_BE &&
(bytestream_get_be16(&bufp) & 0xFFF0) == 0x07F0)
marker = 2;
/* 14 bits little-endian bitstream */
else if (state == DCA_SYNCWORD_CORE_14B_LE &&
(bytestream_get_be16(&bufp) & 0xF0FF) == 0xF007)
marker = 3;
else
continue;
if ((ret = avpriv_dca_convert_bitstream(buf - 2, DCA_CORE_FRAME_HEADER_SIZE,
hdr, DCA_CORE_FRAME_HEADER_SIZE)) < 0)
continue;
if (init_get_bits8(&gb, hdr, ret) < 0)
continue;
if (avpriv_dca_parse_core_frame_header(&gb, &h) < 0)
continue;
marker += 4 * h.sr_code;
markers[marker] ++;
}
if (exss_markers > 3)
return AVPROBE_SCORE_EXTENSION + 1;
sum = max = 0;
for (i=0; i<FF_ARRAY_ELEMS(markers); i++) {
sum += markers[i];
if (markers[max] < markers[i])
max = i;
}
if (markers[max] > 3 && p->buf_size / markers[max] < 32*1024 &&
markers[max] * 4 > sum * 3 &&
diff / p->buf_size > 200)
return AVPROBE_SCORE_EXTENSION + 1;
return 0;
}
AVInputFormat ff_dts_demuxer = {
.name = "dts",
.long_name = NULL_IF_CONFIG_SMALL("raw DTS"),
.read_probe = dts_probe,
.read_header = ff_raw_audio_read_header,
.read_packet = ff_raw_read_partial_packet,
.flags = AVFMT_GENERIC_INDEX,
.extensions = "dts",
.raw_codec_id = AV_CODEC_ID_DTS,
};