]> git.sesse.net Git - vlc/blob - modules/packetizer/vorbis.c
* src/audio_output/input.c: don't try to play sound if the input pipeline couldn...
[vlc] / modules / packetizer / vorbis.c
1 /*****************************************************************************
2  * vorbis.c Vorbis audio packetizer
3  *****************************************************************************
4  * Copyright (C) 2001, 2002 VideoLAN
5  * $Id: vorbis.c,v 1.1 2003/06/23 23:51:31 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 <vlc/vlc.h>
28 #include <vlc/aout.h>
29 #include <vlc/decoder.h>
30 #include <vlc/input.h>
31 #include <vlc/sout.h>
32
33 #include <stdlib.h>                                      /* malloc(), free() */
34 #include <string.h>                                              /* strdup() */
35 #include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
36
37 #include <ogg/ogg.h>
38 #include <vorbis/codec.h>
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 typedef struct packetizer_s
44 {
45     /*
46      * Input properties
47      */
48     decoder_fifo_t         *p_fifo;            /* stores the PES stream data */
49     pes_packet_t           *p_pes;            /* current PES we are decoding */
50
51     /* Output properties */
52     sout_packetizer_input_t *p_sout_input;
53     sout_format_t           output_format;
54
55     /*
56      * Vorbis properties
57      */
58     vorbis_info      vi; /* struct that stores all the static vorbis bitstream
59                             settings */
60     vorbis_comment   vc; /* struct that stores all the bitstream user
61                           * comments */
62     vorbis_dsp_state vd; /* central working state for the packet->PCM
63                           * decoder */
64     vorbis_block     vb; /* local working space for packet->PCM decode */
65
66     uint64_t                i_samplescount;
67
68     mtime_t                 i_interpolated_pts;
69     int                     i_last_block_size;
70
71 } packetizer_t;
72
73 static int  Open    ( vlc_object_t * );
74 static int  Run     ( decoder_fifo_t * );
75
76 static int  InitThread     ( packetizer_t * );
77 static void PacketizeThread   ( packetizer_t * );
78 static void EndThread      ( packetizer_t * );
79
80 static int GetOggPacket( packetizer_t *, ogg_packet *, mtime_t * );
81 static int SendOggPacket( packetizer_t *, ogg_packet *, mtime_t, int );
82
83 #define FREE( p ) if( p ) free( p ); p = NULL
84
85 /*****************************************************************************
86  * Module descriptor
87  *****************************************************************************/
88 vlc_module_begin();
89     set_description( _("Vorbis audio packetizer") );
90     set_capability( "packetizer", 50 );
91     set_callbacks( Open, NULL );
92 vlc_module_end();
93
94 /*****************************************************************************
95  * OpenDecoder: probe the packetizer and return score
96  *****************************************************************************/
97 static int Open( vlc_object_t *p_this )
98 {
99     decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
100
101     if( p_fifo->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b') )
102     {
103         return VLC_EGENERIC;
104     }
105
106     p_fifo->pf_run = Run;
107     return VLC_SUCCESS;
108 }
109
110 /*****************************************************************************
111  * RunDecoder: this function is called just after the thread is created
112  *****************************************************************************/
113 static int Run( decoder_fifo_t *p_fifo )
114 {
115     packetizer_t *p_pack;
116     int b_error;
117
118     msg_Info( p_fifo, "Running vorbis packetizer" );
119     if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
120     {
121         msg_Err( p_fifo, "out of memory" );
122         DecoderError( p_fifo );
123         return -1;
124     }
125     memset( p_pack, 0, sizeof( packetizer_t ) );
126
127     p_pack->p_fifo = p_fifo;
128
129     if( InitThread( p_pack ) != 0 )
130     {
131         DecoderError( p_fifo );
132         return -1;
133     }
134
135     while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
136     {
137         PacketizeThread( p_pack );
138     }
139
140
141     if( ( b_error = p_pack->p_fifo->b_error ) )
142     {
143         DecoderError( p_pack->p_fifo );
144     }
145
146     EndThread( p_pack );
147
148     FREE( p_pack );
149
150     if( b_error )
151     {
152         return -1;
153     }
154
155     return 0;
156 }
157
158 /*****************************************************************************
159  * InitThread: initialize data before entering main loop
160  *****************************************************************************/
161 static int InitThread( packetizer_t *p_pack )
162
163     mtime_t    i_pts;
164     ogg_packet oggpacket;
165
166     p_pack->output_format.i_cat = AUDIO_ES;
167     p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
168     p_pack->output_format.i_sample_rate = 0;
169     p_pack->output_format.i_channels    = 0;
170     p_pack->output_format.i_block_align = 0;
171     p_pack->output_format.i_bitrate     = 0;
172     p_pack->output_format.i_extra_data  = 0;
173     p_pack->output_format.p_extra_data  = NULL;
174
175
176     p_pack->p_sout_input = NULL;
177
178     p_pack->i_samplescount = 0;
179     p_pack->i_interpolated_pts = 0;
180
181     p_pack->p_pes  = NULL;
182
183     /* Take care of vorbis init */
184     vorbis_info_init( &p_pack->vi );
185     vorbis_comment_init( &p_pack->vc );
186
187     /* Take care of the initial Vorbis headers */
188     if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
189         goto error;
190
191     oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
192     if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
193     {
194         msg_Err( p_pack->p_fifo, "This bitstream does not contain Vorbis "
195                  "audio data");
196         goto error;
197     }
198
199     /* add a input for the stream ouput */
200     p_pack->output_format.i_sample_rate = p_pack->vi.rate;
201     p_pack->output_format.i_channels    = p_pack->vi.channels;
202     p_pack->output_format.i_block_align = 1;
203     p_pack->output_format.i_bitrate     = p_pack->vi.bitrate_nominal;
204
205     p_pack->p_sout_input =
206         sout_InputNew( p_pack->p_fifo, &p_pack->output_format );
207
208     if( !p_pack->p_sout_input )
209     {
210         msg_Err( p_pack->p_fifo, "cannot add a new stream" );
211         p_pack->p_fifo->b_error = 1;
212         goto error;
213     }
214     msg_Dbg( p_pack->p_fifo, "channels:%d samplerate:%d bitrate:%d",
215              p_pack->vi.channels, p_pack->vi.rate, p_pack->vi.bitrate_nominal);
216
217     if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
218         goto error;
219
220     /* The next two packets in order are the comment and codebook headers.
221        We need to watch out that these packets are not missing as a
222        missing or corrupted header is fatal. */
223     if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
224         goto error;
225
226     if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
227     {
228         msg_Err( p_pack->p_fifo, "2nd Vorbis header is corrupted" );
229         goto error;
230     }
231     
232     if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
233         goto error;
234
235     if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
236         goto error;
237
238     if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
239     {
240         msg_Err( p_pack->p_fifo, "3rd Vorbis header is corrupted" );
241         goto error;
242     }
243
244     if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
245         goto error;
246
247     /* Initialize the Vorbis packet->PCM decoder */
248     vorbis_synthesis_init( &p_pack->vd, &p_pack->vi );
249     vorbis_block_init( &p_pack->vd, &p_pack->vb );
250
251     return 0;
252
253  error:
254     EndThread( p_pack );
255     return -1;
256 }
257
258 /*****************************************************************************
259  * PacketizeThread: packetize an unit (here copy a complete ogg packet)
260  *****************************************************************************/
261 static void PacketizeThread( packetizer_t *p_pack )
262 {
263     mtime_t    i_pts;
264     int        i_samples, i_block_size;
265     ogg_packet oggpacket;
266
267     /* Timestamp all the packets */
268     if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
269         goto error;
270
271     if( i_pts <= 0 && p_pack->i_interpolated_pts <= 0 )
272     {
273         msg_Dbg( p_pack->p_fifo, "need a starting pts" );
274         return;
275     }
276
277     if( i_pts > 0 ) p_pack->i_interpolated_pts = i_pts;
278
279     i_block_size = vorbis_packet_blocksize( &p_pack->vi, &oggpacket );
280     if( i_block_size < 0 ) i_block_size = 0; /* non audio packet */
281     i_samples = ( p_pack->i_last_block_size + i_block_size ) >> 2;
282     p_pack->i_last_block_size = i_block_size;
283
284     if( SendOggPacket( p_pack, &oggpacket, p_pack->i_interpolated_pts,
285                        i_samples ) != VLC_SUCCESS )
286         goto error;
287
288     p_pack->i_interpolated_pts += 1000000 * (uint64_t)i_samples
289         / p_pack->vi.rate;
290
291     return;
292
293  error:
294     p_pack->p_fifo->b_error = 1;
295 }
296
297 /*****************************************************************************
298  * EndThread : packetizer thread destruction
299  *****************************************************************************/
300 static void EndThread ( packetizer_t *p_pack)
301 {
302     if( p_pack->p_pes )
303         input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pack->p_pes );
304
305     vorbis_block_clear( &p_pack->vb );
306     vorbis_dsp_clear( &p_pack->vd );
307     vorbis_comment_clear( &p_pack->vc );
308     vorbis_info_clear( &p_pack->vi );  /* must be called last */
309
310     if( p_pack->p_sout_input )
311     {
312         sout_InputDelete( p_pack->p_sout_input );
313     }
314 }
315
316 /*****************************************************************************
317  * GetOggPacket: get the following vorbis packet from the stream and send back
318  *               the result in an ogg packet (for easy decoding by libvorbis).
319  *****************************************************************************
320  * Returns VLC_EGENERIC in case of eof.
321  *****************************************************************************/
322 static int GetOggPacket( packetizer_t *p_pack, ogg_packet *p_oggpacket,
323                          mtime_t *p_pts )
324 {
325     if( p_pack->p_pes ) input_DeletePES( p_pack->p_fifo->p_packets_mgt,
326                                          p_pack->p_pes );
327
328     input_ExtractPES( p_pack->p_fifo, &p_pack->p_pes );
329     if( !p_pack->p_pes ) return VLC_EGENERIC;
330
331     p_oggpacket->packet = p_pack->p_pes->p_first->p_payload_start;
332     p_oggpacket->bytes = p_pack->p_pes->i_pes_size;
333     p_oggpacket->granulepos = p_pack->p_pes->i_dts;
334     p_oggpacket->b_o_s = 0;
335     p_oggpacket->e_o_s = 0;
336     p_oggpacket->packetno = 0;
337
338     *p_pts = p_pack->p_pes->i_pts;
339
340     return VLC_SUCCESS;
341 }
342
343 /*****************************************************************************
344  * SendOggPacket: send an ogg packet to the stream output.
345  *****************************************************************************
346  * Returns VLC_EGENERIC in case of error.
347  *****************************************************************************/
348 static int SendOggPacket( packetizer_t *p_pack, ogg_packet *p_oggpacket,
349                           mtime_t i_pts, int i_samples )
350 {
351     sout_buffer_t *p_sout_buffer =
352         sout_BufferNew( p_pack->p_sout_input->p_sout, p_oggpacket->bytes );
353
354     if( !p_sout_buffer )
355     {
356         p_pack->p_fifo->b_error = 1;
357         return VLC_EGENERIC;
358     }
359
360     p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer,
361                                       p_oggpacket->packet,
362                                       p_oggpacket->bytes );
363
364     p_sout_buffer->i_bitrate = p_pack->vi.bitrate_nominal;
365
366     p_sout_buffer->i_dts = i_pts;
367     p_sout_buffer->i_pts = i_pts;
368
369     p_sout_buffer->i_length = 1000000 * (uint64_t)i_samples / p_pack->vi.rate;
370
371     p_pack->i_samplescount += i_samples;
372
373     sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
374
375     return VLC_SUCCESS;
376 }