X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fogg.c;h=4c50f6d2c8a07447e568957d360e946d74a4e1a7;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=5e50b7a55297a0b22759b5335d9d941525a1c237;hpb=66bd92014e5d721d8fe74bfd69f601bfd228012a;p=vlc diff --git a/modules/demux/ogg.c b/modules/demux/ogg.c index 5e50b7a552..4c50f6d2c8 100644 --- a/modules/demux/ogg.c +++ b/modules/demux/ogg.c @@ -39,9 +39,11 @@ #include #include -#include +#include "xiph.h" #include "vorbis.h" #include "kate_categories.h" +#include "ogg.h" +#include "oggseek.h" /***************************************************************************** * Module descriptor @@ -63,69 +65,6 @@ vlc_module_end () /***************************************************************************** * Definitions of structures and functions used by this plugins *****************************************************************************/ -typedef struct logical_stream_s -{ - ogg_stream_state os; /* logical stream of packets */ - - es_format_t fmt; - es_format_t fmt_old; /* format of old ES is reused */ - es_out_id_t *p_es; - double f_rate; - - int i_serial_no; - - /* the header of some logical streams (eg vorbis) contain essential - * data for the decoder. We back them up here in case we need to re-feed - * them to the decoder. */ - int b_force_backup; - int i_packets_backup; - uint8_t *p_headers; - int i_headers; - - /* program clock reference (in units of 90kHz) derived from the previous - * granulepos */ - mtime_t i_pcr; - mtime_t i_interpolated_pcr; - mtime_t i_previous_pcr; - - /* Misc */ - bool b_reinit; - int i_granule_shift; - - /* kate streams have the number of headers in the ID header */ - int i_kate_num_headers; - - /* for Annodex logical bitstreams */ - int i_secondary_header_packets; - -} logical_stream_t; - -struct demux_sys_t -{ - ogg_sync_state oy; /* sync and verify incoming physical bitstream */ - - int i_streams; /* number of logical bitstreams */ - logical_stream_t **pp_stream; /* pointer to an array of logical streams */ - - logical_stream_t *p_old_stream; /* pointer to a old logical stream to avoid recreating it */ - - /* program clock reference (in units of 90kHz) derived from the pcr of - * the sub-streams */ - mtime_t i_pcr; - - /* stream state */ - int i_bos; - int i_eos; - - /* bitrate */ - int i_bitrate; - - /* after reading all headers, the first data page is stuffed into the relevant stream, ready to use */ - bool b_page_waiting; - - /* */ - vlc_meta_t *p_meta; -}; /* OggDS headers for the new header format (used in ogm files) */ typedef struct @@ -166,7 +105,6 @@ typedef struct } sh; } stream_header_t; -#define OGG_BLOCK_SIZE 4096 /* Some defines from OggDS */ #define PACKET_TYPE_HEADER 0x01 @@ -276,9 +214,9 @@ static void Close( vlc_object_t *p_this ) static int Demux( demux_t * p_demux ) { demux_sys_t *p_sys = p_demux->p_sys; - ogg_page oggpage; ogg_packet oggpacket; int i_stream; + bool b_skipping = false; if( p_sys->i_eos == p_sys->i_streams ) @@ -323,11 +261,11 @@ static int Demux( demux_t * p_demux ) /* * Demux an ogg page from the stream */ - if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS ) + if( Ogg_ReadPage( p_demux, &p_sys->current_page ) != VLC_SUCCESS ) return 0; /* EOF */ /* Test for End of Stream */ - if( ogg_page_eos( &oggpage ) ) + if( ogg_page_eos( &p_sys->current_page ) ) p_sys->i_eos++; } @@ -340,10 +278,10 @@ static int Demux( demux_t * p_demux ) if( !p_sys->b_page_waiting ) { if( p_sys->i_streams == 1 && - ogg_page_serialno( &oggpage ) != p_stream->os.serialno ) + ogg_page_serialno( &p_sys->current_page ) != p_stream->os.serialno ) { msg_Err( p_demux, "Broken Ogg stream (serialno) mismatch" ); - ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &oggpage ) ); + ogg_stream_reset_serialno( &p_stream->os, ogg_page_serialno( &p_sys->current_page ) ); p_stream->b_reinit = true; p_stream->i_pcr = -1; @@ -351,8 +289,11 @@ static int Demux( demux_t * p_demux ) es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); } - if( ogg_stream_pagein( &p_stream->os, &oggpage ) != 0 ) + if( ogg_stream_pagein( &p_stream->os, &p_sys->current_page ) != 0 ) + { continue; + } + } while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 ) @@ -378,8 +319,17 @@ static int Demux( demux_t * p_demux ) { p_stream->i_secondary_header_packets = 0; } + + /* update start of data pointer */ + p_stream->i_data_start = stream_Tell( p_demux->s ); + } + /* If any streams have i_skip_frames, only decode (pre-roll) + * for those streams */ + if ( b_skipping && p_stream->i_skip_frames == 0 ) continue; + + if( p_stream->b_reinit ) { /* If synchro is re-initialized we need to drop all the packets @@ -408,7 +358,7 @@ static int Demux( demux_t * p_demux ) else { es_out_Control( p_demux->out, ES_OUT_SET_PCR, - p_stream->i_pcr ); + VLC_TS_0 + p_stream->i_pcr ); } continue; } @@ -438,8 +388,8 @@ static int Demux( demux_t * p_demux ) p_sys->i_pcr = p_stream->i_interpolated_pcr; } - if( p_sys->i_pcr >= 0 ) - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pcr ); + if( p_sys->i_pcr >= 0 && ! b_skipping ) + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr ); return 1; } @@ -519,9 +469,9 @@ static int Ogg_ReadPage( demux_t *p_demux, ogg_page *p_oggpage ) while( ogg_sync_pageout( &p_ogg->oy, p_oggpage ) != 1 ) { - p_buffer = ogg_sync_buffer( &p_ogg->oy, OGG_BLOCK_SIZE ); + p_buffer = ogg_sync_buffer( &p_ogg->oy, OGGSEEK_BYTES_TO_READ ); - i_read = stream_Read( p_demux->s, p_buffer, OGG_BLOCK_SIZE ); + i_read = stream_Read( p_demux->s, p_buffer, OGGSEEK_BYTES_TO_READ ); if( i_read <= 0 ) return VLC_EGENERIC; @@ -549,8 +499,8 @@ static void Ogg_UpdatePCR( logical_stream_t *p_stream, ogg_int64_t pframe = p_oggpacket->granulepos - ( iframe << p_stream->i_granule_shift ); - p_stream->i_pcr = ( iframe + pframe ) * INT64_C(1000000) - / p_stream->f_rate; + p_stream->i_pcr = ( iframe + pframe - p_stream->i_keyframe_offset ) + * INT64_C(1000000) / p_stream->f_rate; } else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) { @@ -625,10 +575,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, if( p_stream->b_force_backup ) { - uint8_t *p_sav; - bool b_store_size = true; - bool b_store_num_headers = false; - + bool b_xiph; p_stream->i_packets_backup++; switch( p_stream->fmt.i_codec ) { @@ -636,6 +583,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, case VLC_CODEC_SPEEX: case VLC_CODEC_THEORA: if( p_stream->i_packets_backup == 3 ) p_stream->b_force_backup = 0; + b_xiph = true; break; case VLC_CODEC_FLAC: @@ -653,42 +601,46 @@ static void Ogg_DecodePacket( demux_t *p_demux, p_oggpacket->bytes -= 9; } } - b_store_size = false; + b_xiph = false; break; case VLC_CODEC_KATE: - if( p_stream->i_packets_backup == 1) - b_store_num_headers = true; if( p_stream->i_packets_backup == p_stream->i_kate_num_headers ) p_stream->b_force_backup = 0; + b_xiph = true; break; default: p_stream->b_force_backup = 0; + b_xiph = false; break; } /* Backup the ogg packet (likely an header packet) */ - p_stream->p_headers = - realloc( p_sav = p_stream->p_headers, p_stream->i_headers + - p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0) ); - if( p_stream->p_headers ) + if( !b_xiph ) { - uint8_t *p_extra = p_stream->p_headers + p_stream->i_headers; - - if( b_store_num_headers ) + void *p_org = p_stream->p_headers; + p_stream->i_headers += p_oggpacket->bytes; + p_stream->p_headers = realloc( p_stream->p_headers, p_stream->i_headers ); + if( p_stream->p_headers ) { - /* Kate streams store the number of headers in the first header, - so we can't just test for 3 as Vorbis/Theora */ - *(p_extra++) = p_stream->i_kate_num_headers; + memcpy( (unsigned char *)p_stream->p_headers + p_stream->i_headers - p_oggpacket->bytes, + p_oggpacket->packet, p_stream->i_headers ); } - if( b_store_size ) + else { - *(p_extra++) = p_oggpacket->bytes >> 8; - *(p_extra++) = p_oggpacket->bytes & 0xFF; + p_stream->i_headers = 0; + p_stream->p_headers = NULL; + free( p_org ); } - memcpy( p_extra, p_oggpacket->packet, p_oggpacket->bytes ); - p_stream->i_headers += p_oggpacket->bytes + (b_store_size ? 2 : 0) + (b_store_num_headers ? 1 : 0); - + } + else if( xiph_AppendHeaders( &p_stream->i_headers, &p_stream->p_headers, + p_oggpacket->bytes, p_oggpacket->packet ) ) + { + p_stream->i_headers = 0; + p_stream->p_headers = NULL; + } + if( p_stream->i_headers > 0 ) + { if( !p_stream->b_force_backup ) { /* Last header received, commit changes */ @@ -714,10 +666,6 @@ static void Ogg_DecodePacket( demux_t *p_demux, p_ogg->i_bos--; } } - else - { - p_stream->p_headers = p_sav; - } b_selected = false; /* Discard the header packet */ } @@ -738,7 +686,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, /* Call the pace control */ es_out_Control( p_demux->out, ES_OUT_SET_PCR, - p_stream->i_pcr ); + VLC_TS_0 + p_stream->i_pcr ); } p_stream->i_previous_pcr = p_stream->i_pcr; @@ -765,7 +713,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); /* Call the pace control */ - es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_stream->i_pcr ); + es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_stream->i_pcr ); } } } @@ -793,10 +741,19 @@ static void Ogg_DecodePacket( demux_t *p_demux, if( !( p_block = block_New( p_demux, p_oggpacket->bytes ) ) ) return; + + /* may need to preroll video frames after a seek */ + if ( p_stream->i_skip_frames > 0 ) + { + p_block->i_flags |= BLOCK_FLAG_PREROLL; + p_stream->i_skip_frames--; + } + + /* Normalize PTS */ - if( i_pts == 0 ) i_pts = 1; - else if( i_pts == -1 && i_interpolated_pts == 0 ) i_pts = 1; - else if( i_pts == -1 ) i_pts = 0; + if( i_pts == 0 ) i_pts = VLC_TS_0; + else if( i_pts == -1 && i_interpolated_pts == 0 ) i_pts = VLC_TS_0; + else if( i_pts == -1 ) i_pts = VLC_TS_INVALID; if( p_stream->fmt.i_cat == AUDIO_ES ) p_block->i_dts = p_block->i_pts = i_pts; @@ -806,7 +763,13 @@ static void Ogg_DecodePacket( demux_t *p_demux, p_block->i_length = 0; } else if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ) + { p_block->i_dts = p_block->i_pts = i_pts; + if( (p_oggpacket->granulepos & ((1<i_granule_shift)-1)) == 0 ) + { + p_block->i_flags |= BLOCK_FLAG_TYPE_I; + } + } else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) { ogg_int64_t dts = p_oggpacket->granulepos >> 31; @@ -815,15 +778,17 @@ static void Ogg_DecodePacket( demux_t *p_demux, uint64_t u_pnum = dts + delay; p_block->i_dts = p_stream->i_pcr; - p_block->i_pts = 0; + p_block->i_pts = VLC_TS_INVALID; /* NB, OggDirac granulepos values are in units of 2*picturerate */ + + /* granulepos for dirac is possibly broken, this value should be ignored */ if( -1 != p_oggpacket->granulepos ) p_block->i_pts = u_pnum * INT64_C(1000000) / p_stream->f_rate / 2; } else { p_block->i_dts = i_pts; - p_block->i_pts = 0; + p_block->i_pts = VLC_TS_INVALID; } if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS && @@ -897,17 +862,21 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) { demux_sys_t *p_ogg = p_demux->p_sys ; ogg_packet oggpacket; - ogg_page oggpage; int i_stream; - while( Ogg_ReadPage( p_demux, &oggpage ) == VLC_SUCCESS ) + p_ogg->i_total_length = stream_Size ( p_demux->s ); + msg_Dbg( p_demux, "File length is %"PRId64" bytes", p_ogg->i_total_length ); + + + while( Ogg_ReadPage( p_demux, &p_ogg->current_page ) == VLC_SUCCESS ) { - if( ogg_page_bos( &oggpage ) ) + + if( ogg_page_bos( &p_ogg->current_page ) ) { /* All is wonderful in our fine fine little world. * We found the beginning of our first logical stream. */ - while( ogg_page_bos( &oggpage ) ) + while( ogg_page_bos( &p_ogg->current_page ) ) { logical_stream_t *p_stream; @@ -921,16 +890,21 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) p_stream->p_headers = 0; p_stream->i_secondary_header_packets = 0; + p_stream->i_keyframe_offset = 0; + p_stream->i_skip_frames = 0; + + p_stream->i_data_start = 0; + es_format_Init( &p_stream->fmt, 0, 0 ); es_format_Init( &p_stream->fmt_old, 0, 0 ); /* Setup the logical stream */ - p_stream->i_serial_no = ogg_page_serialno( &oggpage ); + p_stream->i_serial_no = ogg_page_serialno( &p_ogg->current_page ); ogg_stream_init( &p_stream->os, p_stream->i_serial_no ); /* Extract the initial header from the first page and verify * the codec type of this Ogg bitstream */ - if( ogg_stream_pagein( &p_stream->os, &oggpage ) < 0 ) + if( ogg_stream_pagein( &p_stream->os, &p_ogg->current_page ) < 0 ) { /* error. stream version mismatch perhaps */ msg_Err( p_demux, "error reading first page of " @@ -1002,8 +976,10 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) p_stream->fmt.i_bitrate, p_stream->f_rate ); } /* Check for Dirac header */ - else if( oggpacket.bytes >= 5 && - ! memcmp( oggpacket.packet, "BBCD\x00", 5 ) ) + else if( ( oggpacket.bytes >= 5 && + ! memcmp( oggpacket.packet, "BBCD\x00", 5 ) ) || + ( oggpacket.bytes >= 9 && + ! memcmp( oggpacket.packet, "KW-DIRAC\x00", 9 ) ) ) { if( Ogg_ReadDiracHeader( p_stream, &oggpacket ) ) msg_Dbg( p_demux, "found dirac header" ); @@ -1103,7 +1079,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) /* Check for audio header (old format) */ else if( GetDWLE((oggpacket.packet+96)) == 0x05589F81 ) { - unsigned int i_extra_size; + int i_extra_size; unsigned int i_format_tag; p_stream->fmt.i_cat = AUDIO_ES; @@ -1214,7 +1190,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) else if( !strncmp( st->streamtype, "audio", 5 ) ) { char p_buffer[5]; - unsigned int i_extra_size; + int i_extra_size; int i_format_tag; st->sh.audio.channels = GetWLE( &oggpacket.packet[1+44] ); @@ -1308,7 +1284,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) p_ogg->i_streams--; } - if( Ogg_ReadPage( p_demux, &oggpage ) != VLC_SUCCESS ) + if( Ogg_ReadPage( p_demux, &p_ogg->current_page ) != VLC_SUCCESS ) return VLC_EGENERIC; } @@ -1328,7 +1304,7 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) for( i_stream = 0; i_stream < p_ogg->i_streams; i_stream++ ) { if( ogg_stream_pagein( &p_ogg->pp_stream[i_stream]->os, - &oggpage ) == 0 ) + &p_ogg->current_page ) == 0 ) { p_ogg->b_page_waiting = true; break; @@ -1368,6 +1344,9 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) p_stream->p_es = NULL; + /* initialise kframe index */ + p_stream->idx=NULL; + /* Try first to reuse an old ES */ if( p_old_stream && p_old_stream->fmt.i_cat == p_stream->fmt.i_cat && @@ -1413,6 +1392,11 @@ static int Ogg_BeginningOfStream( demux_t *p_demux ) Ogg_LogicalStreamDelete( p_demux, p_ogg->p_old_stream ); p_ogg->p_old_stream = NULL; } + + + /* get total frame count for video stream; we will need this for seeking */ + p_ogg->i_total_frames = 0; + return VLC_SUCCESS; } @@ -1453,6 +1437,11 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea es_format_Clean( &p_stream->fmt_old ); es_format_Clean( &p_stream->fmt ); + if ( p_stream->idx != NULL) + { + oggseek_index_entries_free( p_stream->idx ); + } + free( p_stream ); } /** @@ -1461,33 +1450,34 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea */ static bool Ogg_IsVorbisFormatCompatible( const es_format_t *p_new, const es_format_t *p_old ) { - int i_new = 0; - int i_old = 0; - int i; - - for( i = 0; i < 3; i++ ) + unsigned pi_new_size[XIPH_MAX_HEADER_COUNT]; + void *pp_new_data[XIPH_MAX_HEADER_COUNT]; + unsigned i_new_count; + if( xiph_SplitHeaders(pi_new_size, pp_new_data, &i_new_count, p_new->i_extra, p_new->p_extra ) ) + i_new_count = 0; + + unsigned pi_old_size[XIPH_MAX_HEADER_COUNT]; + void *pp_old_data[XIPH_MAX_HEADER_COUNT]; + unsigned i_old_count; + if( xiph_SplitHeaders(pi_old_size, pp_old_data, &i_old_count, p_old->i_extra, p_old->p_extra ) ) + i_old_count = 0; + + bool b_match = i_new_count == i_old_count; + for( unsigned i = 0; i < i_new_count && b_match; i++ ) { - const uint8_t *p_new_extra = ( const uint8_t*)p_new->p_extra + i_new; - const uint8_t *p_old_extra = ( const uint8_t*)p_old->p_extra + i_old; - - if( p_new->i_extra < i_new+2 || p_old->i_extra < i_old+2 ) - return false; - - const int i_new_size = GetWBE( &p_new_extra[0] ); - const int i_old_size = GetWBE( &p_old_extra[0] ); - - if( i != 1 ) /* Ignore vorbis comment */ - { - if( i_new_size != i_old_size ) - return false; - if( memcmp( &p_new_extra[2], &p_old_extra[2], i_new_size ) ) - return false; - } - - i_new += 2 + i_new_size; - i_old += 2 + i_old_size; + /* Ignore vorbis comment */ + if( i == 1 ) + continue; + if( pi_new_size[i] != pi_old_size[i] || + memcmp( pp_new_data[i], pp_old_data[i], pi_new_size[i] ) ) + b_match = false; } - return true; + + for( unsigned i = 0; i < i_new_count; i++ ) + free( pp_new_data[i] ); + for( unsigned i = 0; i < i_old_count; i++ ) + free( pp_old_data[i] ); + return b_match; } static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t *p_stream ) { @@ -1504,44 +1494,22 @@ static bool Ogg_LogicalStreamResetEsFormat( demux_t *p_demux, logical_stream_t * return !b_compatible; } -static void Ogg_ExtractXiphMeta( demux_t *p_demux, const uint8_t *p_headers, int i_headers, int i_skip, bool b_has_num_headers ) +static void Ogg_ExtractXiphMeta( demux_t *p_demux, const void *p_headers, unsigned i_headers, unsigned i_skip ) { demux_sys_t *p_ogg = p_demux->p_sys; - if (b_has_num_headers) - { - if (i_headers <= 0) - return; - /* number of headers on a byte, we're interested in the second header, so should be at least 2 to go on */ - if (*p_headers++ < 2) - return; - --i_headers; - } - - if( i_headers <= 2 ) - return; - - /* Skip first packet */ - const int i_tmp = GetWBE( &p_headers[0] ); - if( i_tmp > i_headers-2 ) - return; - p_headers += 2 + i_tmp; - i_headers -= 2 + i_tmp; - - if( i_headers <= 2 ) - return; - - /* */ - int i_comment = GetWBE( &p_headers[0] ); - const uint8_t *p_comment = &p_headers[2]; - if( i_comment > i_headers - 2 ) - return; - - if( i_comment <= i_skip ) + unsigned pi_size[XIPH_MAX_HEADER_COUNT]; + void *pp_data[XIPH_MAX_HEADER_COUNT]; + unsigned i_count; + if( xiph_SplitHeaders( pi_size, pp_data, &i_count, i_headers, p_headers ) ) return; /* TODO how to handle multiple comments properly ? */ - vorbis_ParseComment( &p_ogg->p_meta, &p_comment[i_skip], i_comment - i_skip ); + if( i_count >= 2 && pi_size[1] > i_skip ) + vorbis_ParseComment( &p_ogg->p_meta, (uint8_t*)pp_data[1] + i_skip, pi_size[1] - i_skip ); + + for( unsigned i = 0; i < i_count; i++ ) + free( pp_data[i] ); } static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8_t *p_headers, int i_headers ) { @@ -1549,21 +1517,21 @@ static void Ogg_ExtractMeta( demux_t *p_demux, vlc_fourcc_t i_codec, const uint8 switch( i_codec ) { - /* 3 headers with the 2° one being the comments */ + /* 3 headers with the 2° one being the comments */ case VLC_CODEC_VORBIS: - Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6, false ); + Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 ); break; case VLC_CODEC_THEORA: - Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6, false ); + Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+6 ); break; case VLC_CODEC_SPEEX: - Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0, false ); + Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 0 ); break; - /* N headers with the 2° one being the comments */ + /* N headers with the 2° one being the comments */ case VLC_CODEC_KATE: - /* 1 byte for header type, 7 bit for magic, 1 reserved zero byte */ - Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+7+1, true ); + /* 1 byte for header type, 7 bytes for magic, 1 reserved zero byte */ + Ogg_ExtractXiphMeta( p_demux, p_headers, i_headers, 1+7+1 ); break; /* TODO */ @@ -1588,6 +1556,10 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream, int i_fps_numerator; int i_fps_denominator; int i_keyframe_frequency_force; + int i_major; + int i_minor; + int i_subminor; + int i_version; p_stream->fmt.i_cat = VIDEO_ES; p_stream->fmt.i_codec = VLC_CODEC_THEORA; @@ -1600,9 +1572,11 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream, /* Cheat and get additionnal info ;) */ bs_init( &bitstream, p_oggpacket->packet, p_oggpacket->bytes ); bs_skip( &bitstream, 56 ); - bs_read( &bitstream, 8 ); /* major version num */ - bs_read( &bitstream, 8 ); /* minor version num */ - bs_read( &bitstream, 8 ); /* subminor version num */ + + i_major = bs_read( &bitstream, 8 ); /* major version num */ + i_minor = bs_read( &bitstream, 8 ); /* minor version num */ + i_subminor = bs_read( &bitstream, 8 ); /* subminor version num */ + bs_read( &bitstream, 16 ) /*<< 4*/; /* width */ bs_read( &bitstream, 16 ) /*<< 4*/; /* height */ bs_read( &bitstream, 24 ); /* frame width */ @@ -1633,6 +1607,14 @@ static void Ogg_ReadTheoraHeader( logical_stream_t *p_stream, i_keyframe_frequency_force >>= 1; } + i_version = i_major * 1000000 + i_minor * 1000 + i_subminor; + p_stream->i_keyframe_offset = 0; + + if ( i_version >= 3002001 ) + { + p_stream->i_keyframe_offset = 1; + } + p_stream->f_rate = ((float)i_fps_numerator) / i_fps_denominator; } @@ -1826,7 +1808,7 @@ static void Ogg_ReadAnnodexHeader( vlc_object_t *p_this, uint8_t *p = memchr( &p_oggpacket->packet[42], '\r', p_oggpacket->bytes - 1 ); if( p && p[0] == '\r' && p[1] == '\n' ) - sscanf( (char*)(&p_oggpacket->packet[42]), "%1024s\r\n", + sscanf( (char*)(&p_oggpacket->packet[42]), "%1023s\r\n", content_type_string ); }