Commit 535be4f6 authored by Gildas Bazin's avatar Gildas Bazin

* include/vlc_es_out.h, src/input/es_out.c: added an ES_OUT_SET_FMT control.

* modules/demux/ogg.c, modules/demux/mkv.cpp:
  - store the vorbis/theora/speex headers in fmt.p_extra.
  - this change simplifies the code quite a bit and is a lot cleaner.
* modules/codec/vorbis.c, theora.c, speex.c, flac.c:
  - get the headers from fmt_in.p_extra or from the bitstream if empty.
* modules/mux/ogg.c:
  - recontstruct the headers from fmt.p_extra.
parent e96986fe
......@@ -2,7 +2,7 @@
* vlc_es_out.h
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id: ninput.h 7930 2004-06-07 18:23:15Z fenrir $
* $Id$
*
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
......@@ -62,6 +62,9 @@ enum es_out_query_e
ES_OUT_SET_PCR, /* arg1=int64_t i_pcr(microsecond!) (using default group 0)*/
ES_OUT_SET_GROUP_PCR, /* arg1= int i_group, arg2=int64_t i_pcr(microsecond!)*/
ES_OUT_RESET_PCR, /* no arg */
/* Try not to use this one as it is a bit hacky */
ES_OUT_SET_FMT /* arg1= es_out_id_t* arg2=es_format_t* */
};
struct es_out_t
......
......@@ -215,14 +215,6 @@ static int OpenDecoder( vlc_object_t *p_this )
p_dec->pf_decode_audio = DecodeBlock;
p_dec->pf_packetize = PacketizeBlock;
/* Decode STREAMINFO */
msg_Dbg( p_dec, "decode STREAMINFO" );
p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra );
memcpy( p_sys->p_block->p_buffer, p_dec->fmt_in.p_extra,
p_dec->fmt_in.i_extra );
FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac );
msg_Dbg( p_dec, "STREAMINFO decoded" );
return VLC_SUCCESS;
}
......@@ -236,11 +228,43 @@ static int OpenPacketizer( vlc_object_t *p_this )
i_ret = OpenDecoder( p_this );
/* Set output properties */
p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','a','c');
if( i_ret != VLC_SUCCESS ) return i_ret;
return i_ret;
}
/*****************************************************************************
* ProcessHeader: processe Flac header.
*****************************************************************************/
static void ProcessHeader( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
if( !p_dec->fmt_in.i_extra ) return;
/* Decode STREAMINFO */
msg_Dbg( p_dec, "decode STREAMINFO" );
p_sys->p_block = block_New( p_dec, p_dec->fmt_in.i_extra );
memcpy( p_sys->p_block->p_buffer, p_dec->fmt_in.p_extra,
p_dec->fmt_in.i_extra );
FLAC__stream_decoder_process_until_end_of_metadata( p_sys->p_flac );
msg_Dbg( p_dec, "STREAMINFO decoded" );
if( !p_sys->b_stream_info ) return;
if( p_dec->fmt_out.i_codec == VLC_FOURCC('f','l','a','c') )
{
p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
p_dec->fmt_out.p_extra =
realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra,
p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
}
}
/****************************************************************************
* PacketizeBlock: the whole thing
****************************************************************************
......@@ -254,6 +278,8 @@ static block_t *PacketizeBlock( decoder_t *p_dec, block_t **pp_block )
if( !pp_block || !*pp_block ) return NULL;
if( !p_sys->b_stream_info ) ProcessHeader( p_dec );
if( !aout_DateGet( &p_sys->end_date ) && !(*pp_block)->i_pts )
{
/* We've just started the stream, wait for the first PTS. */
......
......@@ -82,7 +82,8 @@ static int OpenPacketizer( vlc_object_t * );
static void CloseDecoder ( vlc_object_t * );
static void *DecodeBlock ( decoder_t *, block_t ** );
static int ProcessHeader ( decoder_t *, ogg_packet * );
static int ProcessHeaders( decoder_t * );
static int ProcessInitialHeader ( decoder_t *, ogg_packet * );
static void *ProcessPacket( decoder_t *, ogg_packet *, block_t ** );
static aout_buffer_t *DecodePacket( decoder_t *, ogg_packet * );
......@@ -202,37 +203,116 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
if( p_sys->i_headers == 0 )
/* Check for headers */
if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
{
/* Take care of the initial Speex header */
if( ProcessHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
/* Headers already available as extra data */
p_sys->i_headers = 2;
}
else if( oggpacket.bytes && p_sys->i_headers < 2 )
{
msg_Err( p_dec, "initial Speex header is corrupted" );
/* Backup headers as extra data */
uint8_t *p_extra;
p_dec->fmt_in.p_extra =
realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
oggpacket.bytes + 2 );
p_extra = p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
*(p_extra++) = oggpacket.bytes >> 8;
*(p_extra++) = oggpacket.bytes & 0xFF;
memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
p_dec->fmt_in.i_extra += oggpacket.bytes + 2;
block_Release( *pp_block );
p_sys->i_headers++;
return NULL;
}
p_sys->i_headers++;
if( p_sys->i_headers == 2 )
{
if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
{
p_sys->i_headers = 0;
p_dec->fmt_in.i_extra = 0;
block_Release( *pp_block );
return NULL;
}
else p_sys->i_headers++;
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
}
/*****************************************************************************
* ProcessHeaders: process Speex headers.
*****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
ogg_packet oggpacket;
uint8_t *p_extra;
int i_extra;
if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
oggpacket.granulepos = -1;
oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
p_extra = p_dec->fmt_in.p_extra;
i_extra = p_dec->fmt_in.i_extra;
/* Take care of the initial Vorbis header */
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
p_extra += oggpacket.bytes;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
if( p_sys->i_headers == 1 )
/* Take care of the initial Speex header */
if( ProcessInitialHeader( p_dec, &oggpacket ) != VLC_SUCCESS )
{
msg_Err( p_dec, "initial Speex header is corrupted" );
return VLC_EGENERIC;
}
/* The next packet in order is the comments header */
oggpacket.b_o_s = 0;
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
p_extra += oggpacket.bytes;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
ParseSpeexComments( p_dec, &oggpacket );
p_sys->i_headers++;
return ProcessPacket( p_dec, &oggpacket, pp_block );
if( p_sys->b_packetizer )
{
p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
p_dec->fmt_out.p_extra =
realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra,
p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
return VLC_SUCCESS;
}
/*****************************************************************************
* ProcessHeader: processes the inital Speex header packet.
* ProcessInitialHeader: processes the inital Speex header packet.
*****************************************************************************/
static int ProcessHeader( decoder_t *p_dec, ogg_packet *p_oggpacket )
static int ProcessInitialHeader( decoder_t *p_dec, ogg_packet *p_oggpacket )
{
decoder_sys_t *p_sys = p_dec->p_sys;
......@@ -350,10 +430,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
else
p_aout_buffer = NULL; /* Skip headers */
if( p_block )
{
block_Release( p_block );
}
if( p_block ) block_Release( p_block );
return p_aout_buffer;
}
}
......@@ -463,6 +540,8 @@ static void ParseSpeexComments( decoder_t *p_dec, ogg_packet *p_oggpacket )
const SpeexMode *p_mode;
int i_len;
if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
p_mode = speex_mode_list[p_sys->p_header->mode];
input_Control( p_input, INPUT_ADD_INFO, _("Speex comment"), _("Mode"),
......@@ -603,9 +682,8 @@ static int OpenEncoder( vlc_object_t *p_this )
pp_header[1] = "ENCODER=VLC media player";
pi_header[1] = sizeof("ENCODER=VLC media player");
p_enc->fmt_out.i_extra = 1 + 3 * 2 + pi_header[0] + pi_header[1];
p_enc->fmt_out.i_extra = 3 * 2 + pi_header[0] + pi_header[1];
p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
*(p_extra++) = 2; /* number of headers */
for( i = 0; i < 2; i++ )
{
*(p_extra++) = pi_header[i] >> 8;
......
......@@ -67,6 +67,7 @@ static int OpenPacketizer( vlc_object_t * );
static void CloseDecoder ( vlc_object_t * );
static void *DecodeBlock ( decoder_t *, block_t ** );
static int ProcessHeaders( decoder_t * );
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
static picture_t *DecodePacket( decoder_t *, ogg_packet * );
......@@ -194,19 +195,83 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
if( p_sys->i_headers == 0 )
/* Check for headers */
if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
{
/* Take care of the initial Theora header */
/* Headers already available as extra data */
p_sys->i_headers = 3;
}
else if( oggpacket.bytes && p_sys->i_headers < 3 )
{
/* Backup headers as extra data */
uint8_t *p_extra;
p_dec->fmt_in.p_extra =
realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
oggpacket.bytes + 2 );
p_extra = p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
*(p_extra++) = oggpacket.bytes >> 8;
*(p_extra++) = oggpacket.bytes & 0xFF;
memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
p_dec->fmt_in.i_extra += oggpacket.bytes + 2;
block_Release( *pp_block );
p_sys->i_headers++;
return NULL;
}
if( p_sys->i_headers == 3 )
{
if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
{
p_sys->i_headers = 0;
p_dec->fmt_in.i_extra = 0;
block_Release( *pp_block );
return NULL;
}
else p_sys->i_headers++;
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
}
/*****************************************************************************
* ProcessHeaders: process Theora headers.
*****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
ogg_packet oggpacket;
uint8_t *p_extra;
int i_extra;
if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
oggpacket.granulepos = -1;
oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
p_extra = p_dec->fmt_in.p_extra;
i_extra = p_dec->fmt_in.i_extra;
/* Take care of the initial Vorbis header */
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
p_extra += oggpacket.bytes;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
{
msg_Err( p_dec, "This bitstream does not contain Theora "
"video data." );
block_Release( p_block );
return NULL;
msg_Err( p_dec, "This bitstream does not contain Theora video data" );
return VLC_EGENERIC;
}
p_sys->i_headers++;
/* Set output properties */
p_dec->fmt_out.video.i_width = p_sys->ti.width;
......@@ -225,52 +290,71 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
}
msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content "
"is %dx%d with offset (%d,%d).",
"is %dx%d with offset (%d,%d)",
p_sys->ti.width, p_sys->ti.height,
(double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator,
p_sys->ti.frame_width, p_sys->ti.frame_height,
p_sys->ti.offset_x, p_sys->ti.offset_y );
return ProcessPacket( p_dec, &oggpacket, pp_block );
/* The next packet in order is the comments header */
oggpacket.b_o_s = 0;
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
p_extra += oggpacket.bytes;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
if( p_sys->i_headers == 1 )
{
/* The next packet in order is the comments header */
if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
{
msg_Err( p_dec, "2nd Theora header is corrupted." );
return NULL;
msg_Err( p_dec, "2nd Theora header is corrupted" );
return VLC_EGENERIC;
}
p_sys->i_headers++;
ParseTheoraComments( p_dec );
return ProcessPacket( p_dec, &oggpacket, pp_block );
/* The next packet in order is the codebooks header
* We need to watch out that this packet is not missing as a
* missing or corrupted header is fatal. */
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
if( p_sys->i_headers == 2 )
{
/* The next packet in order is the codebooks header
We need to watch out that this packet is not missing as a
missing or corrupted header is fatal. */
* We need to watch out that this packet is not missing as a
* missing or corrupted header is fatal */
if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 )
{
msg_Err( p_dec, "3rd Theora header is corrupted." );
return NULL;
msg_Err( p_dec, "3rd Theora header is corrupted" );
return VLC_EGENERIC;
}
p_sys->i_headers++;
if( !p_sys->b_packetizer )
{
/* We have all the headers, initialize decoder */
theora_decode_init( &p_sys->td, &p_sys->ti );
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
else
{
p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
p_dec->fmt_out.p_extra =
realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra,
p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
return VLC_SUCCESS;
}
/*****************************************************************************
......@@ -289,6 +373,8 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
p_sys->i_pts = p_block->i_pts;
}
*pp_block = NULL; /* To avoid being fed the same packet again */
if( p_sys->b_packetizer )
{
/* Date management */
......@@ -308,11 +394,7 @@ static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
else
p_buf = NULL;
if( p_block )
{
block_Release( p_block );
*pp_block = NULL;
}
if( p_block ) block_Release( p_block );
}
/* Date management */
......@@ -353,9 +435,11 @@ static picture_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
static void ParseTheoraComments( decoder_t *p_dec )
{
input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
int i = 0;
char *psz_name, *psz_value, *psz_comment;
int i = 0;
if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
while ( i < p_dec->p_sys->tc.comments )
{
psz_comment = strdup( p_dec->p_sys->tc.user_comments[i] );
......@@ -459,7 +543,7 @@ static int OpenEncoder( vlc_object_t *p_this )
{
encoder_t *p_enc = (encoder_t *)p_this;
encoder_sys_t *p_sys = p_enc->p_sys;
ogg_packet header[3];
ogg_packet header;
uint8_t *p_extra;
vlc_value_t val;
int i_quality, i;
......@@ -549,19 +633,24 @@ static int OpenEncoder( vlc_object_t *p_this )
theora_comment_init( &p_sys->tc );
/* Create and store headers */
theora_encode_header( &p_sys->td, &header[0] );
theora_encode_comment( &p_sys->tc, &header[1] );
theora_encode_tables( &p_sys->td, &header[2] );
p_enc->fmt_out.i_extra = 1 + 3 * 2 + header[0].bytes +
header[1].bytes + header[2].bytes;
p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
*(p_extra++) = 3; /* number of headers */
p_enc->fmt_out.i_extra = 3 * 2;
for( i = 0; i < 3; i++ )
{
*(p_extra++) = header[i].bytes >> 8;
*(p_extra++) = header[i].bytes & 0xFF;
memcpy( p_extra, header[i].packet, header[i].bytes );
p_extra += header[i].bytes;
if( i == 0 ) theora_encode_header( &p_sys->td, &header );
else if( i == 1 ) theora_encode_comment( &p_sys->tc, &header );
else if( i == 2 ) theora_encode_tables( &p_sys->td, &header );
p_enc->fmt_out.p_extra =
realloc( p_enc->fmt_out.p_extra,
p_enc->fmt_out.i_extra + header.bytes );
p_extra = p_enc->fmt_out.p_extra;
p_extra += p_enc->fmt_out.i_extra + (i-3)*2;
p_enc->fmt_out.i_extra += header.bytes;
*(p_extra++) = header.bytes >> 8;
*(p_extra++) = header.bytes & 0xFF;
memcpy( p_extra, header.packet, header.bytes );
}
return VLC_SUCCESS;
......
......@@ -101,6 +101,7 @@ static int OpenPacketizer( vlc_object_t * );
static void CloseDecoder ( vlc_object_t * );
static void *DecodeBlock ( decoder_t *, block_t ** );
static int ProcessHeaders( decoder_t * );
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
static aout_buffer_t *DecodePacket ( decoder_t *, ogg_packet * );
......@@ -268,20 +269,83 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
if( p_sys->i_headers == 0 )
/* Check for headers */
if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
{
/* Take care of the initial Vorbis header */
/* Headers already available as extra data */
p_sys->i_headers = 3;
}
else if( oggpacket.bytes && p_sys->i_headers < 3 )
{
/* Backup headers as extra data */
uint8_t *p_extra;
oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc,
&oggpacket ) < 0 )
p_dec->fmt_in.p_extra =
realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
oggpacket.bytes + 2 );
p_extra = p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
*(p_extra++) = oggpacket.bytes >> 8;
*(p_extra++) = oggpacket.bytes & 0xFF;
memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
p_dec->fmt_in.i_extra += oggpacket.bytes + 2;
block_Release( *pp_block );
p_sys->i_headers++;
return NULL;
}
if( p_sys->i_headers == 3 )
{
if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
{
msg_Err( p_dec, "this bitstream does not contain Vorbis "
"audio data.");
p_sys->i_headers = 0;
p_dec->fmt_in.i_extra = 0;
block_Release( *pp_block );
return NULL;
}
p_sys->i_headers++;
else p_sys->i_headers++;
}
return ProcessPacket( p_dec, &oggpacket, pp_block );
}
/*****************************************************************************
* ProcessHeaders: process Vorbis headers.
*****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
ogg_packet oggpacket;
uint8_t *p_extra;
int i_extra;
if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
oggpacket.granulepos = -1;
oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
oggpacket.e_o_s = 0;
oggpacket.packetno = 0;
p_extra = p_dec->fmt_in.p_extra;
i_extra = p_dec->fmt_in.i_extra;
/* Take care of the initial Vorbis header */
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);
oggpacket.packet = p_extra;
p_extra += oggpacket.bytes;
i_extra -= (oggpacket.bytes + 2);
if( i_extra < 0 )
{
msg_Err( p_dec, "header data corrupted");
return VLC_EGENERIC;
}
if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
{
msg_Err( p_dec, "this bitstream does not contain Vorbis audio data");
return VLC_EGENERIC;
}
/* Setup the format */
p_dec->fmt_out.audio.i_rate = p_sys->vi.rate;
......@@ -292,44 +356,49 @@ static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
p_dec->fmt_out.i_bitrate = p_sys->vi.bitrate_nominal;
aout_DateInit( &p_sys->end_date, p_sys->vi.rate );
aout_DateSet( &p_sys->end_date, 0 );
msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ld",
p_sys->vi.channels, p_sys->vi.rate,
p_sys->vi.bitrate_nominal );
p_sys->vi.channels, p_sys->vi.rate, p_sys->vi.bitrate_nominal );
return ProcessPacket( p_dec, &oggpacket, pp_block );
/* The next packet in order is the comments header */
oggpacket.b_o_s = 0;
oggpacket.bytes = *(p_extra++) << 8;
oggpacket.bytes |= (*(p_extra++) & 0xFF);