* modules/packetizer/vorbis.c: vorbis data packetizer for the stream output.
authorGildas Bazin <gbazin@videolan.org>
Mon, 23 Jun 2003 23:51:31 +0000 (23:51 +0000)
committerGildas Bazin <gbazin@videolan.org>
Mon, 23 Jun 2003 23:51:31 +0000 (23:51 +0000)
* modules/mux/ogg.c: cleanup, bug fixes and vorbis support.
* modules/demux/ogg.c: added vorbis channels info.
* modules/misc/httpd.c: bug fix for stream header generation.

configure.ac
modules/demux/ogg.c
modules/misc/httpd.c
modules/mux/ogg.c
modules/packetizer/Modules.am
modules/packetizer/vorbis.c [new file with mode: 0644]

index 6b38a01..9de0d9d 100644 (file)
@@ -1008,12 +1008,7 @@ then
   PLUGINS="${PLUGINS} stream_out_dummy stream_out_standard stream_out_es"
   PLUGINS="${PLUGINS} stream_out_duplicate stream_out_display"
 
-    dnl Ogg/ogm
-    AC_CHECK_HEADERS(ogg/ogg.h, [
-      AC_CHECK_LIB( ogg, ogg_stream_packetin, [
-        PLUGINS="${PLUGINS} mux_ogg"
-        LDFLAGS_mux_ogg="${LDFLAGS_mux_ogg} -logg" ])
-    ],[])
+  dnl Ogg and vorbis are handled in their respective section
 fi
 
 
@@ -1425,7 +1420,9 @@ then
       PLUGINS="${PLUGINS} ogg"
       LDFLAGS_ogg="${LDFLAGS_ogg} -logg"
       AC_CHECK_LIB( ogg, oggpackB_read, [
-        CPPFLAGS_ogg="${CPPFLAGS_ogg} -DHAVE_OGGPACKB"])])
+        CPPFLAGS_ogg="${CPPFLAGS_ogg} -DHAVE_OGGPACKB"])
+      PLUGINS="${PLUGINS} mux_ogg"
+      LDFLAGS_mux_ogg="${LDFLAGS_mux_ogg} -logg"])
    ],[])
 fi
 
@@ -1889,7 +1886,10 @@ then
   AC_CHECK_HEADERS(vorbis/codec.h, [
     PLUGINS="${PLUGINS} vorbis"
     LDFLAGS_vorbis="${LDFLAGS_vorbis} -lvorbis -logg"
-   ],[])
+    if test "${enable_sout}" != "no"; then
+      PLUGINS="${PLUGINS} packetizer_vorbis"
+      LDFLAGS_packetizer_vorbis="${LDFLAGS_packetizer_vorbis} -lvorbis -logg"
+    fi ],[])
 fi
 
 dnl
index d9d7f0e..1124e35 100644 (file)
@@ -2,7 +2,7 @@
  * ogg.c : ogg stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: ogg.c,v 1.26 2003/06/11 15:53:50 gbazin Exp $
+ * $Id: ogg.c,v 1.27 2003/06/23 23:51:31 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  * 
@@ -70,6 +70,7 @@ typedef struct logical_stream_s
     /* info from logical streams */
     double f_rate;
     int i_bitrate;
+    int i_channels;
     int b_reinit;
 
     /* codec specific stuff */
@@ -543,7 +544,8 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
 
                     /* Cheat and get additionnal info ;) */
                     oggpack_readinit( &opb, oggpacket.packet, oggpacket.bytes);
-                    oggpack_adv( &opb, 96 );
+                    oggpack_adv( &opb, 88 );
+                    p_stream->i_channels = oggpack_read( &opb, 8 );
                     p_stream->f_rate = oggpack_read( &opb, 32 );
                     oggpack_adv( &opb, 32 );
                     p_stream->i_bitrate = oggpack_read( &opb, 32 );
@@ -556,6 +558,8 @@ static int Ogg_FindLogicalStreams( input_thread_t *p_input, demux_sys_t *p_ogg)
                         input_AddInfo( p_cat, _("Codec"), _("Vorbis") );
                         input_AddInfo( p_cat, _("Sample Rate"), "%f",
                                        p_stream->f_rate );
+                        input_AddInfo( p_cat, _("Channels"), "%d",
+                                       p_stream->i_channels );
                         input_AddInfo( p_cat, _("Bit Rate"), "%d",
                                        p_stream->i_bitrate );
                     }
