mad_adec.c 8.95 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/***************************************************************************
              mad_adec.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.                                   *
 *                                                                         *
 ***************************************************************************/

Sam Hocevar's avatar
 
Sam Hocevar committed
23
#define MODULE_NAME mad
24 25 26 27 28 29 30 31 32 33 34 35 36 37
#include "modules_inner.h"

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include "defs.h"

#include <stdlib.h>                                      /* malloc(), free() */
#include <string.h>                                              /* strdup() */

#include "common.h"                                     /* boolean_t, byte_t */
#include "intf_msg.h"
#include "threads.h"
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
38
#include "tests.h"
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

#include "audio_output.h"

#include "modules.h"
#include "modules_export.h"

#include "stream_control.h"
#include "input_ext-dec.h"

#include "debug.h"

/*****************************************************************************
 * Libmad include files                                                      *
 *****************************************************************************/
#include <mad.h>
#include "mad_adec.h"
#include "mad_libmad.h"

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
60 61 62 63
static int  decoder_Probe  ( probedata_t * );
static int  decoder_Run    ( decoder_config_t * );
static int  InitThread     ( mad_adec_thread_t * p_mad_adec );
static void EndThread      ( mad_adec_thread_t * p_mad_adec );
64 65 66 67 68 69

/*****************************************************************************
 * Capabilities
 *****************************************************************************/
void _M( adec_getfunctions )( function_list_t * p_function_list )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
70 71
    p_function_list->pf_probe = decoder_Probe;
    p_function_list->functions.dec.pf_run = decoder_Run;
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
}

/*****************************************************************************
 * Build configuration tree.
 *****************************************************************************/
MODULE_CONFIG_START
ADD_WINDOW( "Configuration for mad_adec module" )
    ADD_COMMENT( "No device to configure." )
MODULE_CONFIG_STOP

MODULE_INIT_START
    p_module->i_capabilities = MODULE_CAPABILITY_DEC;
    p_module->psz_longname = "Libmad MPEG 1/2/3 audio decoder library";
MODULE_INIT_STOP

MODULE_ACTIVATE_START
    _M( adec_getfunctions )( &p_module->p_functions->dec );
MODULE_ACTIVATE_STOP

MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
95
 * decoder_Probe: probe the decoder and return score
96 97 98 99
 *****************************************************************************
 * Tries to launch a decoder and return score so that the interface is able
 * to chose.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
100
static int decoder_Probe( probedata_t *p_data )
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
{
    if( p_data->i_type == MPEG1_AUDIO_ES || p_data->i_type == MPEG2_AUDIO_ES )
    {
        if( TestMethod( ADEC_MPEG_VAR, "mad" ) )
        {
            return( 999 );
        }
        return( 50 );
    }
    else
    {
        return( 0 );
    }
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
117
 * decoder_Run: this function is called just after the thread is created
118
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
119
static int decoder_Run ( decoder_config_t * p_config )
120 121 122 123 124 125 126 127 128 129 130
{
    mad_adec_thread_t *   p_mad_adec;

    intf_ErrMsg( "mad_adec debug: mad_adec thread launched, initializing" );

    /* Allocate the memory needed to store the thread's structure */
    p_mad_adec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t));

    if (p_mad_adec == NULL)
    {
        intf_ErrMsg ( "mad_adec error: not enough memory "
Sam Hocevar's avatar
 
Sam Hocevar committed
131 132
                      "for decoder_Run() to allocate p_mad_adec" );
        DecoderError( p_config->p_decoder_fifo );
133 134 135 136 137 138 139 140
        return( -1 );
    }

    /*
     * Initialize the thread properties
     */
    p_mad_adec->p_config = p_config;
    p_mad_adec->p_fifo = p_mad_adec->p_config->p_decoder_fifo;
Sam Hocevar's avatar
 
Sam Hocevar committed
141
    if( InitThread( p_mad_adec ) )
