summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dec_audio.c327
-rw-r--r--libmpdemux/Makefile2
-rw-r--r--libmpdemux/demux_ogg.c597
-rw-r--r--libmpdemux/demuxer.c23
-rw-r--r--libmpdemux/demuxer.h5
-rw-r--r--libmpdemux/stream.c9
-rw-r--r--libmpdemux/stream.h1
7 files changed, 734 insertions, 230 deletions
diff --git a/dec_audio.c b/dec_audio.c
index af51793e45..c13134fa13 100644
--- a/dec_audio.c
+++ b/dec_audio.c
@@ -73,13 +73,8 @@ static DS_AudioDecoder* ds_adec=NULL;
#include <math.h>
#include <vorbis/codec.h>
+// This struct is also defined in demux_ogg.c => common header ?
typedef struct ov_struct_st {
- ogg_sync_state oy; /* sync and verify incoming physical bitstream */
- ogg_stream_state os; /* take physical pages, weld into a logical
- stream of packets */
- ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
- ogg_packet op; /* one raw packet of data for decode */
-
vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */
vorbis_comment vc; /* struct that stores all the bitstream user comments */
@@ -389,6 +384,7 @@ case AFM_VORBIS:
driver=0;
#else
/* OggVorbis audio via libvorbis, compatible with files created by nandub and zorannt codec */
+ // Is there always 1024 samples/frame ? ***** Albeu
sh_audio->audio_out_minsize=1024*4; // 1024 samples/frame
#endif
break;
@@ -759,124 +755,61 @@ case AFM_MPEG: {
}
#ifdef HAVE_OGGVORBIS
case AFM_VORBIS: {
- // OggVorbis Audio:
-#if 0 /* just here for reference - atmos */
- ogg_sync_state oy; /* sync and verify incoming physical bitstream */
- ogg_stream_state os; /* take physical pages, weld into a logical
- stream of packets */
- ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
- ogg_packet op; /* one raw packet of data for decode */
-
- 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 */
-#else
- /* nix, nada, rien, nothing, nem, nüx */
-#endif
-
- uint32_t hdrsizes[3];/* stores vorbis header sizes from AVI audio header,
- maybe use ogg_uint32_t */
- //int i;
- int ret;
- char *buffer;
- ogg_packet hdr;
- //ov_struct_t *s=&sh_audio->ov;
- sh_audio->ov=malloc(sizeof(ov_struct_t));
- //s=&sh_audio->ov;
-
- vorbis_info_init(&sh_audio->ov->vi);
- vorbis_comment_init(&sh_audio->ov->vc);
-
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"OggVorbis: cbsize: %i\n", sh_audio->wf->cbSize);
- memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"OggVorbis: Read header sizes: initial: %i comment: %i codebook: %i\n", hdrsizes[0], hdrsizes[1], hdrsizes[2]);
- /*for(i=12; i <= 40; i+=2) { // header bruteforce :)
- memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+i, 3*sizeof(uint32_t));
- printf("OggVorbis: Read header sizes (%i): %ld %ld %ld\n", i, hdrsizes[0], hdrsizes[1], hdrsizes[2]);
- }*/
-
- /* read headers */ // FIXME disable sound on errors here, we absolutely need this headers! - atmos
- hdr.packet=NULL;
- hdr.b_o_s = 1; /* beginning of stream for first packet */
- hdr.bytes = hdrsizes[0];
- hdr.packet = realloc(hdr.packet,hdr.bytes);
- memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdr.bytes);
- if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
- mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: initial (identification) header broken!\n");
- hdr.b_o_s = 0;
- hdr.bytes = hdrsizes[1];
- hdr.packet = realloc(hdr.packet,hdr.bytes);
- memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdr.bytes);
- if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
- mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: comment header broken!\n");
- hdr.bytes = hdrsizes[2];
- hdr.packet = realloc(hdr.packet,hdr.bytes);
- memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdr.bytes);
- if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
+ ogg_packet op;
+ vorbis_comment vc;
+ struct ov_struct_st *ov;
+
+ /// Init the decoder with the 3 header packets
+ ov = (struct ov_struct_st*)malloc(sizeof(struct ov_struct_st));
+ vorbis_info_init(&ov->vi);
+ vorbis_comment_init(&vc);
+ op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
+ op.b_o_s = 1;
+ /// Header
+ if(vorbis_synthesis_headerin(&ov->vi,&vc,&op) <0) {
+ mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis: initial (identification) header broken!\n");
+ driver = 0;
+ free(ov);
+ break;
+ }
+ op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
+ op.b_o_s = 0;
+ /// Comments
+ if(vorbis_synthesis_headerin(&ov->vi,&vc,&op) <0) {
+ mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis: comment header broken!\n");
+ driver = 0;
+ free(ov);
+ break;
+ }
+ op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
+ //// Codebook
+ if(vorbis_synthesis_headerin(&ov->vi,&vc,&op)<0) {
mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: codebook header broken!\n");
- hdr.bytes=0;
- hdr.packet = realloc(hdr.packet,hdr.bytes); /* free */
- /* done with the headers */
-
-
- /* Throw the comments plus a few lines about the bitstream we're
- decoding */
- {
- char **ptr=sh_audio->ov->vc.user_comments;
+ driver = 0;
+ free(ov);
+ break;
+ } else { /// Print the infos
+ char **ptr=vc.user_comments;
while(*ptr){
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbisComment: %s\n",*ptr);
++ptr;
}
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Bitstream is %d channel, %ldHz, %ldkbit/s %cBR\n",sh_audio->ov->vi.channels,sh_audio->ov->vi.rate,sh_audio->ov->vi.bitrate_nominal/1000, (sh_audio->ov->vi.bitrate_lower!=sh_audio->ov->vi.bitrate_nominal)||(sh_audio->ov->vi.bitrate_upper!=sh_audio->ov->vi.bitrate_nominal)?'V':'C');
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Encoded by: %s\n",sh_audio->ov->vc.vendor);
- }
- sh_audio->channels=sh_audio->ov->vi.channels;
- sh_audio->samplerate=sh_audio->ov->vi.rate;
- sh_audio->i_bps=sh_audio->ov->vi.bitrate_nominal/8;
-
-// printf("[\n");
-// sh_audio->a_buffer_len=sh_audio->audio_out_minsize;///ov->vi.channels;
-// printf("]\n");
-
- /* OK, got and parsed all three headers. Initialize the Vorbis
- packet->PCM decoder. */
- vorbis_synthesis_init(&sh_audio->ov->vd,&sh_audio->ov->vi); /* central decode state */
- vorbis_block_init(&sh_audio->ov->vd,&sh_audio->ov->vb); /* local state for most of the decode
- so multiple block decodes can
- proceed in parallel. We could init
- multiple vorbis_block structures
- for vd here */
- //printf("OggVorbis: synthesis and block init done.\n");
- ogg_sync_init(&sh_audio->ov->oy); /* Now we can read pages */
-
- while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
- if(ret == -1)
- mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
- else
- if(ret == 0) {
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: need more data to verify page, reading more data.\n");
- /* submit a a_buffer_len block to libvorbis' Ogg layer */
- buffer=ogg_sync_buffer(&sh_audio->ov->oy,256);
- ogg_sync_wrote(&sh_audio->ov->oy,demux_read_data(sh_audio->ds,buffer,256));
- }
+ mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Bitstream is %d channel, %ldHz, %ldkbit/s %cBR\n",ov->vi.channels,ov->vi.rate,ov->vi.bitrate_nominal/1000, (ov->vi.bitrate_lower!=ov->vi.bitrate_nominal)||(ov->vi.bitrate_upper!=ov->vi.bitrate_nominal)?'V':'C');
+ mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Encoded by: %s\n",vc.vendor);
}
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: successfull.\n");
- ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og); /* we can ignore any errors here
- as they'll also become apparent
- at packetout */
-
- /* Get the serial number and set up the rest of decode. */
- /* serialno first; use it to set up a logical stream */
- ogg_stream_init(&sh_audio->ov->os,ogg_page_serialno(&sh_audio->ov->og));
-
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Init OK!\n");
- break;
-}
-#endif
+ // Setup the decoder
+ sh_audio->channels=ov->vi.channels;
+ sh_audio->samplerate=ov->vi.rate;
+ sh_audio->i_bps=ov->vi.bitrate_nominal/8;
+ sh_audio->context = ov;
+ /// Finish the decoder init
+ vorbis_synthesis_init(&ov->vd,&ov->vi);
+ vorbis_block_init(&ov->vd,&ov->vb);
+ mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Init OK!\n");
+} break;
+#endif
#ifdef USE_LIBMAD
case AFM_MAD:
{
@@ -982,117 +915,64 @@ int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){
// len=MP3_DecodeFrame(buf,3);
break;
#ifdef HAVE_OGGVORBIS
- case AFM_VORBIS: { // OggVorbis
- /* note: good minlen would be 4k or 8k IMHO - atmos */
- int ret;
- char *buffer;
- int bytes;
- int samples;
- float **pcm;
- //ogg_int16_t convbuffer[4096];
-// int convsize;
- int readlen=1024;
- len=0;
-// convsize=minlen/sh_audio->ov->vi.channels;
-
- while(len < minlen) { /* double loop allows for break in inner loop */
- while(len < minlen) { /* without aborting the outer loop - atmos */
- ret=ogg_stream_packetout(&sh_audio->ov->os,&sh_audio->ov->op);
- if(ret==0) {
- int xxx=0;
- //printf("OggVorbis: Packetout: need more data, paging!\n");
- while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
- if(ret == -1)
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
- else
- if(ret == 0) {
- //printf("OggVorbis: Pageout: need more data to verify page, reading more data.\n");
- /* submit a readlen k block to libvorbis' Ogg layer */
- buffer=ogg_sync_buffer(&sh_audio->ov->oy,readlen);
- bytes=demux_read_data(sh_audio->ds,buffer,readlen);
- xxx+=bytes;
- ogg_sync_wrote(&sh_audio->ov->oy,bytes);
- if(bytes==0)
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: 0Bytes written, possible End of Stream\n");
- }
- }
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[sync: %d ]\n",xxx);
- //printf("OggVorbis: Pageout: successfull, pagin in.\n");
- if(ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og)<0)
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pagein failed!\n");
- break;
- } else if(ret<0) {
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Packetout: missing or corrupt data, skipping packet!\n");
- break;
- } else {
-
- /* we have a packet. Decode it */
-
- if(vorbis_synthesis(&sh_audio->ov->vb,&sh_audio->ov->op)==0) /* test for success! */
- vorbis_synthesis_blockin(&sh_audio->ov->vd,&sh_audio->ov->vb);
-
- /* **pcm is a multichannel float vector. In stereo, for
- example, pcm[0] is left, and pcm[1] is right. samples is
- the size of each channel. Convert the float values
- (-1.<=range<=1.) to whatever PCM format and write it out */
-
- while((samples=vorbis_synthesis_pcmout(&sh_audio->ov->vd,&pcm))>0){
- int i,j;
- int clipflag=0;
- int convsize=(maxlen-len)/(2*sh_audio->ov->vi.channels); // max size!
- int bout=(samples<convsize?samples:convsize);
+ case AFM_VORBIS: { // Vorbis
+ int samples;
+ float **pcm;
+ ogg_packet op;
+ char* np;
+ struct ov_struct_st *ov = sh_audio->context;
+ len = 0;
+ op.b_o_s = op.e_o_s = 0;
+ while(len < minlen) {
+ op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
+ if(!op.packet)
+ break;
+ if(vorbis_synthesis(&ov->vb,&op)==0) /* test for success! */
+ vorbis_synthesis_blockin(&ov->vd,&ov->vb);
+ while((samples=vorbis_synthesis_pcmout(&ov->vd,&pcm))>0){
+ int i,j;
+ int clipflag=0;
+ int convsize=(maxlen-len)/(2*ov->vi.channels); // max size!
+ int bout=(samples<convsize?samples:convsize);
- if(bout<=0) break;
-
- /* convert floats to 16 bit signed ints (host order) and
- interleave */
- for(i=0;i<sh_audio->ov->vi.channels;i++){
- ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
- ogg_int16_t *ptr=convbuffer+i;
- float *mono=pcm[i];
- for(j=0;j<bout;j++){
+ if(bout<=0) break;
+
+ /* convert floats to 16 bit signed ints (host order) and
+ interleave */
+ for(i=0;i<ov->vi.channels;i++){
+ ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
+ ogg_int16_t *ptr=convbuffer+i;
+ float *mono=pcm[i];
+ for(j=0;j<bout;j++){
#if 1
- int val=mono[j]*32767.f;
+ int val=mono[j]*32767.f;
#else /* optional dither */
- int val=mono[j]*32767.f+drand48()-0.5f;
+ int val=mono[j]*32767.f+drand48()-0.5f;
#endif
- /* might as well guard against clipping */
- if(val>32767){
- val=32767;
- clipflag=1;
- }
- if(val<-32768){
- val=-32768;
- clipflag=1;
+ /* might as well guard against clipping */
+ if(val>32767){
+ val=32767;
+ clipflag=1;
+ }
+ if(val<-32768){
+ val=-32768;
+ clipflag=1;
+ }
+ *ptr=val;
+ ptr+=ov->vi.channels;
}
- *ptr=val;
- ptr+=sh_audio->ov->vi.channels;
}
- }
- if(clipflag)
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"Clipping in frame %ld\n",(long)(sh_audio->ov->vd.sequence));
-
- //fwrite(convbuffer,2*sh_audio->ov->vi.channels,bout,stderr); //dump pcm to file for debugging
- //memcpy(buf+len,convbuffer,2*sh_audio->ov->vi.channels*bout);
- len+=2*sh_audio->ov->vi.channels*bout;
-
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[decoded: %d / %d ]\n",bout,samples);
-
- vorbis_synthesis_read(&sh_audio->ov->vd,bout); /* tell libvorbis how
- many samples we
- actually consumed */
- }
- } // from else, packetout ok
- } // while len
- } // outer while len
- if(ogg_page_eos(&sh_audio->ov->og))
- mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: End of Stream reached!\n"); // FIXME clearup decoder, notify mplayer - atmos
-
- mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[len: %d ]\n",len);
-
- break;
- }
+ if(clipflag)
+ mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"Clipping in frame %ld\n",(long)(ov->vd.sequence));
+ len+=2*ov->vi.channels*bout;
+ mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[decoded: %d / %d ]\n",bout,samples);
+ vorbis_synthesis_read(&ov->vd,bout); /* tell libvorbis how
+ many samples we
+ actually consumed */
+ }
+ }
+ } break;
#endif
case AFM_PCM: // AVI PCM
len=demux_read_data(sh_audio->ds,buf,minlen);
@@ -1337,13 +1217,6 @@ void resync_audio_stream(sh_audio_t *sh_audio){
MP3_DecodeFrame(NULL,-2); // resync
MP3_DecodeFrame(NULL,-2); // resync
break;
-#ifdef HAVE_OGGVORBIS
- case AFM_VORBIS:
- //printf("OggVorbis: resetting stream.\n");
- ogg_sync_reset(&sh_audio->ov->oy);
- ogg_stream_reset(&sh_audio->ov->os);
- break;
-#endif
#ifdef USE_LIBAC3
case AFM_AC3:
ac3_bitstream_reset(); // reset AC3 bitstream buffer
diff --git a/libmpdemux/Makefile b/libmpdemux/Makefile
index fa6236f45a..b85d0dcad4 100644
--- a/libmpdemux/Makefile
+++ b/libmpdemux/Makefile
@@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a
include ../config.mak
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c opt-reg.c mpdemux.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c opt-reg.c mpdemux.c demux_ogg.c
ifeq ($(STREAMING),yes)
SRCS += asf_streaming.c url.c http.c network.c rtp.c
endif
diff --git a/libmpdemux/demux_ogg.c b/libmpdemux/demux_ogg.c
new file mode 100644
index 0000000000..de86878aef
--- /dev/null
+++ b/libmpdemux/demux_ogg.c
@@ -0,0 +1,597 @@
+
+#include "config.h"
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "../mp_msg.h"
+#include "../help_mp.h"
+#include "stream.h"
+#include "demuxer.h"
+#include "stheader.h"
+
+#ifndef HAVE_OGGVORBIS
+/// Some dummy function to use when no Ogg and Vorbis lib are avaible
+int demux_ogg_open(demuxer_t* demuxer) {
+ return 0;
+}
+
+int demux_ogg_fill_buffer(demuxer_t *d) {
+ return 0;
+}
+
+demuxer_t* init_avi_with_ogg(demuxer_t* demuxer) {
+ mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_NoOggVorbis);
+ // disable audio
+ demuxer->audio->id = -2;
+ return demuxer;
+}
+#else
+
+#include <ogg/ogg.h>
+#include <vorbis/codec.h>
+
+#define BLOCK_SIZE 1024
+
+/// 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 */
+ vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+ vorbis_block vb; /* local working space for packet->PCM decode */
+} ov_struct_t;
+
+//// 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
+
+/// 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;
+} 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;
+} ogg_demuxer_t;
+
+/// 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
+
+
+// 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;
+ }
+
+ if(id == ogg_d->num_sub)
+ return -1;
+
+ if(os)
+ *os = &ogg_d->subs[id].stream;
+
+ return id;
+
+}
+
+/// 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;
+
+ // If packet is an header we jump it except for vorbis
+ if((*pack->packet & PACKET_TYPE_HEADER) &&
+ (ds == d->video || (ds == d->audio && ((sh_audio_t*)ds->sh)->format != 0xFFFE )))
+ return 0;
+
+ // For vorbis packet the packet is the data, for other codec we must jump the header
+ if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == 0xFFFE) {
+ data = pack->packet;
+ if(*pack->packet & PACKET_TYPE_HEADER)
+ pts = 0;
+ else {
+ vorbis_info* vi = &((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi;
+ // When we dump the audio, there is no vi, but we dont care of timestamp in this case
+ if(vi) {
+ 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;
+ }
+ }
+ } 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
+ else if(*pack->packet & PACKET_IS_SYNCPOINT)
+ flags = 1;
+ pts = pack->granulepos/os->samplerate;
+ // Save the packet length and timestamp
+ os->lastsize = 0;
+ while(hdrlen) {
+ os->lastsize <<= 8;
+ os->lastsize |= pack->packet[hdrlen];
+ hdrlen--;
+ }
+ os->lastpos = pack->granulepos;
+ }
+
+ /// Send the packet
+ dp = new_demux_packet(pack->bytes-(data-pack->packet));
+ memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));
+ ds->pts = pts;
+ ds->flags = flags;
+ ds_add_packet(ds,dp);
+ return 1;
+}
+
+/// Open an ogg physical stream
+int demux_ogg_open(demuxer_t* demuxer) {
+ ogg_demuxer_t* ogg_d;
+ stream_t *s;
+ char* buf;
+ int np,s_no, n_audio = 0, n_video = 0;
+ ogg_sync_state* sync;
+ ogg_page* page;
+ ogg_packet pack;
+ sh_audio_t* sh_a;
+ sh_video_t* sh_v;
+
+ s = demuxer->stream;
+
+ ogg_d = (ogg_demuxer_t*)calloc(1,sizeof(ogg_demuxer_t));
+ sync = &ogg_d->sync;
+ page = &ogg_d->page;
+
+ ogg_sync_init(&ogg_d->sync);
+
+ while(1) {
+ /// Try to get a page
+ np = ogg_sync_pageout(sync,page);
+ /// Error
+ if(np < 0) {
+ mp_msg(MSGT_DEMUX,MSGL_DBG2,"OGG demuxer : Bad page sync\n");
+ return 0;
+ }
+ /// Need some more data
+ if(np <= 0) {
+ 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;
+ }
+
+ // 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
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG : Warning found none bos page from unknow stream %d\n",ogg_page_serialno(page));
+ 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;
+ n_audio++;
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG : stream %d is vorbis\n",ogg_d->num_sub);
+
+ /// Check for old header
+ } else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) {
+
+ // Old video header
+ if(*(int32_t*)(pack.packet+96) == 0x05589f80 && pack.bytes >= 184) {
+ sh_v = new_sh_video(demuxer,ogg_d->num_sub);
+ sh_v->bih = (BITMAPINFOHEADER*)calloc(1,sizeof(BITMAPINFOHEADER));
+ sh_v->format = mmioFOURCC(pack.packet[68],pack.packet[69],
+ pack.packet[70],pack.packet[71]);
+ sh_v->frametime = (*(int64_t*)(pack.packet+164))*0.0000001;
+ sh_v->fps = 1/sh_v->frametime;
+ sh_v->disp_w = sh_v->bih->biWidth = *(int32_t*)(pack.packet+176);
+ sh_v->disp_h = sh_v->bih->biHeight = *(int32_t*)(pack.packet+180);
+ sh_v->bih->biBitCount = *(int16_t*)(pack.packet+182);
+
+ ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
+ n_video++;
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is video\n",ogg_d->num_sub);
+
+ // Old audio header
+ } else if(*(int32_t*)pack.packet+96 == 0x05589F81) {
+ unsigned int extra_size;
+ sh_a = new_sh_audio(demuxer,ogg_d->num_sub);
+ extra_size = *(int16_t*)(pack.packet+140);
+ sh_a->wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)+extra_size);
+ sh_a->format = sh_a->wf->wFormatTag = *(int16_t*)(pack.packet+124);
+ sh_a->channels = sh_a->wf->nChannels = *(int16_t*)(pack.packet+126);
+ sh_a->samplerate = sh_a->wf->nSamplesPerSec = *(int32_t*)(pack.packet+128);
+ sh_a->wf->nAvgBytesPerSec = *(int32_t*)(pack.packet+132);
+ sh_a->wf->nBlockAlign = *(int16_t*)(pack.packet+136);
+ sh_a->wf->wBitsPerSample = *(int16_t*)(pack.packet+138);
+ 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);
+
+ ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate * sh_a->channels;
+ n_audio++;
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is audio\n",ogg_d->num_sub);
+ } else
+ mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG stream %d contain an old header but the header type is unknow\n",ogg_d->num_sub);
+
+ // 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));
+ sh_v->format = mmioFOURCC(st->subtype[0],st->subtype[1],
+ st->subtype[2],st->subtype[3]);
+ sh_v->frametime = st->time_unit*0.0000001;
+ sh_v->fps = 1/sh_v->frametime;
+ sh_v->bih->biSize = st->buffersize;
+ sh_v->bih->biBitCount = st->bits_per_sample;
+ sh_v->disp_w = sh_v->bih->biWidth = st->sh.video.width;
+ sh_v->disp_h = sh_v->bih->biHeight = st->sh.video.height;
+
+ ogg_d->subs[ogg_d->num_sub].samplerate= sh_v->fps;
+ n_video++;
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is video\n",ogg_d->num_sub);
+ /// New audio header
+ } else if(strncmp(st->streamtype,"audio",5) == 0) {
+ char buffer[5];
+ unsigned int extra_size = st->size - sizeof(stream_header);
+ 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);
+ sh_a->format = sh_a->wf->wFormatTag = atoi(buffer);
+ sh_a->channels = sh_a->wf->nChannels = st->sh.audio.channels;
+ sh_a->samplerate = sh_a->wf->nSamplesPerSec = st->samples_per_unit;
+ sh_a->wf->nAvgBytesPerSec = st->sh.audio.avgbytespersec;
+ sh_a->wf->nBlockAlign = st->sh.audio.blockalign;
+ sh_a->wf->wBitsPerSample = st->bits_per_sample;
+ 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);
+
+ ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate * sh_a->channels;
+ n_audio++;
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is audio\n",ogg_d->num_sub);
+
+ /// Check for text (subtitles) header
+ } else if(strncmp(st->streamtype,"text",4) == 0) {
+ mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG text stream are not supported\n");
+ //// Unknow header type
+ } else
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG stream %d has a header marker but is of an unknow type\n",ogg_d->num_sub);
+ /// Unknow (invalid ?) header
+ } else
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG stream %d is of an unknow type\n",ogg_d->num_sub);
+
+ 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;
+ demuxer->audio->sh = sh_a;
+ sh_a->ds = demuxer->audio;
+ }
+ /// Is it the stream we want
+ if(demuxer->audio->id == ogg_d->num_sub)
+ ds = demuxer->audio;
+ }
+ if(sh_v) {
+ /// Also for video
+ if(demuxer->video->id == -1) {
+ demuxer->video->id = ogg_d->num_sub;
+ demuxer->video->sh = sh_v;
+ sh_v->ds = demuxer->video;
+ }
+ if(demuxer->video->id == ogg_d->num_sub)
+ ds = demuxer->video;
+ }
+ /// Add the packet contained in this page
+ if(ds) {
+ /// 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);
+
+ }
+ }
+ ogg_d->num_sub++;
+ }
+
+ /// Finish to setup the demuxer
+ demuxer->priv = ogg_d;
+ /// We can't seek :(
+ demuxer->seekable = 0;
+
+ if(!n_video)
+ demuxer->video->id = -2;
+ if(!n_audio)
+ demuxer->audio->id = -2;
+
+ mp_msg(MSGT_DEMUX,MSGL_V,"OGG demuxer : found %d audio stream and %d video stream\n",n_audio,n_video);
+
+ 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;
+ /// Get the next page from the physical stream
+ while( (pa = ogg_sync_pageout(sync,page)) != 1) {
+ /// Error : we skip some bytes
+ if(pa < 0) {
+ mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG : Page out not synced, we skip some bytes\n");
+ 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
+
+ /// Find the page's logical stream
+ if( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
+ mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG demuxer error : we met an unknow stream\n");
+ 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");
+ }
+ } 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;
+
+ if(ds) {
+ if(!demux_ogg_add_packet(ds,&ogg_d->subs[id],&pack))
+ continue; /// Unuseful packet, get another
+ 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
+ if(sh_audio->wf->cbSize < 3*sizeof(uint32_t)) {
+ 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
+ memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
+
+ /// Check the size
+ if(sh_audio->wf->cbSize < 3*sizeof(uint32_t) + sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1] + hdrsizes[2]) {
+ 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));
+
+ // 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'