index 4a3bd93..8e51938 100644 (file)
@@ -2,7 +2,7 @@
  * httpd.c
  *****************************************************************************
  * Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.c,v 1.14 2003/05/09 16:01:17 gbazin Exp $
+ * $Id: httpd.c,v 1.15 2003/06/23 23:51:31 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
@@ -1612,14 +1612,15 @@ search_file:
 
     p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
 
+    p_con->i_buffer_size = 4096;
+    p_con->i_buffer = 0;
+
     /* we send stream header with this one */
     if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
     {
-        p_con->i_buffer_size = 4096 + p_con->p_file->i_header_size;
+        p_con->i_buffer_size += p_con->p_file->i_header_size;
     }
 
-    p_con->i_buffer_size = 4096;
-    p_con->i_buffer = 0;
     p = p_con->p_buffer = malloc( p_con->i_buffer_size );
 
     p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
@@ -1633,7 +1634,8 @@ search_file:
 
     p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
 
-    if( p_con->i_http_error == 200 && p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
+    if( p_con->i_http_error == 200 && p_con->p_file->b_stream &&
+        p_con->p_file->i_header_size > 0 )
     {
         /* add stream header */
         memcpy( &p_con->p_buffer[p_con->i_buffer_size],
index ca48bbd..b398397 100644 (file)
@@ -2,9 +2,10 @@
  * ogg.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ogg.c,v 1.5 2003/04/13 20:00:21 fenrir Exp $
+ * $Id: ogg.c,v 1.6 2003/06/23 23:51:31 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Gildas Bazin <gbazin@netcourrier.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -152,7 +153,8 @@ static void _SetQWLE( uint8_t *p, uint64_t i_qw )
 }
 
 static void OggSetDate( sout_buffer_t *, mtime_t , mtime_t  );
-static sout_buffer_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, mtime_t );
+static sout_buffer_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *,
+                                      mtime_t );
 
 /*****************************************************************************
  * Open:
@@ -192,7 +194,8 @@ static void Close( vlc_object_t * p_this )
     free( p_sys );
 }
 
-static int Capability( sout_mux_t *p_mux, int i_query, void *p_args, void *p_answer )
+static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
+                       void *p_answer )
 {
    switch( i_query )
    {
@@ -219,75 +222,87 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
     p_stream->header.i_packet_type = PACKET_TYPE_HEADER;
     switch( p_input->p_fmt->i_cat )
     {
-        case VIDEO_ES:
-            switch( p_input->p_fmt->i_fourcc )
+    case VIDEO_ES:
+        switch( p_input->p_fmt->i_fourcc )
+        {
+        case VLC_FOURCC( 'm', 'p','4', 'v' ):
+        case VLC_FOURCC( 'D', 'I','V', '3' ):
+            memcpy( p_stream->header.stream_type, "video    ", 8 );
+            if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) )
+            {
+                memcpy( p_stream->header.sub_type, "XVID", 4 );
+            }
+            else if( p_input->p_fmt->i_fourcc ==
+                     VLC_FOURCC( 'D', 'I','V', '3' ) )
             {
-                case VLC_FOURCC( 'm', 'p','4', 'v' ):
-                case VLC_FOURCC( 'D', 'I','V', '3' ):
-                    memcpy( p_stream->header.stream_type,
-                            "video    ",
-                            8 );
-                    if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) )
-                    {
-                        memcpy( p_stream->header.sub_type, "XVID", 4 );
-                    }
-                    else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) )
-                    {
-                        memcpy( p_stream->header.sub_type, "DIV3", 4 );
-                    }
-                    SetDWLE( &p_stream->header.i_size, sizeof( ogg_stream_header_t ) - 1);
-                    /* XXX this won't make mplayer happy, but vlc can read that without any problem so...*/
-                    SetQWLE( &p_stream->header.i_time_unit, 10*1000 );//(int64_t)10*1000*1000/(int64_t)25 );  // FIXME (25fps)
-                    SetQWLE( &p_stream->header.i_samples_per_unit, 1 );
-                    SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
-                    SetDWLE( &p_stream->header.i_buffer_size, 1024*1024 );
-                    SetWLE( &p_stream->header.i_bits_per_sample, 0 );
-                    SetDWLE( &p_stream->header.header.video.i_width,  p_input->p_fmt->i_width );
-                    SetDWLE( &p_stream->header.header.video.i_height, p_input->p_fmt->i_height );
-                    break;
-                default:
-                    FREE( p_input->p_sys );
-                    return( VLC_EGENERIC );
+                memcpy( p_stream->header.sub_type, "DIV3", 4 );
             }
