summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Jager <t.jager@gmx.de>2013-08-10 23:21:55 +0200
committerTorsten Jager <t.jager@gmx.de>2013-08-10 23:21:55 +0200
commite5318f7f8fa3c9b6f09fd9d32202a61f86edc1d8 (patch)
treebfa437852d83b1a8c058199e1dc9f494096527a4
parenta771cb809c8f14057536f28f62930d32c2d4f088 (diff)
downloadxine-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.c646
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;