diff options
Diffstat (limited to 'libmpdemux/demux_ogg.c')
-rw-r--r-- | libmpdemux/demux_ogg.c | 1660 |
1 files changed, 0 insertions, 1660 deletions
diff --git a/libmpdemux/demux_ogg.c b/libmpdemux/demux_ogg.c deleted file mode 100644 index 9eea061106..0000000000 --- a/libmpdemux/demux_ogg.c +++ /dev/null @@ -1,1660 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * MPlayer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <math.h> -#include <inttypes.h> - -#include <libavutil/intreadwrite.h> - -#include "options.h" -#include "mp_msg.h" -#include "talloc.h" -#include "stream/stream.h" -#include "demuxer.h" -#include "stheader.h" -#include "aviprint.h" -#include "demux_mov.h" -#include "demux_ogg.h" - -#define FOURCC_VORBIS mmioFOURCC('v', 'r', 'b', 's') -#define FOURCC_SPEEX mmioFOURCC('s', 'p', 'x', ' ') -#define FOURCC_THEORA mmioFOURCC('t', 'h', 'e', 'o') - -#ifdef CONFIG_TREMOR -#include <tremor/ogg.h> -#include <tremor/ivorbiscodec.h> -#else -#include <ogg/ogg.h> -#include <vorbis/codec.h> -#endif - -#ifdef CONFIG_OGGTHEORA -#include <theora/theora.h> -int _ilog (unsigned int); /* defined in many places in theora/lib/ */ -#endif - -#define BLOCK_SIZE 4096 - -/* Theora decoder context : we won't be able to interpret granule positions - * without using theora_granule_time with the theora_state of the stream. - * This is duplicated in `vd_theora.c'; put this in a common header? - */ -#ifdef CONFIG_OGGTHEORA -typedef struct theora_struct_st { - theora_state st; - theora_comment cc; - theora_info inf; -} theora_struct_t; -#endif - -//// OggDS headers -// Header for the new header format -typedef struct stream_header_video { - ogg_int32_t width; - ogg_int32_t height; -} stream_header_video; - -typedef struct stream_header_audio { - ogg_int16_t channels; - ogg_int16_t blockalign; - ogg_int32_t avgbytespersec; -} stream_header_audio; - -typedef struct __attribute__((__packed__)) stream_header { - char streamtype[8]; - char subtype[4]; - - ogg_int32_t size; // size of the structure - - ogg_int64_t time_unit; // in reference time - ogg_int64_t samples_per_unit; - ogg_int32_t default_len; // in media time - - ogg_int32_t buffersize; - ogg_int16_t bits_per_sample; - - ogg_int16_t padding; - - union { - // Video specific - stream_header_video video; - // Audio specific - stream_header_audio audio; - } sh; -} stream_header; - -/// Our private datas - -typedef struct ogg_syncpoint { - int64_t granulepos; - off_t page_pos; -} ogg_syncpoint_t; - -/// A logical stream -typedef struct ogg_stream { - /// Timestamping stuff - float samplerate; /// granulpos 2 time - int64_t lastpos; - int32_t lastsize; - int keyframe_frequency_force; - - // Logical stream state - ogg_stream_state stream; - int hdr_packets; - int vorbis; - int speex; - int theora; - int flac; - int text; - int id; - - vorbis_info vi; - int vi_initialized; - - void *ogg_d; -} ogg_stream_t; - -typedef struct ogg_demuxer { - /// Physical stream state - ogg_sync_state sync; - /// Current page - ogg_page page; - /// Logical streams - ogg_stream_t *subs; - int num_sub; - ogg_syncpoint_t *syncpoints; - int num_syncpoint; - off_t pos, last_size; - int64_t initial_granulepos; - int64_t final_granulepos; - int64_t duration; - - /* Used for subtitle switching. */ - int n_text; - int *text_ids; - char **text_langs; -} ogg_demuxer_t; - -#define NUM_VORBIS_HDR_PACKETS 3 - -/// Some defines from OggDS -#define PACKET_TYPE_HEADER 0x01 -#define PACKET_TYPE_BITS 0x07 -#define PACKET_LEN_BITS01 0xc0 -#define PACKET_LEN_BITS2 0x02 -#define PACKET_IS_SYNCPOINT 0x08 - -//-------- subtitle support - should be moved to decoder layer, and queue -// - subtitles up in demuxer buffer... - -#include "sub/subreader.h" -#include "sub/sub.h" -#define OGG_SUB_MAX_LINE 128 - -static subtitle ogg_sub; -//FILE* subout; - -static void demux_ogg_add_sub(ogg_stream_t *os, ogg_packet *pack) -{ - int lcv; - char *packet = pack->packet; - - if (pack->bytes < 4) - return; - mp_msg(MSGT_DEMUX, MSGL_DBG2, "\ndemux_ogg_add_sub %02X %02X %02X '%s'\n", - (unsigned char)packet[0], - (unsigned char)packet[1], - (unsigned char)packet[2], - &packet[3]); - - if (((unsigned char)packet[0]) == 0x88) { // some subtitle text - // Find data start - double endpts = MP_NOPTS_VALUE; - int32_t duration = 0; - int16_t hdrlen = (*packet & PACKET_LEN_BITS01) >> 6, i; - - hdrlen |= (*packet & PACKET_LEN_BITS2) << 1; - lcv = 1 + hdrlen; - if (pack->bytes < lcv) - return; - for (i = hdrlen; i > 0; i--) { - duration <<= 8; - duration |= (unsigned char)packet[i]; - } - if (hdrlen > 0 && duration > 0) { - float pts; - - if (pack->granulepos == -1) - pack->granulepos = os->lastpos + os->lastsize; - pts = (float)pack->granulepos / (float)os->samplerate; - endpts = 1.0 + pts + (float)duration / 1000.0; - } - sub_clear_text(&ogg_sub, MP_NOPTS_VALUE); - sub_add_text(&ogg_sub, &packet[lcv], pack->bytes - lcv, endpts); - } - - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Ogg sub lines: %d first: '%s'\n", - ogg_sub.lines, ogg_sub.text[0]); -#ifdef CONFIG_ICONV - subcp_recode(&ogg_sub); -#endif - vo_sub = &ogg_sub; - vo_osd_changed(OSDTYPE_SUBTITLE); -} - - -// get the logical stream of the current page -// fill os if non NULL and return the stream id -static int demux_ogg_get_page_stream(ogg_demuxer_t *ogg_d, - ogg_stream_state **os) -{ - int id, s_no; - ogg_page *page = &ogg_d->page; - - s_no = ogg_page_serialno(page); - - for (id = 0; id < ogg_d->num_sub; id++) - if (s_no == ogg_d->subs[id].stream.serialno) - break; - - if (id == ogg_d->num_sub) { - // If we have only one vorbis stream allow the stream id to change - // it's normal on radio stream (each song have an different id). - // But we (or the codec?) should check that the samplerate, etc - // doesn't change (for radio stream it's ok) - if (ogg_d->num_sub == 1 && ogg_d->subs[0].vorbis) { - ogg_stream_reset(&ogg_d->subs[0].stream); - ogg_stream_init(&ogg_d->subs[0].stream, s_no); - id = 0; - } else - return -1; - } - - if (os) - *os = &ogg_d->subs[id].stream; - - return id; -} - -static unsigned char *demux_ogg_read_packet(ogg_stream_t *os, ogg_packet *pack, - float *pts, bool *keyframe, - int samplesize) -{ - unsigned char *data = pack->packet; - - *pts = MP_NOPTS_VALUE; - *keyframe = false; - - if (os->vorbis) { - if (*pack->packet & PACKET_TYPE_HEADER) { - os->hdr_packets++; - } else { - vorbis_info *vi; - int32_t blocksize = 0; - - // When we dump the audio, there is no vi, but we don't care of timestamp in this case - vi = os->vi_initialized ? &os->vi : NULL; - if (vi) - blocksize = vorbis_packet_blocksize(vi, pack) / samplesize; - // Calculate the timestamp if the packet don't have any - if (pack->granulepos == -1) { - pack->granulepos = os->lastpos; - if (os->lastsize > 0) - pack->granulepos += os->lastsize; - } else - *keyframe = true; - if (vi) - *pts = pack->granulepos / (float)vi->rate; - os->lastsize = blocksize; - os->lastpos = pack->granulepos; - } - } else if (os->speex) { - // whole packet (default) -# ifdef CONFIG_OGGTHEORA - } else if (os->theora) { - /* we pass complete packets to theora, mustn't strip the header! */ - os->lastsize = 1; - - /* header packets begin on 1-bit: thus check (*data&0x80). We don't - have theora_state st, until all header packets were passed to the - decoder. */ - if (!pack->bytes || !(*data&0x80)) { - int keyframe_granule_shift = _ilog(os->keyframe_frequency_force - 1); - int64_t iframemask = (1 << keyframe_granule_shift) - 1; - - if (pack->granulepos >= 0) { - os->lastpos = pack->granulepos >> keyframe_granule_shift; - os->lastpos += pack->granulepos & iframemask; - *keyframe = (pack->granulepos & iframemask) == 0; - } else { - os->lastpos++; - } - pack->granulepos = os->lastpos; - *pts = (double)os->lastpos / (double)os->samplerate; - } -#endif /* CONFIG_OGGTHEORA */ - } else if (os->flac) { - /* we pass complete packets to flac, mustn't strip the header! */ - if (os->flac == 2 && pack->packet[0] != 0xff) - return NULL; - } else { - if (*pack->packet & PACKET_TYPE_HEADER) { - os->hdr_packets++; - } else { - // Find data start - int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01) >> 6; - - hdrlen |= (*pack->packet & PACKET_LEN_BITS2) << 1; - data = pack->packet + 1 + hdrlen; - // Calculate the timestamp - if (pack->granulepos == -1) - pack->granulepos = os->lastpos + (os->lastsize ? os->lastsize : 1); - // If we already have a timestamp it can be a syncpoint - if (*pack->packet & PACKET_IS_SYNCPOINT) - *keyframe = true; - *pts = pack->granulepos / os->samplerate; - // Save the packet length and timestamp - os->lastsize = 0; - while (hdrlen) { - os->lastsize <<= 8; - os->lastsize |= pack->packet[hdrlen]; - hdrlen--; - } - os->lastpos = pack->granulepos; - } - } - return data; -} - -// check if clang has substring from comma separated langlist -static int demux_ogg_check_lang(const char *clang, char **langlist) -{ - if (!langlist) - return 0; - for (int i = 0; langlist[i]; i++) - if (!strncasecmp(clang, langlist[i], strlen(langlist[i]))) - return 1; - return 0; -} - -/** \brief Change the current subtitle stream and return its ID. - - \param demuxer The demuxer whose subtitle stream will be changed. - \param new_num The number of the new subtitle track. The number must be - between 0 and ogg_d->n_text - 1. - - \returns The Ogg stream number ( = page serial number) of the newly selected - track. - */ -static int demux_ogg_sub_id(demuxer_t *demuxer, int index) -{ - ogg_demuxer_t *ogg_d = demuxer->priv; - return (index < 0) ? index : (index >= ogg_d->n_text) ? -1 : ogg_d->text_ids[index]; -} - -/** \brief Translate the ogg track number into the subtitle number. - * \param demuxer The demuxer about whose subtitles we are inquiring. - * \param id The ogg track number of the subtitle track. - */ -static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id) -{ - ogg_demuxer_t *ogg_d = demuxer->priv; - int i; - - for (i = 0; i < ogg_d->n_text; i++) - if (ogg_d->text_ids[i] == id) - return i; - return -1; -} - -/// Try to print out comments and also check for LANGUAGE= tag -static void demux_ogg_check_comments(demuxer_t *d, ogg_stream_t *os, - int id, vorbis_comment *vc) -{ - const char *hdr, *val; - char **cmt = vc->user_comments; - int index, i; - ogg_demuxer_t *ogg_d = d->priv; - static const struct table { - const char *ogg; - const char *mp; - } table[] = { - { "ENCODED_USING", "Software" }, - { "ENCODER_URL", "Encoder URL" }, - { "TITLE", "Title" }, - { "ARTIST", "Artist" }, - { "COMMENT", "Comments" }, - { "DATE", "Creation Date" }, - { "GENRE", "Genre" }, - { "ALBUM", "Album" }, - { "TRACKNUMBER", "Track" }, - { NULL, NULL }, - }; - - while (*cmt) { - hdr = val = NULL; - if (!strncasecmp(*cmt, "LANGUAGE=", 9)) { - val = *cmt + 9; - if (ogg_d->subs[id].text) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", - ogg_d->subs[id].id, val); - else if (id != d->video->id) - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", - ogg_d->subs[id].id, val); - if (ogg_d->subs[id].text) - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] Language for -sid %d is '-slang \"%s\"'\n", - ogg_d->subs[id].id, val); - // copy this language name into the array - index = demux_ogg_sub_reverse_id(d, id); - if (index >= 0) { - sh_sub_t *sh; - - // in case of malicious files with more than one lang per track: - free(ogg_d->text_langs[index]); - ogg_d->text_langs[index] = strdup(val); - sh = d->s_streams[index]; - if (sh) { - talloc_free(sh->lang); - sh->lang = talloc_strdup(sh, val); - } - } - // check for -slang if subs are uninitialized yet - if (os->text && d->sub->id < 0 - && demux_ogg_check_lang(val, d->opts->sub_lang)) { - d->sub->id = index; - d->opts->sub_id = index; - mp_msg(MSGT_DEMUX, MSGL_V, - "Ogg demuxer: Displaying subtitle stream id %d which matched -slang %s\n", - id, val); - } - else - hdr = "Language"; - } - else { - for (i = 0; table[i].ogg; i++) { - if (!strncasecmp(*cmt, table[i].ogg, strlen(table[i].ogg)) && - (*cmt)[strlen(table[i].ogg)] == '=') { - hdr = table[i].mp; - val = *cmt + strlen(table[i].ogg) + 1; - } - } - } - if (hdr) - demux_info_add(d, hdr, val); - mp_dbg(MSGT_DEMUX, MSGL_DBG2, " %s: %s\n", hdr, val); - cmt++; - } -} - -/// Calculate the timestamp and add the packet to the demux stream -// return 1 if the packet was added, 0 otherwise -static int demux_ogg_add_packet(demux_stream_t *ds, ogg_stream_t *os, - int id, ogg_packet *pack) -{ - demuxer_t *d = ds->demuxer; - int samplesize = 1; - - // If packet is an comment header then we try to get comments at first - if (pack->bytes >= 7 && !memcmp(pack->packet, "\003vorbis", 7)) { - vorbis_info vi; - vorbis_comment vc; - - vorbis_info_init(&vi); - vorbis_comment_init(&vc); - vi.rate = 1L; // it's checked by vorbis_synthesis_headerin() - if (vorbis_synthesis_headerin(&vi, &vc, pack) == 0) // if no errors - demux_ogg_check_comments(d, os, id, &vc); - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); - } - if (os->text) { - if (id == demux_ogg_sub_id(d, d->sub->id)) // don't want to add subtitles to the demuxer for now - demux_ogg_add_sub(os, pack); - return 0; - } - if (os->speex) { - // discard first two packets, they contain the header and comment - if (os->hdr_packets < 2) { - os->hdr_packets++; - return 0; - } - } else { - // If packet is an header we jump it except for vorbis and theora - // (PACKET_TYPE_HEADER bit doesn't even exist for theora ?!) - // We jump nothing for FLAC. Ain't this great? Packet contents have to be - // handled differently for each and every stream type. The joy! The joy! - if (!os->flac && (*pack->packet & PACKET_TYPE_HEADER) && - (ds != d->audio || ((sh_audio_t*)ds->sh)->format != FOURCC_VORBIS || os->hdr_packets >= NUM_VORBIS_HDR_PACKETS ) && - (ds != d->video || (((sh_video_t*)ds->sh)->format != FOURCC_THEORA))) - return 0; - } - - // For vorbis packet the packet is the data, for other codec we must jump - // the header - if (ds == d->audio && ((sh_audio_t*)ds->sh)->format == FOURCC_VORBIS) { - samplesize = ((sh_audio_t *)ds->sh)->samplesize; - } - bool keyframe; - float pts; - unsigned char *data; - data = demux_ogg_read_packet(os, pack, &pts, &keyframe, samplesize); - if (!data) - return 0; - - /// Clear subtitles if necessary (for broken files) - if (sub_clear_text(&ogg_sub, pts)) { - vo_sub = &ogg_sub; - vo_osd_changed(OSDTYPE_SUBTITLE); - } - /// Send the packet - struct demux_packet *dp; - dp = new_demux_packet(pack->bytes - (data - pack->packet)); - memcpy(dp->buffer, data, pack->bytes - (data - pack->packet)); - dp->pts = pts; - dp->keyframe = keyframe; - ds_add_packet(ds, dp); - mp_msg(MSGT_DEMUX, MSGL_DBG2, - "New dp: %p ds=%p pts=%5.3f len=%d keyframe=%d \n", - dp, ds, pts, dp->len, keyframe); - return 1; -} - -/// if -forceidx build a table of all syncpoints to make seeking easier -/// otherwise try to get at least the final_granulepos -static void demux_ogg_scan_stream(demuxer_t *demuxer) -{ - ogg_demuxer_t *ogg_d = demuxer->priv; - stream_t *s = demuxer->stream; - ogg_sync_state *sync = &ogg_d->sync; - ogg_page *page = &ogg_d->page; - ogg_stream_state *oss; - ogg_stream_t *os; - ogg_packet op; - int np, sid, p, samplesize = 1; - off_t pos, last_pos; - - pos = last_pos = demuxer->movi_start; - - // Reset the stream - stream_seek(s, demuxer->movi_start); - ogg_sync_reset(sync); - - // Get the serial number of the stream we use - if (demuxer->video->id >= 0) { - sid = demuxer->video->id; - } else if (demuxer->audio->id >= 0) { - sid = demuxer->audio->id; - if (((sh_audio_t*)demuxer->audio->sh)->format == FOURCC_VORBIS) - samplesize = ((sh_audio_t*)demuxer->audio->sh)->samplesize; - } else - return; - os = &ogg_d->subs[sid]; - oss = &os->stream; - - while (1) { - np = ogg_sync_pageseek(sync, page); - if (np < 0) { // We had to skip some bytes - if (index_mode == 2) - mp_msg(MSGT_DEMUX, MSGL_ERR, - "Bad page sync while building syncpoints table (%d)\n", - -np); - pos += -np; - continue; - } - if (np <= 0) { // We need more data - char *buf = ogg_sync_buffer(sync, BLOCK_SIZE); - int len = stream_read(s, buf, BLOCK_SIZE); - - if (len == 0 && s->eof) - break; - ogg_sync_wrote(sync, len); - continue; - } - // The page is ready - //ogg_sync_pageout(sync, page); - if (ogg_page_serialno(page) != os->stream.serialno) { // It isn't a page from the stream we want - pos += np; - continue; - } - if (ogg_stream_pagein(oss, page) != 0) { - mp_msg(MSGT_DEMUX, MSGL_ERR, "Pagein error ????\n"); - pos += np; - continue; - } - p = 0; - while (ogg_stream_packetout(oss, &op) == 1) { - float pts; - bool keyframe; - - demux_ogg_read_packet(os, &op, &pts, &keyframe, samplesize); - if (op.granulepos >= 0) { - ogg_d->final_granulepos = op.granulepos; - if (ogg_d->initial_granulepos == MP_NOPTS_VALUE && keyframe) { - ogg_d->initial_granulepos = op.granulepos; - if (index_mode != 2 && ogg_d->pos < demuxer->movi_end - 2 * 270000) { - //the 270000 are just a wild guess - stream_seek(s, FFMAX(ogg_d->pos, demuxer->movi_end - 270000)); - ogg_sync_reset(sync); - continue; - } - } - } - if (index_mode == 2 && (keyframe || (os->vorbis && op.granulepos >= 0))) { - if (ogg_d->num_syncpoint > SIZE_MAX / sizeof(ogg_syncpoint_t) - 1) - break; - ogg_d->syncpoints = realloc_struct(ogg_d->syncpoints, (ogg_d->num_syncpoint + 1), sizeof(ogg_syncpoint_t)); - ogg_d->syncpoints[ogg_d->num_syncpoint].granulepos = op.granulepos; - ogg_d->syncpoints[ogg_d->num_syncpoint].page_pos = (ogg_page_continued(page) && p == 0) ? last_pos : pos; - ogg_d->num_syncpoint++; - } - p++; - } - if (p > 1 || (p == 1 && !ogg_page_continued(page))) - last_pos = pos; - pos += np; - if (index_mode == 2) - mp_msg(MSGT_DEMUX, MSGL_INFO, "Building syncpoint table %d%%\r", - (int)(pos * 100 / s->end_pos)); - } - - if (index_mode == 2) { - mp_msg(MSGT_DEMUX, MSGL_INFO, "\n"); - mp_msg(MSGT_DEMUX, MSGL_V, - "Ogg syncpoints table builed: %d syncpoints\n", - ogg_d->num_syncpoint); - } - - mp_msg(MSGT_DEMUX, MSGL_V, "Ogg stream length (granulepos): %"PRId64"\n", - ogg_d->final_granulepos); - - stream_reset(s); - stream_seek(s, demuxer->movi_start); - ogg_sync_reset(sync); - for (np = 0; np < ogg_d->num_sub; np++) { - ogg_stream_reset(&ogg_d->subs[np].stream); - ogg_d->subs[np].lastpos = ogg_d->subs[np].lastsize = ogg_d->subs[np].hdr_packets = 0; - } - - // Get the first page - while (1) { - np = ogg_sync_pageout(sync, page); - if (np <= 0) { // We need more data - char *buf = ogg_sync_buffer(sync, BLOCK_SIZE); - int len = stream_read(s, buf, BLOCK_SIZE); - - if (len == 0 && s->eof) { - mp_msg(MSGT_DEMUX, MSGL_ERR, "EOF while trying to get the first page !!!!\n"); - break; - } - ogg_sync_wrote(sync, len); - continue; - } - demux_ogg_get_page_stream(ogg_d, &oss); - ogg_stream_pagein(oss, page); - break; - } -} - -static void fixup_vorbis_wf(sh_audio_t *sh, ogg_demuxer_t *od) -{ - int i, offset; - int ris, init_error = 0; - ogg_packet op[3]; - unsigned char *buf[3]; - unsigned char *ptr; - unsigned int len; - ogg_stream_t *os = &od->subs[sh->ds->id]; - vorbis_comment vc; - - vorbis_info_init(&os->vi); - vorbis_comment_init(&vc); - for (i = 0; i < 3; i++) { - op[i].bytes = ds_get_packet(sh->ds, &(op[i].packet)); - mp_msg(MSGT_DEMUX, MSGL_V, "fixup_vorbis_wf: i=%d, size=%ld\n", i, op[i].bytes); - if (op[i].bytes < 0) { - mp_msg(MSGT_DEMUX, MSGL_ERR, "Ogg demuxer error!, fixup_vorbis_wf: bad packet n. %d\n", i); - return; - } - buf[i] = malloc(op[i].bytes); - if (!buf[i]) - return; - memcpy(buf[i], op[i].packet, op[i].bytes); - - op[i].b_o_s = (i == 0); - ris = vorbis_synthesis_headerin(&os->vi, &vc, &op[i]); - if (ris < 0) { - init_error = 1; - mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DEMUX_OGG: header n. %d broken! len=%ld, code: %d\n", i, op[i].bytes, ris); - } - } - vorbis_comment_clear(&vc); - if (!init_error) - os->vi_initialized = 1; - - len = op[0].bytes + op[1].bytes + op[2].bytes; - sh->wf = calloc(1, sizeof(*sh->wf) + len + len / 255 + 64); - ptr = (unsigned char*)(sh->wf + 1); - - ptr[0] = 2; - offset = 1; - offset += store_ughvlc(&ptr[offset], op[0].bytes); - mp_msg(MSGT_DEMUX, MSGL_V, "demux_ogg, offset after 1st len = %u\n", offset); - offset += store_ughvlc(&ptr[offset], op[1].bytes); - mp_msg(MSGT_DEMUX, MSGL_V, "demux_ogg, offset after 2nd len = %u\n", offset); - for (i = 0; i < 3; i++) { - mp_msg(MSGT_DEMUX, MSGL_V, "demux_ogg, i=%d, bytes: %ld, offset: %u\n", i, op[i].bytes, offset); - memcpy(&ptr[offset], buf[i], op[i].bytes); - offset += op[i].bytes; - } - sh->wf->cbSize = offset; - mp_msg(MSGT_DEMUX, MSGL_V, "demux_ogg, extradata size: %d\n", sh->wf->cbSize); - sh->wf = realloc(sh->wf, sizeof(*sh->wf) + sh->wf->cbSize); - - if (op[0].bytes >= 29) { - unsigned int br; - int nombr, minbr, maxbr; - - ptr = buf[0]; - sh->channels = ptr[11]; - sh->samplerate = sh->wf->nSamplesPerSec = AV_RL32(&ptr[12]); - maxbr = AV_RL32(&ptr[16]); //max - nombr = AV_RL32(&ptr[20]); //nominal - minbr = AV_RL32(&ptr[24]); //minimum - - if (maxbr == -1) - maxbr = 0; - if (nombr == -1) - nombr = 0; - if (minbr == -1) - minbr = 0; - - br = maxbr / 8; - if (!br) - br = nombr / 8; - if (!br) - br = minbr / 8; - sh->wf->nAvgBytesPerSec = br; - sh->wf->wBitsPerSample = 16; - sh->samplesize = (sh->wf->wBitsPerSample + 7) / 8; - - 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", - sh->channels, sh->samplerate, sh->wf->nAvgBytesPerSec, - maxbr, nombr, minbr); - } - free(buf[2]); - free(buf[1]); - free(buf[0]); -} - -/// Open an ogg physical stream -// Not static because it's used also in demuxer_avi.c -int demux_ogg_open(demuxer_t *demuxer) -{ - ogg_demuxer_t *ogg_d; - stream_t *s; - char *buf; - int np, s_no, n_audio = 0, n_video = 0; - int audio_id = -1, video_id = -1, text_id = -1; - ogg_sync_state *sync; - ogg_page *page; - ogg_packet pack; - sh_audio_t *sh_a; - sh_video_t *sh_v; - -#ifdef CONFIG_ICONV - subcp_open(NULL); -#endif - - s = demuxer->stream; - - demuxer->priv = ogg_d = calloc(1, sizeof(*ogg_d)); - sync = &ogg_d->sync; - page = &ogg_d->page; - - ogg_sync_init(sync); - - while (1) { - /// Try to get a page - ogg_d->pos += ogg_d->last_size; - np = ogg_sync_pageseek(sync, page); - /// Error - if (np < 0) { - mp_msg(MSGT_DEMUX, MSGL_DBG2, "Ogg demuxer : Bad page sync\n"); - goto err_out; - } - /// Need some more data - if (np == 0) { - int len; - - buf = ogg_sync_buffer(sync, BLOCK_SIZE); - len = stream_read(s, buf, BLOCK_SIZE); - if (len == 0 && s->eof) { - goto err_out; - } - ogg_sync_wrote(sync, len); - continue; - } - ogg_d->last_size = np; - // We got one page now - - if (!ogg_page_bos(page)) { // It's not a beginning page - // Header parsing end here, we need to get the page otherwise it will be lost - int id = demux_ogg_get_page_stream(ogg_d, NULL); - if (id >= 0) - ogg_stream_pagein(&ogg_d->subs[id].stream, page); - else - mp_msg(MSGT_DEMUX, MSGL_ERR, - "Ogg : Warning found none bos page from unknown stream %d\n", - ogg_page_serialno(page)); - break; - } - - /// Init the data structure needed for a logical stream - ogg_d->subs = realloc_struct(ogg_d->subs, ogg_d->num_sub+1, - sizeof(ogg_stream_t)); - memset(&ogg_d->subs[ogg_d->num_sub], 0, sizeof(ogg_stream_t)); - /// Get the stream serial number - s_no = ogg_page_serialno(page); - ogg_stream_init(&ogg_d->subs[ogg_d->num_sub].stream, s_no); - mp_msg(MSGT_DEMUX, MSGL_DBG2, - "Ogg : Found a stream with serial=%d\n", s_no); - // Take the first page - ogg_stream_pagein(&ogg_d->subs[ogg_d->num_sub].stream, page); - // Get first packet of the page - ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream, &pack); - - // Reset our vars - sh_a = NULL; - sh_v = NULL; - - ogg_d->subs[ogg_d->num_sub].ogg_d = ogg_d; - - // Check for Vorbis - if (pack.bytes >= 7 && !strncmp(&pack.packet[1], "vorbis", 6)) { - sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio); - sh_a->format = FOURCC_VORBIS; - ogg_d->subs[ogg_d->num_sub].vorbis = 1; - ogg_d->subs[ogg_d->num_sub].id = n_audio; - n_audio++; - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] stream %d: audio (Vorbis), -aid %d\n", - ogg_d->num_sub, n_audio - 1); - } else if (pack.bytes >= 80 && !strncmp(pack.packet, "Speex", 5)) { - sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio); - sh_a->wf = calloc(1, sizeof(*sh_a->wf) + pack.bytes); - sh_a->format = FOURCC_SPEEX; - sh_a->samplerate = sh_a->wf->nSamplesPerSec = AV_RL32(&pack.packet[36]); - sh_a->channels = sh_a->wf->nChannels = AV_RL32(&pack.packet[48]); - sh_a->wf->wFormatTag = sh_a->format; - sh_a->wf->nAvgBytesPerSec = AV_RL32(&pack.packet[52]); - sh_a->wf->nBlockAlign = 0; - sh_a->wf->wBitsPerSample = 16; - sh_a->samplesize = 2; - sh_a->wf->cbSize = pack.bytes; - memcpy(&sh_a->wf[1], pack.packet, pack.bytes); - - ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate; - ogg_d->subs[ogg_d->num_sub].speex = 1; - ogg_d->subs[ogg_d->num_sub].id = n_audio; - n_audio++; - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] stream %d: audio (Speex), -aid %d\n", - ogg_d->num_sub, n_audio - 1); - - // check for Theora -#ifdef CONFIG_OGGTHEORA - } else if (pack.bytes >= 7 && !strncmp (&pack.packet[1], "theora", 6)) { - int errorCode = 0; - theora_info inf; - theora_comment cc; - - theora_info_init (&inf); - theora_comment_init (&cc); - - errorCode = theora_decode_header (&inf, &cc, &pack); - if (errorCode) { - mp_msg(MSGT_DEMUX, MSGL_ERR, - "Theora header parsing failed: %i \n", errorCode); - } else { - sh_v = new_sh_video_vid(demuxer, ogg_d->num_sub, n_video); - - sh_v->bih = calloc(1, sizeof(*sh_v->bih)); - sh_v->bih->biSize = sizeof(*sh_v->bih); - sh_v->bih->biCompression = sh_v->format = FOURCC_THEORA; - sh_v->fps = ((double)inf.fps_numerator) / (double)inf.fps_denominator; - sh_v->frametime = ((double)inf.fps_denominator) / (double)inf.fps_numerator; - sh_v->disp_w = sh_v->bih->biWidth = inf.frame_width; - sh_v->disp_h = sh_v->bih->biHeight = inf.frame_height; - sh_v->bih->biBitCount = 24; - sh_v->bih->biPlanes = 3; - sh_v->bih->biSizeImage = ((sh_v->bih->biBitCount / 8) * sh_v->bih->biWidth * sh_v->bih->biHeight); - ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps; - ogg_d->subs[ogg_d->num_sub].theora = 1; - ogg_d->subs[ogg_d->num_sub].keyframe_frequency_force = inf.keyframe_frequency_force; - ogg_d->subs[ogg_d->num_sub].id = n_video; - n_video++; - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] stream %d: video (Theora v%d.%d.%d), -vid %d\n", - ogg_d->num_sub, - (int)inf.version_major, - (int)inf.version_minor, - (int)inf.version_subminor, - n_video - 1); - if (mp_msg_test(MSGT_HEADER, MSGL_V)) - print_video_header(sh_v->bih, MSGL_V); - } - theora_comment_clear(&cc); - theora_info_clear(&inf); -#endif /* CONFIG_OGGTHEORA */ - } else if (pack.bytes >= 4 && !strncmp (&pack.packet[0], "fLaC", 4)) { - sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio); - sh_a->format = mmioFOURCC('f', 'L', 'a', 'C'); - ogg_d->subs[ogg_d->num_sub].id = n_audio; - n_audio++; - ogg_d->subs[ogg_d->num_sub].flac = 1; - sh_a->wf = NULL; - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] stream %d: audio (FLAC), -aid %d\n", - ogg_d->num_sub, n_audio - 1); - } else if (pack.bytes >= 51 && !strncmp(&pack.packet[1], "FLAC", 4)) { - sh_a = new_sh_audio_aid(demuxer, ogg_d->num_sub, n_audio); - sh_a->format = mmioFOURCC('f', 'L', 'a', 'C'); - ogg_d->subs[ogg_d->num_sub].id = n_audio; - n_audio++; - ogg_d->subs[ogg_d->num_sub].flac = 2; - sh_a->wf = calloc(1, sizeof(*sh_a->wf) + 34); - sh_a->wf->wFormatTag = sh_a->format; - sh_a->wf->cbSize = 34; - memcpy(&sh_a->wf[1], &pack.packet[17], 34); - mp_msg(MSGT_DEMUX, MSGL_INFO, - "[Ogg] stream %d: audio (FLAC, try 2), -aid %d\n", - ogg_d->num_sub, n_audio - 1); - - /// Check for old header - } else if (pack.bytes >= 142 && - !strncmp(&pack.packet[1], "Direct Show Samples embedded in Ogg", 35)) { - - // Old video header - if (AV_RL32(pack.packet + 96) == 0x05589f80 && pack.bytes >= 184) { - sh_v = new_sh_video_vid(demuxer, ogg_d->num_sub, n_video); - sh_v->bih = calloc(1, sizeof(*sh_v->bih)); - sh_v->bih->biSize = sizeof(*sh_v->bih); - sh_v->bih->biCompression = sh_v->format = mmioFOURCC(pack.packet[68], pack.packet[69], - pack.packet[70], pack.packet[71]); - sh_v-& |