diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index 075227f302..0c7d4a2c7a 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -119,6 +119,23 @@ static uint64_t truehd_layout(int chanmap) return layout; } +static int ff_mlp_get_major_sync_size(const uint8_t * buf, int bufsize) +{ + int has_extension, extensions = 0; + int size = 28; + if (bufsize < 28) + return -1; + + if (AV_RB32(buf) == 0xf8726fba) { + has_extension = buf[25] & 1; + if (has_extension) { + extensions = buf[26] >> 4; + size += 2 + extensions * 2; + } + } + return size; +} + /** Read a major sync info header - contains high level information about * the stream - sample rate, channel arrangement etc. Most of this * information is not actually necessary for decoding, only for playback. @@ -127,18 +144,19 @@ static uint64_t truehd_layout(int chanmap) int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) { - int ratebits, channel_arrangement; + int ratebits, channel_arrangement, header_size; uint16_t checksum; assert(get_bits_count(gb) == 0); - if (gb->size_in_bits < 28 << 3) { + header_size = ff_mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); + if (header_size < 0 || gb->size_in_bits < header_size << 3) { av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); return -1; } - checksum = ff_mlp_checksum16(gb->buffer, 26); - if (checksum != AV_RL16(gb->buffer+26)) { + checksum = ff_mlp_checksum16(gb->buffer, header_size - 2); + if (checksum != AV_RL16(gb->buffer+header_size-2)) { av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); return AVERROR_INVALIDDATA; } @@ -147,6 +165,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) return AVERROR_INVALIDDATA; mh->stream_type = get_bits(gb, 8); + mh->header_size = header_size; if (mh->stream_type == 0xbb) { mh->group1_bits = mlp_quants[get_bits(gb, 4)]; @@ -197,7 +216,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) mh->num_substreams = get_bits(gb, 4); - skip_bits_long(gb, 4 + 11 * 8); + skip_bits_long(gb, 4 + (header_size - 17) * 8); return 0; } diff --git a/libavcodec/mlp_parser.h b/libavcodec/mlp_parser.h index 7530facebf..06ab421ba9 100644 --- a/libavcodec/mlp_parser.h +++ b/libavcodec/mlp_parser.h @@ -32,6 +32,7 @@ typedef struct MLPHeaderInfo { int stream_type; ///< 0xBB for MLP, 0xBA for TrueHD + int header_size; ///< Size of the major sync header, in bytes int group1_bits; ///< The bit depth of the first substream int group2_bits; ///< Bit depth of the second substream (MLP only) diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index 624efc152e..8f1b6f42c6 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -132,6 +132,9 @@ typedef struct MLPDecodeContext { /// Current access unit being read has a major sync. int is_major_sync_unit; + /// Size of the major sync unit, in bytes + int major_sync_header_size; + /// Set if a valid major sync block has been read. Otherwise no decoding is possible. uint8_t params_valid; @@ -346,6 +349,8 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) return AVERROR_PATCHWELCOME; } + m->major_sync_header_size = mh.header_size; + m->access_unit_size = mh.access_unit_size; m->access_unit_size_pow2 = mh.access_unit_size_pow2; @@ -1105,7 +1110,7 @@ static int read_access_unit(AVCodecContext *avctx, void* data, if (read_major_sync(m, &gb) < 0) goto error; m->is_major_sync_unit = 1; - header_size += 28; + header_size += m->major_sync_header_size; } if (!m->params_valid) {