Commit 1ae5bed4 authored by Cyril Deguet's avatar Cyril Deguet

- better communication between audio decoder and output: aout plugins

are now opened directly in the right mode (works with mpeg_adec and
ac3_adec, not tested with mad)
- first attempt to implement mono output (doesn't work yet)
parent 1bed861b
......@@ -2,9 +2,10 @@
* audio_output.h : audio output thread interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: audio_output.h,v 1.39 2001/12/30 07:09:54 sam Exp $
* $Id: audio_output.h,v 1.40 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -212,7 +213,8 @@ typedef struct aout_thread_s
void aout_InitBank ( void );
void aout_EndBank ( void );
aout_thread_t * aout_CreateThread ( int *pi_status );
aout_thread_t * aout_CreateThread ( int *pi_status, int i_channels,
long l_rate );
void aout_DestroyThread ( aout_thread_t *, int * );
aout_fifo_t * aout_CreateFifo ( int, int, long, long, long, void * );
......
......@@ -2,7 +2,7 @@
* ac3_adec.c: ac3 decoder module main file
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ac3_adec.c,v 1.12 2001/12/31 04:53:33 sam Exp $
* $Id: ac3_adec.c,v 1.13 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Lespinasse <walken@zoy.org>
*
......@@ -95,121 +95,6 @@ static int decoder_Probe( probedata_t *p_data )
return ( p_data->i_type == AC3_AUDIO_ES ) ? 50 : 0;
}
/*****************************************************************************
* decoder_Run: this function is called just after the thread is created
*****************************************************************************/
static int decoder_Run ( decoder_config_t * p_config )
{
ac3dec_thread_t * p_ac3thread;
int sync;
intf_DbgMsg( "ac3_adec debug: ac3_adec thread launched, initializing" );
/* Allocate the memory needed to store the thread's structure */
p_ac3thread = (ac3dec_thread_t *)memalign(16, sizeof(ac3dec_thread_t));
if( p_ac3thread == NULL )
{
intf_ErrMsg ( "ac3_adec error: not enough memory "
"for decoder_Run() to allocate p_ac3thread" );
DecoderError( p_config->p_decoder_fifo );
return( -1 );
}
/*
* Initialize the thread properties
*/
p_ac3thread->p_config = p_config;
if( InitThread( p_ac3thread ) )
{
intf_ErrMsg( "ac3_adec error: could not initialize thread" );
DecoderError( p_config->p_decoder_fifo );
free( p_ac3thread );
return( -1 );
}
sync = 0;
p_ac3thread->sync_ptr = 0;
/* ac3 decoder thread's main loop */
/* FIXME : do we have enough room to store the decoded frames ?? */
while ((!p_ac3thread->p_fifo->b_die) && (!p_ac3thread->p_fifo->b_error))
{
s16 * buffer;
ac3_sync_info_t sync_info;
int ptr;
if (!sync) {
do {
GetBits(&p_ac3thread->ac3_decoder->bit_stream,8);
} while ((!p_ac3thread->sync_ptr) && (!p_ac3thread->p_fifo->b_die)
&& (!p_ac3thread->p_fifo->b_error));
ptr = p_ac3thread->sync_ptr;
while(ptr-- && (!p_ac3thread->p_fifo->b_die)
&& (!p_ac3thread->p_fifo->b_error))
{
p_ac3thread->ac3_decoder->bit_stream.p_byte++;
}
/* we are in sync now */
sync = 1;
}
if (p_ac3thread->p_fifo->p_first->i_pts)
{
p_ac3thread->p_aout_fifo->date[
p_ac3thread->p_aout_fifo->l_end_frame] =
p_ac3thread->p_fifo->p_first->i_pts;
p_ac3thread->p_fifo->p_first->i_pts = 0;
} else {
p_ac3thread->p_aout_fifo->date[
p_ac3thread->p_aout_fifo->l_end_frame] =
LAST_MDATE;
}
if (ac3_sync_frame (p_ac3thread->ac3_decoder, &sync_info))
{
sync = 0;
goto bad_frame;
}
p_ac3thread->p_aout_fifo->l_rate = sync_info.sample_rate;
buffer = ((s16 *)p_ac3thread->p_aout_fifo->buffer) +
(p_ac3thread->p_aout_fifo->l_end_frame * AC3DEC_FRAME_SIZE);
if (ac3_decode_frame (p_ac3thread->ac3_decoder, buffer))
{
sync = 0;
goto bad_frame;
}
vlc_mutex_lock (&p_ac3thread->p_aout_fifo->data_lock);
p_ac3thread->p_aout_fifo->l_end_frame =
(p_ac3thread->p_aout_fifo->l_end_frame + 1) & AOUT_FIFO_SIZE;
vlc_cond_signal (&p_ac3thread->p_aout_fifo->data_wait);
vlc_mutex_unlock (&p_ac3thread->p_aout_fifo->data_lock);
bad_frame:
RealignBits(&p_ac3thread->ac3_decoder->bit_stream);
}
/* If b_error is set, the ac3 decoder thread enters the error loop */
if (p_ac3thread->p_fifo->b_error)
{
DecoderError( p_ac3thread->p_fifo );
}
/* End of the ac3 decoder thread */
EndThread (p_ac3thread);
free( p_ac3thread );
return( 0 );
}
/*****************************************************************************
* InitThread: initialize data before entering main loop
......@@ -312,43 +197,6 @@ static int InitThread( ac3dec_thread_t * p_ac3thread )
intf_DbgMsg ( "ac3_adec debug: ac3_adec thread (%p) initialized",
p_ac3thread );
/* Creating the audio output fifo */
p_ac3thread->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_STEREO_FIFO, 2, 0, 0,
AC3DEC_FRAME_SIZE, NULL );
if ( p_ac3thread->p_aout_fifo == NULL )
{
free( IMDCT->w_1 );
free( IMDCT->w_64 );
free( IMDCT->w_32 );
free( IMDCT->w_16 );
free( IMDCT->w_8 );
free( IMDCT->w_4 );
free( IMDCT->w_2 );
free( IMDCT->xcos_sin_sse );
free( IMDCT->xsin2 );
free( IMDCT->xcos2 );
free( IMDCT->xsin1 );
free( IMDCT->xcos1 );
free( IMDCT->delay1 );
free( IMDCT->delay );
free( IMDCT->buf );
#undef IMDCT
#if defined( __MINGW32__ )
free( p_ac3thread->ac3_decoder->samples_back );
#else
free( p_ac3thread->ac3_decoder->samples );
#endif
module_Unneed( p_ac3thread->ac3_decoder->imdct->p_module );
module_Unneed( p_ac3thread->ac3_decoder->downmix.p_module );
free( p_ac3thread->ac3_decoder->imdct );
free( p_ac3thread->ac3_decoder );
return( -1 );
}
/*
* Bit stream
*/
......@@ -362,6 +210,158 @@ static int InitThread( ac3dec_thread_t * p_ac3thread )
return( 0 );
}
/*****************************************************************************
* decoder_Run: this function is called just after the thread is created
*****************************************************************************/
static int decoder_Run ( decoder_config_t * p_config )
{
ac3dec_thread_t * p_ac3thread;
int sync;
intf_DbgMsg( "ac3_adec debug: ac3_adec thread launched, initializing" );
/* Allocate the memory needed to store the thread's structure */
p_ac3thread = (ac3dec_thread_t *)memalign(16, sizeof(ac3dec_thread_t));
if( p_ac3thread == NULL )
{
intf_ErrMsg ( "ac3_adec error: not enough memory "
"for decoder_Run() to allocate p_ac3thread" );
DecoderError( p_config->p_decoder_fifo );
return( -1 );
}
/*
* Initialize the thread properties
*/
p_ac3thread->p_config = p_config;
if( InitThread( p_ac3thread ) )
{
intf_ErrMsg( "ac3_adec error: could not initialize thread" );
DecoderError( p_config->p_decoder_fifo );
free( p_ac3thread );
return( -1 );
}
sync = 0;
p_ac3thread->sync_ptr = 0;
/* ac3 decoder thread's main loop */
/* FIXME : do we have enough room to store the decoded frames ?? */
while ((!p_ac3thread->p_fifo->b_die) && (!p_ac3thread->p_fifo->b_error))
{
s16 * buffer;
ac3_sync_info_t sync_info;
int ptr;
if (!sync) {
do {
GetBits(&p_ac3thread->ac3_decoder->bit_stream,8);
} while ((!p_ac3thread->sync_ptr) && (!p_ac3thread->p_fifo->b_die)
&& (!p_ac3thread->p_fifo->b_error));
ptr = p_ac3thread->sync_ptr;
while(ptr-- && (!p_ac3thread->p_fifo->b_die)
&& (!p_ac3thread->p_fifo->b_error))
{
p_ac3thread->ac3_decoder->bit_stream.p_byte++;
}
/* we are in sync now */
sync = 1;
}
if (ac3_sync_frame (p_ac3thread->ac3_decoder, &sync_info))
{
sync = 0;
goto bad_frame;
}
/* Creating the audio output fifo if not created yet */
if (p_ac3thread->p_aout_fifo == NULL ) {
p_ac3thread->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_STEREO_FIFO,
2, sync_info.sample_rate, 0, AC3DEC_FRAME_SIZE, NULL );
if ( p_ac3thread->p_aout_fifo == NULL )
{
free( IMDCT->w_1 );
free( IMDCT->w_64 );
free( IMDCT->w_32 );
free( IMDCT->w_16 );
free( IMDCT->w_8 );
free( IMDCT->w_4 );
free( IMDCT->w_2 );
free( IMDCT->xcos_sin_sse );
free( IMDCT->xsin2 );
free( IMDCT->xcos2 );
free( IMDCT->xsin1 );
free( IMDCT->xcos1 );
free( IMDCT->delay1 );
free( IMDCT->delay );
free( IMDCT->buf );
#undef IMDCT
#if defined( __MINGW32__ )
free( p_ac3thread->ac3_decoder->samples_back );
#else
free( p_ac3thread->ac3_decoder->samples );
#endif
module_Unneed( p_ac3thread->ac3_decoder->imdct->p_module );
module_Unneed( p_ac3thread->ac3_decoder->downmix.p_module );
free( p_ac3thread->ac3_decoder->imdct );
free( p_ac3thread->ac3_decoder );
return( -1 );
}
}
if (p_ac3thread->p_fifo->p_first->i_pts)
{
p_ac3thread->p_aout_fifo->date[
p_ac3thread->p_aout_fifo->l_end_frame] =
p_ac3thread->p_fifo->p_first->i_pts;
p_ac3thread->p_fifo->p_first->i_pts = 0;
} else {
p_ac3thread->p_aout_fifo->date[
p_ac3thread->p_aout_fifo->l_end_frame] =
LAST_MDATE;
}
buffer = ((s16 *)p_ac3thread->p_aout_fifo->buffer) +
(p_ac3thread->p_aout_fifo->l_end_frame * AC3DEC_FRAME_SIZE);
if (ac3_decode_frame (p_ac3thread->ac3_decoder, buffer))
{
sync = 0;
goto bad_frame;
}
vlc_mutex_lock (&p_ac3thread->p_aout_fifo->data_lock);
p_ac3thread->p_aout_fifo->l_end_frame =
(p_ac3thread->p_aout_fifo->l_end_frame + 1) & AOUT_FIFO_SIZE;
vlc_cond_signal (&p_ac3thread->p_aout_fifo->data_wait);
vlc_mutex_unlock (&p_ac3thread->p_aout_fifo->data_lock);
bad_frame:
RealignBits(&p_ac3thread->ac3_decoder->bit_stream);
}
/* If b_error is set, the ac3 decoder thread enters the error loop */
if (p_ac3thread->p_fifo->b_error)
{
DecoderError( p_ac3thread->p_fifo );
}
/* End of the ac3 decoder thread */
EndThread (p_ac3thread);
free( p_ac3thread );
return( 0 );
}
/*****************************************************************************
* EndThread : ac3 decoder thread destruction
......
......@@ -2,7 +2,7 @@
* aout_dsp.c : dsp functions library
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: aout_dsp.c,v 1.18 2001/12/30 07:09:54 sam Exp $
* $Id: aout_dsp.c,v 1.19 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
......@@ -133,10 +133,13 @@ static int aout_Open( aout_thread_t *p_aout )
/* Initialize some variables */
p_aout->psz_device = main_GetPszVariable( AOUT_DSP_VAR, AOUT_DSP_DEFAULT );
p_aout->i_format = AOUT_FORMAT_DEFAULT;
/* All that is drawn directly from the audio stream.
p_aout->i_channels = 1 + main_GetIntVariable( AOUT_STEREO_VAR,
AOUT_STEREO_DEFAULT );
p_aout->l_rate = main_GetIntVariable( AOUT_RATE_VAR,
AOUT_RATE_DEFAULT );
*/
/* Open the sound device */
if( (p_aout->i_fd = open( p_aout->psz_device, O_WRONLY )) < 0 )
......
......@@ -2,11 +2,12 @@
* mpeg_adec.c: MPEG audio decoder thread
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: mpeg_adec.c,v 1.10 2001/12/30 07:09:55 sam Exp $
* $Id: mpeg_adec.c,v 1.11 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Michel Lespinasse <walken@via.ecp.fr>
* Samuel Hocevar <sam@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -125,14 +126,9 @@ static int decoder_Run ( decoder_config_t * p_config )
p_adec->p_config->pf_init_bit_stream( &p_adec->bit_stream,
p_adec->p_config->p_decoder_fifo, NULL, NULL );
/* Create the audio output fifo */
p_adec->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_STEREO_FIFO, 2, 0, 0,
ADEC_FRAME_SIZE, NULL );
if ( p_adec->p_aout_fifo == NULL )
{
intf_ErrMsg("mpeg_adec error: cannot create audio output fifo");
return -1;
}
/* We do not create the audio output fifo now, but
it will be created when the first frame is received */
p_adec->p_aout_fifo = NULL;
intf_DbgMsg("mpeg_adec debug: thread initialized, decoding begins.");
......@@ -170,6 +166,35 @@ static void DecodeThread( adec_thread_t * p_adec )
if( ! adec_SyncFrame (p_adec, &sync_info) )
{
/* TODO: check if audio type has changed */
/* Create the output fifo if it doesn't exist yet */
if( p_adec->p_aout_fifo == NULL )
{
int fifo_type;
int channels;
if( sync_info.b_stereo )
{
fifo_type = AOUT_ADEC_STEREO_FIFO;
channels = 2;
}
else
{
fifo_type = AOUT_ADEC_MONO_FIFO;
channels = 1;
}
p_adec->p_aout_fifo = aout_CreateFifo( fifo_type, channels,
sync_info.sample_rate, 0, ADEC_FRAME_SIZE, NULL );
if( p_adec->p_aout_fifo == NULL)
{
intf_ErrMsg( "adec error: failed to create Audio Output "
"Fifo." );
DecoderError( p_adec->p_fifo );
}
}
p_adec->i_sync = 1;
p_adec->p_aout_fifo->l_rate = sync_info.sample_rate;
......
......@@ -2,10 +2,11 @@
* adec_generic.c: MPEG audio decoder
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: mpeg_adec_generic.c,v 1.5 2001/12/30 07:09:55 sam Exp $
* $Id: mpeg_adec_generic.c,v 1.6 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Michel Lespinasse <walken@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -167,6 +168,14 @@ int adec_SyncFrame( adec_thread_t * p_adec, adec_sync_info_t * p_sync_info )
RemoveBits( &p_adec->bit_stream, 24 );
p_adec->i_read_bits = 32;
if( ! (p_adec->header & 0x10000) )
{
/* Error check, skip it */
RemoveBits( &p_adec->bit_stream, 16 );
p_adec->i_read_bits += 16;
}
p_sync_info->b_stereo = ((p_adec->header & 0xc0) != 0xc0);
p_sync_info->sample_rate = sample_rate;
p_sync_info->bit_rate = bit_rate;
p_sync_info->frame_size = frame_size;
......@@ -179,13 +188,6 @@ int adec_DecodeFrame( adec_thread_t * p_adec, s16 * buffer )
{
int i_total_bytes_read;
if( ! (p_adec->header & 0x10000) )
{
/* Error check, skip it */
RemoveBits( &p_adec->bit_stream, 16 );
p_adec->i_read_bits += 16;
}
/* parse audio data */
switch( (p_adec->header >> 17) & 3 )
......
......@@ -2,7 +2,7 @@
* audio_decoder.h : audio decoder interface
*****************************************************************************
* Copyright (C) 1999, 2000 VideoLAN
* $Id: mpeg_adec_generic.h,v 1.1 2001/11/13 12:09:18 henri Exp $
* $Id: mpeg_adec_generic.h,v 1.2 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
*
......@@ -29,6 +29,7 @@ typedef struct adec_sync_info_s {
int sample_rate; /* sample rate in Hz */
int frame_size; /* frame size in bytes */
int bit_rate; /* nominal bit rate in kbps */
int b_stereo; /* mono/stereo */
} adec_sync_info_t;
typedef struct adec_bank_s
......
......@@ -2,9 +2,10 @@
* aout_ext-dec.c : exported fifo management functions
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: aout_ext-dec.c,v 1.8 2001/12/30 07:09:56 sam Exp $
* $Id: aout_ext-dec.c,v 1.9 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -50,7 +51,7 @@ aout_fifo_t * aout_CreateFifo( int i_type, int i_channels, long l_rate,
{
intf_WarnMsg( 1, "aout: no aout present, spawning one" );
p_aout = aout_CreateThread( NULL );
p_aout = aout_CreateThread( NULL, i_channels, l_rate );
/* Everything failed */
if( p_aout == NULL )
......@@ -70,7 +71,7 @@ aout_fifo_t * aout_CreateFifo( int i_type, int i_channels, long l_rate,
aout_DestroyThread( p_aout_bank->pp_aout[0], NULL );
p_aout = aout_CreateThread( NULL );
p_aout = aout_CreateThread( NULL, i_channels, l_rate );
/* Everything failed */
if( p_aout == NULL )
......
......@@ -35,14 +35,70 @@
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void S16StereoPlay( aout_thread_t * p_aout, aout_fifo_t * p_fifo );
static void S16Play( aout_thread_t * p_aout, aout_fifo_t * p_fifo );
/*****************************************************************************
* Functions
*****************************************************************************/
void aout_S16MonoThread( aout_thread_t * p_aout )
{
intf_ErrMsg( "aout error: 16 bit signed mono thread unsupported" );
int i_fifo;
long l_buffer, l_buffer_limit, l_bytes;
/* As the s32_buffer was created with calloc(), we don't have to set this
* memory to zero and we can immediately jump into the thread's loop */
while ( ! p_aout->b_die )
{
vlc_mutex_lock( &p_aout->fifos_lock );
for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
{
if( p_aout->fifo[i_fifo].b_die )
{
aout_FreeFifo( &p_aout->fifo[i_fifo] );
}
else
{
S16Play( p_aout, &p_aout->fifo[i_fifo] );
}
}
vlc_mutex_unlock( &p_aout->fifos_lock );
l_buffer_limit = p_aout->l_units; /* p_aout->b_stereo == 0 */
for ( l_buffer = 0; l_buffer < l_buffer_limit; l_buffer++ )
{
((s16 *)p_aout->buffer)[l_buffer] =
(s16)( ( p_aout->s32_buffer[l_buffer] / AOUT_MAX_FIFOS )
* p_aout->i_volume / 256 ) ;
p_aout->s32_buffer[l_buffer] = 0;
}
l_bytes = p_aout->pf_getbufinfo( p_aout, l_buffer_limit );
/* sizeof(s16) << (p_aout->b_stereo) == 2 */
p_aout->date = mdate() + ((((mtime_t)((l_bytes + 2 * p_aout->i_latency) / 2)) * 1000000)
/ ((mtime_t)p_aout->l_rate))
+ p_main->i_desync;
p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
l_buffer_limit * sizeof(s16) );
if ( l_bytes > (l_buffer_limit * sizeof(s16)) )
{
msleep( p_aout->l_msleep );
}
}
vlc_mutex_lock( &p_aout->fifos_lock );
for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
{
aout_FreeFifo( &p_aout->fifo[i_fifo] );
}
vlc_mutex_unlock( &p_aout->fifos_lock );
}
void aout_S16StereoThread( aout_thread_t * p_aout )
......@@ -64,7 +120,7 @@ void aout_S16StereoThread( aout_thread_t * p_aout )
}
else
{
S16StereoPlay( p_aout, &p_aout->fifo[i_fifo] );
S16Play( p_aout, &p_aout->fifo[i_fifo] );
}
}
......@@ -107,7 +163,7 @@ void aout_S16StereoThread( aout_thread_t * p_aout )
/* Following functions are local */
static void S16StereoPlay( aout_thread_t * p_aout, aout_fifo_t * p_fifo )
static void S16Play( aout_thread_t * p_aout, aout_fifo_t * p_fifo )
{
long l_buffer = 0;
long l_buffer_limit, l_units;
......
......@@ -2,9 +2,10 @@
* audio_output.c : audio output thread
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: audio_output.c,v 1.69 2001/12/30 07:09:56 sam Exp $
* $Id: audio_output.c,v 1.70 2002/01/09 00:33:37 asmax Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Cyril Deguet <asmax@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -77,7 +78,7 @@ void aout_EndBank ( void )
/*****************************************************************************
* aout_CreateThread: initialize audio thread
*****************************************************************************/
aout_thread_t *aout_CreateThread( int *pi_status )
aout_thread_t *aout_CreateThread( int *pi_status, int i_channels, long l_rate )
{
aout_thread_t * p_aout; /* thread descriptor */
#if 0
......@@ -121,16 +122,11 @@ aout_thread_t *aout_CreateThread( int *pi_status )
return( NULL );
}
if( p_aout->l_rate == 0 )
{