diff options
author | Torsten Jager <t.jager@gmx.de> | 2013-08-10 23:21:55 +0200 |
---|---|---|
committer | Torsten Jager <t.jager@gmx.de> | 2013-08-10 23:21:55 +0200 |
commit | e5318f7f8fa3c9b6f09fd9d32202a61f86edc1d8 (patch) | |
tree | bfa437852d83b1a8c058199e1dc9f494096527a4 | |
parent | a771cb809c8f14057536f28f62930d32c2d4f088 (diff) | |
download | xine-lib-e5318f7f8fa3c9b6f09fd9d32202a61f86edc1d8.tar.gz xine-lib-e5318f7f8fa3c9b6f09fd9d32202a61f86edc1d8.tar.bz2 |
ff_audio_decoder: fix multichannel playback
* Observe channel configuration immediately after av_decode_audio* ().
Do not try to access nonexistant channels after a 5.1 -> 2.0 switch
for example.
* Add NULL plane pointer paranoia.
* Assume generic channel layout when no detailled one provided.
Needed for wma2.
* Follow user speaker arrangement changes on the fly.
* Defer opening audio out until we have something to play.
* Do not reopen audio out with identical settings. This and the
previous item should help avoiding waiting on some drivers.
* Hard wire output to int16_t. Some of the code did assume that,
and we are converting to that anyway.
* Do not read sample format from bits_per_coded_sample. Decoders
neither alter that field, nor do they force its value to their
output.
* Rename some vars for better readability.
-rw-r--r-- | src/combined/ffmpeg/ff_audio_decoder.c | 646 |
1 files changed, 498 insertions, 148 deletions
diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c index 205a64370..1a80b9dcf 100644 --- a/src/combined/ffmpeg/ff_audio_decoder.c +++ b/src/combined/ffmpeg/ff_audio_decoder.c @@ -46,6 +46,8 @@ #define AUDIOBUFSIZE (64 * 1024) +#define MAX_CHANNELS 6 + typedef struct { audio_decoder_class_t decoder_class; @@ -59,11 +61,6 @@ typedef struct ff_audio_decoder_s { xine_stream_t *stream; - int output_open; - int audio_channels; - int audio_bits; - int audio_sample_rate; - unsigned char *buf; int bufsize; int size; @@ -78,6 +75,29 @@ typedef struct ff_audio_decoder_s { #if AVAUDIO > 3 AVFrame *av_frame; #endif + + /* decoder settings */ + int ff_channels; + int ff_bits; + int ff_sample_rate; + int64_t ff_map; + + /* channel mixer settings */ + /* map[ao_channel] = ff_channel */ + int8_t map[MAX_CHANNELS]; + int8_t left[4], right[4]; + /* how many left[] / right[] entries are in use */ + int front_mixes; + /* volume adjustment */ + int downmix_shift; + + /* audio out settings */ + int output_open; + int ao_channels; + int new_mode; + int ao_mode; + int ao_caps; + } ff_audio_decoder_t; @@ -163,11 +183,11 @@ static void ff_audio_init_codec(ff_audio_decoder_t *this, unsigned int codec_typ /* Current ffmpeg audio decoders usually use 16 bits/sample * buf->decoder_info[2] can't be used as it doesn't refer to the output * bits/sample for some codecs (e.g. MS ADPCM) */ - this->audio_bits = 16; + this->ff_bits = 16; - this->context->bits_per_sample = this->audio_bits; - this->context->sample_rate = this->audio_sample_rate; - this->context->channels = this->audio_channels; + this->context->bits_per_sample = this->ff_bits; + this->context->sample_rate = this->ff_sample_rate; + this->context->channels = this->ff_channels; this->context->codec_id = this->codec->id; this->context->codec_type = this->codec->type; this->context->codec_tag = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC); @@ -237,8 +257,8 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf } if(buf->decoder_flags & BUF_FLAG_STDHEADER) { - this->audio_sample_rate = buf->decoder_info[1]; - this->audio_channels = buf->decoder_info[3]; + this->ff_sample_rate = buf->decoder_info[1]; + this->ff_channels = buf->decoder_info[3]; if(this->size) { audio_header = (xine_waveformatex *)this->buf; @@ -259,15 +279,15 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf switch(codec_type) { case BUF_AUDIO_14_4: - this->audio_sample_rate = 8000; - this->audio_channels = 1; + this->ff_sample_rate = 8000; + this->ff_channels = 1; this->context->block_align = 240; break; case BUF_AUDIO_28_8: - this->audio_sample_rate = _X_BE_16(&this->buf[0x30]); - this->audio_channels = this->buf[0x37]; - /* this->audio_bits = buf->content[0x35] */ + this->ff_sample_rate = _X_BE_16(&this->buf[0x30]); + this->ff_channels = this->buf[0x37]; + /* this->ff_bits = buf->content[0x35] */ this->context->block_align = _X_BE_32(&this->buf[0x18]); @@ -284,7 +304,7 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "ffmpeg_audio_dec: 28_8 audio channels %d bits %d sample rate %d block align %d\n", - this->audio_channels, this->audio_bits, this->audio_sample_rate, + this->ff_channels, this->ff_bits, this->ff_sample_rate, this->context->block_align); break; case BUF_AUDIO_COOK: @@ -295,15 +315,15 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf version = _X_BE_16 (this->buf+4); if (version == 4) { - this->audio_sample_rate = _X_BE_16 (this->buf+48); - this->audio_bits = _X_BE_16 (this->buf+52); - this->audio_channels = _X_BE_16 (this->buf+54); + this->ff_sample_rate = _X_BE_16 (this->buf+48); + this->ff_bits = _X_BE_16 (this->buf+52); + this->ff_channels = _X_BE_16 (this->buf+54); data_len = _X_BE_32 (this->buf+67); extradata = 71; } else { - this->audio_sample_rate = _X_BE_16 (this->buf+54); - this->audio_bits = _X_BE_16 (this->buf+58); - this->audio_channels = _X_BE_16 (this->buf+60); + this->ff_sample_rate = _X_BE_16 (this->buf+54); + this->ff_bits = _X_BE_16 (this->buf+58); + this->ff_channels = _X_BE_16 (this->buf+60); data_len = _X_BE_32 (this->buf+74); extradata = 78; } @@ -311,7 +331,7 @@ static void ff_handle_header_buffer(ff_audio_decoder_t *this, buf_element_t *buf xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "ffmpeg_audio_dec: cook audio channels %d bits %d sample rate %d block align %d\n", - this->audio_channels, this->audio_bits, this->audio_sample_rate, + this->ff_channels, this->ff_bits, this->ff_sample_rate, this->context->block_align); if (extradata + data_len > this->size) @@ -363,11 +383,146 @@ static void ff_audio_output_close(ff_audio_decoder_t *this) this->output_open = 0; } - this->audio_bits = 0; - this->audio_sample_rate = 0; - this->audio_channels = 0; + this->ff_sample_rate = 0; + this->ao_mode = 0; } +static void ff_map_channels (ff_audio_decoder_t *this) { + uint64_t ff_map; + int caps = this->stream->audio_out->get_capabilities (this->stream->audio_out); + + /* safety kludge for very old libavcodec */ +#ifdef AV_CH_FRONT_LEFT + ff_map = this->context->channel_layout; + if (!ff_map) /* wma2 bug */ +#endif + ff_map = (1 << this->context->channels) - 1; + + if ((caps != this->ao_caps) || (ff_map != this->ff_map)) { + int i, j; + /* ff: see names[] below; xine: L R RL RR C LFE */ + const int8_t base_map[] = {0, 1, 4, 5, 2, 3, -1, -1, -1, 2, 3}; + int8_t name_map[MAX_CHANNELS]; + const int modes[] = { + AO_CAP_MODE_MONO, AO_CAP_MODE_STEREO, + AO_CAP_MODE_4CHANNEL, AO_CAP_MODE_4_1CHANNEL, + AO_CAP_MODE_5CHANNEL, AO_CAP_MODE_5_1CHANNEL + }; + const int num_modes = sizeof (modes) / sizeof (modes[0]); + const int8_t mode_channels[] = {1, 2, 4, 6, 6, 6}; + const int8_t wishlist[] = { + 0, 1, 2, 3, 4, 5, /* mono */ + 1, 2, 3, 4, 5, 0, /* stereo */ + 5, 4, 3, 2, 1, 0, /* center + lfe */ + 4, 5, 2, 3, 1, 0, /* center */ + 3, 5, 2, 4, 1, 0, /* lfe */ + 2, 3, 4, 5, 1, 0 /* 4.0 */ + }; + const int8_t *tries; + + this->ao_caps = caps; + this->ff_map = ff_map; + this->ff_channels = this->context->channels; + + /* silence out */ + for (i = 0; i < MAX_CHANNELS; i++) + this->map[i] = -1; + for (i = 0; i < 4; i++) + this->left[i] = this->right[i] = -1; + + /* set up raw map and ao mode wishlist */ + if (this->ff_channels == 1) { /* mono */ + name_map[0] = 2; + this->left[0] = this->right[0] = 0; + tries = wishlist + 0 * num_modes; + } else if (this->ff_channels == 2) { /* stereo */ + name_map[0] = 0; + name_map[1] = 1; + this->left[0] = 0; + this->right[0] = 1; + tries = wishlist + 1 * num_modes; + } else { + for (i = j = 0; i < sizeof (base_map) / sizeof (base_map[0]); i++) { + if ((ff_map >> i) & 1) { + int8_t target = base_map[i]; + if ((target >= 0) && (this->map[target] < 0)) + this->map[target] = j; + name_map[j] = i; /* for debug output below */ + j++; + } + } + this->left[0] = this->map[0] < 0 ? 0 : this->map[0]; + this->map[0] = -1; + this->right[0] = this->map[1] < 0 ? 1 : this->map[1]; + this->map[1] = -1; + tries = wishlist + + (2 + (this->map[4] < 0 ? 2 : 0) + (this->map[5] < 0 ? 1 : 0)) * num_modes; + } + this->front_mixes = 1; + + /* find ao mode */ + for (i = 0; i < num_modes; i++) if (caps & modes[tries[i]]) break; + i = i == num_modes ? 1 : tries[i]; + this->new_mode = modes[i]; + this->ao_channels = mode_channels[i]; + + /* mix center to front */ + if ((this->map[4] >= 0) && !((0x30 >> i) & 1)) { + this->left[this->front_mixes] = this->map[4]; + this->right[this->front_mixes++] = this->map[4]; + this->map[4] = -1; + } + /* mix lfe to front */ + if ((this->map[5] >= 0) && !((0x28 >> i) & 1)) { + this->left[this->front_mixes] = this->map[5]; + this->right[this->front_mixes++] = this->map[5]; + this->map[5] = -1; + } + /* mix surround to front */ + if ((this->map[2] >= 0) && (this->map[3] >= 0) && !((0x3c >> i) & 1)) { + this->left[this->front_mixes] = this->map[2]; + this->right[this->front_mixes++] = this->map[3]; + this->map[2] = -1; + this->map[3] = -1; + } + + this->downmix_shift = this->front_mixes > 1 ? 1 : 0; + /* this will be on the safe side but usually too soft?? */ +#if 0 + if (this->front_mixes > 2) + this->downmix_shift = 2; +#endif + + if (this->stream->xine->verbosity >= XINE_VERBOSITY_LOG) { + const int8_t *names[] = { + "left", "right", "center", "bass", + "rear left", "rear right", + "half left", "half right", + "rear center", + "side left", "side right" + }; + int8_t buf[200]; + int p = sprintf (buf, "ff_audio_dec: channel layout: "); + int8_t *indx = this->left; + for (i = 0; i < 2; i++) { + buf[p++] = '['; + for (j = 0; j < this->front_mixes; j++) + p += sprintf (buf + p, "%s%s", names[name_map[indx[j]]], (j < this->front_mixes - 1) ? " + " : ""); + buf[p++] = ']'; + buf[p++] = ' '; + indx = this->right; + } + for (i = 2; i < this->ao_channels; i++) + p += sprintf (buf + p, "[%s] ", + ((this->map[i] < 0) || (this->map[i] > 5)) ? (const int8_t *)"-" : names[name_map[this->map[i]]]); + buf[p++] = '\n'; + fwrite (buf, 1, p, stdout); + } + } +} + +#define CLIP_16(v) ((v + 0x8000) & ~0xffff ? (v >> 31) ^ 0x7fff : v) + static int ff_audio_decode (ff_audio_decoder_t *this, int16_t *decode_buffer, int *decode_buffer_size, uint8_t *buf, int size) { int consumed; @@ -408,106 +563,250 @@ static int ff_audio_decode (ff_audio_decoder_t *this, avpkt.flags = AV_PKT_FLAG_KEY; # if AVAUDIO > 3 int got_frame; - const float gain = this->class->gain; + float gain = this->class->gain; if (!this->av_frame) this->av_frame = avcodec_alloc_frame (); consumed = avcodec_decode_audio4 (this->context, this->av_frame, &got_frame, &avpkt); if ((consumed >= 0) && got_frame) { + /* setup may have altered while decoding */ + ff_map_channels (this); + int16_t *q = decode_buffer; int samples = this->av_frame->nb_samples; - int channels = this->context->channels; - int bytes, i, j; + int channels = this->ao_channels; + int bytes, i, j, shift = this->downmix_shift; /* limit buffer */ - if (channels > 12) - channels = 12; if (*decode_buffer_size < samples * channels * 2) samples = *decode_buffer_size / (channels * 2); bytes = samples * channels * 2; *decode_buffer_size = bytes; - /* convert to packed int16_t. I guess there is something - in libavfilter but also another dependency... */ + /* TJ. convert to packed int16_t while respecting the user's speaker arrangement. + I tried to speed up and not to pull in libswresample. */ + for (i = 2; i < channels; i++) if (this->map[i] < 0) { + /* clear if there is an upmix mute channel */ + memset (q, 0, bytes); + break; + } + /* For mono output, downmix to stereo first */ + if ((channels == 1) && (this->ff_channels > 1)) + channels = 2; + gain /= (float)(1 << shift); switch (this->context->sample_fmt) { +#define MIX_AUDIO(stype,planar,idx,num,dindx) {\ + stype *p1, *p2, *p3, *p4;\ + int i, sstep;\ + int8_t *x = idx;\ + int16_t *dptr = (int16_t *)decode_buffer + dindx;\ + if (planar) {\ + p1 = (stype *)this->av_frame->extended_data[x[0]];\ + sstep = 1;\ + } else {\ + p1 = (stype *)this->av_frame->extended_data[0] + x[0];\ + sstep = this->ff_channels;\ + }\ + if (num == 1) {\ + if (p1) for (i = 0; i < samples; i++) {\ + int32_t v = MIX_FIX(*p1);\ + p1 += sstep;\ + v >>= shift;\ + *dptr = (v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p2 = (stype *)this->av_frame->extended_data[x[1]];\ + else\ + p2 = (stype *)this->av_frame->extended_data[0] + x[1];\ + if (num == 2) {\ + if (p1 && p2) for (i = 0; i < samples; i++) {\ + int32_t v = MIX_FIX(*p1);\ + p1 += sstep;\ + v += MIX_FIX(*p2);\ + p2 += sstep;\ + v >>= shift;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p3 = (stype *)this->av_frame->extended_data[x[2]];\ + else\ + p3 = (stype *)this->av_frame->extended_data[0] + x[2];\ + if (num == 3) {\ + if (p1 && p2 && p3) for (i = 0; i < samples; i++) {\ + int32_t v = MIX_FIX(*p1);\ + p1 += sstep;\ + v += MIX_FIX(*p2);\ + p2 += sstep;\ + v += MIX_FIX(*p3);\ + p3 += sstep;\ + v >>= shift;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p4 = (stype *)this->av_frame->extended_data[x[3]];\ + else\ + p4 = (stype *)this->av_frame->extended_data[0] + x[3];\ + if (p1 && p2 && p3 && p4) for (i = 0; i < samples; i++) {\ + int32_t v = MIX_FIX(*p1);\ + p1 += sstep;\ + v += MIX_FIX(*p2);\ + p2 += sstep;\ + v += MIX_FIX(*p3);\ + p3 += sstep;\ + v += MIX_FIX(*p4);\ + p4 += sstep;\ + v >>= shift;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + }\ + }\ + }\ + } +#define MIX_FIX(v) (((int16_t)(v)<<8)^0x8000) case AV_SAMPLE_FMT_U8P: - if (channels > 1) { - uint8_t *p[12]; - for (i = 0; i < channels; i++) - p[i] = (uint8_t *)this->av_frame->extended_data[i]; - for (i = samples; i; i--) { - for (j = 0; j < channels; j++) - *q++ = ((uint16_t)(*p[j]++) << 8) ^ 0x8000; - } - break; - } + MIX_AUDIO (uint8_t, 1, this->left, this->front_mixes, 0); + MIX_AUDIO (uint8_t, 1, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (uint8_t, 1, this->map + j, 1, j); + break; case AV_SAMPLE_FMT_U8: - { - uint8_t *p = (uint8_t *)this->av_frame->extended_data[0]; - for (i = samples * channels; i; i--) - *q++ = ((uint16_t)(*p++) << 8) ^ 0x8000; - } + MIX_AUDIO (uint8_t, 0, this->left, this->front_mixes, 0); + MIX_AUDIO (uint8_t, 0, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (uint8_t, 0, this->map + j, 1, j); break; +#undef MIX_FIX +#define MIX_FIX(v) (v) case AV_SAMPLE_FMT_S16P: - if (channels > 1) { - int16_t *p[12]; - for (i = 0; i < channels; i++) - p[i] = (int16_t *)this->av_frame->extended_data[i]; - for (i = samples; i; i--) { - for (j = 0; j < channels; j++) - *q++ = *p[j]++; - } - break; - } + MIX_AUDIO (int16_t, 1, this->left, this->front_mixes, 0); + MIX_AUDIO (int16_t, 1, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (int16_t, 1, this->map + j, 1, j); + break; case AV_SAMPLE_FMT_S16: - xine_fast_memcpy (q, this->av_frame->extended_data[0], bytes); + MIX_AUDIO (int16_t, 0, this->left, this->front_mixes, 0); + MIX_AUDIO (int16_t, 0, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (int16_t, 0, this->map + j, 1, j); break; +#undef MIX_FIX +#define MIX_FIX(v) ((v)>>16) case AV_SAMPLE_FMT_S32P: - if (channels > 1) { - int32_t *p[12]; - for (i = 0; i < channels; i++) - p[i] = (int32_t *)this->av_frame->extended_data[i]; - for (i = samples; i; i--) { - for (j = 0; j < channels; j++) - *q++ = *p[j]++ >> 16; - } - break; - } + MIX_AUDIO (int32_t, 1, this->left, this->front_mixes, 0); + MIX_AUDIO (int32_t, 1, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (int32_t, 1, this->map + j, 1, j); + break; case AV_SAMPLE_FMT_S32: - { - int32_t *p = (int32_t *)this->av_frame->extended_data[0]; - for (i = samples * channels; i; i--) - *q++ = *p++ >> 16; - } + MIX_AUDIO (int32_t, 0, this->left, this->front_mixes, 0); + MIX_AUDIO (int32_t, 0, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (int32_t, 0, this->map + j, 1, j); break; +#undef MIX_FIX +#undef MIX_AUDIO +#define MIX_AUDIO(stype,planar,idx,num,dindx) {\ + stype *p1, *p2, *p3, *p4;\ + int i, sstep;\ + int8_t *x = idx;\ + int16_t *dptr = (int16_t *)decode_buffer + dindx;\ + if (planar) {\ + p1 = (stype *)this->av_frame->extended_data[x[0]];\ + sstep = 1;\ + } else {\ + p1 = (stype *)this->av_frame->extended_data[0] + x[0];\ + sstep = this->ff_channels;\ + }\ + if (num == 1) {\ + if (p1) for (i = 0; i < samples; i++) {\ + int32_t v = (*p1) * gain;\ + p1 += sstep;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p2 = (stype *)this->av_frame->extended_data[x[1]];\ + else\ + p2 = (stype *)this->av_frame->extended_data[0] + x[1];\ + if (num == 2) {\ + if (p1 && p2) for (i = 0; i < samples; i++) {\ + int32_t v = (*p1 + *p2) * gain;\ + p1 += sstep;\ + p2 += sstep;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p3 = (stype *)this->av_frame->extended_data[x[2]];\ + else\ + p3 = (stype *)this->av_frame->extended_data[0] + x[2];\ + if (num == 3) {\ + if (p1 && p2 && p3) for (i = 0; i < samples; i++) {\ + int32_t v = (*p1 + *p2 + *p3) * gain;\ + p1 += sstep;\ + p2 += sstep;\ + p3 += sstep;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + } else {\ + if (planar)\ + p4 = (stype *)this->av_frame->extended_data[x[3]];\ + else\ + p4 = (stype *)this->av_frame->extended_data[0] + x[3];\ + if (p1 && p2 && p3 && p4) for (i = 0; i < samples; i++) {\ + int32_t v = (*p1 + *p2 + *p3 + *p4) * gain;\ + p1 += sstep;\ + p2 += sstep;\ + p3 += sstep;\ + p4 += sstep;\ + *dptr = CLIP_16(v);\ + dptr += channels;\ + }\ + }\ + }\ + }\ + } case AV_SAMPLE_FMT_FLTP: /* the most popular one */ - if (channels > 1) { - float *p[12]; - for (i = 0; i < channels; i++) - p[i] = (float *)this->av_frame->extended_data[i]; - for (i = samples; i; i--) { - for (j = 0; j < channels; j++) { - int v = *p[j]++ * gain; - *q++ = (v + 0x8000) & ~0xffff ? (v >> 31) ^ 0x7fff : v; - } - } - break; - } + MIX_AUDIO (float, 1, this->left, this->front_mixes, 0); + MIX_AUDIO (float, 1, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (float, 1, this->map + j, 1, j); + break; case AV_SAMPLE_FMT_FLT: - { - float *p = (float *)this->av_frame->extended_data[0]; - for (i = samples * channels; i; i--) { - int v = *p++ * gain; - *q++ = (v + 0x8000) & ~0xffff ? (v >> 31) ^ 0x7fff : v; - } - } + MIX_AUDIO (float, 0, this->left, this->front_mixes, 0); + MIX_AUDIO (float, 0, this->right, this->front_mixes, 1); + for (j = 0; j < channels; j++) if (this->map[j] >= 0) + MIX_AUDIO (float, 0, this->map + j, 1, j); break; default: ; } + if (channels > this->ao_channels) { + /* final mono downmix */ + int16_t *p = decode_buffer; + q = p; + for (i = samples; i; i--) { + int v = *p++; + v += *p++; + *q++ = v >> 1; + } + *decode_buffer_size = samples * 2; + } } else *decode_buffer_size = 0; # else consumed = avcodec_decode_audio3 (this->context, decode_buffer, decode_buffer_size, &avpkt); + ff_map_channels (this); # endif #else consumed = avcodec_decode_audio2 (this->context, decode_buffer, decode_buffer_size, buf, size); + ff_map_channels (this); #endif if (consumed < 0) { @@ -567,23 +866,25 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) while (this->size>=0) { decode_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; - bytes_consumed = - ff_audio_decode(this, - (int16_t *)this->decode_buffer, &decode_buffer_size, - &this->buf[offset], this->size); + bytes_consumed = ff_audio_decode (this, (int16_t *)this->decode_buffer, &decode_buffer_size, + &this->buf[offset], this->size); - if (bytes_consumed<0) { - this->size=0; - return; - } else if (bytes_consumed == 0 && decode_buffer_size == 0) { + if (bytes_consumed < 0) + break; + + offset += bytes_consumed; + this->size -= bytes_consumed; + + if (decode_buffer_size == 0) { + if (bytes_consumed) + continue; if (offset) memmove(this->buf, &this->buf[offset], this->size); return; } - if (this->audio_bits != this->context->bits_per_sample || - this->audio_sample_rate != this->context->sample_rate || - this->audio_channels != this->context->channels) { + if (this->ff_sample_rate != this->context->sample_rate || + this->ao_mode != this->new_mode) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_audio_dec: codec parameters changed\n")); /* close if it was open, and always trigger 1 new open attempt below */ @@ -591,12 +892,11 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) } if (!this->output_open) { - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { - this->audio_bits = this->context->bits_per_sample; - this->audio_sample_rate = this->context->sample_rate; - this->audio_channels = this->context->channels; + if (!this->ff_sample_rate || !this->ao_mode) { + this->ff_sample_rate = this->context->sample_rate; + this->ao_mode = this->new_mode; } - if (!this->audio_bits || !this->audio_sample_rate || !this->audio_channels) { + if (!this->ff_sample_rate || !this->new_mode) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, _("ffmpeg_audio_dec: cannot read codec parameters from packet\n")); /* try to decode next packet. */ @@ -606,8 +906,8 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) buf->pts = 0; } else { this->output_open = (this->stream->audio_out->open) (this->stream->audio_out, - this->stream, this->audio_bits, this->audio_sample_rate, - _x_ao_channels2mode(this->audio_channels)); + this->stream, 16, this->ff_sample_rate, + this->ao_mode); if (!this->output_open) { xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "ffmpeg_audio_dec: error opening audio output\n"); @@ -617,6 +917,84 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) } } +#if AVAUDIO < 4 + /* Old style postprocessing */ + if (codec_type == BUF_AUDIO_WMAPRO) { + /* the above codecs output float samples, not 16-bit integers */ + int samples = decode_buffer_size / sizeof(float); + float gain = this->class->gain; + float *p = (float *)this->decode_buffer; + int16_t *q = (int16_t *)this->decode_buffer; + int i; + for (i = samples; i; i--) { + int v = *p++ * gain; + *q++ = CLIP_16 (v); + } + decode_buffer_size = samples * 2; + } + + if ((this->ao_channels != this->ff_channels) || (this->ao_channels > 2)) { + /* Channel reordering and/or mixing */ + int samples = decode_buffer_size / (this->ff_channels * 2); + int channels = this->ao_channels; + int ff_channels = this->ff_channels; + int16_t *p = (int16_t *)this->decode_buffer; + int16_t *q = p; + int shift = this->downmix_shift, i, j; + /* downmix mono output to stereo first */ + if ((channels == 1) && (ff_channels > 1)) + channels = 2; + /* move to end of buf for in-place editing */ + p += AVCODEC_MAX_AUDIO_FRAME_SIZE - decode_buffer_size; + if (p >= q + decode_buffer_size) + xine_fast_memcpy (p, q, decode_buffer_size); + else + memmove (p, q, decode_buffer_size); + /* not very optimized but it only hits when playing multichannel audio through + old ffmpeg - and its still better than previous code there */ + if (this->front_mixes < 2) { + /* just reorder and maybe upmix */ + for (i = samples; i; i--) { + q[0] = p[0]; + q[1] = p[this->right[0]]; + for (j = 2; j < channels; j++) + q[j] = this->map[j] < 0 ? 0 : p[this->map[j]]; + p += ff_channels; + q += channels; + } + } else { + /* downmix */ + for (i = samples; i; i--) { + int left = p[0]; + int right = p[this->right[0]]; + for (j = 1; j < this->front_mixes; j++) { + left += p[this->left[j]]; + right += p[this->right[j]]; + } + left >>= shift; + q[0] = CLIP_16 (left); + right >>= shift; + q[1] = CLIP_16 (right); + for (j = 2; j < channels; j++) + q[j] = this->map[j] < 0 ? 0 : p[this->map[j]] >> shift; + p += ff_channels; + q += channels; + } + } + /* final mono downmix */ + if (channels > this->ao_channels) { + p = (int16_t *)this->decode_buffer; + q = p; + for (i = samples; i; i--) { + int v = *p++; + v += *p++; + *q++ = v >> 1; + } + } + decode_buffer_size = samples * this->ao_channels * 2; + } +#endif + /* dispatch the decoded audio */ out = 0; while (out < decode_buffer_size) { @@ -636,40 +1014,16 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) } /* fill up this buffer */ -#if AVAUDIO < 4 - if (codec_type == BUF_AUDIO_WMAPRO) { - /* the above codecs output float samples, not 16-bit integers */ - int bytes_per_sample = sizeof(float); - if (((decode_buffer_size - out) * 2 / bytes_per_sample) > audio_buffer->mem_size) - bytes_to_send = audio_buffer->mem_size * bytes_per_sample / 2; - else - bytes_to_send = decode_buffer_size - out; - - int16_t *int_buffer = calloc(1, bytes_to_send * 2 / bytes_per_sample); - int i; - for (i = 0; i < (bytes_to_send / bytes_per_sample); i++) { - float *float_sample = (float *)&this->decode_buffer[i * bytes_per_sample + out]; - int_buffer[i] = (int16_t)lrintf(*float_sample * 32768.); - } + if ((decode_buffer_size - out) > audio_buffer->mem_size) + bytes_to_send = audio_buffer->mem_size; + else + bytes_to_send = decode_buffer_size - out; - out += bytes_to_send; - bytes_to_send = bytes_to_send * 2 / bytes_per_sample; - xine_fast_memcpy(audio_buffer->mem, int_buffer, bytes_to_send); - free(int_buffer); - } else -#endif - { - if ((decode_buffer_size - out) > audio_buffer->mem_size) - bytes_to_send = audio_buffer->mem_size; - else - bytes_to_send = decode_buffer_size - out; - - xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out], bytes_to_send); - out += bytes_to_send; - } + xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out], bytes_to_send); + out += bytes_to_send; /* byte count / 2 (bytes / sample) / channels */ - audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels; + audio_buffer->num_frames = bytes_to_send / 2 / this->ao_channels; audio_buffer->vpts = buf->pts; @@ -677,11 +1031,7 @@ static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); } - - this->size -= bytes_consumed; - offset += bytes_consumed; } - /* reset internal accumulation buffer */ this->size = 0; } @@ -765,7 +1115,7 @@ static audio_decoder_t *ff_audio_open_plugin (audio_decoder_class_t *class_gen, this->audio_decoder.dispose = ff_audio_dispose; this->output_open = 0; - this->audio_channels = 0; + this->ff_channels = 0; this->stream = stream; this->buf = NULL; this->size = 0; |