Although the libFLAC decoder cannot handle such a change, it is allowed by the spec and could potentially occur with live streams.tags/n1.1
| @@ -19,6 +19,7 @@ | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| #include "libavutil/audioconvert.h" | |||||
| #include "libavutil/crc.h" | #include "libavutil/crc.h" | ||||
| #include "libavutil/log.h" | #include "libavutil/log.h" | ||||
| #include "bytestream.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 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) | static int64_t get_utf8(GetBitContext *gb) | ||||
| { | { | ||||
| int64_t val; | int64_t val; | ||||
| @@ -181,6 +191,14 @@ int avpriv_flac_is_extradata_valid(AVCodecContext *avctx, | |||||
| return 1; | 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, | void avpriv_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo *s, | ||||
| const uint8_t *buffer) | const uint8_t *buffer) | ||||
| { | { | ||||
| @@ -205,6 +223,7 @@ void avpriv_flac_parse_streaminfo(AVCodecContext *avctx, struct FLACStreaminfo * | |||||
| avctx->channels = s->channels; | avctx->channels = s->channels; | ||||
| avctx->sample_rate = s->samplerate; | avctx->sample_rate = s->samplerate; | ||||
| avctx->bits_per_raw_sample = s->bps; | 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_long(&gb, 32) << 4; | ||||
| s->samples |= get_bits(&gb, 4); | s->samples |= get_bits(&gb, 4); | ||||
| @@ -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, | int ff_flac_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, | ||||
| FLACFrameInfo *fi, int log_level_offset); | FLACFrameInfo *fi, int log_level_offset); | ||||
| void ff_flac_set_channel_layout(AVCodecContext *avctx); | |||||
| #endif /* AVCODEC_FLAC_H */ | #endif /* AVCODEC_FLAC_H */ | ||||
| @@ -459,6 +459,7 @@ static int get_best_header(FLACParseContext* fpc, const uint8_t **poutbuf, | |||||
| fpc->avctx->sample_rate = header->fi.samplerate; | fpc->avctx->sample_rate = header->fi.samplerate; | ||||
| fpc->avctx->channels = header->fi.channels; | fpc->avctx->channels = header->fi.channels; | ||||
| ff_flac_set_channel_layout(fpc->avctx); | |||||
| fpc->pc->duration = header->fi.blocksize; | fpc->pc->duration = header->fi.blocksize; | ||||
| *poutbuf = flac_fifo_read_wrap(fpc, header->offset, *poutbuf_size, | *poutbuf = flac_fifo_read_wrap(fpc, header->offset, *poutbuf_size, | ||||
| &fpc->wrap_buf, | &fpc->wrap_buf, | ||||
| @@ -66,15 +66,6 @@ typedef struct FLACContext { | |||||
| FLACDSPContext dsp; | FLACDSPContext dsp; | ||||
| } FLACContext; | } 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 int allocate_buffers(FLACContext *s); | ||||
| static void flac_set_bps(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); | avcodec_get_frame_defaults(&s->frame); | ||||
| avctx->coded_frame = &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; | return 0; | ||||
| } | } | ||||
| @@ -421,7 +409,7 @@ static inline int decode_subframe(FLACContext *s, int channel) | |||||
| static int decode_frame(FLACContext *s) | static int decode_frame(FLACContext *s) | ||||
| { | { | ||||
| int i; | |||||
| int i, ret; | |||||
| GetBitContext *gb = &s->gb; | GetBitContext *gb = &s->gb; | ||||
| FLACFrameInfo fi; | FLACFrameInfo fi; | ||||
| @@ -430,12 +418,15 @@ static int decode_frame(FLACContext *s) | |||||
| return -1; | 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; | s->channels = s->avctx->channels = fi.channels; | ||||
| ff_flac_set_channel_layout(s->avctx); | |||||
| s->ch_mode = fi.ch_mode; | s->ch_mode = fi.ch_mode; | ||||
| if (!s->bps && !fi.bps) { | if (!s->bps && !fi.bps) { | ||||
| @@ -478,7 +469,7 @@ static int decode_frame(FLACContext *s) | |||||
| s->samplerate = s->avctx->sample_rate = fi.samplerate; | s->samplerate = s->avctx->sample_rate = fi.samplerate; | ||||
| if (!s->got_streaminfo) { | if (!s->got_streaminfo) { | ||||
| int ret = allocate_buffers(s); | |||||
| ret = allocate_buffers(s); | |||||
| if (ret < 0) | if (ret < 0) | ||||
| return ret; | return ret; | ||||
| ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps); | ff_flacdsp_init(&s->dsp, s->avctx->sample_fmt, s->bps); | ||||