mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
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>.
This commit is contained in:
parent
cd632619d9
commit
81c9e2e6d0
@ -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;
|
||||
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->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;
|
||||
}
|
||||
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 (alac->sample_size > 16) {
|
||||
for (ch = 0; ch < alac->channels; ch++)
|
||||
alac->output_samples_buffer[ch] = (int32_t *)alac->frame.data[ch];
|
||||
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));
|
||||
|
Loading…
Reference in New Issue
Block a user