diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2012-07-09 16:05:53 -0400 |
---|---|---|
committer | Justin Ruggles <justin.ruggles@gmail.com> | 2012-07-19 13:26:48 -0400 |
commit | 81c9e2e6d074ccbf94e19c67d38b7b62e7c3f820 (patch) | |
tree | e381fcaf30b4b06270c27bce6c6828f0dab7e93b /libavcodec | |
parent | cd632619d954c653add4b4f1820e7d3488a5c9a7 (diff) | |
download | ffmpeg-81c9e2e6d074ccbf94e19c67d38b7b62e7c3f820.tar.gz |
alac: split element parsing into a separate function
This will make multi-channel implementation simpler.
Based partially on a patch by Andrew D'Addesio <modchipv12@gmail.com>.
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/alac.c | 121 |
1 files changed, 81 insertions, 40 deletions
diff --git a/libavcodec/alac.c b/libavcodec/alac.c index b44b5c44ba..1e37290740 100644 --- a/libavcodec/alac.c +++ b/libavcodec/alac.c @@ -78,6 +78,18 @@ typedef struct { int nb_samples; /**< number of samples in the current frame */ } ALACContext; +enum RawDataBlockType { + /* At the moment, only SCE, CPE, LFE, and END are recognized. */ + TYPE_SCE, + TYPE_CPE, + TYPE_CCE, + TYPE_LFE, + TYPE_DSE, + TYPE_PCE, + TYPE_FIL, + TYPE_END +}; + static inline unsigned int decode_scalar(GetBitContext *gb, int k, int readsamplesize) { @@ -268,27 +280,18 @@ static void append_extra_bits(int32_t *buffer[MAX_CHANNELS], buffer[ch][i] = (buffer[ch][i] << extra_bits) | extra_bits_buffer[ch][i]; } -static int alac_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame_ptr, AVPacket *avpkt) +static int decode_element(AVCodecContext *avctx, void *data, int ch_index, + int channels) { ALACContext *alac = avctx->priv_data; - - int channels; int hassize; unsigned int readsamplesize; int is_compressed; uint8_t interlacing_shift; uint8_t interlacing_leftweight; + uint32_t output_samples; int i, ch, ret; - init_get_bits(&alac->gb, avpkt->data, avpkt->size * 8); - - channels = get_bits(&alac->gb, 3) + 1; - if (channels != avctx->channels) { - av_log(avctx, AV_LOG_ERROR, "frame header channel count mismatch\n"); - return AVERROR_INVALIDDATA; - } - skip_bits(&alac->gb, 4); /* element instance tag */ skip_bits(&alac->gb, 12); /* unused header bits */ @@ -305,28 +308,32 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data, /* whether the frame is compressed */ is_compressed = !get_bits1(&alac->gb); - if (hassize) { - /* now read the number of samples as a 32bit integer */ - uint32_t output_samples = get_bits_long(&alac->gb, 32); - if (!output_samples || output_samples > alac->max_samples_per_frame) { - av_log(avctx, AV_LOG_ERROR, "invalid samples per frame: %d\n", - output_samples); - return AVERROR_INVALIDDATA; - } - alac->nb_samples = output_samples; - } else - alac->nb_samples = alac->max_samples_per_frame; - - /* get output buffer */ - alac->frame.nb_samples = alac->nb_samples; - if ((ret = avctx->get_buffer(avctx, &alac->frame)) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); - return ret; + if (hassize) + output_samples = get_bits_long(&alac->gb, 32); + else + output_samples = alac->max_samples_per_frame; + if (!output_samples || output_samples > alac->max_samples_per_frame) { + av_log(avctx, AV_LOG_ERROR, "invalid samples per frame: %d\n", + output_samples); + return AVERROR_INVALIDDATA; } - if (alac->sample_size > 16) { - for (ch = 0; ch < alac->channels; ch++) - alac->output_samples_buffer[ch] = (int32_t *)alac->frame.data[ch]; + if (!alac->nb_samples) { + /* get output buffer */ + alac->frame.nb_samples = output_samples; + if ((ret = avctx->get_buffer(avctx, &alac->frame)) < 0) { + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return ret; + } + if (alac->sample_size > 16) { + for (ch = 0; ch < channels; ch++) + alac->output_samples_buffer[ch] = (int32_t *)alac->frame.data[ch_index + ch]; + } + } else if (output_samples != alac->nb_samples) { + av_log(avctx, AV_LOG_ERROR, "sample count mismatch: %u != %d\n", + output_samples, alac->nb_samples); + return AVERROR_INVALIDDATA; } + alac->nb_samples = output_samples; if (is_compressed) { int16_t predictor_coef_table[MAX_CHANNELS][32]; @@ -391,16 +398,13 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data, /* not compressed, easy case */ for (i = 0; i < alac->nb_samples; i++) { for (ch = 0; ch < channels; ch++) { - alac->output_samples_buffer[ch][i] = get_sbits_long(&alac->gb, - alac->sample_size); + alac->output_samples_buffer[ch][i] = get_sbits_long(&alac->gb, alac->sample_size); } } alac->extra_bits = 0; interlacing_shift = 0; interlacing_leftweight = 0; } - if (get_bits(&alac->gb, 3) != 7) - av_log(avctx, AV_LOG_ERROR, "Error : Wrong End Of Frame\n"); if (channels == 2 && interlacing_leftweight) { decorrelate_stereo(alac->output_samples_buffer, alac->nb_samples, @@ -409,25 +413,62 @@ static int alac_decode_frame(AVCodecContext *avctx, void *data, if (alac->extra_bits) { append_extra_bits(alac->output_samples_buffer, alac->extra_bits_buffer, - alac->extra_bits, alac->channels, alac->nb_samples); + alac->extra_bits, channels, alac->nb_samples); } switch(alac->sample_size) { case 16: { - for (ch = 0; ch < alac->channels; ch++) { - int16_t *outbuffer = (int16_t *)alac->frame.data[ch]; + for (ch = 0; ch < channels; ch++) { + int16_t *outbuffer = (int16_t *)alac->frame.data[ch_index + ch]; for (i = 0; i < alac->nb_samples; i++) *outbuffer++ = alac->output_samples_buffer[ch][i]; }} break; case 24: { - for (ch = 0; ch < alac->channels; ch++) { + for (ch = 0; ch < channels; ch++) { for (i = 0; i < alac->nb_samples; i++) alac->output_samples_buffer[ch][i] <<= 8; }} break; } + return 0; +} + +static int alac_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + ALACContext *alac = avctx->priv_data; + enum RawDataBlockType element; + int channels; + int ch, ret; + + init_get_bits(&alac->gb, avpkt->data, avpkt->size * 8); + + alac->nb_samples = 0; + ch = 0; + while (get_bits_left(&alac->gb)) { + element = get_bits(&alac->gb, 3); + if (element == TYPE_END) + break; + if (element > TYPE_CPE && element != TYPE_LFE) { + av_log(avctx, AV_LOG_ERROR, "syntax element unsupported: %d", element); + return AVERROR_PATCHWELCOME; + } + + channels = (element == TYPE_CPE) ? 2 : 1; + if (ch + channels > alac->channels) { + av_log(avctx, AV_LOG_ERROR, "invalid element channel count\n"); + return AVERROR_INVALIDDATA; + } + + ret = decode_element(avctx, data, ch, channels); + if (ret < 0) + return ret; + + ch += channels; + } + if (avpkt->size * 8 - get_bits_count(&alac->gb) > 8) av_log(avctx, AV_LOG_ERROR, "Error : %d bits left\n", avpkt->size * 8 - get_bits_count(&alac->gb)); |