* vorbis.c: vorbis decoder module making use of libvorbis.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
- * $Id: vorbis.c,v 1.1 2002/10/24 09:30:47 gbazin Exp $
+ * $Id: vorbis.c,v 1.16 2003/03/30 18:14:36 gbazin Exp $
*
* Authors: Gildas Bazin <gbazin@netcourrier.com>
*
#include <vlc/input.h>
#include <ogg/ogg.h>
+#ifdef MODULE_NAME_IS_tremor
+#include <tremor/ivorbiscodec.h>
+#else
#include <vorbis/codec.h>
+#endif
/*****************************************************************************
* dec_thread_t : vorbis decoder thread descriptor
/*
* Input properties
*/
- decoder_fifo_t * p_fifo; /* stores the PES stream data */
+ decoder_fifo_t *p_fifo; /* stores the PES stream data */
+ pes_packet_t *p_pes; /* current PES we are decoding */
/*
* Output properties
} dec_thread_t;
+static int pi_channels_maps[6] =
+{
+ 0,
+ AOUT_CHAN_CENTER, AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+ AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
+ | AOUT_CHAN_REARRIGHT,
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
+ | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static void CloseDecoder ( dec_thread_t * );
static void DecodePacket ( dec_thread_t * );
-static int GetOggPacket ( dec_thread_t *, ogg_packet *, mtime_t *, int );
+static int GetOggPacket ( dec_thread_t *, ogg_packet *, mtime_t * );
+#ifdef MODULE_NAME_IS_tremor
+static void Interleave ( int32_t *, const int32_t **, int, int );
+#else
static void Interleave ( float *, const float **, int, int );
+#endif
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
- set_description( _("Vorbis decoder module") );
+ set_description( _("Vorbis audio decoder") );
+#ifdef MODULE_NAME_IS_tremor
+ set_capability( "decoder", 90 );
+#else
set_capability( "decoder", 100 );
+#endif
set_callbacks( OpenDecoder, NULL );
vlc_module_end();
}
/* Initialize the thread properties */
+ memset( p_dec, 0, sizeof(dec_thread_t) );
p_dec->p_fifo = p_fifo;
+ p_dec->p_pes = NULL;
/* Take care of the initial Vorbis header */
vorbis_info_init( &p_dec->vi );
vorbis_comment_init( &p_dec->vc );
- if( GetOggPacket( p_dec, &oggpacket, &i_pts, 0 ) != VLC_SUCCESS )
+ if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
goto error;
oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
/* The next two packets in order are the comment and codebook headers.
We need to watch out that these packets are not missing as a
missing or corrupted header is fatal. */
- if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+ if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
goto error;
if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
msg_Err( p_dec->p_fifo, "2nd Vorbis header is corrupted" );
goto error;
}
-
- if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+ /* parse the vorbis comment. FIXME should be done in demuxer*/
+ {
+ input_thread_t *p_input = (input_thread_t *)p_fifo->p_parent;
+ input_info_category_t *p_cat = input_InfoCategory( p_input,
+ _("Vorbis Comment") );
+ int i = 0;
+ char *psz_name, *psz_value, *psz_comment;
+ while ( i < p_dec->vc.comments )
+ {
+ psz_comment = strdup( p_dec->vc.user_comments[i] );
+ if ( !psz_comment )
+ {
+ msg_Warn( p_dec->p_fifo, "Out of memory" );
+ break;
+ }
+ psz_name = psz_comment;
+ psz_value = strchr( psz_comment, '=' );
+ if( psz_value )
+ {
+ *psz_value = '\0';
+ psz_value++;
+ input_AddInfo( p_cat, psz_name, psz_value );
+ }
+ free( psz_comment );
+ i++;
+ }
+ }
+
+ if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
goto error;
if( vorbis_synthesis_headerin( &p_dec->vi, &p_dec->vc, &oggpacket ) < 0 )
vorbis_synthesis_init( &p_dec->vd, &p_dec->vi );
vorbis_block_init( &p_dec->vd, &p_dec->vb );
+#ifdef MODULE_NAME_IS_tremor
+ p_dec->output_format.i_format = VLC_FOURCC('f','i','3','2');
+#else
p_dec->output_format.i_format = VLC_FOURCC('f','l','3','2');
- p_dec->output_format.i_channels = p_dec->vi.channels;
+#endif
+ p_dec->output_format.i_physical_channels =
+ p_dec->output_format.i_original_channels =
+ pi_channels_maps[p_dec->vi.channels];
p_dec->output_format.i_rate = p_dec->vi.rate;
aout_DateInit( &p_dec->end_date, p_dec->vi.rate );
goto error;
}
- /* Take care of the first pts we receive. We need to be careful as a pts
- * in vorbis language does in fact correspond to the presentation time of
- * the _next_ packet to receive */
- if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
- {
- aout_DateSet( &p_dec->end_date, i_pts );
- }
-
/* vorbis decoder thread's main loop */
while( (!p_dec->p_fifo->b_die) && (!p_dec->p_fifo->b_error) )
{
return 0;
error:
+ DecoderError( p_fifo );
if( p_dec )
{
if( p_dec->p_fifo )
p_dec->p_fifo->b_error = 1;
- free( p_dec );
+
+ /* End of the vorbis decoder thread */
+ CloseDecoder( p_dec );
}
- DecoderError( p_fifo );
return -1;
}
{
aout_buffer_t *p_aout_buffer;
ogg_packet oggpacket;
+#ifdef MODULE_NAME_IS_tremor
+ int32_t **pp_pcm;
+#else
float **pp_pcm;
+#endif
int i_samples;
mtime_t i_pts;
- if( GetOggPacket( p_dec, &oggpacket, &i_pts, 1 ) != VLC_SUCCESS )
+ if( GetOggPacket( p_dec, &oggpacket, &i_pts ) != VLC_SUCCESS )
{
/* This should mean an eos */
return;
}
+ /* Date management */
+ if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
+ {
+ aout_DateSet( &p_dec->end_date, i_pts );
+ }
+
if( vorbis_synthesis( &p_dec->vb, &oggpacket ) == 0 )
vorbis_synthesis_blockin( &p_dec->vd, &p_dec->vb );
- else
- msg_Err( p_dec->p_fifo, "vorbis_synthesis error" );
/* **pp_pcm is a multichannel float vector. In stereo, for
* example, pp_pcm[0] is left, and pp_pcm[1] is right. i_samples is
}
/* Interleave the samples */
- Interleave( (float *)p_aout_buffer->p_buffer, (const float **)pp_pcm,
- p_dec->vi.channels, i_samples );
+#ifdef MODULE_NAME_IS_tremor
+ Interleave( (int32_t *)p_aout_buffer->p_buffer,
+ (const int32_t **)pp_pcm, p_dec->vi.channels, i_samples );
+#else
+ Interleave( (float *)p_aout_buffer->p_buffer,
+ (const float **)pp_pcm, p_dec->vi.channels, i_samples );
+#endif
/* Tell libvorbis how many samples we actually consumed */
vorbis_synthesis_read( &p_dec->vd, i_samples );
p_aout_buffer->end_date = aout_DateIncrement( &p_dec->end_date,
i_samples );
- if( i_pts > 0 && i_pts != aout_DateGet( &p_dec->end_date ) )
- {
- aout_DateSet( &p_dec->end_date, i_pts );
- p_aout_buffer->end_date = aout_DateGet( &p_dec->end_date );
- }
- else
- {
- aout_DateSet( &p_dec->end_date, p_aout_buffer->end_date );
- }
-
aout_DecPlay( p_dec->p_aout, p_dec->p_aout_input, p_aout_buffer );
}
* Returns VLC_EGENERIC in case of eof.
*****************************************************************************/
static int GetOggPacket( dec_thread_t *p_dec, ogg_packet *p_oggpacket,
- mtime_t *p_pts, int b_next )
+ mtime_t *p_pts )
{
- pes_packet_t *p_pes;
+ if( p_dec->p_pes ) input_DeletePES( p_dec->p_fifo->p_packets_mgt,
+ p_dec->p_pes );
- if( b_next ) NextPES( p_dec->p_fifo );
- p_pes = GetPES( p_dec->p_fifo );
+ input_ExtractPES( p_dec->p_fifo, &p_dec->p_pes );
+ if( !p_dec->p_pes ) return VLC_EGENERIC;
- p_oggpacket->packet = p_pes->p_first->p_payload_start;
- p_oggpacket->bytes = p_pes->i_pes_size;
- p_oggpacket->granulepos = p_pes->i_dts;
+ p_oggpacket->packet = p_dec->p_pes->p_first->p_payload_start;
+ p_oggpacket->bytes = p_dec->p_pes->i_pes_size;
+ p_oggpacket->granulepos = p_dec->p_pes->i_dts;
p_oggpacket->b_o_s = 0;
p_oggpacket->e_o_s = 0;
p_oggpacket->packetno = 0;
- *p_pts = p_pes->i_pts;
+ *p_pts = p_dec->p_pes->i_pts;
- return p_pes ? VLC_SUCCESS : VLC_EGENERIC;
+ return VLC_SUCCESS;
}
/*****************************************************************************
* Interleave: helper function to interleave channels
*****************************************************************************/
-static void Interleave( float *p_out, const float **pp_in, int i_channels,
- int i_samples )
+#ifdef MODULE_NAME_IS_tremor
+static void Interleave( int32_t *p_out, const int32_t **pp_in,
+#else
+static void Interleave( float *p_out, const float **pp_in,
+#endif
+ int i_nb_channels, int i_samples )
{
int i, j;
for ( j = 0; j < i_samples; j++ )
{
- for ( i = 0; i < i_channels; i++ )
+ for ( i = 0; i < i_nb_channels; i++ )
{
- p_out[j * i_channels + i] = pp_in[i][j];
+ p_out[j * i_nb_channels + i] = pp_in[i][j];
}
}
}
if( p_dec )
{
+ if( p_dec->p_pes )
+ input_DeletePES( p_dec->p_fifo->p_packets_mgt, p_dec->p_pes );
vorbis_block_clear( &p_dec->vb );
vorbis_dsp_clear( &p_dec->vd );
vorbis_comment_clear( &p_dec->vc );