]> git.sesse.net Git - vlc/blob - modules/codec/vorbis.c
e1fe7f4c319e31b9108283df6744d1e93eead7f2
[vlc] / modules / codec / vorbis.c
1 /*****************************************************************************
2  * vorbis.c: vorbis decoder module making use of libvorbis.
3  *****************************************************************************
4  * Copyright (C) 1999-2001 VideoLAN
5  * $Id: vorbis.c,v 1.1 2002/10/24 09:30:47 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
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 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                    /* memcpy(), memset() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/aout.h>
32 #include <vlc/decoder.h>
33 #include <input_ext-dec.h>
34
35 #include <vlc/input.h>
36
37 #include <ogg/ogg.h>
38 #include <vorbis/codec.h>
39
40 /*****************************************************************************
41  * dec_thread_t : vorbis decoder thread descriptor
42  *****************************************************************************/
43 typedef struct dec_thread_t
44 {
45     /*
46      * Thread properties
47      */
48     vlc_thread_t        thread_id;                /* id for thread functions */
49
50     /*
51      * Vorbis properties
52      */
53     vorbis_info      vi; /* struct that stores all the static vorbis bitstream
54                             settings */
55     vorbis_comment   vc; /* struct that stores all the bitstream user
56                           * comments */
57     vorbis_dsp_state vd; /* central working state for the packet->PCM
58                           * decoder */
59     vorbis_block     vb; /* local working space for packet->PCM decode */
60
61     /*
62      * Input properties
63      */
64     decoder_fifo_t *    p_fifo;                /* stores the PES stream data */
65
66     /*
67      * Output properties
68      */
69     aout_instance_t        *p_aout;
70     aout_input_t           *p_aout_input;
71     audio_sample_format_t   output_format;
72     audio_date_t            end_date;
73
74 } dec_thread_t;
75
76 /*****************************************************************************
77  * Local prototypes
78  *****************************************************************************/
79 static int  OpenDecoder  ( vlc_object_t * );
80 static int  RunDecoder   ( decoder_fifo_t * );
81 static void CloseDecoder ( dec_thread_t * );
82
83 static void DecodePacket ( dec_thread_t * );
84 static int  GetOggPacket ( dec_thread_t *, ogg_packet *, mtime_t *, int );
85
86 static void Interleave   ( float *, const float **, int, int );
87
88 /*****************************************************************************
89  * Module descriptor
90  *****************************************************************************/
91 vlc_module_begin();
92     set_description( _("Vorbis decoder module") );
93     set_capability( "decoder", 100 );
94     set_callbacks( OpenDecoder, NULL );
95 vlc_module_end();
96
97 /*****************************************************************************
98  * OpenDecoder: probe the decoder and return score
99  *****************************************************************************/
100 static int OpenDecoder( vlc_object_t *p_this )
101 {
102     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
103
104     if( p_fifo->i_fourcc != VLC_FOURCC('v','o','r','b') )
105     {
106         return VLC_EGENERIC;
107     }
108
109     p_fifo->pf_run = RunDecoder;
110     return VLC_SUCCESS;
111 }
112
113 /*****************************************************************************
114  * RunDecoder: the vorbis decoder
115  *****************************************************************************/
116 static int RunDecoder( decoder_fifo_t * p_fifo )
117 {
118     dec_thread_t *p_dec;
119     ogg_packet oggpacket;
120     mtime_t i_pts;
121
122     /* Allocate the memory needed to store the thread's structure */
123     if( (p_dec = (dec_thread_t *)malloc (sizeof(dec_thread_t)) )
124             == NULL)
125     {
126         msg_Err( p_fifo, "out of memory" );
127         goto error;
128     }
129
130     /* Initialize the thread properties */
131     p_dec->p_fifo = p_fifo;
132
133     /* Take care of the initial Vorbis header */
134     vorbis_info_init( &p_dec->vi );
135     vorbis_comment_init( &p_dec->vc );
136
137     if( GetOggPacket( p_dec, &oggpacket, &i_pts, 0 ) != VLC_SUCCESS )
138         goto error;
139
140     oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
141     if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
142     {
143         msg_Err( p_dec->p_fifo, "This bitstream does not contain Vorbis "
144                  "audio data");
145         goto error;
146     }
147
148     /* The next two packets in order are the comment and codebook headers.
149        We need to watch out that these packets are not missing as a
150        missing or corrupted header is fatal. */
151     if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
152         goto error;
153
154     if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
155     {
156         msg_Err( p_dec->p_fifo, "2nd Vorbis header is corrupted" );
157         goto error;
158     }
159
160     if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
161         goto error;
162
163     if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
164     {
165         msg_Err( p_dec->p_fifo, "3rd Vorbis header is corrupted" );
166         goto error;
167     }
168
169     /* Initialize the Vorbis packet->PCM decoder */
170     vorbis_synthesis_init( &p_dec->vd, &p_dec->vi );
171     vorbis_block_init( &p_dec->vd, &p_dec->vb );
172
173     p_dec->output_format.i_format = VLC_FOURCC('f','l','3','2');
174     p_dec->output_format.i_channels = p_dec->vi.channels;
175     p_dec->output_format.i_rate = p_dec->vi.rate;
176
177     aout_DateInit( &p_dec->end_date, p_dec->vi.rate );
178     p_dec->p_aout = NULL;
179     p_dec->p_aout_input = aout_DecNew( p_dec->p_fifo,
180                                        &p_dec->p_aout,
181                                        &p_dec->output_format );
182
183     if( p_dec->p_aout_input == NULL )
184     {
185         msg_Err( p_dec->p_fifo, "failed to create aout fifo" );
186         goto error;
187     }
188
189     /* Take care of the first pts we receive. We need to be careful as a pts
190      * in vorbis language does in fact correspond to the presentation time of
191      * the _next_ packet to receive */
192     if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
193     {
194         aout_DateSet( &p_dec->end_date, i_pts );
195     }
196
197     /* vorbis decoder thread's main loop */
198     while( (!p_dec->p_fifo->b_die) && (!p_dec->p_fifo->b_error) )
199     {
200         DecodePacket( p_dec );
201     }
202
203     /* If b_error is set, the vorbis decoder thread enters the error loop */
204     if( p_dec->p_fifo->b_error )
205     {
206         DecoderError( p_dec->p_fifo );
207     }
208
209     /* End of the vorbis decoder thread */
210     CloseDecoder( p_dec );
211
212     return 0;
213
214  error:
215     if( p_dec )
216     {
217         if( p_dec->p_fifo )
218             p_dec->p_fifo->b_error = 1;
219         free( p_dec );
220     }
221
222     DecoderError( p_fifo );
223     return -1;
224
225 }
226
227 /*****************************************************************************
228  * DecodePacket: decodes a Vorbis packet.
229  *****************************************************************************/
230 static void DecodePacket( dec_thread_t *p_dec )
231 {
232     aout_buffer_t *p_aout_buffer;
233     ogg_packet    oggpacket;
234     float         **pp_pcm;
235     int           i_samples;
236     mtime_t       i_pts;
237
238     if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
239     {
240         /* This should mean an eos */
241         return;
242     }
243
244     if( vorbis_synthesis( &p_dec->vb, &oggpacket ) == 0 )
245         vorbis_synthesis_blockin( &p_dec->vd, &p_dec->vb );
246     else
247         msg_Err( p_dec->p_fifo, "vorbis_synthesis error" );
248
249     /* **pp_pcm is a multichannel float vector. In stereo, for
250      * example, pp_pcm[0] is left, and pp_pcm[1] is right. i_samples is
251      * the size of each channel. Convert the float values
252      * (-1.<=range<=1.) to whatever PCM format and write it out */
253
254     while( ( i_samples = vorbis_synthesis_pcmout( &p_dec->vd, &pp_pcm ) ) > 0 )
255     {
256
257         p_aout_buffer = aout_DecNewBuffer( p_dec->p_aout, p_dec->p_aout_input,
258                                            i_samples );
259         if( !p_aout_buffer )
260         {
261             msg_Err( p_dec->p_fifo, "cannot get aout buffer" );
262             p_dec->p_fifo->b_error = 1;
263             return;
264         }
265
266         /* Interleave the samples */
267         Interleave( (float *)p_aout_buffer->p_buffer, (const float **)pp_pcm,
268                     p_dec->vi.channels, i_samples );
269
270         /* Tell libvorbis how many samples we actually consumed */
271         vorbis_synthesis_read( &p_dec->vd, i_samples );
272
273         /* Date management */
274         p_aout_buffer->start_date = aout_DateGet( &p_dec->end_date );
275         p_aout_buffer->end_date = aout_DateIncrement( &p_dec->end_date,
276                                                       i_samples );
277
278         if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
279         {
280             aout_DateSet( &p_dec->end_date, i_pts );
281             p_aout_buffer->end_date = aout_DateGet( &p_dec->end_date );
282         }
283         else
284         {
285             aout_DateSet( &p_dec->end_date, p_aout_buffer->end_date );
286         }
287
288         aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
289     }
290
291 }
292
293 /*****************************************************************************
294  * GetOggPacket: get the following vorbis packet from the stream and send back
295  *               the result in an ogg packet (for easy decoding by libvorbis).
296  *****************************************************************************
297  * Returns VLC_EGENERIC in case of eof.
298  *****************************************************************************/
299 static int GetOggPacket( dec_thread_t *p_dec, ogg_packet *p_oggpacket,
300                          mtime_t *p_pts, int b_next )
301 {
302     pes_packet_t *p_pes;
303
304     if( b_next ) NextPES( p_dec->p_fifo );
305     p_pes = GetPES( p_dec->p_fifo );
306
307     p_oggpacket->packet = p_pes->p_first->p_payload_start;
308     p_oggpacket->bytes = p_pes->i_pes_size;
309     p_oggpacket->granulepos = p_pes->i_dts;
310     p_oggpacket->b_o_s = 0;
311     p_oggpacket->e_o_s = 0;
312     p_oggpacket->packetno = 0;
313
314     *p_pts = p_pes->i_pts;
315
316     return p_pes ? VLC_SUCCESS : VLC_EGENERIC;
317 }
318
319 /*****************************************************************************
320  * Interleave: helper function to interleave channels
321  *****************************************************************************/
322 static void Interleave( float *p_out, const float **pp_in, int i_channels,
323                         int i_samples )
324 {
325     int i, j;
326
327     for ( j = 0; j < i_samples; j++ )
328     {
329         for ( i = 0; i < i_channels; i++ )
330         {
331             p_out[j * i_channels + i] = pp_in[i][j];
332         }
333     }
334 }
335
336 /*****************************************************************************
337  * CloseDecoder: vorbis decoder destruction
338  *****************************************************************************/
339 static void CloseDecoder( dec_thread_t * p_dec )
340 {
341     if( p_dec->p_aout_input != NULL )
342     {
343         aout_DecDelete( p_dec->p_aout, p_dec->p_aout_input );
344     }
345
346     if( p_dec )
347     {
348         vorbis_block_clear( &p_dec->vb );
349         vorbis_dsp_clear( &p_dec->vd );
350         vorbis_comment_clear( &p_dec->vc );
351         vorbis_info_clear( &p_dec->vi );  /* must be called last */
352         free( p_dec );
353     }
354 }