synced with r24565
[mplayer/glamo.git] / libmpdemux / demux_ogg.c
blob868bd2ed22a8d813f81650b81e3ce2238375bbf1
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 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 HAVE_OGGTHEORA
31 #include <theora/theora.h>
32 extern 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 HAVE_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;
103 // Logical stream state
104 ogg_stream_state stream;
105 int hdr_packets;
106 int vorbis;
107 int speex;
108 int theora;
109 int flac;
110 int text;
111 int id;
113 vorbis_info vi;
114 int vi_inited;
116 void *ogg_d;
117 } ogg_stream_t;
119 typedef struct ogg_demuxer {
120 /// Physical stream state
121 ogg_sync_state sync;
122 /// Current page
123 ogg_page page;
124 /// Logical streams
125 ogg_stream_t *subs;
126 int num_sub;
127 ogg_syncpoint_t* syncpoints;
128 int num_syncpoint;
129 off_t pos, last_size;
130 int64_t final_granulepos;
132 /* Used for subtitle switching. */
133 int n_text;
134 int *text_ids;
135 char **text_langs;
136 } ogg_demuxer_t;
138 #define NUM_VORBIS_HDR_PACKETS 3
140 /// Some defines from OggDS
141 #define PACKET_TYPE_HEADER 0x01
142 #define PACKET_TYPE_BITS 0x07
143 #define PACKET_LEN_BITS01 0xc0
144 #define PACKET_LEN_BITS2 0x02
145 #define PACKET_IS_SYNCPOINT 0x08
147 extern char *dvdsub_lang, *audio_lang;
148 extern int dvdsub_id;
150 //-------- subtitle support - should be moved to decoder layer, and queue
151 // - subtitles up in demuxer buffer...
153 #include "subreader.h"
154 #include "libvo/sub.h"
155 #define OGG_SUB_MAX_LINE 128
157 static subtitle ogg_sub;
158 //FILE* subout;
160 #define get_uint16(b) AV_RL16(b)
161 #define get_uint32(b) AV_RL32(b)
162 #define get_uint64(b) AV_RL64(b)
164 void demux_ogg_add_sub (ogg_stream_t* os,ogg_packet* pack) {
165 int lcv;
166 char *packet = pack->packet;
168 if (pack->bytes < 4)
169 return;
170 mp_msg(MSGT_DEMUX,MSGL_DBG2,"\ndemux_ogg_add_sub %02X %02X %02X '%s'\n",
171 (unsigned char)packet[0],
172 (unsigned char)packet[1],
173 (unsigned char)packet[2],
174 &packet[3]);
176 if (((unsigned char)packet[0]) == 0x88) { // some subtitle text
177 // Find data start
178 double endpts = MP_NOPTS_VALUE;
179 int32_t duration = 0;
180 int16_t hdrlen = (*packet & PACKET_LEN_BITS01)>>6, i;
181 hdrlen |= (*packet & PACKET_LEN_BITS2) <<1;
182 lcv = 1 + hdrlen;
183 if (pack->bytes < lcv)
184 return;
185 for (i = hdrlen; i > 0; i--) {
186 duration <<= 8;
187 duration |= (unsigned char)packet[i];
189 if ((hdrlen > 0) && (duration > 0)) {
190 float pts;
191 if(pack->granulepos == -1)
192 pack->granulepos = os->lastpos + os->lastsize;
193 pts = (float)pack->granulepos/(float)os->samplerate;
194 endpts = 1.0 + pts + (float)duration/1000.0;
196 sub_clear_text(&ogg_sub, MP_NOPTS_VALUE);
197 sub_add_text(&ogg_sub, &packet[lcv], pack->bytes - lcv, endpts);
200 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg sub lines: %d first: '%s'\n",
201 ogg_sub.lines, ogg_sub.text[0]);
202 #ifdef USE_ICONV
203 subcp_recode(&ogg_sub);
204 #endif
205 vo_sub = &ogg_sub;
206 vo_osd_changed(OSDTYPE_SUBTITLE);
210 // get the logical stream of the current page
211 // fill os if non NULL and return the stream id
212 static int demux_ogg_get_page_stream(ogg_demuxer_t* ogg_d,ogg_stream_state** os) {
213 int id,s_no;
214 ogg_page* page = &ogg_d->page;
216 s_no = ogg_page_serialno(page);
218 for(id= 0; id < ogg_d->num_sub ; id++) {
219 if(s_no == ogg_d->subs[id].stream.serialno)
220 break;
223 if(id == ogg_d->num_sub) {
224 // If we have only one vorbis stream allow the stream id to change
225 // it's normal on radio stream (each song have an different id).
226 // But we (or the codec?) should check that the samplerate, etc
227 // doesn't change (for radio stream it's ok)
228 if(ogg_d->num_sub == 1 && ogg_d->subs[0].vorbis) {
229 ogg_stream_reset(&ogg_d->subs[0].stream);
230 ogg_stream_init(&ogg_d->subs[0].stream,s_no);
231 id = 0;
232 } else
233 return -1;
236 if(os)
237 *os = &ogg_d->subs[id].stream;
239 return id;
243 static unsigned char* demux_ogg_read_packet(ogg_stream_t* os,ogg_packet* pack,void *context,float* pts,int* flags, int samplesize) {
244 unsigned char* data = pack->packet;
246 *pts = 0;
247 *flags = 0;
249 if(os->vorbis) {
250 if(*pack->packet & PACKET_TYPE_HEADER)
251 os->hdr_packets++;
252 else if (os->vi_inited)
254 vorbis_info *vi;
255 int32_t blocksize;
257 // When we dump the audio, there is no vi, but we don't care of timestamp in this case
258 vi = &(os->vi);
259 blocksize = vorbis_packet_blocksize(vi,pack) / samplesize;
260 // Calculate the timestamp if the packet don't have any
261 if(pack->granulepos == -1) {
262 pack->granulepos = os->lastpos;
263 if(os->lastsize > 0)
264 pack->granulepos += os->lastsize;
266 *pts = pack->granulepos / (float)vi->rate;
267 os->lastsize = blocksize;
268 os->lastpos = pack->granulepos;
270 } else if (os->speex) {
271 // whole packet (default)
272 # ifdef HAVE_OGGTHEORA
273 } else if (os->theora) {
274 /* we pass complete packets to theora, mustn't strip the header! */
275 os->lastsize = 1;
277 /* header packets beginn on 1-bit: thus check (*data&0x80). We don't
278 have theora_state st, until all header packets were passed to the
279 decoder. */
280 if (context != NULL && !(*data&0x80))
282 theora_info *thi = ((theora_struct_t*)context)->st.i;
283 int keyframe_granule_shift=_ilog(thi->keyframe_frequency_force-1);
284 int64_t iframemask = (1 << keyframe_granule_shift) - 1;
286 if (pack->granulepos >= 0)
288 os->lastpos = pack->granulepos >> keyframe_granule_shift;
289 os->lastpos += pack->granulepos & iframemask;
290 *flags = ((pack->granulepos & iframemask) == 0);
292 else
294 os->lastpos++;
296 pack->granulepos = os->lastpos;
297 *pts = (double)os->lastpos / (double)os->samplerate;
299 #endif /* HAVE_OGGTHEORA */
300 } else if (os->flac) {
301 /* we pass complete packets to flac, mustn't strip the header! */
302 if (os->flac == 2 && pack->packet[0] != 0xff)
303 return NULL;
304 } else {
305 if(*pack->packet & PACKET_TYPE_HEADER)
306 os->hdr_packets++;
307 else {
308 // Find data start
309 int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6;
310 hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1;
311 data = pack->packet + 1 + hdrlen;
312 // Calculate the timestamp
313 if(pack->granulepos == -1)
314 pack->granulepos = os->lastpos + (os->lastsize ? os->lastsize : 1);
315 // If we already have a timestamp it can be a syncpoint
316 if(*pack->packet & PACKET_IS_SYNCPOINT)
317 *flags = 1;
318 *pts = pack->granulepos/os->samplerate;
319 // Save the packet length and timestamp
320 os->lastsize = 0;
321 while(hdrlen) {
322 os->lastsize <<= 8;
323 os->lastsize |= pack->packet[hdrlen];
324 hdrlen--;
326 os->lastpos = pack->granulepos;
329 return data;
332 // check if clang has substring from comma separated langlist
333 static int demux_ogg_check_lang(const char *clang, char *langlist)
335 char *c;
337 if (!langlist || !*langlist)
338 return 0;
339 while ((c = strchr(langlist, ',')))
341 if (!strncasecmp(clang, langlist, c - langlist))
342 return 1;
343 langlist = &c[1];
345 if (!strncasecmp(clang, langlist, strlen(langlist)))
346 return 1;
347 return 0;
350 static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id);
352 /// Try to print out comments and also check for LANGUAGE= tag
353 static void demux_ogg_check_comments(demuxer_t *d, ogg_stream_t *os, int id, vorbis_comment *vc)
355 const char *hdr, *val;
356 char **cmt = vc->user_comments;
357 int index, i;
358 ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)d->priv;
359 struct table {
360 const char *ogg;
361 const char *mp;
362 } table[] = {
363 { "ENCODED_USING", "Software" },
364 { "ENCODER_URL", "Encoder URL" },
365 { "TITLE", "Name" },
366 { "ARTIST", "Artist" },
367 { "COMMENT", "Comments" },
368 { "DATE", "Creation Date" },
369 { "GENRE", "Genre" },
370 { "ALBUM", "Album" },
371 { "TRACKNUMBER", "Track" },
372 { NULL, NULL },
375 while(*cmt)
377 hdr = NULL;
378 if (!strncasecmp(*cmt, "LANGUAGE=", 9))
380 val = *cmt + 9;
381 if (ogg_d->subs[id].text)
382 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", ogg_d->subs[id].id, val);
383 else if (id != d->video->id)
384 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", ogg_d->subs[id].id, val);
385 if (ogg_d->subs[id].text)
386 mp_msg(MSGT_DEMUX, MSGL_INFO, "[Ogg] Language for -sid %d is '-slang \"%s\"'\n", ogg_d->subs[id].id, val);
387 // copy this language name into the array
388 index = demux_ogg_sub_reverse_id(d, id);
389 if (index >= 0) {
390 // in case of malicious files with more than one lang per track:
391 if (ogg_d->text_langs[index]) free(ogg_d->text_langs[index]);
392 ogg_d->text_langs[index] = 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 void *context = NULL;
431 int samplesize = 1;
433 // If packet is an comment header then we try to get comments at first
434 if (pack->bytes >= 7 && !memcmp(pack->packet, "\003vorbis", 7))
436 vorbis_info vi;
437 vorbis_comment vc;
439 vorbis_info_init(&vi);
440 vorbis_comment_init(&vc);
441 vi.rate = 1L; // it's checked by vorbis_synthesis_headerin()
442 if(vorbis_synthesis_headerin(&vi, &vc, pack) == 0) // if no errors
443 demux_ogg_check_comments(d, os, id, &vc);
444 vorbis_comment_clear(&vc);
445 vorbis_info_clear(&vi);
447 if (os->text) {
448 if (id == demux_ogg_sub_id(d, d->sub->id)) // don't want to add subtitles to the demuxer for now
449 demux_ogg_add_sub(os,pack);
450 return 0;
452 if (os->speex) {
453 // discard first two packets, they contain the header and comment
454 if (os->hdr_packets < 2) {
455 os->hdr_packets++;
456 return 0;
458 } else
459 // If packet is an header we jump it except for vorbis and theora
460 // (PACKET_TYPE_HEADER bit doesn't even exist for theora ?!)
461 // We jump nothing for FLAC. Ain't this great? Packet contents have to be
462 // handled differently for each and every stream type. The joy! The joy!
463 if(!os->flac && ((*pack->packet & PACKET_TYPE_HEADER) &&
464 (ds != d->audio || ( ((sh_audio_t*)ds->sh)->format != FOURCC_VORBIS || os->hdr_packets >= NUM_VORBIS_HDR_PACKETS ) ) &&
465 (ds != d->video || (((sh_video_t*)ds->sh)->format != FOURCC_THEORA))))
466 return 0;
468 // For vorbis packet the packet is the data, for other codec we must jump
469 // the header
470 if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == FOURCC_VORBIS) {
471 context = ((sh_audio_t *)ds->sh)->context;
472 samplesize = ((sh_audio_t *)ds->sh)->samplesize;
474 if (ds == d->video && ((sh_audio_t*)ds->sh)->format == FOURCC_THEORA)
475 context = ((sh_video_t *)ds->sh)->context;
476 data = demux_ogg_read_packet(os,pack,context,&pts,&flags,samplesize);
477 if (!data)
478 return 0;
480 /// Clear subtitles if necessary (for broken files)
481 if (sub_clear_text(&ogg_sub, pts)) {
482 vo_sub = &ogg_sub;
483 vo_osd_changed(OSDTYPE_SUBTITLE);
485 /// Send the packet
486 dp = new_demux_packet(pack->bytes-(data-pack->packet));
487 memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));
488 dp->pts = pts;
489 dp->flags = flags;
490 ds_add_packet(ds,dp);
491 mp_msg(MSGT_DEMUX,MSGL_DBG2,"New dp: %p ds=%p pts=%5.3f len=%d flag=%d \n",
492 dp, ds, pts, dp->len, flags);
493 return 1;
496 /// if -forceidx build a table of all syncpoints to make seeking easier
497 /// otherwise try to get at least the final_granulepos
498 void demux_ogg_scan_stream(demuxer_t* demuxer) {
499 ogg_demuxer_t* ogg_d = demuxer->priv;
500 stream_t *s = demuxer->stream;
501 ogg_sync_state* sync = &ogg_d->sync;
502 ogg_page* page= &ogg_d->page;
503 ogg_stream_state* oss;
504 ogg_stream_t* os;
505 ogg_packet op;
506 int np,sid,p,samplesize=1;
507 void *context = NULL;
508 off_t pos, last_pos;
509 pos = last_pos = demuxer->movi_start;
511 // Reset the stream
512 if(index_mode == 2) {
513 stream_seek(s,demuxer->movi_start);
514 } else {
515 //the 270000 are just a wild guess
516 stream_seek(s,FFMAX(ogg_d->pos,demuxer->movi_end-270000));
518 ogg_sync_reset(sync);
520 // Get the serial number of the stream we use
521 if(demuxer->video->id >= 0) {
522 sid = demuxer->video->id;
523 /* demux_ogg_read_packet needs decoder context for Theora streams */
524 if (((sh_video_t*)demuxer->video->sh)->format == FOURCC_THEORA)
525 context = ((sh_video_t*)demuxer->video->sh)->context;
527 else if(demuxer->audio->id >= 0) {
528 sid = demuxer->audio->id;
529 /* demux_ogg_read_packet needs decoder context for Vorbis streams */
530 if(((sh_audio_t*)demuxer->audio->sh)->format == FOURCC_VORBIS) {
531 context = ((sh_audio_t*)demuxer->audio->sh)->context;
532 samplesize = ((sh_audio_t*)demuxer->audio->sh)->samplesize;
535 else return;
536 os = &ogg_d->subs[sid];
537 oss = &os->stream;
539 while(1) {
540 np = ogg_sync_pageseek(sync,page);
541 if(np < 0) { // We had to skip some bytes
542 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_ERR,"Bad page sync while building syncpoints table (%d)\n",-np);
543 pos += -np;
544 continue;
546 if(np <= 0) { // We need more data
547 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
548 int len = stream_read(s,buf,BLOCK_SIZE);
549 if(len == 0 && s->eof)
550 break;
551 ogg_sync_wrote(sync,len);
552 continue;
554 // The page is ready
555 //ogg_sync_pageout(sync,page);
556 if(ogg_page_serialno(page) != os->stream.serialno) { // It isn't a page from the stream we want
557 pos += np;
558 continue;
560 if(ogg_stream_pagein(oss,page) != 0) {
561 mp_msg(MSGT_DEMUX,MSGL_ERR,"Pagein error ????\n");
562 pos += np;
563 continue;
565 p = 0;
566 while(ogg_stream_packetout(oss,&op) == 1) {
567 float pts;
568 int flags;
569 demux_ogg_read_packet(os,&op,context,&pts,&flags,samplesize);
570 if(op.granulepos >= 0) ogg_d->final_granulepos = op.granulepos;
571 if(index_mode == 2 && (flags || (os->vorbis && op.granulepos >= 0))) {
572 if (ogg_d->num_syncpoint > SIZE_MAX / sizeof(ogg_syncpoint_t) - 1) break;
573 ogg_d->syncpoints = realloc_struct(ogg_d->syncpoints,(ogg_d->num_syncpoint+1), sizeof(ogg_syncpoint_t));
574 ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos = op.granulepos;
575 ogg_d->syncpoints[ogg_d->num_syncpoint].page_pos = (ogg_page_continued(page) && p == 0) ? last_pos : pos;
576 ogg_d->num_syncpoint++;
578 p++;
580 if(p > 1 || (p == 1 && ! ogg_page_continued(page)))
581 last_pos = pos;
582 pos += np;
583 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"Building syncpoint table %d%%\r",(int)(pos*100/s->end_pos));
585 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_INFO,"\n");
587 if(index_mode == 2) mp_msg(MSGT_DEMUX,MSGL_V,"Ogg syncpoints table builed: %d syncpoints\n",ogg_d->num_syncpoint);
588 mp_msg(MSGT_DEMUX,MSGL_V,"Ogg stream length (granulepos): %"PRId64"\n",ogg_d->final_granulepos);
590 stream_reset(s);
591 stream_seek(s,demuxer->movi_start);
592 ogg_sync_reset(sync);
593 for(np = 0 ; np < ogg_d->num_sub ; np++) {
594 ogg_stream_reset(&ogg_d->subs[np].stream);
595 ogg_d->subs[np].lastpos = ogg_d->subs[np].lastsize = ogg_d->subs[np].hdr_packets = 0;
599 // Get the first page
600 while(1) {
601 np = ogg_sync_pageout(sync,page);
602 if(np <= 0) { // We need more data
603 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
604 int len = stream_read(s,buf,BLOCK_SIZE);
605 if(len == 0 && s->eof) {
606 mp_msg(MSGT_DEMUX,MSGL_ERR,"EOF while trying to get the first page !!!!\n");
607 break;
610 ogg_sync_wrote(sync,len);
611 continue;
613 demux_ogg_get_page_stream(ogg_d,&oss);
614 ogg_stream_pagein(oss,page);
615 break;
620 extern void print_wave_header(WAVEFORMATEX *h, int verbose_level);
621 extern void print_video_header(BITMAPINFOHEADER *h, int verbose_level);
623 /* defined in demux_mov.c */
624 extern unsigned int store_ughvlc(unsigned char *s, unsigned int v);
626 /** \brief Change the current subtitle stream and return its ID.
628 \param demuxer The demuxer whose subtitle stream will be changed.
629 \param new_num The number of the new subtitle track. The number must be
630 between 0 and ogg_d->n_text - 1.
632 \returns The Ogg stream number ( = page serial number) of the newly selected
633 track.
635 int demux_ogg_sub_id(demuxer_t *demuxer, int index) {
636 ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;
637 return (index < 0) ? index : (index >= ogg_d->n_text) ? -1 : ogg_d->text_ids[index];
640 /** \brief Translate the ogg track number into the subtitle number.
641 * \param demuxer The demuxer about whose subtitles we are inquiring.
642 * \param id The ogg track number of the subtitle track.
644 static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id) {
645 ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;
646 int i;
647 for (i = 0; i < ogg_d->n_text; i++)
648 if (ogg_d->text_ids[i] == id) return i;
649 return -1;
652 /** \brief Lookup the subtitle language by the subtitle number. Returns NULL on out-of-bounds input.
653 * \param demuxer The demuxer about whose subtitles we are inquiring.
654 * \param index The subtitle number.
656 char *demux_ogg_sub_lang(demuxer_t *demuxer, int index) {
657 ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)demuxer->priv;
658 return (index < 0) ? NULL : (index >= ogg_d->n_text) ? NULL : ogg_d->text_langs[index];
661 static void demux_close_ogg(demuxer_t* demuxer);
663 static void fixup_vorbis_wf(sh_audio_t *sh, ogg_demuxer_t *od)
665 int i, offset;
666 int ris, init_error = 0;
667 ogg_packet op[3];
668 unsigned char *buf[3];
669 unsigned char *ptr;
670 unsigned int len;
671 ogg_stream_t *os = &od->subs[sh->ds->id];
672 vorbis_comment vc;
674 vorbis_info_init(&os->vi);
675 vorbis_comment_init(&vc);
676 for(i = 0; i < 3; i++) {
677 op[i].bytes = ds_get_packet(sh->ds, &(op[i].packet));
678 mp_msg(MSGT_DEMUX,MSGL_V, "fixup_vorbis_wf: i=%d, size=%ld\n", i, op[i].bytes);
679 if(op[i].bytes < 0) {
680 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error!, fixup_vorbis_wf: bad packet n. %d\n", i);
681 return;
683 buf[i] = malloc(op[i].bytes);
684 if(!buf[i])
685 return;
686 memcpy(buf[i], op[i].packet, op[i].bytes);
688 op[i].b_o_s = (i==0);
689 ris = vorbis_synthesis_headerin(&(os->vi),&vc,&(op[i]));
690 if(ris < 0) {
691 init_error = 1;
692 mp_msg(MSGT_DECAUDIO,MSGL_ERR,"DEMUX_OGG: header n. %d broken! len=%ld, code: %d\n", i, op[i].bytes, ris);
695 vorbis_comment_clear(&vc);
696 if(!init_error)
697 os->vi_inited = 1;
699 len = op[0].bytes + op[1].bytes + op[2].bytes;
700 sh->wf = calloc(1, sizeof(WAVEFORMATEX) + len + len/255 + 64);
701 ptr = (unsigned char*) (sh->wf+1);
703 ptr[0] = 2;
704 offset = 1;
705 offset += store_ughvlc(&ptr[offset], op[0].bytes);
706 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 1st len = %u\n", offset);
707 offset += store_ughvlc(&ptr[offset], op[1].bytes);
708 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, offset after 2nd len = %u\n", offset);
709 for(i = 0; i < 3; i++) {
710 mp_msg(MSGT_DEMUX,MSGL_V,"demux_ogg, i=%d, bytes: %ld, offset: %u\n", i, op[i].bytes, offset);
711 memcpy(&ptr[offset], buf[i], op[i].bytes);
712 offset += op[i].bytes;
714 sh->wf->cbSize = offset;
715 mp_msg(MSGT_DEMUX,MSGL_V, "demux_ogg, extradata size: %d\n", sh->wf->cbSize);
716 sh->wf = (WAVEFORMATEX*)realloc(sh->wf, sizeof(WAVEFORMATEX) + sh->wf->cbSize);
718 if(op[0].bytes >= 29) {
719 unsigned int br;
720 int nombr, minbr, maxbr;
721 ptr = buf[0];
722 sh->channels = ptr[11];
723 sh->samplerate = sh->wf->nSamplesPerSec = get_uint32(&ptr[12]);
724 maxbr = get_uint32(&ptr[16]); //max
725 nombr = get_uint32(&ptr[20]); //nominal
726 minbr = get_uint32(&ptr[24]); //minimum
728 if(maxbr == -1)
729 maxbr = 0;
730 if(nombr == -1)
731 nombr = 0;
732 if(minbr == -1)
733 minbr = 0;
735 br = maxbr / 8;
736 if(!br)
737 br = nombr / 8;
738 if(!br)
739 br = minbr / 8;
740 sh->wf->nAvgBytesPerSec = br;
741 sh->wf->wBitsPerSample = 16;
742 sh->samplesize = (sh->wf->wBitsPerSample+7)/8;
744 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",
745 sh->channels, sh->samplerate, sh->wf->nAvgBytesPerSec, maxbr, nombr, minbr);
747 free(buf[2]);
748 free(buf[1]);
749 free(buf[0]);
753 /// Open an ogg physical stream
754 // Not static because it's used also in demuxer_avi.c
755 int demux_ogg_open(demuxer_t* demuxer) {
756 ogg_demuxer_t* ogg_d;
757 stream_t *s;
758 char* buf;
759 int np,s_no, n_audio = 0, n_video = 0;
760 int audio_id = -1, video_id = -1, text_id = -1;
761 ogg_sync_state* sync;
762 ogg_page* page;
763 ogg_packet pack;
764 sh_audio_t* sh_a;
765 sh_video_t* sh_v;
767 #ifdef USE_ICONV
768 subcp_open(NULL);
769 #endif
771 s = demuxer->stream;
773 demuxer->priv =
774 ogg_d = calloc(1,sizeof(ogg_demuxer_t));
775 sync = &ogg_d->sync;
776 page = &ogg_d->page;
778 ogg_sync_init(sync);
780 while(1) {
781 /// Try to get a page
782 ogg_d->pos += ogg_d->last_size;
783 np = ogg_sync_pageseek(sync,page);
784 /// Error
785 if(np < 0) {
786 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg demuxer : Bad page sync\n");
787 goto err_out;
789 /// Need some more data
790 if(np == 0) {
791 int len;
792 buf = ogg_sync_buffer(sync,BLOCK_SIZE);
793 len = stream_read(s,buf,BLOCK_SIZE);
794 if(len == 0 && s->eof) {
795 goto err_out;
797 ogg_sync_wrote(sync,len);
798 continue;
800 ogg_d->last_size = np;
801 // We got one page now
803 if( ! ogg_page_bos(page) ) { // It's not a begining page
804 // Header parsing end here, we need to get the page otherwise it will be lost
805 int id = demux_ogg_get_page_stream(ogg_d,NULL);
806 if(id >= 0)
807 ogg_stream_pagein(&ogg_d->subs[id].stream,page);
808 else
809 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg : Warning found none bos page from unknown stream %d\n",ogg_page_serialno(page));
810 break;
813 /// Init the data structure needed for a logical stream
814 ogg_d->subs = (ogg_stream_t*)realloc(ogg_d->subs,(ogg_d->num_sub+1)*sizeof(ogg_stream_t));
815 memset(&ogg_d->subs[ogg_d->num_sub],0,sizeof(ogg_stream_t));
816 /// Get the stream serial number
817 s_no = ogg_page_serialno(page);
818 ogg_stream_init(&ogg_d->subs[ogg_d->num_sub].stream,s_no);
819 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg : Found a stream with serial=%d\n",s_no);
820 // Take the first page
821 ogg_stream_pagein(&ogg_d->subs[ogg_d->num_sub].stream,page);
822 // Get first packet of the page
823 ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack);
825 // Reset our vars
826 sh_a = NULL;
827 sh_v = NULL;
829 ogg_d->subs[ogg_d->num_sub].ogg_d = ogg_d;
831 // Check for Vorbis
832 if(pack.bytes >= 7 && ! strncmp(&pack.packet[1],"vorbis", 6) ) {
833 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
834 sh_a->format = FOURCC_VORBIS;
835 ogg_d->subs[ogg_d->num_sub].vorbis = 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 (Vorbis), -aid %d\n",ogg_d->num_sub,n_audio-1);
839 } else if (pack.bytes >= 80 && !strncmp(pack.packet,"Speex", 5)) {
840 sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio);
841 sh_a->wf = calloc(1, sizeof(WAVEFORMATEX) + pack.bytes);
842 sh_a->format = FOURCC_SPEEX;
843 sh_a->samplerate = sh_a->wf->nSamplesPerSec = get_uint32(&pack.packet[36]);
844 sh_a->channels = sh_a->wf->nChannels = get_uint32(&pack.packet[48]);
845 sh_a->wf->wFormatTag = sh_a->format;
846 sh_a->wf->nAvgBytesPerSec = get_uint32(&pack.packet[52]);
847 sh_a->wf->nBlockAlign = 0;
848 sh_a->wf->wBitsPerSample = 16;
849 sh_a->samplesize = 2;
850 sh_a->wf->cbSize = pack.bytes;
851 memcpy(&sh_a->wf[1], pack.packet, pack.bytes);
853 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate;
854 ogg_d->subs[ogg_d->num_sub].speex = 1;
855 ogg_d->subs[ogg_d->num_sub].id = n_audio;
856 n_audio++;
857 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (Speex), -aid %d\n",ogg_d->num_sub,n_audio-1);
859 // check for Theora
860 # ifdef HAVE_OGGTHEORA
861 } else if (pack.bytes >= 7 && !strncmp (&pack.packet[1], "theora", 6)) {
862 int errorCode = 0;
863 theora_info inf;
864 theora_comment cc;
866 theora_info_init (&inf);
867 theora_comment_init (&cc);
869 errorCode = theora_decode_header (&inf, &cc, &pack);
870 if (errorCode)
871 mp_msg(MSGT_DEMUX,MSGL_ERR,"Theora header parsing failed: %i \n",
872 errorCode);
873 else
875 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
877 sh_v->context = NULL;
878 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
879 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
880 sh_v->bih->biCompression= sh_v->format = FOURCC_THEORA;
881 sh_v->fps = ((double)inf.fps_numerator)/
882 (double)inf.fps_denominator;
883 sh_v->frametime = ((double)inf.fps_denominator)/
884 (double)inf.fps_numerator;
885 sh_v->disp_w = sh_v->bih->biWidth = inf.frame_width;
886 sh_v->disp_h = sh_v->bih->biHeight = inf.frame_height;
887 sh_v->bih->biBitCount = 24;
888 sh_v->bih->biPlanes = 3;
889 sh_v->bih->biSizeImage = ((sh_v->bih->biBitCount/8) *
890 sh_v->bih->biWidth*sh_v->bih->biHeight);
891 ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
892 ogg_d->subs[ogg_d->num_sub].theora = 1;
893 ogg_d->subs[ogg_d->num_sub].id = n_video;
894 n_video++;
895 mp_msg(MSGT_DEMUX,MSGL_INFO,
896 "[Ogg] stream %d: video (Theora v%d.%d.%d), -vid %d\n",
897 ogg_d->num_sub,
898 (int)inf.version_major,
899 (int)inf.version_minor,
900 (int)inf.version_subminor,
901 n_video - 1);
902 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
904 theora_comment_clear(&cc);
905 theora_info_clear(&inf);
906 # endif /* HAVE_OGGTHEORA */
907 } else if (pack.bytes >= 4 && !strncmp (&pack.packet[0], "fLaC", 4)) {
908 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
909 sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
910 ogg_d->subs[ogg_d->num_sub].id = n_audio;
911 n_audio++;
912 ogg_d->subs[ogg_d->num_sub].flac = 1;
913 sh_a->wf = NULL;
914 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (FLAC), -aid %d\n",ogg_d->num_sub,n_audio-1);
915 } else if (pack.bytes >= 51 && !strncmp(&pack.packet[1], "FLAC", 4)) {
916 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
917 sh_a->format = mmioFOURCC('f', 'L', 'a', 'C');
918 ogg_d->subs[ogg_d->num_sub].id = n_audio;
919 n_audio++;
920 ogg_d->subs[ogg_d->num_sub].flac = 2;
921 sh_a->wf = calloc(1, sizeof(WAVEFORMATEX) + 34);
922 sh_a->wf->wFormatTag = sh_a->format;
923 sh_a->wf->cbSize = 34;
924 memcpy(&sh_a->wf[1], &pack.packet[17], 34);
925 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: audio (FLAC, try 2), -aid %d\n",ogg_d->num_sub,n_audio-1);
927 /// Check for old header
928 } else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) {
930 // Old video header
931 if(get_uint32 (pack.packet+96) == 0x05589f80 && pack.bytes >= 184) {
932 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
933 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
934 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
935 sh_v->bih->biCompression=
936 sh_v->format = mmioFOURCC(pack.packet[68],pack.packet[69],
937 pack.packet[70],pack.packet[71]);
938 sh_v->frametime = get_uint64(pack.packet+164)*0.0000001;
939 sh_v->fps = 1/sh_v->frametime;
940 sh_v->disp_w = sh_v->bih->biWidth = get_uint32(pack.packet+176);
941 sh_v->disp_h = sh_v->bih->biHeight = get_uint32(pack.packet+180);
942 sh_v->bih->biBitCount = get_uint16(pack.packet+182);
943 if(!sh_v->bih->biBitCount) sh_v->bih->biBitCount=24; // hack, FIXME
944 sh_v->bih->biPlanes=1;
945 sh_v->bih->biSizeImage=(sh_v->bih->biBitCount>>3)*sh_v->bih->biWidth*sh_v->bih->biHeight;
947 ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
948 ogg_d->subs[ogg_d->num_sub].id = n_video;
949 n_video++;
950 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: video (FOURCC %c%c%c%c), -vid %d\n",
951 ogg_d->num_sub,pack.packet[68],pack.packet[69],pack.packet[70],pack.packet[71],n_video-1);
952 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
953 // Old audio header
954 } else if(get_uint32(pack.packet+96) == 0x05589F81) {
955 unsigned int extra_size;
956 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
957 extra_size = get_uint16(pack.packet+140);
958 sh_a->wf = calloc(1,sizeof(WAVEFORMATEX)+extra_size);
959 sh_a->format = sh_a->wf->wFormatTag = get_uint16(pack.packet+124);
960 sh_a->channels = sh_a->wf->nChannels = get_uint16(pack.packet+126);
961 sh_a->samplerate = sh_a->wf->nSamplesPerSec = get_uint32(pack.packet+128);
962 sh_a->wf->nAvgBytesPerSec = get_uint32(pack.packet+132);
963 sh_a->wf->nBlockAlign = get_uint16(pack.packet+136);
964 sh_a->wf->wBitsPerSample = get_uint16(pack.packet+138);
965 sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
966 sh_a->wf->cbSize = extra_size;
967 if(extra_size > 0)
968 memcpy(((char *)sh_a->wf)+sizeof(WAVEFORMATEX),pack.packet+142,extra_size);
970 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate; // * sh_a->channels;
971 ogg_d->subs[ogg_d->num_sub].id = n_audio;
972 n_audio++;
973 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);
974 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_a->wf,MSGL_V);
975 } else
976 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg stream %d contains an old header but the header type is unknown\n",ogg_d->num_sub);
978 // Check new header
979 } else if ( (*pack.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER &&
980 pack.bytes >= (int)sizeof(stream_header)+1) {
981 stream_header *st = (stream_header*)(pack.packet+1);
982 /// New video header
983 if(strncmp(st->streamtype,"video",5) == 0) {
984 sh_v = new_sh_video_vid(demuxer,ogg_d->num_sub, n_video);
985 sh_v->bih = calloc(1,sizeof(BITMAPINFOHEADER));
986 sh_v->bih->biSize=sizeof(BITMAPINFOHEADER);
987 sh_v->bih->biCompression=
988 sh_v->format = mmioFOURCC(st->subtype[0],st->subtype[1],
989 st->subtype[2],st->subtype[3]);
990 sh_v->frametime = get_uint64(&st->time_unit)*0.0000001;
991 sh_v->fps = 1.0/sh_v->frametime;
992 sh_v->bih->biBitCount = get_uint16(&st->bits_per_sample);
993 sh_v->disp_w = sh_v->bih->biWidth = get_uint32(&st->sh.video.width);
994 sh_v->disp_h = sh_v->bih->biHeight = get_uint32(&st->sh.video.height);
995 if(!sh_v->bih->biBitCount) sh_v->bih->biBitCount=24; // hack, FIXME
996 sh_v->bih->biPlanes=1;
997 sh_v->bih->biSizeImage=(sh_v->bih->biBitCount>>3)*sh_v->bih->biWidth*sh_v->bih->biHeight;
999 ogg_d->subs[ogg_d->num_sub].samplerate= sh_v->fps;
1000 ogg_d->subs[ogg_d->num_sub].id = n_video;
1001 n_video++;
1002 mp_msg(MSGT_DEMUX,MSGL_INFO,"[Ogg] stream %d: video (FOURCC %c%c%c%c), -vid %d\n",
1003 ogg_d->num_sub,st->subtype[0],st->subtype[1],st->subtype[2],st->subtype[3],n_video-1);
1004 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_video_header(sh_v->bih,MSGL_V);
1005 /// New audio header
1006 } else if(strncmp(st->streamtype,"audio",5) == 0) {
1007 char buffer[5];
1008 unsigned int extra_size = get_uint32 (&st->size) - sizeof(stream_header);
1009 unsigned int extra_offset = 0;
1011 memcpy(buffer,st->subtype,4);
1012 buffer[4] = '\0';
1014 /* Nasty workaround. stream_header.size seems not to contain the real
1015 size in all cases. There are four extra bytes that are unaccounted
1016 for in front of the real codec initialization data _at least_ for
1017 AAC. So far I've only seen those bytes being all 0, so we can
1018 just skip them here. */
1019 if ((strtol(buffer, NULL, 16) == 0xff) && (extra_size >= 4)) {
1020 extra_size -= 4;
1021 extra_offset = 4;
1024 sh_a = new_sh_audio_aid(demuxer,ogg_d->num_sub, n_audio);
1025 sh_a->wf = calloc(1,sizeof(WAVEFORMATEX)+extra_size);
1026 sh_a->format = sh_a->wf->wFormatTag = strtol(buffer, NULL, 16);
1027 sh_a->channels = sh_a->wf->nChannels = get_uint16(&st->sh.audio.channels);
1028 sh_a->samplerate = sh_a->wf->nSamplesPerSec = get_uint64(&st->samples_per_unit);
1029 sh_a->wf->nAvgBytesPerSec = get_uint32(&st->sh.audio.avgbytespersec);
1030 sh_a->wf->nBlockAlign = get_uint16(&st->sh.audio.blockalign);
1031 sh_a->wf->wBitsPerSample = get_uint16(&st->bits_per_sample);
1032 sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
1033 sh_a->wf->cbSize = extra_size;
1034 if(extra_size)
1035 memcpy(((char *)sh_a->wf)+sizeof(WAVEFORMATEX),((char *)(st+1))+extra_offset,extra_size);
1037 ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate; // * sh_a->channels;
1038 ogg_d->subs[ogg_d->num_sub].id = n_audio;
1039 n_audio++;
1040 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);
1041 if( mp_msg_test(MSGT_HEADER,MSGL_V) ) print_wave_header(sh_a->wf,MSGL_V);
1043 /// Check for text (subtitles) header
1044 } else if (strncmp(st->streamtype, "text", 4) == 0) {
1045 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);
1046 ogg_d->subs[ogg_d->num_sub].samplerate= get_uint64(&st->time_unit)/10;
1047 ogg_d->subs[ogg_d->num_sub].text = 1;
1048 ogg_d->subs[ogg_d->num_sub].id = ogg_d->n_text;
1049 if (demuxer->sub->id == ogg_d->n_text)
1050 text_id = ogg_d->num_sub;
1051 new_sh_sub(demuxer, ogg_d->n_text);
1052 ogg_d->n_text++;
1053 ogg_d->text_ids = (int *)realloc(ogg_d->text_ids, sizeof(int) * ogg_d->n_text);
1054 ogg_d->text_ids[ogg_d->n_text - 1] = ogg_d->num_sub;
1055 ogg_d->text_langs = (char **)realloc(ogg_d->text_langs, sizeof(char *) * ogg_d->n_text);
1056 ogg_d->text_langs[ogg_d->n_text - 1] = NULL;
1057 //// Unknown header type
1058 } else
1059 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg stream %d has a header marker but is of an unknown type\n",ogg_d->num_sub);
1060 /// Unknown (invalid ?) header
1061 } else
1062 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg stream %d is of an unknown type\n",ogg_d->num_sub);
1064 if(sh_a || sh_v) {
1065 demux_stream_t* ds = NULL;
1066 if(sh_a) {
1067 // If the audio stream is not defined we took the first one
1068 if(demuxer->audio->id == -1) {
1069 demuxer->audio->id = n_audio - 1;
1070 // if(sh_a->wf) print_wave_header(sh_a->wf,MSGL_INFO);
1072 /// Is it the stream we want
1073 if(demuxer->audio->id == (n_audio - 1)) {
1074 demuxer->audio->sh = sh_a;
1075 sh_a->ds = demuxer->audio;
1076 ds = demuxer->audio;
1077 audio_id = ogg_d->num_sub;
1080 if(sh_v) {
1081 /// Also for video
1082 if(demuxer->video->id == -1) {
1083 demuxer->video->id = n_video - 1;
1084 // if(sh_v->bih) print_video_header(sh_v->bih,MSGL_INFO);
1086 if(demuxer->video->id == (n_video - 1)) {
1087 demuxer->video->sh = sh_v;
1088 sh_v->ds = demuxer->video;
1089 ds = demuxer->video;
1090 video_id = ogg_d->num_sub;
1093 /// Add the header packets if the stream isn't seekable
1094 if(ds && !s->end_pos) {
1095 /// Finish the page, otherwise packets will be lost
1096 do {
1097 demux_ogg_add_packet(ds,&ogg_d->subs[ogg_d->num_sub],ogg_d->num_sub,&pack);
1098 } while(ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack) == 1);
1101 ogg_d->num_sub++;
1104 if(!n_video && !n_audio) {
1105 goto err_out;
1108 if(!n_video || (video_id < 0))
1109 demuxer->video->id = -2;
1110 else
1111 demuxer->video->id = video_id;
1112 if(!n_audio || (audio_id < 0))
1113 demuxer->audio->id = -2;
1114 else
1115 demuxer->audio->id = audio_id;
1116 /* Disable the subs only if there are no text streams at all.
1117 Otherwise the stream to display might be chosen later when the comment
1118 packet is encountered and the user used -slang instead of -sid. */
1119 if(!ogg_d->n_text)
1120 demuxer->sub->id = -2;
1121 else if (text_id >= 0) {
1122 demuxer->sub->id = text_id;
1123 mp_msg(MSGT_DEMUX, MSGL_V, "Ogg demuxer: Displaying subtitle stream id %d\n", text_id);
1126 ogg_d->final_granulepos=0;
1127 if(!s->end_pos)
1128 demuxer->seekable = 0;
1129 else {
1130 demuxer->movi_start = s->start_pos; // Needed for XCD (Ogg written in MODE2)
1131 demuxer->movi_end = s->end_pos;
1132 demuxer->seekable = 1;
1133 demux_ogg_scan_stream(demuxer);
1136 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":"");
1138 sh_a = demuxer->audio->sh;
1139 if(sh_a)
1140 if(sh_a->format == FOURCC_VORBIS)
1141 fixup_vorbis_wf(sh_a, ogg_d);
1143 return DEMUXER_TYPE_OGG;
1145 err_out:
1146 return 0;
1150 static int demux_ogg_fill_buffer(demuxer_t *d, demux_stream_t *dsds) {
1151 ogg_demuxer_t* ogg_d;
1152 stream_t *s;
1153 demux_stream_t *ds;
1154 ogg_sync_state* sync;
1155 ogg_stream_state* os;
1156 ogg_page* page;
1157 ogg_packet pack;
1158 int np = 0, id=0;
1160 s = d->stream;
1161 ogg_d = d->priv;
1162 sync = &ogg_d->sync;
1163 page = &ogg_d->page;
1165 /// Find the stream we are working on
1166 if ( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
1167 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer : can't get current stream\n");
1168 return 0;
1171 while(1) {
1172 np = 0;
1173 ds = NULL;
1174 /// Try to get some packet from the current page
1175 while( (np = ogg_stream_packetout(os,&pack)) != 1) {
1176 /// No packet we go the next page
1177 if(np == 0) {
1178 while(1) {
1179 int pa,len;
1180 char *buf;
1181 ogg_d->pos += ogg_d->last_size;
1182 /// Get the next page from the physical stream
1183 while( (pa = ogg_sync_pageseek(sync,page)) <= 0) {
1184 /// Error : we skip some bytes
1185 if(pa < 0) {
1186 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg : Page out not synced, we skip some bytes\n");
1187 ogg_d->pos -= pa;
1188 continue;
1190 /// We need more data
1191 buf = ogg_sync_buffer(sync,BLOCK_SIZE);
1192 len = stream_read(s,buf,BLOCK_SIZE);
1193 if(len == 0 && s->eof) {
1194 mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg : Stream EOF !!!!\n");
1195 return 0;
1197 ogg_sync_wrote(sync,len);
1198 } /// Page loop
1199 ogg_d->last_size = pa;
1200 /// Find the page's logical stream
1201 if( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
1202 mp_msg(MSGT_DEMUX,MSGL_ERR,"Ogg demuxer error : we met an unknown stream\n");
1203 return 0;
1205 /// Take the page
1206 if(ogg_stream_pagein(os,page) == 0)
1207 break;
1208 /// Page was invalid => retry
1209 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg demuxer : got invalid page !!!!!\n");
1210 ogg_d->pos += ogg_d->last_size;
1212 } else /// Packet was corrupted
1213 mp_msg(MSGT_DEMUX,MSGL_WARN,"Ogg : bad packet in stream %d\n",id);
1214 } /// Packet loop
1216 /// Is the actual logical stream in use ?
1217 if(id == d->audio->id)
1218 ds = d->audio;
1219 else if(id == d->video->id)
1220 ds = d->video;
1221 else if (ogg_d->subs[id].text)
1222 ds = d->sub;
1224 if(ds) {
1225 if(!demux_ogg_add_packet(ds,&ogg_d->subs[id],id,&pack))
1226 continue; /// Unuseful packet, get another
1227 d->filepos = ogg_d->pos;
1228 return 1;
1231 } /// while(1)
1235 /// For avi with Ogg audio stream we have to create an ogg demuxer for this
1236 // stream, then we join the avi and ogg demuxer with a demuxers demuxer
1237 demuxer_t* init_avi_with_ogg(demuxer_t* demuxer) {
1238 demuxer_t *od;
1239 ogg_demuxer_t *ogg_d;
1240 stream_t* s;
1241 uint32_t hdrsizes[3];
1242 demux_packet_t *dp;
1243 sh_audio_t *sh_audio = demuxer->audio->sh;
1244 int np;
1245 unsigned char *p = NULL,*buf;
1246 int plen;
1248 /// Check that the cbSize is enouth big for the following reads
1249 if(sh_audio->wf->cbSize < 22+3*sizeof(uint32_t)) {
1250 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Initial audio header is too small !!!!!\n");
1251 goto fallback;
1253 /// Get the size of the 3 header packet
1254 memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
1255 // printf("\n!!!!!! hdr sizes: %d %d %d \n",hdrsizes[0],hdrsizes[1],hdrsizes[2]);
1257 /// Check the size
1258 if(sh_audio->wf->cbSize < 22+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1] + hdrsizes[2]) {
1259 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg : Audio header is too small !!!!!\n");
1260 goto fallback;
1263 // Build the ogg demuxer private datas
1264 ogg_d = calloc(1,sizeof(ogg_demuxer_t));
1265 ogg_d->num_sub = 1;
1266 ogg_d->subs = malloc(sizeof(ogg_stream_t));
1267 ogg_d->subs[0].vorbis = 1;
1269 // Init the ogg physical stream
1270 ogg_sync_init(&ogg_d->sync);
1272 // Get the first page of the stream : we assume there only 1 logical stream
1273 while((np = ogg_sync_pageout(&ogg_d->sync,&ogg_d->page)) <= 0 ) {
1274 if(np < 0) {
1275 mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI Ogg error : Can't init using first stream packets\n");
1276 free(ogg_d);
1277 goto fallback;
1279 // Add some data
1280 plen = ds_get_packet(demuxer->audio,&p);
1281 buf = ogg_sync_buffer(&ogg_d->sync,plen);
1282 memcpy(buf,p,plen);
1283 ogg_sync_wrote(&ogg_d->sync,plen);
1285 // Init the logical stream
1286 mp_msg(MSGT_DEMUX,MSGL_DBG2,"AVI Ogg found page with serial %d\n",ogg_page_serialno(&ogg_d->page));
1287 ogg_stream_init(&ogg_d->subs[0].stream,ogg_page_serialno(&ogg_d->page));
1288 // Write the page
1289 ogg_stream_pagein(&ogg_d->subs[0].stream,&ogg_d->page);
1291 // Create the ds_stream and the ogg demuxer
1292 s = new_ds_stream(demuxer->audio);
1293 od = new_demuxer(s,DEMUXER_TYPE_OGG,0,-2,-2,NULL);
1295 /// Add the header packets in the ogg demuxer audio stream
1296 // Initial header
1297 dp = new_demux_packet(hdrsizes[0]);
1298 memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdrsizes[0]);
1299 ds_add_packet(od->audio,dp);
1300 /// Comments
1301 dp = new_demux_packet(hdrsizes[1]);
1302 memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdrsizes[1]);
1303 ds_add_packet(od->audio,dp);
1304 /// Code book
1305 dp = new_demux_packet(hdrsizes[2]);
1306 memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+22+sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdrsizes[2]);
1307 ds_add_packet(od->audio,dp);
1309 // Finish setting up the ogg demuxer
1310 od->priv = ogg_d;
1311 sh_audio = new_sh_audio(od,0);
1312 od->audio->id = 0;
1313 od->video->id = -2;
1314 od->audio->sh = sh_audio;
1315 sh_audio->ds = od->audio;
1316 sh_audio->format = FOURCC_VORBIS;
1318 /// Return the joined demuxers
1319 return new_demuxers_demuxer(demuxer,od,demuxer);
1321 fallback:
1322 demuxer->audio->id = -2;
1323 return demuxer;
1327 static void demux_ogg_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags) {
1328 ogg_demuxer_t* ogg_d = demuxer->priv;
1329 ogg_sync_state* sync = &ogg_d->sync;
1330 ogg_page* page= &ogg_d->page;
1331 ogg_stream_state* oss;
1332 ogg_stream_t* os;
1333 demux_stream_t* ds;
1334 ogg_packet op;
1335 float rate;
1336 int i,sp,first,precision=1,do_seek=1;
1337 vorbis_info* vi = NULL;
1338 int64_t gp = 0, old_gp;
1339 void *context = NULL;
1340 off_t pos, old_pos;
1341 int np;
1342 int is_gp_valid;
1343 float pts;
1344 int is_keyframe;
1345 int samplesize=1;
1346 ogg_int64_t granulepos_orig;
1348 if(demuxer->video->id >= 0) {
1349 ds = demuxer->video;
1350 /* demux_ogg_read_packet needs decoder context for Theora streams */
1351 if (((sh_video_t*)demuxer->video->sh)->format == FOURCC_THEORA)
1352 context = ((sh_video_t*)demuxer->video->sh)->context;
1353 rate = ogg_d->subs[ds->id].samplerate;
1354 } else {
1355 ds = demuxer->audio;
1356 os = &ogg_d->subs[ds->id];
1357 /* demux_ogg_read_packet needs decoder context for Vorbis streams */
1358 if(((sh_audio_t*)demuxer->audio->sh)->format == FOURCC_VORBIS)
1359 context = ((sh_audio_t*)demuxer->audio->sh)->context;
1360 vi = &(os->vi);
1361 rate = (float)vi->rate;
1362 samplesize = ((sh_audio_t*)ds->sh)->samplesize;
1365 os = &ogg_d->subs[ds->id];
1366 oss = &os->stream;
1368 old_gp = os->lastpos;
1369 old_pos = ogg_d->pos;
1371 //calculate the granulepos to seek to
1372 gp = flags & 1 ? 0 : os->lastpos;
1373 if(flags & 2) {
1374 if (ogg_d->final_granulepos > 0)
1375 gp += ogg_d->final_granulepos * rel_seek_secs;
1376 else
1377 gp += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * os->lastpos / ogg_d->pos;
1378 } else
1379 gp += rel_seek_secs * rate;
1380 if (gp < 0) gp = 0;
1382 //calculate the filepos to seek to
1383 if(ogg_d->syncpoints) {
1384 for(sp = 0; sp < ogg_d->num_syncpoint ; sp++) {
1385 if(ogg_d->syncpoints[sp].granulepos >= gp) break;
1388 if(sp >= ogg_d->num_syncpoint) return;
1389 if (sp > 0 && ogg_d->syncpoints[sp].granulepos - gp > gp - ogg_d->syncpoints[sp-1].granulepos)
1390 sp--;
1391 if (ogg_d->syncpoints[sp].granulepos == os->lastpos) {
1392 if (sp > 0 && gp < os->lastpos) sp--;
1393 if (sp < ogg_d->num_syncpoint-1 && gp > os->lastpos) sp++;
1395 pos = ogg_d->syncpoints[sp].page_pos;
1396 precision = 0;
1397 } else {
1398 pos = flags & 1 ? 0 : ogg_d->pos;
1399 if(flags & 2)
1400 pos += (demuxer->movi_end - demuxer->movi_start) * rel_seek_secs;
1401 else {
1402 if (ogg_d->final_granulepos > 0) {
1403 pos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / (ogg_d->final_granulepos / rate);
1404 } else if (os->lastpos > 0) {
1405 pos += rel_seek_secs * ogg_d->pos / (os->lastpos / rate);
1408 if (pos < 0) pos = 0;
1409 if (pos > (demuxer->movi_end - demuxer->movi_start))
1410 pos = demuxer->movi_end - demuxer->movi_start;
1411 } // if(ogg_d->syncpoints)
1413 while(1) {
1414 if (do_seek) {
1415 stream_seek(demuxer->stream,pos+demuxer->movi_start);
1416 ogg_sync_reset(sync);
1417 for(i = 0 ; i < ogg_d->num_sub ; i++) {
1418 ogg_stream_reset(&ogg_d->subs[i].stream);
1419 ogg_d->subs[i].lastpos = ogg_d->subs[i].lastsize = 0;
1421 ogg_d->pos = pos;
1422 ogg_d->last_size = 0;
1423 /* we just guess that we reached correct granulepos, in case a
1424 subsequent search occurs before we read a valid granulepos */
1425 os->lastpos = gp;
1426 first = !(ogg_d->syncpoints);
1427 do_seek=0;
1429 ogg_d->pos += ogg_d->last_size;
1430 ogg_d->last_size = 0;
1431 np = ogg_sync_pageseek(sync,page);
1433 if(np < 0)
1434 ogg_d->pos -= np;
1435 if(np <= 0) { // We need more data
1436 char* buf = ogg_sync_buffer(sync,BLOCK_SIZE);
1437 int len = stream_read(demuxer->stream,buf,BLOCK_SIZE);
1438 if(len == 0 && demuxer->stream->eof) {
1439 mp_msg(MSGT_DEMUX,MSGL_V,"EOF while trying to seek !!!!\n");
1440 return;
1442 ogg_sync_wrote(sync,len);
1443 continue;
1445 ogg_d->last_size = np;
1446 if(ogg_page_serialno(page) != oss->serialno)
1447 continue;
1449 if(ogg_stream_pagein(oss,page) != 0)
1450 continue;
1452 while(1) {
1453 np = ogg_stream_packetout(oss,&op);
1454 if(np < 0)
1455 continue;
1456 else if(np == 0)
1457 break;
1458 if (first) { /* Discard the first packet as it's probably broken,
1459 and we don't have any other means to decide whether it is
1460 complete or not. */
1461 first = 0;
1462 break;
1464 is_gp_valid = (op.granulepos >= 0);
1465 granulepos_orig=op.granulepos;
1466 demux_ogg_read_packet(os,&op,context,&pts,&is_keyframe,samplesize);
1467 if (precision && is_gp_valid) {
1468 precision--;
1469 if (abs(gp - op.granulepos) > rate && (op.granulepos != old_gp)) {
1470 //prepare another seek because we are off by more than 1s
1471 pos += (gp - op.granulepos) * (pos - old_pos) / (op.granulepos - old_gp);
1472 if (pos < 0) pos = 0;
1473 if (pos < (demuxer->movi_end - demuxer->movi_start)) {
1474 do_seek=1;
1475 break;
1479 if (is_gp_valid && (pos > 0) && (old_gp > gp)
1480 && (2 * (old_gp - op.granulepos) < old_gp - gp)) {
1481 /* prepare another seek because looking for a syncpoint
1482 destroyed the backward search */
1483 pos = old_pos - 1.5 * (old_pos - pos);
1484 if (pos < 0) pos = 0;
1485 if (pos < (demuxer->movi_end - demuxer->movi_start)) {
1486 do_seek=1;
1487 break;
1490 if(!precision && (is_keyframe || os->vorbis || os->speex) ) {
1491 if (sub_clear_text(&ogg_sub, MP_NOPTS_VALUE)) {
1492 vo_sub = &ogg_sub;
1493 vo_osd_changed(OSDTYPE_SUBTITLE);
1495 op.granulepos=granulepos_orig;
1496 demux_ogg_add_packet(ds,os,ds->id,&op);
1497 return;
1502 mp_msg(MSGT_DEMUX,MSGL_ERR,"Can't find the good packet :(\n");
1506 static void demux_close_ogg(demuxer_t* demuxer) {
1507 ogg_demuxer_t* ogg_d = demuxer->priv;
1508 ogg_stream_t* os = NULL;
1509 int i;
1511 if(!ogg_d)
1512 return;
1514 #ifdef USE_ICONV
1515 subcp_close();
1516 #endif
1518 ogg_sync_clear(&ogg_d->sync);
1519 if(ogg_d->subs)
1521 for (i = 0; i < ogg_d->num_sub; i++)
1523 os = &ogg_d->subs[i];
1524 ogg_stream_clear(&os->stream);
1525 if(os->vi_inited)
1526 vorbis_info_clear(&os->vi);
1528 free(ogg_d->subs);
1530 if(ogg_d->syncpoints)
1531 free(ogg_d->syncpoints);
1532 if (ogg_d->text_ids)
1533 free(ogg_d->text_ids);
1534 if (ogg_d->text_langs) {
1535 for (i = 0; i < ogg_d->n_text; i++)
1536 if (ogg_d->text_langs[i]) free(ogg_d->text_langs[i]);
1537 free(ogg_d->text_langs);
1539 free(ogg_d);
1542 static int demux_ogg_control(demuxer_t *demuxer,int cmd, void *arg){
1543 ogg_demuxer_t* ogg_d = demuxer->priv;
1544 ogg_stream_t* os;
1545 float rate;
1547 if(demuxer->video->id >= 0) {
1548 os = &ogg_d->subs[demuxer->video->id];
1549 rate = os->samplerate;
1550 } else {
1551 os = &ogg_d->subs[demuxer->audio->id];
1552 rate = os->vi.rate;
1556 switch(cmd) {
1557 case DEMUXER_CTRL_GET_TIME_LENGTH:
1558 if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW;
1559 *((double *)arg)=(double)ogg_d->final_granulepos / rate;
1560 return DEMUXER_CTRL_GUESS;
1562 case DEMUXER_CTRL_GET_PERCENT_POS:
1563 if (ogg_d->final_granulepos<=0) return DEMUXER_CTRL_DONTKNOW;
1564 *((int *)arg)=(int)( (os->lastpos*100) / ogg_d->final_granulepos);
1565 return DEMUXER_CTRL_OK;
1567 default:
1568 return DEMUXER_CTRL_NOTIMPL;
1574 demuxer_desc_t demuxer_desc_ogg = {
1575 "Ogg demuxer",
1576 "ogg",
1577 "Ogg",
1578 "?",
1580 DEMUXER_TYPE_OGG,
1581 1, // safe autodetect
1582 demux_ogg_open,
1583 demux_ogg_fill_buffer,
1584 NULL,
1585 demux_close_ogg,
1586 demux_ogg_seek,
1587 demux_ogg_control