142 143
    {
        intf_ErrMsg( "mad_adec error: could not initialize thread" );
Sam Hocevar's avatar
 
Sam Hocevar committed
144 145
        DecoderError( p_config->p_decoder_fifo );
        free( p_mad_adec );
146 147 148 149 150 151 152 153 154 155
        return( -1 );
    }

    /* mad decoder thread's main loop */
    while ((!p_mad_adec->p_fifo->b_die) && (!p_mad_adec->p_fifo->b_error))
    {
	intf_ErrMsg( "mad_adec: starting libmad decoder" );
	if (mad_decoder_run(p_mad_adec->libmad_decoder, MAD_DECODER_MODE_SYNC)==-1)
	{
	  intf_ErrMsg( "mad_adec error: libmad decoder returns abnormally");
Sam Hocevar's avatar
 
Sam Hocevar committed
156 157
          DecoderError( p_mad_adec->p_fifo );
	  EndThread(p_mad_adec);
158 159 160 161 162 163 164
      	  return( -1 );
	}
    }

    /* If b_error is set, the mad decoder thread enters the error loop */
    if (p_mad_adec->p_fifo->b_error)
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
165
        DecoderError( p_mad_adec->p_fifo );
166 167 168
    }

    /* End of the ac3 decoder thread */
Sam Hocevar's avatar
 
Sam Hocevar committed
169
    EndThread (p_mad_adec);
170 171 172 173 174

    return( 0 );
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
175
 * InitThread: initialize data before entering main loop
176
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
177
static int InitThread( mad_adec_thread_t * p_mad_adec )
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
{
    /*
     * Properties of audio for libmad
     */
	
    /* Initialize the libmad decoder structures */
    p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder));

    /*
     * Initialize bit stream
     */
    p_mad_adec->p_config->pf_init_bit_stream( &p_mad_adec->bit_stream,
					      p_mad_adec->p_config->p_decoder_fifo,
					      NULL,    /* pf_bitstream_callback */
					      NULL );  /* void **/

    RealignBits( &p_mad_adec->bit_stream );

    mad_decoder_init( p_mad_adec->libmad_decoder,
    		      p_mad_adec, 	/* vlc's thread structure and p_fifo playbuffer */
		      libmad_input,  	/* input_func */
		      libmad_header, 	/* header_func */
		      0,		/* filter */
		      libmad_output, 	/* output_func */
		      0,  	/* error */
		      0);            	/* message */

    mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC);
 	
    /*
     * Initialize the output properties
     */

    /* Creating the audio output fifo */
    p_mad_adec->p_aout_fifo = aout_CreateFifo(  AOUT_ADEC_STEREO_FIFO, /* fifo type */
						2,                     /* nr. of channels */
						48000,	 	       /* frame rate in Hz ?*/
						0,                     /* units */
                                                ADEC_FRAME_SIZE/2,     /* frame size */
						NULL  );               /* buffer */

    if ( p_mad_adec->p_aout_fifo == NULL )
    {
        return( -1 );
    }

    intf_ErrMsg("mad_adec debug: mad decoder thread %p initialized", p_mad_adec);

    return( 0 );
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
230
 * EndThread : libmad decoder thread destruction
231
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
232
static void EndThread (mad_adec_thread_t * p_mad_adec)
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
{
    intf_ErrMsg ("mad_adec debug: destroying mad decoder thread %p", p_mad_adec);

    /* If the audio output fifo was created, we destroy it */
    if (p_mad_adec->p_aout_fifo != NULL)
    {
        aout_DestroyFifo (p_mad_adec->p_aout_fifo);

        /* Make sure the output thread leaves the NextFrame() function */
        vlc_mutex_lock (&(p_mad_adec->p_aout_fifo->data_lock));
        vlc_cond_signal (&(p_mad_adec->p_aout_fifo->data_wait));
        vlc_mutex_unlock (&(p_mad_adec->p_aout_fifo->data_lock));
    }

    /* mad_decoder_finish releases the memory allocated inside the struct */
    mad_decoder_finish( p_mad_adec->libmad_decoder );

    /* Unlock the modules */
    free( p_mad_adec->libmad_decoder );
//    free( p_mad_adec->p_config ); /* for now a reminder until integration with cvs */
    free( p_mad_adec );

    intf_ErrMsg ("mad_adec debug: mad decoder thread %p destroyed", p_mad_adec);
}