*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
-static int InitThread ( mad_adec_thread_t * p_mad_adec );
-static void EndThread ( mad_adec_thread_t * p_mad_adec );
+static int InitThread ( mad_adec_thread_t * );
+static void EndThread ( mad_adec_thread_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-#define DOWNSCALE_TEXT N_("Mad audio downscale routine (fast,mp321)")
+#define DOWNSCALE_TEXT N_("mad audio downscale routine (fast,mpg321)")
#define DOWNSCALE_LONGTEXT N_( \
"Specify the mad audio downscale routine you want to use. By default " \
"the mad plugin will use the fastest routine.")
vlc_module_begin();
- add_category_hint( N_("Miscellaneous"), NULL );
+ add_category_hint( N_("Libmad"), NULL );
add_string( "downscale", "fast", NULL, DOWNSCALE_TEXT, DOWNSCALE_LONGTEXT );
set_description( _("libmad MPEG 1/2/3 audio decoder") );
set_capability( "decoder", 100 );
*****************************************************************************/
static int RunDecoder( decoder_fifo_t *p_fifo )
{
- mad_adec_thread_t * p_mad_adec;
+ mad_adec_thread_t * p_dec;
+ int i_ret;
/* Allocate the memory needed to store the thread's structure */
- p_mad_adec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t));
+ p_dec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t));
- if (p_mad_adec == NULL)
+ if (p_dec == NULL)
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
- return( -1 );
+ return VLC_ENOMEM;
}
/*
* Initialize the thread properties
*/
- p_mad_adec->p_fifo = p_fifo;
- if( InitThread( p_mad_adec ) )
+ p_dec->p_fifo = p_fifo;
+ if( InitThread( p_dec ) )
{
msg_Err( p_fifo, "could not initialize thread" );
DecoderError( p_fifo );
- free( p_mad_adec );
- return( -1 );
+ free( p_dec );
+ return VLC_ETHREAD;
}
/* mad decoder thread's main loop */
- while ((!p_mad_adec->p_fifo->b_die) && (!p_mad_adec->p_fifo->b_error))
+ while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
{
- msg_Dbg( p_mad_adec->p_fifo, "starting libmad decoder" );
- if (mad_decoder_run(p_mad_adec->libmad_decoder, MAD_DECODER_MODE_SYNC)==-1)
+ msg_Dbg( p_dec->p_fifo, "starting libmad decoder" );
+ i_ret = mad_decoder_run( &p_dec->libmad_decoder,
+ MAD_DECODER_MODE_SYNC );
+ if( i_ret == -1 )
{
- msg_Err( p_mad_adec->p_fifo, "libmad decoder returned abnormally" );
- DecoderError( p_mad_adec->p_fifo );
- EndThread(p_mad_adec);
- return( -1 );
+ msg_Err( p_dec->p_fifo, "libmad decoder returned abnormally" );
+ DecoderError( p_dec->p_fifo );
+ EndThread(p_dec);
+ return VLC_EGENERIC;
}
}
/* If b_error is set, the mad decoder thread enters the error loop */
- if (p_mad_adec->p_fifo->b_error)
+ if (p_dec->p_fifo->b_error)
{
- DecoderError( p_mad_adec->p_fifo );
+ DecoderError( p_dec->p_fifo );
}
/* End of the mad decoder thread */
- EndThread (p_mad_adec);
+ EndThread (p_dec);
- return( 0 );
+ return VLC_SUCCESS;
}
/*****************************************************************************
* InitThread: initialize data before entering main loop
*****************************************************************************/
-static int InitThread( mad_adec_thread_t * p_mad_adec )
+static int InitThread( mad_adec_thread_t * p_dec )
{
- decoder_fifo_t * p_fifo = p_mad_adec->p_fifo;
+ decoder_fifo_t * p_fifo = p_dec->p_fifo;
char *psz_downscale = NULL;
/* Initialize the thread properties */
- p_mad_adec->p_aout = NULL;
- p_mad_adec->p_aout_input = NULL;
- p_mad_adec->output_format.i_format = AOUT_FMT_FIXED32;
- p_mad_adec->output_format.i_channels = 2; /* FIXME ! */
+ p_dec->p_aout = NULL;
+ p_dec->p_aout_input = NULL;
+ p_dec->output_format.i_format = AOUT_FMT_FIXED32;
+ p_dec->output_format.i_channels = 2; /* FIXME ! */
/*
* Properties of audio for libmad
if ( strncmp(psz_downscale,"fast",4)==0 )
{
- p_mad_adec->audio_scaling = FAST_SCALING;
+ p_dec->audio_scaling = FAST_SCALING;
msg_Dbg( p_fifo, "downscale fast selected" );
}
else if ( strncmp(psz_downscale,"mpg321",7)==0 )
{
- p_mad_adec->audio_scaling = MPG321_SCALING;
+ p_dec->audio_scaling = MPG321_SCALING;
msg_Dbg( p_fifo, "downscale mpg321 selected" );
}
else
{
- p_mad_adec->audio_scaling = FAST_SCALING;
+ p_dec->audio_scaling = FAST_SCALING;
msg_Dbg( p_fifo, "downscale default fast selected" );
}
if (psz_downscale) free(psz_downscale);
/* Initialize the libmad decoder structures */
- p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder));
- if (p_mad_adec->libmad_decoder == NULL)
- {
- msg_Err( p_mad_adec->p_fifo, "out of memory" );
- return -1;
- }
- p_mad_adec->i_current_pts = p_mad_adec->i_next_pts = 0;
+ p_dec->i_current_pts = p_dec->i_next_pts = 0;
- mad_decoder_init( p_mad_adec->libmad_decoder,
- p_mad_adec, /* vlc's thread structure and p_fifo playbuffer */
- libmad_input, /* input_func */
- 0, /* header_func */
- 0, /* filter */
- libmad_output3, /* output_func */
- 0, /* error */
- 0); /* message */
+ mad_decoder_init( &p_dec->libmad_decoder,
+ p_dec, /* vlc's thread structure and p_fifo playbuffer */
+ libmad_input, /* input_func */
+ NULL, /* header_func */
+ NULL, /* filter */
+ libmad_output, /* output_func */
+ NULL, /* error */
+ NULL ); /* message */
- mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC);
+ mad_decoder_options( &p_dec->libmad_decoder, MAD_OPTION_IGNORECRC );
/*
* Initialize the input properties
*/
+
+ /* Init the Bitstream */
+ InitBitstream( &p_dec->bit_stream, p_dec->p_fifo, NULL, NULL );
+
/* Get the first data packet. */
vlc_mutex_lock( &p_fifo->data_lock );
while ( p_fifo->p_first == NULL )
if ( p_fifo->b_die )
{
vlc_mutex_unlock( &p_fifo->data_lock );
- return( -1 );
+ return VLC_EGENERIC;
}
vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
}
vlc_mutex_unlock( &p_fifo->data_lock );
- p_mad_adec->p_data = p_fifo->p_first->p_first;
+ p_dec->p_data = p_fifo->p_first->p_first;
- return( 0 );
+ return VLC_SUCCESS;
}
/*****************************************************************************
* EndThread : libmad decoder thread destruction
*****************************************************************************/
-static void EndThread (mad_adec_thread_t * p_mad_adec)
+static void EndThread (mad_adec_thread_t * p_dec)
{
/* If the audio output fifo was created, we destroy it */
- if (p_mad_adec->p_aout_input != NULL)
+ if (p_dec->p_aout_input != NULL)
{
- aout_InputDelete( p_mad_adec->p_aout, p_mad_adec->p_aout_input );
+ aout_InputDelete( p_dec->p_aout, p_dec->p_aout_input );
}
/* mad_decoder_finish releases the memory allocated inside the struct */
- mad_decoder_finish( p_mad_adec->libmad_decoder );
+ mad_decoder_finish( &p_dec->libmad_decoder );
- /* Unlock the modules, p_mad_adec->p_fifo is released by the decoder subsystem */
- free( p_mad_adec->libmad_decoder );
- free( p_mad_adec );
+ free( p_dec );
}
* libmad_input: this function is called by libmad when the input buffer needs
* to be filled.
*****************************************************************************/
-enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
+enum mad_flow libmad_input( void *p_data, struct mad_stream *p_stream )
{
- mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
- size_t ReadSize, Remaining;
- unsigned char *ReadStart;
+ mad_adec_thread_t * p_dec = (mad_adec_thread_t *) p_data;
+ size_t i_wanted, i_left;
- if ( p_mad_adec->p_fifo->b_die == 1 ) {
- msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" );
+ if ( p_dec->p_fifo->b_die )
+ {
+ msg_Dbg( p_dec->p_fifo, "stopping libmad decoder" );
return MAD_FLOW_STOP;
}
- if ( p_mad_adec->p_fifo->b_error == 1 ) {
- msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" );
+ if ( p_dec->p_fifo->b_error )
+ {
+ msg_Warn( p_dec->p_fifo, "ignoring current audio frame" );
return MAD_FLOW_IGNORE;
}
- /* libmad_stream_buffer does not consume the total buffer, it consumes only data
- * for one frame only. So all data left in the buffer should be put back in front.
- */
- if ((p_libmad_stream->buffer==NULL) || (p_libmad_stream->error==MAD_ERROR_BUFLEN))
+ /* libmad_stream_buffer does not consume the total buffer, it consumes
+ * only data for one frame only. So all data left in the buffer should
+ * be put back in front. */
+ if ( !p_stream->buffer || p_stream->error == MAD_ERROR_BUFLEN )
{
- /* libmad does not consume all the buffer it's given. Some
- * datas, part of a truncated frame, is left unused at the
- * end of the buffer. Those datas must be put back at the
- * beginning of the buffer and taken in account for
- * refilling the buffer. This means that the input buffer
- * must be large enough to hold a complete frame at the
- * highest observable bit-rate (currently 448 kb/s). XXX=XXX
- * Is 2016 bytes the size of the largest frame?
- * (448000*(1152/32000))/8
- */
- if(p_libmad_stream->next_frame!=NULL)
+ /* libmad does not consume all the buffer it's given. Some data,
+ * part of a truncated frame, is left unused at the end of the
+ * buffer. Those datas must be put back at the beginning of the
+ * buffer and taken in account for refilling the buffer. This
+ * means that the input buffer must be large enough to hold a
+ * complete frame at the highest observable bit-rate (currently
+ * 448 kb/s). XXX=XXX Is 2016 bytes the size of the largest frame?
+ * (448000*(1152/32000))/8 */
+ if( p_stream->next_frame )
{
- Remaining=p_libmad_stream->bufend-p_libmad_stream->next_frame;
- if( p_mad_adec->buffer != p_libmad_stream->next_frame )
+ i_left = p_stream->bufend - p_stream->next_frame;
+ if( p_dec->buffer != p_stream->next_frame )
{
- memcpy( p_mad_adec->buffer,
- p_libmad_stream->next_frame, Remaining );
+ memcpy( p_dec->buffer, p_stream->next_frame, i_left );
}
- ReadStart=p_mad_adec->buffer+Remaining;
- ReadSize=(MAD_BUFFER_MDLEN)-Remaining;
+ i_wanted = MAD_BUFFER_MDLEN - i_left;
- /* Store time stamp of next frame */
- p_mad_adec->i_current_pts = p_mad_adec->i_next_pts;
- p_mad_adec->i_next_pts = p_mad_adec->p_fifo->p_first->i_pts;
+ /* Store timestamp for next frame */
+ p_dec->i_next_pts = p_dec->p_fifo->p_first->i_pts;
}
else
{
- ReadSize=(MAD_BUFFER_MDLEN);
- ReadStart=p_mad_adec->buffer;
- Remaining=0;
- p_mad_adec->i_next_pts = 0;
- p_mad_adec->i_current_pts = p_mad_adec->p_fifo->p_first->i_pts;
+ i_wanted = MAD_BUFFER_MDLEN;
+ i_left = 0;
+
+ /* Store timestamp for this frame */
+ p_dec->i_current_pts = p_dec->p_fifo->p_first->i_pts;
}
- /* Fill-in the buffer. If an error occurs print a message
- * and leave the decoding loop. If the end of stream is
- * reached we also leave the loop but the return status is
- * left untouched.
- */
- if( ReadSize > p_mad_adec->p_data->p_payload_end
- - p_mad_adec->p_data->p_payload_start )
+ /* Fill-in the buffer. If an error occurs print a message and leave
+ * the decoding loop. If the end of stream is reached we also leave
+ * the loop but the return status is left untouched. */
+ if( i_wanted > p_dec->p_data->p_payload_end
+ - p_dec->p_data->p_payload_start )
{
- ReadSize = p_mad_adec->p_data->p_payload_end
- - p_mad_adec->p_data->p_payload_start;
- memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize );
- NextDataPacket( p_mad_adec->p_fifo, &p_mad_adec->p_data );
+ i_wanted = p_dec->p_data->p_payload_end
+ - p_dec->p_data->p_payload_start;
+ memcpy( p_dec->buffer + i_left,
+ p_dec->p_data->p_payload_start, i_wanted );
+ NextDataPacket( p_dec->p_fifo, &p_dec->p_data );
}
else
{
- memcpy( ReadStart, p_mad_adec->p_data->p_payload_start, ReadSize );
- p_mad_adec->p_data->p_payload_start += ReadSize;
+ memcpy( p_dec->buffer + i_left,
+ p_dec->p_data->p_payload_start, i_wanted );
+ p_dec->p_data->p_payload_start += i_wanted;
}
- if ( p_mad_adec->p_fifo->b_die == 1 )
+ if ( p_dec->p_fifo->b_die )
{
- msg_Dbg( p_mad_adec->p_fifo, "libmad_input stopping libmad decoder" );
+ msg_Dbg( p_dec->p_fifo, "stopping libmad decoder" );
return MAD_FLOW_STOP;
}
- if ( p_mad_adec->p_fifo->b_error == 1 )
+ if ( p_dec->p_fifo->b_error )
{
- msg_Warn( p_mad_adec->p_fifo, "libmad_input ignoring current audio frame" );
+ msg_Warn( p_dec->p_fifo, "ignoring current audio frame" );
return MAD_FLOW_IGNORE;
}
/* Pipe the new buffer content to libmad's stream decoder facility.
- * Libmad never copies the buffer, but just references it. So keep it in
- * mad_adec_thread_t structure.
- */
- mad_stream_buffer(p_libmad_stream,(unsigned char*) &p_mad_adec->buffer,
- Remaining + ReadSize);
- p_libmad_stream->error=0;
+ * Libmad never copies the buffer, but just references it. So keep
+ * it in mad_adec_thread_t structure. */
+ mad_stream_buffer( p_stream, (unsigned char*) &p_dec->buffer,
+ i_left + i_wanted );
+ p_stream->error = 0;
}
return MAD_FLOW_CONTINUE;
}
/*****************************************************************************
- * libmad_header: this function is called just after the header of a frame is
- * decoded
- *****************************************************************************/
-/*
- *enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header)
- *{
- * mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
- *
- * msg_Err( p_mad_adec->p_fifo, "libmad_header samplerate %d", p_libmad_header->samplerate);
- *
- * PrintFrameInfo(p_limad_mad_header)
- * return MAD_FLOW_CONTINUE;
- *}
- */
-
-/*****************************************************************************
- * lib_mad_filter: this function is called to filter data of a frame
- *****************************************************************************/
-/* enum mad_flow libmad_filter(void *data, struct mad_stream const *p_libmad_stream, struct mad_frame *p_libmad_frame)
- * {
- * return MAD_FLOW_CONTINUE;
- * }
- */
-
-///*****************************************************************************
-// * support routines borrowed from mpg321 (file: mad.c), which is distributed
-// * under GPL license
-// *
-// * mpg321 was written by Joe Drew <drew@debian.org>, and based upon 'plaympeg'
-// * from the smpeg sources, which was written by various people from Loki Software
-// * (http://www.lokigames.com).
-// *
-// * It also incorporates some source from mad, written by Robert Leslie
-// *****************************************************************************/
-//
-///* The following two routines and data structure are from the ever-brilliant
-// Rob Leslie.
-//*/
-//
-//struct audio_dither {
-// mad_fixed_t error[3];
-// mad_fixed_t random;
-//};
-//
-///*
-//* NAME: prng()
-//* DESCRIPTION: 32-bit pseudo-random number generator
-//*/
-//static inline unsigned long prng(unsigned long state)
-//{
-// return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
-//}
-//
-///*
-//* NAME: mpg321_s24_to_s16_pcm()
-//* DESCRIPTION: generic linear sample quantize and dither routine
-//*/
-//static inline signed int mpg321_s24_to_s16_pcm(unsigned int bits, mad_fixed_t sample,
-// struct audio_dither *dither)
-//{
-// unsigned int scalebits;
-// mad_fixed_t output, mask, random;
-//
-// enum {
-// MIN = -MAD_F_ONE,
-// MAX = MAD_F_ONE - 1
-// };
-//
-// /* noise shape */
-// sample += dither->error[0] - dither->error[1] + dither->error[2];
-//
-// dither->error[2] = dither->error[1];
-// dither->error[1] = dither->error[0] / 2;
-//
-// /* bias */
-// output = sample + (1L << (MAD_F_FRACBITS + 1 - bits - 1));
-//
-// scalebits = MAD_F_FRACBITS + 1 - bits;
-// mask = (1L << scalebits) - 1;
-//
-// /* dither */
-// random = prng(dither->random);
-// output += (random & mask) - (dither->random & mask);
-//
-// dither->random = random;
-//
-// /* clip */
-// if (output > MAX) {
-// output = MAX;
-//
-// if (sample > MAX)
-// sample = MAX;
-// }
-// else if (output < MIN) {
-// output = MIN;
-//
-// if (sample < MIN)
-// sample = MIN;
-// }
-//
-// /* quantize */
-// output &= ~mask;
-//
-// /* error feedback */
-// dither->error[0] = sample - output;
-//
-// /* scale */
-// return output >> scalebits;
-//}
-//
-///*****************************************************************************
-// * s24_to_s16_pcm: Scale a 24 bit pcm sample to a 16 bit pcm sample.
-// *****************************************************************************/
-//static inline mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample)
-//{
-// /* round */
-// sample += (1L << (MAD_F_FRACBITS - 16));
-//
-// /* clip */
-// if (sample >= MAD_F_ONE)
-// sample = MAD_F_ONE - 1;
-// else if (sample < -MAD_F_ONE)
-// sample = -MAD_F_ONE;
-//
-// /* quantize */
-// return sample >> (MAD_F_FRACBITS + 1 - 16);
-//}
-//
-/*****************************************************************************
- * libmad_ouput: this function is called just after the frame is decoded
+ * libmad_output: this function is called just after the frame is decoded
*****************************************************************************/
-//enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm)
-//{
-// mad_adec_thread_t *p_mad_adec= (mad_adec_thread_t *) data;
-// byte_t *buffer=NULL;
-// mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1];
-// register int nsamples = p_libmad_pcm->length;
-// mad_fixed_t sample;
-// static struct audio_dither dither;
-//
-// /* Creating the audio output fifo.
-// * Assume the samplerate and nr of channels from the first decoded frame is right for the entire audio track.
-// */
-// if (p_mad_adec->p_aout_fifo==NULL)
-// {
-// p_mad_adec->p_aout_fifo = aout_CreateFifo(
-// p_mad_adec->p_fifo,
-// AOUT_FIFO_PCM, /* fifo type */
-// 2, /*p_libmad_pcm->channels,*/ /* nr. of channels */
-// p_libmad_pcm->samplerate, /* frame rate in Hz ?*/
-// p_libmad_pcm->length*2, /* length of output buffer *2 channels*/
-// NULL ); /* buffer */
-//
-// if ( p_mad_adec->p_aout_fifo == NULL )
-// {
-// return MAD_FLOW_BREAK;
-// }
-//
-// msg_Dbg( p_mad_adec->p_fifo, "aout fifo created");
-// }
-//
-// if (p_mad_adec->p_aout_fifo->i_rate != p_libmad_pcm->samplerate)
-// {
-// msg_Warn( p_mad_adec->p_fifo, "samplerate is changing from [%d] Hz "
-// "to [%d] Hz, sample size [%d], error_code [%0x]",
-// p_mad_adec->p_aout_fifo->i_rate, p_libmad_pcm->samplerate,
-// p_libmad_pcm->length,
-// p_mad_adec->libmad_decoder->sync->stream.error );
-// p_mad_adec->p_aout_fifo->i_rate = p_libmad_pcm->samplerate;
-// }
-//
-// if( p_mad_adec->i_current_pts )
-// {
-// p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame]
-// = p_mad_adec->i_current_pts;
-// }
-// else
-// {
-// p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->i_end_frame]
-// = LAST_MDATE;
-// }
-//// mad_timer_add(&p_mad_adec->libmad_timer,p_libmad_header->duration);
-//
-// buffer = ((byte_t *)p_mad_adec->p_aout_fifo->buffer) + (p_mad_adec->p_aout_fifo->i_end_frame * (p_libmad_pcm->length*4));
-//
-// while (nsamples--)
-// {
-// switch (p_mad_adec->audio_scaling)
-// {
-// case MPG321_SCALING:
-// sample = mpg321_s24_to_s16_pcm(16, *left_ch++, &dither);
-// break;
-// case FAST_SCALING: /* intended fall through */
-// default:
-// sample = s24_to_s16_pcm(*left_ch++);
-// break;
-// }
-//
-// /* left audio channel */
-//#ifndef WORDS_BIGENDIAN
-// *buffer++ = (byte_t) (sample >> 0);
-// *buffer++ = (byte_t) (sample >> 8);
-//#else
-// *buffer++ = (byte_t) (sample >> 8);
-// *buffer++ = (byte_t) (sample >> 0);
-//#endif
-// if (p_libmad_pcm->channels == 2)
-// {
-// /* right audio channel */
-// switch (p_mad_adec->audio_scaling)
-// {
-// case MPG321_SCALING:
-// sample = mpg321_s24_to_s16_pcm(16, *right_ch++, &dither);
-// break;
-// case FAST_SCALING: /* intended fall through */
-// default:
-// sample = s24_to_s16_pcm(*right_ch++);
-// break;
-// }
-// }
-// /* else reuse left_ch */
-//#ifndef WORDS_BIGENDIAN
-// *buffer++ = (byte_t) (sample >> 0);
-// *buffer++ = (byte_t) (sample >> 8);
-//#else
-// *buffer++ = (byte_t) (sample >> 8);
-// *buffer++ = (byte_t) (sample >> 0);
-//#endif
-// }
-//
-// /* DEBUG */
-// /*
-// if (p_libmad_pcm->channels == 1) {
-// msg_Dbg( p_mad_adec->p_fifo, "libmad_output channels [%d]", p_libmad_pcm->channels);
-// }
-// */
-//
-// vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
-// p_mad_adec->p_aout_fifo->i_end_frame = (p_mad_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
-// vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
-// vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock);
-//
-// return MAD_FLOW_CONTINUE;
-//}
-
-/*****************************************************************************
- * libmad_ouput3: this function is called just after the frame is decoded
- *****************************************************************************/
-enum mad_flow libmad_output3(void *data, struct mad_header const *p_libmad_header, struct mad_pcm *p_libmad_pcm)
+enum mad_flow libmad_output( void *p_data, struct mad_header const *p_header,
+ struct mad_pcm *p_pcm )
{
- mad_adec_thread_t *p_mad_adec= (mad_adec_thread_t *) data;
- aout_buffer_t * p_buffer;
- mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1];
- register int nsamples = p_libmad_pcm->length;
- mad_fixed_t sample;
-
- /* Creating the audio output fifo.
- * Assume the samplerate and nr of channels from the first decoded frame
- * is right for the entire audio track.
- */
- if( (p_mad_adec->p_aout_input != NULL) &&
- (p_mad_adec->output_format.i_rate != p_libmad_pcm->samplerate) )
+ mad_adec_thread_t * p_dec = (mad_adec_thread_t *) p_data;
+ aout_buffer_t * p_buffer;
+ mad_fixed_t const * p_left = p_pcm->samples[0];
+ mad_fixed_t const * p_right = p_pcm->samples[1];
+ register int i_samples = p_pcm->length;
+ mad_fixed_t * p_samples;
+
+ /* Creating the audio output fifo. Assume the samplerate and nr of channels
+ * from the first decoded frame is right for the entire audio track. */
+ if( (p_dec->p_aout_input != NULL) &&
+ (p_dec->output_format.i_rate != p_pcm->samplerate) )
{
/* Parameters changed - this should not happen. */
- aout_InputDelete( p_mad_adec->p_aout, p_mad_adec->p_aout_input );
- p_mad_adec->p_aout_input = NULL;
+ aout_InputDelete( p_dec->p_aout, p_dec->p_aout_input );
+ p_dec->p_aout_input = NULL;
}
/* Creating the audio input if not created yet. */
- if( p_mad_adec->p_aout_input == NULL )
+ if( p_dec->p_aout_input == NULL )
{
- p_mad_adec->output_format.i_rate = p_libmad_pcm->samplerate;
- /* p_mad_adec->output_format.i_channels = p_libmad_pcm->channels; */
- p_mad_adec->p_aout_input = aout_InputNew( p_mad_adec->p_fifo,
- &p_mad_adec->p_aout,
- &p_mad_adec->output_format );
+ p_dec->output_format.i_rate = p_pcm->samplerate;
+ /* p_dec->output_format.i_channels = p_pcm->channels; */
+ aout_DateInit( &p_dec->end_date, p_pcm->samplerate );
+ p_dec->p_aout_input = aout_InputNew( p_dec->p_fifo,
+ &p_dec->p_aout,
+ &p_dec->output_format );
+
+ if ( p_dec->p_aout_input == NULL )
+ {
+ p_dec->p_fifo->b_error = VLC_TRUE;
+ return MAD_FLOW_BREAK;
+ }
+ }
- if ( p_mad_adec->p_aout_input == NULL )
+ if( p_dec->i_current_pts )
+ {
+ /* Set the Presentation Time Stamp */
+ if( p_dec->i_current_pts != aout_DateGet( &p_dec->end_date ) )
{
- p_mad_adec->p_fifo->b_error = 1;
- return MAD_FLOW_BREAK;
+ aout_DateSet( &p_dec->end_date, p_dec->i_current_pts );
}
- msg_Dbg( p_mad_adec->p_fifo, "aout3 input created");
+
+ p_dec->i_current_pts = 0;
+ }
+ else if( p_dec->i_next_pts )
+ {
+ /* No PTS this time, but it'll be for next frame */
+ p_dec->i_current_pts = p_dec->i_next_pts;
+ p_dec->i_next_pts = 0;
}
- if (p_mad_adec->output_format.i_rate != p_libmad_pcm->samplerate)
+ if( !aout_DateGet( &p_dec->end_date ) )
{
- msg_Warn( p_mad_adec->p_fifo, "samplerate is changing from [%d] Hz "
- "to [%d] Hz, sample size [%d], error_code [%0x]",
- p_mad_adec->output_format.i_rate, p_libmad_pcm->samplerate,
- p_libmad_pcm->length,
- p_mad_adec->libmad_decoder->sync->stream.error );
- p_mad_adec->output_format.i_rate = p_libmad_pcm->samplerate;
+ /* No date available yet, wait for the first PTS. */
+ return MAD_FLOW_CONTINUE;
}
- /* Set the Presentation Time Stamp */
- p_buffer = aout_BufferNew( p_mad_adec->p_aout,
- p_mad_adec->p_aout_input,
- (p_libmad_pcm->length*2) );
+ p_buffer = aout_BufferNew( p_dec->p_aout, p_dec->p_aout_input, i_samples );
if ( p_buffer == NULL )
{
- msg_Dbg( p_mad_adec->p_fifo, "allocating new buffer failed");
+ msg_Err( p_dec->p_fifo, "allocating new buffer failed" );
return MAD_FLOW_BREAK;
}
- /* Add accurate PTS to buffer. */
- if ( p_mad_adec->i_current_pts )
- {
- p_buffer->start_date = p_mad_adec->i_current_pts;
- }
- else
- {
- p_buffer->start_date = LAST_MDATE;
- }
- p_mad_adec->last_date += (mtime_t)(p_libmad_pcm->length*2)
- / p_mad_adec->output_format.i_rate;
- p_buffer->end_date = p_mad_adec->last_date;
+
+ p_buffer->start_date = aout_DateGet( &p_dec->end_date );
+ p_buffer->end_date = aout_DateIncrement( &p_dec->end_date, i_samples );
/* Interleave and keep buffers in mad_fixed_t format */
- while (nsamples--)
+ p_samples = (mad_fixed_t *)p_buffer->p_buffer;
+
+ switch( p_pcm->channels )
{
- /* left audio channel */
- sample = *left_ch++;
-#ifndef WORDS_BIGENDIAN
- *(p_buffer->p_buffer)++ = (byte_t) (sample);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-#else
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-#endif
- /* right audio channel */
- if (p_libmad_pcm->channels == 2)
+ case 2:
+ while( i_samples-- )
+ {
+ *p_samples++ = *p_left++;
+ *p_samples++ = *p_right++;
+ }
+ break;
+ case 1:
+ while( i_samples-- )
{
- sample = *right_ch++;
- } /* else reuse left audio channel */
-#ifndef WORDS_BIGENDIAN
- *(p_buffer->p_buffer)++ = (byte_t) (sample);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-#else
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 8);
-// *(p_buffer->p_buffer)++ = (byte_t) (sample >> 0);
-#endif
+ *p_samples++ = *p_left;
+ *p_samples++ = *p_left++;
+ }
+ break;
+ default:
+ msg_Err( p_dec->p_fifo, "cannot interleave %i channels",
+ p_pcm->channels );
}
- aout_BufferPlay( p_mad_adec->p_aout, p_mad_adec->p_aout_input, p_buffer );
+ aout_BufferPlay( p_dec->p_aout, p_dec->p_aout_input, p_buffer );
return MAD_FLOW_CONTINUE;
}
/*****************************************************************************
* libmad_error: this function is called when an error occurs during decoding
*****************************************************************************/
-enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struct mad_frame *p_libmad_frame)
+enum mad_flow libmad_error( void *data, struct mad_stream *p_libmad_stream,
+ struct mad_frame *p_libmad_frame )
{
+ mad_adec_thread_t *p_dec = (mad_adec_thread_t *) data;
enum mad_flow result = MAD_FLOW_CONTINUE;
switch (p_libmad_stream->error)
{
case MAD_ERROR_BUFLEN: /* input buffer too small (or EOF) */
-//X msg_Err("libmad error: input buffer too small (or EOF)");
+ msg_Err( p_dec->p_fifo, "input buffer too small (or EOF)" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BUFPTR: /* invalid (null) buffer pointer */
-//X msg_Err("libmad error: invalid (null) buffer pointer");
+ msg_Err( p_dec->p_fifo, "invalid (null) buffer pointer" );
result = MAD_FLOW_STOP;
break;
case MAD_ERROR_NOMEM: /* not enough memory */
-//X msg_Err("libmad error: invalid (null) buffer pointer");
+ msg_Err( p_dec->p_fifo, "invalid (null) buffer pointer" );
result = MAD_FLOW_STOP;
break;
case MAD_ERROR_LOSTSYNC: /* lost synchronization */
-//X msg_Err("libmad error: lost synchronization");
+ msg_Err( p_dec->p_fifo, "lost synchronization" );
mad_stream_sync(p_libmad_stream);
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADLAYER: /* reserved header layer value */
-//X msg_Err("libmad error: reserved header layer value");
+ msg_Err( p_dec->p_fifo, "reserved header layer value" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADBITRATE: /* forbidden bitrate value */
-//X msg_Err("libmad error: forbidden bitrate value");
+ msg_Err( p_dec->p_fifo, "forbidden bitrate value" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADSAMPLERATE: /* reserved sample frequency value */
-//X msg_Err("libmad error: reserved sample frequency value");
+ msg_Err( p_dec->p_fifo, "reserved sample frequency value" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADEMPHASIS: /* reserved emphasis value */
-//X msg_Err("libmad error: reserverd emphasis value");
+ msg_Err( p_dec->p_fifo, "reserverd emphasis value" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADCRC: /* CRC check failed */
-//X msg_Err("libmad error: CRC check failed");
+ msg_Err( p_dec->p_fifo, "CRC check failed" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADBITALLOC: /* forbidden bit allocation value */
-//X msg_Err("libmad error: forbidden bit allocation value");
+ msg_Err( p_dec->p_fifo, "forbidden bit allocation value" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADSCALEFACTOR:/* bad scalefactor index */
-//X msg_Err("libmad error: bad scalefactor index");
+ msg_Err( p_dec->p_fifo, "bad scalefactor index" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADFRAMELEN: /* bad frame length */
-//X msg_Err("libmad error: bad frame length");
+ msg_Err( p_dec->p_fifo, "bad frame length" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADBIGVALUES: /* bad big_values count */
-//X msg_Err("libmad error: bad big values count");
+ msg_Err( p_dec->p_fifo, "bad big values count" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADBLOCKTYPE: /* reserved block_type */
-//X msg_Err("libmad error: reserverd block_type");
+ msg_Err( p_dec->p_fifo, "reserverd block_type" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADSCFSI: /* bad scalefactor selection info */
-//X msg_Err("libmad error: bad scalefactor selection info");
+ msg_Err( p_dec->p_fifo, "bad scalefactor selection info" );
result = MAD_FLOW_CONTINUE;
break;
case MAD_ERROR_BADDATAPTR: /* bad main_data_begin pointer */
-//X msg_Err("libmad error: bad main_data_begin pointer");
+ msg_Err( p_dec->p_fifo, "bad main_data_begin pointer" );
result = MAD_FLOW_STOP;
break;
case MAD_ERROR_BADPART3LEN: /* bad audio data length */
-//X msg_Err("libmad error: bad audio data length");
+ msg_Err( p_dec->p_fifo, "bad audio data length" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADHUFFTABLE: /* bad Huffman table select */
-//X msg_Err("libmad error: bad Huffman table select");
+ msg_Err( p_dec->p_fifo, "bad Huffman table select" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADHUFFDATA: /* Huffman data overrun */
-//X msg_Err("libmad error: Huffman data overrun");
+ msg_Err( p_dec->p_fifo, "Huffman data overrun" );
result = MAD_FLOW_IGNORE;
break;
case MAD_ERROR_BADSTEREO: /* incompatible block_type for JS */
-//X msg_Err("libmad error: incompatible block_type for JS");
+ msg_Err( p_dec->p_fifo, "incompatible block_type for JS" );
result = MAD_FLOW_IGNORE;
break;
default:
-//X msg_Err("libmad error: unknown error occured stopping decoder");
+ msg_Err( p_dec->p_fifo, "unknown error occured stopping decoder" );
result = MAD_FLOW_STOP;
break;
}
*Mode,
*Emphasis;
- /* Convert the layer number to it's printed representation. */
+ /* Convert the layer number to its printed representation. */
switch(Header->layer)
{
case MAD_LAYER_I:
break;
}
- /* Convert the audio mode to it's printed representation. */
+ /* Convert the audio mode to its printed representation. */
switch(Header->mode)
{
case MAD_MODE_SINGLE_CHANNEL:
break;
}
- /* Convert the emphasis to it's printed representation. */
+ /* Convert the emphasis to its printed representation. */
switch(Header->emphasis)
{
case MAD_EMPHASIS_NONE: