]> git.sesse.net Git - vlc/blob - plugins/mpeg_adec/mpeg_adec.c
* ALL: new module API. Makes a few things a lot simpler, and we gain
[vlc] / plugins / mpeg_adec / mpeg_adec.c
1 /*****************************************************************************
2  * mpeg_adec.c: MPEG audio decoder thread
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: mpeg_adec.c,v 1.27 2002/07/31 20:56:52 sam Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Michel Lespinasse <walken@via.ecp.fr>
9  *          Samuel Hocevar <sam@via.ecp.fr>
10  *          Cyril Deguet <asmax@via.ecp.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <stdlib.h>                                      /* malloc(), free() */
31 #include <string.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/decoder.h>
35 #include <vlc/aout.h>
36
37 #include "mpeg_adec_generic.h"
38 #include "mpeg_adec.h"
39
40 #define ADEC_FRAME_SIZE (2*1152)
41
42 /*****************************************************************************
43  * Local Prototypes
44  *****************************************************************************/
45 static int  OpenDecoder    ( vlc_object_t * );
46 static int  RunDecoder     ( decoder_fifo_t * );
47
48 static void EndThread      ( adec_thread_t * );
49 static void DecodeThread   ( adec_thread_t * );
50
51 /*****************************************************************************
52  * Module descriptor
53  *****************************************************************************/
54 vlc_module_begin();
55     set_description( _("MPEG I/II layer 1/2 audio decoder") );
56     set_capability( "decoder", 50 );
57     add_requirement( FPU );
58     add_shortcut( "builtin" );
59     set_callbacks( OpenDecoder, NULL );
60 vlc_module_end();
61
62 /*****************************************************************************
63  * OpenDecoder: probe the decoder and return score
64  *****************************************************************************
65  * Tries to launch a decoder and return score so that the interface is able
66  * to choose.
67  *****************************************************************************/
68 static int OpenDecoder( vlc_object_t *p_this )
69 {   
70     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
71
72     if( p_fifo->i_fourcc != VLC_FOURCC('m','p','g','a') )
73     {   
74         return VLC_EGENERIC;
75     }
76     
77     p_fifo->pf_run = RunDecoder;
78     return VLC_SUCCESS;
79 }
80
81 /*****************************************************************************
82  * RunDecoder: initialize, go inside main loop, destroy
83  *****************************************************************************/
84 static int RunDecoder( decoder_fifo_t *p_fifo )
85 {
86     adec_thread_t   * p_adec;
87     
88     /* Allocate the memory needed to store the thread's structure */
89     if ( (p_adec = (adec_thread_t *)malloc (sizeof(adec_thread_t))) == NULL ) 
90     {
91         msg_Err( p_fifo, "out of memory" );
92         DecoderError( p_fifo );
93         return 0;
94     }
95     
96     /*
97      * Initialize the thread properties
98      */
99     p_adec->p_fifo = p_fifo;
100
101     /* 
102      * Initilize the banks
103      */
104     p_adec->bank_0.actual = p_adec->bank_0.v1;
105     p_adec->bank_0.pos = 0;
106     p_adec->bank_1.actual = p_adec->bank_1.v1;
107     p_adec->bank_1.pos = 0;
108     
109     /*
110      * Initialize bit stream 
111      */
112     InitBitstream( &p_adec->bit_stream, p_adec->p_fifo, NULL, NULL );
113
114     /* We do not create the audio output fifo now, but
115        it will be created when the first frame is received */
116     p_adec->p_aout_fifo = NULL;
117
118     p_adec->i_sync = 0;
119
120     /* Audio decoder thread's main loop */
121     while( (!p_adec->p_fifo->b_die) && (!p_adec->p_fifo->b_error) )
122     {
123         DecodeThread( p_adec );
124     }
125     
126     /* If b_error is set, the audio decoder thread enters the error loop */
127     if( p_adec->p_fifo->b_error ) 
128     {
129         DecoderError( p_adec->p_fifo );
130     }
131
132     /* End of the audio decoder thread */
133     EndThread( p_adec );
134
135     return( 0 );
136 }
137
138 /*
139  * Following functions are local to this module
140  */
141
142 /*****************************************************************************
143  * DecodeThread: decodes a mpeg frame
144  *****************************************************************************/
145 static void DecodeThread( adec_thread_t * p_adec )
146 {
147     s16 *p_buffer;
148     adec_sync_info_t sync_info;
149
150     if( ! adec_SyncFrame (p_adec, &sync_info) )
151     {
152         
153         /* TODO: check if audio type has changed */
154         
155         /* Create the output fifo if it doesn't exist yet */
156         if( p_adec->p_aout_fifo == NULL )
157         {
158             int i_channels;
159             
160             if( !config_GetInt( p_adec->p_fifo, "mono" ) )
161             {
162                 msg_Dbg( p_adec->p_fifo, "setting stereo output" );
163                 i_channels = 2;
164             }
165             else if( sync_info.b_stereo )
166             {
167                 i_channels = 2;
168             }
169             else
170             {
171                 i_channels = 1;
172             }
173             p_adec->p_aout_fifo =
174                aout_CreateFifo( p_adec->p_fifo, AOUT_FIFO_PCM, i_channels,
175                                 sync_info.sample_rate, ADEC_FRAME_SIZE, NULL );
176             if( p_adec->p_aout_fifo == NULL)
177             {
178                 msg_Err( p_adec->p_fifo, "failed to create aout fifo" );
179                 p_adec->p_fifo->b_error = 1;
180                 return;
181             }
182         }
183
184         p_adec->i_sync = 1;
185
186         p_buffer = ((s16 *)p_adec->p_aout_fifo->buffer)
187                     + (p_adec->p_aout_fifo->i_end_frame * ADEC_FRAME_SIZE);
188
189         CurrentPTS( &p_adec->bit_stream,
190             &p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame],
191             NULL );
192         if( !p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] )
193         {
194             p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] =
195                 LAST_MDATE;
196         }
197
198         if( adec_DecodeFrame (p_adec, p_buffer) )
199         {
200             /* Ouch, failed decoding... We'll have to resync */
201             p_adec->i_sync = 0;
202         }
203         else
204         {
205             vlc_mutex_lock (&p_adec->p_aout_fifo->data_lock);
206             p_adec->p_aout_fifo->i_end_frame =
207                 (p_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
208             vlc_cond_signal (&p_adec->p_aout_fifo->data_wait);
209             vlc_mutex_unlock (&p_adec->p_aout_fifo->data_lock);
210         }
211     }
212 }
213
214 /*****************************************************************************
215  * EndThread : audio decoder thread destruction
216  *****************************************************************************
217  * This function is called when the thread ends after a sucessful
218  * initialization.
219  *****************************************************************************/
220 static void EndThread ( adec_thread_t *p_adec )
221 {
222     /* If the audio output fifo was created, we destroy it */
223     if ( p_adec->p_aout_fifo != NULL ) 
224     {
225         aout_DestroyFifo ( p_adec->p_aout_fifo );
226
227         /* Make sure the output thread leaves the NextFrame() function */
228         vlc_mutex_lock (&(p_adec->p_aout_fifo->data_lock));
229         vlc_cond_signal (&(p_adec->p_aout_fifo->data_wait));
230         vlc_mutex_unlock (&(p_adec->p_aout_fifo->data_lock));
231     }
232     /* Destroy descriptor */
233     free( p_adec );
234 }
235