+            SetDWLE( &p_stream->header.i_size,
+                     sizeof( ogg_stream_header_t ) - 1);
+            /* XXX this won't make mplayer happy,
+             * but vlc can read that without any problem so...*/
+            SetQWLE( &p_stream->header.i_time_unit, 10*1000 );
+            //(int64_t)10*1000*1000/(int64_t)25 );  // FIXME (25fps)
+            SetQWLE( &p_stream->header.i_samples_per_unit, 1 );
+            SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
+            SetDWLE( &p_stream->header.i_buffer_size, 1024*1024 );
+            SetWLE( &p_stream->header.i_bits_per_sample, 0 );
+            SetDWLE( &p_stream->header.header.video.i_width,
+                     p_input->p_fmt->i_width );
+            SetDWLE( &p_stream->header.header.video.i_height,
+                     p_input->p_fmt->i_height );
             break;
-        case AUDIO_ES:
-            switch( p_input->p_fmt->i_fourcc )
+
+        default:
+            FREE( p_input->p_sys );
+            return( VLC_EGENERIC );
+        }
+        break;
+    case AUDIO_ES:
+        switch( p_input->p_fmt->i_fourcc )
+        {
+        case VLC_FOURCC( 'm', 'p','g', 'a' ):
+        case VLC_FOURCC( 'a', '5','2', ' ' ):
+            memcpy( p_stream->header.stream_type, "audio    ", 8 );
+            if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) )
+            {
+                memcpy( p_stream->header.sub_type, "55  ", 4 );
+            }
+            else if( p_input->p_fmt->i_fourcc ==
+                     VLC_FOURCC( 'a', '5','2', ' ' ) )
             {
-                case VLC_FOURCC( 'm', 'p','g', 'a' ):
-                case VLC_FOURCC( 'a', '5','2', ' ' ):
-                    memcpy( p_stream->header.stream_type,
-                            "audio    ",
-                            8 );
-                    if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) )
-                    {
-                        memcpy( p_stream->header.sub_type, "55  ", 4 );
-                    }
-                    else if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) )
-                    {
-                        memcpy( p_stream->header.sub_type, "2000", 4 );
-                    }
-                    SetDWLE( &p_stream->header.i_size, sizeof( ogg_stream_header_t ) - 1);
-                    SetQWLE( &p_stream->header.i_time_unit, 1000000 );  /* is it used ? */
-                    SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
-                    SetDWLE( &p_stream->header.i_buffer_size, 30*1024 );
-                    SetQWLE( &p_stream->header.i_samples_per_unit, p_input->p_fmt->i_sample_rate );
-                    SetWLE( &p_stream->header.i_bits_per_sample, 0 );
-                    SetDWLE( &p_stream->header.header.audio.i_channels, p_input->p_fmt->i_channels );
-                    SetDWLE( &p_stream->header.header.audio.i_block_align, p_input->p_fmt->i_block_align );
-                    SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 );
-                    break;
-                case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
-                default:
-                    FREE( p_input->p_sys );
-                    return( VLC_EGENERIC );
+                memcpy( p_stream->header.sub_type, "2000", 4 );
             }
+            SetDWLE( &p_stream->header.i_size,
+                     sizeof( ogg_stream_header_t ) - 1);
+            SetQWLE( &p_stream->header.i_time_unit, 1000000 );  /* is it used ? */
+            SetDWLE( &p_stream->header.i_default_len, 0 );      /* ??? */
+            SetDWLE( &p_stream->header.i_buffer_size, 30*1024 );
+            SetQWLE( &p_stream->header.i_samples_per_unit,
+                     p_input->p_fmt->i_sample_rate );
+            SetWLE( &p_stream->header.i_bits_per_sample, 0 );
+            SetDWLE( &p_stream->header.header.audio.i_channels,
+                     p_input->p_fmt->i_channels );
+            SetDWLE( &p_stream->header.header.audio.i_block_align,
+                     p_input->p_fmt->i_block_align );
+            SetDWLE( &p_stream->header.header.audio.i_avgbytespersec, 0 );
             break;
