Commit bff03e0b authored by Gildas Bazin's avatar Gildas Bazin

* modules/demux/ogg.c, modules/codec/vorbis.c: misc small fixes.
* modules/mux/ogg.c: support for inserting/removing elementary streams on the fly (really handy for the --sout-keep option). This will produce a chained Ogg bitstream.
parent f5012c55
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* vorbis.c: vorbis decoder module making use of libvorbis. * vorbis.c: vorbis decoder module making use of libvorbis.
***************************************************************************** *****************************************************************************
* Copyright (C) 1999-2001 VideoLAN * Copyright (C) 1999-2001 VideoLAN
* $Id: vorbis.c,v 1.18 2003/09/24 23:45:06 gbazin Exp $ * $Id: vorbis.c,v 1.19 2003/09/28 16:50:05 gbazin Exp $
* *
* Authors: Gildas Bazin <gbazin@netcourrier.com> * Authors: Gildas Bazin <gbazin@netcourrier.com>
* *
...@@ -293,7 +293,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block ) ...@@ -293,7 +293,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block )
if( p_sys->b_packetizer ) if( p_sys->b_packetizer )
{ {
i_ret = SendPacket( p_dec, &oggpacket ); i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
block_Release( p_block ); block_Release( p_block );
return i_ret; return i_ret;
} }
...@@ -319,7 +319,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block ) ...@@ -319,7 +319,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block )
if( p_sys->b_packetizer ) if( p_sys->b_packetizer )
{ {
i_ret = SendPacket( p_dec, &oggpacket ); i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
block_Release( p_block ); block_Release( p_block );
return i_ret; return i_ret;
} }
...@@ -352,7 +352,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block ) ...@@ -352,7 +352,7 @@ static int RunDecoder( decoder_t *p_dec, block_t *p_block )
if( p_sys->b_packetizer ) if( p_sys->b_packetizer )
{ {
i_ret = SendPacket( p_dec, &oggpacket ); i_ret = ProcessPacket( p_dec, &oggpacket, p_block->i_pts );
block_Release( p_block ); block_Release( p_block );
return i_ret; return i_ret;
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* ogg.c : ogg stream input module for vlc * ogg.c : ogg stream input module for vlc
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: ogg.c,v 1.36 2003/09/27 15:33:02 gbazin Exp $ * $Id: ogg.c,v 1.37 2003/09/28 16:50:04 gbazin Exp $
* *
* Authors: Gildas Bazin <gbazin@netcourrier.com> * Authors: Gildas Bazin <gbazin@netcourrier.com>
* *
...@@ -210,8 +210,7 @@ static int Ogg_ElemStreamStart( input_thread_t *p_input, ...@@ -210,8 +210,7 @@ static int Ogg_ElemStreamStart( input_thread_t *p_input,
int i; int i;
for( i = 0; i < p_stream->i_packets_backup; i++ ) for( i = 0; i < p_stream->i_packets_backup; i++ )
{ {
/* Set correct starting date in the last header packet */ /* Set correct starting date in header packets */
if( i == p_stream->i_packets_backup -1 )
p_stream->p_packets_backup[i].granulepos = p_stream->p_packets_backup[i].granulepos =
p_stream->i_interpolated_pcr * p_stream->f_rate / 90000; p_stream->i_interpolated_pcr * p_stream->f_rate / 90000;
...@@ -375,8 +374,16 @@ static void Ogg_DecodePacket( input_thread_t *p_input, ...@@ -375,8 +374,16 @@ static void Ogg_DecodePacket( input_thread_t *p_input,
&p_stream->p_packets_backup[p_stream->i_packets_backup - 1]; &p_stream->p_packets_backup[p_stream->i_packets_backup - 1];
p_packet_backup->bytes = p_oggpacket->bytes; p_packet_backup->bytes = p_oggpacket->bytes;
if( p_stream->b_force_backup ) p_oggpacket->granulepos = -1;
p_packet_backup->granulepos = p_oggpacket->granulepos; p_packet_backup->granulepos = p_oggpacket->granulepos;
if( p_oggpacket->granulepos >= 0 )
{
/* Because of vorbis granulepos scheme we must set the pcr for the
* 1st header packet so it doesn't get discarded in the
* packetizer */
Ogg_UpdatePCR( p_stream, p_oggpacket );
}
p_packet_backup->packet = malloc( p_oggpacket->bytes ); p_packet_backup->packet = malloc( p_oggpacket->bytes );
if( !p_packet_backup->packet ) return; if( !p_packet_backup->packet ) return;
memcpy( p_packet_backup->packet, p_oggpacket->packet, memcpy( p_packet_backup->packet, p_oggpacket->packet,
...@@ -1524,7 +1531,7 @@ static int Demux( input_thread_t * p_input ) ...@@ -1524,7 +1531,7 @@ static int Demux( input_thread_t * p_input )
static int Control( input_thread_t *p_input, int i_query, va_list args ) static int Control( input_thread_t *p_input, int i_query, va_list args )
{ {
demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data; demux_sys_t *p_ogg = (demux_sys_t *)p_input->p_demux_data;
int64_t i64, *pi64; int64_t *pi64;
switch( i_query ) switch( i_query )
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* ogg.c: ogg muxer module for vlc * ogg.c: ogg muxer module for vlc
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * Copyright (C) 2001, 2002 VideoLAN
* $Id: ogg.c,v 1.9 2003/09/25 23:09:41 gbazin Exp $ * $Id: ogg.c,v 1.10 2003/09/28 16:50:04 gbazin Exp $
* *
* Authors: Laurent Aimar <fenrir@via.ecp.fr> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com> * Gildas Bazin <gbazin@netcourrier.com>
...@@ -48,6 +48,9 @@ static int AddStream( sout_mux_t *, sout_input_t * ); ...@@ -48,6 +48,9 @@ static int AddStream( sout_mux_t *, sout_input_t * );
static int DelStream( sout_mux_t *, sout_input_t * ); static int DelStream( sout_mux_t *, sout_input_t * );
static int Mux ( sout_mux_t * ); static int Mux ( sout_mux_t * );
static sout_buffer_t *OggCreateHeader( sout_mux_t *, mtime_t );
static sout_buffer_t *OggCreateFooter( sout_mux_t *, mtime_t );
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
...@@ -60,13 +63,14 @@ vlc_module_begin(); ...@@ -60,13 +63,14 @@ vlc_module_begin();
vlc_module_end(); vlc_module_end();
/***************************************************************************** /*****************************************************************************
* * Misc declarations
*****************************************************************************/ *****************************************************************************/
#define FREE( p ) if( p ) { free( p ); (p) = NULL; } #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
/* Structures used for OggDS headers used in ogm files */
#define PACKET_TYPE_HEADER 0x01 #define PACKET_TYPE_HEADER 0x01
#define PACKET_TYPE_COMMENT 0x03 #define PACKET_TYPE_COMMENT 0x03
#define PACKET_IS_SYNCPOINT 0x08 #define PACKET_IS_SYNCPOINT 0x08
typedef struct typedef struct
...@@ -115,29 +119,7 @@ typedef struct ...@@ -115,29 +119,7 @@ typedef struct
} ogg_stream_header_t; } ogg_stream_header_t;
/* Helper writer functions */
typedef struct
{
int i_cat;
int i_fourcc;
ogg_stream_header_t header;
int i_packet_no;
mtime_t i_dts;
mtime_t i_length;
ogg_stream_state os;
} ogg_stream_t;
struct sout_mux_sys_t
{
int b_write_header;
int i_streams;
mtime_t i_start_dts;
};
#define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v) #define SetWLE( p, v ) _SetWLE( (uint8_t*)p, v)
static void _SetWLE( uint8_t *p, uint16_t i_dw ) static void _SetWLE( uint8_t *p, uint16_t i_dw )
...@@ -161,12 +143,88 @@ static void _SetQWLE( uint8_t *p, uint64_t i_qw ) ...@@ -161,12 +143,88 @@ static void _SetQWLE( uint8_t *p, uint64_t i_qw )
SetDWLE( p+4, ( i_qw >> 32)&0xffffffff ); SetDWLE( p+4, ( i_qw >> 32)&0xffffffff );
} }
/*
* 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 )
{
mtime_t i_dts;
int i_stream;
int i;
for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
{
sout_fifo_t *p_fifo;
p_fifo = p_mux->pp_inputs[i]->p_fifo;
if( p_fifo->i_depth > 2 )
{
sout_buffer_t *p_buf;
p_buf = sout_FifoShow( p_fifo );
if( i_stream < 0 || p_buf->i_dts < i_dts )
{
i_dts = p_buf->i_dts;
i_stream = i;
}
}
else
{
// wait that all fifo have at least 3 packets (3 vorbis headers)
return( -1 );
}
}
if( pi_stream )
{
*pi_stream = i_stream;
}
if( pi_dts )
{
*pi_dts = i_dts;
}
return( i_stream );
}
/*****************************************************************************
* Definitions of structures and functions used by this plugins
*****************************************************************************/
typedef struct
{
int i_cat;
int i_fourcc;
int b_new;
mtime_t i_dts;
mtime_t i_length;
int i_packet_no;
ogg_stream_state os;
ogg_stream_header_t header;
} ogg_stream_t;
struct sout_mux_sys_t
{
int i_streams;
mtime_t i_start_dts;
/* number of logical streams pending to be added */
int i_add_streams;
/* logical streams pending to be deleted */
int i_del_streams;
ogg_stream_t **pp_del_streams;
};
static void OggSetDate( sout_buffer_t *, mtime_t , mtime_t ); static void OggSetDate( sout_buffer_t *, mtime_t , mtime_t );
static sout_buffer_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *, static sout_buffer_t *OggStreamFlush( sout_mux_t *, ogg_stream_state *,
mtime_t ); mtime_t );
/***************************************************************************** /*****************************************************************************
* Open: * Open: Open muxer
*****************************************************************************/ *****************************************************************************/
static int Open( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
...@@ -177,7 +235,9 @@ static int Open( vlc_object_t *p_this ) ...@@ -177,7 +235,9 @@ static int Open( vlc_object_t *p_this )
p_sys = malloc( sizeof( sout_mux_sys_t ) ); p_sys = malloc( sizeof( sout_mux_sys_t ) );
p_sys->i_streams = 0; p_sys->i_streams = 0;
p_sys->b_write_header = VLC_TRUE; p_sys->i_add_streams = 0;
p_sys->i_del_streams = 0;
p_sys->pp_del_streams = 0;
p_mux->p_sys = p_sys; p_mux->p_sys = p_sys;
p_mux->pf_capacity = Capability; p_mux->pf_capacity = Capability;
...@@ -190,9 +250,8 @@ static int Open( vlc_object_t *p_this ) ...@@ -190,9 +250,8 @@ static int Open( vlc_object_t *p_this )
} }
/***************************************************************************** /*****************************************************************************
* Close: * Close: Finalize ogg bitstream and close muxer
*****************************************************************************/ *****************************************************************************/
static void Close( vlc_object_t * p_this ) static void Close( vlc_object_t * p_this )
{ {
sout_mux_t *p_mux = (sout_mux_t*)p_this; sout_mux_t *p_mux = (sout_mux_t*)p_this;
...@@ -200,6 +259,31 @@ static void Close( vlc_object_t * p_this ) ...@@ -200,6 +259,31 @@ static void Close( vlc_object_t * p_this )
msg_Info( p_mux, "Close" ); msg_Info( p_mux, "Close" );
if( p_sys->i_del_streams )
{
sout_buffer_t *p_og = NULL;
mtime_t i_dts = -1;
int i;
/* Close the current ogg stream */
msg_Dbg( p_mux, "writing footer" );
sout_BufferChain( &p_og, OggCreateFooter( p_mux, 0 ) );
/* Remove deleted logical streams */
for( i = 0; i < p_sys->i_del_streams; i++ )
{
i_dts = p_sys->pp_del_streams[i]->i_dts;
ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
FREE( p_sys->pp_del_streams[i] );
}
FREE( p_sys->pp_del_streams );
p_sys->i_streams -= p_sys->i_del_streams;
/* Write footer */
OggSetDate( p_og, i_dts, 0 );
sout_AccessOutWrite( p_mux->p_access, p_og );
}
free( p_sys ); free( p_sys );
} }
...@@ -209,20 +293,24 @@ static int Capability( sout_mux_t *p_mux, int i_query, void *p_args, ...@@ -209,20 +293,24 @@ static int Capability( sout_mux_t *p_mux, int i_query, void *p_args,
switch( i_query ) switch( i_query )
{ {
case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME: case SOUT_MUX_CAP_GET_ADD_STREAM_ANY_TIME:
*(vlc_bool_t*)p_answer = VLC_FALSE; *(vlc_bool_t*)p_answer = VLC_TRUE;
return( SOUT_MUX_CAP_ERR_OK ); return( SOUT_MUX_CAP_ERR_OK );
default: default:
return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED ); return( SOUT_MUX_CAP_ERR_UNIMPLEMENTED );
} }
} }
/*****************************************************************************
* AddStream: Add an elementary stream to the muxed stream
*****************************************************************************/
static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys; sout_mux_sys_t *p_sys = p_mux->p_sys;
ogg_stream_t *p_stream; ogg_stream_t *p_stream;
msg_Dbg( p_mux, "adding input" ); msg_Dbg( p_mux, "adding input" );
p_input->p_sys = (void*)p_stream = malloc( sizeof( ogg_stream_t ) );
p_input->p_sys = (void *)p_stream = malloc( sizeof( ogg_stream_t ) );
p_stream->i_cat = p_input->p_fmt->i_cat; p_stream->i_cat = p_input->p_fmt->i_cat;
p_stream->i_fourcc = p_input->p_fmt->i_fourcc; p_stream->i_fourcc = p_input->p_fmt->i_fourcc;
...@@ -232,17 +320,16 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -232,17 +320,16 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
switch( p_input->p_fmt->i_cat ) switch( p_input->p_fmt->i_cat )
{ {
case VIDEO_ES: case VIDEO_ES:
switch( p_input->p_fmt->i_fourcc ) switch( p_stream->i_fourcc )
{ {
case VLC_FOURCC( 'm', 'p','4', 'v' ): case VLC_FOURCC( 'm', 'p','4', 'v' ):
case VLC_FOURCC( 'D', 'I','V', '3' ): case VLC_FOURCC( 'D', 'I','V', '3' ):
memcpy( p_stream->header.stream_type, "video ", 8 ); memcpy( p_stream->header.stream_type, "video ", 8 );
if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) ) if( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p','4', 'v' ) )
{ {
memcpy( p_stream->header.sub_type, "XVID", 4 ); memcpy( p_stream->header.sub_type, "XVID", 4 );
} }
else if( p_input->p_fmt->i_fourcc == else if( p_stream->i_fourcc == VLC_FOURCC( 'D', 'I','V', '3' ) )
VLC_FOURCC( 'D', 'I','V', '3' ) )
{ {
memcpy( p_stream->header.sub_type, "DIV3", 4 ); memcpy( p_stream->header.sub_type, "DIV3", 4 );
} }
...@@ -273,23 +360,22 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -273,23 +360,22 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
break; break;
case AUDIO_ES: case AUDIO_ES:
switch( p_input->p_fmt->i_fourcc ) switch( p_stream->i_fourcc )
{ {
case VLC_FOURCC( 'm', 'p','g', 'a' ): case VLC_FOURCC( 'm', 'p','g', 'a' ):
case VLC_FOURCC( 'a', '5','2', ' ' ): case VLC_FOURCC( 'a', '5','2', ' ' ):
memcpy( p_stream->header.stream_type, "audio ", 8 ); memcpy( p_stream->header.stream_type, "audio ", 8 );
if( p_input->p_fmt->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) ) if( p_stream->i_fourcc == VLC_FOURCC( 'm', 'p','g', 'a' ) )
{ {
memcpy( p_stream->header.sub_type, "55 ", 4 ); memcpy( p_stream->header.sub_type, "55 ", 4 );
} }
else if( p_input->p_fmt->i_fourcc == else if( p_stream->i_fourcc == VLC_FOURCC( 'a', '5','2', ' ' ) )
VLC_FOURCC( 'a', '5','2', ' ' ) )
{ {
memcpy( p_stream->header.sub_type, "2000", 4 ); memcpy( p_stream->header.sub_type, "2000", 4 );
} }
SetDWLE( &p_stream->header.i_size, SetDWLE( &p_stream->header.i_size,
sizeof( ogg_stream_header_t ) - 1); sizeof( ogg_stream_header_t ) - 1);
SetQWLE( &p_stream->header.i_time_unit, 1000000 ); /* is it used ? */ SetQWLE( &p_stream->header.i_time_unit, 1000000 ); /*is it used ?*/
SetDWLE( &p_stream->header.i_default_len, 0 ); /* ??? */ SetDWLE( &p_stream->header.i_default_len, 0 ); /* ??? */
SetDWLE( &p_stream->header.i_buffer_size, 30*1024 ); SetDWLE( &p_stream->header.i_buffer_size, 30*1024 );
SetQWLE( &p_stream->header.i_samples_per_unit, SetQWLE( &p_stream->header.i_samples_per_unit,
...@@ -312,85 +398,76 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) ...@@ -312,85 +398,76 @@ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input )
} }
break; break;
case SPU_ES:
switch( p_stream->i_fourcc )
{
case VLC_FOURCC( 's', 'u','b', 't' ):
memcpy( p_stream->header.stream_type, "text ", 8 );
break;
default:
FREE( p_input->p_sys );
return( VLC_EGENERIC );
}
break;
default: default:
FREE( p_input->p_sys ); FREE( p_input->p_sys );
return( VLC_EGENERIC ); return( VLC_EGENERIC );
} }
ogg_stream_init( &p_stream->os, rand () ); ogg_stream_init( &p_stream->os, rand () );
p_stream->b_new = VLC_TRUE;
p_sys->i_add_streams++;
p_sys->i_streams++;
return( VLC_SUCCESS ); return( VLC_SUCCESS );
} }
/*****************************************************************************
* DelStream: Delete an elementary stream from the muxed stream
*****************************************************************************/
static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input ) static int DelStream( sout_mux_t *p_mux, sout_input_t *p_input )
{ {
sout_mux_sys_t *p_sys = p_mux->p_sys;
ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys; ogg_stream_t *p_stream = (ogg_stream_t*)p_input->p_sys;
sout_buffer_t *p_og; sout_buffer_t *p_og;
msg_Dbg( p_mux, "removing input" ); msg_Dbg( p_mux, "removing input" );
/* flush all remaining data */ /* flush all remaining data */
if( p_input->p_sys ) if( p_input->p_sys )
{ {
p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ); if( ( p_og = OggStreamFlush( p_mux, &p_stream->os, 0 ) ) )
if( p_og )
{ {
OggSetDate( p_og, p_stream->i_dts, p_stream->i_length ); OggSetDate( p_og, p_stream->i_dts, p_stream->i_length );
sout_AccessOutWrite( p_mux->p_access, p_og ); sout_AccessOutWrite( p_mux->p_access, p_og );
} }
ogg_stream_clear( &p_stream->os ); /* move input in delete queue */
if( !p_stream->b_new )
FREE( p_input->p_sys );
}
return( 0 );
}
/*
* 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 )
{
mtime_t i_dts;
int i_stream;
int i;
for( i = 0, i_dts = 0, i_stream = -1; i < p_mux->i_nb_inputs; i++ )
{
sout_fifo_t *p_fifo;
p_fifo = p_mux->pp_inputs[i]->p_fifo;
if( p_fifo->i_depth > 1 )
{
sout_buffer_t *p_buf;
p_buf = sout_FifoShow( p_fifo );
if( i_stream < 0 || p_buf->i_dts < i_dts )
{ {
i_dts = p_buf->i_dts; p_sys->pp_del_streams = realloc( p_sys->pp_del_streams,
i_stream = i; (p_sys->i_del_streams + 1) *
} sizeof(ogg_stream_t *) );
p_sys->pp_del_streams[p_sys->i_del_streams++] = p_stream;
} }
else else
{ {
return( -1 ); // wait that all fifo have at least 2 packets /* Wasn't already added so get rid of it */
ogg_stream_clear( &p_stream->os );
FREE( p_stream );
p_sys->i_add_streams--;
} }
} }
if( pi_stream )
{ p_input->p_sys = NULL;
*pi_stream = i_stream;
} return( 0 );
if( pi_dts )
{
*pi_dts = i_dts;
}
return( i_stream );
} }
/*****************************************************************************
* Ogg bitstream manipulation routines
*****************************************************************************/
static sout_buffer_t *OggStreamFlush( sout_mux_t *p_mux, 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 )
{ {
...@@ -468,9 +545,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -468,9 +545,8 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
* must appear first in the ogg stream so we take care of them first. */ * must appear first in the ogg stream so we take care of them first. */
for( i = 0; i < p_mux->i_nb_inputs; i++ ) for( i = 0; i < p_mux->i_nb_inputs; i++ )
{ {
ogg_stream_t *p_stream; ogg_stream_t *p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
p_stream->b_new = VLC_FALSE;
p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) || if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) ) p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
...@@ -492,7 +568,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -492,7 +568,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
{ {
/* ds header */ /* ds header */
op.packet = (uint8_t*)&p_stream->header; op.packet = (uint8_t*)&p_stream->header;
op.bytes = sizeof( ogg_stream_t ); op.bytes = sizeof( ogg_stream_header_t );
op.b_o_s = 1; op.b_o_s = 1;
op.e_o_s = 0; op.e_o_s = 0;
op.granulepos = 0; op.granulepos = 0;
...@@ -507,9 +583,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -507,9 +583,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
/* Take care of the non b_o_s headers */ /* Take care of the non b_o_s headers */
for( i = 0; i < p_mux->i_nb_inputs; i++ ) for( i = 0; i < p_mux->i_nb_inputs; i++ )
{ {
ogg_stream_t *p_stream; ogg_stream_t *p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
p_stream = (ogg_stream_t*)p_mux->pp_inputs[i]->p_sys;
if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) || if( p_stream->i_fourcc == VLC_FOURCC( 'v', 'o', 'r', 'b' ) ||
p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) ) p_stream->i_fourcc == VLC_FOURCC( 't', 'h', 'e', 'o' ) )
...@@ -537,7 +611,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -537,7 +611,7 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
/* comment */ /* comment */
com[0] = PACKET_TYPE_COMMENT; com[0] = PACKET_TYPE_COMMENT;
i_com = snprintf( &com[1], 128, "VLC 0.5.x stream output" ) + 1; i_com = snprintf( &com[1], 128, VERSION" stream output" ) + 1;
op.packet = com; op.packet = com;
op.bytes = i_com; op.bytes = i_com;
op.b_o_s = 0; op.b_o_s = 0;
...@@ -559,6 +633,51 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts ) ...@@ -559,6 +633,51 @@ static sout_buffer_t *OggCreateHeader( sout_mux_t *p_mux, mtime_t i_dts )
return( p_hdr ); return( p_hdr );
} }
static sout_buffer_t *OggCreateFooter( sout_mux_t *p_mux, mtime_t i_dts )
{
sout_mux_sys_t *p_sys = p_mux->p_sys;
sout_buffer_t *p_hdr = NULL;
sout_buffer_t *p_og;
ogg_packet op;
int i;
/* Write eos packets for each stream. */
for( i = 0; i < p_mux->i_nb_inputs; i++ )
{
ogg_stream_t *p_stream = p_mux->pp_inputs[i]->p_sys;
/* skip newly added streams */
if( p_stream->b_new ) continue;
op.packet = NULL;
op.bytes = 0;
op.b_o_s = 0;
op.e_o_s = 1;
op.granulepos = -1;
op.packetno = p_stream->i_packet_no++;
ogg_stream_packetin( &p_stream->os, &op );
p_og = OggStreamFlush( p_mux, &p_stream->os, 0 );
sout_BufferChain( &p_hdr, p_og );
}
for( i = 0; i < p_sys->i_del_streams; i++ )
{
op.packet = NULL;
op.bytes = 0;
op.b_o_s = 0;
op.e_o_s = 1;
op.granulepos = -1;
op.packetno = p_sys->pp_del_streams[i]->i_packet_no++;
ogg_stream_packetin( &p_sys->pp_del_streams[i]->os, &op );
p_og = OggStreamFlush( p_mux, &p_sys->pp_del_streams[i]->os, 0 );
sout_BufferChain( &p_hdr, p_og );
}
return( p_hdr );
}
static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length ) static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length )
{ {
int i_count; int i_count;
...@@ -580,6 +699,9 @@ static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length ) ...@@ -580,6 +699,9 @@ static void OggSetDate( sout_buffer_t *p_og, mtime_t i_dts, mtime_t i_length )
} }
} }
/*****************************************************************************
* Mux: multiplex available data in input fifos into the Ogg bitstream
*****************************************************************************/
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_mux_sys_t *p_sys = p_mux->p_sys;
...@@ -587,18 +709,44 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -587,18 +709,44 @@ static int Mux( sout_mux_t *p_mux )
int i_stream; int i_stream;
mtime_t i_dts; mtime_t i_dts;
if( p_sys->b_write_header ) if( p_sys->i_add_streams || p_sys->i_del_streams )
{ {
/* Open new ogg stream */
if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 ) if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
{ {
msg_Dbg( p_mux, "waiting data..." ); msg_Dbg( p_mux, "waiting for data..." );
return( VLC_SUCCESS ); return( VLC_SUCCESS );
} }
p_sys->i_start_dts = i_dts;
if( p_sys->i_streams )
{
/* Close current ogg stream */
int i;
msg_Dbg( p_mux, "writing footer" );
sout_BufferChain( &p_og, OggCreateFooter( p_mux, 0 ) );
/* Remove deleted logical streams */
for( i = 0; i < p_sys->i_del_streams; i++ )
{
ogg_stream_clear( &p_sys->pp_del_streams[i]->os );
FREE( p_sys->pp_del_streams[i] );
}
FREE( p_sys->pp_del_streams );
p_sys->i_streams = 0;
}
msg_Dbg( p_mux, "writing header" ); msg_Dbg( p_mux, "writing header" );
p_sys->i_start_dts = i_dts;
p_sys->i_streams = p_mux->i_nb_inputs;
p_sys->i_del_streams = 0;
p_sys->i_add_streams = 0;
sout_BufferChain( &p_og, OggCreateHeader( p_mux, i_dts ) ); sout_BufferChain( &p_og, OggCreateHeader( p_mux, i_dts ) );
p_sys->b_write_header = VLC_FALSE;
/* Write header and/or footer */
OggSetDate( p_og, i_dts, 0 );
sout_AccessOutWrite( p_mux->p_access, p_og );
p_og = NULL;
} }
for( ;; ) for( ;; )
...@@ -610,16 +758,11 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -610,16 +758,11 @@ static int Mux( sout_mux_t *p_mux )
if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 ) if( MuxGetStream( p_mux, &i_stream, &i_dts) < 0 )
{ {
//msg_Dbg( p_mux, "waiting data..." );
return( VLC_SUCCESS ); return( VLC_SUCCESS );
} }
//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_input = p_mux->pp_inputs[i_stream];
p_stream = (ogg_stream_t*)p_input->p_sys; p_stream = (ogg_stream_t*)p_input->p_sys;
p_data = sout_FifoGet( p_input->p_fifo ); p_data = sout_FifoGet( p_input->p_fifo );
if( p_stream->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b' ) ) if( p_stream->i_fourcc != VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
...@@ -659,6 +802,11 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -659,6 +802,11 @@ static int Mux( sout_mux_t *p_mux )
else else
op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000; op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
} }
else if( p_stream->i_cat == SPU_ES )
{
/* granulepos is in milisec */
op.granulepos = ( i_dts - p_sys->i_start_dts ) / 1000;
}
ogg_stream_packetin( &p_stream->os, &op ); ogg_stream_packetin( &p_stream->os, &op );
......
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