]> git.sesse.net Git - vlc/blobdiff - modules/codec/vorbis.c
* modules/gui/skins/src/*: oops, forgot to add a bunch of files.
[vlc] / modules / codec / vorbis.c
index e1fe7f4c319e31b9108283df6744d1e93eead7f2..84e4ea9d18a8168c8bf5a7b9032e1ba443735084 100644 (file)
@@ -2,7 +2,7 @@
  * 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
@@ -61,7 +65,8 @@ typedef struct dec_thread_t
     /*
      * 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
@@ -73,6 +78,17 @@ typedef struct dec_thread_t
 
 } 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
  *****************************************************************************/
@@ -81,16 +97,24 @@ static int  RunDecoder   ( decoder_fifo_t * );
 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();
 
@@ -128,13 +152,15 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
     }
 
     /* 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 :) */
@@ -148,7 +174,7 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
     /* 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 )
@@ -156,8 +182,35 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
         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 )
@@ -170,8 +223,14 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
     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 );
@@ -186,14 +245,6 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
         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) )
     {
@@ -212,14 +263,16 @@ static int RunDecoder( decoder_fifo_t * p_fifo )
     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;
 
 }
@@ -231,20 +284,28 @@ static void DecodePacket( dec_thread_t *p_dec )
 {
     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
@@ -264,8 +325,13 @@ static void DecodePacket( dec_thread_t *p_dec )
         }
 
         /* 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 );
@@ -275,16 +341,6 @@ static void DecodePacket( dec_thread_t *p_dec )
         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 );
     }
 
@@ -297,38 +353,43 @@ static void DecodePacket( dec_thread_t *p_dec )
  * 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];
         }
     }
 }
@@ -345,6 +406,8 @@ static void CloseDecoder( dec_thread_t * p_dec )
 
     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 );