From: Torsten J. <t....@gm...> - 2013-08-13 16:29:30
|
# HG changeset patch # User Torsten Jager <t....@gm...> # Date 1376169715 -7200 # Node ID 16e7014e73695a0f7362500394647a330cfef04b # Branch default # Parent 683526bc6d2316d16e881bd8ea350363c6fce053 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. diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c --- 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 @@ 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 @@ #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 @@ /* 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 @@ } 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 @@ 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 @@ 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 @@ 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); [... 573 lines omitted ...] + 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 @@ } /* 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; + if ((decode_buffer_size - out) > audio_buffer->mem_size) + bytes_to_send = audio_buffer->mem_size; + 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; - - 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 @@ 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 @@ 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; |