]> git.sesse.net Git - vlc/blob - modules/codec/faad.c
* all: only include header that are needed (and no more stdlib.h, string.h
[vlc] / modules / codec / faad.c
1 /*****************************************************************************
2  * decoder.c: AAC decoder using libfaad2
3  *****************************************************************************
4  * Copyright (C) 2001, 2003 VideoLAN
5  * $Id: faad.c,v 1.5 2003/11/22 23:39:14 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <vlc/vlc.h>
25 #include <vlc/aout.h>
26 #include <vlc/decoder.h>
27
28 #include <faad.h>
29
30 /*****************************************************************************
31  * Module descriptor
32  *****************************************************************************/
33 static int  Open( vlc_object_t * );
34 static void Close( vlc_object_t * );
35
36 vlc_module_begin();
37     set_description( _("AAC audio decoder (using libfaad2)") );
38     set_capability( "decoder", 60 );
39     set_callbacks( Open, Close );
40 vlc_module_end();
41
42
43 /****************************************************************************
44  * Local prototypes
45  ****************************************************************************/
46 static aout_buffer_t *DecodeBlock( decoder_t *, block_t ** );
47
48 struct decoder_sys_t
49 {
50     /* faad handler */
51     faacDecHandle *hfaad;
52
53     /* samples */
54     audio_date_t date;
55
56     /* temporary buffer */
57     uint8_t *p_buffer;
58     int     i_buffer;
59     int     i_buffer_size;
60 };
61
62 static unsigned int pi_channels_maps[7] =
63 {
64     0,
65     AOUT_CHAN_CENTER,
66     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
67     AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
68     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT |
69         AOUT_CHAN_REARRIGHT,
70     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
71         AOUT_CHAN_REARRIGHT,
72      /* FIXME */
73     AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT |
74         AOUT_CHAN_REARRIGHT | AOUT_CHAN_REARCENTER
75 };
76
77 /*****************************************************************************
78  * OpenDecoder: probe the decoder and return score
79  *****************************************************************************/
80 static int Open( vlc_object_t *p_this )
81 {
82     decoder_t *p_dec = (decoder_t*)p_this;
83     decoder_sys_t *p_sys = p_dec->p_sys;
84     faacDecConfiguration *cfg;
85
86     if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','4','a') )
87     {
88         return VLC_EGENERIC;
89     }
90
91     /* Allocate the memory needed to store the decoder's structure */
92     if( ( p_dec->p_sys = p_sys =
93           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
94     {
95         msg_Err( p_dec, "out of memory" );
96         return VLC_EGENERIC;
97     }
98
99     /* Open a faad context */
100     if( ( p_sys->hfaad = faacDecOpen() ) == NULL )
101     {
102         msg_Err( p_dec, "Cannot initialize faad" );
103         return VLC_EGENERIC;
104     }
105
106     /* Misc init */
107     aout_DateSet( &p_sys->date, 0 );
108     p_dec->fmt_out.i_cat = AUDIO_ES;
109     p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
110     p_dec->pf_decode_audio = DecodeBlock;
111
112     if( p_dec->fmt_in.i_extra > 0 )
113     {
114         /* We have a decoder config so init the handle */
115         unsigned long i_rate;
116         unsigned char i_channels;
117
118         if( faacDecInit2( p_sys->hfaad, p_dec->fmt_in.p_extra,
119                           p_dec->fmt_in.i_extra,
120                           &i_rate, &i_channels ) < 0 )
121         {
122             return VLC_EGENERIC;
123         }
124
125         p_dec->fmt_out.audio.i_rate = i_rate;
126         p_dec->fmt_out.audio.i_channels = i_channels;
127         p_dec->fmt_out.audio.i_physical_channels =
128             p_dec->fmt_out.audio.i_original_channels =
129                 pi_channels_maps[i_channels];
130
131         aout_DateInit( &p_sys->date, i_rate );
132     }
133     else
134     {
135         /* Will be initalised from first frame */
136         p_dec->fmt_out.audio.i_rate = 0;
137         p_dec->fmt_out.audio.i_channels = 0;
138         p_dec->fmt_out.audio.i_physical_channels =
139             p_dec->fmt_out.audio.i_original_channels = 0;
140     }
141
142     /* Set the faad config */
143     cfg = faacDecGetCurrentConfiguration( p_sys->hfaad );
144     cfg->outputFormat = FAAD_FMT_FLOAT;
145     faacDecSetConfiguration( p_sys->hfaad, cfg );
146
147     /* buffer */
148     p_sys->i_buffer = 0;
149     p_sys->i_buffer_size = 10000;
150     p_sys->p_buffer = malloc( p_sys->i_buffer_size );
151
152     return VLC_SUCCESS;
153 }
154
155 /*****************************************************************************
156  * DecodeBlock:
157  *****************************************************************************/
158 static aout_buffer_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
159 {
160     decoder_sys_t *p_sys = p_dec->p_sys;
161     block_t *p_block;
162
163     if( !pp_block || !*pp_block ) return NULL;
164
165     p_block = *pp_block;
166
167     /* Append the block to the temporary buffer */
168     if( p_sys->i_buffer_size < p_sys->i_buffer + p_block->i_buffer )
169     {
170         p_sys->i_buffer_size = p_sys->i_buffer + p_block->i_buffer;
171         p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
172     }
173
174     if( p_block->i_buffer )
175     {
176         memcpy( &p_sys->p_buffer[p_sys->i_buffer],
177                 p_block->p_buffer, p_block->i_buffer );
178         p_sys->i_buffer += p_block->i_buffer;
179         p_block->i_buffer = 0;
180     }
181
182     if( p_dec->fmt_out.audio.i_rate == 0 && p_sys->i_buffer )
183     {
184         unsigned long i_rate;
185         unsigned char i_channels;
186
187         /* Init faad with the first frame */
188         if( faacDecInit( p_sys->hfaad,
189                          p_sys->p_buffer, p_sys->i_buffer,
190                          &i_rate, &i_channels ) < 0 )
191         {
192             block_Release( p_block );
193             return NULL;
194         }
195
196         p_dec->fmt_out.audio.i_rate = i_rate;
197         p_dec->fmt_out.audio.i_channels = i_channels;
198         p_dec->fmt_out.audio.i_physical_channels =
199             p_dec->fmt_out.audio.i_original_channels =
200                 pi_channels_maps[i_channels];
201
202         aout_DateInit( &p_sys->date, i_rate );
203     }
204
205     if( p_block->i_pts != 0 && p_block->i_pts != aout_DateGet( &p_sys->date ) )
206     {
207         aout_DateSet( &p_sys->date, p_block->i_pts );
208     }
209     else if( !aout_DateGet( &p_sys->date ) )
210     {
211         /* We've just started the stream, wait for the first PTS. */
212         block_Release( p_block );
213         p_sys->i_buffer = 0;
214         return NULL;
215     }
216
217     /* Decode all data */
218     if( p_sys->i_buffer )
219     {
220         void *samples;
221         faacDecFrameInfo frame;
222         aout_buffer_t *p_out;
223
224         samples = faacDecDecode( p_sys->hfaad, &frame,
225                                  p_sys->p_buffer, p_sys->i_buffer );
226
227         if( frame.error > 0 )
228         {
229             msg_Warn( p_dec, "%s", faacDecGetErrorMessage( frame.error ) );
230
231             /* Flush the buffer */
232             p_sys->i_buffer = 0;
233             block_Release( p_block );
234             return NULL;
235         }
236
237         if( frame.channels <= 0 || frame.channels > 6 )
238         {
239             msg_Warn( p_dec, "invalid channels count" );
240
241             /* Flush the buffer */
242             p_sys->i_buffer = 0;
243             block_Release( p_block );
244             return NULL;
245         }
246
247         if( frame.samples <= 0 )
248         {
249             msg_Warn( p_dec, "decoded zero samples" );
250
251             /* Flush the buffer */
252             p_sys->i_buffer = 0;
253             block_Release( p_block );
254             return NULL;
255         }
256
257         /* We decoded a valid frame */
258         if( p_dec->fmt_out.audio.i_rate != frame.samplerate )
259         {
260             aout_DateInit( &p_sys->date, frame.samplerate );
261             aout_DateSet( &p_sys->date, p_block->i_pts );
262         }
263         p_block->i_pts = 0;  /* PTS is valid only once */
264
265         p_dec->fmt_out.audio.i_rate = frame.samplerate;
266         p_dec->fmt_out.audio.i_channels = frame.channels;
267         p_dec->fmt_out.audio.i_physical_channels =
268             p_dec->fmt_out.audio.i_original_channels =
269                 pi_channels_maps[frame.channels];
270
271         p_out = p_dec->pf_aout_buffer_new( p_dec,
272                                            frame.samples / frame.channels );
273         if( p_out == NULL )
274         {
275             p_sys->i_buffer = 0;
276             block_Release( p_block );
277             return NULL;
278         }
279
280         p_out->start_date = aout_DateGet( &p_sys->date );
281         p_out->end_date = aout_DateIncrement( &p_sys->date,
282                                               frame.samples / frame.channels );
283
284         memcpy( p_out->p_buffer, samples, p_out->i_nb_bytes );
285
286         p_sys->i_buffer -= frame.bytesconsumed;
287         if( p_sys->i_buffer > 0 )
288         {
289             memmove( p_sys->p_buffer, &p_sys->p_buffer[frame.bytesconsumed],
290                      p_sys->i_buffer );
291         }
292
293         return p_out;
294     }
295
296     block_Release( p_block );
297     return NULL;
298 }
299
300 /*****************************************************************************
301  * Close:
302  *****************************************************************************/
303 static void Close( vlc_object_t *p_this )
304 {
305     decoder_t *p_dec = (decoder_t *)p_this;
306     decoder_sys_t *p_sys = p_dec->p_sys;
307
308     faacDecClose( p_sys->hfaad );
309     free( p_sys );
310 }