1 /*****************************************************************************
2 * speex.c: speex decoder module making use of libspeex.
3 *****************************************************************************
4 * Copyright (C) 1999-2001 VideoLAN
5 * $Id: speex.c,v 1.1 2003/10/22 17:12:30 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <string.h> /* memcpy(), memset() */
32 #include <vlc/decoder.h>
33 #include <vlc/input.h>
35 #include <input_ext-dec.h>
37 #include <vlc/input.h>
41 #include "speex_header.h"
42 #include "speex_stereo.h"
43 #include "speex_callbacks.h"
45 /*****************************************************************************
46 * decoder_sys_t : speex decoder descriptor
47 *****************************************************************************/
51 vlc_bool_t b_packetizer;
62 SpeexHeader *p_header;
63 SpeexStereoState stereo;
69 aout_instance_t *p_aout;
70 aout_input_t *p_aout_input;
71 audio_sample_format_t aout_format;
74 * Packetizer output properties
76 sout_packetizer_input_t *p_sout_input;
77 sout_format_t sout_format;
82 audio_date_t end_date;
86 static int pi_channels_maps[6] =
89 AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
90 AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
91 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
92 | AOUT_CHAN_REARRIGHT,
93 AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
94 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
97 /****************************************************************************
99 ****************************************************************************/
100 static int OpenDecoder ( vlc_object_t * );
101 static int OpenPacketizer( vlc_object_t * );
103 static int InitDecoder ( decoder_t * );
104 static int RunDecoder ( decoder_t *, block_t * );
105 static int EndDecoder ( decoder_t * );
107 static int ProcessHeader ( decoder_t *, ogg_packet * );
108 static int ProcessPacket ( decoder_t *, ogg_packet *, mtime_t );
109 static int DecodePacket ( decoder_t *, ogg_packet * );
110 static int SendPacket ( decoder_t *, ogg_packet * );
112 static void ParseSpeexComments( decoder_t *, ogg_packet * );
114 /*****************************************************************************
116 *****************************************************************************/
118 set_description( _("Speex audio decoder") );
119 set_capability( "decoder", 100 );
120 set_callbacks( OpenDecoder, NULL );
123 set_description( _("Speex audio packetizer") );
124 set_capability( "packetizer", 100 );
125 set_callbacks( OpenPacketizer, NULL );
128 /*****************************************************************************
129 * OpenDecoder: probe the decoder and return score
130 *****************************************************************************/
131 static int OpenDecoder( vlc_object_t *p_this )
133 decoder_t *p_dec = (decoder_t*)p_this;
135 if( p_dec->p_fifo->i_fourcc != VLC_FOURCC('s','p','x',' ') )
140 p_dec->pf_init = InitDecoder;
141 p_dec->pf_decode = RunDecoder;
142 p_dec->pf_end = EndDecoder;
144 /* Allocate the memory needed to store the decoder's structure */
146 (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
148 msg_Err( p_dec, "out of memory" );
151 p_dec->p_sys->b_packetizer = VLC_FALSE;
156 static int OpenPacketizer( vlc_object_t *p_this )
158 decoder_t *p_dec = (decoder_t*)p_this;
160 int i_ret = OpenDecoder( p_this );
162 if( i_ret == VLC_SUCCESS ) p_dec->p_sys->b_packetizer = VLC_TRUE;
167 /*****************************************************************************
168 * InitDecoder: Initalize the decoder
169 *****************************************************************************/
170 static int InitDecoder( decoder_t *p_dec )
172 decoder_sys_t *p_sys = p_dec->p_sys;
174 aout_DateSet( &p_sys->end_date, 0 );
176 p_sys->p_aout = NULL;
177 p_sys->p_aout_input = NULL;
178 p_sys->aout_format.i_format = VLC_FOURCC('s','p','x',' ');
180 p_sys->p_sout_input = NULL;
181 p_sys->sout_format.i_cat = AUDIO_ES;
182 p_sys->sout_format.i_fourcc = VLC_FOURCC( 's', 'p', 'x', ' ' );
183 p_sys->sout_format.i_block_align = 0;
184 p_sys->sout_format.i_bitrate = 0;
185 p_sys->sout_format.i_extra_data = 0;
186 p_sys->sout_format.p_extra_data = NULL;
188 p_sys->i_headers = 0;
189 p_sys->p_state = NULL;
190 p_sys->p_header = NULL;
195 /****************************************************************************
196 * RunDecoder: the whole thing
197 ****************************************************************************
198 * This function must be fed with ogg packets.
199 ****************************************************************************/
200 static int RunDecoder( decoder_t *p_dec, block_t *p_block )
202 decoder_sys_t *p_sys = p_dec->p_sys;
203 ogg_packet oggpacket;
206 /* Block to Ogg packet */
207 oggpacket.packet = p_block->p_buffer;
208 oggpacket.bytes = p_block->i_buffer;
209 oggpacket.granulepos = -1;
212 oggpacket.packetno = 0;
214 if( p_sys->i_headers == 0 )
216 /* Take care of the initial Speex header */
217 if( ProcessHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
219 msg_Err( p_dec, "Initial Speex header is corrupted" );
225 if( p_sys->b_packetizer )
227 i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
228 block_Release( p_block );
233 block_Release( p_block );
238 if( p_sys->i_headers == 1 )
240 /* The next packet in order is the comments header */
241 ParseSpeexComments( p_dec, &oggpacket );
244 if( p_sys->b_packetizer )
246 i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
247 block_Release( p_block );
252 block_Release( p_block );
257 if( p_sys->i_headers < p_sys->p_header->extra_headers + 2 )
259 /* Skip them for now */
262 if( p_sys->b_packetizer )
264 i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
265 block_Release( p_block );
270 block_Release( p_block );
275 i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
276 block_Release( p_block );
280 /*****************************************************************************
281 * ProcessHeader: processes the inital Speex header packet.
282 *****************************************************************************/
283 static int ProcessHeader( decoder_t *p_dec, ogg_packet *p_oggpacket )
285 decoder_sys_t *p_sys = p_dec->p_sys;
288 SpeexHeader *p_header;
290 SpeexCallback callback;
292 p_sys->p_header = p_header =
293 speex_packet_to_header( p_oggpacket->packet, p_oggpacket->bytes );
296 msg_Err( p_dec, "Cannot read Speex header" );
299 if( p_header->mode >= SPEEX_NB_MODES )
301 msg_Err( p_dec, "Mode number %d does not (yet/any longer) exist in "
302 "this version of libspeex", p_header->mode );
306 p_mode = speex_mode_list[p_header->mode];
308 if( p_header->speex_version_id > 1 )
310 msg_Err( p_dec, "This file was encoded with Speex bit-stream "
311 "version %d, which I don't know how to decode",
312 p_header->speex_version_id );
316 if( p_mode->bitstream_version < p_header->mode_bitstream_version )
318 msg_Err( p_dec, "File encoded with a newer version of Speex" );
321 if( p_mode->bitstream_version > p_header->mode_bitstream_version )
323 msg_Err( p_dec, "File encoded with an older version of Speex" );
327 msg_Dbg( p_dec, "Speex %d Hz audio using %s mode %s%s",
328 p_header->rate, p_mode->modeName,
329 ( p_header->nb_channels == 1 ) ? " (mono" : " (stereo",
330 p_header->vbr ? ", VBR)" : ")" );
332 aout_DateInit( &p_sys->end_date, p_header->rate );
334 if( p_sys->b_packetizer )
336 /* add an input for the stream ouput */
337 p_sys->sout_format.i_sample_rate = p_header->rate;
338 p_sys->sout_format.i_channels = p_header->nb_channels;
339 p_sys->sout_format.i_block_align = 1;
340 p_sys->sout_format.i_bitrate = 0;
342 p_sys->p_sout_input = sout_InputNew( p_dec, &p_sys->sout_format );
343 if( !p_sys->p_sout_input )
345 msg_Err( p_dec, "cannot add a new stream" );
353 /* Take care of speex decoder init */
354 speex_bits_init( &p_sys->bits );
355 p_sys->p_state = p_state = speex_decoder_init( p_mode );
358 msg_Err( p_dec, "Decoder initialization failed" );
362 if( p_header->nb_channels == 1 )
364 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
365 p_sys->stereo = stereo;
366 callback.callback_id = SPEEX_INBAND_STEREO;
367 callback.func = speex_std_stereo_request_handler;
368 callback.data = &p_sys->stereo;
369 speex_decoder_ctl( p_state, SPEEX_SET_HANDLER, &callback );
372 p_sys->aout_format.i_format = AOUT_FMT_S16_NE;
373 p_sys->aout_format.i_physical_channels =
374 p_sys->aout_format.i_original_channels =
375 pi_channels_maps[p_header->nb_channels];
376 p_sys->aout_format.i_rate = p_header->rate;
378 p_sys->p_aout = NULL;
379 p_sys->p_aout_input = aout_DecNew( p_dec, &p_sys->p_aout,
380 &p_sys->aout_format );
381 if( p_sys->p_aout_input == NULL )
383 msg_Err( p_dec, "failed to create aout fifo" );
390 /*****************************************************************************
391 * ProcessPacket: processes a Speex packet.
392 *****************************************************************************/
393 static int ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
396 decoder_sys_t *p_sys = p_dec->p_sys;
398 /* Date management */
399 if( i_pts > 0 && i_pts != aout_DateGet( &p_sys->end_date ) )
401 aout_DateSet( &p_sys->end_date, i_pts );
404 if( !aout_DateGet( &p_sys->end_date ) )
406 /* We've just started the stream, wait for the first PTS. */
410 if( p_sys->b_packetizer )
412 return SendPacket( p_dec, p_oggpacket );
416 return DecodePacket( p_dec, p_oggpacket );
420 /*****************************************************************************
421 * DecodePacket: decodes a Speex packet.
422 *****************************************************************************/
423 static int DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
425 decoder_sys_t *p_sys = p_dec->p_sys;
428 /* Copy Ogg packet to Speex bitstream */
429 speex_bits_read_from( &p_sys->bits, p_oggpacket->packet,
430 p_oggpacket->bytes );
432 /* Decode each frame of the packet */
433 for( j = 0; j != p_sys->p_header->frames_per_packet; j++ )
435 aout_buffer_t *p_aout_buffer;
438 p_aout_buffer = aout_DecNewBuffer( p_sys->p_aout, p_sys->p_aout_input,
439 p_sys->p_header->frame_size );
442 msg_Err( p_dec, "cannot get aout buffer" );
446 i_ret = speex_decode( p_sys->p_state, &p_sys->bits,
447 (int16_t *)p_aout_buffer->p_buffer );
448 if( i_ret == -1 ) break; /* End of stream */
451 msg_Warn( p_dec, "Decoding error: corrupted stream?" );
455 if( speex_bits_remaining( &p_sys->bits ) < 0 )
457 msg_Warn( p_dec, "Decoding overflow: corrupted stream?" );
461 if( p_sys->p_header->nb_channels == 2 )
462 speex_decode_stereo( (int16_t *)p_aout_buffer->p_buffer,
463 p_sys->p_header->frame_size, &p_sys->stereo );
465 /* Date management */
466 p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
467 p_aout_buffer->end_date =
468 aout_DateIncrement( &p_sys->end_date, p_sys->p_header->frame_size);
470 aout_DecPlay( p_sys->p_aout, p_sys->p_aout_input, p_aout_buffer );
475 /*****************************************************************************
476 * SendPacket: send an ogg packet to the stream output.
477 *****************************************************************************/
478 static int SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
480 decoder_sys_t *p_sys = p_dec->p_sys;
482 sout_buffer_t *p_sout_buffer =
483 sout_BufferNew( p_sys->p_sout_input->p_sout, p_oggpacket->bytes );
485 if( !p_sout_buffer ) return VLC_EGENERIC;
487 p_dec->p_vlc->pf_memcpy( p_sout_buffer->p_buffer,
489 p_oggpacket->bytes );
491 p_sout_buffer->i_bitrate = 0;
493 /* Date management */
494 p_sout_buffer->i_dts = p_sout_buffer->i_pts =
495 aout_DateGet( &p_sys->end_date );
497 if( p_sys->i_headers >= p_sys->p_header->extra_headers + 2 )
498 p_sout_buffer->i_length =
499 aout_DateIncrement( &p_sys->end_date,
500 p_sys->p_header->frame_size ) -
501 p_sout_buffer->i_pts;
503 p_sout_buffer->i_length = 0;
505 sout_InputSendBuffer( p_sys->p_sout_input, p_sout_buffer );
510 /*****************************************************************************
511 * ParseSpeexComments: FIXME should be done in demuxer
512 *****************************************************************************/
513 #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
514 ((buf[base+2]<<16)&0xff0000)| \
515 ((buf[base+1]<<8)&0xff00)| \
518 static void ParseSpeexComments( decoder_t *p_dec, ogg_packet *p_oggpacket )
520 input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
521 decoder_sys_t *p_sys = p_dec->p_sys;
523 input_info_category_t *p_cat =
524 input_InfoCategory( p_input, _("Speex Comment") );
526 char *p_buf = (char *)p_oggpacket->packet;
530 p_mode = speex_mode_list[p_sys->p_header->mode];
531 input_AddInfo( p_cat, _("Mode"), "%s%s",
532 p_mode->modeName, p_sys->p_header->vbr ? " VBR" : "" );
534 if( p_oggpacket->bytes < 8 )
536 msg_Warn( p_dec, "Invalid/corrupted comments" );
540 i_len = readint( p_buf, 0 ); p_buf += 4;
541 if( i_len > p_oggpacket->bytes - 4 )
543 msg_Warn( p_dec, "Invalid/corrupted comments" );
547 input_AddInfo( p_cat, p_buf, "" );
549 /* TODO: finish comments parsing */
552 /*****************************************************************************
553 * EndDecoder: speex decoder destruction
554 *****************************************************************************/
555 static int EndDecoder( decoder_t * p_dec )
557 decoder_sys_t *p_sys = p_dec->p_sys;
559 if( p_sys->p_aout_input != NULL )
561 aout_DecDelete( p_sys->p_aout, p_sys->p_aout_input );
564 if( p_sys->p_sout_input != NULL )
566 sout_InputDelete( p_sys->p_sout_input );
571 speex_decoder_destroy( p_sys->p_state );
572 speex_bits_destroy( &p_sys->bits );
575 if( p_sys->p_header ) free( p_sys->p_header );