* 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.
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
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
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
* 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>
*
/* info from logical streams */
double f_rate;
int i_bitrate;
+ int i_channels;
int b_reinit;
/* codec specific stuff */
/* 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 );
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 );
}
* 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>
*
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 );
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],
* 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
}
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:
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 )
{
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 );
/*
* 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;
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( ;; )
{
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;
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( ;; )
{
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;
return( p_og_first );
}
+
static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
{
sout_buffer_t *p_hdr = NULL;
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;
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;
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;
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 );
return( p_hdr );
}
-
static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length )
{
int i_count;
}
}
-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 )
}
//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 )
{
return( VLC_SUCCESS );
}
-
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
--- /dev/null
+/*****************************************************************************
+ * 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;
+}