Re: AAC 5.1 audio is broken in xine-lib-1.2
"Torsten Jager" <[email protected]> Sat, 30 Mar 2013 15:27:03 +0100
| Newsgroups | gmane.comp.video.xine.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi.
Sorry I forgot the subject.
No german TV uses AAC audio, we take mp2 and sometimes a52.
So I crafted one. Works with ffplay and xine ff plugin
(with my wrong header fix). Xine faad failed after 2
channel configuration switches with a flood of error
messages about invalid input data - so much for breaking
something.
But you are right that there IS a need for a more general
solution - we have to reorder and/or up/down mix audio
following the user speaker arrangement. See this one:
[ff_audio_channel_mixer.diff]
ff_audio_decoder: mix multichannel audio to users speaker arrangement
Background: I am using this self designed analogue crossover
network:
+--------+ +------+ /|
| ____ | | |\ | +--+ |
Input L --+-----| _/ |-----| | > |-----| | | Front Left
| | | | |/ | +--+ |
| +--------+ +------+ \|
|
V +--------+ +------+ /|
+---+ | _ | | |\ | +--+ |
| + |---| \____ |-----| | > |-----| | | Bass
+---+ | | | |/ | +--+ |
^ +--------+ +------+ \|
|
| +--------+ +------+ /|
| | ____ | | |\ | +--+ |
Input R --+-----| _/ |-----| | > |-----| | | Front Right
| | | |/ | +--+ |
+--------+ +------+ \|
It has been doing a good job for the past 20 years, and it
still does because most audio sources are plain stereo with
center panned bass. The missing center dialogue speaker is
not a problem since I own neither a large hall nor a huge
screen.
All I need to do for this is to set my xine speaker arrangement
to 2.0 and I will hear those dialogues through the front
speakers, and the LFE through the subwoofer where they
belong.
Anyone with a more sophisticated equipment just sets to
4.0 / 4.1 / 5.0 / 5.1 (xine conf allowes 7.1 too but
there is no matching ao mode yet??).
mp1/2/3 audio is a solo artist on stage. A quite talented
artist admittedly but there are some sounds that need a
lot of effort.
mp4 audio addresses that issue by supplying a whole band.
The compressed data looks like an orchestra score.
Unfortunately, xine's own version of libfaad is quite
incomplete and simply does skip some of the playback
instructions (most notably channel coupling and parametric
stereo), thus dropping most of the bass and some more
sounds, too.
Until someone gives a better solu tion, I will insist in
using that halfway up to date ffmpeg mp4a decoder.
And, behind the lame LATM excuse, you tend to do so as
well ;-)
Torsten
------------------------------------------------------------------------------
Own the Future-Intel(R) Level Up Game Demo Contest 2013
Rise to greatness in Intel's independent game demo contest. Compete
for recognition, cash, and the chance to get your game on Steam.
$5K grand prize plus 10 genre and skill prizes. Submit your demo
by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2
_______________________________________________
xine-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xine-devel
ff_audio_channel_mixer.diff
(application/octet-stream, 23.4 KB)
--- xine-lib-1.2-20130318/src/combined/ffmpeg/ff_audio_decoder.c 2013-03-18 13:25:00.000000000 +0100
+++ xine-lib-1.2-20130318/src/combined/ffmpeg/ff_audio_decoder.c 2013-03-29 15:45:34.000000000 +0100
@@ -46,6 +46,8 @@
#define AUDIOBUFSIZE (64 * 1024)
+#define MAX_CHANNELS 6
+
typedef struct {
audio_decoder_class_t decoder_class;
@@ -78,6 +80,9 @@ typedef struct ff_audio_decoder_s {
#if AVAUDIO > 3
AVFrame *av_frame;
#endif
+
+ int8_t map[MAX_CHANNELS], front_mix[2];
+ int ao_channels, ao_mode;
} ff_audio_decoder_t;
@@ -368,6 +385,81 @@ static void ff_audio_output_close(ff_aud
this->audio_channels = 0;
}
+static void ff_map_channels (ff_audio_decoder_t *this) {
+ int i, j;
+ uint64_t ff_map;
+ int caps = this->stream->audio_out->get_capabilities (this->stream->audio_out);
+ /* ff: L R C LFE RL RR; xine: L R RL RR C LFE */
+ const int8_t base_map[6] = {0, 1, 4, 5, 2, 3};
+ 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_has_center[] = {0, 0, 0, 0, 1, 1};
+ const int8_t mode_has_lfe[] = {0, 0, 0, 1, 0, 1};
+ 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;
+
+ /* safety kludge for very old libavcodec */
+#ifdef AV_CH_FRONT_LEFT
+ ff_map = this->context->channel_layout;
+#else
+ ff_map = (1 << this->context->channels) - 1;
+#endif
+
+ /* silence out */
+ for (i = 0; i < MAX_CHANNELS; i++) this->map[i] = -1;
+ this->front_mix[0] = this->front_mix[1] = -1;
+
+ /* set up raw map and ao mode wishlist */
+ if (this->context->channels == 1) { /* mono */
+ this->map[0] = this->map[1] = 0;
+ tries = wishlist + 0 * num_modes;
+ } else if (this->context->channels == 2) { /* stereo */
+ this->map[0] = 0;
+ this->map[1] = 1;
+ tries = wishlist + 1 * num_modes;
+ } else {
+ j = 0;
+ for (i = 0; i < 6; i++) {
+ if ((ff_map >> i) & 1)
+ this->map[base_map[i]] = j++;
+ }
+ tries = wishlist
+ + (2 + (this->map[4] < 0 ? 2 : 0) + (this->map[5] < 0 ? 1 : 0)) * num_modes;
+ }
+
+ /* find ao mode */
+ for (i = 0; i < num_modes; i++) if (caps & modes[tries[i]]) break;
+ i = i == num_modes ? 1 : tries[i];
+ this->ao_mode = modes[i];
+ this->ao_channels = mode_channels[i];
+
+ j = 0;
+ /* mix center to front */
+ if ((this->map[4] >= 0) && !mode_has_center[i]) {
+ this->front_mix[j++] = this->map[4];
+ this->map[4] = -1;
+ }
+ /* mix lfe to front */
+ if ((this->map[5] >= 0) && !mode_has_lfe[i]) {
+ this->front_mix[j] = this->map[5];
+ this->map[5] = -1;
+ }
+}
+
+#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,7 +500,12 @@ static int ff_audio_decode (ff_audio_dec
avpkt.flags = AV_PKT_FLAG_KEY;
# if AVAUDIO > 3
int got_frame;
- const float gain = this->class->gain;
+ float gain = this->class->gain;
+ /* Downmix gain is ambigous. To avoid all possible distortion, we must attennuate
+ by 1/num_components. On the other hand, center and lfe normally are supplementary
+ and we will be too soft. Lets do a compromise of -3dB * (num_components - 1). */
+ if (this->front_mix[0] >= 0) gain *= 0.707;
+ if (this->front_mix[1] >= 0) gain *= 0.707;
if (!this->av_frame)
this->av_frame = avcodec_alloc_frame ();
@@ -416,92 +513,324 @@ static int ff_audio_decode (ff_audio_dec
if ((consumed >= 0) && got_frame) {
int16_t *q = decode_buffer;
int samples = this->av_frame->nb_samples;
- int channels = this->context->channels;
+ int channels = this->ao_channels;
int bytes, i, j;
/* 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. Sorry for that
+ shitload of similar code.
+ PS. Does anybody need 8 bit downmix support? */
+ for (i = 2; i < channels; i++) if (this->map[i] < 0) {
+ /* clear if there is an upmix mute channel */
+ memset (q, 0, bytes);
+ break;
+ }
+ if ((channels == 1) && (this->audio_channels > 1))
+ /* For mono output, downmix to stereo first */
+ channels = 2;
switch (this->context->sample_fmt) {
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;
+ for (i = 0; i < channels; i++) if (this->map[i] >= 0) {
+ int8_t *p = (int8_t *)this->av_frame->extended_data[this->map[i]];
+ q = decode_buffer + i;
+ for (j = samples; j; j--) {
+ *q = ((uint16_t)(*p++) << 8) ^ 0x8000;
+ q += channels;
}
- break;
}
+ 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;
+ for (i = 0; i < channels; i++) if (this->map[i] >= 0) {
+ int ff_channels = this->audio_channels;
+ int8_t *p = (int8_t *)this->av_frame->extended_data[0] + this->map[i];
+ q = decode_buffer + i;
+ for (j = samples; j; j--) {
+ *q = ((uint16_t)(*p) << 8) ^ 0x8000;
+ p += ff_channels;
+ q += channels;
+ }
}
break;
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]++;
+ {
+ int16_t *p = (int16_t *)this->av_frame->extended_data[this->map[0]];
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ int16_t *p1 = (int16_t *)this->av_frame->extended_data[this->front_mix[0]];
+ int16_t *p2 = (int16_t *)this->av_frame->extended_data[this->front_mix[1]];
+ int16_t *p0 = (int16_t *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ int m = (int)*p1++ + (int)*p2++;
+ int v = (int)*p++ + m;
+ *q++ = CLIP_16 (v);
+ v = (int)*p0++ + m;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ int16_t *p1 = (int16_t *)this->av_frame->extended_data[this->front_mix[0]];
+ int16_t *p0 = (int16_t *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ int v = (int)*p++ + (int)*p1;
+ *q++ = CLIP_16 (v);
+ v = (int)*p0++ + (int)*p1++;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (int16_t *)this->av_frame->extended_data[this->map[i]];
+ for (j = samples; j; j--) {
+ *q = *p++;
+ q += channels;
+ }
}
- break;
}
+ break;
case AV_SAMPLE_FMT_S16:
- xine_fast_memcpy (q, this->av_frame->extended_data[0], bytes);
+ {
+ int ff_channels = this->audio_channels;
+ int16_t *p = (int16_t *)this->av_frame->extended_data[0];
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ int16_t *p1 = p + this->front_mix[0];
+ int16_t *p2 = p + this->front_mix[1];
+ int16_t *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ int m = (int)*p1 + (int)*p2;
+ int v = (int)*p + m;
+ p1 += ff_channels;
+ p2 += ff_channels;
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (int)*p0 + m;
+ p0 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ int16_t *p1 = p + this->front_mix[0];
+ int16_t *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ int v = (int)*p + (int)*p1;
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (int)*p0 + (int)*p1;
+ p0 += ff_channels;
+ p1 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (int16_t *)this->av_frame->extended_data[0] + this->map[i];
+ for (j = samples; j; j--) {
+ *q = *p;
+ p += ff_channels;
+ q += channels;
+ }
+ }
+ }
break;
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;
+ {
+ int32_t *p = (int32_t *)this->av_frame->extended_data[this->map[0]];
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ int32_t *p1 = (int32_t *)this->av_frame->extended_data[this->front_mix[0]];
+ int32_t *p2 = (int32_t *)this->av_frame->extended_data[this->front_mix[1]];
+ int32_t *p0 = (int32_t *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ int m = (*p1++ >> 16) + (*p2++ >> 16);
+ int v = (*p++ >> 16) + m;
+ *q++ = CLIP_16 (v);
+ v = (*p0++ >> 16) + m;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ int32_t *p1 = (int32_t *)this->av_frame->extended_data[this->front_mix[0]];
+ int32_t *p0 = (int32_t *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ int v = (*p++ >> 16) + (*p1 >> 16);
+ *q++ = CLIP_16 (v);
+ v = (*p0++ >> 16) + (*p1++ >> 16);
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (int32_t *)this->av_frame->extended_data[this->map[i]];
+ for (j = samples; j; j--) {
+ *q = *p++ >> 16;
+ q += channels;
+ }
}
- break;
}
+ break;
case AV_SAMPLE_FMT_S32:
{
+ int ff_channels = this->audio_channels;
int32_t *p = (int32_t *)this->av_frame->extended_data[0];
- for (i = samples * channels; i; i--)
- *q++ = *p++ >> 16;
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ int32_t *p1 = p + this->front_mix[0];
+ int32_t *p2 = p + this->front_mix[1];
+ int32_t *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ int m = (*p1 >> 16) + (*p2 >> 16);
+ int v = (*p >> 16) + m;
+ p1 += ff_channels;
+ p2 += ff_channels;
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (*p0 >> 16) + m;
+ p0 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ int32_t *p1 = p + this->front_mix[0];
+ int32_t *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ int v = (*p >> 16) + (*p1 >> 16);
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (*p0 >> 16) + (*p1 >> 16);
+ p0 += ff_channels;
+ p1 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (int32_t *)this->av_frame->extended_data[0] + this->map[i];
+ for (j = samples; j; j--) {
+ *q = *p >> 16;
+ p += ff_channels;
+ q += channels;
+ }
+ }
}
break;
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;
+ {
+ float *p = (float *)this->av_frame->extended_data[this->map[0]];
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ float *p1 = (float *)this->av_frame->extended_data[this->front_mix[0]];
+ float *p2 = (float *)this->av_frame->extended_data[this->front_mix[1]];
+ float *p0 = (float *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ float m = *p1++ + *p2++;
+ int v = (*p++ + m) * gain;
+ *q++ = CLIP_16 (v);
+ v = (*p0++ + m) * gain;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ float *p1 = (float *)this->av_frame->extended_data[this->front_mix[0]];
+ float *p0 = (float *)this->av_frame->extended_data[this->map[1]];
+ for (j = samples; j; j--) {
+ int v = (*p++ + *p1) * gain;
+ *q++ = CLIP_16 (v);
+ v = (*p0++ + *p1++) * gain;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (float *)this->av_frame->extended_data[this->map[i]];
+ for (j = samples; j; j--) {
+ int v = *p++ * gain;
+ *q = CLIP_16 (v);
+ q += channels;
}
}
- break;
}
+ break;
case AV_SAMPLE_FMT_FLT:
{
+ int ff_channels = this->audio_channels;
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;
+ i = 0;
+ if (this->front_mix[1] >= 0) {
+ float *p1 = p + this->front_mix[0];
+ float *p2 = p + this->front_mix[1];
+ float *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ float m = *p1 + *p2;
+ int v = (*p + m) * gain;
+ p1 += ff_channels;
+ p2 += ff_channels;
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (*p0 + m) * gain;
+ p0 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ } else if (this->front_mix[0] >= 0) {
+ float *p1 = p + this->front_mix[0];
+ float *p0 = p + this->map[1];
+ for (j = samples; j; j--) {
+ int v = (*p + *p1) * gain;
+ p += ff_channels;
+ *q++ = CLIP_16 (v);
+ v = (*p0 + *p1) * gain;
+ p0 += ff_channels;
+ p1 += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels - 1;
+ }
+ i = 2;
+ }
+ for (; i < channels; i++) if (this->map[i] >= 0) {
+ q = decode_buffer + i;
+ p = (float *)this->av_frame->extended_data[0] + this->map[i];
+ for (j = samples; j; j--) {
+ int v = *p * gain;
+ p += ff_channels;
+ *q = CLIP_16 (v);
+ q += channels;
+ }
}
}
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);
@@ -606,9 +934,10 @@ static void ff_audio_decode_data (audio_
/* pts applies only to first audio packet */
buf->pts = 0;
} else {
+ ff_map_channels (this);
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->ao_mode);
if (!this->output_open) {
xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
"ffmpeg_audio_dec: error opening audio output\n");
@@ -618,6 +947,80 @@ static void ff_audio_decode_data (audio_
}
}
+#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->audio_channels) || (this->ao_channels > 2)) {
+ /* Channel reordering and/or mixing */
+ int samples = decode_buffer_size / (this->audio_channels * 2);
+ int channels = this->ao_channels;
+ int ff_channels = this->audio_channels;
+ int16_t *p = (int16_t *)this->decode_buffer;
+ int16_t *q = p;
+ int 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);
+ if (this->front_mix[1] >= 0) {
+ for (i = samples; i; i--) {
+ int m = (int)p[this->front_mix[0]] + (int)p[this->front_mix[1]];
+ int v = ((int)p[this->map[0]] + m) >> 1;
+ *q++ = CLIP_16 (v);
+ v = ((int)p[this->map[1]] + m) >> 1;
+ *q++ = CLIP_16 (v);
+ for (j = 2; j < channels; j++)
+ *q++ = this->map[j] < 0 ? 0 : p[this->map[j]] >> 1;
+ p += ff_channels;
+ }
+ } else if (this->front_mix[0] >= 0) {
+ for (i = samples; i; i--) {
+ int m = (int)p[this->front_mix[0]];
+ *q++ = ((int)p[this->map[0]] + m) >> 1;
+ *q++ = ((int)p[this->map[1]] + m) >> 1;
+ for (j = 2; j < channels; j++)
+ *q++ = this->map[j] < 0 ? 0 : p[this->map[j]] >> 1;
+ p += ff_channels;
+ }
+ } else {
+ for (i = samples; i; i--) {
+ for (j = 0; j < channels; j++)
+ *q++ = this->map[j] < 0 ? 0 : p[this->map[j]];
+ p += ff_channels;
+ }
+ }
+ if (channels > this->ao_channels) {
+ /* final mono downmix */
+ 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) {
@@ -637,40 +1040,16 @@ static void ff_audio_decode_data (audio_
}
/* 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.);
- }
-
- 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;
+ 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;