From 90fcac0e95b7d266c148a86506f301a2072d9de3 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Sun, 21 Oct 2012 17:02:28 -0400 Subject: [PATCH] flacdec: allow mid-stream channel layout change Although the libFLAC decoder cannot handle such a change, it is allowed by the spec and could potentially occur with live streams. --- libavcodec/flac.c | 19 +++++++++++++++++++ libavcodec/flac.h | 3 +++ libavcodec/flac_parser.c | 1 + libavcodec/flacdec.c | 27 +++++++++------------------ 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/libavcodec/flac.c b/libavcodec/flac.c index d624beb61f..07da702e94 100644 --- a/libavcodec/flac.c +++ b/libavcodec/flac.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/audioconvert.h" #include "libavutil/crc.h" #include "libavutil/log.h" #include "bytestream.h" @@ -28,6 +29,15 @@ static const int8_t sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 }; +static const int64_t flac_channel_layouts[6] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_5POINT0, + AV_CH_LAYOUT_5POINT1 +}; + static int64_t get_utf8(GetBitContext *gb) { int64_t val; @@ -181,6 +191,14 @@ int avpriv_flac_is_extradata_valid(AVCodecContext *avctx, return 1; } +void ff_flac_set_channel_layout(AVCodecContext *avctx) +{ + if (avctx->channels <= FF_ARRAY_ELEMS(flac_channel_layouts)) + avctx->channel_layout = flac_channel_layouts[avctx->channels - 1]; + else + avctx->channel_layout = 0; +} + void avpriv_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, const uint8_t *buffer) { @@ -205,6 +223,7 @@ void avpriv_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo * avctx->channels = s->channels; avctx->sample_rate = s->samplerate; avctx->bits_per_raw_sample = s->bps; + ff_flac_set_channel_layout(avctx); s->samples = get_bits_long(&gb, 32) << 4; s->samples |= get_bits(&gb, 4); diff --git a/libavcodec/flac.h b/libavcodec/flac.h index 55bacea9ea..63f41c25a4 100644 --- a/libavcodec/flac.h +++ b/libavcodec/flac.h @@ -137,4 +137,7 @@ int ff_flac_get_max_frame_size(int blocksize, int ch, int bps); */ int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, FLACFrameInfo *fi, int log_level_offset); + +void ff_flac_set_channel_layout(AVCodecContext *avctx); + #endif /* AVCODEC_FLAC_H */ diff --git a/libavcodec/flac_parser.c b/libavcodec/flac_parser.c index 6c8c04675c..f0a37f310e 100644 --- a/libavcodec/flac_parser.c +++ b/libavcodec/flac_parser.c @@ -459,6 +459,7 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf, fpc->avctx->sample_rate = header->fi.samplerate; fpc->avctx->channels = header->fi.channels; + ff_flac_set_channel_layout(fpc->avctx); fpc->pc->duration = header->fi.blocksize; *poutbuf = flac_fifo_read_wrap(fpc, header->offset, *poutbuf_size, &fpc->wrap_buf, diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index 4ecf5f27aa..20af820a9d 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -66,15 +66,6 @@ typedef struct FLACContext { FLACDSPContext dsp; } FLACContext; -static const int64_t flac_channel_layouts[6] = { - AV_CH_LAYOUT_MONO, - AV_CH_LAYOUT_STEREO, - AV_CH_LAYOUT_SURROUND, - AV_CH_LAYOUT_QUAD, - AV_CH_LAYOUT_5POINT0, - AV_CH_LAYOUT_5POINT1 -}; - static int allocate_buffers(FLACContext *s); static void flac_set_bps(FLACContext *s) @@ -127,9 +118,6 @@ static av_cold int flac_decode_init(AVCodecContext *avctx) avcodec_get_frame_defaults(&s->frame); avctx->coded_frame = &s->frame; - if (avctx->channels <= FF_ARRAY_ELEMS(flac_channel_layouts)) - avctx->channel_layout = flac_channel_layouts[avctx->channels - 1]; - return 0; } @@ -421,7 +409,7 @@ static inline int decode_subframe(FLACContext *s, int channel) static int decode_frame(FLACContext *s) { - int i; + int i, ret; GetBitContext *gb = &s->gb; FLACFrameInfo fi; @@ -430,12 +418,15 @@ static int decode_frame(FLACContext *s) return -1; } - if (s->channels && fi.channels != s->channels) { - av_log(s->avctx, AV_LOG_ERROR, "switching channel layout mid-stream " - "is not supported\n"); - return -1; + if (s->channels && fi.channels != s->channels && s->got_streaminfo) { + s->channels = s->avctx->channels = fi.channels; + ff_flac_set_channel_layout(s->avctx); + ret = allocate_buffers(s); + if (ret < 0) + return ret; } s->channels = s->avctx->channels = fi.channels; + ff_flac_set_channel_layout(s->avctx); s->ch_mode = fi.ch_mode; if (!s->bps && !fi.bps) { @@ -478,7 +469,7 @@ static int decode_frame(FLACContext *s) s->samplerate = s->avctx->sample_rate = fi.samplerate; if (!s->got_streaminfo) { - int ret = allocate_buffers(s); + ret = allocate_buffers(s); if (ret < 0) return ret; ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps);