]> git.sesse.net Git - vlc/blob - plugins/mad_adec/mad_adec.c
libmad plug-in, courtesy of Jean-Paul Saman <jpsaman@wxs.nl>.
[vlc] / plugins / mad_adec / mad_adec.c
1 /***************************************************************************
2               mad_adec.c  -  description
3                 -------------------
4     Plugin Module definition for using libmad audio decoder in vlc. The
5     libmad codec uses integer arithmic only. This makes it suitable for using
6     it on architectures without a hardware FPU unit, such as the StrongArm
7     CPU.
8
9     begin                : Mon Nov 5 2001
10     copyright            : (C) 2001 by Jean-Paul Saman
11     email                : jpsaman@wxs.nl
12  ***************************************************************************/
13
14 /***************************************************************************
15  *                                                                         *
16  *   This program is free software; you can redistribute it and/or modify  *
17  *   it under the terms of the GNU General Public License as published by  *
18  *   the Free Software Foundation; either version 2 of the License, or     *
19  *   (at your option) any later version.                                   *
20  *                                                                         *
21  ***************************************************************************/
22
23 #define MODULE_NAME mad_adec
24 #include "modules_inner.h"
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <string.h>                                              /* strdup() */
33
34 #include "config.h"
35 #include "common.h"                                     /* boolean_t, byte_t */
36 #include "intf_msg.h"
37 #include "threads.h"
38 #include "mtime.h"
39
40 #include "audio_output.h"
41
42 #include "modules.h"
43 #include "modules_export.h"
44
45 #include "stream_control.h"
46 #include "input_ext-dec.h"
47
48 #include "debug.h"
49
50 /*****************************************************************************
51  * Libmad include files                                                      *
52  *****************************************************************************/
53 #include <mad.h>
54 #include "mad_adec.h"
55 #include "mad_libmad.h"
56
57 /*****************************************************************************
58  * Local prototypes
59  *****************************************************************************/
60 static int      mad_adec_Probe       ( probedata_t * );
61 static int      mad_adec_Run         ( decoder_config_t * );
62 static int      mad_adec_Init        (mad_adec_thread_t * p_mad_adec);
63 static void     mad_adec_ErrorThread (mad_adec_thread_t * p_mad_adec);
64 static void     mad_adec_EndThread   (mad_adec_thread_t * p_mad_adec);
65
66 /*****************************************************************************
67  * Capabilities
68  *****************************************************************************/
69 void _M( adec_getfunctions )( function_list_t * p_function_list )
70 {
71     p_function_list->pf_probe = mad_adec_Probe;
72     p_function_list->functions.dec.pf_run = mad_adec_Run;
73 }
74
75 /*****************************************************************************
76  * Build configuration tree.
77  *****************************************************************************/
78 MODULE_CONFIG_START
79 ADD_WINDOW( "Configuration for mad_adec module" )
80     ADD_COMMENT( "No device to configure." )
81 MODULE_CONFIG_STOP
82
83 MODULE_INIT_START
84     p_module->i_capabilities = MODULE_CAPABILITY_DEC;
85     p_module->psz_longname = "Libmad MPEG 1/2/3 audio decoder library";
86 MODULE_INIT_STOP
87
88 MODULE_ACTIVATE_START
89     _M( adec_getfunctions )( &p_module->p_functions->dec );
90 MODULE_ACTIVATE_STOP
91
92 MODULE_DEACTIVATE_START
93 MODULE_DEACTIVATE_STOP
94
95 /*****************************************************************************
96  * mad_adec_Probe: probe the decoder and return score
97  *****************************************************************************
98  * Tries to launch a decoder and return score so that the interface is able
99  * to chose.
100  *****************************************************************************/
101 static int mad_adec_Probe( probedata_t *p_data )
102 {
103     if( p_data->i_type == MPEG1_AUDIO_ES || p_data->i_type == MPEG2_AUDIO_ES )
104     {
105         if( TestMethod( ADEC_MPEG_VAR, "mad" ) )
106         {
107             return( 999 );
108         }
109         return( 50 );
110     }
111     else
112     {
113         return( 0 );
114     }
115 }
116
117 /*****************************************************************************
118  * mad_adec_Run: this function is called just after the thread is created
119  *****************************************************************************/
120 static int mad_adec_Run ( decoder_config_t * p_config )
121 {
122     mad_adec_thread_t *   p_mad_adec;
123
124     intf_ErrMsg( "mad_adec debug: mad_adec thread launched, initializing" );
125
126     /* Allocate the memory needed to store the thread's structure */
127     p_mad_adec = (mad_adec_thread_t *) malloc(sizeof(mad_adec_thread_t));
128
129     if (p_mad_adec == NULL)
130     {
131         intf_ErrMsg ( "mad_adec error: not enough memory "
132                       "for mad_adec_Run() to allocate p_mad_adec" );
133         return( -1 );
134     }
135
136     /*
137      * Initialize the thread properties
138      */
139     p_mad_adec->p_config = p_config;
140     p_mad_adec->p_fifo = p_mad_adec->p_config->p_decoder_fifo;
141     if( mad_adec_Init( p_mad_adec ) )
142     {
143         intf_ErrMsg( "mad_adec error: could not initialize thread" );
144         return( -1 );
145     }
146
147     /* mad decoder thread's main loop */
148     while ((!p_mad_adec->p_fifo->b_die) && (!p_mad_adec->p_fifo->b_error))
149     {
150         intf_ErrMsg( "mad_adec: starting libmad decoder" );
151         if (mad_decoder_run(p_mad_adec->libmad_decoder, MAD_DECODER_MODE_SYNC)==-1)
152         {
153           intf_ErrMsg( "mad_adec error: libmad decoder returns abnormally");
154           mad_adec_EndThread(p_mad_adec);
155           return( -1 );
156         }
157     }
158
159     /* If b_error is set, the mad decoder thread enters the error loop */
160     if (p_mad_adec->p_fifo->b_error)
161     {
162         mad_adec_ErrorThread (p_mad_adec);
163     }
164
165     /* End of the ac3 decoder thread */
166     mad_adec_EndThread (p_mad_adec);
167
168     return( 0 );
169 }
170
171 /*****************************************************************************
172  * mad_adec_Init: initialize data before entering main loop
173  *****************************************************************************/
174 static int mad_adec_Init( mad_adec_thread_t * p_mad_adec )
175 {
176     /*
177      * Properties of audio for libmad
178      */
179         
180     /* Initialize the libmad decoder structures */
181     p_mad_adec->libmad_decoder = (struct mad_decoder*) malloc(sizeof(struct mad_decoder));
182
183     /*
184      * Initialize bit stream
185      */
186     p_mad_adec->p_config->pf_init_bit_stream( &p_mad_adec->bit_stream,
187                                               p_mad_adec->p_config->p_decoder_fifo,
188                                               NULL,    /* pf_bitstream_callback */
189                                               NULL );  /* void **/
190
191     RealignBits( &p_mad_adec->bit_stream );
192
193     mad_decoder_init( p_mad_adec->libmad_decoder,
194                       p_mad_adec,       /* vlc's thread structure and p_fifo playbuffer */
195                       libmad_input,     /* input_func */
196                       libmad_header,    /* header_func */
197                       0,                /* filter */
198                       libmad_output,    /* output_func */
199                       0,        /* error */
200                       0);               /* message */
201
202     mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC);
203         
204     /*
205      * Initialize the output properties
206      */
207
208     /* Creating the audio output fifo */
209     p_mad_adec->p_aout_fifo = aout_CreateFifo(  AOUT_ADEC_STEREO_FIFO, /* fifo type */
210                                                 2,                     /* nr. of channels */
211                                                 48000,                 /* frame rate in Hz ?*/
212                                                 0,                     /* units */
213                                                 ADEC_FRAME_SIZE/2,     /* frame size */
214                                                 NULL  );               /* buffer */
215
216     if ( p_mad_adec->p_aout_fifo == NULL )
217     {
218         return( -1 );
219     }
220
221     intf_ErrMsg("mad_adec debug: mad decoder thread %p initialized", p_mad_adec);
222
223     return( 0 );
224 }
225
226
227 /*****************************************************************************
228  * mad_adec_ErrorThread : mad decoder's RunThread() error loop
229  *****************************************************************************/
230 static void mad_adec_ErrorThread (mad_adec_thread_t * p_mad_adec)
231 {
232     /* We take the lock, because we are going to read/write the start/end
233      * indexes of the decoder fifo */
234     vlc_mutex_lock (&p_mad_adec->p_fifo->data_lock);
235
236     /* Wait until a `die' order is sent */
237     while (!p_mad_adec->p_fifo->b_die)
238     {
239         /* Trash all received PES packets */
240         while (!DECODER_FIFO_ISEMPTY(*p_mad_adec->p_fifo))
241         {
242             p_mad_adec->p_fifo->pf_delete_pes(
243                     p_mad_adec->p_fifo->p_packets_mgt,
244                     DECODER_FIFO_START(*p_mad_adec->p_fifo));
245             DECODER_FIFO_INCSTART (*p_mad_adec->p_fifo);
246         }
247
248         /* Waiting for the input thread to put new PES packets in the fifo */
249         vlc_cond_wait (&p_mad_adec->p_fifo->data_wait,
250                        &p_mad_adec->p_fifo->data_lock);
251     }
252
253     /* We can release the lock before leaving */
254     vlc_mutex_unlock (&p_mad_adec->p_fifo->data_lock);
255 }
256
257 /*****************************************************************************
258  * mad_adec_EndThread : libmad decoder thread destruction
259  *****************************************************************************/
260 static void mad_adec_EndThread (mad_adec_thread_t * p_mad_adec)
261 {
262     intf_ErrMsg ("mad_adec debug: destroying mad decoder thread %p", p_mad_adec);
263
264     /* If the audio output fifo was created, we destroy it */
265     if (p_mad_adec->p_aout_fifo != NULL)
266     {
267         aout_DestroyFifo (p_mad_adec->p_aout_fifo);
268
269         /* Make sure the output thread leaves the NextFrame() function */
270         vlc_mutex_lock (&(p_mad_adec->p_aout_fifo->data_lock));
271         vlc_cond_signal (&(p_mad_adec->p_aout_fifo->data_wait));
272         vlc_mutex_unlock (&(p_mad_adec->p_aout_fifo->data_lock));
273     }
274
275     /* mad_decoder_finish releases the memory allocated inside the struct */
276     mad_decoder_finish( p_mad_adec->libmad_decoder );
277
278     /* Unlock the modules */
279     free( p_mad_adec->libmad_decoder );
280 //    free( p_mad_adec->p_config ); /* for now a reminder until integration with cvs */
281     free( p_mad_adec );
282
283     intf_ErrMsg ("mad_adec debug: mad decoder thread %p destroyed", p_mad_adec);
284 }
285