+
+        case VLC_FOURCC( 'v', 'o', 'r', 'b' ):
+          msg_Dbg( p_mux, "vorbis stream" );
+          break;
         default:
             FREE( p_input->p_sys );
             return( VLC_EGENERIC );
+        }
+        break;
+
+    default:
+        FREE( p_input->p_sys );
+        return( VLC_EGENERIC );
     }
 
-    ogg_stream_init (&p_stream->os, rand ());
+    ogg_stream_init( &p_stream->os, rand () );
 
     p_sys->i_streams++;
     return( VLC_SUCCESS );
@@ -322,9 +337,7 @@ static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
 /*
  * TODO  move this function to src/stream_output.c (used by nearly all muxers)
  */
-static int MuxGetStream( sout_mux_t *p_mux,
-                         int        *pi_stream,
-                         mtime_t    *pi_dts )
+static int MuxGetStream( sout_mux_t *p_mux, int *pi_stream, mtime_t *pi_dts )
 {
     mtime_t i_dts;
     int     i_stream;
@@ -363,13 +376,11 @@ static int MuxGetStream( sout_mux_t *p_mux,
     return( i_stream );
 }
 
-
 static sout_buffer_t *OggStreamFlush( sout_mux_t *p_mux,
-                                      ogg_stream_state *p_os,
-                                      mtime_t i_pts )
+                                      ogg_stream_state *p_os, mtime_t i_pts )
 {
-    sout_buffer_t       *p_og, *p_og_first = NULL;
-    ogg_page            og;
+    sout_buffer_t *p_og, *p_og_first = NULL;
+    ogg_page      og;
 
     for( ;; )
     {
@@ -383,12 +394,8 @@ static sout_buffer_t *OggStreamFlush( sout_mux_t *p_mux,
         i_size = og.header_len + og.body_len;
         p_og = sout_BufferNew( p_mux->p_sout, i_size);
 
-        memcpy( p_og->p_buffer,
-                og.header,
-                og.header_len );
-        memcpy( p_og->p_buffer + og.header_len,
-                og.body,
-                og.body_len );
+        memcpy( p_og->p_buffer, og.header, og.header_len );
+        memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
         p_og->i_size    = i_size;
         p_og->i_dts     = 0;
         p_og->i_pts     = i_pts;
@@ -401,12 +408,12 @@ static sout_buffer_t *OggStreamFlush( sout_mux_t *p_mux,
 
     return( p_og_first );
 }
+
 static sout_buffer_t *OggStreamPageOut( sout_mux_t *p_mux,
-                                        ogg_stream_state *p_os,
-                                        mtime_t i_pts )
+                                        ogg_stream_state *p_os, mtime_t i_pts )
 {
-    sout_buffer_t       *p_og, *p_og_first = NULL;
-    ogg_page            og;
+    sout_buffer_t *p_og, *p_og_first = NULL;
+    ogg_page      og;
 
     for( ;; )
     {
@@ -420,12 +427,8 @@ static sout_buffer_t *OggStreamPageOut( sout_mux_t *p_mux,
         i_size = og.header_len + og.body_len;
         p_og = sout_BufferNew( p_mux->p_sout, i_size);
 
-        memcpy( p_og->p_buffer,
-                og.header,
-                og.header_len );
-        memcpy( p_og->p_buffer + og.header_len,
-                og.body,
-                og.body_len );
+        memcpy( p_og->p_buffer, og.header, og.header_len );
+        memcpy( p_og->p_buffer + og.header_len, og.body, og.body_len );
         p_og->i_size    = i_size;
         p_og->i_dts     = 0;
         p_og->i_pts     = i_pts;
@@ -438,6 +441,7 @@ static sout_buffer_t *OggStreamPageOut( sout_mux_t *p_mux,
 
     return( p_og_first );
 }
+
 static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
 {
     sout_buffer_t *p_hdr = NULL;
@@ -445,7 +449,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
     ogg_packet    op;
     int i;
 
-    /* write header for each stream */
+    /* Write header for each stream. All b_o_s (beginning of stream) packets
+     * must appear first in the ogg stream so we take care of them first. */
     for( i = 0; i < p_mux->i_nb_inputs; i++ )
     {
         ogg_stream_t *p_stream;
@@ -454,17 +459,22 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
 
         if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
         {
-            /* special case */
+            /* Special case, headers are already there in the
+             * incoming stream */
+
+            /* first packet in order: vorbis info */
+            p_og = sout_FifoGet( p_mux->pp_inputs[i]->p_fifo );
+            op.packet = p_og->p_buffer;
+            op.bytes  = p_og->i_size;
+            op.b_o_s  = 1;
+            op.e_o_s  = 0;
+            op.granulepos = 0;
+            op.packetno = p_stream->i_packet_no++;
+            ogg_stream_packetin( &p_stream->os, &op );
         }
         else
         {
             /* ds header */
-#if 0
-            uint8_t com[128];
-            int     i_com;
-#endif
-
-            /* header */
             op.packet = (uint8_t*)&p_stream->header;
             op.bytes  = sizeof( ogg_stream_t );
             op.b_o_s  = 1;
@@ -472,8 +482,42 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
             op.granulepos = 0;
             op.packetno = p_stream->i_packet_no++;
             ogg_stream_packetin( &p_stream->os, &op );
-#if 0
-            /* I don't know why but this produce broken file */
+        }
+
+        p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
+        sout_BufferChain( &p_hdr, p_og );
+    }
+
+    /* Take care of the non b_o_s headers */
+    for( i = 0; i < p_mux->i_nb_inputs; i++ )
+    {
+        ogg_stream_t *p_stream;
+
+        p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
+
+        if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
+        {
+            /* Special case, headers are already there in the incoming stream.
+             * We need to gather them an mark them as headers. */
+            int j;
+            for( j = 0; j < 2; j++ )
+            {
+                /* next packets in order: comments and codebooks */
+                p_og = sout_FifoGet( p_mux->pp_inputs[i]->p_fifo );
+                op.packet = p_og->p_buffer;
+                op.bytes  = p_og->i_size;
+                op.b_o_s  = 0;
+                op.e_o_s  = 0;
+                op.granulepos = 0;
+                op.packetno = p_stream->i_packet_no++;
+                ogg_stream_packetin( &p_stream->os, &op );
+            }
+        }
+        else
+        {
+            uint8_t com[128];
+            int     i_com;
+
             /* comment */
             com[0] = PACKET_TYPE_COMMENT;
             i_com = snprintf( &com[1], 128, "VLC 0.5.x stream output" ) + 1;
@@ -484,7 +528,6 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
             op.granulepos = 0;
             op.packetno = p_stream->i_packet_no++;
             ogg_stream_packetin( &p_stream->os, &op );
-#endif
         }
 
         p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
@@ -499,7 +542,6 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
     return( p_hdr );
 }
 
-
 static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length )
 {
     int i_count;
@@ -521,11 +563,11 @@ static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length )
     }
 }
 
-static int Mux      ( sout_mux_t *p_mux )
+static int Mux( sout_mux_t *p_mux )
 {
     sout_mux_sys_t      *p_sys  = p_mux->p_sys;
     sout_buffer_t       *p_og = NULL;
-    int i_stream;
+    int                 i_stream;
     mtime_t             i_dts;
 
     if( p_sys->b_write_header )
@@ -556,35 +598,50 @@ static int Mux      ( sout_mux_t *p_mux )
         }
         //msg_Dbg( p_mux, "doing job" );
 
+        if( p_sys->i_start_dts <= 0 ) p_sys->i_start_dts = i_dts;
+
         p_input  = p_mux->pp_inputs[i_stream];
         p_stream = (ogg_stream_t*)p_input->p_sys;
 
         p_data  = sout_FifoGet( p_input->p_fifo );
 
-        sout_BufferReallocFromPreHeader( p_mux->p_sout, p_data, 1 );
-        p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
+        if( p_stream->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
+        {
+            sout_BufferReallocFromPreHeader( p_mux->p_sout, p_data, 1 );
+            p_data->p_buffer[0] = PACKET_IS_SYNCPOINT;      // FIXME
+        }
+
+        op.packet   = p_data->p_buffer;
+        op.bytes    = p_data->i_size;
+        op.b_o_s    = 0;
+        op.e_o_s    = 0;
+        op.packetno = p_stream->i_packet_no++;
 
-        op.packet = p_data->p_buffer;
-        op.bytes  = p_data->i_size;
-        op.b_o_s  = 0;
-        op.e_o_s  = 0;
         if( p_stream->i_cat == AUDIO_ES )
         {
-            /* number of sample from begining */
-            op.granulepos = ( i_dts - p_sys->i_start_dts ) *
-                                p_stream->header.i_samples_per_unit / (int64_t)1000000;
+            if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
+            {
+                /* number of sample from begining + current packet */
+                op.granulepos =
+                    ( i_dts + p_data->i_length - p_sys->i_start_dts ) *
+                    p_input->p_fmt->i_sample_rate / (int64_t)1000000;
+            }
+            else
+            {
+                /* number of sample from begining */
+                op.granulepos = ( i_dts - p_sys->i_start_dts ) *
+                    p_stream->header.i_samples_per_unit / (int64_t)1000000;
+            }
         }
         else if( p_stream->i_cat == VIDEO_ES )
         {
-            op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;//p_stream->i_packet_no;
+            op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
         }
-        op.packetno = p_stream->i_packet_no++;
+
         ogg_stream_packetin( &p_stream->os, &op );
 
-        sout_BufferChain( &p_og,
-                          OggStreamPageOut( p_mux,
-                                            &p_stream->os,
-                                            p_data->i_dts ) );
+        sout_BufferChain( &p_og, OggStreamPageOut( p_mux, &p_stream->os,
+                                                   p_data->i_dts ) );
 
         if( p_og )
         {
@@ -611,4 +668,3 @@ static int Mux      ( sout_mux_t *p_mux )
 
     return( VLC_SUCCESS );
 }
-
index f087c48..21bb27f 100644 (file)
@@ -4,3 +4,4 @@ SOURCES_packetizer_mpegaudio = modules/packetizer/mpegaudio.c
 SOURCES_packetizer_mpegvideo = modules/packetizer/mpegvideo.c
 SOURCES_packetizer_mpeg4video = modules/packetizer/mpeg4video.c
 SOURCES_packetizer_mpeg4audio = modules/packetizer/mpeg4audio.c
+SOURCES_packetizer_vorbis = modules/packetizer/vorbis.c
diff --git a/modules/packetizer/vorbis.c b/modules/packetizer/vorbis.c
new file mode 100644 (file)
index 0000000..efca225
--- /dev/null
@@ -0,0 +1,376 @@
+/*****************************************************************************
+ * vorbis.c Vorbis audio packetizer
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: vorbis.c,v 1.1 2003/06/23 23:51:31 gbazin Exp $
+ *
+ * Authors: Gildas Bazin <gbazin@netcourrier.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <vlc/vlc.h>
+#include <vlc/aout.h>
+#include <vlc/decoder.h>
+#include <vlc/input.h>
+#include <vlc/sout.h>
+
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include "codecs.h"                         /* WAVEFORMATEX BITMAPINFOHEADER */
+
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+typedef struct packetizer_s
+{
+    /*
+     * Input properties
+     */
+    decoder_fifo_t         *p_fifo;            /* stores the PES stream data */
+    pes_packet_t           *p_pes;            /* current PES we are decoding */
+
+    /* Output properties */
+    sout_packetizer_input_t *p_sout_input;
+    sout_format_t           output_format;
+
+    /*
+     * Vorbis properties
+     */
+    vorbis_info      vi; /* struct that stores all the static vorbis bitstream
+                            settings */
+    vorbis_comment   vc; /* struct that stores all the bitstream user
+                          * comments */
+    vorbis_dsp_state vd; /* central working state for the packet->PCM
+                          * decoder */
+    vorbis_block     vb; /* local working space for packet->PCM decode */
+
+    uint64_t                i_samplescount;
+
+    mtime_t                 i_interpolated_pts;
+    int                     i_last_block_size;
+
+} packetizer_t;
+
+static int  Open    ( vlc_object_t * );
+static int  Run     ( decoder_fifo_t * );
+
+static int  InitThread     ( packetizer_t * );
+static void PacketizeThread   ( packetizer_t * );
+static void EndThread      ( packetizer_t * );
+
+static int GetOggPacket( packetizer_t *, ogg_packet *, mtime_t * );
+static int SendOggPacket( packetizer_t *, ogg_packet *, mtime_t, int );
+
+#define FREE( p ) if( p ) free( p ); p = NULL
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("Vorbis audio packetizer") );
+    set_capability( "packetizer", 50 );
+    set_callbacks( Open, NULL );
+vlc_module_end();
+
+/*****************************************************************************
+ * OpenDecoder: probe the packetizer and return score
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
+
+    if( p_fifo->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b') )
+    {
+        return VLC_EGENERIC;
+    }
+
+    p_fifo->pf_run = Run;
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * RunDecoder: this function is called just after the thread is created
+ *****************************************************************************/
+static int Run( decoder_fifo_t *p_fifo )
+{
+    packetizer_t *p_pack;
+    int b_error;
+
+    msg_Info( p_fifo, "Running vorbis packetizer" );
+    if( !( p_pack = malloc( sizeof( packetizer_t ) ) ) )
+    {
+        msg_Err( p_fifo, "out of memory" );
+        DecoderError( p_fifo );
+        return -1;
+    }
+    memset( p_pack, 0, sizeof( packetizer_t ) );
+
+    p_pack->p_fifo = p_fifo;
+
+    if( InitThread( p_pack ) != 0 )
+    {
+        DecoderError( p_fifo );
+        return -1;
+    }
+
+    while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) )
+    {
+        PacketizeThread( p_pack );
+    }
+
+
+    if( ( b_error = p_pack->p_fifo->b_error ) )
+    {
+        DecoderError( p_pack->p_fifo );
+    }
+
+    EndThread( p_pack );
+
+    FREE( p_pack );
+
+    if( b_error )
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+/*****************************************************************************
+ * InitThread: initialize data before entering main loop
+ *****************************************************************************/
+static int InitThread( packetizer_t *p_pack )
+{ 
+    mtime_t    i_pts;
+    ogg_packet oggpacket;
+
+    p_pack->output_format.i_cat = AUDIO_ES;
+    p_pack->output_format.i_fourcc = p_pack->p_fifo->i_fourcc;
+    p_pack->output_format.i_sample_rate = 0;
+    p_pack->output_format.i_channels    = 0;
+    p_pack->output_format.i_block_align = 0;
+    p_pack->output_format.i_bitrate     = 0;
+    p_pack->output_format.i_extra_data  = 0;
+    p_pack->output_format.p_extra_data  = NULL;
+
+
+    p_pack->p_sout_input = NULL;
+
+    p_pack->i_samplescount = 0;
+    p_pack->i_interpolated_pts = 0;
+
+    p_pack->p_pes  = NULL;
+
+    /* Take care of vorbis init */
+    vorbis_info_init( &p_pack->vi );
+    vorbis_comment_init( &p_pack->vc );
+
+    /* Take care of the initial Vorbis headers */
+    if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
+        goto error;
+
+    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
+    if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_pack->p_fifo, "This bitstream does not contain Vorbis "
+                 "audio data");
+        goto error;
+    }
+
+    /* add a input for the stream ouput */
+    p_pack->output_format.i_sample_rate = p_pack->vi.rate;
+    p_pack->output_format.i_channels    = p_pack->vi.channels;
+    p_pack->output_format.i_block_align = 1;
+    p_pack->output_format.i_bitrate     = p_pack->vi.bitrate_nominal;
+
+    p_pack->p_sout_input =
+        sout_InputNew( p_pack->p_fifo, &p_pack->output_format );
+
+    if( !p_pack->p_sout_input )
+    {
+        msg_Err( p_pack->p_fifo, "cannot add a new stream" );
+        p_pack->p_fifo->b_error = 1;
+        goto error;
+    }
+    msg_Dbg( p_pack->p_fifo, "channels:%d samplerate:%d bitrate:%d",
+             p_pack->vi.channels, p_pack->vi.rate, p_pack->vi.bitrate_nominal);
+
+    if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
+        goto error;
+
+    /* 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_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
+        goto error;
+
+    if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_pack->p_fifo, "2nd Vorbis header is corrupted" );
+        goto error;
+    }
+    
+    if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
+        goto error;
+
+    if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
+        goto error;
+
+    if( vorbis_synthesis_headerin( &p_pack->vi, &p_pack->vc, &oggpacket ) < 0 )
+    {
+        msg_Err( p_pack->p_fifo, "3rd Vorbis header is corrupted" );
+        goto error;
+    }
+
+    if( SendOggPacket( p_pack, &oggpacket, 0, 0 ) != VLC_SUCCESS )
+        goto error;
+
+    /* Initialize the Vorbis packet->PCM decoder */
+    vorbis_synthesis_init( &p_pack->vd, &p_pack->vi );
+    vorbis_block_init( &p_pack->vd, &p_pack->vb );
+
+    return 0;
+
+ error:
+    EndThread( p_pack );
+    return -1;
+}
+
+/*****************************************************************************
+ * PacketizeThread: packetize an unit (here copy a complete ogg packet)
+ *****************************************************************************/
+static void PacketizeThread( packetizer_t *p_pack )
+{
+    mtime_t    i_pts;
+    int        i_samples, i_block_size;
+    ogg_packet oggpacket;
+
+    /* Timestamp all the packets */
+    if( GetOggPacket( p_pack, &oggpacket, &i_pts ) != VLC_SUCCESS )
+        goto error;
+
+    if( i_pts <= 0 && p_pack->i_interpolated_pts <= 0 )
+    {
+        msg_Dbg( p_pack->p_fifo, "need a starting pts" );
+        return;
+    }
+
+    if( i_pts > 0 ) p_pack->i_interpolated_pts = i_pts;
+
+    i_block_size = vorbis_packet_blocksize( &p_pack->vi, &oggpacket );
+    if( i_block_size < 0 ) i_block_size = 0; /* non audio packet */
+    i_samples = ( p_pack->i_last_block_size + i_block_size ) >> 2;
+    p_pack->i_last_block_size = i_block_size;
+
+    if( SendOggPacket( p_pack, &oggpacket, p_pack->i_interpolated_pts,
+                       i_samples ) != VLC_SUCCESS )
+        goto error;
+
+    p_pack->i_interpolated_pts += 1000000 * (uint64_t)i_samples
+        / p_pack->vi.rate;
+
+    return;
+
+ error:
+    p_pack->p_fifo->b_error = 1;
+}
+
+/*****************************************************************************
+ * EndThread : packetizer thread destruction
+ *****************************************************************************/
+static void EndThread ( packetizer_t *p_pack)
+{
+    if( p_pack->p_pes )
+        input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pack->p_pes );
+
+    vorbis_block_clear( &p_pack->vb );
+    vorbis_dsp_clear( &p_pack->vd );
+    vorbis_comment_clear( &p_pack->vc );
+    vorbis_info_clear( &p_pack->vi );  /* must be called last */
+
+    if( p_pack->p_sout_input )
+    {
+        sout_InputDelete( p_pack->p_sout_input );
+    }
+}
+
+/*****************************************************************************
+ * GetOggPacket: get the following vorbis packet from the stream and send back
+ *               the result in an ogg packet (for easy decoding by libvorbis).
+ *****************************************************************************
+ * Returns VLC_EGENERIC in case of eof.
+ *****************************************************************************/
+static int GetOggPacket( packetizer_t *p_pack, ogg_packet *p_oggpacket,
+                         mtime_t *p_pts )
+{
+    if( p_pack->p_pes ) input_DeletePES( p_pack->p_fifo->p_packets_mgt,
+                                         p_pack->p_pes );
+
+    input_ExtractPES( p_pack->p_fifo, &p_pack->p_pes );
+    if( !p_pack->p_pes ) return VLC_EGENERIC;
+
+    p_oggpacket->packet = p_pack->p_pes->p_first->p_payload_start;
+    p_oggpacket->bytes = p_pack->p_pes->i_pes_size;
+    p_oggpacket->granulepos = p_pack->p_pes->i_dts;
+    p_oggpacket->b_o_s = 0;
+    p_oggpacket->e_o_s = 0;
+    p_oggpacket->packetno = 0;
+
+    *p_pts = p_pack->p_pes->i_pts;
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * SendOggPacket: send an ogg packet to the stream output.
+ *****************************************************************************
+ * Returns VLC_EGENERIC in case of error.
+ *****************************************************************************/
+static int SendOggPacket( packetizer_t *p_pack, ogg_packet *p_oggpacket,
+                          mtime_t i_pts, int i_samples )
+{
+    sout_buffer_t *p_sout_buffer =
+        sout_BufferNew( p_pack->p_sout_input->p_sout, p_oggpacket->bytes );
+
+    if( !p_sout_buffer )
+    {
+        p_pack->p_fifo->b_error = 1;
+        return VLC_EGENERIC;
+    }
+
+    p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer,
+                                      p_oggpacket->packet,
+                                      p_oggpacket->bytes );
+
+    p_sout_buffer->i_bitrate = p_pack->vi.bitrate_nominal;
+
+    p_sout_buffer->i_dts = i_pts;
+    p_sout_buffer->i_pts = i_pts;
+
+    p_sout_buffer->i_length = 1000000 * (uint64_t)i_samples / p_pack->vi.rate;
+
+    p_pack->i_samplescount += i_samples;
+
+    sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
+
+    return VLC_SUCCESS;
+}