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