Commit 8b67039c authored by Gildas Bazin's avatar Gildas Bazin

* modules/packetizer/vorbis.c: vorbis data packetizer for the stream output.
* 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.
parent 48e78c14
......@@ -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
......
......@@ -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 );
}
......
......@@ -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],
......
......@@ -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 );
}
......@@ -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
/*****************************************************************************
* 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment