X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fmlp_parser.c;h=e8fb4f5f4d95a0ebb7dd0c07ee825fbffee966b0;hb=bb198c4997d5036f3bf91de51e44f807115677d0;hp=1879e0044f326d03fd9da990fb4a4c696059bfab;hpb=0a9efe4c6eb48bf863e2e630b3ad907a198961c5;p=ffmpeg diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index 1879e0044f3..e8fb4f5f4d9 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -26,8 +26,9 @@ #include +#include "libavutil/channel_layout.h" #include "libavutil/crc.h" -#include "libavutil/audioconvert.h" +#include "libavutil/internal.h" #include "get_bits.h" #include "parser.h" #include "mlp_parser.h" @@ -83,10 +84,10 @@ static const uint64_t thd_layout[13] = { AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT, // LRrs AV_CH_BACK_CENTER, // Cs AV_CH_TOP_CENTER, // Ts - AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRsd + AV_CH_SURROUND_DIRECT_LEFT|AV_CH_SURROUND_DIRECT_RIGHT, // LRsd AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT, // LRw AV_CH_TOP_FRONT_CENTER, // Cvh - AV_CH_LOW_FREQUENCY // LFE2 + AV_CH_LOW_FREQUENCY_2, // LFE2 }; static int mlp_samplerate(int in) @@ -118,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. @@ -126,18 +144,19 @@ static uint64_t truehd_layout(int chanmap) int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) { - int ratebits; + 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; } @@ -146,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)]; @@ -157,7 +177,9 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) skip_bits(gb, 11); - mh->channels_mlp = get_bits(gb, 5); + channel_arrangement = get_bits(gb, 5); + mh->channels_mlp = mlp_channels[channel_arrangement]; + mh->channel_layout_mlp = mlp_layout[channel_arrangement]; } else if (mh->stream_type == 0xba) { mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? mh->group2_bits = 0; @@ -166,13 +188,20 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) mh->group1_samplerate = mlp_samplerate(ratebits); mh->group2_samplerate = 0; - skip_bits(gb, 8); + skip_bits(gb, 4); + + mh->channel_modifier_thd_stream0 = get_bits(gb, 2); + mh->channel_modifier_thd_stream1 = get_bits(gb, 2); - mh->channels_thd_stream1 = get_bits(gb, 5); + channel_arrangement = get_bits(gb, 5); + mh->channels_thd_stream1 = truehd_channels(channel_arrangement); + mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement); - skip_bits(gb, 2); + mh->channel_modifier_thd_stream2 = get_bits(gb, 2); - mh->channels_thd_stream2 = get_bits(gb, 13); + channel_arrangement = get_bits(gb, 13); + mh->channels_thd_stream2 = truehd_channels(channel_arrangement); + mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement); } else return AVERROR_INVALIDDATA; @@ -187,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; } @@ -316,16 +345,33 @@ static int mlp_parse(AVCodecParserContext *s, if (mh.stream_type == 0xbb) { /* MLP stream */ - avctx->channels = mlp_channels[mh.channels_mlp]; - avctx->channel_layout = mlp_layout[mh.channels_mlp]; + if (avctx->request_channel_layout && + (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == + avctx->request_channel_layout && + mh.num_substreams > 1) { + avctx->channels = 2; + avctx->channel_layout = AV_CH_LAYOUT_STEREO; + } else { + avctx->channels = mh.channels_mlp; + avctx->channel_layout = mh.channel_layout_mlp; + } } else { /* mh.stream_type == 0xba */ /* TrueHD stream */ - if (mh.channels_thd_stream2) { - avctx->channels = truehd_channels(mh.channels_thd_stream2); - avctx->channel_layout = truehd_layout(mh.channels_thd_stream2); + if (avctx->request_channel_layout && + (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == + avctx->request_channel_layout && + mh.num_substreams > 1) { + avctx->channels = 2; + avctx->channel_layout = AV_CH_LAYOUT_STEREO; + } else if (!mh.channels_thd_stream2 || + (avctx->request_channel_layout && + (avctx->request_channel_layout & mh.channel_layout_thd_stream1) == + avctx->request_channel_layout)) { + avctx->channels = mh.channels_thd_stream1; + avctx->channel_layout = mh.channel_layout_thd_stream1; } else { - avctx->channels = truehd_channels(mh.channels_thd_stream1); - avctx->channel_layout = truehd_layout(mh.channels_thd_stream1); + avctx->channels = mh.channels_thd_stream2; + avctx->channel_layout = mh.channel_layout_thd_stream2; } } @@ -346,7 +392,7 @@ lost_sync: } AVCodecParser ff_mlp_parser = { - .codec_ids = { CODEC_ID_MLP, CODEC_ID_TRUEHD }, + .codec_ids = { AV_CODEC_ID_MLP, AV_CODEC_ID_TRUEHD }, .priv_data_size = sizeof(MLPParseContext), .parser_init = mlp_init, .parser_parse = mlp_parse,