diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 7 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 10 | ||||
-rw-r--r-- | src/xine-engine/audio_out.c | 253 | ||||
-rw-r--r-- | src/xine-engine/audio_out.h | 24 | ||||
-rw-r--r-- | src/xine-engine/resample.c | 50 | ||||
-rw-r--r-- | src/xine-engine/resample.h | 14 |
6 files changed, 271 insertions, 87 deletions
diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 4dcf98ae2..0ac30a2e0 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -26,7 +26,7 @@ * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.66 2002/07/01 11:45:25 pmhahn Exp $ + * $Id: audio_alsa_out.c,v 1.67 2002/07/01 13:51:26 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -942,7 +942,12 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { printf ("audio_alsa_out: access type not available"); return NULL; } + this->capabilities = 0; + + if ( !(snd_pcm_hw_params_set_format(this->audio_fd, params, SND_PCM_FORMAT_U8))) + this->capabilities |= AO_CAP_8BITS; + printf ("audio_alsa_out : supported modes are "); if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 1))) { this->capabilities |= AO_CAP_MODE_MONO; diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index dedff1aa4..af1264a7a 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_oss_out.c,v 1.69 2002/06/13 18:36:26 tmattern Exp $ + * $Id: audio_oss_out.c,v 1.70 2002/07/01 13:51:27 miguelfreitas Exp $ * * 20-8-2001 First implementation of Audio sync and Audio driver separation. * Copyright (C) 2001 James Courtier-Dutton James@superbug.demon.co.uk @@ -622,7 +622,7 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { int rate ; int devnum; int audio_fd; - int num_channels, status, arg; + int num_channels, bits, status, arg; static char *sync_methods[] = {"auto", "getodelay", "getoptr", "softsync", "probebuffer", NULL}; this = (oss_driver_t *) malloc (sizeof (oss_driver_t)); @@ -775,7 +775,11 @@ ao_driver_t *init_audio_out_plugin (config_values_t *config) { NULL, NULL); this->capabilities = 0; - + + bits = 8; + if( ioctl(audio_fd, SNDCTL_DSP_SAMPLESIZE,&bits) != -1 ) + this->capabilities |= AO_CAP_8BITS; + printf ("audio_oss_out : supported modes are "); num_channels = 1; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 47f440933..9767ba26b 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.59 2002/06/22 13:40:38 mroi Exp $ + * $Id: audio_out.c,v 1.60 2002/07/01 13:51:27 miguelfreitas Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -231,7 +231,7 @@ static void ao_fill_gap (ao_instance_t *this, int64_t pts_len) { printf ("audio_out: inserting %d 0-frames to fill a gap of %lld pts\n", num_frames, pts_len); - if ((this->mode == AO_CAP_MODE_A52) || (this->mode == AO_CAP_MODE_AC5)) { + if ((this->output.mode == AO_CAP_MODE_A52) || (this->output.mode == AO_CAP_MODE_AC5)) { write_pause_burst(this,num_frames); return; } @@ -247,19 +247,48 @@ static void ao_fill_gap (ao_instance_t *this, int64_t pts_len) { } } -static void ensure_buffer_size (ao_instance_t *this, int size) +static void ensure_buffer_size (audio_buffer_t *buf, int bytes_per_frame, + int frames) { - if (this->frame_buffer_size < size) { - this->frame_buffer = realloc( this->frame_buffer, size ); - this->frame_buffer_size = size; + int size = bytes_per_frame * frames; + + if (buf->mem_size < size) { + buf->mem = realloc( buf->mem, size ); + buf->mem_size = size; } + buf->num_frames = frames; +} + +static audio_buffer_t * swap_frame_buffers ( ao_instance_t *this ) { + audio_buffer_t *tmp; + + tmp = this->frame_buf[1]; + this->frame_buf[1] = this->frame_buf[0]; + this->frame_buf[0] = tmp; + return this->frame_buf[0]; } +static int mode_channels( int mode ) { + switch( mode ) { + case AO_CAP_MODE_MONO: + return 1; + case AO_CAP_MODE_STEREO: + return 2; + case AO_CAP_MODE_4CHANNEL: + return 4; + case AO_CAP_MODE_5CHANNEL: + return 5; + case AO_CAP_MODE_5_1CHANNEL: + return 6; + } + return 0; +} + static void *ao_loop (void *this_gen) { ao_instance_t *this = (ao_instance_t *) this_gen; int64_t hw_vpts; - audio_buffer_t *buf; + audio_buffer_t *buf, *in_buf; int64_t gap; int delay; int64_t cur_time; @@ -274,7 +303,7 @@ static void *ao_loop (void *this_gen) { while ((this->audio_loop_running) || (!this->audio_loop_running && this->out_fifo->first)) { - buf = fifo_remove (this->out_fifo); + in_buf = buf = fifo_remove (this->out_fifo); bufs_since_sync++; #ifdef LOG @@ -300,7 +329,7 @@ static void *ao_loop (void *this_gen) { #endif /* External A52 decoder delay correction */ - if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5)) + if ((this->output.mode==AO_CAP_MODE_A52) || (this->output.mode==AO_CAP_MODE_AC5)) delay+=10; hw_vpts += delay * 1024 / this->frames_per_kpts; @@ -387,53 +416,104 @@ static void *ao_loop (void *this_gen) { printf ("audio_out: outputting %d frames\n", num_output_frames); #endif - /* check if resample is needed */ - if (((!this->do_resample) || (buf->num_frames == num_output_frames)) - && (this->mode != AO_CAP_MODE_A52) - && (this->mode != AO_CAP_MODE_AC5)) { - - this->driver->write (this->driver, buf->mem, - buf->num_frames ); - } else switch (this->mode) { - case AO_CAP_MODE_MONO: - ensure_buffer_size(this, 2*num_output_frames); - audio_out_resample_mono (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_STEREO: - ensure_buffer_size(this, 4*num_output_frames); - audio_out_resample_stereo (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_4CHANNEL: - ensure_buffer_size(this, 8*num_output_frames); - audio_out_resample_4channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5CHANNEL: - ensure_buffer_size(this, 10*num_output_frames); - audio_out_resample_5channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5_1CHANNEL: - ensure_buffer_size(this, 12*num_output_frames); - audio_out_resample_6channel (buf->mem, buf->num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_A52: - case AO_CAP_MODE_AC5: - this->driver->write(this->driver, buf->mem, buf->num_frames); - break; + /* convert 8 bit samples as needed */ + if( this->input.bits == 8 && + (this->do_resample || this->output.bits != 8 || + this->input.mode != this->output.mode ) ) { + ensure_buffer_size(this->frame_buf[1], 2*mode_channels(this->input.mode), + buf->num_frames ); + audio_out_resample_8to16((int8_t *)buf->mem, this->frame_buf[1]->mem, + mode_channels(this->input.mode) * buf->num_frames ); + buf = swap_frame_buffers(this); + } + + /* check if resampling may be skipped */ + if ( this->do_resample && + buf->num_frames != num_output_frames ) { + switch (this->input.mode) { + case AO_CAP_MODE_MONO: + ensure_buffer_size(this->frame_buf[1], 2, num_output_frames); + audio_out_resample_mono (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_STEREO: + ensure_buffer_size(this->frame_buf[1], 4, num_output_frames); + audio_out_resample_stereo (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_4CHANNEL: + ensure_buffer_size(this->frame_buf[1], 8, num_output_frames); + audio_out_resample_4channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_5CHANNEL: + ensure_buffer_size(this->frame_buf[1], 10, num_output_frames); + audio_out_resample_5channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_5_1CHANNEL: + ensure_buffer_size(this->frame_buf[1], 12, num_output_frames); + audio_out_resample_6channel (buf->mem, buf->num_frames, + this->frame_buf[1]->mem, num_output_frames); + buf = swap_frame_buffers(this); + break; + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + /* pass-through modes: no resampling */ + break; + } + } + + /* mode conversion */ + if ( this->input.mode != this->output.mode ) { + switch (this->input.mode) { + case AO_CAP_MODE_MONO: + if( this->output.mode == AO_CAP_MODE_STEREO ) { + ensure_buffer_size(this->frame_buf[1], 4, buf->num_frames ); + audio_out_resample_monotostereo(buf->mem, this->frame_buf[1]->mem, + buf->num_frames ); + buf = swap_frame_buffers(this); + } + break; + case AO_CAP_MODE_STEREO: + if( this->output.mode == AO_CAP_MODE_MONO ) { + ensure_buffer_size(this->frame_buf[1], 2, buf->num_frames ); + audio_out_resample_stereotomono(buf->mem, this->frame_buf[1]->mem, + buf->num_frames ); + buf = swap_frame_buffers(this); + } + break; + case AO_CAP_MODE_4CHANNEL: + break; + case AO_CAP_MODE_5CHANNEL: + break; + case AO_CAP_MODE_5_1CHANNEL: + break; + case AO_CAP_MODE_A52: + case AO_CAP_MODE_AC5: + break; + } } + + /* convert back to 8 bits after resampling */ + if( this->output.bits == 8 && (this->do_resample || + this->input.mode != this->output.mode) ) { + ensure_buffer_size(this->frame_buf[1], 1*mode_channels(this->output.mode), + buf->num_frames ); + audio_out_resample_16to8(buf->mem, (int8_t *)this->frame_buf[1]->mem, + mode_channels(this->output.mode) * buf->num_frames ); + buf = swap_frame_buffers(this); + } + + this->driver->write (this->driver, buf->mem, buf->num_frames ); } pthread_mutex_unlock( &this->driver_lock ); - fifo_append (this->free_fifo, buf); + fifo_append (this->free_fifo, in_buf); } @@ -455,6 +535,29 @@ static int ao_open(ao_instance_t *this, "audio_out: stream audio format is %d kHz sampling rate, %d bits. mode is %d.\n", rate, bits, mode); + this->input.mode = mode; + this->input.rate = rate; + this->input.bits = bits; + + /* not all drivers/cards support 8 bits */ + if( this->input.bits == 8 && + !(this->driver->get_capabilities(this->driver) & AO_CAP_8BITS) ) { + bits = 16; + printf("audio_out: 8 bits not supported by driver, converting to 16 bits.\n"); + } + + /* provide mono->stereo and stereo->mono conversions */ + if( this->input.mode == AO_CAP_MODE_MONO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_MONO) ) { + mode = AO_CAP_MODE_STEREO; + printf("audio_out: mono not supported by driver, converting to stereo.\n"); + } + if( this->input.mode == AO_CAP_MODE_STEREO && + !(this->driver->get_capabilities(this->driver) & AO_CAP_MODE_STEREO) ) { + mode = AO_CAP_MODE_MONO; + printf("audio_out: stereo not supported by driver, converting to mono.\n"); + } + pthread_mutex_lock( &this->driver_lock ); output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode); pthread_mutex_unlock( &this->driver_lock ); @@ -466,11 +569,10 @@ static int ao_open(ao_instance_t *this, printf("audio_out: output sample rate %d\n", output_sample_rate); - this->mode = mode; - this->input_frame_rate = rate; - this->bits = bits; this->last_audio_vpts = 0; - this->output_frame_rate = output_sample_rate; + this->output.mode = mode; + this->output.rate = output_sample_rate; + this->output.bits = bits; switch (this->resample_conf) { case 1: /* force off */ @@ -480,24 +582,16 @@ static int ao_open(ao_instance_t *this, this->do_resample = 1; break; default: /* AUTO */ - this->do_resample = this->output_frame_rate != this->input_frame_rate; + this->do_resample = this->output.rate != this->input.rate; } - /* HACK: we do not have resample functions for 8-bit audio */ - if (this->bits==8) - this->do_resample = 0; - if (this->do_resample) printf("audio_out: will resample audio from %d to %d\n", - this->input_frame_rate, this->output_frame_rate); - - pthread_mutex_lock( &this->driver_lock ); - this->num_channels = this->driver->num_channels(this->driver); - pthread_mutex_unlock( &this->driver_lock ); + this->input.rate, this->output.rate); - this->frame_rate_factor = (double) this->output_frame_rate / (double) this->input_frame_rate; - this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input_frame_rate; - this->frames_per_kpts = this->output_frame_rate * 1024 / 90000; + this->frame_rate_factor = (double) this->output.rate / (double) this->input.rate; + this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input.rate; + this->frames_per_kpts = this->output.rate * 1024 / 90000; #ifdef LOG printf ("audio_out : audio_step %d pts per 32768 frames\n", this->audio_step); #endif @@ -525,7 +619,7 @@ static int ao_open(ao_instance_t *this, } else printf ("audio_out: thread created\n"); - return this->output_frame_rate; + return this->output.rate; } static audio_buffer_t *ao_get_buffer (ao_instance_t *this) { @@ -616,7 +710,10 @@ static void ao_exit(ao_instance_t *this) { this->driver->exit(this->driver); pthread_mutex_unlock( &this->driver_lock ); - free (this->frame_buffer); + free (this->frame_buf[0]->mem); + free (this->frame_buf[0]); + free (this->frame_buf[1]->mem); + free (this->frame_buf[1]); free (this->zero_space); buf = this->free_fifo->first; @@ -719,8 +816,6 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { this->control = ao_control; this->audio_loop_running = 0; this->audio_paused = 0; - this->frame_buffer = xine_xmalloc (4 * AUDIO_BUF_SIZE); - this->frame_buffer_size = 4 * AUDIO_BUF_SIZE; this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6); this->gap_tolerance = driver->get_gap_tolerance (this->driver); @@ -749,6 +844,18 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) { fifo_append (this->free_fifo, buf); } + + /* buffers used for audio conversions */ + for (i=0; i<2; i++) { + + audio_buffer_t *buf; + + buf = (audio_buffer_t *) malloc (sizeof (audio_buffer_t)); + buf->mem = malloc (4*AUDIO_BUF_SIZE); + buf->mem_size = 4*AUDIO_BUF_SIZE; + + this->frame_buf[i] = buf; + } /* * Set audio volume to latest used one ? diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index 1cb4baade..d7a345ac9 100644 --- a/src/xine-engine/audio_out.h +++ b/src/xine-engine/audio_out.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.h,v 1.30 2002/05/24 12:23:58 miguelfreitas Exp $ + * $Id: audio_out.h,v 1.31 2002/07/01 13:51:28 miguelfreitas Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -148,6 +148,14 @@ struct audio_buffer_s { uint32_t first_access_unit; }; +typedef struct ao_format_s ao_format_t; + +struct ao_format_s { + uint32_t bits; + uint32_t rate; + int mode; +}; + typedef struct ao_instance_s ao_instance_t; struct ao_instance_s { @@ -207,20 +215,19 @@ struct ao_instance_s { int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */ int32_t frames_per_kpts; /* frames per 1024/90000 sec */ - int32_t output_frame_rate, input_frame_rate; + + ao_format_t input, output; /* format conversion done at audio_out.c */ double frame_rate_factor; - uint32_t num_channels; - int64_t last_audio_vpts; + int resample_conf; int force_rate; /* force audio output rate to this value if non-zero */ int do_resample; - int mode; - int bits; int gap_tolerance; audio_fifo_t *free_fifo; audio_fifo_t *out_fifo; - uint16_t *frame_buffer; - uint32_t frame_buffer_size; + int64_t last_audio_vpts; + + audio_buffer_t *frame_buf[2]; /* two buffers for "stackable" conversions */ int16_t *zero_space; }; @@ -263,6 +270,7 @@ ao_instance_t *ao_new_instance (ao_driver_t *driver, xine_t *xine) ; #define AO_CAP_MIXER_VOL 0x00000080 /* driver supports mixer control */ #define AO_CAP_PCM_VOL 0x00000100 /* driver supports pcm control */ #define AO_CAP_MUTE_VOL 0x00000200 /* driver can mute volume */ +#define AO_CAP_8BITS 0x00000400 /* driver support 8-bit samples */ /* properties supported by get/set_property() */ #define AO_PROP_MIXER_VOL 0 diff --git a/src/xine-engine/resample.c b/src/xine-engine/resample.c index 4b363735c..6f7863e6e 100644 --- a/src/xine-engine/resample.c +++ b/src/xine-engine/resample.c @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: resample.c,v 1.2 2001/12/27 14:30:30 f1rmb Exp $ + * $Id: resample.c,v 1.3 2002/07/01 13:51:28 miguelfreitas Exp $ */ #ifdef HAVE_CONFIG_H @@ -278,3 +278,51 @@ void audio_out_resample_6channel(int16_t* input_samples, uint32_t in_samples, output_samples[out_samples*6-2] = input_samples[in_samples*6-2]; output_samples[out_samples*6-1] = input_samples[in_samples*6-1]; } + +void audio_out_resample_8to16(int8_t* input_samples, + int16_t* output_samples, uint32_t samples) +{ + while( samples-- ) { + int16_t os; + + os = *input_samples++; + os = (os - 0x80) << 8; + *output_samples++ = os; + } +} + +void audio_out_resample_16to8(int16_t* input_samples, + int8_t* output_samples, uint32_t samples) +{ + while( samples-- ) { + int16_t os; + + os = *input_samples++; + os = (os >> 8) + 0x80; + *output_samples++ = os; + } +} + +void audio_out_resample_monotostereo(int16_t* input_samples, + int16_t* output_samples, uint32_t frames) +{ + while( frames-- ) { + int16_t os; + + os = *input_samples++; + *output_samples++ = os; + *output_samples++ = os; + } +} + +void audio_out_resample_stereotomono(int16_t* input_samples, + int16_t* output_samples, uint32_t frames) +{ + while( frames-- ) { + int16_t os; + + os = (*input_samples++)>>1; + os += (*input_samples++)>>1; + *output_samples++ = os; + } +} diff --git a/src/xine-engine/resample.h b/src/xine-engine/resample.h index 8693aea19..e56ec45d6 100644 --- a/src/xine-engine/resample.h +++ b/src/xine-engine/resample.h @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: resample.h,v 1.1 2001/08/21 19:48:48 jcdutton Exp $ + * $Id: resample.h,v 1.2 2002/07/01 13:51:28 miguelfreitas Exp $ * * utilitiy functions for audio drivers * @@ -42,4 +42,16 @@ void audio_out_resample_5channel(int16_t* input_samples, uint32_t in_samples, void audio_out_resample_6channel(int16_t* input_samples, uint32_t in_samples, int16_t* output_samples, uint32_t out_samples); +void audio_out_resample_8to16(int8_t* input_samples, + int16_t* output_samples, uint32_t samples); + +void audio_out_resample_16to8(int16_t* input_samples, + int8_t* output_samples, uint32_t samples); + +void audio_out_resample_monotostereo(int16_t* input_samples, + int16_t* output_samples, uint32_t frames); + +void audio_out_resample_stereotomono(int16_t* input_samples, + int16_t* output_samples, uint32_t frames); + #endif |