diff options
Diffstat (limited to 'libavcodec/mlpdec.c')
-rw-r--r-- | libavcodec/mlpdec.c | 56 |
1 files changed, 41 insertions, 15 deletions
diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index 73f51c5e40..610cfece21 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -2,20 +2,20 @@ * MLP decoder * Copyright (c) 2007-2008 Ian Caulfield * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * 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. * - * Libav is distributed in the hope that it will be useful, + * 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 Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -131,6 +131,9 @@ typedef struct MLPDecodeContext { /// Index of the last substream to decode - further substreams are skipped. uint8_t max_decoded_substream; + /// Stream needs channel reordering to comply with FFmpeg's channel order + uint8_t needs_reordering; + /// number of PCM samples contained in each frame int access_unit_size; /// next power of two above the number of samples in each frame @@ -371,8 +374,17 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) else m->substream[2].ch_layout = mh.channel_layout_thd_stream1; m->substream[substr].ch_layout = mh.channel_layout_thd_stream1; + + if (m->avctx->channels<=2 && m->substream[substr].ch_layout == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) { + av_log(m->avctx, AV_LOG_DEBUG, "Mono stream with 2 substreams, ignoring 2nd\n"); + m->max_decoded_substream = 0; + if (m->avctx->channels==2) + m->avctx->channel_layout = AV_CH_LAYOUT_STEREO; + } } + m->needs_reordering = mh.channel_arrangement >= 18 && mh.channel_arrangement <= 20; + return 0; } @@ -418,7 +430,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, if (max_matrix_channel > std_max_matrix_channel) { av_log(m->avctx, AV_LOG_ERROR, "Max matrix channel cannot be greater than %d.\n", - max_matrix_channel); + std_max_matrix_channel); return AVERROR_INVALIDDATA; } @@ -430,11 +442,11 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, /* This should happen for TrueHD streams with >6 channels and MLP's noise * type. It is not yet known if this is allowed. */ - if (s->max_channel > MAX_MATRIX_CHANNEL_MLP && !s->noise_type) { + if (max_channel > MAX_MATRIX_CHANNEL_MLP && !s->noise_type) { avpriv_request_sample(m->avctx, "%d channels (more than the " "maximum supported by the decoder)", - s->max_channel + 2); + max_channel + 2); return AVERROR_PATCHWELCOME; } @@ -496,7 +508,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, ch_assign = av_get_channel_layout_channel_index(s->ch_layout, channel); } - if (ch_assign > s->max_matrix_channel) { + if ((unsigned)ch_assign > s->max_matrix_channel) { avpriv_request_sample(m->avctx, "Assignment of matrix channel %d to invalid output channel %d", ch, ch_assign); @@ -536,6 +548,20 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, if (substr == m->max_decoded_substream) { m->avctx->channels = s->max_matrix_channel + 1; m->avctx->channel_layout = s->ch_layout; + + if (m->avctx->codec_id == AV_CODEC_ID_MLP && m->needs_reordering) { + if (m->avctx->channel_layout == (AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY) || + m->avctx->channel_layout == AV_CH_LAYOUT_5POINT0_BACK) { + int i = s->ch_assign[4]; + s->ch_assign[4] = s->ch_assign[3]; + s->ch_assign[3] = s->ch_assign[2]; + s->ch_assign[2] = i; + } else if (m->avctx->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) { + FFSWAP(int, s->ch_assign[2], s->ch_assign[4]); + FFSWAP(int, s->ch_assign[3], s->ch_assign[5]); + } + } + } return 0; @@ -554,7 +580,7 @@ static int read_filter_params(MLPDecodeContext *m, GetBitContext *gbp, int i, order; // Filter is 0 for FIR, 1 for IIR. - assert(filter < 2); + av_assert0(filter < 2); if (m->filter_changed[channel][filter]++ > 1) { av_log(m->avctx, AV_LOG_ERROR, "Filters may change only once per access unit.\n"); @@ -609,7 +635,7 @@ static int read_filter_params(MLPDecodeContext *m, GetBitContext *gbp, /* TODO: Check validity of state data. */ for (i = 0; i < order; i++) - fp->state[i] = get_sbits(gbp, state_bits) << state_shift; + fp->state[i] = state_bits ? get_sbits(gbp, state_bits) << state_shift : 0; } } @@ -728,6 +754,7 @@ static int read_channel_params(MLPDecodeContext *m, unsigned int substr, if (cp->huff_lsbs > 24) { av_log(m->avctx, AV_LOG_ERROR, "Invalid huff_lsbs.\n"); + cp->huff_lsbs = 0; return AVERROR_INVALIDDATA; } @@ -754,7 +781,7 @@ static int read_decoding_params(MLPDecodeContext *m, GetBitContext *gbp, if (get_bits1(gbp)) { s->blocksize = get_bits(gbp, 9); if (s->blocksize < 8 || s->blocksize > m->access_unit_size) { - av_log(m->avctx, AV_LOG_ERROR, "Invalid blocksize."); + av_log(m->avctx, AV_LOG_ERROR, "Invalid blocksize.\n"); s->blocksize = 0; return AVERROR_INVALIDDATA; } @@ -998,10 +1025,8 @@ static int output_data(MLPDecodeContext *m, unsigned int substr, /* get output buffer */ frame->nb_samples = s->blockpos; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - } data_32 = (int32_t *)frame->data[0]; data_16 = (int16_t *)frame->data[0]; @@ -1221,6 +1246,7 @@ error: return AVERROR_INVALIDDATA; } +#if CONFIG_MLP_DECODER AVCodec ff_mlp_decoder = { .name = "mlp", .type = AVMEDIA_TYPE_AUDIO, @@ -1231,7 +1257,7 @@ AVCodec ff_mlp_decoder = { .capabilities = CODEC_CAP_DR1, .long_name = NULL_IF_CONFIG_SMALL("MLP (Meridian Lossless Packing)"), }; - +#endif #if CONFIG_TRUEHD_DECODER AVCodec ff_truehd_decoder = { .name = "truehd", |