From: Gildas Bazin Date: Mon, 23 Jun 2003 23:51:31 +0000 (+0000) Subject: * modules/packetizer/vorbis.c: vorbis data packetizer for the stream output. X-Git-Tag: 0.6.1~314 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=8b67039c5f27bc85724f0db3a1adfa6d54aef2c0;hp=48e78c14b17e1b7efa065cbf22044a4590e25c63;p=vlc * 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. --- diff --git a/configure.ac b/configure.ac index 6b38a015c1..9de0d9da67 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c index d9d7f0e5ee..1124e35d31 100644 --- a/modules/demux/ogg.c +++ b/modules/demux/ogg.c @@ -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 * @@ -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 ); } diff --git a/modules/misc/httpd.c b/modules/misc/httpd.c index 4a3bd93520..8e51938c4e 100644 --- a/modules/misc/httpd.c +++ b/modules/misc/httpd.c @@ -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 * @@ -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], diff --git a/modules/mux/ogg.c b/modules/mux/ogg.c index ca48bbdfd2..b398397286 100644 --- a/modules/mux/ogg.c +++ b/modules/mux/ogg.c @@ -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 + * Gildas Bazin * * 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 ); } - diff --git a/modules/packetizer/Modules.am b/modules/packetizer/Modules.am index f087c48568..21bb27f280 100644 --- a/modules/packetizer/Modules.am +++ b/modules/packetizer/Modules.am @@ -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 index 0000000000..efca22514f --- /dev/null +++ b/modules/packetizer/vorbis.c @@ -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 + * + * 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 +#include +#include +#include +#include + +#include /* malloc(), free() */ +#include /* strdup() */ +#include "codecs.h" /* WAVEFORMATEX BITMAPINFOHEADER */ + +#include +#include + +/***************************************************************************** + * 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; +}