comparison libmpdemux/demux_ogg.c @ 5732:6586448b5243

Seeking implemented
author albeu
date Sat, 20 Apr 2002 17:50:11 +0000
parents 779ebb242aec
children 4b24942acdbb
comparison
equal deleted inserted replaced
5731:56983ecb89aa 5732:6586448b5243
81 } sh; 81 } sh;
82 } stream_header; 82 } stream_header;
83 83
84 /// Our private datas 84 /// Our private datas
85 85
86 typedef struct ogg_syncpoint {
87 int64_t granulepos;
88 off_t page_pos;
89 } ogg_syncpoint_t;
90
86 /// A logical stream 91 /// A logical stream
87 typedef struct ogg_stream { 92 typedef struct ogg_stream {
88 /// Timestamping stuff 93 /// Timestamping stuff
89 float samplerate; /// granulpos 2 time 94 float samplerate; /// granulpos 2 time
90 int64_t lastpos; 95 int64_t lastpos;
91 int32_t lastsize; 96 int32_t lastsize;
92 97
93 // Logical stream state 98 // Logical stream state
94 ogg_stream_state stream; 99 ogg_stream_state stream;
100 int hdr_packets;
101 int vorbis;
95 } ogg_stream_t; 102 } ogg_stream_t;
96 103
97 typedef struct ogg_demuxer { 104 typedef struct ogg_demuxer {
98 /// Physical stream state 105 /// Physical stream state
99 ogg_sync_state sync; 106 ogg_sync_state sync;
100 /// Current page 107 /// Current page
101 ogg_page page; 108 ogg_page page;
102 /// Logical streams 109 /// Logical streams
103 ogg_stream_t *subs; 110 ogg_stream_t *subs;
104 int num_sub; 111 int num_sub;
112 ogg_syncpoint_t* syncpoints;
113 int num_syncpoint;
105 } ogg_demuxer_t; 114 } ogg_demuxer_t;
115
116 #define NUM_VORBIS_HDR_PACKETS 3
106 117
107 /// Some defines from OggDS 118 /// Some defines from OggDS
108 #define PACKET_TYPE_HEADER 0x01 119 #define PACKET_TYPE_HEADER 0x01
109 #define PACKET_TYPE_BITS 0x07 120 #define PACKET_TYPE_BITS 0x07
110 #define PACKET_LEN_BITS01 0xc0 121 #define PACKET_LEN_BITS01 0xc0
133 144
134 return id; 145 return id;
135 146
136 } 147 }
137 148
138 /// Calculate the timestamp and add the packet to the demux stream 149 static unsigned char* demux_ogg_read_packet(ogg_stream_t* os,ogg_packet* pack,vorbis_info* vi,float* pts,int* flags) {
139 // return 1 if the packet was added, 0 otherwise
140 static int demux_ogg_add_packet(demux_stream_t* ds,ogg_stream_t* os,ogg_packet* pack) {
141 demuxer_t* d = ds->demuxer;
142 demux_packet_t* dp;
143 unsigned char* data; 150 unsigned char* data;
144 float pts = 0; 151
145 int flags = 0; 152 *pts = 0;
146 153 *flags = 0;
147 // If packet is an header we jump it except for vorbis 154
148 if((*pack->packet & PACKET_TYPE_HEADER) && 155 if(os->vorbis) {
149 (ds == d->video || (ds == d->audio && ((sh_audio_t*)ds->sh)->format != 0xFFFE )))
150 return 0;
151
152 // For vorbis packet the packet is the data, for other codec we must jump the header
153 if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == 0xFFFE) {
154 data = pack->packet; 156 data = pack->packet;
155 if(*pack->packet & PACKET_TYPE_HEADER) 157 if(*pack->packet & PACKET_TYPE_HEADER)
156 pts = 0; 158 os->hdr_packets++;
157 else { 159 else if(vi) {
158 vorbis_info* vi = &((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi;
159 // When we dump the audio, there is no vi, but we dont care of timestamp in this case 160 // When we dump the audio, there is no vi, but we dont care of timestamp in this case
160 if(vi) { 161 int32_t blocksize = vorbis_packet_blocksize(vi,pack) / vi->channels;
161 int32_t blocksize = vorbis_packet_blocksize(vi,pack) / vi->channels; 162 // Calculate the timestamp if the packet don't have any
162 // Calculate the timestamp if the packet don't have any 163 if(pack->granulepos == -1) {
163 if(pack->granulepos == -1) { 164 pack->granulepos = os->lastpos;
164 pack->granulepos = os->lastpos; 165 if(os->lastsize > 0)
165 if(os->lastsize > 0) 166 pack->granulepos += os->lastsize;
166 pack->granulepos += os->lastsize;
167 }
168 pts = pack->granulepos / (float)vi->rate;
169 os->lastsize = blocksize;
170 os->lastpos = pack->granulepos;
171 } 167 }
168 *pts = pack->granulepos / (float)vi->rate;
169 os->lastsize = blocksize;
170 os->lastpos = pack->granulepos;
172 } 171 }
173 } else { 172 } else {
174 // Find data start 173 // Find data start
175 int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6; 174 int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6;
176 hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1; 175 hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1;
177 data = pack->packet + 1 + hdrlen; 176 data = pack->packet + 1 + hdrlen;
178 // Calculate the timestamp 177 // Calculate the timestamp
179 if(pack->granulepos == -1) 178 if(pack->granulepos == -1)
180 pack->granulepos = os->lastpos + os->lastsize; 179 pack->granulepos = os->lastpos + os->lastsize;
181 // If we alredy have a timestamp it can be a syncpoint 180 // If we alredy have a timestamp it can be a syncpoint
182 else if(*pack->packet & PACKET_IS_SYNCPOINT) 181 if(*pack->packet & PACKET_IS_SYNCPOINT)
183 flags = 1; 182 *flags = 1;
184 pts = pack->granulepos/os->samplerate; 183 *pts = pack->granulepos/os->samplerate;
185 // Save the packet length and timestamp 184 // Save the packet length and timestamp
186 os->lastsize = 0; 185 os->lastsize = 0;
187 while(hdrlen) { 186 while(hdrlen) {
188 os->lastsize <<= 8; 187 os->lastsize <<= 8;
189 os->lastsize |= pack->packet[hdrlen]; 188 os->lastsize |= pack->packet[hdrlen];
190 hdrlen--; 189 hdrlen--;
191 } 190 }
192 os->lastpos = pack->granulepos; 191 os->lastpos = pack->granulepos;
193 } 192 }
193 return data;
194 }
195
196 /// Calculate the timestamp and add the packet to the demux stream
197 // return 1 if the packet was added, 0 otherwise
198 static int demux_ogg_add_packet(demux_stream_t* ds,ogg_stream_t* os,ogg_packet* pack) {
199 demuxer_t* d = ds->demuxer;
200 demux_packet_t* dp;
201 unsigned char* data;
202 float pts = 0;
203 int flags = 0;
204
205 // If packet is an header we jump it except for vorbis
206 if((*pack->packet & PACKET_TYPE_HEADER) &&
207 (ds == d->video || (ds == d->audio && ( ((sh_audio_t*)ds->sh)->format != 0xFFFE || os->hdr_packets >= NUM_VORBIS_HDR_PACKETS ) ) ))
208 return 0;
209
210 // For vorbis packet the packet is the data, for other codec we must jump the header
211 if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == 0xFFFE)
212 data = demux_ogg_read_packet(os,pack,&((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi,
213 &pts,&flags);
214 else
215 data = demux_ogg_read_packet(os,pack,NULL,&pts,&flags);
216
194 217
195 /// Send the packet 218 /// Send the packet
196 dp = new_demux_packet(pack->bytes-(data-pack->packet)); 219 dp = new_demux_packet(pack->bytes-(data-pack->packet));
197 memcpy(dp->buffer,data,pack->bytes-(data-pack->packet)); 220 memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));
198 dp->pts = pts; 221 dp->pts = pts;
199 dp->flags = flags; 222 dp->flags = flags;
200 ds_add_packet(ds,dp); 223 ds_add_packet(ds,dp);
201 if(verbose>1)printf("New dp: %p ds=%p pts=%5.3f len=%d flag=%d \n", 224 if(verbose>1)printf("New dp: %p ds=%p pts=%5.3f len=%d flag=%d \n",
202 dp, ds, pts, dp->len, flags); 225 dp, ds, pts, dp->len, flags);
203 return 1; 226 return 1;
227 }
228
229 /// Build a table of all syncpoints to make seeking easier
230 void demux_ogg_build_syncpoints_table(demuxer_t* demuxer) {
231 ogg_demuxer_t* ogg_d = demuxer->priv;
232 stream_t *s = demuxer->stream;
233 ogg_sync_state* sync = &ogg_d->sync;
234 ogg_page* page= &ogg_d->page;
235 ogg_stream_state* oss;
236 ogg_stream_t* os;
237 ogg_packet op;
238 int np,sid,p;
239 vorbis_info* vi = NULL;
240 off_t pos, last_pos;
241 pos = last_pos = demuxer->movi_start;
242
243 // Reset the stream
244 stream_seek(s,demuxer->movi_start);
245 ogg_sync_reset(sync);
246
247 // Get the serial number of the stream we use
248 if(demuxer->video->id >= 0)
249 sid = demuxer->video->id;
250 else {
251 sid = demuxer->audio->id;
252 if(((sh_audio_t*)demuxer->audio->sh)->format == 0xFFFE)
253 vi = &((ov_struct_t*)((sh_audio_t*)demuxer->audio->sh)->context)->vi;
254 }
255 os = &ogg_d->subs[sid];
256 oss = &os->stream;
257
258 while(1) {
259 np = ogg_sync_pageseek(sync,page);
260 if(np < 0) { // We had to skip some bytes
261 mp_msg(MSGT_DEMUX,MSGL_ERR,"Bad page sync while building syncpoints table (%ld)\n",-np);
262 pos += -np;
263 continue;
264 }
265 if(np <= 0) { // We need more data
266 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
267 int len = stream_read(s,buf,BLOCK_SIZE);
268 if(len == 0 && s->eof)
269 break;
270 ogg_sync_wrote(sync,len);
271 continue;
272 }
273 // The page is ready
274 //ogg_sync_pageout(sync,page);
275 if(ogg_page_serialno(page) != os->stream.serialno) { // It isn't a page from the stream we want
276 pos += np;
277 continue;
278 }
279 if(ogg_stream_pagein(oss,page) != 0) {
280 mp_msg(MSGT_DEMUX,MSGL_ERR,"Pagein error ????\n");
281 pos += np;
282 continue;
283 }
284 p = 0;
285 while(ogg_stream_packetout(oss,&op) == 1) {
286 float pts;
287 int flags;
288 demux_ogg_read_packet(os,&op,vi,&pts,&flags);
289 if(flags || (os->vorbis && op.granulepos >= 0)) {
290 ogg_d->syncpoints = (ogg_syncpoint_t*)realloc(ogg_d->syncpoints,(ogg_d->num_syncpoint+1)*sizeof(ogg_syncpoint_t));
291 ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos = op.granulepos;
292 ogg_d->syncpoints[ogg_d->num_syncpoint].page_pos = (ogg_page_continued(page) && p == 0) ? last_pos : pos;
293 ogg_d->num_syncpoint++;
294 }
295 p++;
296 }
297 if(p > 0)
298 last_pos = pos;
299 pos += np;
300 }
301
302 mp_msg(MSGT_DEMUX,MSGL_V,"Ogg syncpoints table builed: %d syncpoints\n",ogg_d->num_syncpoint);
303
304 stream_reset(s);
305 stream_seek(s,demuxer->movi_start);
306 ogg_sync_reset(sync);
307 for(np = 0 ; np < ogg_d->num_sub ; np++) {
308 ogg_stream_reset(&ogg_d->subs[np].stream);
309 ogg_d->subs[np].lastpos = ogg_d->subs[np].lastsize = ogg_d->subs[np].hdr_packets = 0;
310 }
311
312
313 // Get the first page
314 while(1) {
315 np = ogg_sync_pageout(sync,page);
316 if(np <= 0) { // We need more data
317 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
318 int len = stream_read(s,buf,BLOCK_SIZE);
319 if(len == 0 && s->eof) {
320 mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to get the first page !!!!\n");
321 break;
322 }
323
324 ogg_sync_wrote(sync,len);
325 continue;
326 }
327 demux_ogg_get_page_stream(ogg_d,&oss);
328 ogg_stream_pagein(oss,page);
329 break;
330 }
331
204 } 332 }
205 333
206 /// Open an ogg physical stream 334 /// Open an ogg physical stream
207 int demux_ogg_open(demuxer_t* demuxer) { 335 int demux_ogg_open(demuxer_t* demuxer) {
208 ogg_demuxer_t* ogg_d; 336 ogg_demuxer_t* ogg_d;
274 402
275 // Check for Vorbis 403 // Check for Vorbis
276 if(pack.bytes >= 7 && ! strncmp(&pack.packet[1],"vorbis", 6) ) { 404 if(pack.bytes >= 7 && ! strncmp(&pack.packet[1],"vorbis", 6) ) {
277 sh_a = new_sh_audio(demuxer,ogg_d->num_sub); 405 sh_a = new_sh_audio(demuxer,ogg_d->num_sub);
278 sh_a->format = 0xFFFE; 406 sh_a->format = 0xFFFE;
407 ogg_d->subs[ogg_d->num_sub].vorbis = 1;
279 n_audio++; 408 n_audio++;
280 mp_msg(MSGT_DEMUX,MSGL_V,"OGG : stream %d is vorbis\n",ogg_d->num_sub); 409 mp_msg(MSGT_DEMUX,MSGL_V,"OGG : stream %d is vorbis\n",ogg_d->num_sub);
281 410
282 /// Check for old header 411 /// Check for old header
283 } else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) { 412 } else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) {
409 // if(sh_v->bih) print_video_header(sh_v->bih); 538 // if(sh_v->bih) print_video_header(sh_v->bih);
410 } 539 }
411 if(demuxer->video->id == ogg_d->num_sub) 540 if(demuxer->video->id == ogg_d->num_sub)
412 ds = demuxer->video; 541 ds = demuxer->video;
413 } 542 }
414 /// Add the packet contained in this page 543 /// Add the header packets if the stream isn't seekable
415 if(ds) { 544 if(ds && !s->end_pos) {
416 /// Finish the page, otherwise packets will be lost 545 /// Finish the page, otherwise packets will be lost
417 do { 546 do {
418 demux_ogg_add_packet(ds,&ogg_d->subs[ogg_d->num_sub],&pack); 547 demux_ogg_add_packet(ds,&ogg_d->subs[ogg_d->num_sub],&pack);
419 } while(ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack) == 1); 548 } while(ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack) == 1);
420 549 }
421 }
422 } 550 }
423 ogg_d->num_sub++; 551 ogg_d->num_sub++;
424 } 552 }
425 553
426 /// Finish to setup the demuxer 554 /// Finish to setup the demuxer
427 demuxer->priv = ogg_d; 555 demuxer->priv = ogg_d;
428 /// We can't seek :(
429 demuxer->seekable = 0;
430 556
431 if(!n_video) 557 if(!n_video)
432 demuxer->video->id = -2; 558 demuxer->video->id = -2;
433 if(!n_audio) 559 if(!n_audio)
434 demuxer->audio->id = -2; 560 demuxer->audio->id = -2;
561
562 if(!s->end_pos)
563 demuxer->seekable = 0;
564 else {
565 demuxer->movi_start = 0;
566 demuxer->movi_end = s->end_pos;
567 demux_ogg_build_syncpoints_table(demuxer);
568 }
435 569
436 mp_msg(MSGT_DEMUX,MSGL_V,"OGG demuxer : found %d audio stream and %d video stream\n",n_audio,n_video); 570 mp_msg(MSGT_DEMUX,MSGL_V,"OGG demuxer : found %d audio stream and %d video stream\n",n_audio,n_video);
437 571
438 return 1; 572 return 1;
439 } 573 }
606 demuxer->audio->id = -2; 740 demuxer->audio->id = -2;
607 return demuxer; 741 return demuxer;
608 742
609 } 743 }
610 744
611 /// TODO : Seeking 8-) 745 void demux_ogg_seek(demuxer_t *demuxer,float rel_seek_secs,int flags) {
612 746 ogg_demuxer_t* ogg_d = demuxer->priv;
747 ogg_sync_state* sync = &ogg_d->sync;
748 ogg_page* page= &ogg_d->page;
749 ogg_stream_state* oss;
750 ogg_stream_t* os;
751 demux_stream_t* ds;
752 sh_audio_t* sh_audio = demuxer->audio->sh;
753 //sh_video_t* sh_video = demuxer->video->sh;
754 ogg_packet op;
755 float time_pos,rate;
756 int i,sp;
757 vorbis_info* vi = NULL;
758 int64_t gp;
759
760 if(!ogg_d->syncpoints)
761 return;
762
763 if(demuxer->video->id >= 0) {
764 ds = demuxer->video;
765 rate = ogg_d->subs[ds->id].samplerate;
766 } else {
767 ds = demuxer->audio;
768 vi = &((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi;
769 rate = (float)vi->rate;
770 }
771
772 os = &ogg_d->subs[ds->id];
773 oss = &os->stream;
774
775 time_pos = flags & 1 ? 0 : os->lastpos/ rate;
776 if(flags & 2)
777 time_pos += ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos / rate * rel_seek_secs;
778 else
779 time_pos += rel_seek_secs;
780
781 gp = time_pos * rate;
782
783 for(sp = 0; sp < ogg_d->num_syncpoint ; sp++) {
784 if(ogg_d->syncpoints[sp].granulepos >= gp)
785 break;
786 }
787
788 if(sp >= ogg_d->num_syncpoint)
789 return;
790
791 stream_seek(demuxer->stream,ogg_d->syncpoints[sp].page_pos);
792 ogg_sync_reset(sync);
793 for(i = 0 ; i < ogg_d->num_sub ; i++)
794 ogg_stream_reset(&ogg_d->subs[i].stream);
795
796 while(1) {
797 int np = ogg_sync_pageout(sync,page);
798 if(np <= 0) { // We need more data
799 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
800 int len = stream_read(demuxer->stream,buf,BLOCK_SIZE);
801 if(len == 0 && demuxer->stream->eof) {
802 mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to seek !!!!\n");
803 break;
804 }
805 ogg_sync_wrote(sync,len);
806 continue;
807 }
808
809 if(ogg_page_serialno(page) != os->stream.serialno)
810 continue;
811 if(ogg_stream_pagein(oss,page) != 0)
812 continue;
813
814 while(1) {
815 np = ogg_stream_packetpeek(oss,&op);
816 if(np < 0) {
817 ogg_stream_packetout(oss,&op);
818 continue;
819 } else if(np == 0)
820 break;
821 else {
822 float pts;
823 int f;
824 demux_ogg_read_packet(os,&op,vi,&pts,&f);
825 if(f || (os->vorbis && op.granulepos >= gp)) {
826 if(sh_audio)
827 resync_audio_stream(sh_audio);
828 return;
829 }
830 ogg_stream_packetout(oss,&op);
831 demux_ogg_read_packet(os,&op,vi,&pts,&f);
832 }
833 }
834 }
835
836 mp_msg(MSGT_DEMUX,MSGL_ERR,"Can't find the good packet :(\n");
837
838 }
839
613 #endif 840 #endif