2002-03-16 14:32:03 +00:00
# include "config.h"
2002-09-15 22:38:30 +00:00
# ifdef HAVE_OGGVORBIS
2002-03-16 14:32:03 +00:00
# include <stdlib.h>
# include <stdio.h>
2002-10-22 15:41:41 +00:00
# include <string.h>
2003-05-11 16:39:16 +00:00
# include <assert.h>
# include <math.h>
2002-03-16 14:32:03 +00:00
# include "../mp_msg.h"
# include "../help_mp.h"
# include "stream.h"
# include "demuxer.h"
# include "stheader.h"
2002-12-04 20:27:36 +00:00
# ifdef TREMOR
# include <tremor/ogg.h>
# include <tremor/ivorbiscodec.h>
# else
2002-03-16 14:32:03 +00:00
# include <ogg/ogg.h>
# include <vorbis/codec.h>
2002-12-04 20:27:36 +00:00
# endif
2002-03-16 14:32:03 +00:00
2003-05-11 16:39:16 +00:00
# ifdef HAVE_OGGTHEORA
# include <theora/theora.h>
# endif
2002-04-24 12:28:03 +00:00
# define BLOCK_SIZE 4096
2002-03-16 14:32:03 +00:00
/// Vorbis decoder context : we need the vorbis_info for vorbis timestamping
/// Shall we put this struct def in a common header ?
typedef struct ov_struct_st {
vorbis_info vi ; /* struct that stores all the static vorbis bitstream
settings */
2002-12-05 21:04:26 +00:00
vorbis_comment vc ; /* struct that stores all the bitstream user comments */
2002-03-16 14:32:03 +00:00
vorbis_dsp_state vd ; /* central working state for the packet->PCM decoder */
vorbis_block vb ; /* local working space for packet->PCM decode */
2002-12-05 21:01:59 +00:00
float rg_scale ; /* replaygain scale */
# ifdef TREMOR
int rg_scale_int ;
# endif
2002-03-16 14:32:03 +00:00
} ov_struct_t ;
2003-05-11 16:39:16 +00:00
/* Theora decoder context : we won't be able to interpret granule positions
* without using theora_granule_time with the theora_state of the stream .
* This is duplicated in ` vd_theora . c ' ; put this in a common header ?
*/
# ifdef HAVE_OGGTHEORA
typedef struct theora_struct_st {
theora_state st ;
2003-08-18 13:13:41 +00:00
theora_comment cc ;
2003-05-11 16:39:16 +00:00
theora_info inf ;
} theora_struct_t ;
# endif
2002-03-16 14:32:03 +00:00
//// OggDS headers
// Header for the new header format
typedef struct stream_header_video
{
ogg_int32_t width ;
ogg_int32_t height ;
} stream_header_video ;
typedef struct stream_header_audio
{
ogg_int16_t channels ;
ogg_int16_t blockalign ;
ogg_int32_t avgbytespersec ;
} stream_header_audio ;
typedef struct stream_header
{
char streamtype [ 8 ] ;
char subtype [ 4 ] ;
ogg_int32_t size ; // size of the structure
ogg_int64_t time_unit ; // in reference time
ogg_int64_t samples_per_unit ;
ogg_int32_t default_len ; // in media time
ogg_int32_t buffersize ;
ogg_int16_t bits_per_sample ;
union
{
// Video specific
stream_header_video video ;
// Audio specific
stream_header_audio audio ;
} sh ;
} stream_header ;
/// Our private datas
2002-04-20 17:50:11 +00:00
typedef struct ogg_syncpoint {
int64_t granulepos ;
off_t page_pos ;
} ogg_syncpoint_t ;
2002-03-16 14:32:03 +00:00
/// A logical stream
typedef struct ogg_stream {
/// Timestamping stuff
float samplerate ; /// granulpos 2 time
int64_t lastpos ;
int32_t lastsize ;
// Logical stream state
ogg_stream_state stream ;
2002-04-20 17:50:11 +00:00
int hdr_packets ;
int vorbis ;
2003-05-11 16:39:16 +00:00
int theora ;
2003-10-04 22:00:25 +00:00
int flac ;
2002-03-16 14:32:03 +00:00
} ogg_stream_t ;
typedef struct ogg_demuxer {
/// Physical stream state
ogg_sync_state sync ;
/// Current page
ogg_page page ;
/// Logical streams
ogg_stream_t * subs ;
int num_sub ;
2002-04-20 17:50:11 +00:00
ogg_syncpoint_t * syncpoints ;
int num_syncpoint ;
2002-04-24 12:28:03 +00:00
off_t pos , last_size ;
2003-12-08 09:47:15 +00:00
int64_t final_granulepos ;
2002-03-16 14:32:03 +00:00
} ogg_demuxer_t ;
2002-04-20 17:50:11 +00:00
# define NUM_VORBIS_HDR_PACKETS 3
2002-03-16 14:32:03 +00:00
/// Some defines from OggDS
# define PACKET_TYPE_HEADER 0x01
# define PACKET_TYPE_BITS 0x07
# define PACKET_LEN_BITS01 0xc0
# define PACKET_LEN_BITS2 0x02
# define PACKET_IS_SYNCPOINT 0x08
2002-04-24 12:28:03 +00:00
extern int index_mode ;
2002-08-14 23:41:19 +00:00
//-------- subtitle support - should be moved to decoder layer, and queue
// - subtitles up in demuxer buffer...
# include "../subreader.h"
# include "../libvo/sub.h"
# define OGG_SUB_MAX_LINE 128
static subtitle ogg_sub ;
extern subtitle * vo_sub ;
2003-01-04 22:56:56 +00:00
static float clear_sub ;
2002-08-14 23:41:19 +00:00
//FILE* subout;
2002-10-22 15:41:41 +00:00
static
uint16_t get_uint16 ( const void * buf )
{
uint16_t ret ;
unsigned char * tmp ;
tmp = ( unsigned char * ) buf ;
ret = tmp [ 1 ] & 0xff ;
ret = ( ret < < 8 ) + ( tmp [ 0 ] & 0xff ) ;
return ( ret ) ;
}
static
uint32_t get_uint32 ( const void * buf )
{
uint32_t ret ;
unsigned char * tmp ;
tmp = ( unsigned char * ) buf ;
ret = tmp [ 3 ] & 0xff ;
ret = ( ret < < 8 ) + ( tmp [ 2 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 1 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 0 ] & 0xff ) ;
return ( ret ) ;
}
static
uint64_t get_uint64 ( const void * buf )
{
uint64_t ret ;
unsigned char * tmp ;
tmp = ( unsigned char * ) buf ;
ret = tmp [ 7 ] & 0xff ;
ret = ( ret < < 8 ) + ( tmp [ 6 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 5 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 4 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 3 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 2 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 1 ] & 0xff ) ;
ret = ( ret < < 8 ) + ( tmp [ 0 ] & 0xff ) ;
return ( ret ) ;
}
2002-08-14 23:41:19 +00:00
void demux_ogg_init_sub ( ) {
int lcv ;
if ( ! ogg_sub . text [ 0 ] ) // not yet allocated
for ( lcv = 0 ; lcv < SUB_MAX_TEXT ; lcv + + ) {
ogg_sub . text [ lcv ] = ( char * ) malloc ( OGG_SUB_MAX_LINE ) ;
}
}
2003-01-04 22:56:56 +00:00
void demux_ogg_add_sub ( ogg_stream_t * os , ogg_packet * pack ) {
2002-08-14 23:41:19 +00:00
int lcv ;
int line_pos = 0 ;
int ignoring = 0 ;
2003-01-04 22:56:56 +00:00
char * packet = pack - > packet ;
2002-08-14 23:41:19 +00:00
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " \n demux_ogg_add_sub %02X %02X %02X '%s' \n " ,
( unsigned char ) packet [ 0 ] ,
( unsigned char ) packet [ 1 ] ,
( unsigned char ) packet [ 2 ] ,
& packet [ 3 ] ) ;
ogg_sub . lines = 0 ;
if ( ( ( unsigned char ) packet [ 0 ] ) = = 0x88 ) { // some subtitle text
2003-01-04 22:56:56 +00:00
// Find data start
int32_t duration = 0 ;
int16_t hdrlen = ( * packet & PACKET_LEN_BITS01 ) > > 6 , i ;
hdrlen | = ( * packet & PACKET_LEN_BITS2 ) < < 1 ;
lcv = 1 + hdrlen ;
for ( i = hdrlen ; i > 0 ; i - - ) {
duration < < = 8 ;
duration | = ( unsigned char ) packet [ i ] ;
}
if ( ( hdrlen > 0 ) & & ( duration > 0 ) ) {
float pts ;
if ( pack - > granulepos = = - 1 )
pack - > granulepos = os - > lastpos + os - > lastsize ;
pts = ( float ) pack - > granulepos / ( float ) os - > samplerate ;
2003-10-15 16:46:55 +00:00
clear_sub = 0.001 + pts + ( float ) duration / 1000.0 ;
2003-01-04 22:56:56 +00:00
}
2002-08-14 23:41:19 +00:00
while ( 1 ) {
int c = packet [ lcv + + ] ;
2002-08-28 17:07:55 +00:00
if ( c = = ' \n ' | | c = = 0 | | line_pos > = OGG_SUB_MAX_LINE - 1 ) {
2002-08-14 23:41:19 +00:00
ogg_sub . text [ ogg_sub . lines ] [ line_pos ] = 0 ; // close sub
if ( line_pos ) ogg_sub . lines + + ;
if ( ! c | | ogg_sub . lines > = SUB_MAX_TEXT ) break ; // EOL or TooMany
line_pos = 0 ;
}
switch ( c ) {
case ' \r ' :
case ' \n ' : // just ignore linefeeds for now
// their placement seems rather haphazard
break ;
case ' < ' : // some html markup, ignore for now
ignoring = 1 ;
break ;
case ' > ' :
ignoring = 0 ;
break ;
default :
2002-08-28 17:07:55 +00:00
if ( ! ignoring )
2002-08-14 23:41:19 +00:00
ogg_sub . text [ ogg_sub . lines ] [ line_pos + + ] = c ;
break ;
}
}
}
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " ogg sub lines: %d first: '%s' \n " ,
ogg_sub . lines , ogg_sub . text [ 0 ] ) ;
2002-12-28 15:19:41 +00:00
# ifdef USE_ICONV
subcp_recode1 ( & ogg_sub ) ;
# endif
2002-08-14 23:41:19 +00:00
vo_sub = & ogg_sub ;
vo_osd_changed ( OSDTYPE_SUBTITLE ) ;
}
2002-03-16 14:32:03 +00:00
// get the logical stream of the current page
// fill os if non NULL and return the stream id
static int demux_ogg_get_page_stream ( ogg_demuxer_t * ogg_d , ogg_stream_state * * os ) {
int id , s_no ;
ogg_page * page = & ogg_d - > page ;
s_no = ogg_page_serialno ( page ) ;
for ( id = 0 ; id < ogg_d - > num_sub ; id + + ) {
if ( s_no = = ogg_d - > subs [ id ] . stream . serialno )
break ;
}
2003-07-02 20:43:07 +00:00
if ( id = = ogg_d - > num_sub ) {
// If we have only one vorbis stream allow the stream id to change
// it's normal on radio stream (each song have an different id).
// But we (or the codec?) should check that the samplerate, etc
// doesn't change (for radio stream it's ok)
if ( ogg_d - > num_sub = = 1 & & ogg_d - > subs [ 0 ] . vorbis ) {
ogg_stream_reset ( & ogg_d - > subs [ 0 ] . stream ) ;
ogg_stream_init ( & ogg_d - > subs [ 0 ] . stream , s_no ) ;
id = 0 ;
} else
return - 1 ;
}
2002-03-16 14:32:03 +00:00
if ( os )
* os = & ogg_d - > subs [ id ] . stream ;
return id ;
}
2003-05-11 16:39:16 +00:00
static unsigned char * demux_ogg_read_packet ( ogg_stream_t * os , ogg_packet * pack , void * context , float * pts , int * flags ) {
2002-03-16 14:32:03 +00:00
unsigned char * data ;
2002-04-20 17:50:11 +00:00
* pts = 0 ;
* flags = 0 ;
2002-03-16 14:32:03 +00:00
2002-04-20 17:50:11 +00:00
if ( os - > vorbis ) {
2002-03-16 14:32:03 +00:00
data = pack - > packet ;
if ( * pack - > packet & PACKET_TYPE_HEADER )
2002-04-20 17:50:11 +00:00
os - > hdr_packets + + ;
2003-05-11 16:39:16 +00:00
else if ( context )
{
vorbis_info * vi = & ( ( ov_struct_t * ) context ) - > vi ;
2003-10-04 17:29:08 +00:00
// When we dump the audio, there is no vi, but we don't care of timestamp in this case
2003-05-11 16:39:16 +00:00
int32_t blocksize = vorbis_packet_blocksize ( vi , pack ) / vi - > channels ;
// Calculate the timestamp if the packet don't have any
if ( pack - > granulepos = = - 1 ) {
pack - > granulepos = os - > lastpos ;
if ( os - > lastsize > 0 )
pack - > granulepos + = os - > lastsize ;
}
* pts = pack - > granulepos / ( float ) vi - > rate ;
os - > lastsize = blocksize ;
os - > lastpos = pack - > granulepos ;
2002-03-16 14:32:03 +00:00
}
2003-05-11 16:39:16 +00:00
# ifdef HAVE_OGGTHEORA
} else if ( os - > theora ) {
/* we pass complete packets to theora, mustn't strip the header! */
data = pack - > packet ;
os - > lastsize = 1 ;
2003-08-28 17:32:28 +00:00
/* header packets beginn on 1-bit: thus check (*data&0x80). We don't
have theora_state st , until all header packets were passed to the
decoder . */
if ( context ! = NULL & & ! ( * data & 0x80 ) )
2003-05-11 16:39:16 +00:00
{
theora_state * st ;
int64_t usable_granulepos ;
st = & ( ( theora_struct_t * ) context ) - > st ;
* pts = theora_granule_time ( st , pack - > granulepos ) ;
if ( * pts > = 0 )
{
usable_granulepos = ( int64_t ) ceil ( * pts * os - > samplerate - 0.5 ) ;
os - > lastpos = usable_granulepos ;
}
else
{
os - > lastpos + + ;
* pts = ( double ) os - > lastpos / ( double ) os - > samplerate ;
}
}
# endif /* HAVE_OGGTHEORA */
2003-10-04 22:00:25 +00:00
# ifdef HAVE_FLAC
} else if ( os - > flac ) {
/* we pass complete packets to flac, mustn't strip the header! */
data = pack - > packet ;
# endif /* HAVE_FLAC */
2002-03-16 14:32:03 +00:00
} else {
// Find data start
int16_t hdrlen = ( * pack - > packet & PACKET_LEN_BITS01 ) > > 6 ;
hdrlen | = ( * pack - > packet & PACKET_LEN_BITS2 ) < < 1 ;
data = pack - > packet + 1 + hdrlen ;
// Calculate the timestamp
if ( pack - > granulepos = = - 1 )
pack - > granulepos = os - > lastpos + os - > lastsize ;
// If we alredy have a timestamp it can be a syncpoint
2002-04-20 17:50:11 +00:00
if ( * pack - > packet & PACKET_IS_SYNCPOINT )
* flags = 1 ;
* pts = pack - > granulepos / os - > samplerate ;
2002-03-16 14:32:03 +00:00
// Save the packet length and timestamp
os - > lastsize = 0 ;
while ( hdrlen ) {
os - > lastsize < < = 8 ;
os - > lastsize | = pack - > packet [ hdrlen ] ;
hdrlen - - ;
}
os - > lastpos = pack - > granulepos ;
}
2002-04-20 17:50:11 +00:00
return data ;
}
/// Calculate the timestamp and add the packet to the demux stream
// return 1 if the packet was added, 0 otherwise
static int demux_ogg_add_packet ( demux_stream_t * ds , ogg_stream_t * os , ogg_packet * pack ) {
demuxer_t * d = ds - > demuxer ;
demux_packet_t * dp ;
unsigned char * data ;
float pts = 0 ;
int flags = 0 ;
2003-05-11 16:39:16 +00:00
void * context = NULL ;
2002-04-20 17:50:11 +00:00
2002-08-14 23:41:19 +00:00
if ( ds = = d - > sub ) { // don't want to add subtitles to the demuxer for now
2003-01-04 22:56:56 +00:00
demux_ogg_add_sub ( os , pack ) ;
2002-08-14 23:41:19 +00:00
return 0 ;
}
2003-05-11 16:39:16 +00:00
// If packet is an header we jump it except for vorbis and theora
// (PACKET_TYPE_HEADER bit doesn't even exist for theora ?!)
2003-11-15 20:00:31 +00:00
// We jump nothing for FLAC. Ain't this great? Packet contents have to be
// handled differently for each and every stream type. The joy! The joy!
if ( ! os - > flac & & ( ( * pack - > packet & PACKET_TYPE_HEADER ) & &
2003-05-11 16:39:16 +00:00
( ds ! = d - > audio | | ( ( ( sh_audio_t * ) ds - > sh ) - > format ! = 0xFFFE | | os - > hdr_packets > = NUM_VORBIS_HDR_PACKETS ) ) & &
2003-11-15 20:00:31 +00:00
( ds ! = d - > video | | ( ( ( sh_video_t * ) ds - > sh ) - > format ! = 0xFFFC ) ) ) )
2002-04-20 17:50:11 +00:00
return 0 ;
2003-05-11 16:39:16 +00:00
// For vorbis packet the packet is the data, for other codec we must jump
// the header
2002-04-20 17:50:11 +00:00
if ( ds = = d - > audio & & ( ( sh_audio_t * ) ds - > sh ) - > format = = 0xFFFE )
2003-05-11 16:39:16 +00:00
context = ( ( sh_audio_t * ) ds - > sh ) - > context ;
if ( ds = = d - > video & & ( ( sh_audio_t * ) ds - > sh ) - > format = = 0xFFFC )
context = ( ( sh_video_t * ) ds - > sh ) - > context ;
data = demux_ogg_read_packet ( os , pack , context , & pts , & flags ) ;
2004-01-06 11:22:32 +00:00
if ( d - > video - > id < 0 )
( ( sh_audio_t * ) ds - > sh ) - > delay = pts ;
2002-04-20 17:50:11 +00:00
2003-01-04 22:56:56 +00:00
/// Clear subtitles if necessary (for broken files)
if ( ( clear_sub > 0 ) & & ( pts > = clear_sub ) ) {
ogg_sub . lines = 0 ;
vo_sub = & ogg_sub ;
vo_osd_changed ( OSDTYPE_SUBTITLE ) ;
clear_sub = - 1 ;
}
2002-03-16 14:32:03 +00:00
/// Send the packet
dp = new_demux_packet ( pack - > bytes - ( data - pack - > packet ) ) ;
memcpy ( dp - > buffer , data , pack - > bytes - ( data - pack - > packet ) ) ;
2002-03-31 20:09:17 +00:00
dp - > pts = pts ;
dp - > flags = flags ;
2002-03-16 14:32:03 +00:00
ds_add_packet ( ds , dp ) ;
2002-03-31 20:09:17 +00:00
if ( verbose > 1 ) printf ( " New dp: %p ds=%p pts=%5.3f len=%d flag=%d \n " ,
dp , ds , pts , dp - > len , flags ) ;
2002-03-16 14:32:03 +00:00
return 1 ;
}
2002-04-20 17:50:11 +00:00
/// Build a table of all syncpoints to make seeking easier
2003-12-08 09:47:15 +00:00
void demux_ogg_scan_stream ( demuxer_t * demuxer ) {
2002-04-20 17:50:11 +00:00
ogg_demuxer_t * ogg_d = demuxer - > priv ;
stream_t * s = demuxer - > stream ;
ogg_sync_state * sync = & ogg_d - > sync ;
ogg_page * page = & ogg_d - > page ;
ogg_stream_state * oss ;
ogg_stream_t * os ;
ogg_packet op ;
int np , sid , p ;
2003-05-11 16:39:16 +00:00
void * context = NULL ;
2002-04-20 17:50:11 +00:00
off_t pos , last_pos ;
pos = last_pos = demuxer - > movi_start ;
// Reset the stream
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) {
2002-04-20 17:50:11 +00:00
stream_seek ( s , demuxer - > movi_start ) ;
2003-12-08 09:47:15 +00:00
}
else {
stream_seek ( s , demuxer - > movi_end - 20 * BLOCK_SIZE ) ;
}
2002-04-20 17:50:11 +00:00
ogg_sync_reset ( sync ) ;
// Get the serial number of the stream we use
2003-05-11 16:39:16 +00:00
if ( demuxer - > video - > id > = 0 ) {
2002-04-20 17:50:11 +00:00
sid = demuxer - > video - > id ;
2003-05-11 16:39:16 +00:00
/* demux_ogg_read_packet needs decoder context for Theora streams */
if ( ( ( sh_video_t * ) demuxer - > video - > sh ) - > format = = 0xFFFC )
context = ( ( sh_video_t * ) demuxer - > video - > sh ) - > context ;
}
2002-04-20 17:50:11 +00:00
else {
sid = demuxer - > audio - > id ;
2003-05-11 16:39:16 +00:00
/* demux_ogg_read_packet needs decoder context for Vorbis streams */
2002-04-20 17:50:11 +00:00
if ( ( ( sh_audio_t * ) demuxer - > audio - > sh ) - > format = = 0xFFFE )
2003-05-11 16:39:16 +00:00
context = ( ( sh_audio_t * ) demuxer - > audio - > sh ) - > context ;
2002-04-20 17:50:11 +00:00
}
os = & ogg_d - > subs [ sid ] ;
oss = & os - > stream ;
while ( 1 ) {
np = ogg_sync_pageseek ( sync , page ) ;
if ( np < 0 ) { // We had to skip some bytes
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) mp_msg ( MSGT_DEMUX , MSGL_ERR , " Bad page sync while building syncpoints table (%d) \n " , - np ) ;
2002-04-20 17:50:11 +00:00
pos + = - np ;
continue ;
}
if ( np < = 0 ) { // We need more data
char * buf = ogg_sync_buffer ( sync , BLOCK_SIZE ) ;
int len = stream_read ( s , buf , BLOCK_SIZE ) ;
if ( len = = 0 & & s - > eof )
break ;
ogg_sync_wrote ( sync , len ) ;
continue ;
}
// The page is ready
//ogg_sync_pageout(sync,page);
if ( ogg_page_serialno ( page ) ! = os - > stream . serialno ) { // It isn't a page from the stream we want
pos + = np ;
continue ;
}
if ( ogg_stream_pagein ( oss , page ) ! = 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_ERR , " Pagein error ???? \n " ) ;
pos + = np ;
continue ;
}
p = 0 ;
while ( ogg_stream_packetout ( oss , & op ) = = 1 ) {
float pts ;
int flags ;
2003-05-11 16:39:16 +00:00
demux_ogg_read_packet ( os , & op , context , & pts , & flags ) ;
2002-04-20 17:50:11 +00:00
if ( flags | | ( os - > vorbis & & op . granulepos > = 0 ) ) {
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) {
2002-04-20 17:50:11 +00:00
ogg_d - > syncpoints = ( ogg_syncpoint_t * ) realloc ( ogg_d - > syncpoints , ( ogg_d - > num_syncpoint + 1 ) * sizeof ( ogg_syncpoint_t ) ) ;
ogg_d - > syncpoints [ ogg_d - > num_syncpoint ] . granulepos = op . granulepos ;
ogg_d - > syncpoints [ ogg_d - > num_syncpoint ] . page_pos = ( ogg_page_continued ( page ) & & p = = 0 ) ? last_pos : pos ;
ogg_d - > num_syncpoint + + ;
2003-12-08 09:47:15 +00:00
}
ogg_d - > final_granulepos = op . granulepos ;
2002-04-20 17:50:11 +00:00
}
p + + ;
}
2002-04-24 12:28:03 +00:00
if ( p > 1 | | ( p = = 1 & & ! ogg_page_continued ( page ) ) )
2002-04-20 17:50:11 +00:00
last_pos = pos ;
pos + = np ;
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) mp_msg ( MSGT_DEMUX , MSGL_INFO , " Building syncpoint table %d%% \r " , ( int ) ( pos * 100 / s - > end_pos ) ) ;
2002-04-20 17:50:11 +00:00
}
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) mp_msg ( MSGT_DEMUX , MSGL_INFO , " \n " ) ;
2002-04-20 17:50:11 +00:00
2003-12-08 09:47:15 +00:00
if ( index_mode = = 2 ) mp_msg ( MSGT_DEMUX , MSGL_V , " Ogg syncpoints table builed: %d syncpoints \n " , ogg_d - > num_syncpoint ) ;
2003-12-08 09:51:10 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " Ogg stream length (granulepos): %lld \n " , ogg_d - > final_granulepos ) ;
2002-04-20 17:50:11 +00:00
stream_reset ( s ) ;
stream_seek ( s , demuxer - > movi_start ) ;
ogg_sync_reset ( sync ) ;
for ( np = 0 ; np < ogg_d - > num_sub ; np + + ) {
ogg_stream_reset ( & ogg_d - > subs [ np ] . stream ) ;
ogg_d - > subs [ np ] . lastpos = ogg_d - > subs [ np ] . lastsize = ogg_d - > subs [ np ] . hdr_packets = 0 ;
}
// Get the first page
while ( 1 ) {
np = ogg_sync_pageout ( sync , page ) ;
if ( np < = 0 ) { // We need more data
char * buf = ogg_sync_buffer ( sync , BLOCK_SIZE ) ;
int len = stream_read ( s , buf , BLOCK_SIZE ) ;
if ( len = = 0 & & s - > eof ) {
mp_msg ( MSGT_DEMUX , MSGL_ERR , " EOF while trying to get the first page !!!! \n " ) ;
break ;
}
ogg_sync_wrote ( sync , len ) ;
continue ;
}
demux_ogg_get_page_stream ( ogg_d , & oss ) ;
ogg_stream_pagein ( oss , page ) ;
break ;
}
}
2002-11-06 23:54:29 +00:00
extern void print_wave_header ( WAVEFORMATEX * h ) ;
extern void print_video_header ( BITMAPINFOHEADER * h ) ;
2002-03-16 14:32:03 +00:00
/// Open an ogg physical stream
int demux_ogg_open ( demuxer_t * demuxer ) {
ogg_demuxer_t * ogg_d ;
stream_t * s ;
char * buf ;
2002-08-14 23:41:19 +00:00
int np , s_no , n_audio = 0 , n_video = 0 , n_text = 0 ;
2002-03-16 14:32:03 +00:00
ogg_sync_state * sync ;
ogg_page * page ;
ogg_packet pack ;
sh_audio_t * sh_a ;
sh_video_t * sh_v ;
2002-12-28 15:19:41 +00:00
# ifdef USE_ICONV
subcp_open ( ) ;
# endif
2003-01-04 22:56:56 +00:00
clear_sub = - 1 ;
2002-03-16 14:32:03 +00:00
s = demuxer - > stream ;
ogg_d = ( ogg_demuxer_t * ) calloc ( 1 , sizeof ( ogg_demuxer_t ) ) ;
sync = & ogg_d - > sync ;
page = & ogg_d - > page ;
2002-04-24 12:28:03 +00:00
ogg_sync_init ( sync ) ;
2002-03-16 14:32:03 +00:00
while ( 1 ) {
/// Try to get a page
2002-04-24 12:28:03 +00:00
ogg_d - > pos + = ogg_d - > last_size ;
np = ogg_sync_pageseek ( sync , page ) ;
2002-03-16 14:32:03 +00:00
/// Error
if ( np < 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " OGG demuxer : Bad page sync \n " ) ;
2002-10-16 20:17:20 +00:00
free ( ogg_d ) ;
2002-03-16 14:32:03 +00:00
return 0 ;
}
/// Need some more data
2002-04-24 12:28:03 +00:00
if ( np = = 0 ) {
2002-03-16 14:32:03 +00:00
int len ;
buf = ogg_sync_buffer ( sync , BLOCK_SIZE ) ;
len = stream_read ( s , buf , BLOCK_SIZE ) ;
if ( len = = 0 & & s - > eof ) {
free ( ogg_d ) ;
return 0 ;
}
ogg_sync_wrote ( sync , len ) ;
continue ;
}
2002-04-24 12:28:03 +00:00
ogg_d - > last_size = np ;
2002-03-16 14:32:03 +00:00
// We got one page now
if ( ! ogg_page_bos ( page ) ) { // It's not a begining page
// Header parsing end here, we need to get the page otherwise it will be lost
int id = demux_ogg_get_page_stream ( ogg_d , NULL ) ;
if ( id > = 0 )
ogg_stream_pagein ( & ogg_d - > subs [ id ] . stream , page ) ;
else
2003-07-09 01:30:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " OGG : Warning found none bos page from unknown stream %d \n " , ogg_page_serialno ( page ) ) ;
2002-03-16 14:32:03 +00:00
break ;
}
/// Init the data structure needed for a logical stream
ogg_d - > subs = ( ogg_stream_t * ) realloc ( ogg_d - > subs , ( ogg_d - > num_sub + 1 ) * sizeof ( ogg_stream_t ) ) ;
memset ( & ogg_d - > subs [ ogg_d - > num_sub ] , 0 , sizeof ( ogg_stream_t ) ) ;
/// Get the stream serial number
s_no = ogg_page_serialno ( page ) ;
ogg_stream_init ( & ogg_d - > subs [ ogg_d - > num_sub ] . stream , s_no ) ;
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " OGG : Found a stream with serial=%d \n " , s_no ) ;
// Take the first page
ogg_stream_pagein ( & ogg_d - > subs [ ogg_d - > num_sub ] . stream , page ) ;
// Get first packet of the page
ogg_stream_packetout ( & ogg_d - > subs [ ogg_d - > num_sub ] . stream , & pack ) ;
// Reset our vars
sh_a = NULL ;
sh_v = NULL ;
// Check for Vorbis
if ( pack . bytes > = 7 & & ! strncmp ( & pack . packet [ 1 ] , " vorbis " , 6 ) ) {
sh_a = new_sh_audio ( demuxer , ogg_d - > num_sub ) ;
sh_a - > format = 0xFFFE ;
2002-04-20 17:50:11 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . vorbis = 1 ;
2002-03-16 14:32:03 +00:00
n_audio + + ;
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG : stream %d is vorbis \n " , ogg_d - > num_sub ) ;
2003-05-11 16:39:16 +00:00
// check for Theora
# ifdef HAVE_OGGTHEORA
} else if ( pack . bytes > = 7 & & ! strncmp ( & pack . packet [ 1 ] , " theora " , 6 ) ) {
int errorCode = 0 ;
theora_info inf ;
2003-08-18 13:13:41 +00:00
theora_comment cc ;
theora_info_init ( & inf ) ;
theora_comment_init ( & cc ) ;
errorCode = theora_decode_header ( & inf , & cc , & pack ) ;
2003-05-11 16:39:16 +00:00
if ( errorCode )
mp_msg ( MSGT_DEMUX , MSGL_ERR , " Theora header parsing failed: %i \n " ,
errorCode ) ;
else
{
sh_v = new_sh_video ( demuxer , ogg_d - > num_sub ) ;
sh_v - > context = NULL ;
sh_v - > bih = ( BITMAPINFOHEADER * ) calloc ( 1 , sizeof ( BITMAPINFOHEADER ) ) ;
sh_v - > bih - > biSize = sizeof ( BITMAPINFOHEADER ) ;
sh_v - > bih - > biCompression = sh_v - > format = 0xFFFC ;
sh_v - > fps = ( ( double ) inf . fps_numerator ) /
( double ) inf . fps_denominator ;
sh_v - > frametime = ( ( double ) inf . fps_denominator ) /
( double ) inf . fps_numerator ;
sh_v - > disp_w = sh_v - > bih - > biWidth = inf . width ;
sh_v - > disp_h = sh_v - > bih - > biHeight = inf . height ;
sh_v - > bih - > biBitCount = 24 ;
sh_v - > bih - > biPlanes = 3 ;
sh_v - > bih - > biSizeImage = ( ( sh_v - > bih - > biBitCount / 8 ) *
sh_v - > bih - > biWidth * sh_v - > bih - > biHeight ) ;
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = sh_v - > fps ;
ogg_d - > subs [ ogg_d - > num_sub ] . theora = 1 ;
n_video + + ;
mp_msg ( MSGT_DEMUX , MSGL_V ,
" OGG : stream %d is theora v%i.%i.%i %i:%i, %.3f FPS, "
" aspect %i:%i \n " , ogg_d - > num_sub ,
( int ) inf . version_major ,
( int ) inf . version_minor ,
( int ) inf . version_subminor ,
inf . width , inf . height ,
sh_v - > fps ,
inf . aspect_numerator , inf . aspect_denominator ) ;
if ( verbose > 0 ) print_video_header ( sh_v - > bih ) ;
}
# endif /* HAVE_OGGTHEORA */
2003-10-04 22:00:25 +00:00
# ifdef HAVE_FLAC
} else if ( pack . bytes > = 4 & & ! strncmp ( & pack . packet [ 0 ] , " fLaC " , 4 ) ) {
sh_a = new_sh_audio ( demuxer , ogg_d - > num_sub ) ;
sh_a - > format = mmioFOURCC ( ' f ' , ' L ' , ' a ' , ' C ' ) ;
n_audio + + ;
ogg_d - > subs [ ogg_d - > num_sub ] . flac = 1 ;
sh_a - > wf = NULL ;
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG : stream %d is FLAC \n " , ogg_d - > num_sub ) ;
# endif /* HAVE_FLAC */
2002-03-16 14:32:03 +00:00
/// Check for old header
} else if ( pack . bytes > = 142 & & ! strncmp ( & pack . packet [ 1 ] , " Direct Show Samples embedded in Ogg " , 35 ) ) {
// Old video header
2002-10-22 15:41:41 +00:00
if ( get_uint32 ( pack . packet + 96 ) = = 0x05589f80 & & pack . bytes > = 184 ) {
2002-03-16 14:32:03 +00:00
sh_v = new_sh_video ( demuxer , ogg_d - > num_sub ) ;
sh_v - > bih = ( BITMAPINFOHEADER * ) calloc ( 1 , sizeof ( BITMAPINFOHEADER ) ) ;
2002-03-31 20:17:27 +00:00
sh_v - > bih - > biSize = sizeof ( BITMAPINFOHEADER ) ;
sh_v - > bih - > biCompression =
2002-03-16 14:32:03 +00:00
sh_v - > format = mmioFOURCC ( pack . packet [ 68 ] , pack . packet [ 69 ] ,
pack . packet [ 70 ] , pack . packet [ 71 ] ) ;
2002-10-22 15:41:41 +00:00
sh_v - > frametime = get_uint64 ( pack . packet + 164 ) * 0.0000001 ;
2002-03-16 14:32:03 +00:00
sh_v - > fps = 1 / sh_v - > frametime ;
2002-10-22 15:41:41 +00:00
sh_v - > disp_w = sh_v - > bih - > biWidth = get_uint32 ( pack . packet + 176 ) ;
sh_v - > disp_h = sh_v - > bih - > biHeight = get_uint32 ( pack . packet + 180 ) ;
sh_v - > bih - > biBitCount = get_uint16 ( pack . packet + 182 ) ;
2002-03-31 20:17:27 +00:00
if ( ! sh_v - > bih - > biBitCount ) sh_v - > bih - > biBitCount = 24 ; // hack, FIXME
sh_v - > bih - > biPlanes = 1 ;
sh_v - > bih - > biSizeImage = ( sh_v - > bih - > biBitCount > > 3 ) * sh_v - > bih - > biWidth * sh_v - > bih - > biHeight ;
2002-03-16 14:32:03 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = sh_v - > fps ;
n_video + + ;
2002-03-31 20:17:27 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG stream %d is video (old hdr) \n " , ogg_d - > num_sub ) ;
2002-11-01 17:46:45 +00:00
if ( verbose > 0 ) print_video_header ( sh_v - > bih ) ;
2002-03-16 14:32:03 +00:00
// Old audio header
2002-10-22 15:41:41 +00:00
} else if ( get_uint32 ( pack . packet + 96 ) = = 0x05589F81 ) {
2002-03-16 14:32:03 +00:00
unsigned int extra_size ;
sh_a = new_sh_audio ( demuxer , ogg_d - > num_sub ) ;
2002-10-22 15:41:41 +00:00
extra_size = get_uint16 ( pack . packet + 140 ) ;
2002-03-16 14:32:03 +00:00
sh_a - > wf = ( WAVEFORMATEX * ) calloc ( 1 , sizeof ( WAVEFORMATEX ) + extra_size ) ;
2002-10-22 15:41:41 +00:00
sh_a - > format = sh_a - > wf - > wFormatTag = get_uint16 ( pack . packet + 124 ) ;
sh_a - > channels = sh_a - > wf - > nChannels = get_uint16 ( pack . packet + 126 ) ;
sh_a - > samplerate = sh_a - > wf - > nSamplesPerSec = get_uint32 ( pack . packet + 128 ) ;
sh_a - > wf - > nAvgBytesPerSec = get_uint32 ( pack . packet + 132 ) ;
sh_a - > wf - > nBlockAlign = get_uint16 ( pack . packet + 136 ) ;
sh_a - > wf - > wBitsPerSample = get_uint16 ( pack . packet + 138 ) ;
2002-03-16 14:32:03 +00:00
sh_a - > samplesize = ( sh_a - > wf - > wBitsPerSample + 7 ) / 8 ;
sh_a - > wf - > cbSize = extra_size ;
if ( extra_size > 0 )
memcpy ( sh_a - > wf + sizeof ( WAVEFORMATEX ) , pack . packet + 142 , extra_size ) ;
2002-09-14 23:21:22 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = sh_a - > samplerate ; // * sh_a->channels;
2002-03-16 14:32:03 +00:00
n_audio + + ;
2002-03-31 20:17:27 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG stream %d is audio (old hdr) \n " , ogg_d - > num_sub ) ;
2002-11-01 17:46:45 +00:00
if ( verbose > 0 ) print_wave_header ( sh_a - > wf ) ;
2002-03-16 14:32:03 +00:00
} else
2003-07-09 01:30:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_WARN , " OGG stream %d contains an old header but the header type is unknown \n " , ogg_d - > num_sub ) ;
2002-03-16 14:32:03 +00:00
// Check new header
} else if ( ( * pack . packet & PACKET_TYPE_BITS ) = = PACKET_TYPE_HEADER & &
pack . bytes > = ( int ) sizeof ( stream_header ) + 1 ) {
stream_header * st = ( stream_header * ) ( pack . packet + 1 ) ;
/// New video header
if ( strncmp ( st - > streamtype , " video " , 5 ) = = 0 ) {
sh_v = new_sh_video ( demuxer , ogg_d - > num_sub ) ;
sh_v - > bih = ( BITMAPINFOHEADER * ) calloc ( 1 , sizeof ( BITMAPINFOHEADER ) ) ;
2002-03-31 20:27:52 +00:00
sh_v - > bih - > biSize = sizeof ( BITMAPINFOHEADER ) ;
sh_v - > bih - > biCompression =
2002-03-16 14:32:03 +00:00
sh_v - > format = mmioFOURCC ( st - > subtype [ 0 ] , st - > subtype [ 1 ] ,
st - > subtype [ 2 ] , st - > subtype [ 3 ] ) ;
2002-10-22 15:41:41 +00:00
sh_v - > frametime = get_uint64 ( & st - > time_unit ) * 0.0000001 ;
sh_v - > fps = 1.0 / sh_v - > frametime ;
sh_v - > bih - > biBitCount = get_uint16 ( & st - > bits_per_sample ) ;
sh_v - > disp_w = sh_v - > bih - > biWidth = get_uint32 ( & st - > sh . video . width ) ;
sh_v - > disp_h = sh_v - > bih - > biHeight = get_uint32 ( & st - > sh . video . height ) ;
2002-03-31 20:27:52 +00:00
if ( ! sh_v - > bih - > biBitCount ) sh_v - > bih - > biBitCount = 24 ; // hack, FIXME
sh_v - > bih - > biPlanes = 1 ;
sh_v - > bih - > biSizeImage = ( sh_v - > bih - > biBitCount > > 3 ) * sh_v - > bih - > biWidth * sh_v - > bih - > biHeight ;
2002-03-16 14:32:03 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = sh_v - > fps ;
n_video + + ;
2002-03-31 20:17:27 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG stream %d is video (new hdr) \n " , ogg_d - > num_sub ) ;
2002-11-01 17:46:45 +00:00
if ( verbose > 0 ) print_video_header ( sh_v - > bih ) ;
2002-03-16 14:32:03 +00:00
/// New audio header
} else if ( strncmp ( st - > streamtype , " audio " , 5 ) = = 0 ) {
char buffer [ 5 ] ;
2002-10-22 15:41:41 +00:00
unsigned int extra_size = get_uint32 ( & st - > size ) - sizeof ( stream_header ) ;
2002-03-16 14:32:03 +00:00
memcpy ( buffer , st - > subtype , 4 ) ;
buffer [ 4 ] = ' \0 ' ;
sh_a = new_sh_audio ( demuxer , ogg_d - > num_sub ) ;
sh_a - > wf = ( WAVEFORMATEX * ) calloc ( 1 , sizeof ( WAVEFORMATEX ) + extra_size ) ;
2002-07-30 18:14:02 +00:00
sh_a - > format = sh_a - > wf - > wFormatTag = strtol ( buffer , NULL , 16 ) ;
2002-10-22 15:41:41 +00:00
sh_a - > channels = sh_a - > wf - > nChannels = get_uint16 ( & st - > sh . audio . channels ) ;
sh_a - > samplerate = sh_a - > wf - > nSamplesPerSec = get_uint64 ( & st - > samples_per_unit ) ;
sh_a - > wf - > nAvgBytesPerSec = get_uint32 ( & st - > sh . audio . avgbytespersec ) ;
sh_a - > wf - > nBlockAlign = get_uint16 ( & st - > sh . audio . blockalign ) ;
sh_a - > wf - > wBitsPerSample = get_uint16 ( & st - > bits_per_sample ) ;
2002-03-16 14:32:03 +00:00
sh_a - > samplesize = ( sh_a - > wf - > wBitsPerSample + 7 ) / 8 ;
sh_a - > wf - > cbSize = extra_size ;
if ( extra_size )
memcpy ( sh_a - > wf + sizeof ( WAVEFORMATEX ) , st + 1 , extra_size ) ;
2002-09-14 23:21:22 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = sh_a - > samplerate ; // * sh_a->channels;
2002-03-16 14:32:03 +00:00
n_audio + + ;
2002-03-31 20:17:27 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG stream %d is audio (new hdr) \n " , ogg_d - > num_sub ) ;
2002-11-01 17:46:45 +00:00
if ( verbose > 0 ) print_wave_header ( sh_a - > wf ) ;
2002-03-16 14:32:03 +00:00
/// Check for text (subtitles) header
2002-08-14 23:41:19 +00:00
} else if ( strncmp ( st - > streamtype , " text " , 4 ) = = 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG stream %d is text \n " , ogg_d - > num_sub ) ;
2003-01-04 22:56:56 +00:00
ogg_d - > subs [ ogg_d - > num_sub ] . samplerate = get_uint64 ( & st - > time_unit ) / 10 ;
2002-08-14 23:41:19 +00:00
n_text + + ;
demux_ogg_init_sub ( ) ;
2003-07-09 01:30:24 +00:00
//// Unknown header type
2002-03-16 14:32:03 +00:00
} else
2003-07-09 01:30:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " OGG stream %d has a header marker but is of an unknown type \n " , ogg_d - > num_sub ) ;
2003-08-14 12:15:44 +00:00
/// Unknown (invalid ?) header
2002-03-16 14:32:03 +00:00
} else
2003-07-09 01:30:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " OGG stream %d is of an unknown type \n " , ogg_d - > num_sub ) ;
2002-03-16 14:32:03 +00:00
if ( sh_a | | sh_v ) {
demux_stream_t * ds = NULL ;
if ( sh_a ) {
// If the audio stream is not defined we took the first one
if ( demuxer - > audio - > id = = - 1 ) {
demuxer - > audio - > id = ogg_d - > num_sub ;
2002-03-31 20:09:17 +00:00
// if(sh_a->wf) print_wave_header(sh_a->wf);
2002-03-16 14:32:03 +00:00
}
/// Is it the stream we want
2002-05-23 09:47:18 +00:00
if ( demuxer - > audio - > id = = ogg_d - > num_sub ) {
2002-05-19 23:25:40 +00:00
demuxer - > audio - > sh = sh_a ;
sh_a - > ds = demuxer - > audio ;
2002-03-16 14:32:03 +00:00
ds = demuxer - > audio ;
2002-05-23 09:47:18 +00:00
}
2002-03-16 14:32:03 +00:00
}
if ( sh_v ) {
/// Also for video
if ( demuxer - > video - > id = = - 1 ) {
demuxer - > video - > id = ogg_d - > num_sub ;
2002-03-31 20:09:17 +00:00
// if(sh_v->bih) print_video_header(sh_v->bih);
2002-03-16 14:32:03 +00:00
}
2002-05-23 09:47:18 +00:00
if ( demuxer - > video - > id = = ogg_d - > num_sub ) {
2002-05-19 23:25:40 +00:00
demuxer - > video - > sh = sh_v ;
sh_v - > ds = demuxer - > video ;
2002-03-16 14:32:03 +00:00
ds = demuxer - > video ;
2002-05-23 09:47:18 +00:00
}
2002-03-16 14:32:03 +00:00
}
2002-04-20 17:50:11 +00:00
/// Add the header packets if the stream isn't seekable
2003-12-08 09:47:15 +00:00
if ( ds & & ! s - > end_pos ) {
2002-04-20 17:50:11 +00:00
/// Finish the page, otherwise packets will be lost
do {
demux_ogg_add_packet ( ds , & ogg_d - > subs [ ogg_d - > num_sub ] , & pack ) ;
} while ( ogg_stream_packetout ( & ogg_d - > subs [ ogg_d - > num_sub ] . stream , & pack ) = = 1 ) ;
}
2002-03-16 14:32:03 +00:00
}
ogg_d - > num_sub + + ;
}
/// Finish to setup the demuxer
demuxer - > priv = ogg_d ;
if ( ! n_video )
demuxer - > video - > id = - 2 ;
if ( ! n_audio )
demuxer - > audio - > id = - 2 ;
2002-08-14 23:41:19 +00:00
if ( ! n_text )
demuxer - > sub - > id = - 2 ;
2002-03-16 14:32:03 +00:00
2003-12-08 09:47:15 +00:00
ogg_d - > final_granulepos = 0 ;
2002-04-20 17:50:11 +00:00
if ( ! s - > end_pos )
demuxer - > seekable = 0 ;
else {
2003-01-05 13:48:13 +00:00
demuxer - > movi_start = s - > start_pos ; // Needed for XCD (Ogg written in MODE2)
2002-04-20 17:50:11 +00:00
demuxer - > movi_end = s - > end_pos ;
2002-04-24 12:28:03 +00:00
demuxer - > seekable = 1 ;
2003-12-08 09:47:15 +00:00
demux_ogg_scan_stream ( demuxer ) ;
2002-04-20 17:50:11 +00:00
}
2002-08-14 23:41:19 +00:00
mp_msg ( MSGT_DEMUX , MSGL_V , " OGG demuxer : found %d audio stream%s, %d video stream%s and %d text stream%s \n " , n_audio , n_audio > 1 ? " s " : " " , n_video , n_video > 1 ? " s " : " " , n_text , n_text > 1 ? " s " : " " ) ;
2002-03-16 14:32:03 +00:00
return 1 ;
}
int demux_ogg_fill_buffer ( demuxer_t * d ) {
ogg_demuxer_t * ogg_d ;
stream_t * s ;
demux_stream_t * ds ;
ogg_sync_state * sync ;
ogg_stream_state * os ;
ogg_page * page ;
ogg_packet pack ;
int np = 0 , id = 0 ;
s = d - > stream ;
ogg_d = d - > priv ;
sync = & ogg_d - > sync ;
page = & ogg_d - > page ;
/// Find the stream we are working on
if ( ( id = demux_ogg_get_page_stream ( ogg_d , & os ) ) < 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_ERR , " OGG demuxer : can't get current stream \n " ) ;
return 0 ;
}
while ( 1 ) {
np = 0 ;
ds = NULL ;
/// Try to get some packet from the current page
while ( ( np = ogg_stream_packetout ( os , & pack ) ) ! = 1 ) {
/// No packet we go the next page
if ( np = = 0 ) {
while ( 1 ) {
int pa , len ;
char * buf ;
2002-04-24 12:28:03 +00:00
ogg_d - > pos + = ogg_d - > last_size ;
2002-03-16 14:32:03 +00:00
/// Get the next page from the physical stream
2002-04-24 12:28:03 +00:00
while ( ( pa = ogg_sync_pageseek ( sync , page ) ) < = 0 ) {
2002-03-16 14:32:03 +00:00
/// Error : we skip some bytes
if ( pa < 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_WARN , " OGG : Page out not synced, we skip some bytes \n " ) ;
2002-04-24 12:28:03 +00:00
ogg_d - > pos - = pa ;
2002-03-16 14:32:03 +00:00
continue ;
}
/// We need more data
buf = ogg_sync_buffer ( sync , BLOCK_SIZE ) ;
len = stream_read ( s , buf , BLOCK_SIZE ) ;
if ( len = = 0 & & s - > eof ) {
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " OGG : Stream EOF !!!! \n " ) ;
return 0 ;
}
ogg_sync_wrote ( sync , len ) ;
} /// Page loop
2002-04-24 12:28:03 +00:00
ogg_d - > last_size = pa ;
2002-03-16 14:32:03 +00:00
/// Find the page's logical stream
if ( ( id = demux_ogg_get_page_stream ( ogg_d , & os ) ) < 0 ) {
2003-07-09 01:30:24 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " OGG demuxer error : we met an unknown stream \n " ) ;
2002-03-16 14:32:03 +00:00
return 0 ;
}
/// Take the page
if ( ogg_stream_pagein ( os , page ) = = 0 )
break ;
/// Page was invalid => retry
mp_msg ( MSGT_DEMUX , MSGL_WARN , " OGG demuxer : got invalid page !!!!! \n " ) ;
2002-04-24 12:28:03 +00:00
ogg_d - > pos + = ogg_d - > last_size ;
2002-03-16 14:32:03 +00:00
}
} else /// Packet was corrupted
mp_msg ( MSGT_DEMUX , MSGL_WARN , " OGG : bad packet in stream %d \n " , id ) ;
} /// Packet loop
/// Is the actual logical stream in use ?
if ( id = = d - > audio - > id )
ds = d - > audio ;
else if ( id = = d - > video - > id )
ds = d - > video ;
2002-08-14 23:41:19 +00:00
else if ( id = = d - > sub - > id )
ds = d - > sub ;
2002-03-16 14:32:03 +00:00
if ( ds ) {
if ( ! demux_ogg_add_packet ( ds , & ogg_d - > subs [ id ] , & pack ) )
continue ; /// Unuseful packet, get another
2002-04-24 12:28:03 +00:00
d - > filepos = ogg_d - > pos ;
2002-03-16 14:32:03 +00:00
return 1 ;
}
} /// while(1)
}
/// For avi with Ogg audio stream we have to create an ogg demuxer for this
// stream, then we join the avi and ogg demuxer with a demuxers demuxer
demuxer_t * init_avi_with_ogg ( demuxer_t * demuxer ) {
demuxer_t * od ;
ogg_demuxer_t * ogg_d ;
stream_t * s ;
uint32_t hdrsizes [ 3 ] ;
demux_packet_t * dp ;
sh_audio_t * sh_audio = demuxer - > audio - > sh ;
int np ;
unsigned char * p = NULL , * buf ;
int plen ;
/// Check that the cbSize is enouth big for the following reads
2003-01-29 21:53:56 +00:00
if ( sh_audio - > wf - > cbSize < 22 + 3 * sizeof ( uint32_t ) ) {
2002-03-16 14:32:03 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " AVI OGG : Initial audio header is too small !!!!! \n " ) ;
goto fallback ;
}
/// Get the size of the 3 header packet
2003-01-29 21:53:56 +00:00
memcpy ( hdrsizes , ( ( unsigned char * ) sh_audio - > wf ) + 22 + sizeof ( WAVEFORMATEX ) , 3 * sizeof ( uint32_t ) ) ;
// printf("\n!!!!!! hdr sizes: %d %d %d \n",hdrsizes[0],hdrsizes[1],hdrsizes[2]);
2002-03-16 14:32:03 +00:00
/// Check the size
2003-01-29 21:53:56 +00:00
if ( sh_audio - > wf - > cbSize < 22 + 3 * sizeof ( uint32_t ) + hdrsizes [ 0 ] + hdrsizes [ 1 ] + hdrsizes [ 2 ] ) {
2002-03-16 14:32:03 +00:00
mp_msg ( MSGT_DEMUX , MSGL_ERR , " AVI OGG : Audio header is too small !!!!! \n " ) ;
goto fallback ;
}
// Build the ogg demuxer private datas
ogg_d = ( ogg_demuxer_t * ) calloc ( 1 , sizeof ( ogg_demuxer_t ) ) ;
ogg_d - > num_sub = 1 ;
ogg_d - > subs = ( ogg_stream_t * ) malloc ( sizeof ( ogg_stream_t ) ) ;
2002-04-24 17:28:23 +00:00
ogg_d - > subs [ 0 ] . vorbis = 1 ;
2002-03-16 14:32:03 +00:00
// Init the ogg physical stream
ogg_sync_init ( & ogg_d - > sync ) ;
// Get the first page of the stream : we assume there only 1 logical stream
while ( ( np = ogg_sync_pageout ( & ogg_d - > sync , & ogg_d - > page ) ) < = 0 ) {
if ( np < 0 ) {
mp_msg ( MSGT_DEMUX , MSGL_ERR , " AVI OGG error : Can't init using first stream packets \n " ) ;
free ( ogg_d ) ;
goto fallback ;
}
// Add some data
plen = ds_get_packet ( demuxer - > audio , & p ) ;
buf = ogg_sync_buffer ( & ogg_d - > sync , plen ) ;
memcpy ( buf , p , plen ) ;
ogg_sync_wrote ( & ogg_d - > sync , plen ) ;
}
// Init the logical stream
mp_msg ( MSGT_DEMUX , MSGL_DBG2 , " AVI OGG found page with serial %d \n " , ogg_page_serialno ( & ogg_d - > page ) ) ;
ogg_stream_init ( & ogg_d - > subs [ 0 ] . stream , ogg_page_serialno ( & ogg_d - > page ) ) ;
// Write the page
ogg_stream_pagein ( & ogg_d - > subs [ 0 ] . stream , & ogg_d - > page ) ;
// Create the ds_stream and the ogg demuxer
s = new_ds_stream ( demuxer - > audio ) ;
od = new_demuxer ( s , DEMUXER_TYPE_OGG , 0 , - 2 , - 2 ) ;
/// Add the header packets in the ogg demuxer audio stream
// Initial header
dp = new_demux_packet ( hdrsizes [ 0 ] ) ;
2003-01-29 21:53:56 +00:00
memcpy ( dp - > buffer , ( ( unsigned char * ) sh_audio - > wf ) + 22 + sizeof ( WAVEFORMATEX ) + 3 * sizeof ( uint32_t ) , hdrsizes [ 0 ] ) ;
2002-03-16 14:32:03 +00:00
ds_add_packet ( od - > audio , dp ) ;
/// Comments
dp = new_demux_packet ( hdrsizes [ 1 ] ) ;
2003-01-29 21:53:56 +00:00
memcpy ( dp - > buffer , ( ( unsigned char * ) sh_audio - > wf ) + 22 + sizeof ( WAVEFORMATEX ) + 3 * sizeof ( uint32_t ) + hdrsizes [ 0 ] , hdrsizes [ 1 ] ) ;
2002-03-16 14:32:03 +00:00
ds_add_packet ( od - > audio , dp ) ;
/// Code book
dp = new_demux_packet ( hdrsizes [ 2 ] ) ;
2003-01-29 21:53:56 +00:00
memcpy ( dp - > buffer , ( ( unsigned char * ) sh_audio - > wf ) + 22 + sizeof ( WAVEFORMATEX ) + 3 * sizeof ( uint32_t ) + hdrsizes [ 0 ] + hdrsizes [ 1 ] , hdrsizes [ 2 ] ) ;
2002-03-16 14:32:03 +00:00
ds_add_packet ( od - > audio , dp ) ;
// Finish setting up the ogg demuxer
od - > priv = ogg_d ;
sh_audio = new_sh_audio ( od , 0 ) ;
od - > audio - > id = 0 ;
od - > video - > id = - 2 ;
od - > audio - > sh = sh_audio ;
sh_audio - > ds = od - > audio ;
sh_audio - > format = 0xFFFE ;
/// Return the joined demuxers
return new_demuxers_demuxer ( demuxer , od , demuxer ) ;
fallback :
demuxer - > audio - > id = - 2 ;
return demuxer ;
}
2002-11-06 23:54:29 +00:00
extern void resync_audio_stream ( sh_audio_t * sh_audio ) ;
2002-04-20 17:50:11 +00:00
void demux_ogg_seek ( demuxer_t * demuxer , float rel_seek_secs , int flags ) {
ogg_demuxer_t * ogg_d = demuxer - > priv ;
ogg_sync_state * sync = & ogg_d - > sync ;
ogg_page * page = & ogg_d - > page ;
ogg_stream_state * oss ;
ogg_stream_t * os ;
demux_stream_t * ds ;
sh_audio_t * sh_audio = demuxer - > audio - > sh ;
ogg_packet op ;
2002-04-24 12:28:03 +00:00
float rate ;
2002-12-30 08:59:33 +00:00
int i , sp , first ;
2002-04-20 17:50:11 +00:00
vorbis_info * vi = NULL ;
2002-04-24 12:28:03 +00:00
int64_t gp = 0 ;
off_t pos ;
2002-04-20 17:50:11 +00:00
if ( demuxer - > video - > id > = 0 ) {
ds = demuxer - > video ;
rate = ogg_d - > subs [ ds - > id ] . samplerate ;
} else {
ds = demuxer - > audio ;
vi = & ( ( ov_struct_t * ) ( ( sh_audio_t * ) ds - > sh ) - > context ) - > vi ;
rate = ( float ) vi - > rate ;
}
os = & ogg_d - > subs [ ds - > id ] ;
oss = & os - > stream ;
2002-04-24 12:28:03 +00:00
if ( ogg_d - > syncpoints ) {
2004-01-31 09:38:01 +00:00
gp = flags & 1 ? 0 : os - > lastpos ;
if ( flags & 2 )
gp + = ogg_d - > syncpoints [ ogg_d - > num_syncpoint ] . granulepos * rel_seek_secs ;
2002-04-24 12:28:03 +00:00
else
2004-01-31 09:38:01 +00:00
gp + = rel_seek_secs * rate ;
2002-04-20 17:50:11 +00:00
2002-04-24 12:28:03 +00:00
for ( sp = 0 ; sp < ogg_d - > num_syncpoint ; sp + + ) {
2004-01-31 09:38:01 +00:00
if ( ogg_d - > syncpoints [ sp ] . granulepos > = gp ) break ;
2002-04-24 12:28:03 +00:00
}
2002-04-20 17:50:11 +00:00
2002-04-24 12:28:03 +00:00
if ( sp > = ogg_d - > num_syncpoint )
return ;
pos = ogg_d - > syncpoints [ sp ] . page_pos ;
2002-04-20 17:50:11 +00:00
2002-04-24 12:28:03 +00:00
} else {
2003-01-05 13:48:13 +00:00
pos = flags & 1 ? 0 : ogg_d - > pos ;
2002-04-24 12:28:03 +00:00
if ( flags & 2 )
pos + = ( demuxer - > movi_end - demuxer - > movi_start ) * rel_seek_secs ;
2004-01-31 09:38:01 +00:00
else {
if ( ogg_d - > final_granulepos > 0 )
pos + = rel_seek_secs * ( demuxer - > movi_end - demuxer - > movi_start ) / ( ogg_d - > final_granulepos / rate ) ;
2002-04-24 12:28:03 +00:00
else
pos + = rel_seek_secs * ogg_d - > pos / ( os - > lastpos / rate ) ;
2004-01-31 09:38:01 +00:00
}
2003-01-05 13:48:13 +00:00
if ( pos < 0 )
pos = 0 ;
else if ( pos > ( demuxer - > movi_end - demuxer - > movi_start ) )
2002-04-24 12:28:03 +00:00
return ;
}
2002-04-20 17:50:11 +00:00
2003-01-05 13:48:13 +00:00
stream_seek ( demuxer - > stream , pos + demuxer - > movi_start ) ;
2002-04-20 17:50:11 +00:00
ogg_sync_reset ( sync ) ;
2002-04-24 12:28:03 +00:00
for ( i = 0 ; i < ogg_d - > num_sub ; i + + ) {
2002-04-20 17:50:11 +00:00
ogg_stream_reset ( & ogg_d - > subs [ i ] . stream ) ;
2002-04-24 12:28:03 +00:00
ogg_d - > subs [ i ] . lastpos = ogg_d - > subs [ i ] . lastsize = 0 ;
}
ogg_d - > pos = pos ;
ogg_d - > last_size = 0 ;
2002-04-20 17:50:11 +00:00
2002-12-30 08:59:33 +00:00
first = 1 ;
2002-04-20 17:50:11 +00:00
while ( 1 ) {
2002-04-24 12:28:03 +00:00
int np ;
ogg_d - > pos + = ogg_d - > last_size ;
ogg_d - > last_size = 0 ;
np = ogg_sync_pageseek ( sync , page ) ;
if ( np < 0 )
ogg_d - > pos - = np ;
2002-04-20 17:50:11 +00:00
if ( np < = 0 ) { // We need more data
char * buf = ogg_sync_buffer ( sync , BLOCK_SIZE ) ;
int len = stream_read ( demuxer - > stream , buf , BLOCK_SIZE ) ;
if ( len = = 0 & & demuxer - > stream - > eof ) {
mp_msg ( MSGT_DEMUX , MSGL_ERR , " EOF while trying to seek !!!! \n " ) ;
break ;
}
ogg_sync_wrote ( sync , len ) ;
continue ;
}
2002-04-24 12:28:03 +00:00
ogg_d - > last_size = np ;
if ( ogg_page_serialno ( page ) ! = oss - > serialno )
2002-04-20 17:50:11 +00:00
continue ;
2002-04-24 12:28:03 +00:00
2002-04-20 17:50:11 +00:00
if ( ogg_stream_pagein ( oss , page ) ! = 0 )
continue ;
2002-04-24 12:28:03 +00:00
while ( 1 ) {
np = ogg_stream_packetout ( oss , & op ) ;
if ( np < 0 )
2002-04-20 17:50:11 +00:00
continue ;
2002-04-24 12:28:03 +00:00
else if ( np = = 0 )
2002-04-20 17:50:11 +00:00
break ;
2002-12-30 08:59:33 +00:00
if ( first ) { /* Discard the first packet as it's probably broken,
and we don ' t have any other means to decide whether it is
complete or not . */
first = 0 ;
break ;
}
2003-05-11 16:39:16 +00:00
/* the detection of keyframes for theora is somewhat a hack: granulepos
for theora packets is ` keyframeNumber < < shift | iframeNumber ' ; ` shift '
is * variable * , with its excact value encoded in the theora header .
This code just hopes that it is greater than 9 and that keyframes
distance will never overflow 512. */
if ( ( ( ( * op . packet & PACKET_IS_SYNCPOINT ) & & ! os - > theora ) | |
os - > vorbis | | ( os - > theora & & ( op . granulepos & 0x1FF ) = = 0 ) ) & &
2002-04-24 12:28:03 +00:00
( ! ogg_d - > syncpoints | | op . granulepos > = gp ) ) {
2003-01-04 22:56:56 +00:00
ogg_sub . lines = 0 ;
vo_sub = & ogg_sub ;
vo_osd_changed ( OSDTYPE_SUBTITLE ) ;
clear_sub = - 1 ;
2002-04-24 12:28:03 +00:00
demux_ogg_add_packet ( ds , os , & op ) ;
if ( sh_audio )
resync_audio_stream ( sh_audio ) ;
return ;
2002-04-20 17:50:11 +00:00
}
2002-04-24 12:28:03 +00:00
}
2002-04-20 17:50:11 +00:00
}
mp_msg ( MSGT_DEMUX , MSGL_ERR , " Can't find the good packet :( \n " ) ;
}
2002-04-24 17:28:23 +00:00
void demux_close_ogg ( demuxer_t * demuxer ) {
ogg_demuxer_t * ogg_d = demuxer - > priv ;
if ( ! ogg_d )
return ;
2002-12-28 15:19:41 +00:00
# ifdef USE_ICONV
subcp_close ( ) ;
# endif
2002-04-24 17:28:23 +00:00
if ( ogg_d - > subs )
free ( ogg_d - > subs ) ;
if ( ogg_d - > syncpoints )
free ( ogg_d - > syncpoints ) ;
free ( ogg_d ) ;
}
2003-12-08 09:47:15 +00:00
int demux_ogg_control ( demuxer_t * demuxer , int cmd , void * arg ) {
ogg_demuxer_t * ogg_d = demuxer - > priv ;
ogg_stream_t * os ;
float rate ;
2003-12-08 11:11:32 +00:00
2003-12-08 09:47:15 +00:00
if ( demuxer - > video - > id > = 0 ) {
os = & ogg_d - > subs [ demuxer - > video - > id ] ;
rate = os - > samplerate ;
} else {
os = & ogg_d - > subs [ demuxer - > audio - > id ] ;
rate = ( float ) ( ( ov_struct_t * ) ( ( sh_audio_t * ) demuxer - > audio - > sh ) - > context ) - > vi . rate ;
}
switch ( cmd ) {
case DEMUXER_CTRL_GET_TIME_LENGTH :
if ( ogg_d - > final_granulepos < = 0 ) return DEMUXER_CTRL_DONTKNOW ;
2003-12-08 11:11:32 +00:00
* ( ( unsigned long * ) arg ) = ogg_d - > final_granulepos / rate ;
2003-12-08 09:47:15 +00:00
return DEMUXER_CTRL_GUESS ;
case DEMUXER_CTRL_GET_PERCENT_POS :
if ( ogg_d - > final_granulepos < = 0 ) return DEMUXER_CTRL_DONTKNOW ;
* ( ( int * ) arg ) = ( int ) ( ( os - > lastpos * 100 ) / ogg_d - > final_granulepos ) ;
return DEMUXER_CTRL_OK ;
default :
return DEMUXER_CTRL_NOTIMPL ;
}
}
2002-03-16 14:32:03 +00:00
# endif