Commit 305bc15e authored by Christophe Massiot's avatar Christophe Massiot

* Totally rewrote the mad plug-in, in order to fix the PTS problems :

- Now using the low-level API of libmad,
- Decoding split in parsing & decoding (just like A/52),
- Should handle dual-mono files correctly,
* The old mpeg_audio plug-in can no longer work in this scheme and has
  been disabled. Please _always_ compile with mad from now on.
* Updated po files.
parent 15622f88
......@@ -1375,8 +1375,8 @@ then
[ --with-mad=PATH path to libmad],[],[])
if test "x${with_mad}" != "xno" -a "x${with_mad}" != "x"
then
CPPFLAGS_mad="${CPPFLAGS_mad} -I${with_mad}/include"
LDFLAGS_mad="${LDFLAGS_mad} -L${with_mad}/lib"
CPPFLAGS_mad="${CPPFLAGS_mpgatofixed32} -I${with_mad}/include"
LDFLAGS_mad="${LDFLAGS_mpgatofixed32} -L${with_mad}/lib"
fi
AC_ARG_WITH(mad-tree,
......@@ -1395,12 +1395,12 @@ then
if test -f ${real_mad_tree}/libmad/mad.h
then
AC_MSG_RESULT(yes)
CPPFLAGS_mad="${CPPFLAGS_mad} -I${real_mad_tree}/libmad"
LDFLAGS_mad="${LDFLAGS_mad} -L${real_mad_tree}/libmad/.libs"
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_mad}"
CPPFLAGS_mad="${CPPFLAGS_mpgatofixed32} -I${real_mad_tree}/libmad"
LDFLAGS_mad="${LDFLAGS_mpgatofixed32} -L${real_mad_tree}/libmad/.libs"
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_mpgatofixed32}"
AC_CHECK_LIB(mad, mad_bit_init, [
BUILTINS="${BUILTINS} mad"
LDFLAGS_mad="${LDFLAGS_mad} -lmad"
BUILTINS="${BUILTINS} mpgatofixed32"
LDFLAGS_mpgatofixed32="${LDFLAGS_mpgatofixed32} -lmad"
],[ AC_MSG_ERROR([the specified tree hasn't been compiled ])
],[])
LDFLAGS="${LDFLAGS_save}"
......@@ -1409,13 +1409,13 @@ then
AC_MSG_ERROR([the specified tree doesn't have mad.h])
fi
else
CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_mad}"
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_mad}"
CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_mpgatofixed32}"
LDFLAGS="${LDFLAGS_save} ${LDFLAGS_mpgatofixed32}"
AC_CHECK_HEADERS(mad.h, ,
[ AC_MSG_ERROR([Cannot find development headers for libmad...]) ])
AC_CHECK_LIB(mad, mad_bit_init, [
PLUGINS="${PLUGINS} mad"
LDFLAGS_mad="${LDFLAGS_mad} -lmad" ],
PLUGINS="${PLUGINS} mpgatofixed32"
LDFLAGS_mpgatofixed32="${LDFLAGS_mpgatofixed32} -lmad" ],
[ AC_MSG_ERROR([Cannot find libmad library...]) ])
CPPFLAGS="${CPPFLAGS_save}"
LDFLAGS="${LDFLAGS_save}"
......
......@@ -22,8 +22,6 @@ EXTRA_DIST = \
codec/faad/Modules.am \
codec/ffmpeg/Modules.am \
codec/ffmpeg/postprocessing/Modules.am \
codec/mad/Modules.am \
codec/mpeg_audio/Modules.am \
codec/mpeg_video/Modules.am \
codec/mpeg_video/idct/Modules.am \
codec/mpeg_video/motion/Modules.am \
......
......@@ -11,3 +11,4 @@ SOURCES_s16tofloat32swab = modules/audio_filter/converter/s16tofloat32swab.c
SOURCES_s8tofloat32 = modules/audio_filter/converter/s8tofloat32.c
SOURCES_u8tofixed32 = modules/audio_filter/converter/u8tofixed32.c
SOURCES_u8tofloat32 = modules/audio_filter/converter/u8tofloat32.c
SOURCES_mpgatofixed32 = modules/audio_filter/converter/mpgatofixed32.c
/*****************************************************************************
* mpgatofixed32.c: MPEG-1 & 2 audio layer I, II, III + MPEG 2.5 decoder,
* using MAD (MPEG Audio Decoder)
*****************************************************************************
* Copyright (C) 2001 by Jean-Paul Saman
* $Id: mpgatofixed32.c,v 1.1 2003/01/15 10:58:47 massiot Exp $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jean-Paul Saman <jpsaman@wxs.nl>
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <mad.h>
#include <vlc/vlc.h>
#include "audio_output.h"
#include "aout_internal.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Create ( vlc_object_t * );
static void Destroy ( vlc_object_t * );
static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
aout_buffer_t * );
/*****************************************************************************
* Local structures
*****************************************************************************/
struct aout_filter_sys_t
{
struct mad_stream mad_stream;
struct mad_frame mad_frame;
struct mad_synth mad_synth;
};
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( N_("Miscellaneous"), NULL );
set_description( _("MPEG audio decoder module") );
set_capability( "audio filter", 100 );
set_callbacks( Create, Destroy );
vlc_module_end();
/*****************************************************************************
* Create:
*****************************************************************************/
static int Create( vlc_object_t * _p_filter )
{
aout_filter_t * p_filter = (aout_filter_t *)_p_filter;
struct aout_filter_sys_t * p_sys;
if ( (p_filter->input.i_format != VLC_FOURCC('m','p','g','a')
&& p_filter->input.i_format != VLC_FOURCC('m','p','g','3'))
|| (p_filter->output.i_format != VLC_FOURCC('f','l','3','2')
&& p_filter->output.i_format != VLC_FOURCC('f','i','3','2')) )
{
return -1;
}
if ( p_filter->input.i_rate != p_filter->output.i_rate )
{
return -1;
}
if ( p_filter->input.i_original_channels !=
p_filter->output.i_original_channels
&& p_filter->input.i_physical_channels !=
p_filter->output.i_physical_channels )
{
return -1;
}
/* Allocate the memory needed to store the module's structure */
p_sys = p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
if( p_sys == NULL )
{
msg_Err( p_filter, "out of memory" );
return -1;
}
/* Initialize libmad */
mad_stream_init( &p_sys->mad_stream );
mad_frame_init( &p_sys->mad_frame );
mad_synth_init( &p_sys->mad_synth );
mad_stream_options( &p_sys->mad_stream, MAD_OPTION_IGNORECRC );
p_filter->pf_do_work = DoWork;
p_filter->b_in_place = 0;
return 0;
}
/*****************************************************************************
* DoWork: decode an MPEG audio frame.
*****************************************************************************/
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
{
struct aout_filter_sys_t * p_sys = p_filter->p_sys;
p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
p_out_buf->i_nb_bytes = p_in_buf->i_nb_samples * sizeof(vlc_fixed_t);
/* Do the actual decoding now. */
mad_stream_buffer( &p_sys->mad_stream, p_in_buf->p_buffer,
p_in_buf->i_nb_bytes );
if ( mad_frame_decode( &p_sys->mad_frame, &p_sys->mad_stream ) == -1 )
{
msg_Warn( p_aout, "libmad error: %s",
mad_stream_errorstr( &p_sys->mad_stream ) );
memset( p_out_buf->p_buffer, 0, p_out_buf->i_nb_bytes );
return;
}
mad_synth_frame( &p_sys->mad_synth, &p_sys->mad_frame );
if ( p_filter->output.i_format == VLC_FOURCC('f','i','3','2') )
{
/* Interleave and keep buffers in mad_fixed_t format */
mad_fixed_t * p_samples = (mad_fixed_t *)p_out_buf->p_buffer;
struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm;
unsigned int i_samples = p_pcm->length;
mad_fixed_t const * p_left = p_pcm->samples[0];
mad_fixed_t const * p_right = p_pcm->samples[1];
switch ( p_pcm->channels )
{
case 2:
while ( i_samples-- )
{
*p_samples++ = *p_left++;
*p_samples++ = *p_right++;
}
break;
case 1:
p_filter->p_vlc->pf_memcpy( p_samples, p_left,
i_samples * sizeof(mad_fixed_t) );
break;
default:
msg_Err( p_filter, "cannot interleave %i channels",
p_pcm->channels );
}
}
else
{
/* float32 */
float * p_samples = (float *)p_out_buf->p_buffer;
struct mad_pcm * p_pcm = &p_sys->mad_synth.pcm;
unsigned int i_samples = p_pcm->length;
mad_fixed_t const * p_left = p_pcm->samples[0];
mad_fixed_t const * p_right = p_pcm->samples[1];
switch ( p_pcm->channels )
{
case 2:
while ( i_samples-- )
{
*p_samples++ = (float)*p_left++ / (float)FIXED32_ONE;
*p_samples++ = (float)*p_right++ / (float)FIXED32_ONE;
}
break;
case 1:
while ( i_samples-- )
{
*p_samples++ = (float)*p_left++ / (float)FIXED32_ONE;
}
break;
default:
msg_Err( p_filter, "cannot interleave %i channels",
p_pcm->channels );
}
}
}
/*****************************************************************************
* Destroy : deallocate data structures
*****************************************************************************/
static void Destroy( vlc_object_t * _p_filter )
{
aout_filter_t * p_filter = (aout_filter_t *)_p_filter;
struct aout_filter_sys_t * p_sys = p_filter->p_sys;
mad_synth_finish( &p_sys->mad_synth );
mad_frame_finish( &p_sys->mad_frame );
mad_stream_finish( &p_sys->mad_stream );
free( p_sys );
}
......@@ -8,3 +8,4 @@ SOURCES_tremor = modules/codec/vorbis.c
SOURCES_dv = modules/codec/dv.c
SOURCES_xvid = modules/codec/xvid.c
SOURCES_adpcm = modules/codec/adpcm.c
SOURCES_mpeg_audio = modules/codec/mpeg_audio.c
......@@ -2,7 +2,7 @@
* a52.c: A/52 basic parser
*****************************************************************************
* Copyright (C) 2001-2002 VideoLAN
* $Id: a52.c,v 1.20 2002/12/28 02:02:18 massiot Exp $
* $Id: a52.c,v 1.21 2003/01/15 10:58:47 massiot Exp $
*
* Authors: Stphane Borel <stef@via.ecp.fr>
* Christophe Massiot <massiot@via.ecp.fr>
......@@ -41,7 +41,7 @@
#endif
/*****************************************************************************
* dec_thread_t : A52 pass-through thread descriptor
* dec_thread_t : decoder thread descriptor
*****************************************************************************/
typedef struct dec_thread_t
{
......@@ -254,7 +254,7 @@ static int RunDecoder( decoder_fifo_t *p_fifo )
}
/*****************************************************************************
* EndThread : spdif thread destruction
* EndThread : thread destruction
*****************************************************************************/
static void EndThread( dec_thread_t * p_dec )
{
......@@ -268,7 +268,7 @@ static void EndThread( dec_thread_t * p_dec )
}
/*****************************************************************************
* SyncInfo: parse A52 sync info
* SyncInfo: parse A/52 sync info
*****************************************************************************
* This code is borrowed from liba52 by Aaron Holtzman & Michel Lespinasse,
* since we don't want to oblige S/PDIF people to use liba52 just to get
......
SOURCES_mad = \
modules/codec/mad/decoder.c \
modules/codec/mad/decoder.h \
modules/codec/mad/libmad.c \
modules/codec/mad/libmad.h \
$(NULL)
/***************************************************************************
decoder.c - description
-------------------
Plugin Module definition for using libmad audio decoder in vlc. The
libmad codec uses integer arithmic only. This makes it suitable for using
it on architectures without a hardware FPU unit, such as the StrongArm
CPU.
begin : Mon Nov 5 2001
copyright : (C) 2001 by Jean-Paul Saman
email : jpsaman@wxs.nl
***************************************************************************/
/***************************************************************************
* *
* 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 *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
/*****************************************************************************
* Libmad include files *
*****************************************************************************/
#include <mad.h>
#include "decoder.h"
#include "libmad.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int OpenDecoder ( vlc_object_t * );
static int RunDecoder ( decoder_fifo_t * );
static int InitThread ( mad_adec_thread_t * );
static void EndThread ( mad_adec_thread_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_category_hint( N_("Libmad"), NULL );
set_description( _("libmad MPEG 1/2/3 audio decoder") );
set_capability( "decoder", 100 );
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************
* Tries to launch a decoder and return score so that the interface is able
* to choose.
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
if( p_fifo->i_fourcc != VLC_FOURCC('m','p','g','a') )
{
return VLC_EGENERIC;
}
p_fifo->pf_run = RunDecoder;
return VLC_SUCCESS;
}
/*****************************************************************************
* RunDecoder: this function is called just after the thread is created
*****************************************************************************/
static int RunDecoder( decoder_fifo_t *p_fifo )
{
mad_adec_thread_t * p_dec;
int i_ret;
/* Allocate the memory needed to store the thread's structure */
p_dec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t));
if (p_dec == NULL)
{
msg_Err( p_fifo, "out of memory" );
DecoderError( p_fifo );
return VLC_ENOMEM;
}
/*
* Initialize the thread properties
*/
p_dec->p_fifo = p_fifo;
if( InitThread( p_dec ) )
{
msg_Err( p_fifo, "could not initialize thread" );
DecoderError( p_fifo );
free( p_dec );
return VLC_ETHREAD;
}
/* mad decoder thread's main loop */
while( !p_dec->p_fifo->b_die && !p_dec->p_fifo->b_error )
{
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_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_dec->p_fifo->b_error)
{
DecoderError( p_dec->p_fifo );
}
/* End of the mad decoder thread */
EndThread (p_dec);
return VLC_SUCCESS;
}
/*****************************************************************************
* InitThread: initialize data before entering main loop
*****************************************************************************/
static int InitThread( mad_adec_thread_t * p_dec )
{
/* Initialize the thread properties */
p_dec->p_aout = NULL;
p_dec->p_aout_input = NULL;
p_dec->output_format.i_format = VLC_FOURCC('f','i','3','2');
/*
* Properties of audio for libmad
*/
/* Initialize the libmad decoder structures */
p_dec->i_current_pts = p_dec->i_next_pts = 0;
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 */
libmad_error, /* error */
NULL ); /* message */
mad_decoder_options( &p_dec->libmad_decoder, MAD_OPTION_IGNORECRC );
/*
* Initialize the input properties
*/
return InitBitstream( &p_dec->bit_stream, p_dec->p_fifo, NULL, NULL );
}
/*****************************************************************************
* EndThread : libmad decoder thread destruction
*****************************************************************************/
static void EndThread (mad_adec_thread_t * p_dec)
{
/* If the audio output fifo was created, we destroy it */
if (p_dec->p_aout_input != NULL)
{
aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
}
/* mad_decoder_finish releases the memory allocated inside the struct */
mad_decoder_finish( &p_dec->libmad_decoder );
CloseBitstream( &p_dec->bit_stream );
free( p_dec );
}
/***************************************************************************
mad_adec.h - description
-------------------
begin : Mon Nov 5 2001
copyright : (C) 2001 by Jean-Paul Saman
email : jpsaman@wxs.nl
***************************************************************************/
/***************************************************************************
* *
* 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 *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef _VLC_MAD_ADEC_H_
#define _VLC_MAD_ADEC_H_
/*****************************************************************************
* mad_adec_thread_t : mad decoder thread descriptor
*****************************************************************************/
enum mad_scaling { FAST_SCALING, MPG321_SCALING };
typedef struct mad_adec_thread_s
{
/*
* Decoder properties
*/
struct mad_decoder libmad_decoder;
mad_timer_t libmad_timer;
byte_t buffer[MAD_BUFFER_MDLEN];
/*
* Thread properties
*/
vlc_thread_t thread_id; /* id for thread functions */
/*
* Input properties
*/
decoder_fifo_t * p_fifo; /* stores the PES stream data */
bit_stream_t bit_stream; /* handle PES stream at the bit level */
/* Store i_pts for syncing audio frames */
mtime_t i_current_pts, i_next_pts;
/*
* Output properties
*/
aout_instance_t * p_aout; /* opaque */
aout_input_t * p_aout_input; /* opaque */
audio_sample_format_t output_format;
audio_date_t end_date;
} mad_adec_thread_t;
/*****************************************************************************
* Prototypes
*****************************************************************************/
vlc_thread_t mad_adec_CreateThread( decoder_fifo_t * p_fifo );
#endif
/***************************************************************************
libmad.c - description
-------------------
Functions that are called by libmad to communicate with vlc decoder
infrastructure.
begin : Mon Nov 5 2001
copyright : (C) 2001 by Jean-Paul Saman
email : jpsaman@wxs.nl
***************************************************************************/
/***************************************************************************
* *
* 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 *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
#include <vlc/aout.h>
#include <vlc/decoder.h>
/*****************************************************************************
* Libmad includes files
*****************************************************************************/
#include <mad.h>