Commit 18597150 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Changes made to mad plugin:

+ libmad_input now takes one frame at a time (see mad_adec.h for defines)
+ audio_linear_dither() gives better sound quality then s24_to_s16_pcm(),
  but also makes audio artefacts louder so disabled it for now (see file
  mad_libmad.c)
+ cleaned up libmad_output (see file mad_libmad.c)
+ cleaned up InitThread (see file mad_adec.c)
+ Made buffer size match libmad's expectations (see file mad_adec.h)
+ updated documentation
parent ae09661b
...@@ -5,18 +5,22 @@ Directories: ...@@ -5,18 +5,22 @@ Directories:
============ ============
vlc/plugins/mad : mad audio decoder plugin for vlc vlc/plugins/mad : mad audio decoder plugin for vlc
Interface functions to implement in mad plugin are: Interface functions
========= ===================
decoder_Probe The following interface functions are implemented in the mad plugin.
decoder_Run
adec_mad_InitThred decoder_Probe : vlc probes for plugin capabilities
adec_mad_EndThread decoder_Run : vlc starts a decoder plugin by calling this function
InitThread : routine to do some initializations
libmad_input EndThread : cleanup function
libmad_output
libmad_header The following functions are callback functions for the mad decoder library:
libmad_messages
libmad_error libmad_input : called when input data is needed
libmad_output : called whenever a frame has been decoded
libmad_header : called upon decoding of only a frame header
libmad_messages : libmad messages
libmad_error : called whenever an error occured during the decoding process
Design: (ASCII art) Design: (ASCII art)
======= =======
...@@ -35,10 +39,10 @@ initializing, starting and stopping them. ...@@ -35,10 +39,10 @@ initializing, starting and stopping them.
_______________ _______________
^ ^
| |
________________________ ________________________
| <decoder interface> | | <decoder interface> |
| vlc plugin interface | | vlc plugin interface |
________________________ ________________________
Interface view: Interface view:
...@@ -49,6 +53,7 @@ Interface view: ...@@ -49,6 +53,7 @@ Interface view:
----------------------- -----------------------
Rationel: Rationel:
========
Keeping libmad as a separate library on the system, either dynamic or statically linked in, makes maintenance so much simpeler. Keeping libmad as a separate library on the system, either dynamic or statically linked in, makes maintenance so much simpeler.
Merging with a new libmad version should be straight forward as long as the interface stays stable. Merging with a new libmad version should be straight forward as long as the interface stays stable.
There is another benefit: Disk (actually flash ROM) resources and memory are very limited on a iPaq. There is another benefit: Disk (actually flash ROM) resources and memory are very limited on a iPaq.
......
...@@ -24,7 +24,7 @@ commit to current vlc-dev tree in CVS at VideoLan ...@@ -24,7 +24,7 @@ commit to current vlc-dev tree in CVS at VideoLan
[5 - all ready done by Christophe Massiot] [5 - all ready done by Christophe Massiot]
make cross-compile possible for vlc without interface. With interface it is to damn difficult to do cross-compilation. make cross-compile possible for vlc without interface. With interface it is to damn difficult to do cross-compilation.
[6 - ] [6 - busy ]
extending mad plugin with more features extending mad plugin with more features
do fancy stuff (enable MP3 decoding) do fancy stuff (enable MP3 decoding)
...@@ -44,12 +44,3 @@ incorporate new libmad version if possible ...@@ -44,12 +44,3 @@ incorporate new libmad version if possible
see 7 see 7
see 8 see 8
[10 - ]
rewrite the audio decoding process by using a lower level API. In this way the decoding process can be steered and tuned better.
Hopefully it will get rid of audio cracks and jitter.
[11 - ]
test plugin: native Intel, native iPaq
[12 - ]
commit to vlc-dev tree.
\ No newline at end of file
...@@ -165,6 +165,7 @@ static int InitThread( mad_adec_thread_t * p_mad_adec ) ...@@ -165,6 +165,7 @@ static int InitThread( mad_adec_thread_t * p_mad_adec )
/* Initialize the libmad decoder structures */ /* Initialize the libmad decoder structures */
p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder)); p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder));
if (p_mad_adec->libmad_decoder == NULL) { if (p_mad_adec->libmad_decoder == NULL) {
intf_ErrMsg ( "mad_adec error: not enough memory " intf_ErrMsg ( "mad_adec error: not enough memory "
"for decoder_InitThread() to allocate p_mad_adec->libmad_decder" ); "for decoder_InitThread() to allocate p_mad_adec->libmad_decder" );
...@@ -185,16 +186,14 @@ static int InitThread( mad_adec_thread_t * p_mad_adec ) ...@@ -185,16 +186,14 @@ static int InitThread( mad_adec_thread_t * p_mad_adec )
libmad_input, /* input_func */ libmad_input, /* input_func */
0, /* header_func */ 0, /* header_func */
0, /* filter */ 0, /* filter */
libmad_output, /* output_func */ libmad_output, /* output_func */
0, /* error */ 0, /* error */
0); /* message */ 0); /* message */
mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC); mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC);
mad_timer_reset(&p_mad_adec->libmad_timer); mad_timer_reset(&p_mad_adec->libmad_timer);
/* /* output fifo will be created when needed */
* Initialize the output properties
*/
p_mad_adec->p_aout_fifo=NULL; p_mad_adec->p_aout_fifo=NULL;
intf_ErrMsg("mad_adec debug: mad decoder thread %p initialized", p_mad_adec); intf_ErrMsg("mad_adec debug: mad decoder thread %p initialized", p_mad_adec);
......
...@@ -23,8 +23,9 @@ ...@@ -23,8 +23,9 @@
// FIXME: Ugly define inside a decoder // FIXME: Ugly define inside a decoder
#define ADEC_FRAME_SIZE (2*1152) #define ADEC_FRAME_SIZE (2*1152)
#define MAD_BUFFER_SIZE (ADEC_FRAME_SIZE*2) // MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFLEN_GUARD) and MAD_BUFLEN_GUARD is 8
//#define MAD_BUFFER_SIZE (MAD_BUFFER_MDLEN*2) #define MAD_BUFFER_SIZE (MAD_BUFFER_MDLEN)
//#define MAD_BUFFER_SIZE (ADEC_FRAME_SIZE*2)
#define MAD_OUTPUT_SIZE (ADEC_FRAME_SIZE*2) #define MAD_OUTPUT_SIZE (ADEC_FRAME_SIZE*2)
typedef struct mad_adec_thread_s typedef struct mad_adec_thread_s
......
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream) enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
{ {
mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data; mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
size_t ReadSize, Remaining; size_t ReadSize, Remaining;
unsigned char *ReadStart; unsigned char *ReadStart;
if ( p_mad_adec->p_fifo->b_die == 1 ) { if ( p_mad_adec->p_fifo->b_die == 1 ) {
intf_ErrMsg( "mad_adec error: libmad_input stopping libmad decoder" ); intf_ErrMsg( "mad_adec error: libmad_input stopping libmad decoder" );
...@@ -65,35 +65,38 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream) ...@@ -65,35 +65,38 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
*/ */
if ((p_libmad_stream->buffer==NULL) || (p_libmad_stream->error==MAD_ERROR_BUFLEN)) if ((p_libmad_stream->buffer==NULL) || (p_libmad_stream->error==MAD_ERROR_BUFLEN))
{ {
/* libmad does not consume all the buffer it's given. Some /* libmad does not consume all the buffer it's given. Some
* datas, part of a truncated frame, is left unused at the * datas, part of a truncated frame, is left unused at the
* end of the buffer. Those datas must be put back at the * end of the buffer. Those datas must be put back at the
* beginning of the buffer and taken in account for * beginning of the buffer and taken in account for
* refilling the buffer. This means that the input buffer * refilling the buffer. This means that the input buffer
* must be large enough to hold a complete frame at the * must be large enough to hold a complete frame at the
* highest observable bit-rate (currently 448 kb/s). XXX=XXX * highest observable bit-rate (currently 448 kb/s). XXX=XXX
* Is 2016 bytes the size of the largest frame? * Is 2016 bytes the size of the largest frame?
* (448000*(1152/32000))/8 * (448000*(1152/32000))/8
*/ */
if(p_libmad_stream->next_frame!=NULL) if (p_libmad_stream->next_frame!=NULL)
{ {
Remaining=p_libmad_stream->bufend-p_libmad_stream->next_frame; Remaining=p_libmad_stream->bufend-p_libmad_stream->next_frame;
memmove(p_mad_adec->buffer,p_libmad_stream->next_frame,Remaining); memmove(p_mad_adec->buffer,p_libmad_stream->next_frame,Remaining);
ReadStart=p_mad_adec->buffer+Remaining; ReadStart=p_mad_adec->buffer+Remaining;
ReadSize=(MAD_BUFFER_SIZE)-Remaining; ReadSize=(MAD_BUFFER_SIZE)-Remaining;
/* Store time stamp of next frame */ /* Store time stamp of next frame */
p_mad_adec->i_current_pts = p_mad_adec->i_next_pts; p_mad_adec->i_current_pts = p_mad_adec->i_next_pts;
CurrentPTS( &p_mad_adec->bit_stream, &p_mad_adec->i_next_pts, NULL ); CurrentPTS( &p_mad_adec->bit_stream, &p_mad_adec->i_next_pts, NULL );
} }
else else
{ {
ReadSize=(MAD_BUFFER_SIZE); ReadSize=(MAD_BUFFER_SIZE);
ReadStart=p_mad_adec->buffer; ReadStart=p_mad_adec->buffer;
Remaining=0; Remaining=0;
p_mad_adec->i_next_pts = 0;
p_mad_adec->i_next_pts = 0;
CurrentPTS( &p_mad_adec->bit_stream, &p_mad_adec->i_current_pts, NULL ); CurrentPTS( &p_mad_adec->bit_stream, &p_mad_adec->i_current_pts, NULL );
} }
//intf_ErrMsg( "mad_adec debug: buffer size remaining [%d] and readsize [%d] total [%d]",
// Remaining, ReadSize, ReadSize+Remaining);
/* Fill-in the buffer. If an error occurs print a message /* Fill-in the buffer. If an error occurs print a message
* and leave the decoding loop. If the end of stream is * and leave the decoding loop. If the end of stream is
...@@ -132,13 +135,12 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream) ...@@ -132,13 +135,12 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
return MAD_FLOW_IGNORE; return MAD_FLOW_IGNORE;
} }
/* Pipe the new buffer content to libmad's stream decoder facility. /* Pipe the new buffer content to libmad's stream decoder facility.
* Libmad never copies the buffer, but just references it. So keep it in * Libmad never copies the buffer, but just references it. So keep it in
* mad_adec_thread_t structure. * mad_adec_thread_t structure.
*/ */
mad_stream_buffer(p_libmad_stream,(unsigned char*) &p_mad_adec->buffer, mad_stream_buffer(p_libmad_stream,(unsigned char*) &p_mad_adec->buffer,MAD_BUFFER_SIZE);
MAD_BUFFER_SIZE); p_libmad_stream->error=0;
p_libmad_stream->error=0;
} }
return MAD_FLOW_CONTINUE; return MAD_FLOW_CONTINUE;
...@@ -157,7 +159,7 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream) ...@@ -157,7 +159,7 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
* intf_DbgMsg( "mad_adec: libmad_header bitrate %d", p_libmad_header->bitrate); * intf_DbgMsg( "mad_adec: libmad_header bitrate %d", p_libmad_header->bitrate);
* *
* p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate; * p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate;
* mad_timer_add(&p_mad_adec->libmad_timer,p_libmad_header->duration); * mad_timer_add(&p_mad_adec->libmad_timer,p_libmad_header->duration);
* *
* return MAD_FLOW_CONTINUE; * return MAD_FLOW_CONTINUE;
*} *}
...@@ -259,12 +261,12 @@ static __inline__ signed int audio_linear_dither(unsigned int bits, mad_fixed_t ...@@ -259,12 +261,12 @@ static __inline__ signed int audio_linear_dither(unsigned int bits, mad_fixed_t
/* scale */ /* scale */
return output >> scalebits; return output >> scalebits;
} }
#endif #else
/***************************************************************************** /*****************************************************************************
* s24_to_s16_pcm: Scale a 24 bit pcm sample to a 16 bit pcm sample. * 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) static __inline__ mad_fixed_t (mad_fixed_t sample)
{ {
/* round */ /* round */
sample += (1L << (MAD_F_FRACBITS - 16)); sample += (1L << (MAD_F_FRACBITS - 16));
...@@ -278,6 +280,7 @@ static __inline__ mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample) ...@@ -278,6 +280,7 @@ static __inline__ mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample)
/* quantize */ /* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16); return sample >> (MAD_F_FRACBITS + 1 - 16);
} }
#endif
/***************************************************************************** /*****************************************************************************
* libmad_ouput: this function is called just after the frame is decoded * libmad_ouput: this function is called just after the frame is decoded
...@@ -294,10 +297,12 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header ...@@ -294,10 +297,12 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
static struct audio_dither dither; static struct audio_dither dither;
#endif #endif
/* Creating the audio output fifo */ /* 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) if (p_mad_adec->p_aout_fifo==NULL)
{ {
p_mad_adec->p_aout_fifo = aout_CreateFifo( p_mad_adec->p_aout_fifo = aout_CreateFifo(
AOUT_ADEC_STEREO_FIFO, /* fifo type */ AOUT_ADEC_STEREO_FIFO, /* fifo type */
p_libmad_pcm->channels, /* nr. of channels */ p_libmad_pcm->channels, /* nr. of channels */
p_libmad_pcm->samplerate, /* frame rate in Hz ?*/ p_libmad_pcm->samplerate, /* frame rate in Hz ?*/
...@@ -312,28 +317,16 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header ...@@ -312,28 +317,16 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
intf_ErrMsg("mad_adec debug: in libmad_output aout fifo created"); intf_ErrMsg("mad_adec debug: in libmad_output aout fifo created");
} }
else
{
p_mad_adec->p_aout_fifo->l_rate = p_libmad_pcm->samplerate;
}
/* Some frames are nog quite right. Why ??? I do not know. Probably syncing and CRC errors ?? /* Set timestamp to synchronize audio and video decoder fifo's */
* Leaving those frames out futher removes the jitter in the sound and makes it more fluent. if (p_mad_adec->p_aout_fifo->l_rate != p_libmad_pcm->samplerate)
* Still I am missing something, because it is not completely fluent. {
*/ intf_ErrMsg( "mad_adec: libmad_output samplerate is changing from [%d] Hz to [%d] Hz, sample size [%d], error_code [%0x]",
if ((p_mad_adec->libmad_decoder->sync->stream.error==MAD_ERROR_BADCRC) || p_mad_adec->p_aout_fifo->l_rate, p_libmad_pcm->samplerate,
(p_mad_adec->libmad_decoder->sync->stream.error==MAD_ERROR_BADBITRATE) || p_libmad_pcm->length, p_mad_adec->libmad_decoder->sync->stream.error);
(p_mad_adec->libmad_decoder->sync->stream.error==MAD_ERROR_BADSCALEFACTOR) p_mad_adec->p_aout_fifo->l_rate = p_libmad_pcm->samplerate;
) {
// intf_ErrMsg( "LIBMAD_OUTPUT: nr of channels [%d], samplerate in Hz [%d,%d], sample size [%d], error_code [%0x]",
// p_libmad_pcm->channels, p_libmad_pcm->samplerate, p_libmad_header->samplerate,
// p_libmad_pcm->length, p_mad_adec->libmad_decoder->sync->stream.error);
// PrintFrameInfo(&p_libmad_header);
return MAD_FLOW_IGNORE;
} }
/* Set timestamp to synchronize audio and video decoder fifo's */
p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate;
if( p_mad_adec->i_current_pts ) if( p_mad_adec->i_current_pts )
{ {
p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->l_end_frame] p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->l_end_frame]
...@@ -437,7 +430,7 @@ enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struc ...@@ -437,7 +430,7 @@ enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struc
result = MAD_FLOW_CONTINUE; result = MAD_FLOW_CONTINUE;
break; break;
case MAD_ERROR_BADSAMPLERATE: /* reserved sample frequency value */ case MAD_ERROR_BADSAMPLERATE: /* reserved sample frequency value */
intf_ErrMsg("libmad error: reserved sample frequency value"); intf_ErrMsg("libmad error: reserved sample frequency value");
result = MAD_FLOW_CONTINUE; result = MAD_FLOW_CONTINUE;
break; break;
case MAD_ERROR_BADEMPHASIS: /* reserved emphasis value */ case MAD_ERROR_BADEMPHASIS: /* reserved emphasis value */
...@@ -498,8 +491,8 @@ enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struc ...@@ -498,8 +491,8 @@ enum mad_flow libmad_error(void *data, struct mad_stream *p_libmad_stream, struc
break; break;
} }
//return (MAD_RECOVERABLE(p_libmad_stream->error)? result: MAD_FLOW_STOP); return (MAD_RECOVERABLE(p_libmad_stream->error)? result: MAD_FLOW_STOP);
return (MAD_FLOW_CONTINUE); //return (MAD_FLOW_CONTINUE);
} }
/***************************************************************************** /*****************************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment