Remove unnecessary emms Assembler instructions.
[mplayer/glamo.git] / libmpdemux / demux_ogg.c
blob25617145171ab65325e5efd0fa99345858ded678
2 #include "config.h"
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <math.h>
9 #include <inttypes.h>
11 #include "mp_msg.h"
12 #include "help_mp.h"
13 #include "stream/stream.h"
14 #include "demuxer.h"
15 #include "stheader.h"
16 #include "libavutil/intreadwrite.h"
18 #define FOURCC_VORBIS mmioFOURCC('v', 'r', 'b', 's')
19 #define FOURCC_SPEEX mmioFOURCC('s', 'p', 'x', ' ')
20 #define FOURCC_THEORA mmioFOURCC('t', 'h', 'e', 'o')
22 #ifdef CONFIG_TREMOR
23 #include <tremor/ogg.h>
24 #include <tremor/ivorbiscodec.h>
25 #else
26 #include <ogg/ogg.h>
27 #include <vorbis/codec.h>
28 #endif
30 #ifdef CONFIG_OGGTHEORA
31 #include <theora/theora.h>
32 int _ilog (unsigned int); /* defined in many places in theora/lib/ */
33 #endif
35 #define BLOCK_SIZE 4096
37 /* Theora decoder context : we won't be able to interpret granule positions
38 * without using theora_granule_time with the theora_state of the stream.
39 * This is duplicated in `vd_theora.c'; put this in a common header?
41 #ifdef CONFIG_OGGTHEORA
42 typedef struct theora_struct_st {
43 theora_state st;
44 theora_comment cc;
45 theora_info inf;
46 } theora_struct_t;
47 #endif
49 //// OggDS headers
50 // Header for the new header format
51 typedef struct stream_header_video
53 ogg_int32_t width;
54 ogg_int32_t height;
55 } stream_header_video;
57 typedef struct stream_header_audio
59 ogg_int16_t channels;
60 ogg_int16_t blockalign;
61 ogg_int32_t avgbytespersec;
62 } stream_header_audio;
64 typedef struct __attribute__((__packed__)) stream_header
66 char streamtype[8];
67 char subtype[4];
69 ogg_int32_t size; // size of the structure
71 ogg_int64_t time_unit; // in reference time
72 ogg_int64_t samples_per_unit;
73 ogg_int32_t default_len; // in media time
75 ogg_int32_t buffersize;
76 ogg_int16_t bits_per_sample;
78 ogg_int16_t padding;
80 union
82 // Video specific
83 stream_header_video video;
84 // Audio specific
85 stream_header_audio audio;
86 } sh;
87 } stream_header;
89 /// Our private datas
91 typedef struct ogg_syncpoint {
92 int64_t granulepos;
93 off_t page_pos;
94 } ogg_syncpoint_t;
96 /// A logical stream
97 typedef struct ogg_stream {
98 /// Timestamping stuff
99 float samplerate; /// granulpos 2 time
100 int64_t lastpos;
101 int32_t lastsize;
102 int keyframe_frequency_force;
104 // Logical stream state
105 ogg_stream_state stream;
106 int hdr_packets;
107 int vorbis;
108 int speex;
109 int theora;
110 int flac;
111 int text;
112 int id;
114 vorbis_info vi;
115 int vi_initialized;
117 void *ogg_d;
118 } ogg_stream_t;
120 typedef struct ogg_demuxer {
121 /// Physical stream state
122 ogg_sync_state sync;
123 /// Current page
124 ogg_page page;
125 /// Logical streams
126 ogg_stream_t *subs;
127 int num_sub;
128 ogg_syncpoint_t* syncpoints;
129 int num_syncpoint;
130 off_t pos, last_size;
131 int64_t final_granulepos;
133 /* Used for subtitle switching. */
134 int n_text;
135 int *text_ids;
136 char **text_langs;
137 } ogg_demuxer_t;
139 #define NUM_VORBIS_HDR_PACKETS 3
141 /// Some defines from OggDS
142 #define PACKET_TYPE_HEADER 0x01
143 #define PACKET_TYPE_BITS 0x07
144 #define PACKET_LEN_BITS01 0xc0
145 #define PACKET_LEN_BITS2 0x02
146 #define PACKET_IS_SYNCPOINT 0x08
148 extern char *dvdsub_lang, *audio_lang;
149 extern int dvdsub_id;
151 //-------- subtitle support - should be moved to decoder layer, and queue
152 // - subtitles up in demuxer buffer...
154 #include "subreader.h"
155 #include "libvo/sub.h"
156 #define OGG_SUB_MAX_LINE 128
158 static subtitle ogg_sub;
159 //FILE* subout;
161 void demux_ogg_add_sub (ogg_stream_t* os,ogg_packet* pack) {
162 int lcv;
163 char *packet = pack->packet;
165 if (pack->bytes < 4)
166 return;
167 mp_msg(MSGT_DEMUX,MSGL_DBG2,"\ndemux_ogg_add_sub %02X %02X %02X '%s'\n",
168 (unsigned char)packet[0],
169 (unsigned char)packet[1],
170 (unsigned char)packet[2],
171 &packet[3]);
173 if (((unsigned char)packet[0]) == 0x88) { // some subtitle text
174 // Find data start
175 double endpts = MP_NOPTS_VALUE;
176 int32_t duration = 0;
177 int16_t hdrlen = (*packet & PACKET_LEN_BITS01)>>6, i;
178 hdrlen |= (*packet & PACKET_LEN_BITS2) <<1;
179 lcv = 1 + hdrlen;
180 if (pack->bytes < lcv)
181 return;
182 for (i = hdrlen; i > 0; i--) {
183 duration <<= 8;
184 duration |= (unsigned char)packet[i];
186 if (hdrlen > 0 && duration > 0) {
187 float pts;
188 if(pack->granulepos == -1)
189 pack->granulepos = os->lastpos + os->lastsize;
190 pts = (float)pack->granulepos/(float)os->samplerate;
191 endpts = 1.0 + pts + (float)duration/1000.0;
193 sub_clear_text(&ogg_sub, MP_NOPTS_VALUE);
194 sub_add_text(&ogg_sub, &packet[lcv], pack->bytes - lcv, endpts);
197 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg sub lines: %d first: '%s'\n",
198 ogg_sub.lines, ogg_sub.text[0]);
199 #ifdef CONFIG_ICONV
200 subcp_recode(&ogg_sub);
201 #endif
202 vo_sub = &ogg_sub;
203 vo_osd_changed(OSDTYPE_SUBTITLE);
207 // get the logical stream of the current page
208 // fill os if non NULL and return the stream id
209 static int demux_ogg_get_page_stream(ogg_demuxer_t* ogg_d,ogg_stream_state** os) {
210 int id,s_no;
211 ogg_page* page = &ogg_d->page;
213 s_no = ogg_page_serialno(page);
215 for(id= 0; id < ogg_d->num_sub ; id++) {
216 if(s_no == ogg_d->subs[id].stream.serialno)
217 break;
220 if(id == ogg_d->num_sub) {
221 // If we have only one vorbis stream allow the stream id to change
222 // it's normal on radio stream (each song have an different id).
223 // But we (or the codec?) should check that the samplerate, etc
224 // doesn't change (for radio stream it's ok)
225 if(ogg_d->num_sub == 1 && ogg_d->subs[0].vorbis) {
226 ogg_stream_reset(&ogg_d->subs[0].stream);
227 ogg_stream_init(&ogg_d->subs[0].stream,s_no);
228 id = 0;
229 } else
230 return -1;
233 if(os)
234 *os = &ogg_d->subs[id].stream;
236 return id;
240 static unsigned char* demux_ogg_read_packet(ogg_stream_t* os,ogg_packet* pack,float* pts,int* flags, int samplesize) {
241 unsigned char* data = pack->packet;
243 *pts = 0;
244 *flags = 0;
246 if(os->vorbis) {
247 if(*pack->packet & PACKET_TYPE_HEADER)
248 os->hdr_packets++;
249 else if (os->vi_initialized)
251 vorbis_info *vi;
252 int32_t blocksize;
254 // When we dump the audio, there is no vi, but we don't care of timestamp in this case
255 vi = &(os->vi);
256 blocksize = vorbis_packet_blocksize(vi,pack) / samplesize;
257 // Calculate the timestamp if the packet don't have any
258 if(pack->granulepos == -1) {
259 pack->granulepos = os->lastpos;
260 if(os->lastsize > 0)
261 pack->granulepos += os->lastsize;
263 *pts = pack->granulepos / (float)vi->rate;
264 os->lastsize = blocksize;
265 os->lastpos = pack->granulepos;
267 } else if (os->speex) {
268 // whole packet (default)
269 # ifdef CONFIG_OGGTHEORA
270 } else if (os->theora) {
271 /* we pass complete packets to theora, mustn't strip the header! */
272 os->lastsize = 1;
274 /* header packets begin on 1-bit: thus check (*data&0x80). We don't
275 have theora_state st, until all header packets were passed to the
276 decoder. */
277 if (!(*data&0x80))
279 int keyframe_granule_shift=_ilog(os->keyframe_frequency_force-1);
280 int64_t iframemask = (1 << keyframe_granule_shift) - 1;
282 if (pack->granulepos >= 0)
284 os->lastpos = pack->granulepos >> keyframe_granule_shift;
285 os->lastpos += pack->granulepos & iframemask;
286 *flags = (pack->granulepos & iframemask) == 0;
288 else
290 os->lastpos++;
292 pack->granulepos = os->lastpos;
293 *pts = (double)os->lastpos / (double)os->samplerate;
295 #endif /* CONFIG_OGGTHEORA */
296 } else if (os->flac) {
297 /* we pass complete packets to flac, mustn't strip the header! */
298 if (os->flac == 2 && pack->packet[0] != 0xff)
299 return NULL;
300 } else {
301 if(*pack->packet & PACKET_TYPE_HEADER)
302 os->hdr_packets++;
303 else {
304 // Find data start
305 int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6;
306 hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1;
307 data = pack->packet + 1 + hdrlen;
308 // Calculate the timestamp
309 if(pack->granulepos == -1)
310 pack->granulepos = os->lastpos + (os->lastsize ? os->lastsize : 1);
311 // If we already have a timestamp it can be a syncpoint
312 if(*pack->packet & PACKET_IS_SYNCPOINT)
313 *flags = 1;
314 *pts = pack->granulepos/os->samplerate;
315 // Save the packet length and timestamp
316 os->lastsize = 0;
317 while(hdrlen) {
318 os->lastsize <<= 8;
319 os->lastsize |= pack->packet[hdrlen];
320 hdrlen--;
322 os->lastpos = pack->granulepos;
325 return data;
328 // check if clang has substring from comma separated langlist
329 static int demux_ogg_check_lang(const char *clang, const char *langlist)
331 const char *c;
333 if (!langlist || !*langlist)
334 return 0;
335 while ((c = strchr(langlist, ',')))
337 if (!strncasecmp(clang, langlist, c - langlist))
338 return 1;
339 langlist = &c[1];
341 if (!strncasecmp(clang, langlist, strlen(langlist)))
342 return 1;
343 return 0;
346 static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id);
348 /// Try to print out comments and also check for LANGUAGE= tag
349 static void demux_ogg_check_comments(demuxer_t *d, ogg_stream_t *os, int id, vorbis_comment *vc)
351 const char *hdr, *val;
352 char **cmt = vc->user_comments;
353 int index, i;
354 ogg_demuxer_t *ogg_d = d->priv;
355 static const struct table {
356 const char *ogg;
357 const char *mp;
358 } table[] = {
359 { "ENCODED_USING", "Software" },
360 { "ENCODER_URL", "Encoder URL" },
361 { "TITLE", "Name" },
362 { "ARTIST", "Artist" },
363 { "COMMENT", "Comments" },
364 { "DATE", "Creation Date" },
365 { "GENRE", "Genre" },
366 { "ALBUM", "Album" },
367 { "TRACKNUMBER", "Track" },
368 { NULL, NULL },
371 while(*cmt)
373 hdr = NULL;
374 if (!strncasecmp(*cmt, "LANGUAGE=", 9))
376 val = *cmt + 9;
377 if (ogg_d->subs[id].text)
378 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", ogg_d->subs[id].id, val);
379 else if (id != d->video->id)
380 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", ogg_d->subs[id].id, val);
381 if (ogg_d->subs[id].text)
382 mp_msg(MSGT_DEMUX, MSGL_INFO, "[Ogg] Language for -sid %d is '-slang \"%s\"'\n", ogg_d->subs[id].id, val);
383 // copy this language name into the array
384 index = demux_ogg_sub_reverse_id(d, id);
385 if (index >= 0) {
386 sh_sub_t* sh;
387 // in case of malicious files with more than one lang per track:
388 if (ogg_d->text_langs[index]) free(ogg_d->text_langs[index]);
389 ogg_d->text_langs[index] = strdup(val);
390 sh = d->s_streams[index];
391 if (sh && sh->lang) free(sh->lang);
392 if (sh) sh->lang = strdup(val);
394 // check for -slang if subs are uninitialized yet
395 if (os->text && d->sub->id < 0 && demux_ogg_check_lang(val, dvdsub_lang))
397 d->sub->id = index;
398 dvdsub_id = index;
399 mp_msg(MSGT_DEMUX, MSGL_V, "Ogg demuxer: Displaying subtitle stream id %d which matched -slang %s\n", id, val);
401 else
402 hdr = "Language";
404 else {
405 for (i = 0; table[i].ogg; i++)
407 if (!strncasecmp(*cmt, table[i].ogg, strlen(table[i].ogg)) &&
408 (*cmt)[strlen(table[i].ogg)] == '=')
410 hdr = table[i].mp;
411 val = *cmt + strlen(table[i].ogg) + 1;
415 if (hdr)
416 demux_info_add(d, hdr, val);
417 mp_dbg(MSGT_DEMUX, MSGL_DBG2, " %s: %s\n", hdr, val);
418 cmt++;
422 /// Calculate the timestamp and add the packet to the demux stream
423 // return 1 if the packet was added, 0 otherwise
424 static int demux_ogg_add_packet(demux_stream_t* ds,ogg_stream_t* os,int id,ogg_packet* pack) {
425 demuxer_t* d = ds->demuxer;
426 demux_packet_t* dp;
427 unsigned char* data;
428 float pts = 0;
429 int flags = 0;
430 int samplesize = 1;
432 // If packet is an comment header then we try to get comments at first
433 if (pack->bytes >= 7 && !memcmp(pack->packet, "\003vorbis", 7))
435 vorbis_info vi;
436 vorbis_comment vc;
438 vorbis_info_init(&vi);
439 vorbis_comment_init(&vc);
440 vi.rate = 1L; // it's checked by vorbis_synthesis_headerin()
441 if(vorbis_synthesis_headerin(&vi, &vc, pack) == 0) // if no errors
442 demux_ogg_check_comments(d, os, id, &vc);
443 vorbis_comment_clear(&vc);
444 vorbis_info_clear(&vi);
446 if (os->text) {
447 if (id == demux_ogg_sub_id(d, d->sub->id)) // don't want to add subtitles to the demuxer for now
448 demux_ogg_add_sub(os,pack);
449 return 0;
451 if (os->speex) {
452 // discard first two packets, they contain the header and comment
453 if (os->hdr_packets < 2) {
454 os->hdr_packets++;
455 return 0;
457 } else
458 // If packet is an header we jump it except for vorbis and theora
459 // (PACKET_TYPE_HEADER bit doesn't even exist for theora ?!)
460 // We jump nothing for FLAC. Ain't this great? Packet contents have to be
461 // handled differently for each and every stream type. The joy! The joy!
462 if(!os->flac && (*pack->packet & PACKET_TYPE_HEADER) &&
463 (ds != d->audio || ((sh_audio_t*)ds->sh)->format != FOURCC_VORBIS || os->hdr_packets >= NUM_VORBIS_HDR_PACKETS ) &&
464 (ds != d->video || (((sh_video_t*)ds->sh)->format != FOURCC_THEORA)))
465 return 0;
467 // For vorbis packet the packet is the data, for other codec we must jump
468 // the header
469 if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == FOURCC_VORBIS) {
470 samplesize = ((sh_audio_t *)ds->sh)->samplesize;
472 data = demux_ogg_read_packet(os,pack,&pts,&flags,samplesize);
473 if (!data)
474 return 0;
476 /// Clear subtitles if necessary (for broken files)
477 if (sub_clear_text(&ogg_sub, pts)) {
478 vo_sub = &ogg_sub;
479 vo_osd_changed(OSDTYPE_SUBTITLE);
481 /// Send the packet
482 dp = new_demux_packet(pack->bytes-(data-pack->packet));
483 memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));
484 dp->pts = pts;
485 dp->flags = flags;
486 ds_add_packet(ds,dp);
487 mp_msg(MSGT_DEMUX,MSGL_DBG2,"New dp: %p ds=%p pts=%5.3f len=%d flag=%d \n",
488 dp, ds, pts, dp->len, flags);
489 return 1;
492 /// if -forceidx build a table of all syncpoints to make seeking easier
493 /// otherwise try to get at least the final_granulepos
494 void demux_ogg_scan_stream(demuxer_t* demuxer) {
495 ogg_demuxer_t* ogg_d = demuxer->priv;
496 stream_t *s = demuxer->stream;
497 ogg_sync_state* sync = &ogg_d->sync;
498 ogg_page* page= &ogg_d->page;
499 ogg_stream_state* oss;
500 ogg_stream_t* os;
501 ogg_packet op;
502 int np,sid,p,samplesize=1;
503 off_t pos, last_pos;
504 pos = last_pos = demuxer->movi_start;
506 // Reset the stream
507 if(index_mode == 2) {
508 stream_seek(s,demuxer->movi_start);
509 } else {
510 //the 270000 are just a wild guess
511 stream_seek(s,FFMAX(ogg_d->pos,demuxer->movi_end-270000));
513 ogg_sync_reset(sync);
515 // Get the serial number of the stream we use
516 if(demuxer->video->id >= 0) {
517 sid = demuxer->video->id;
519 else if(demuxer->audio->id >= 0) {
520 sid = demuxer->audio->id;
521 if(((sh_audio_t*)demuxer->audio->sh)->format == FOURCC_VORBIS) {
522 samplesize = ((sh_audio_t*)demuxer->audio->sh)->samplesize;
525 else return;
526 os = &ogg_d->subs[sid];
527 oss = &os->stream;
529 while(1) {
530 np = ogg_sync_pageseek(sync,page);
531 if(np < 0) { // We had to skip some bytes
532 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_ERR,"Bad page sync while building syncpoints table (%d)\n",-np);
533 pos += -np;
534 continue;
536 if(np <= 0) { // We need more data
537 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
538 int len = stream_read(s,buf,BLOCK_SIZE);
539 if(len == 0 && s->eof)
540 break;
541 ogg_sync_wrote(sync,len);
542 continue;
544 // The page is ready
545 //ogg_sync_pageout(sync,page);
546 if(ogg_page_serialno(page) != os->stream.serialno) { // It isn't a page from the stream we want
547 pos += np;
548 continue;
550 if(ogg_stream_pagein(oss,page) != 0) {
551 mp_msg(MSGT_DEMUX,MSGL_ERR,"Pagein error ????\n");
552 pos += np;
553 continue;
555 p = 0;
556 while(ogg_stream_packetout(oss,&op) == 1) {
557 float pts;
558 int flags;
559 demux_ogg_read_packet(os,&op,&pts,&flags,samplesize);
560 if(op.granulepos >= 0) ogg_d->final_granulepos = op.granulepos;
561 if(index_mode == 2 && (flags || (os->vorbis && op.granulepos >= 0))) {
562 if (ogg_d->num_syncpoint > SIZE_MAX / sizeof(ogg_syncpoint_t) - 1) break;
563 ogg_d->syncpoints = realloc_struct(ogg_d->syncpoints,(ogg_d->num_syncpoint+1), sizeof(ogg_syncpoint_t));
564 ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos = op.granulepos;
565 ogg_d->syncpoints[ogg_d->num_syncpoint].page_pos = (ogg_page_continued(page) && p == 0) ? last_pos : pos;
566 ogg_d->num_syncpoint++;
568 p++;
570 if(p > 1 || (p == 1 && ! ogg_page_continued(page)))
571 last_pos = pos;
572 pos += np;
573 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"Building syncpoint table %d%%\r",(int)(pos*100/s->end_pos));
575 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"\n");
577 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_V,"Ogg syncpoints table builed: %d syncpoints\n",ogg_d->num_syncpoint);
578 mp_msg(MSGT_DEMUX,MSGL_V,"Ogg stream length (granulepos): %"PRId64"\n",ogg_d->final_granulepos);
580 stream_reset(s);
581 stream_seek(s,demuxer->movi_start);
582 ogg_sync_reset(sync);
583 for(np = 0 ; np < ogg_d->num_sub ; np++) {
584 ogg_stream_reset(&ogg_d->subs[np].stream);
585 ogg_d->subs[np].lastpos = ogg_d->subs[np].lastsize = ogg_d->subs[np].hdr_packets = 0;
589 // Get the first page
590 while(1) {
591 np = ogg_sync_pageout(sync,page);
592 if(np <= 0) { // We need more data
593 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
594 int len = stream_read(s,buf,BLOCK_SIZE);
595 if(len == 0 && s->eof) {
596 mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to get the first page !!!!\n");
597 break;
600 ogg_sync_wrote(sync,len);
601 continue;
603 demux_ogg_get_page_stream(ogg_d,&oss);
604 ogg_stream_pagein(oss,page);
605 break;
610 void print_wave_header(WAVEFORMATEX *h, int verbose_level);
611 void print_video_header(BITMAPINFOHEADER *h, int verbose_level);
613 /* defined in demux_mov.c */
614 unsigned int store_ughvlc(unsigned char *s, unsigned int v);
616 /** \brief Change the current subtitle stream and return its ID.
618 \param demuxer The demuxer whose subtitle stream will be changed.
619 \param new_num The number of the new subtitle track. The number must be
620 between 0 and ogg_d->n_text - 1.
622 \returns The Ogg stream number ( = page serial number) of the newly selected
623 track.
625 int demux_ogg_sub_id(demuxer_t *demuxer, int index) {
626 ogg_demuxer_t *ogg_d = demuxer->priv;
627 return (index < 0) ? index : (index >= ogg_d->n_text) ? -1 : ogg_d->text_ids[index];
630 /** \brief Translate the ogg track number into the subtitle number.
631 * \param demuxer The demuxer about whose subtitles we are inquiring.
632 * \param id The ogg track number of the subtitle track.
634 static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id) {
635 ogg_demuxer_t *ogg_d = demuxer->priv;
636 int i;
637 for (i = 0; i < ogg_d->n_text; i++)
638 if (ogg_d->text_ids[i] == id) return i;
639 return -1;
642 static void demux_close_ogg(demuxer_t* demuxer);
644 static void fixup_vorbis_wf(sh_audio_t *sh, ogg_demuxer_t *od)
646 int i, offset;
647 int ris, init_error = 0;
648 ogg_packet op[3];
649 unsigned char *buf[3];
650 unsigned char *ptr;
651 unsigned int len;
652 ogg_stream_t *os = &od->subs[sh->ds->id];
653 vorbis_comment vc;
655 vorbis_info_init(&os->vi);
656 vorbis_comment_init(&vc);
657 for(i = 0; i < 3; i++) {
658 op[i].bytes = ds_get_packet(sh->ds, &(op[i].packet));
659 mp_msg(MSGT_DEMUX,MSGL_V, "fixup_vorbis_wf: i=%d, size=%ld\n", i, op[i].bytes);
660 if(op[i].bytes < 0) {
661 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error!, fixup_vorbis_wf: bad packet n. %d\n", i);
662 return;
664 buf[i] = malloc(op[i].bytes);
665 if(!buf[i])
666 return;
667 memcpy(buf[i], op[i].packet, op[i].bytes);
669 op[i].b_o_s = (i==0);
670 ris = vorbis_synthesis_headerin(&os->vi,&vc,&op[i]);
671 if(ris < 0) {
672 init_error = 1;
673 mp_msg(MSGT_DECAUDIO,MSGL_ERR,"DEMUX_OGG: header n. %d broken! len=%ld, code: %d\n", i, op[i].bytes, ris);
676 vorbis_comment_clear(&vc);
677 if(!init_error)
678 os->vi_initialized = 1;
680 len = op[0].bytes + op[1].bytes + op[2].bytes;
681 sh->wf = calloc(1, sizeof(WAVEFORMATEX) + len + len/255 + 64);
682 ptr = (unsigned char*) (sh->wf+1);
684 ptr[0] = 2;
685 offset = 1;
686 offset += store_ughvlc(&ptr[offset], op[0].bytes);
687 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 1st len = %u\n", offset);
688 offset += store_ughvlc(&ptr[offset], op[1].bytes);
689 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 2nd len = %u\n", offset);
690 for(i = 0; i < 3; i++) {
691 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, i=%d, bytes: %ld, offset: %u\n", i, op[i].bytes, offset);
692 memcpy(&ptr[offset], buf[i], op[i].bytes);
693 offset += op[i].bytes;
695 sh->wf->cbSize = offset;
696 mp_msg(MSGT_DEMUX,MSGL_V, "demux_ogg, extradata size: %d\n", sh->wf->cbSize);
697 sh->wf = realloc(sh->wf, sizeof(WAVEFORMATEX) + sh->wf->cbSize);
699 if(op[0].bytes >= 29) {
700 unsigned int br;
701 int nombr, minbr, maxbr;
702 ptr = buf[0];
703 sh->channels = ptr[11];
704 sh->samplerate = sh->wf->nSamplesPerSec = AV_RL32(&ptr[12]);
705 maxbr = AV_RL32(&ptr[16]); //max
706 nombr = AV_RL32(&ptr[20]); //nominal
707 minbr = AV_RL32(&ptr[24]); //minimum
709 if(maxbr == -1)
710 maxbr = 0;
711 if(nombr == -1)
712 nombr = 0;
713 if(minbr == -1)
714 minbr = 0;
716 br = maxbr / 8;
717 if(!br)
718 br = nombr / 8;
719 if(!br)
720 br = minbr / 8;
721 sh->wf->nAvgBytesPerSec = br;
722 sh->wf->wBitsPerSample = 16;
723 sh->samplesize = (sh->wf->wBitsPerSample+7)/8;
725 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, vorbis stream features are: channels: %d, srate: %d, bitrate: %d, max: %u, nominal: %u, min: %u\n",
726 sh->channels, sh->samplerate, sh->wf->nAvgBytesPerSec, maxbr, nombr, minbr);
728 free(buf[2]);
729 free(buf[1]);
730 free(buf[0]);
734 /// Open an ogg physical stream
735 // Not static because it's used also in demuxer_avi.c
736 int demux_ogg_open(demuxer_t* demuxer) {
737 ogg_demuxer_t* ogg_d;
738 stream_t *s;
739 char* buf;
740 int np,s_no, n_audio = 0, n_video = 0;
741 int audio_id = -1, video_id = -1, text_id = -1;
742 ogg_sync_state* sync;
743 ogg_page* page;
744 ogg_packet pack;
745 sh_audio_t* sh_a;
746 sh_video_t* sh_v;
748 #ifdef CONFIG_ICONV
749 subcp_open(NULL);
750 #endif
752 s = demuxer->stream;
754 demuxer->priv =
755 ogg_d = calloc(1,sizeof(ogg_demuxer_t));
756 sync = &ogg_d->sync;
757 page = &ogg_d->page;
759 ogg_sync_init(sync);
761 while(1) {
762 /// Try to get a page
763 ogg_d->pos += ogg_d->last_size;
764 np = ogg_sync_pageseek(sync,page);
765 /// Error
766 if(np < 0) {
767 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg demuxer : Bad page sync\n");
768 goto err_out;
770 /// Need some more data
771 if(np == 0) {
772 int len;
773 buf = ogg_sync_buffer(sync,BLOCK_SIZE);
774 len = stream_read(s,buf,BLOCK_SIZE);
775 if(len == 0 && s->eof) {
776 goto err_out;
778 ogg_sync_wrote(sync,len);
779 continue;
781 ogg_d->last_size = np;
782 // We got one page now
784 if( ! ogg_page_bos(page) ) { // It's not a beginning page
785 // Header parsing end here, we need to get the page otherwise it will be lost
786 int id = demux_ogg_get_page_stream(ogg_d,NULL);
787 if(id >= 0)
788 ogg_stream_pagein(&ogg_d->subs[id].stream,page);
789 else
790 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg : Warning found none bos page from unknown stream %d\n",ogg_page_serialno(page));
791 break;
794 /// Init the data structure needed for a logical stream
795 ogg_d->subs = realloc_struct(ogg_d->subs,ogg_d->num_sub+1,sizeof(ogg_stream_t));
796 memset(&ogg_d->subs[ogg_d->num_sub],0,sizeof(ogg_stream_t));
797 /// Get the stream serial number
798 s_no = ogg_page_serialno(page);
799 ogg_stream_init(&ogg_d->subs[ogg_d->num_sub].stream,s_no);
800 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg : Found a stream with serial=%d\n",s_no);
801 // Take the first page
802 ogg_stream_pagein(&ogg_d->subs[ogg_d->num_sub].stream,page);
803 // Get first packet of the page
804 ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack);
806 // Reset our vars
807 sh_a = NULL;
808 sh_v = NULL;
810 ogg_d->subs[ogg_d->num_sub].ogg_d = ogg_d;
812 // Check for Vorbis
813 if(pack.bytes >= 7 && ! strncmp(&pack.packet[1],"vorbis", 6) ) {
814 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
815 sh_a->format = FOURCC_VORBIS;
816 ogg_d->subs[ogg_d->num_sub].vorbis = 1;
817 ogg_d->subs[ogg_d->num_sub].id = n_audio;
818 n_audio++;
819 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (Vorbis), -aid %d\n",ogg_d->num_sub,n_audio-1);
820 } else if (pack.bytes >= 80 && !strncmp(pack.packet,"Speex", 5)) {
821 sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio);
822 sh_a->wf = calloc(1, sizeof(WAVEFORMATEX) + pack.bytes);
823 sh_a->format = FOURCC_SPEEX;
824 sh_a->samplerate = sh_a->wf->nSamplesPerSec = AV_RL32(&pack.packet[36]);
825 sh_a->channels = sh_a->wf->nChannels = AV_RL32(&pack.packet[48]);
826 sh_a->wf->wFormatTag = sh_a->format;
827 sh_a->wf->nAvgBytesPerSec = AV_RL32(&pack.packet[52]);
828 sh_a->wf->nBlockAlign = 0;
829 sh_a->wf->wBitsPerSample = 16;
830 sh_a->samplesize = 2;
831 sh_a->wf->cbSize = pack.bytes;
832 memcpy(&sh_a->wf[1], pack.packet, pack.bytes);
834 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate;
835 ogg_d->subs[ogg_d->num_sub].speex = 1;
836 ogg_d->subs[ogg_d->num_sub].id = n_audio;
837 n_audio++;
838 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (Speex), -aid %d\n",ogg_d->num_sub,n_audio-1);
840 // check for Theora
841 # ifdef CONFIG_OGGTHEORA
842 } else if (pack.bytes >= 7 && !strncmp (&pack.packet[1], "theora", 6)) {
843 int errorCode = 0;
844 theora_info inf;
845 theora_comment cc;
847 theora_info_init (&inf);
848 theora_comment_init (&cc);
850 errorCode = theora_decode_header (&inf, &cc, &pack);
851 if (errorCode)
852 mp_msg(MSGT_DEMUX,MSGL_ERR,"Theora header parsing failed: %i \n",
853 errorCode);
854 else
856 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
858 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
859 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
860 sh_v->bih->biCompression= sh_v->format = FOURCC_THEORA;
861 sh_v->fps = ((double)inf.fps_numerator)/
862 (double)inf.fps_denominator;
863 sh_v->frametime = ((double)inf.fps_denominator)/
864 (double)inf.fps_numerator;
865 sh_v->disp_w = sh_v->bih->biWidth = inf.frame_width;
866 sh_v->disp_h = sh_v->bih->biHeight = inf.frame_height;
867 sh_v->bih->biBitCount = 24;
868 sh_v->bih->biPlanes = 3;
869 sh_v->bih->biSizeImage = ((sh_v->bih->biBitCount/8) *
870 sh_v->bih->biWidth*sh_v->bih->biHeight);
871 ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
872 ogg_d->subs[ogg_d->num_sub].theora = 1;
873 ogg_d->subs[ogg_d->num_sub].keyframe_frequency_force = inf.keyframe_frequency_force;
874 ogg_d->subs[ogg_d->num_sub].id = n_video;
875 n_video++;
876 mp_msg(MSGT_DEMUX,MSGL_INFO,
877 "[Ogg] stream %d: video (Theora v%d.%d.%d), -vid %d\n",
878 ogg_d->num_sub,
879 (int)inf.version_major,
880 (int)inf.version_minor,
881 (int)inf.version_subminor,
882 n_video - 1);
883 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
885 theora_comment_clear(&cc);
886 theora_info_clear(&inf);
887 # endif /* CONFIG_OGGTHEORA */
888 } else if (pack.bytes >= 4 && !strncmp (&pack.packet[0], "fLaC", 4)) {
889 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
890 sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
891 ogg_d->subs[ogg_d->num_sub].id = n_audio;
892 n_audio++;
893 ogg_d->subs[ogg_d->num_sub].flac = 1;
894 sh_a->wf = NULL;
895 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (FLAC), -aid %d\n",ogg_d->num_sub,n_audio-1);
896 } else if (pack.bytes >= 51 && !strncmp(&pack.packet[1], "FLAC", 4)) {
897 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
898 sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
899 ogg_d->subs[ogg_d->num_sub].id = n_audio;
900 n_audio++;
901 ogg_d->subs[ogg_d->num_sub].flac = 2;
902 sh_a->wf = calloc(1, sizeof(WAVEFORMATEX) + 34);
903 sh_a->wf->wFormatTag = sh_a->format;
904 sh_a->wf->cbSize = 34;
905 memcpy(&sh_a->wf[1], &pack.packet[17], 34);
906 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (FLAC, try 2), -aid %d\n",ogg_d->num_sub,n_audio-1);
908 /// Check for old header
909 } else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) {
911 // Old video header
912 if(AV_RL32(pack.packet+96) == 0x05589f80 && pack.bytes >= 184) {
913 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
914 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
915 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
916 sh_v->bih->biCompression=
917 sh_v->format = mmioFOURCC(pack.packet[68],pack.packet[69],
918 pack.packet[70],pack.packet[71]);
919 sh_v->frametime = AV_RL64(pack.packet+164)*0.0000001;
920 sh_v->fps = 1/sh_v->frametime;
921 sh_v->disp_w = sh_v->bih->biWidth = AV_RL32(pack.packet+176);
922 sh_v->disp_h = sh_v->bih->biHeight = AV_RL32(pack.packet+180);
923 sh_v->bih->biBitCount = AV_RL16(pack.packet+182);
924 if(!sh_v->bih->biBitCount) sh_v->bih->biBitCount=24; // hack, FIXME
925 sh_v->bih->biPlanes=1;
926 sh_v->bih->biSizeImage=(sh_v->bih->biBitCount>>3)*sh_v->bih->biWidth*sh_v->bih->biHeight;
928 ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
929 ogg_d->subs[ogg_d->num_sub].id = n_video;
930 n_video++;
931 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: video (FOURCC %c%c%c%c), -vid %d\n",
932 ogg_d->num_sub,pack.packet[68],pack.packet[69],pack.packet[70],pack.packet[71],n_video-1);
933 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
934 // Old audio header
935 } else if(AV_RL32(pack.packet+96) == 0x05589F81) {
936 unsigned int extra_size;
937 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
938 extra_size = AV_RL16(pack.packet+140);
939 sh_a->wf = calloc(1,sizeof(WAVEFORMATEX)+extra_size);
940 sh_a->format = sh_a->wf->wFormatTag = AV_RL16(pack.packet+124);
941 sh_a->channels = sh_a->wf->nChannels = AV_RL16(pack.packet+126);
942 sh_a->samplerate = sh_a->wf->nSamplesPerSec = AV_RL32(pack.packet+128);
943 sh_a->wf->nAvgBytesPerSec = AV_RL32(pack.packet+132);
944 sh_a->wf->nBlockAlign = AV_RL16(pack.packet+136);
945 sh_a->wf->wBitsPerSample = AV_RL16(pack.packet+138);
946 sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
947 sh_a->wf->cbSize = extra_size;
948 if(extra_size > 0)
949 memcpy(((char *)sh_a->wf)+sizeof(WAVEFORMATEX),pack.packet+142,extra_size);
951 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate; // * sh_a->channels;
952 ogg_d->subs[ogg_d->num_sub].id = n_audio;
953 n_audio++;
954 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (format 0x%04x), -aid %d\n",ogg_d->num_sub,sh_a->format,n_audio-1);
955 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_a->wf,MSGL_V);
956 } else
957 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg stream %d contains an old header but the header type is unknown\n",ogg_d->num_sub);
959 // Check new header
960 } else if ( (*pack.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER &&
961 pack.bytes >= (int)sizeof(stream_header)+1) {
962 stream_header *st = (stream_header*)(pack.packet+1);
963 /// New video header
964 if(strncmp(st->streamtype,"video",5) == 0) {
965 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
966 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
967 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
968 sh_v->bih->biCompression=
969 sh_v->format = mmioFOURCC(st->subtype[0],st->subtype[1],
970 st->subtype[2],st->subtype[3]);
971 sh_v->frametime = AV_RL64(&st->time_unit)*0.0000001;
972 sh_v->fps = 1.0/sh_v->frametime;
973 sh_v->bih->biBitCount = AV_RL16(&st->bits_per_sample);
974 sh_v->disp_w = sh_v->bih->biWidth = AV_RL32(&st->sh.video.width);
975 sh_v->disp_h = sh_v->bih->biHeight = AV_RL32(&st->sh.video.height);
976 if(!sh_v->bih->biBitCount) sh_v->bih->biBitCount=24; // hack, FIXME
977 sh_v->bih->biPlanes=1;
978 sh_v->bih->biSizeImage=(sh_v->bih->biBitCount>>3)*sh_v->bih->biWidth*sh_v->bih->biHeight;
980 ogg_d->subs[ogg_d->num_sub].samplerate= sh_v->fps;
981 ogg_d->subs[ogg_d->num_sub].id = n_video;
982 n_video++;
983 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: video (FOURCC %c%c%c%c), -vid %d\n",
984 ogg_d->num_sub,st->subtype[0],st->subtype[1],st->subtype[2],st->subtype[3],n_video-1);
985 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
986 /// New audio header
987 } else if(strncmp(st->streamtype,"audio",5) == 0) {
988 char buffer[5];
989 unsigned int extra_size = AV_RL32(&st->size) - sizeof(stream_header);
990 unsigned int extra_offset = 0;
992 memcpy(buffer,st->subtype,4);
993 buffer[4] = '\0';
995 /* Nasty workaround. stream_header.size seems not to contain the real
996 size in all cases. There are four extra bytes that are unaccounted
997 for in front of the real codec initialization data _at least_ for
998 AAC. So far I've only seen those bytes being all 0, so we can
999 just skip them here. */
1000 if ((strtol(buffer, NULL, 16) == 0xff) && (extra_size >= 4)) {
1001 extra_size -= 4;
1002 extra_offset = 4;
1005 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
1006 sh_a->wf = calloc(1,sizeof(WAVEFORMATEX)+extra_size);
1007 sh_a->format = sh_a->wf->wFormatTag = strtol(buffer, NULL, 16);
1008 sh_a->channels = sh_a->wf->nChannels = AV_RL16(&st->sh.audio.channels);
1009 sh_a->samplerate = sh_a->wf->nSamplesPerSec = AV_RL64(&st->samples_per_unit);
1010 sh_a->wf->nAvgBytesPerSec = AV_RL32(&st->sh.audio.avgbytespersec);
1011 sh_a->wf->nBlockAlign = AV_RL16(&st->sh.audio.blockalign);
1012 sh_a->wf->wBitsPerSample = AV_RL16(&st->bits_per_sample);
1013 sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
1014 sh_a->wf->cbSize = extra_size;
1015 if(extra_size)
1016 memcpy(((char *)sh_a->wf)+sizeof(WAVEFORMATEX),((char *)(st+1))+extra_offset,extra_size);
1018 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate; // * sh_a->channels;
1019 ogg_d->subs[ogg_d->num_sub].id = n_audio;
1020 n_audio++;
1021 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (format 0x%04x), -aid %d\n",ogg_d->num_sub,sh_a->format,n_audio-1);
1022 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_a->wf,MSGL_V);
1024 /// Check for text (subtitles) header
1025 } else if (strncmp(st->streamtype, "text", 4) == 0) {
1026 mp_msg(MSGT_DEMUX, MSGL_INFO, "[Ogg] stream %d: subtitles (SRT-like text subtitles), -sid %d\n", ogg_d->num_sub, ogg_d->n_text);
1027 ogg_d->subs[ogg_d->num_sub].samplerate= AV_RL64(&st->time_unit)/10;
1028 ogg_d->subs[ogg_d->num_sub].text = 1;
1029 ogg_d->subs[ogg_d->num_sub].id = ogg_d->n_text;
1030 if (demuxer->sub->id == ogg_d->n_text)
1031 text_id = ogg_d->num_sub;
1032 new_sh_sub(demuxer, ogg_d->n_text);
1033 ogg_d->n_text++;
1034 ogg_d->text_ids = realloc_struct(ogg_d->text_ids, ogg_d->n_text, sizeof(int));
1035 ogg_d->text_ids[ogg_d->n_text - 1] = ogg_d->num_sub;
1036 ogg_d->text_langs = realloc_struct(ogg_d->text_langs, ogg_d->n_text, sizeof(char *));
1037 ogg_d->text_langs[ogg_d->n_text - 1] = NULL;
1038 //// Unknown header type
1039 } else
1040 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg stream %d has a header marker but is of an unknown type\n",ogg_d->num_sub);
1041 /// Unknown (invalid ?) header
1042 } else
1043 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg stream %d is of an unknown type\n",ogg_d->num_sub);
1045 if(sh_a || sh_v) {
1046 demux_stream_t* ds = NULL;
1047 if(sh_a) {
1048 // If the audio stream is not defined we took the first one
1049 if(demuxer->audio->id == -1) {
1050 demuxer->audio->id = n_audio - 1;
1051 // if(sh_a->wf) print_wave_header(sh_a->wf,MSGL_INFO);
1053 /// Is it the stream we want
1054 if(demuxer->audio->id == n_audio - 1) {
1055 demuxer->audio->sh = sh_a;
1056 sh_a->ds = demuxer->audio;
1057 ds = demuxer->audio;
1058 audio_id = ogg_d->num_sub;
1061 if(sh_v) {
1062 /// Also for video
1063 if(demuxer->video->id == -1) {
1064 demuxer->video->id = n_video - 1;
1065 // if(sh_v->bih) print_video_header(sh_v->bih,MSGL_INFO);
1067 if(demuxer->video->id == n_video - 1) {
1068 demuxer->video->sh = sh_v;
1069 sh_v->ds = demuxer->video;
1070 ds = demuxer->video;
1071 video_id = ogg_d->num_sub;
1074 /// Add the header packets if the stream isn't seekable
1075 if(ds && !s->end_pos) {
1076 /// Finish the page, otherwise packets will be lost
1077 do {
1078 demux_ogg_add_packet(ds,&ogg_d->subs[ogg_d->num_sub],ogg_d->num_sub,&pack);
1079 } while(ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack) == 1);
1082 ogg_d->num_sub++;
1085 if(!n_video && !n_audio) {
1086 goto err_out;
1089 if(!n_video || video_id < 0)
1090 demuxer->video->id = -2;
1091 else
1092 demuxer->video->id = video_id;
1093 if(!n_audio || audio_id < 0)
1094 demuxer->audio->id = -2;
1095 else
1096 demuxer->audio->id = audio_id;
1097 /* Disable the subs only if there are no text streams at all.
1098 Otherwise the stream to display might be chosen later when the comment
1099 packet is encountered and the user used -slang instead of -sid. */
1100 if(!ogg_d->n_text)
1101 demuxer->sub->id = -2;
1102 else if (text_id >= 0) {
1103 demuxer->sub->id = text_id;
1104 mp_msg(MSGT_DEMUX, MSGL_V, "Ogg demuxer: Displaying subtitle stream id %d\n", text_id);
1107 ogg_d->final_granulepos=0;
1108 if(!s->end_pos)
1109 demuxer->seekable = 0;
1110 else {
1111 demuxer->movi_start = s->start_pos; // Needed for XCD (Ogg written in MODE2)
1112 demuxer->movi_end = s->end_pos;
1113 demuxer->seekable = 1;
1114 demux_ogg_scan_stream(demuxer);
1117 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":"",ogg_d->n_text,ogg_d->n_text>1?"s":"");
1119 sh_a = demuxer->audio->sh;
1120 if(sh_a)
1121 if(sh_a->format == FOURCC_VORBIS)
1122 fixup_vorbis_wf(sh_a, ogg_d);
1124 return DEMUXER_TYPE_OGG;
1126 err_out:
1127 return 0;
1131 static int demux_ogg_fill_buffer(demuxer_t *d, demux_stream_t *dsds) {
1132 ogg_demuxer_t* ogg_d;
1133 stream_t *s;
1134 demux_stream_t *ds;
1135 ogg_sync_state* sync;
1136 ogg_stream_state* os;
1137 ogg_page* page;
1138 ogg_packet pack;
1139 int np = 0, id=0;
1141 s = d->stream;
1142 ogg_d = d->priv;
1143 sync = &ogg_d->sync;
1144 page = &ogg_d->page;
1146 /// Find the stream we are working on
1147 if ( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
1148 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer : can't get current stream\n");
1149 return 0;
1152 while(1) {
1153 np = 0;
1154 ds = NULL;
1155 /// Try to get some packet from the current page
1156 while( (np = ogg_stream_packetout(os,&pack)) != 1) {
1157 /// No packet we go the next page
1158 if(np == 0) {
1159 while(1) {
1160 int pa,len;
1161 char *buf;
1162 ogg_d->pos += ogg_d->last_size;
1163 /// Get the next page from the physical stream
1164 while( (pa = ogg_sync_pageseek(sync,page)) <= 0) {
1165 /// Error : we skip some bytes
1166 if(pa < 0) {
1167 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg : Page out not synced, we skip some bytes\n");
1168 ogg_d->pos -= pa;
1169 continue;
1171 /// We need more data
1172 buf = ogg_sync_buffer(sync,BLOCK_SIZE);
1173 len = stream_read(s,buf,BLOCK_SIZE);
1174 if(len == 0 && s->eof) {
1175 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg : Stream EOF !!!!\n");
1176 return 0;
1178 ogg_sync_wrote(sync,len);
1179 } /// Page loop
1180 ogg_d->last_size = pa;
1181 /// Find the page's logical stream
1182 if( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
1183 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error : we met an unknown stream\n");
1184 return 0;
1186 /// Take the page
1187 if(ogg_stream_pagein(os,page) == 0)
1188 break;
1189 /// Page was invalid => retry
1190 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg demuxer : got invalid page !!!!!\n");
1191 ogg_d->pos += ogg_d->last_size;
1193 } else /// Packet was corrupted
1194 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg : bad packet in stream %d\n",id);
1195 } /// Packet loop
1197 /// Is the actual logical stream in use ?
1198 if(id == d->audio->id)
1199 ds = d->audio;
1200 else if(id == d->video->id)
1201 ds = d->video;
1202 else if (ogg_d->subs[id].text)
1203 ds = d->sub;
1205 if(ds) {
1206 if(!demux_ogg_add_packet(ds,&ogg_d->subs[id],id,&pack))
1207 continue; /// Unuseful packet, get another
1208 d->filepos = ogg_d->pos;
1209 return 1;
1212 } /// while(1)
1216 /// For avi with Ogg audio stream we have to create an ogg demuxer for this
1217 // stream, then we join the avi and ogg demuxer with a demuxers demuxer
1218 demuxer_t* init_avi_with_ogg(demuxer_t* demuxer) {
1219 demuxer_t *od;
1220 ogg_demuxer_t *ogg_d;
1221 stream_t* s;
1222 uint32_t hdrsizes[3];
1223 demux_packet_t *dp;
1224 sh_audio_t *sh_audio = demuxer->audio->sh;
1225 int np;
1226 uint8_t *extradata = sh_audio->wf + 1;
1227 int i;
1228 unsigned char *p = NULL,*buf;
1229 int plen;
1231 /// Check that the cbSize is big enough for the following reads
1232 if(sh_audio->wf->cbSize < 22+3*4) {
1233 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Initial audio header is too small !!!!!\n");
1234 goto fallback;
1236 /// Get the size of the 3 header packet
1237 extradata += 22;
1238 for (i = 0; i < 3; i++) {
1239 hdrsizes[i] = AV_RL32(extradata);
1240 extradata += 4;
1242 // printf("\n!!!!!! hdr sizes: %d %d %d \n",hdrsizes[0],hdrsizes[1],hdrsizes[2]);
1244 /// Check the size
1245 if(sh_audio->wf->cbSize < 22+3*4+hdrsizes[0]+hdrsizes[1] + hdrsizes[2]) {
1246 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Audio header is too small !!!!!\n");
1247 goto fallback;
1250 // Build the ogg demuxer private datas
1251 ogg_d = calloc(1,sizeof(ogg_demuxer_t));
1252 ogg_d->num_sub = 1;
1253 ogg_d->subs = malloc(sizeof(ogg_stream_t));
1254 ogg_d->subs[0].vorbis = 1;
1256 // Init the ogg physical stream
1257 ogg_sync_init(&ogg_d->sync);
1259 // Get the first page of the stream : we assume there only 1 logical stream
1260 while((np = ogg_sync_pageout(&ogg_d->sync,&ogg_d->page)) <= 0 ) {
1261 if(np < 0) {
1262 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg error : Can't init using first stream packets\n");
1263 free(ogg_d);
1264 goto fallback;
1266 // Add some data
1267 plen = ds_get_packet(demuxer->audio,&p);
1268 buf = ogg_sync_buffer(&ogg_d->sync,plen);
1269 memcpy(buf,p,plen);
1270 ogg_sync_wrote(&ogg_d->sync,plen);
1272 // Init the logical stream
1273 mp_msg(MSGT_DEMUX,MSGL_DBG2,"AVI Ogg found page with serial %d\n",ogg_page_serialno(&ogg_d->page));
1274 ogg_stream_init(&ogg_d->subs[0].stream,ogg_page_serialno(&ogg_d->page));
1275 // Write the page
1276 ogg_stream_pagein(&ogg_d->subs[0].stream,&ogg_d->page);
1278 // Create the ds_stream and the ogg demuxer
1279 s = new_ds_stream(demuxer->audio);
1280 od = new_demuxer(s,DEMUXER_TYPE_OGG,0,-2,-2,NULL);
1282 /// Add the header packets in the ogg demuxer audio stream
1283 for (i = 0; i < 3; i++) {
1284 dp = new_demux_packet(hdrsizes[i]);
1285 memcpy(dp->buffer,extradata,hdrsizes[i]);
1286 ds_add_packet(od->audio,dp);
1287 extradata += hdrsizes[i];
1290 // Finish setting up the ogg demuxer
1291 od->priv = ogg_d;
1292 sh_audio = new_sh_audio(od,0);
1293 od->audio->id = 0;
1294 od->video->id = -2;
1295 od->audio->sh = sh_audio;
1296 sh_audio->ds = od->audio;
1297 sh_audio->format = FOURCC_VORBIS;
1298 fixup_vorbis_wf(sh_audio, ogg_d);
1300 /// Return the joined demuxers
1301 return new_demuxers_demuxer(demuxer,od,demuxer);
1303 fallback:
1304 demuxer->audio->id = -2;
1305 return demuxer;
1309 static void demux_ogg_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) {
1310 ogg_demuxer_t* ogg_d = demuxer->priv;
1311 ogg_sync_state* sync = &ogg_d->sync;
1312 ogg_page* page= &ogg_d->page;
1313 ogg_stream_state* oss;
1314 ogg_stream_t* os;
1315 demux_stream_t* ds;
1316 ogg_packet op;
1317 float rate;
1318 int i,sp,first,precision=1,do_seek=1;
1319 vorbis_info* vi = NULL;
1320 int64_t gp = 0, old_gp;
1321 off_t pos, old_pos;
1322 int np;
1323 int is_gp_valid;
1324 float pts;
1325 int is_keyframe;
1326 int samplesize=1;
1327 ogg_int64_t granulepos_orig;
1329 if(demuxer->video->id >= 0) {
1330 ds = demuxer->video;
1331 rate = ogg_d->subs[ds->id].samplerate;
1332 } else {
1333 ds = demuxer->audio;
1334 os = &ogg_d->subs[ds->id];
1335 vi = &(os->vi);
1336 rate = (float)vi->rate;
1337 samplesize = ((sh_audio_t*)ds->sh)->samplesize;
1340 os = &ogg_d->subs[ds->id];
1341 oss = &os->stream;
1343 old_gp = os->lastpos;
1344 old_pos = ogg_d->pos;
1346 //calculate the granulepos to seek to
1347 gp = flags & SEEK_ABSOLUTE ? 0 : os->lastpos;
1348 if(flags & SEEK_FACTOR) {
1349 if (ogg_d->final_granulepos > 0)
1350 gp += ogg_d->final_granulepos * rel_seek_secs;
1351 else
1352 gp += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * os->lastpos / ogg_d->pos;
1353 } else
1354 gp += rel_seek_secs * rate;
1355 if (gp < 0) gp = 0;
1357 //calculate the filepos to seek to
1358 if(ogg_d->syncpoints) {
1359 for(sp = 0; sp < ogg_d->num_syncpoint ; sp++) {
1360 if(ogg_d->syncpoints[sp].granulepos >= gp) break;
1363 if(sp >= ogg_d->num_syncpoint) return;
1364 if (sp > 0 && ogg_d->syncpoints[sp].granulepos - gp > gp - ogg_d->syncpoints[sp-1].granulepos)
1365 sp--;
1366 if (ogg_d->syncpoints[sp].granulepos == os->lastpos) {
1367 if (sp > 0 && gp < os->lastpos) sp--;
1368 if (sp < ogg_d->num_syncpoint-1 && gp > os->lastpos) sp++;
1370 pos = ogg_d->syncpoints[sp].page_pos;
1371 precision = 0;
1372 } else {
1373 pos = flags & SEEK_ABSOLUTE ? 0 : ogg_d->pos;
1374 if(flags & SEEK_FACTOR)
1375 pos += (demuxer->movi_end - demuxer->movi_start) * rel_seek_secs;
1376 else {
1377 if (ogg_d->final_granulepos > 0) {
1378 pos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / (ogg_d->final_granulepos / rate);
1379 } else if (os->lastpos > 0) {
1380 pos += rel_seek_secs * ogg_d->pos / (os->lastpos / rate);
1383 if (pos < 0) pos = 0;
1384 if (pos > (demuxer->movi_end - demuxer->movi_start))
1385 pos = demuxer->movi_end - demuxer->movi_start;
1386 } // if(ogg_d->syncpoints)
1388 while(1) {
1389 if (do_seek) {
1390 stream_seek(demuxer->stream,pos+demuxer->movi_start);
1391 ogg_sync_reset(sync);
1392 for(i = 0 ; i < ogg_d->num_sub ; i++) {
1393 ogg_stream_reset(&ogg_d->subs[i].stream);
1394 ogg_d->subs[i].lastpos = ogg_d->subs[i].lastsize = 0;
1396 ogg_d->pos = pos;
1397 ogg_d->last_size = 0;
1398 /* we just guess that we reached correct granulepos, in case a
1399 subsequent search occurs before we read a valid granulepos */
1400 os->lastpos = gp;
1401 first = !(ogg_d->syncpoints);
1402 do_seek=0;
1404 ogg_d->pos += ogg_d->last_size;
1405 ogg_d->last_size = 0;
1406 np = ogg_sync_pageseek(sync,page);
1408 if(np < 0)
1409 ogg_d->pos -= np;
1410 if(np <= 0) { // We need more data
1411 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
1412 int len = stream_read(demuxer->stream,buf,BLOCK_SIZE);
1413 if(len == 0 && demuxer->stream->eof) {
1414 mp_msg(MSGT_DEMUX,MSGL_V,"EOF while trying to seek !!!!\n");
1415 return;
1417 ogg_sync_wrote(sync,len);
1418 continue;
1420 ogg_d->last_size = np;
1421 if(ogg_page_serialno(page) != oss->serialno)
1422 continue;
1424 if(ogg_stream_pagein(oss,page) != 0)
1425 continue;
1427 while(1) {
1428 np = ogg_stream_packetout(oss,&op);
1429 if(np < 0)
1430 continue;
1431 else if(np == 0)
1432 break;
1433 if (first) { /* Discard the first packet as it's probably broken,
1434 and we don't have any other means to decide whether it is
1435 complete or not. */
1436 first = 0;
1437 break;
1439 is_gp_valid = (op.granulepos >= 0);
1440 granulepos_orig=op.granulepos;
1441 demux_ogg_read_packet(os,&op,&pts,&is_keyframe,samplesize);
1442 if (precision && is_gp_valid) {
1443 precision--;
1444 if (abs(gp - op.granulepos) > rate && (op.granulepos != old_gp)) {
1445 //prepare another seek because we are off by more than 1s
1446 pos += (gp - op.granulepos) * (pos - old_pos) / (op.granulepos - old_gp);
1447 if (pos < 0) pos = 0;
1448 if (pos < demuxer->movi_end - demuxer->movi_start) {
1449 do_seek=1;
1450 break;
1454 if (is_gp_valid && pos > 0 && old_gp > gp
1455 && 2 * (old_gp - op.granulepos) < old_gp - gp) {
1456 /* prepare another seek because looking for a syncpoint
1457 destroyed the backward search */
1458 pos = old_pos - 1.5 * (old_pos - pos);
1459 if (pos < 0) pos = 0;
1460 if (pos < demuxer->movi_end - demuxer->movi_start) {
1461 do_seek=1;
1462 break;
1465 if(!precision && (is_keyframe || os->vorbis || os->speex) ) {
1466 if (sub_clear_text(&ogg_sub, MP_NOPTS_VALUE)) {
1467 vo_sub = &ogg_sub;
1468 vo_osd_changed(OSDTYPE_SUBTITLE);
1470 op.granulepos=granulepos_orig;
1471 demux_ogg_add_packet(ds,os,ds->id,&op);
1472 return;
1477 mp_msg(MSGT_DEMUX,MSGL_ERR,"Can't find the good packet :(\n");
1481 static void demux_close_ogg(demuxer_t* demuxer) {
1482 ogg_demuxer_t* ogg_d = demuxer->priv;
1483 ogg_stream_t* os = NULL;
1484 int i;
1486 if(!ogg_d)
1487 return;
1489 #ifdef CONFIG_ICONV
1490 subcp_close();
1491 #endif
1493 ogg_sync_clear(&ogg_d->sync);
1494 if(ogg_d->subs)
1496 for (i = 0; i < ogg_d->num_sub; i++)
1498 os = &ogg_d->subs[i];
1499 ogg_stream_clear(&os->stream);
1500 if(os->vi_initialized)
1501 vorbis_info_clear(&os->vi);
1503 free(ogg_d->subs);
1505 if(ogg_d->syncpoints)
1506 free(ogg_d->syncpoints);
1507 if (ogg_d->text_ids)
1508 free(ogg_d->text_ids);
1509 if (ogg_d->text_langs) {
1510 for (i = 0; i < ogg_d->n_text; i++)
1511 if (ogg_d->text_langs[i]) free(ogg_d->text_langs[i]);
1512 free(ogg_d->text_langs);
1514 free(ogg_d);
1517 static int demux_ogg_control(demuxer_t *demuxer,int cmd, void *arg){
1518 ogg_demuxer_t* ogg_d = demuxer->priv;
1519 ogg_stream_t* os;
1520 float rate;
1522 if(demuxer->video->id >= 0) {
1523 os = &ogg_d->subs[demuxer->video->id];
1524 rate = os->samplerate;
1525 } else {
1526 os = &ogg_d->subs[demuxer->audio->id];
1527 rate = os->vi.rate;
1531 switch(cmd) {
1532 case DEMUXER_CTRL_GET_TIME_LENGTH:
1533 if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW;
1534 *(double *)arg=(double)ogg_d->final_granulepos / rate;
1535 return DEMUXER_CTRL_GUESS;
1537 case DEMUXER_CTRL_GET_PERCENT_POS:
1538 if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW;
1539 *(int *)arg=(os->lastpos*100) / ogg_d->final_granulepos;
1540 return DEMUXER_CTRL_OK;
1542 default:
1543 return DEMUXER_CTRL_NOTIMPL;
1549 const demuxer_desc_t demuxer_desc_ogg = {
1550 "Ogg demuxer",
1551 "ogg",
1552 "Ogg",
1553 "?",
1555 DEMUXER_TYPE_OGG,
1556 1, // safe autodetect
1557 demux_ogg_open,
1558 demux_ogg_fill_buffer,
1559 NULL,
1560 demux_close_ogg,
1561 demux_ogg_seek,
1562 demux_ogg_control