From f209e8b8ef44998a5ea20544bbb39aaeefa28086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Diego=20=27Flameeyes=27=20Petten=C3=B2?= Date: Fri, 1 Jun 2007 21:05:12 +0200 Subject: Collapse the Ogg demuxer, and the Theora, Vorbis and Speex decoders in the same 'xiph' plugin. As the three decoders requires Ogg support, and requires an Ogg demuxer to play, enabling any one of them will then enable the ogg demuxer. The Ogg demuxer, on its own, needs to know which of the three formats are enabled, or it will not be able to properly decode them. With this change, only one plugin will need to load and know about Xiph formats and libraries. --HG-- rename : src/demuxers/demux_ogg.c => src/combined/xine_ogg_demuxer.c rename : src/libxineadec/xine_speex_decoder.c => src/combined/xine_speex_decoder.c rename : src/libxinevdec/xine_theora_decoder.c => src/combined/xine_theora_decoder.c rename : src/libxineadec/xine_vorbis_decoder.c => src/combined/xine_vorbis_decoder.c --- src/combined/Makefile.am | 26 + src/combined/xine_ogg_demuxer.c | 2231 +++++++++++++++++++++++++++++++++ src/combined/xine_speex_decoder.c | 413 ++++++ src/combined/xine_theora_decoder.c | 396 ++++++ src/combined/xine_vorbis_decoder.c | 348 +++++ src/demuxers/Makefile.am | 9 - src/demuxers/demux_ogg.c | 2202 -------------------------------- src/libxineadec/Makefile.am | 18 - src/libxineadec/xine_speex_decoder.c | 419 ------- src/libxineadec/xine_vorbis_decoder.c | 354 ------ src/libxinevdec/Makefile.am | 8 - src/libxinevdec/xine_theora_decoder.c | 402 ------ 12 files changed, 3414 insertions(+), 3412 deletions(-) create mode 100644 src/combined/xine_ogg_demuxer.c create mode 100644 src/combined/xine_speex_decoder.c create mode 100644 src/combined/xine_theora_decoder.c create mode 100644 src/combined/xine_vorbis_decoder.c delete mode 100644 src/demuxers/demux_ogg.c delete mode 100644 src/libxineadec/xine_speex_decoder.c delete mode 100644 src/libxineadec/xine_vorbis_decoder.c delete mode 100644 src/libxinevdec/xine_theora_decoder.c (limited to 'src') diff --git a/src/combined/Makefile.am b/src/combined/Makefile.am index cf88795ba..c1e590fd7 100644 --- a/src/combined/Makefile.am +++ b/src/combined/Makefile.am @@ -32,3 +32,29 @@ xineplug_nsf_la_SOURCES = nsf_decoder.c nsf_demuxer.c nsf_combined.c xineplug_nsf_la_LIBADD = $(XINE_LIB) $(top_builddir)/contrib/nosefart/libnosefart.la -lm xineplug_nsf_la_CFLAGS = $(AM_CFLAGS) -fno-strict-aliasing xineplug_nsf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNSF_PLAYER -I$(top_srcdir)/contrib/nosefart -I$(top_srcdir)/src/demuxers + +xineplug_xiph_la_SOURCES = xine_ogg_demuxer.c +xineplug_xiph_la_LIBADD = $(XINE_LIB) +xineplug_xiph_la_CFLAGS = $(AM_CFLAGS) +xineplug_xiph_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/demuxers + +if ENABLE_VORBIS +xineplug_LTLIBRARIES += xineplug_xiph.la +xineplug_xiph_la_SOURCES += xine_vorbis_decoder.c +xineplug_xiph_la_LIBADD += $(VORBIS_LIBS) +xineplug_xiph_la_CFLAGS += $(VORBIS_CFLAGS) +endif + +if ENABLE_THEORA +xineplug_LTLIBRARIES += xineplug_xiph.la +xineplug_xiph_la_SOURCES += xine_theora_decoder.c +xineplug_xiph_la_LIBADD += $(THEORA_LIBS) +xineplug_xiph_la_CFLAGS += $(THEORA_CFLAGS) +endif + +if ENABLE_SPEEX +xineplug_LTLIBRARIES += xineplug_xiph.la +xineplug_xiph_la_SOURCES += xine_speex_decoder.c +xineplug_xiph_la_LIBADD += $(SPEEX_LIBS) +xineplug_xiph_la_CFLAGS += $(SPEEX_CFLAGS) +endif diff --git a/src/combined/xine_ogg_demuxer.c b/src/combined/xine_ogg_demuxer.c new file mode 100644 index 000000000..56234723d --- /dev/null +++ b/src/combined/xine_ogg_demuxer.c @@ -0,0 +1,2231 @@ +/* + * Copyright (C) 2000-2004 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * $Id: demux_ogg.c,v 1.177 2007/03/29 19:38:51 dgp85 Exp $ + * + * demultiplexer for ogg streams + * + */ +/* 2003.02.09 (dilb) update of the handling for audio/video infos for strongarm cpus. */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_VORBIS +#include +#endif + +#ifdef HAVE_SPEEX +#include +#include +#include +#include +#endif + +#ifdef HAVE_THEORA +#include +#endif + +#define LOG_MODULE "demux_ogg" +#define LOG_VERBOSE + +/* +#define LOG +*/ + +#define DEBUG_PACKETS 0 +#define DEBUG_PREVIEWS 0 +#define DEBUG_PTS 0 +#define DEBUG_VIDEO_PACKETS 0 + +#include "xine_internal.h" +#include "xineutils.h" +#include "demux.h" +#include "bswap.h" +#include "flacutils.h" + +#define CHUNKSIZE 8500 +#define PACKET_TYPE_HEADER 0x01 +#define PACKET_TYPE_COMMENT 0x03 +#define PACKET_TYPE_CODEBOOK 0x05 +#define PACKET_TYPE_BITS 0x07 +#define PACKET_LEN_BITS01 0xc0 +#define PACKET_LEN_BITS2 0x02 +#define PACKET_IS_SYNCPOINT 0x08 + +#define MAX_STREAMS 32 + +#define PTS_AUDIO 0 +#define PTS_VIDEO 1 + +#define WRAP_THRESHOLD 900000 + +#define SUB_BUFSIZE 1024 + +typedef struct chapter_entry_s { + int64_t start_pts; + char *name; +} chapter_entry_t; + +typedef struct chapter_info_s { + int current_chapter; + int max_chapter; + chapter_entry_t *entries; +} chapter_info_t; + +typedef struct stream_info_s { + ogg_stream_state oss; + uint32_t buf_types; + int headers; + int64_t header_granulepos; + int64_t factor; + int64_t quotient; + int resync; + char *language; + /* CMML, Ogg Skeleton stream information */ + int granuleshift; + /* Annodex v2 stream information */ + int hide_first_header; + int delivered_bos; + int delivered_eos; +} stream_info_t; + +typedef struct demux_ogg_s { + demux_plugin_t demux_plugin; + + xine_stream_t *stream; + fifo_buffer_t *audio_fifo; + fifo_buffer_t *video_fifo; + input_plugin_t *input; + int status; + + int frame_duration; + +#ifdef HAVE_THEORA + theora_info t_info; + theora_comment t_comment; +#endif + + ogg_sync_state oy; + ogg_page og; + + int64_t start_pts; + int64_t last_pts[2]; + + int time_length; + + int num_streams; + stream_info_t *si[MAX_STREAMS]; /* stream info */ + + int num_audio_streams; + int num_video_streams; + int unhandled_video_streams; + int num_spu_streams; + + off_t avg_bitrate; + + char *title; + chapter_info_t *chapter_info; + xine_event_queue_t *event_queue; + + uint8_t send_newpts:1; + uint8_t buf_flag_seek:1; + uint8_t keyframe_needed:1; + uint8_t ignore_keyframes:1; +} demux_ogg_t ; + +typedef struct { + demux_class_t demux_class; +} demux_ogg_class_t; + +typedef struct { + demux_class_t demux_class; +} demux_anx_class_t; + + +#ifdef HAVE_THEORA +static int intlog(int num) { + int ret=0; + + while(num>0){ + num=num/2; + ret=ret+1; + } + return(ret); +} +#endif + +static int get_stream (demux_ogg_t *this, int serno) { + /*finds the stream_num, which belongs to a ogg serno*/ + int i; + + for (i = 0; inum_streams; i++) { + if (this->si[i]->oss.serialno == serno) { + return i; + } + } + return -1; +} + +static int new_stream_info (demux_ogg_t *this, const int cur_serno) { + int stream_num; + + this->si[this->num_streams] = (stream_info_t *)xine_xmalloc(sizeof(stream_info_t)); + ogg_stream_init(&this->si[this->num_streams]->oss, cur_serno); + stream_num = this->num_streams; + this->si[stream_num]->buf_types = 0; + this->si[stream_num]->header_granulepos = -1; + this->si[stream_num]->headers = 0; + this->num_streams++; + + return stream_num; +} + +static int64_t get_pts (demux_ogg_t *this, int stream_num , int64_t granulepos ) { + /*calculates an pts from an granulepos*/ + if (granulepos<0) { + if ( this->si[stream_num]->header_granulepos>=0 ) { + /*return the smallest valid pts*/ + return 1; + } else + return 0; + } else if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA || + (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { + int64_t iframe, pframe; + int granuleshift; + granuleshift = this->si[stream_num]->granuleshift; + iframe = granulepos >> granuleshift; + pframe = granulepos - (iframe << granuleshift); + if (this->si[stream_num]->quotient) + return 1+((iframe+pframe) * this->si[stream_num]->factor / this->si[stream_num]->quotient); + else + return 0; + } else if (this->si[stream_num]->quotient) + return 1+(granulepos * this->si[stream_num]->factor / this->si[stream_num]->quotient); + else + return 0; +} + +static int read_ogg_packet (demux_ogg_t *this) { + char *buffer; + long bytes; + while (ogg_sync_pageout(&this->oy,&this->og)!=1) { + buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); + bytes = this->input->read(this->input, buffer, CHUNKSIZE); + ogg_sync_wrote(&this->oy, bytes); + if (bytes < CHUNKSIZE/2) { + return 0; + } + } + return 1; +} + +static void get_stream_length (demux_ogg_t *this) { + /*determine the streamlenght and set this->time_length accordingly. + ATTENTION:current_pos and oggbuffers will be destroyed by this function, + there will be no way to continue playback uninterrupted. + + You have to seek afterwards, because after get_stream_length, the + current_position is at the end of the file */ + + off_t filelength; + int done=0; + int stream_num; + + this->time_length=-1; + + if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { + filelength=this->input->get_length(this->input); + + if (filelength!=-1) { + if (filelength>70000) { + this->demux_plugin.seek(&this->demux_plugin, + (off_t) ( (double)(filelength-65536)/filelength*65535), 0, 0); + } + done=0; + while (!done) { + if (!read_ogg_packet (this)) { + if (this->time_length) { + _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, + ((int64_t) 8000*filelength)/this->time_length); + /*this is a fine place to compute avg_bitrate*/ + this->avg_bitrate= 8000*filelength/this->time_length; + } + return; + } + stream_num=get_stream(this, ogg_page_serialno (&this->og) ); + if (stream_num!=-1) { + if (this->time_length < (get_pts(this, stream_num, ogg_page_granulepos(&this->og) / 90))) + this->time_length = get_pts(this, stream_num, ogg_page_granulepos(&this->og)) / 90; + } + } + } + } +} + +#ifdef HAVE_THEORA +static void send_ogg_packet (demux_ogg_t *this, + fifo_buffer_t *fifo, + ogg_packet *op, + int64_t pts, + uint32_t decoder_flags, + int stream_num) { + + buf_element_t *buf; + + int done=0,todo=op->bytes; + int op_size = sizeof(ogg_packet); + + while (donebuffer_pool_alloc (fifo); + buf->decoder_flags = decoder_flags; + if (done==0) { + memcpy (buf->content, op, op_size); + offset=op_size; + buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_START; + } + + if (done+buf->max_size-offset < todo) { + memcpy (buf->content+offset, op->packet+done, buf->max_size-offset); + buf->size = buf->max_size; + done=done+buf->max_size-offset; + } else { + memcpy (buf->content+offset , op->packet+done, todo-done); + buf->size = todo-done+offset; + done=todo; + buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_END; + } + + buf->pts = pts; + if( this->input->get_length (this->input) ) + buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * + 65535 / this->input->get_length (this->input) ); + buf->extra_info->input_time = buf->pts / 90 ; + buf->type = this->si[stream_num]->buf_types; + + fifo->put (fifo, buf); + } +} +#endif + +/* redefine abs as macro to handle 64-bit diffs. + i guess llabs may not be available everywhere */ +#define abs(x) ( ((x)<0) ? -(x) : (x) ) + +static void check_newpts (demux_ogg_t *this, int64_t pts, int video, int preview) { + int64_t diff; + + llprintf(DEBUG_PTS, "new pts %" PRId64 " found in stream\n",pts); + + diff = pts - this->last_pts[video]; + + if (!preview && (pts>=0) && + (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { + + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "diff=%" PRId64 " (pts=%" PRId64 ", last_pts=%" PRId64 ")\n", diff, pts, this->last_pts[video]); + + if (this->buf_flag_seek) { + _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); + this->buf_flag_seek = 0; + } else { + _x_demux_control_newpts(this->stream, pts, 0); + } + this->send_newpts = 0; + this->last_pts[1-video] = 0; + } + + if (!preview && (pts>=0) ) + this->last_pts[video] = pts; + + /* use pts for bitrate measurement */ + + /*compute avg_bitrate if time_length isn't set*/ + if ((pts>180000) && !(this->time_length)) { + this->avg_bitrate = this->input->get_current_pos (this->input) * 8 * 90000/ pts; + + if (this->avg_bitrate<1) + this->avg_bitrate = 1; + + } +} + +static void ogg_handle_event (demux_ogg_t *this) { + xine_event_t *event; + + while ((event = xine_event_get(this->event_queue))) { + switch(event->type) { + case XINE_EVENT_INPUT_NEXT: + { + if (this->chapter_info) { + int c_chap = this->chapter_info->current_chapter; + if (c_chap+1 < this->chapter_info->max_chapter) { + int start_time = this->chapter_info->entries[c_chap+1].start_pts / 90; + this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); + } + } + } + break; + case XINE_EVENT_INPUT_PREVIOUS: + { + if (this->chapter_info) { + int c_chap = this->chapter_info->current_chapter; + if (c_chap >= 1) { + int start_time = this->chapter_info->entries[c_chap-1].start_pts / 90; + this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); + } + } + } + break; + } + xine_event_free(event); + } + return; +} + +/* + * utility function to read a LANGUAGE= line from the user_comments, + * to label audio and spu streams + */ +static void read_language_comment (demux_ogg_t *this, ogg_packet *op, int stream_num) { +#ifdef HAVE_VORBIS + char **ptr; + char *comment; + vorbis_comment vc; + vorbis_info vi; + + vorbis_comment_init(&vc); + vorbis_info_init(&vi); + + /* this is necessary to make libvorbis accept this vorbis_info*/ + vi.rate=1; + + if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { + ptr=vc.user_comments; + while(*ptr) { + comment=*ptr; + if ( !strncasecmp ("LANGUAGE=", comment, 9) ) { + this->si[stream_num]->language = strdup (comment + strlen ("LANGUAGE=") ); + } + ++ptr; + } + } + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); +#endif +} + +/* + * utility function to read CHAPTER*= and TITLE= from the user_comments, + * to name parts of the videostream + */ +static void read_chapter_comment (demux_ogg_t *this, ogg_packet *op) { +#ifdef HAVE_VORBIS + char **ptr; + char *comment; + vorbis_comment vc; + vorbis_info vi; + + vorbis_comment_init(&vc); + vorbis_info_init(&vi); + + /* this is necessary to make libvorbis accept this vorbis_info*/ + vi.rate=1; + + if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { + char *chapter_time = 0; + char *chapter_name = 0; + int chapter_no = 0; + ptr=vc.user_comments; + while(*ptr) { + comment=*ptr; + if ( !strncasecmp ("TITLE=", comment,6) ) { + this->title = strdup (comment + strlen ("TITLE=") ); + _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title); + } + if ( !chapter_time && strlen(comment) == 22 && + !strncasecmp ("CHAPTER" , comment, 7) && + isdigit(*(comment+7)) && isdigit(*(comment+8)) && + (*(comment+9) == '=')) { + + chapter_time = strdup(comment+10); + chapter_no = strtol(comment+7, NULL, 10); + } + if ( !chapter_name && !strncasecmp("CHAPTER", comment, 7) && + isdigit(*(comment+7)) && isdigit(*(comment+8)) && + !strncasecmp ("NAME=", comment+9, 5)) { + + if (strtol(comment+7,NULL,10) == chapter_no) { + chapter_name = strdup(comment+14); + } + } + if (chapter_time && chapter_name && chapter_no){ + int hour, min, sec, msec; + + lprintf("create chapter entry: no=%d name=%s time=%s\n", chapter_no, chapter_name, chapter_time); + hour= strtol(chapter_time, NULL, 10); + min = strtol(chapter_time+3, NULL, 10); + sec = strtol(chapter_time+6, NULL, 10); + msec = strtol(chapter_time+9, NULL, 10); + lprintf("time: %d %d %d %d\n", hour, min,sec,msec); + + if (!this->chapter_info) { + this->chapter_info = (chapter_info_t *)xine_xmalloc(sizeof(chapter_info_t)); + this->chapter_info->current_chapter = -1; + } + this->chapter_info->max_chapter = chapter_no; + this->chapter_info->entries = realloc( this->chapter_info->entries, chapter_no*sizeof(chapter_entry_t)); + this->chapter_info->entries[chapter_no-1].name = chapter_name; + this->chapter_info->entries[chapter_no-1].start_pts = (msec + (1000.0 * sec) + (60000.0 * min) + (3600000.0 * hour))*90; + + free (chapter_time); + chapter_no = 0; + chapter_time = chapter_name = 0; + } + ++ptr; + } + } + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); +#endif +} + +/* + * update the display of the title, if needed + */ +static void update_chapter_display (demux_ogg_t *this, int stream_num, ogg_packet *op) { + int chapter = 0; + int64_t pts = get_pts(this, stream_num, op->granulepos ); + + while (chapter < this->chapter_info->max_chapter && + this->chapter_info->entries[chapter].start_pts < pts) { + chapter++; + } + chapter--; + + if (chapter != this->chapter_info->current_chapter){ + xine_event_t uevent; + xine_ui_data_t data; + int title_len; + char *title; + + this->chapter_info->current_chapter = chapter; + if (chapter >= 0) { + char t_title[256]; + + if (this->title) { + snprintf(t_title, sizeof (t_title), "%s / %s", this->title, this->chapter_info->entries[chapter].name); + } else { + snprintf(t_title, sizeof (t_title), "%s", this->chapter_info->entries[chapter].name); + } + title = t_title; + } else { + title = this->title; + } + _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title); + lprintf("new TITLE: %s\n", title); + + uevent.type = XINE_EVENT_UI_SET_TITLE; + uevent.stream = this->stream; + uevent.data = &data; + uevent.data_length = sizeof(data); + title_len = strlen(title) + 1; + memcpy(data.str, title, title_len); + data.str_len = title_len; + xine_event_send(this->stream, &uevent); + } +} + +/* + * utility function to pack one ogg_packet into a xine + * buffer, fill out all needed fields + * and send it to the right fifo + */ + +static void send_ogg_buf (demux_ogg_t *this, + ogg_packet *op, + int stream_num, + uint32_t decoder_flags) { + + int hdrlen; + int normpos = 0; + + if( this->input->get_length (this->input) ) + normpos = (int)( (double) this->input->get_current_pos (this->input) * + 65535 / this->input->get_length (this->input) ); + + + hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; + hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; + + /* for Annodex files: the first packet after the AnxData info packet needs + * to have its BOS flag set: we set it here */ + if (!this->si[stream_num]->delivered_bos) { + op->b_o_s = 1; + this->si[stream_num]->delivered_bos = 1; + } + + if ( this->audio_fifo + && (this->si[stream_num]->buf_types & 0xFF000000) == BUF_AUDIO_BASE) { + uint8_t *data; + int size; + int64_t pts; + + if (op->packet[0] == PACKET_TYPE_COMMENT ) { + read_language_comment(this, op, stream_num); + } + + if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_SPEEX || + (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_FLAC || + (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_VORBIS) { + data = op->packet; + size = op->bytes; + } else { + data = op->packet+1+hdrlen; + size = op->bytes-1-hdrlen; + } + llprintf(DEBUG_PACKETS, "audio data size %d\n", size); + + if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { + pts = get_pts(this, stream_num, op->granulepos ); + check_newpts( this, pts, PTS_AUDIO, decoder_flags ); + } else + pts = 0; + + llprintf(DEBUG_PACKETS, + "audiostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", + stream_num, + op->granulepos, + this->si[stream_num]->header_granulepos, + pts); + + _x_demux_send_data(this->audio_fifo, data, size, + pts, this->si[stream_num]->buf_types, decoder_flags, + normpos, + pts / 90, this->time_length, 0); + +#ifdef HAVE_THEORA + } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_VIDEO_THEORA) { + + int64_t pts; + theora_info t_info; + theora_comment t_comment; + + theora_info_init (&t_info); + theora_comment_init (&t_comment); + + /*Lets see if this is an Header*/ + if ((theora_decode_header(&t_info, &t_comment, op))>=0) { + decoder_flags=decoder_flags|BUF_FLAG_HEADER; + lprintf ("found an header\n"); + } + + if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { + pts = get_pts(this, stream_num, op->granulepos ); + check_newpts( this, pts, PTS_VIDEO, decoder_flags ); + } else + pts = 0; + + llprintf(DEBUG_PACKETS, + "theorastream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", + stream_num, + op->granulepos, + this->si[stream_num]->header_granulepos, + pts); + + send_ogg_packet (this, this->video_fifo, op, pts, decoder_flags, stream_num); + + theora_comment_clear (&t_comment); + theora_info_clear (&t_info); +#endif + + } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { + + uint8_t *data; + int size; + int64_t pts; + + llprintf(DEBUG_VIDEO_PACKETS, + "video buffer, type=%08x\n", this->si[stream_num]->buf_types); + + if (op->packet[0] == PACKET_TYPE_COMMENT ) { + read_chapter_comment(this, op); + }else{ + data = op->packet+1+hdrlen; + size = op->bytes-1-hdrlen; + + if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { + pts = get_pts(this, stream_num, op->granulepos ); + check_newpts( this, pts, PTS_VIDEO, decoder_flags ); + } else + pts = 0; + + llprintf(DEBUG_VIDEO_PACKETS, + "videostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", + stream_num, + op->granulepos, + this->si[stream_num]->header_granulepos, + pts); + + _x_demux_send_data(this->video_fifo, data, size, + pts, this->si[stream_num]->buf_types, decoder_flags, + normpos, + pts / 90, this->time_length, 0); + + if (this->chapter_info && op->granulepos != -1) { + update_chapter_display(this, stream_num, op); + } + } + } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { + buf_element_t *buf; + uint32_t *val; + char *str; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + buf->type = this->si[stream_num]->buf_types; + + buf->pts = get_pts (this, stream_num, op->granulepos); + + val = (uint32_t * )buf->content; + str = (char *)val; + + memcpy(str, op->packet, op->bytes); + str[op->bytes] = '\0'; + + buf->size = 12 + op->bytes + 1; + + lprintf ("CMML stream %d (bytes=%ld): PTS %"PRId64": %s\n", + stream_num, op->bytes, buf->pts, str); + + this->video_fifo->put (this->video_fifo, buf); + } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { + + buf_element_t *buf; + int i; + char *subtitle,*str; + int lenbytes; + int start,end; + uint32_t *val; + + for (i = 0, lenbytes = 0; i < hdrlen; i++) { + lenbytes = lenbytes << 8; + lenbytes += *((unsigned char *) op->packet + hdrlen - i); + } + + if (op->packet[0] == PACKET_TYPE_HEADER ) { + lprintf ("Textstream-header-packet\n"); + } else if (op->packet[0] == PACKET_TYPE_COMMENT ) { + lprintf ("Textstream-comment-packet\n"); + read_language_comment(this, op, stream_num); + } else { + subtitle = (char *)&op->packet[hdrlen + 1]; + + if ((strlen(subtitle) > 1) || (*subtitle != ' ')) { + start = op->granulepos; + end = start+lenbytes; + lprintf ("subtitlestream %d: %d -> %d :%s\n",stream_num,start,end,subtitle); + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + + buf->type = this->si[stream_num]->buf_types; + buf->pts = 0; + + val = (uint32_t * )buf->content; + *val++ = start; + *val++ = end; + str = (char *)val; + + memcpy (str, subtitle, 1+strlen(subtitle)); + + this->video_fifo->put (this->video_fifo, buf); + } + } + } else { + lprintf("unknown stream type %x\n", this->si[stream_num]->buf_types); + } +} + +static void decode_vorbis_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +#ifdef HAVE_VORBIS + vorbis_info vi; + vorbis_comment vc; + + this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS + +this->num_audio_streams++; + + this->si[stream_num]->headers = 3; + + vorbis_info_init(&vi); + vorbis_comment_init(&vc); + if (vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, vi.bitrate_nominal); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, vi.rate); + + this->si[stream_num]->factor = 90000; + this->si[stream_num]->quotient = vi.rate; + + if (vi.bitrate_nominal<1) + this->avg_bitrate += 100000; /* assume 100 kbit */ + else + this->avg_bitrate += vi.bitrate_nominal; + + } else { + this->si[stream_num]->factor = 900; + this->si[stream_num]->quotient = 441; + + this->si[stream_num]->headers = 0; + xine_log (this->stream->xine, XINE_LOG_MSG, + _("ogg: vorbis audio track indicated but no vorbis stream header found.\n")); + } + vorbis_comment_clear(&vc); + vorbis_info_clear(&vi); +#endif +} + +static void decode_speex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { +#ifdef HAVE_SPEEX + void *st; + SpeexMode *mode; + SpeexHeader *header; + + this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX + +this->num_audio_streams++; + + this->si[stream_num]->headers = 1; + + header = speex_packet_to_header (op->packet, op->bytes); + + if (header) { + int bitrate; + mode = (SpeexMode *) speex_mode_list[header->mode]; + + st = speex_decoder_init (mode); + + speex_decoder_ctl (st, SPEEX_GET_BITRATE, &bitrate); + + if (bitrate <= 1) + bitrate = 16000; /* assume 16 kbit */ + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); + + this->si[stream_num]->factor = 90000; + this->si[stream_num]->quotient = header->rate; + + this->avg_bitrate += bitrate; + + lprintf ("detected Speex stream,\trate %d\tbitrate %d\n", header->rate, bitrate); + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, header->rate); + this->si[stream_num]->headers += header->extra_headers; + } +#else + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Speex stream detected, unable to play\n"); + + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif +} + +static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + buf_element_t *buf; + xine_bmiheader bih; + int channel; + + int16_t locbits_per_sample; + uint32_t locsubtype; + int32_t locsize, locdefault_len, locbuffersize, locwidth, locheight; + int64_t loctime_unit, locsamples_per_unit; + + /* read fourcc with machine endianness */ + locsubtype = *((uint32_t *)&op->packet[9]); + + /* everything else little endian */ + locsize = LE_32(&op->packet[13]); + loctime_unit = LE_64(&op->packet[17]); + locsamples_per_unit = LE_64(&op->packet[25]); + locdefault_len = LE_32(&op->packet[33]); + locbuffersize = LE_32(&op->packet[37]); + locbits_per_sample = LE_16(&op->packet[41]); + locwidth = LE_32(&op->packet[45]); + locheight = LE_32(&op->packet[49]); + + lprintf ("direct show filter created stream detected, hexdump:\n"); +#ifdef LOG + xine_hexdump (op->packet, op->bytes); +#endif + + channel = this->num_video_streams++; + + this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (locsubtype); + if( !this->si[stream_num]->buf_types ) + this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; + this->si[stream_num]->buf_types |= channel; + this->si[stream_num]->headers = 0; /* header is sent below */ + + lprintf ("subtype %.4s\n", (char*)&locsubtype); + lprintf ("time_unit %" PRId64 "\n", loctime_unit); + lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); + lprintf ("default_len %d\n", locdefault_len); + lprintf ("buffersize %d\n", locbuffersize); + lprintf ("bits_per_sample %d\n", locbits_per_sample); + lprintf ("width %d\n", locwidth); + lprintf ("height %d\n", locheight); + lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types); + + bih.biSize=sizeof(xine_bmiheader); + bih.biWidth = locwidth; + bih.biHeight= locheight; + bih.biPlanes= 0; + memcpy(&bih.biCompression, &locsubtype, 4); + bih.biBitCount= 0; + bih.biSizeImage=locwidth*locheight; + bih.biXPelsPerMeter=1; + bih.biYPelsPerMeter=1; + bih.biClrUsed=0; + bih.biClrImportant=0; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| + BUF_FLAG_FRAME_END; + this->frame_duration = loctime_unit * 9 / 1000; + this->si[stream_num]->factor = loctime_unit * 9; + this->si[stream_num]->quotient = 1000; + buf->decoder_info[0] = this->frame_duration; + memcpy (buf->content, &bih, sizeof (xine_bmiheader)); + buf->size = sizeof (xine_bmiheader); + buf->type = this->si[stream_num]->buf_types; + + /* video metadata */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, locsubtype); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, locwidth); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, locheight); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + + this->avg_bitrate += 500000; /* FIXME */ + + this->video_fifo->put (this->video_fifo, buf); +} + +static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + + if (this->audio_fifo) { + buf_element_t *buf; + int codec; + char str[5]; + int channel; + + int16_t locbits_per_sample, locchannels, locblockalign; + int32_t locsize, locdefault_len, locbuffersize, locavgbytespersec; + int64_t loctime_unit, locsamples_per_unit; + + locsize = LE_32(&op->packet[13]); + loctime_unit = LE_64(&op->packet[17]); + locsamples_per_unit = LE_64(&op->packet[25]); + locdefault_len = LE_32(&op->packet[33]); + locbuffersize = LE_32(&op->packet[37]); + locbits_per_sample = LE_16(&op->packet[41]); + locchannels = LE_16(&op->packet[45]); + locblockalign = LE_16(&op->packet[47]); + locavgbytespersec= LE_32(&op->packet[49]); + + lprintf ("direct show filter created audio stream detected, hexdump:\n"); +#ifdef LOG + xine_hexdump (op->packet, op->bytes); +#endif + + memcpy(str, &op->packet[9], 4); + str[4] = 0; + codec = strtoul(str, NULL, 16); + + channel= this->num_audio_streams++; + + this->si[stream_num]->buf_types = _x_formattag_to_buf_audio(codec); + if( this->si[stream_num]->buf_types ) { + this->si[stream_num]->buf_types |= channel; + } else { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ogg: unknown audio codec type 0x%x\n", codec); + this->si[stream_num]->buf_types = BUF_AUDIO_UNKNOWN; + /*break;*/ + } + + lprintf ("subtype 0x%x\n", codec); + lprintf ("time_unit %" PRId64 "\n", loctime_unit); + lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); + lprintf ("default_len %d\n", locdefault_len); + lprintf ("buffersize %d\n", locbuffersize); + lprintf ("bits_per_sample %d\n", locbits_per_sample); + lprintf ("channels %d\n", locchannels); + lprintf ("blockalign %d\n", locblockalign); + lprintf ("avgbytespersec %d\n", locavgbytespersec); + lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types); + + buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); + buf->type = this->si[stream_num]->buf_types; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + buf->decoder_info[0] = 0; + buf->decoder_info[1] = locsamples_per_unit; + buf->decoder_info[2] = locbits_per_sample; + buf->decoder_info[3] = locchannels; + this->audio_fifo->put (this->audio_fifo, buf); + + this->si[stream_num]->headers = 0; /* header already sent */ + this->si[stream_num]->factor = 90000; + this->si[stream_num]->quotient = locsamples_per_unit; + + this->avg_bitrate += locavgbytespersec*8; + + /* audio metadata */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, codec); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, locchannels); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, locbits_per_sample); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, locsamples_per_unit); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, locavgbytespersec * 8); + + } else /* no audio_fifo there */ + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +} + +static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + + lprintf ("older Direct Show filter-generated stream header detected. Hexdump:\n"); +#ifdef LOG + xine_hexdump (op->packet, op->bytes); +#endif + + this->si[stream_num]->headers = 0; /* header is sent below */ + + if ( (LE_32(&op->packet[96]) == 0x05589f80) && (op->bytes >= 184)) { + + buf_element_t *buf; + xine_bmiheader bih; + int channel; + uint32_t fcc; + + lprintf ("seems to be a video stream.\n"); + + channel = this->num_video_streams++; + fcc = *(uint32_t*)(op->packet+68); + lprintf ("fourcc %08x\n", fcc); + + this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (fcc); + if( !this->si[stream_num]->buf_types ) + this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; + this->si[stream_num]->buf_types |= channel; + + bih.biSize = sizeof(xine_bmiheader); + bih.biWidth = LE_32(&op->packet[176]); + bih.biHeight = LE_32(&op->packet[180]); + bih.biPlanes = 0; + memcpy (&bih.biCompression, op->packet+68, 4); + bih.biBitCount = LE_16(&op->packet[182]); + if (!bih.biBitCount) + bih.biBitCount = 24; /* FIXME ? */ + bih.biSizeImage = (bih.biBitCount>>3)*bih.biWidth*bih.biHeight; + bih.biXPelsPerMeter = 1; + bih.biYPelsPerMeter = 1; + bih.biClrUsed = 0; + bih.biClrImportant = 0; + + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| + BUF_FLAG_FRAME_END; + this->frame_duration = (*(int64_t*)(op->packet+164)) * 9 / 1000; + this->si[stream_num]->factor = (*(int64_t*)(op->packet+164)) * 9; + this->si[stream_num]->quotient = 1000; + + buf->decoder_info[0] = this->frame_duration; + memcpy (buf->content, &bih, sizeof (xine_bmiheader)); + buf->size = sizeof (xine_bmiheader); + buf->type = this->si[stream_num]->buf_types; + this->video_fifo->put (this->video_fifo, buf); + + lprintf ("subtype %.4s\n", (char*)&fcc); + lprintf ("buf_type %08x\n", this->si[stream_num]->buf_types); + lprintf ("video size %d x %d\n", bih.biWidth, bih.biHeight); + lprintf ("frame duration %d\n", this->frame_duration); + + /* video metadata */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, bih.biWidth); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, bih.biHeight); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + + this->avg_bitrate += 500000; /* FIXME */ + + this->ignore_keyframes = 1; + + } else if (LE_32(&op->packet[96]) == 0x05589F81) { + +#if 0 + /* FIXME: no test streams */ + + buf_element_t *buf; + int codec; + char str[5]; + int channel; + int extra_size; + + extra_size = *(int16_t*)(op->packet+140); + format = *(int16_t*)(op->packet+124); + channels = *(int16_t*)(op->packet+126); + samplerate = *(int32_t*)(op->packet+128); + nAvgBytesPerSec = *(int32_t*)(op->packet+132); + nBlockAlign = *(int16_t*)(op->packet+136); + wBitsPerSample = *(int16_t*)(op->packet+138); + samplesize = (sh_a->wf->wBitsPerSample+7)/8; + cbSize = extra_size; + if(extra_size > 0) + memcpy(wf+sizeof(WAVEFORMATEX),op->packet+142,extra_size); +#endif + + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "FIXME, old audio format not handled\n"); + + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + + } else { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "old header detected but stream type is unknown\n"); + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + } +} + +static void decode_text_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + int channel=0; + uint32_t *val; + buf_element_t *buf; + + lprintf ("textstream detected.\n"); + this->si[stream_num]->headers = 2; + channel = this->num_spu_streams++; + this->si[stream_num]->buf_types = BUF_SPU_OGM | channel; + + /*send an empty spu to inform the video_decoder, that there is a stream*/ + buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); + buf->type = this->si[stream_num]->buf_types; + buf->pts = 0; + val = (uint32_t * )buf->content; + *val++=0; + *val++=0; + *val++=0; + this->video_fifo->put (this->video_fifo, buf); +} + +static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + +#ifdef HAVE_THEORA + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ogg: Theorastreamsupport is highly alpha at the moment\n"); + + if (theora_decode_header(&this->t_info, &this->t_comment, op) >= 0) { + + this->num_video_streams++; + + this->si[stream_num]->factor = (int64_t) 90000 * (int64_t) this->t_info.fps_denominator; + + if (!this->t_info.fps_numerator) { + this->t_info.fps_numerator = 1; /* FIXME: default value ? */ + } + this->si[stream_num]->quotient = this->t_info.fps_numerator; + + this->frame_duration = ((int64_t) 90000*this->t_info.fps_denominator); + this->frame_duration /= this->t_info.fps_numerator; + + this->si[stream_num]->granuleshift = intlog(this->t_info.keyframe_frequency_force-1); + + this->si[stream_num]->headers=3; + this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; + + _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->t_info.frame_width); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->t_info.frame_height); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); + + /*currently aspect_nominator and -denumerator are 0?*/ + if (this->t_info.aspect_denominator) { + int64_t ratio = ((int64_t) this->t_info.aspect_numerator * 10000); + + ratio /= this->t_info.aspect_denominator; + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, ratio); + } + + lprintf ("decoded theora header \n"); + lprintf ("frameduration %d\n",this->frame_duration); + lprintf ("w:%d h:%d \n",this->t_info.frame_width,this->t_info.frame_height); + lprintf ("an:%d ad:%d \n",this->t_info.aspect_numerator,this->t_info.aspect_denominator); + } else { + /*Rejected stream*/ + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, + "A theora header was rejected by libtheora\n"); + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + this->si[stream_num]->headers = 0; /* FIXME: don't know */ + } +#else + this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; + this->num_video_streams++; + this->unhandled_video_streams++; + _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); +#endif +} + +static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + xine_flac_metadata_header header; + xine_flac_streaminfo_block streaminfo; + buf_element_t *buf; + xine_waveformatex wave; + + /* Packet type */ + _x_assert(op->packet[0] == 0x7F); + + /* OggFLAC signature */ + _x_assert(op->packet[1] == 'F'); _x_assert(op->packet[2] == 'L'); + _x_assert(op->packet[3] == 'A'); _x_assert(op->packet[4] == 'C'); + + /* Version: supported only 1.0 */ + _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0); + + /* Header count */ + this->si[stream_num]->headers = 0/*BE_16(&op->packet[7]) +1*/; + + /* fLaC signature */ + _x_assert(op->packet[9] == 'f'); _x_assert(op->packet[10] == 'L'); + _x_assert(op->packet[11] == 'a'); _x_assert(op->packet[12] == 'C'); + + _x_parse_flac_metadata_header(&op->packet[13], &header); + + switch ( header.blocktype ) { + case FLAC_BLOCKTYPE_STREAMINFO: + _x_assert(header.length == FLAC_STREAMINFO_SIZE); + _x_parse_flac_streaminfo_block(&op->packet[17], &streaminfo); + break; + } + + this->si[stream_num]->buf_types = BUF_AUDIO_FLAC + +this->num_audio_streams++; + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, streaminfo.samplerate); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, streaminfo.channels); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, streaminfo.bits_per_sample); + + this->si[stream_num]->factor = 90000; + + buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); + + buf->type = BUF_AUDIO_FLAC; + buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; + + buf->decoder_info[0] = 0; + buf->decoder_info[1] = streaminfo.samplerate; + buf->decoder_info[2] = streaminfo.bits_per_sample; + buf->decoder_info[3] = streaminfo.channels; + buf->size = sizeof(xine_waveformatex) + FLAC_STREAMINFO_SIZE; + memcpy(buf->content+sizeof(xine_waveformatex), &op->packet[17], FLAC_STREAMINFO_SIZE); + xine_hexdump(&op->packet[17], FLAC_STREAMINFO_SIZE); + wave.cbSize = FLAC_STREAMINFO_SIZE; + memcpy(buf->content, &wave, sizeof(xine_waveformatex)); + + this->audio_fifo->put(this->audio_fifo, buf); + + /* Skip the Ogg framing info */ + op->bytes -= 9; + op->packet += 9; +} + +static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + lprintf ("Annodex stream detected\n"); + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + this->si[stream_num]->headers = 1; + this->si[stream_num]->header_granulepos = op->granulepos; + _x_meta_info_set(this->stream, XINE_META_INFO_SYSTEMLAYER, "Annodex"); +} + +static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + int64_t granule_rate_n, granule_rate_d; + uint32_t secondary_headers; + char content_type[1024]; + int content_type_length; + + lprintf("AnxData stream detected\n"); + + /* read granule rate */ + granule_rate_n = LE_64(&op->packet[8]); + granule_rate_d = LE_64(&op->packet[16]); + secondary_headers = LE_32(&op->packet[24]); + + lprintf("granule_rate %" PRId64 "/%" PRId64 ", %d secondary headers\n", + granule_rate_n, granule_rate_d, secondary_headers); + + /* read "Content-Tyoe" MIME header */ + sscanf(&op->packet[28], "Content-Type: %1023s\r\n", content_type); + content_type_length = strlen(content_type); + + lprintf("Content-Type: %s (length:%d)\n", content_type, content_type_length); + + /* how many header packets in the AnxData stream? */ + this->si[stream_num]->headers = secondary_headers + 1; + this->si[stream_num]->hide_first_header = 1; + + /* set factor and quotient */ + this->si[stream_num]->factor = (int64_t) 90000 * granule_rate_d; + this->si[stream_num]->quotient = granule_rate_n; + + lprintf("factor: %" PRId64 ", quotient: %" PRId64 "\n", + this->si[stream_num]->factor, this->si[stream_num]->quotient); + + /* what type of stream are we dealing with? */ + if (!strncmp(content_type, "audio/x-vorbis", content_type_length)) { +#ifdef HAVE_VORBIS + this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS; +#else + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif + this->num_audio_streams++; + } else if (!strncmp(content_type, "audio/x-speex", content_type_length)) { + this->num_audio_streams++; +#ifdef HAVE_SPEEX + this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX; +#else + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif + } else if (!strncmp(content_type, "video/x-theora", content_type_length)) { + this->num_video_streams++; +#ifdef HAVE_THEORA + this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; +#else + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; +#endif + } else if (!strncmp(content_type, "text/x-cmml", content_type_length)) { + unsigned int channel = this->num_spu_streams++; + this->si[stream_num]->headers = 0; + this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; + this->si[stream_num]->granuleshift = 0; + } else { + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + } + +} + +static void decode_cmml_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { + unsigned int channel = this->num_spu_streams++; + this->si[stream_num]->headers = 0; + this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; + + this->si[stream_num]->factor = 90000 * LE_64(&op->packet[20]); + this->si[stream_num]->quotient = LE_64(&op->packet[12]); + this->si[stream_num]->granuleshift = (int)op->packet[28]; +} + +/* + * interpret stream start packages, send headers + */ +static void send_header (demux_ogg_t *this) { + + int stream_num = -1; + int cur_serno; + int done = 0; + ogg_packet op; + xine_event_t ui_event; + + lprintf ("detecting stream types...\n"); + + this->ignore_keyframes = 0; + + while (!done) { + if (!read_ogg_packet(this)) { + this->status = DEMUX_FINISHED; + return; + } + /* now we've got at least one new page */ + + cur_serno = ogg_page_serialno (&this->og); + + if (ogg_page_bos(&this->og)) { + lprintf ("beginning of stream\n"); + lprintf ("serial number %d\n", cur_serno); + + if( this->num_streams == MAX_STREAMS ) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); + this->status = DEMUX_FINISHED; + return; + } + stream_num = new_stream_info(this, cur_serno); + + } else { + stream_num = get_stream(this, cur_serno); + if (stream_num == -1) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: stream with no beginning!\n"); + this->status = DEMUX_FINISHED; + return; + } + } + + ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); + + while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { + + if (!this->si[stream_num]->buf_types) { + + /* detect buftype */ + if (!strncmp (&op.packet[1], "vorbis", 6)) { + decode_vorbis_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[0], "Speex", 5)) { + decode_speex_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "video", 5)) { + decode_video_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "audio", 5)) { + decode_audio_header(this, stream_num, &op); + } else if (op.bytes >= 142 + && !strncmp (&op.packet[1], "Direct Show Samples embedded in Ogg", 35) ) { + decode_dshow_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "text", 4)) { + decode_text_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "theora", 6)) { + decode_theora_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[1], "FLAC", 4)) { + decode_flac_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[0], "Annodex", 7)) { + decode_annodex_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[0], "AnxData", 7)) { + decode_anxdata_header(this, stream_num, &op); + } else if (!strncmp (&op.packet[0], "CMML", 4)) { + decode_cmml_header(this, stream_num, &op); + } else { + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "demux_ogg: unknown stream type (signature >%.8s<). hex dump of bos packet follows:\n", + op.packet); + if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) + xine_hexdump (op.packet, op.bytes); + + this->si[stream_num]->buf_types = BUF_CONTROL_NOP; + } + } + + /* send preview buffer */ + if (this->si[stream_num]->headers > 0 || + op.packet[0] == PACKET_TYPE_COMMENT) { + if (this->si[stream_num]->hide_first_header) + this->si[stream_num]->hide_first_header = 0; + else { + lprintf ("sending preview buffer of stream type %08x\n", + this->si[stream_num]->buf_types); + + send_ogg_buf (this, &op, stream_num, BUF_FLAG_HEADER); + this->si[stream_num]->headers --; + } + } + + /* are we finished ? */ + if (!ogg_page_bos(&this->og)) { + int i; + done = 1; + + for (i=0; inum_streams; i++) { + if (this->si[i]->headers > 0) + done = 0; + + llprintf(DEBUG_PREVIEWS, + "%d preview buffers left to send from stream %d\n", + this->si[i]->headers, i); + } + } + } + } + + ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED; + ui_event.data_length = 0; + xine_event_send(this->stream, &ui_event); + + /*get the streamlength*/ + get_stream_length (this); + +} + +static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { + demux_ogg_t *this = (demux_ogg_t *) this_gen; + + int stream_num; + int cur_serno; + + ogg_packet op; + + ogg_handle_event(this); + + llprintf(DEBUG_PACKETS, "send package...\n"); + + if (!read_ogg_packet(this)) { + this->status = DEMUX_FINISHED; + lprintf ("EOF\n"); + return this->status; + } + + /* now we've got one new page */ + + cur_serno = ogg_page_serialno (&this->og); + stream_num = get_stream(this, cur_serno); + if (stream_num < 0) { + lprintf ("error: unknown stream, serialnumber %d\n", cur_serno); + + if (!ogg_page_bos(&this->og)) { + lprintf ("help, stream with no beginning!\n"); + } + lprintf ("adding late stream with serial number %d (all content will be discarded)\n", cur_serno); + + if( this->num_streams == MAX_STREAMS ) { + xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); + this->status = DEMUX_FINISHED; + return this->status; + } + stream_num = new_stream_info(this, cur_serno); + } + + ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); + + if (ogg_page_bos(&this->og)) { + lprintf ("beginning of stream: serial number %d - discard\n", + ogg_page_serialno (&this->og)); + while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) ; + return this->status; + } + + /*while keyframeseeking only process videostream*/ + if (!this->ignore_keyframes && this->keyframe_needed + && ((this->si[stream_num]->buf_types & 0xFF000000) != BUF_VIDEO_BASE)) + return this->status; + + while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { + /* printf("demux_ogg: packet: %.8s\n", op.packet); */ + /* printf("demux_ogg: got a packet\n"); */ + + if ((*op.packet & PACKET_TYPE_HEADER) && + (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX) && (this->si[stream_num]->buf_types!=BUF_AUDIO_FLAC)) { + if (op.granulepos != -1) { + this->si[stream_num]->header_granulepos = op.granulepos; + lprintf ("header with granulepos, remembering granulepos\n"); + } else { + lprintf ("header => discard\n"); + } + continue; + } + + /*discard granulepos-less packets and to early audiopackets*/ + if (this->si[stream_num]->resync) { + if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { + /*never drop subtitles*/ + this->si[stream_num]->resync=0; + } else if ((op.granulepos == -1) && (this->si[stream_num]->header_granulepos == -1)) { + continue; + } else { + + /*dump too early packets*/ + if ((get_pts(this,stream_num,op.granulepos)-this->start_pts) > -90000) + this->si[stream_num]->resync=0; + else + continue; + } + } + + if (!this->ignore_keyframes && this->keyframe_needed) { + lprintf ("keyframe needed... buf_type=%08x\n", this->si[stream_num]->buf_types); + if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA) { +#ifdef HAVE_THEORA + + int keyframe_granule_shift; + int64_t pframe=-1,iframe=-1; + + keyframe_granule_shift = this->si[stream_num]->granuleshift; + + if(op.granulepos>=0){ + iframe=op.granulepos>>keyframe_granule_shift; + pframe=op.granulepos-(iframe<stream->xine, XINE_VERBOSITY_DEBUG, + "seeking keyframe i %" PRId64 " p %" PRId64 "\n", iframe, pframe); + if (pframe!=0) + continue; + } else + continue; + this->keyframe_needed = 0; + this->start_pts=get_pts(this,stream_num,op.granulepos); +#endif + } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { + + /*calculate the current pts*/ + if (op.granulepos!=-1) { + this->start_pts=get_pts(this, stream_num, op.granulepos); + } else if (this->start_pts!=-1) + this->start_pts=this->start_pts+this->frame_duration; + + /*seek the keyframe*/ + if ((*op.packet == PACKET_IS_SYNCPOINT) && (this->start_pts!=-1)) + this->keyframe_needed = 0; + else + continue; + + } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) continue; + } + send_ogg_buf (this, &op, stream_num, 0); + + /*delete used header_granulepos*/ + if (op.granulepos == -1) + this->si[stream_num]->header_granulepos = -1; + + } + if (ogg_page_eos(&this->og)) { + int i; + int finished_streams = 0; + + lprintf("end of stream, serialnumber %d\n", cur_serno); + this->si[stream_num]->delivered_eos = 1; + + /* check if all logical streams are finished */ + for (i = 0; i < this->num_streams; i++) { + finished_streams += this->si[i]->delivered_eos; + } + + /* if all streams are finished, perhaps a chained stream follows */ + if (finished_streams == this->num_streams) { + /* delete current logical streams */ + for (i = 0; i < this->num_streams; i++) { + ogg_stream_clear(&this->si[i]->oss); + if (this->si[i]->language) { + free (this->si[i]->language); + } + free (this->si[i]); + } + this->num_streams = 0; + this->num_audio_streams = 0; + this->num_video_streams = 0; + this->unhandled_video_streams = 0; + this->num_spu_streams = 0; + this->avg_bitrate = 1; + + /* try to read a chained stream */ + this->send_newpts = 1; + this->last_pts[0] = 0; + this->last_pts[1] = 0; + + /* send control buffer to avoid buffer leak */ + _x_demux_control_end(this->stream, 0); + _x_demux_control_start(this->stream); + send_header(this); + } + } + + return this->status; +} + +static void demux_ogg_dispose (demux_plugin_t *this_gen) { + demux_ogg_t *this = (demux_ogg_t *) this_gen; + int i; + + for (i=0; inum_streams; i++) { + ogg_stream_clear(&this->si[i]->oss); + + if (this->si[i]->language) { + free (this->si[i]->language); + } + free(this->si[i]); + } + + ogg_sync_clear(&this->oy); + +#ifdef HAVE_THEORA + theora_comment_clear (&this->t_comment); + theora_info_clear (&this->t_info); +#endif + + if (this->chapter_info){ + free (this->chapter_info->entries); + free (this->chapter_info); + } + if (this->title){ + free (this->title); + } + if (this->event_queue) + xine_event_dispose_queue (this->event_queue); + + free (this); +} + +static int demux_ogg_get_status (demux_plugin_t *this_gen) { + demux_ogg_t *this = (demux_ogg_t *) this_gen; + + return this->status; +} + +static void demux_ogg_send_headers (demux_plugin_t *this_gen) { + demux_ogg_t *this = (demux_ogg_t *) this_gen; + + this->video_fifo = this->stream->video_fifo; + this->audio_fifo = this->stream->audio_fifo; + + this->status = DEMUX_OK; + + /* + * send start buffers + */ + + this->last_pts[0] = 0; + this->last_pts[1] = 0; + + /* + * initialize ogg engine + */ + ogg_sync_init(&this->oy); + + this->num_streams = 0; + this->num_audio_streams = 0; + this->num_video_streams = 0; + this->num_spu_streams = 0; + this->avg_bitrate = 1; + + this->input->seek (this->input, 0, SEEK_SET); + + if (this->status == DEMUX_OK) { + _x_demux_control_start(this->stream); + send_header (this); + lprintf ("headers sent, avg bitrate is %" PRId64 "\n", this->avg_bitrate); + } + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, + this->num_video_streams > 0); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, + this->num_video_streams > this->unhandled_video_streams); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, + this->num_audio_streams > 0); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL, + this->num_spu_streams); +} + +static int demux_ogg_seek (demux_plugin_t *this_gen, + off_t start_pos, int start_time, int playing) { + + demux_ogg_t *this = (demux_ogg_t *) this_gen; + int i; + start_time /= 1000; + start_pos = (off_t) ( (double) start_pos / 65535 * + this->input->get_length (this->input) ); + /* + * seek to start position + */ + + if (INPUT_IS_SEEKABLE(this->input)) { + + this->keyframe_needed = (this->num_video_streams>0); + + if ( (!start_pos) && (start_time)) { + if (this->time_length != -1) { + /*do the seek via time*/ + int current_time=-1; + off_t current_pos; + current_pos=this->input->get_current_pos(this->input); + + /*try to find out the current time*/ + if (this->last_pts[PTS_VIDEO]) { + current_time=this->last_pts[PTS_VIDEO]/90000; + } else if (this->last_pts[PTS_AUDIO]) { + current_time=this->last_pts[PTS_AUDIO]/90000; + } + + /*fixme, the file could grow, do something + about this->time_length using get_lenght to verify, that the stream + hasn` changed its length, otherwise no seek to "new" data is possible*/ + + lprintf ("seek to time %d called\n",start_time); + lprintf ("current time is %d\n",current_time); + + if (current_time > start_time) { + /*seek between beginning and current_pos*/ + + /*fixme - sometimes we seek backwards and during + keyframeseeking, we undo the seek*/ + + start_pos = start_time * current_pos + / current_time ; + } else { + /*seek between current_pos and end*/ + start_pos = current_pos + + ((start_time - current_time) * + ( this->input->get_length(this->input) - current_pos ) / + ( (this->time_length / 1000) - current_time) + ); + } + + lprintf ("current_pos is %" PRId64 "\n",current_pos); + lprintf ("new_pos is %" PRId64 "\n",start_pos); + + } else { + /*seek using avg_bitrate*/ + start_pos = start_time * this->avg_bitrate/8; + } + + lprintf ("seeking to %d seconds => %" PRId64 " bytes\n", + start_time, start_pos); + + } + + ogg_sync_reset(&this->oy); + + for (i=0; inum_streams; i++) { + this->si[i]->header_granulepos = -1; + ogg_stream_reset(&this->si[i]->oss); + } + + /*some strange streams have no syncpoint flag set at the beginning*/ + if (start_pos == 0) + this->keyframe_needed = 0; + + lprintf ("seek to %" PRId64 " called\n",start_pos); + + this->input->seek (this->input, start_pos, SEEK_SET); + + } + + /* fixme - this would be a nice position to do the following tasks + 1. adjust an ogg videostream to a keyframe + 2. compare the keyframe_pts with start_time. if the difference is to + high (e.g. larger than max keyframe_intervall, do a new seek or + continue reading + 3. adjust the audiostreams in such a way, that the + difference is not to high. + + In short words, do all the cleanups necessary to continue playback + without further actions + */ + + this->send_newpts = 1; + this->status = DEMUX_OK; + + if( !playing ) { + + this->buf_flag_seek = 0; + + } else { + if (start_pos!=0) { + this->buf_flag_seek = 1; + /*each stream has to continue with a packet that has an + granulepos*/ + for (i=0; inum_streams; i++) { + this->si[i]->resync = 1; + } + + this->start_pts=-1; + } + + _x_demux_flush_engine(this->stream); + } + + return this->status; +} + +static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) { + + demux_ogg_t *this = (demux_ogg_t *) this_gen; + + if (this->time_length==-1){ + if (this->avg_bitrate) { + return (int)((int64_t)1000 * this->input->get_length (this->input) * 8 / + this->avg_bitrate); + } else { + return 0; + } + } else { + return this->time_length; + } +} + +static uint32_t demux_ogg_get_capabilities(demux_plugin_t *this_gen) { + demux_ogg_t *this = (demux_ogg_t *) this_gen; + int cap_chapter = 0; + + if (this->chapter_info) + cap_chapter = DEMUX_CAP_CHAPTERS; + + return DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG | cap_chapter; +} + +static int format_lang_string (demux_ogg_t * this, uint32_t buf_mask, uint32_t buf_type, int channel, char *str) { + int stream_num; + + for (stream_num=0; stream_numnum_streams; stream_num++) { + if ((this->si[stream_num]->buf_types & buf_mask) == buf_type) { + if (this->si[stream_num]->language) { + if (snprintf (str, XINE_LANG_MAX, "%s", this->si[stream_num]->language) >= XINE_LANG_MAX) + /* the string got truncated */ + str[XINE_LANG_MAX - 2] = str[XINE_LANG_MAX - 3] = str[XINE_LANG_MAX - 4] = '.'; + /* TODO: provide long version in XINE_META_INFO_FULL_LANG */ + } else { + snprintf(str, XINE_LANG_MAX, "channel %d",channel); + } + return DEMUX_OPTIONAL_SUCCESS; + } + } + return DEMUX_OPTIONAL_UNSUPPORTED; +} + +static int demux_ogg_get_optional_data(demux_plugin_t *this_gen, + void *data, int data_type) { + + demux_ogg_t *this = (demux_ogg_t *) this_gen; + + char *str=(char *) data; + int channel = *((int *)data); + + switch (data_type) { + case DEMUX_OPTIONAL_DATA_SPULANG: + lprintf ("DEMUX_OPTIONAL_DATA_SPULANG channel = %d\n",channel); + if (channel==-1) { + strcpy( str, "none"); + return DEMUX_OPTIONAL_SUCCESS; + } else if ((channel>=0) && (channelnum_streams)) { + return format_lang_string (this, 0xFFFFFFFF, BUF_SPU_OGM+channel, channel, str); + } + return DEMUX_OPTIONAL_UNSUPPORTED; + case DEMUX_OPTIONAL_DATA_AUDIOLANG: + lprintf ("DEMUX_OPTIONAL_DATA_AUDIOLANG channel = %d\n",channel); + if (channel==-1) { + return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE, channel, str); + } else if ((channel>=0) && (channelnum_streams)) { + return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE+channel, channel, str); + } + return DEMUX_OPTIONAL_UNSUPPORTED; + default: + return DEMUX_OPTIONAL_UNSUPPORTED; + } +} + +static int detect_ogg_content (int detection_method, demux_class_t *class_gen, + input_plugin_t *input) { + + switch (detection_method) { + + case METHOD_BY_CONTENT: { + uint8_t buf[4]; + + if (_x_demux_read_header(input, buf, 4) != 4) + return 0; + + if ((buf[0] == 'O') && (buf[1] == 'g') && (buf[2] == 'g') && + (buf[3] == 'S')) + return 1; + else + return 0; + } + + case METHOD_BY_EXTENSION: { + const char *extensions, *mrl; + + mrl = input->get_mrl (input); + extensions = class_gen->get_extensions (class_gen); + + if (_x_demux_check_extension (mrl, extensions)) + return 1; + else + return 0; + } + + case METHOD_EXPLICIT: + return 1; + + default: + return 0; + } +} + +static int detect_anx_content (int detection_method, demux_class_t *class_gen, + input_plugin_t *input) { + + if (detect_ogg_content(detection_method, class_gen, input) == 0) + return 0; + + switch (detection_method) { + +#define ANNODEX_SIGNATURE_SEARCH 128 + + case METHOD_BY_CONTENT: { + uint8_t buf[ANNODEX_SIGNATURE_SEARCH]; + int found_annodex_signature = 0; + const char *annodex_signature = "Annodex"; + int annodex_signature_length = 7; /* = strlen(annodex_signature) */ + int i, j; + + if (_x_demux_read_header(input, buf, ANNODEX_SIGNATURE_SEARCH) != + ANNODEX_SIGNATURE_SEARCH) + return 0; + + /* scan for 'Annodex' signature in the first 64 bytes */ + for (i = 0, j = 0; i < ANNODEX_SIGNATURE_SEARCH; i++) { + if (buf[i] == annodex_signature[j]) { + if (j >= annodex_signature_length) { + /* found signature */ + found_annodex_signature = 1; + break; + } else { + j++; + } + } + } + + if (found_annodex_signature) + return 1; + else + return 0; + } + +#undef ANNODEX_SIGNATURE_SEARCH + + case METHOD_BY_EXTENSION: { + const char *extensions, *mrl; + + mrl = input->get_mrl (input); + extensions = class_gen->get_extensions (class_gen); + + if (_x_demux_check_extension (mrl, extensions)) + return 1; + else + return 0; + } + + case METHOD_EXPLICIT: + return 1; + + default: + return 0; + } +} + +static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, + xine_stream_t *stream, + input_plugin_t *input) { + + demux_ogg_t *this; + + if (detect_anx_content(stream->content_detection_method, class_gen, input) == 0) + return NULL; + + /* + * if we reach this point, the input has been accepted. + */ + + this = xine_xmalloc (sizeof (demux_ogg_t)); + memset (this, 0, sizeof(demux_ogg_t)); + this->stream = stream; + this->input = input; + + /* the Annodex demuxer currently calls into exactly the same functions as + * the Ogg demuxer, which seems to make this function a bit redundant, but + * this design leaves us a bit more room to change an Annodex demuxer's + * behaviour in the future if necessary */ + this->demux_plugin.send_headers = demux_ogg_send_headers; + this->demux_plugin.send_chunk = demux_ogg_send_chunk; + this->demux_plugin.seek = demux_ogg_seek; + this->demux_plugin.dispose = demux_ogg_dispose; + this->demux_plugin.get_status = demux_ogg_get_status; + this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; + this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; + this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; + this->demux_plugin.demux_class = class_gen; + + this->status = DEMUX_FINISHED; + +#ifdef HAVE_THEORA + theora_info_init (&this->t_info); + theora_comment_init (&this->t_comment); +#endif + + this->chapter_info = 0; + this->title = 0; + this->event_queue = xine_event_new_queue (this->stream); + + return &this->demux_plugin; +} + +static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, + xine_stream_t *stream, + input_plugin_t *input) { + + demux_ogg_t *this; + + if (detect_ogg_content(stream->content_detection_method, class_gen, input) == 0) + return NULL; + + /* + * if we reach this point, the input has been accepted. + */ + + this = xine_xmalloc (sizeof (demux_ogg_t)); + memset (this, 0, sizeof(demux_ogg_t)); + this->stream = stream; + this->input = input; + + this->demux_plugin.send_headers = demux_ogg_send_headers; + this->demux_plugin.send_chunk = demux_ogg_send_chunk; + this->demux_plugin.seek = demux_ogg_seek; + this->demux_plugin.dispose = demux_ogg_dispose; + this->demux_plugin.get_status = demux_ogg_get_status; + this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; + this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; + this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; + this->demux_plugin.demux_class = class_gen; + + this->status = DEMUX_FINISHED; + +#ifdef HAVE_THEORA + theora_info_init (&this->t_info); + theora_comment_init (&this->t_comment); +#endif + + this->chapter_info = 0; + this->title = 0; + this->event_queue = xine_event_new_queue (this->stream); + + return &this->demux_plugin; +} + +/* + * Annodex demuxer class + */ + +static const char *anx_get_description (demux_class_t *this_gen) { + return "Annodex demux plugin"; +} + +static const char *anx_get_identifier (demux_class_t *this_gen) { + return "Annodex"; +} + +static const char *anx_get_extensions (demux_class_t *this_gen) { + return "anx axa axv"; +} + +static const char *anx_get_mimetypes (demux_class_t *this_gen) { + return "application/x-annodex: ogg: Annodex media;"; +} + +static void anx_class_dispose (demux_class_t *this_gen) { + demux_anx_class_t *this = (demux_anx_class_t *) this_gen; + + free (this); +} + +static void *anx_init_class (xine_t *xine, void *data) { + demux_anx_class_t *this; + + this = xine_xmalloc (sizeof (demux_anx_class_t)); + + this->demux_class.open_plugin = anx_open_plugin; + this->demux_class.get_description = anx_get_description; + this->demux_class.get_identifier = anx_get_identifier; + this->demux_class.get_mimetypes = anx_get_mimetypes; + this->demux_class.get_extensions = anx_get_extensions; + this->demux_class.dispose = anx_class_dispose; + + return this; +} + +/* + * ogg demuxer class + */ + +static const char *ogg_get_description (demux_class_t *this_gen) { + return "OGG demux plugin"; +} + +static const char *ogg_get_identifier (demux_class_t *this_gen) { + return "OGG"; +} + +static const char *ogg_get_extensions (demux_class_t *this_gen) { + return "ogg ogm spx"; +} + +static const char *ogg_get_mimetypes (demux_class_t *this_gen) { + return "audio/x-ogg: ogg: OggVorbis Audio;" + "audio/x-speex: ogg: Speex Audio;" + "application/x-ogg: ogg: Ogg Stream;" + "application/ogg: ogg: Ogg Stream;"; +} + +static void ogg_class_dispose (demux_class_t *this_gen) { + demux_ogg_class_t *this = (demux_ogg_class_t *) this_gen; + + free (this); +} + +static void *ogg_init_class (xine_t *xine, void *data) { + demux_ogg_class_t *this; + + this = xine_xmalloc (sizeof (demux_ogg_class_t)); + + this->demux_class.open_plugin = ogg_open_plugin; + this->demux_class.get_description = ogg_get_description; + this->demux_class.get_identifier = ogg_get_identifier; + this->demux_class.get_mimetypes = ogg_get_mimetypes; + this->demux_class.get_extensions = ogg_get_extensions; + this->demux_class.dispose = ogg_class_dispose; + + return this; +} + +/* + * exported plugin catalog entry + */ +static const demuxer_info_t demux_info_anx = { + 20 /* priority */ +}; + +static const demuxer_info_t demux_info_ogg = { + 10 /* priority */ +}; + +extern const demuxer_info_t dec_info_vorbis; +void *vorbis_init_plugin (xine_t *xine, void *data); +extern const demuxer_info_t dec_info_speex; +void *speex_init_plugin (xine_t *xine, void *data); +extern const demuxer_info_t dec_info_theora; +void *theora_init_plugin (xine_t *xine, void *data); + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_DEMUX, 26, "ogg", XINE_VERSION_CODE, &demux_info_ogg, ogg_init_class }, + { PLUGIN_DEMUX, 26, "anx", XINE_VERSION_CODE, &demux_info_anx, anx_init_class }, +#ifdef HAVE_VORBIS + { PLUGIN_AUDIO_DECODER, 15, "vorbis", XINE_VERSION_CODE, &dec_info_vorbis, vorbis_init_plugin }, +#endif +#ifdef HAVE_SPEEX + { PLUGIN_AUDIO_DECODER, 15, "speex", XINE_VERSION_CODE, &dec_info_speex, speex_init_plugin }, +#endif +#ifdef HAVE_THEORA + { PLUGIN_VIDEO_DECODER, 18, "theora", XINE_VERSION_CODE, &dec_info_theora, theora_init_plugin }, +#endif + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; diff --git a/src/combined/xine_speex_decoder.c b/src/combined/xine_speex_decoder.c new file mode 100644 index 000000000..a17de15d6 --- /dev/null +++ b/src/combined/xine_speex_decoder.c @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: xine_decoder.c,v 1.22 2007/01/19 01:48:05 dgp85 Exp $ + * + * (ogg/)speex audio decoder plugin (libspeex wrapper) for xine + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define LOG_MODULE "speex_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ +#define LOG_BUFFERS 0 + +#include "xine_internal.h" +#include "audio_out.h" +#include "buffer.h" + +#include + +#include +#include +#include +#include + +#define MAX_FRAME_SIZE 2000 + +typedef struct { + audio_decoder_class_t decoder_class; +} speex_class_t; + +typedef struct speex_decoder_s { + audio_decoder_t audio_decoder; + + int64_t pts; + + int output_sampling_rate; + int output_open; + int output_mode; + + /* speex stuff */ + void *st; + int frame_size; + int rate; + int nframes; + int channels; + SpeexBits bits; + SpeexStereoState stereo; + int expect_metadata; + + int header_count; + + xine_stream_t *stream; + +} speex_decoder_t; + + +static void speex_reset (audio_decoder_t *this_gen) { + + speex_decoder_t *this = (speex_decoder_t *) this_gen; + + speex_bits_init (&this->bits); +} + +static void speex_discontinuity (audio_decoder_t *this_gen) { + + speex_decoder_t *this = (speex_decoder_t *) this_gen; + + this->pts=0; +} + +/* Known speex comment keys from ogg123 sources*/ +static struct { + char *key; /* includes the '=' for programming convenience */ + int xine_metainfo_index; +} speex_comment_keys[] = { + {"ARTIST=", XINE_META_INFO_ARTIST}, + {"ALBUM=", XINE_META_INFO_ALBUM}, + {"TITLE=", XINE_META_INFO_TITLE}, + {"GENRE=", XINE_META_INFO_GENRE}, + {"DESCRIPTION=", XINE_META_INFO_COMMENT}, + {"DATE=", XINE_META_INFO_YEAR}, + {NULL, 0} +}; + +#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ + ((buf[base+2]<<16)&0xff0000)| \ + ((buf[base+1]<<8)&0xff00)| \ + (buf[base]&0xff)) + +static +void read_metadata (speex_decoder_t *this, char * comments, int length) +{ + char * c = comments; + int len, i, nb_fields; + char * end; + + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "speex"); + + if (length < 8) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); + return; + } + + end = c+length; + len = readint (c, 0); + c += 4; + + if (c+len > end) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); + return; + } + +#ifdef LOG + /* Encoder */ + printf ("libspeex: "); + fwrite (c, 1, len, stdout); + printf ("\n"); +#endif + + c += len; + + if (c+4 > end) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); + return; + } + + nb_fields = readint (c, 0); + c += 4; + + for (i = 0; i < nb_fields; i++) { + if (c+4 > end) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); + return; + } + + len = readint (c, 0); + c += 4; + if (c+len > end) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); + return; + } + +#ifdef LOG + printf ("libspeex: "); + fwrite (c, 1, len, stdout); + printf ("\n"); +#endif + + for (i = 0; speex_comment_keys[i].key != NULL; i++) { + + if ( !strncasecmp (speex_comment_keys[i].key, c, + strlen(speex_comment_keys[i].key)) ) { + int keylen = strlen(speex_comment_keys[i].key); + char meta_info[(len - keylen) + 1]; + + lprintf ("known metadata %d %d\n", + i, speex_comment_keys[i].xine_metainfo_index); + + snprintf(meta_info, (len - keylen), "%s", c + keylen); + _x_meta_info_set_utf8(this->stream, speex_comment_keys[i].xine_metainfo_index, meta_info); + } + } + + c += len; + } +} + +static void speex_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + + speex_decoder_t *this = (speex_decoder_t *) this_gen; + + llprintf (LOG_BUFFERS, "decode buf=%8p content=%8p flags=%08x\n", + buf, buf->content, buf->decoder_flags); + + if ( (buf->decoder_flags & BUF_FLAG_HEADER) && + !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { + lprintf ("preview buffer, %d headers to go\n", this->header_count); + + if (this->header_count) { + + if (!this->st) { + SpeexMode * spx_mode; + SpeexHeader * spx_header; + int modeID; + int bitrate; + + speex_bits_init (&this->bits); + + spx_header = speex_packet_to_header (buf->content, buf->size); + + if (!spx_header) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: could not read Speex header\n"); + return; + } + + modeID = spx_header->mode; + spx_mode = (SpeexMode *) speex_mode_list[modeID]; + + if (spx_mode->bitstream_version != spx_header->mode_bitstream_version) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: incompatible Speex mode bitstream version\n"); + return; + } + + this->st = speex_decoder_init (spx_mode); + if (!this->st) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: decoder initialization failed\n"); + return; + } + + this->rate = spx_header->rate; + speex_decoder_ctl (this->st, SPEEX_SET_SAMPLING_RATE, &this->rate); + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, + this->rate); + + this->channels = spx_header->nb_channels; + if (this->channels == 2) { + SpeexCallback callback; + + callback.callback_id = SPEEX_INBAND_STEREO; + callback.func = speex_std_stereo_request_handler; + callback.data = &this->stereo; + speex_decoder_ctl (this->st, SPEEX_SET_HANDLER, &callback); + } + + this->nframes = spx_header->frames_per_packet; + if (!this->nframes) this->nframes = 1; + + speex_decoder_ctl (this->st, SPEEX_GET_FRAME_SIZE, &this->frame_size); + + speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); + if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); + + this->header_count += spx_header->extra_headers; + this->expect_metadata = 1; + + free (spx_header); + } else if (this->expect_metadata) { + read_metadata (this, buf->content, buf->size); + } + + this->header_count--; + + if (!this->header_count) { + int mode = _x_ao_channels2mode(this->channels); + + if (!this->output_open) { + this->output_open = + this->stream->audio_out->open(this->stream->audio_out, + this->stream, + 16, + this->rate, + mode); + lprintf ("this->output_open after attempt is %d\n", this->output_open); + } + } + } + + } else if (this->output_open) { + int i, j; + + audio_buffer_t *audio_buffer; + + audio_buffer = + this->stream->audio_out->get_buffer (this->stream->audio_out); + + speex_bits_read_from (&this->bits, buf->content, buf->size); + + for (j = 0; j < this->nframes; j++) { + int ret; + int bitrate; + + ret = speex_decode_int (this->st, &this->bits, audio_buffer->mem); + + if (ret==-1) + break; + if (ret==-2) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding error, corrupted stream?\n"); + break; + } + if (speex_bits_remaining(&this->bits)<0) { + xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding overflow, corrupted stream?\n"); + break; + } + + if (this->channels == 2) { + speex_decode_stereo_int (audio_buffer->mem, this->frame_size, &this->stereo); + } + + speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); + if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); + + audio_buffer->vpts = this->pts; + this->pts=0; + audio_buffer->num_frames = this->frame_size; + + this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + + buf->pts=0; + + } + } + else { + llprintf (LOG_BUFFERS, "output not open\n"); + } +} + +static void speex_dispose (audio_decoder_t *this_gen) { + + speex_decoder_t *this = (speex_decoder_t *) this_gen; + + if (this->st) { + speex_decoder_destroy (this->st); + } + speex_bits_destroy (&this->bits); + + if (this->output_open) + this->stream->audio_out->close (this->stream->audio_out, this->stream); + + free (this_gen); +} + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, + xine_stream_t *stream) { + + speex_decoder_t *this ; + static SpeexStereoState init_stereo = SPEEX_STEREO_STATE_INIT; + + this = (speex_decoder_t *) xine_xmalloc (sizeof (speex_decoder_t)); + + this->audio_decoder.decode_data = speex_decode_data; + this->audio_decoder.reset = speex_reset; + this->audio_decoder.discontinuity = speex_discontinuity; + this->audio_decoder.dispose = speex_dispose; + this->stream = stream; + + this->output_open = 0; + this->header_count = 1; + this->expect_metadata = 0; + + this->st = NULL; + + this->channels = 1; + + memcpy (&this->stereo, &init_stereo, sizeof (SpeexStereoState)); + + return (audio_decoder_t *) this; +} + +/* + * speex plugin class + */ + +static char *get_identifier (audio_decoder_class_t *this) { + return "speex"; +} + +static char *get_description (audio_decoder_class_t *this) { + return "Speex audio decoder plugin"; +} + +static void dispose_class (audio_decoder_class_t *this) { + free (this); +} + +void *speex_init_plugin (xine_t *xine, void *data) { + + speex_class_t *this; + + this = (speex_class_t *) xine_xmalloc (sizeof (speex_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + return this; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_SPEEX, 0 + }; + +const decoder_info_t dec_info_speex = { + audio_types, /* supported types */ + 5 /* priority */ +}; diff --git a/src/combined/xine_theora_decoder.c b/src/combined/xine_theora_decoder.c new file mode 100644 index 000000000..8dd997692 --- /dev/null +++ b/src/combined/xine_theora_decoder.c @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2001-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: xine_decoder.c,v 1.26 2006/07/10 22:08:30 dgp85 Exp $ + * + * xine decoder plugin using libtheora + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_MODULE "theora_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "video_out.h" +#include "buffer.h" +#include "metronom.h" +#include "xineutils.h" + +typedef struct theora_class_s { + video_decoder_class_t decoder_class; +} theora_class_t; + +typedef struct theora_decoder_s { + video_decoder_t theora_decoder; + theora_class_t *class; + theora_info t_info; + theora_comment t_comment; + theora_state t_state; + ogg_packet op; + yuv_buffer yuv; + xine_stream_t* stream; + int reject; + int op_max_size; + char* packet; + int done; + int width, height; + double ratio; + int offset_x, offset_y; + int frame_duration; + int skipframes; + int hp_read; + int initialized; +} theora_decoder_t; + +static void readin_op (theora_decoder_t *this, char* src, int size) { + if ( this->done+size > this->op_max_size) { + while (this->op_max_size < this->done+size) + this->op_max_size=this->op_max_size*2; + this->packet=realloc(this->packet, this->op_max_size); + this->op.packet=this->packet; + } + xine_fast_memcpy ( this->packet+this->done, src, size); + this->done=this->done+size; +} + +static void yuv2frame(yuv_buffer *yuv, vo_frame_t *frame, int offset_x, int offset_y) { + int i; + int crop_offset; + + /* fixme - direct rendering (exchaning pointers) may be possible. + * frame->base[0] = yuv->y could work if one could change the + * pitches[0,1,2] values, and rely on the drawing routine using + * the new pitches. With cropping and offsets, it's a bit trickier, + * but it would still be possible. + * Attempts at doing this have yielded nothing but SIGSEVs so far. + */ + + /* Copy yuv data onto the frame. Cropping and offset as specified + * by the frame_width, frame_height, offset_x and offset_y fields + * in the theora header is carried out. + */ + + crop_offset=offset_x+yuv->y_stride*offset_y; + for(i=0;iheight;i++) + xine_fast_memcpy(frame->base[0]+frame->pitches[0]*i, + yuv->y+crop_offset+yuv->y_stride*i, + frame->width); + + crop_offset=(offset_x/2)+(yuv->uv_stride)*(offset_y/2); + for(i=0;iheight/2;i++){ + xine_fast_memcpy(frame->base[1]+frame->pitches[1]*i, + yuv->u+crop_offset+yuv->uv_stride*i, + frame->width/2); + xine_fast_memcpy(frame->base[2]+frame->pitches[2]*i, + yuv->v+crop_offset+yuv->uv_stride*i, + frame->width/2); + + } +} + +static int collect_data (theora_decoder_t *this, buf_element_t *buf ) { + /* Assembles an ogg_packet which was sent with send_ogg_packet over xinebuffers */ + /* this->done, this->rejected, this->op and this->decoder->flags are needed*/ + int op_size = sizeof (ogg_packet); + + if (buf->decoder_flags & BUF_FLAG_FRAME_START) { + this->done=0; /*start from the beginnig*/ + this->reject=0;/*new packet - new try*/ + + /*copy the ogg_packet struct and the sum, correct the adress of the packet*/ + xine_fast_memcpy (&this->op, buf->content, op_size); + this->op.packet=this->packet; + + readin_op (this, buf->content + op_size, buf->size - op_size ); + /*read the rest of the data*/ + + } else { + if (this->done==0 || this->reject) { + /*we are starting to collect an packet without the beginnig + reject the rest*/ + printf ("libtheora: rejecting packet\n"); + this->reject=1; + return 0; + } + readin_op (this, buf->content, buf->size ); + } + + if ((buf->decoder_flags & BUF_FLAG_FRAME_END) && !this->reject) { + if ( this->done != this->op.bytes ) { + printf ("libtheora: A packet changed its size during transfer - rejected\n"); + printf (" size %d should be %ld\n", this->done , this->op.bytes); + this->op.bytes=this->done; + } + return 1; + } + return 0; +} + +static void theora_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { + /* + * decode data from buf and feed decoded frames to + * video output + */ + theora_decoder_t *this = (theora_decoder_t *) this_gen; + vo_frame_t *frame; + yuv_buffer yuv; + int ret; + + if (!collect_data(this, buf)) return; + /*return, until a entire packets is collected*/ + + if ( (buf->decoder_flags & BUF_FLAG_HEADER) && + !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { + /*get the first 3 packets and decode the header during preview*/ + + if (this->hp_read==0) { + /*decode first hp*/ + if (theora_decode_header(&this->t_info, &this->t_comment, &this->op)>=0) { + this->hp_read++; + return; + } + } + + if (this->hp_read==1) { + /*decode three header packets*/ + if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { + printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); + } else { + this->hp_read++; + return; + } + } + + if (this->hp_read==2) { + if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { + printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); + } + /*headers are now decoded. initialize the decoder*/ + theora_decode_init (&this->t_state, &this->t_info); + + lprintf("theora stream is Theora %dx%d %.02f fps video.\n" + " frame content is %dx%d with offset (%d,%d).\n" + " pixel aspect is %d:%d.\n", + this->t_info.width,this->t_info.height, + (double)this->t_info.fps_numerator/this->t_info.fps_denominator, + this->t_info.frame_width, this->t_info.frame_height, + this->t_info.offset_x, this->t_info.offset_y, + this->t_info.aspect_numerator, this->t_info.aspect_denominator); + + this->frame_duration=((int64_t)90000*this->t_info.fps_denominator)/this->t_info.fps_numerator; + this->width=this->t_info.frame_width; + this->height=this->t_info.frame_height; + if (this->t_info.aspect_numerator==0 || this->t_info.aspect_denominator==0) + /* 0-values are undefined, so don't do any scaling. */ + this->ratio=(double)this->width/(double)this->height; + else + /* Yes, this video needs to be scaled. */ + this->ratio=(double)(this->width*this->t_info.aspect_numerator) / + (double)(this->height*this->t_info.aspect_denominator); + this->offset_x=this->t_info.offset_x; + this->offset_y=this->t_info.offset_y; + this->initialized=1; + this->hp_read++; + } + + } else if (buf->decoder_flags & BUF_FLAG_HEADER) { + /*ignore headerpackets*/ + + return; + + } else { + /*decode videodata*/ + + if (!this->initialized) { + printf ("libtheora: cannot decode stream without header\n"); + return; + } + + ret=theora_decode_packetin( &this->t_state, &this->op); + + if ( ret!=0) { + xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "libtheora:Received an bad packet\n"); + } else if (!this->skipframes) { + + theora_decode_YUVout(&this->t_state,&yuv); + + /*fixme - aspectratio from theora is not considered*/ + frame = this->stream->video_out->get_frame( this->stream->video_out, + this->width, this->height, + this->ratio, + XINE_IMGFMT_YV12, + VO_BOTH_FIELDS); + yuv2frame(&yuv, frame, this->offset_x, this->offset_y); + + frame->pts = buf->pts; + frame->duration=this->frame_duration; + this->skipframes=frame->draw(frame, this->stream); + frame->free(frame); + } else { + this->skipframes=this->skipframes-1; + } + } +} + + +static void theora_flush (video_decoder_t *this_gen) { + /* + * flush out any frames that are still stored in the decoder + */ + theora_decoder_t *this = (theora_decoder_t *) this_gen; + this->skipframes=0; +} + +static void theora_reset (video_decoder_t *this_gen) { + /* + * reset decoder after engine flush (prepare for new + * video data not related to recently decoded data) + */ + theora_decoder_t *this = (theora_decoder_t *) this_gen; + this->skipframes=0; +} + +static void theora_discontinuity (video_decoder_t *this_gen) { + /* + * inform decoder that a time reference discontinuity has happened. + * that is, it must forget any currently held pts value + */ + theora_decoder_t *this = (theora_decoder_t *) this_gen; + this->skipframes=0; +} + +static void theora_dispose (video_decoder_t *this_gen) { + /* + * close down, free all resources + */ + + theora_decoder_t *this = (theora_decoder_t *) this_gen; + + lprintf ("dispose \n"); + + theora_clear (&this->t_state); + theora_comment_clear (&this->t_comment); + theora_info_clear (&this->t_info); + this->stream->video_out->close(this->stream->video_out, this->stream); + free (this->packet); + free (this); +} + +static video_decoder_t *theora_open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) { + + /* + * open a new instance of this plugin class + */ + + theora_decoder_t *this ; + + this = (theora_decoder_t *) xine_xmalloc (sizeof (theora_decoder_t)); + + this->theora_decoder.decode_data = theora_decode_data; + this->theora_decoder.flush = theora_flush; + this->theora_decoder.reset = theora_reset; + this->theora_decoder.discontinuity = theora_discontinuity; + this->theora_decoder.dispose = theora_dispose; + + this->stream = stream; + this->class = (theora_class_t *) class_gen; + + this->op_max_size = 4096; + this->packet = malloc(this->op_max_size); + + this->done = 0; + + this->stream = stream; + + this->initialized = 0; + + theora_comment_init (&this->t_comment); + theora_info_init (&this->t_info); + stream->video_out->open (stream->video_out, stream); + + return &this->theora_decoder; + +} + +/* + * theora plugin class + */ + +static char *theora_get_identifier (video_decoder_class_t *this) { + /* + * return short, human readable identifier for this plugin class + */ + return "theora video"; +} + +static char *theora_get_description (video_decoder_class_t *this) { + /* + * return human readable (verbose = 1 line) description for + * this plugin class + */ + return "theora video decoder plugin"; +} + +static void theora_dispose_class (video_decoder_class_t *this) { + /* + * free all class-related resources + */ + free (this); +} + +void *theora_init_plugin (xine_t *xine, void *data) { + /*initialize our plugin*/ + theora_class_t *this; + + this = (theora_class_t *) xine_xmalloc (sizeof (theora_class_t)); + + this->decoder_class.open_plugin = theora_open_plugin; + this->decoder_class.get_identifier = theora_get_identifier; + this->decoder_class.get_description = theora_get_description; + this->decoder_class.dispose = theora_dispose_class; + + return this; +} + +/* + * exported plugin catalog entry + */ + +static uint32_t supported_types[] = { BUF_VIDEO_THEORA, 0 }; + +const decoder_info_t dec_info_theora = { + supported_types, /* supported types */ + 5 /* priority */ +}; diff --git a/src/combined/xine_vorbis_decoder.c b/src/combined/xine_vorbis_decoder.c new file mode 100644 index 000000000..259ef40b0 --- /dev/null +++ b/src/combined/xine_vorbis_decoder.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2000-2003 the xine project + * + * This file is part of xine, a free video player. + * + * xine 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. + * + * xine 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: xine_decoder.c,v 1.48 2006/12/04 13:59:38 dgp85 Exp $ + * + * (ogg/)vorbis audio decoder plugin (libvorbis wrapper) for xine + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define LOG_MODULE "vorbis_decoder" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "audio_out.h" +#include "buffer.h" + +#include +#include + +#define MAX_NUM_SAMPLES 4096 + +typedef struct { + audio_decoder_class_t decoder_class; +} vorbis_class_t; + +typedef struct vorbis_decoder_s { + audio_decoder_t audio_decoder; + + int64_t pts; + + int output_sampling_rate; + int output_open; + int output_mode; + + ogg_packet op; /* we must use this struct to sent data to libvorbis */ + + /* vorbis stuff */ + vorbis_info vi; /* stores static vorbis bitstream settings */ + vorbis_comment vc; + vorbis_dsp_state vd; /* central working state for packet->PCM decoder */ + vorbis_block vb; /* local working state for packet->PCM decoder */ + + int16_t convbuffer[MAX_NUM_SAMPLES]; + int convsize; + + int header_count; + + xine_stream_t *stream; + +} vorbis_decoder_t; + + +static void vorbis_reset (audio_decoder_t *this_gen) { + + vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + + if( !this->header_count ) + vorbis_block_init(&this->vd,&this->vb); +} + +static void vorbis_discontinuity (audio_decoder_t *this_gen) { + + vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + + this->pts=0; +} + +/* Known vorbis comment keys from ogg123 sources*/ +static const struct { + const char *key; /* includes the '=' for programming convenience */ + int xine_metainfo_index; +} vorbis_comment_keys[] = { + {"ARTIST=", XINE_META_INFO_ARTIST}, + {"ALBUM=", XINE_META_INFO_ALBUM}, + {"TITLE=", XINE_META_INFO_TITLE}, + {"GENRE=", XINE_META_INFO_GENRE}, + {"DESCRIPTION=", XINE_META_INFO_COMMENT}, + {"COMMENT=", XINE_META_INFO_COMMENT}, + {"DATE=", XINE_META_INFO_YEAR}, + {"TRACKNUMBER=", XINE_META_INFO_TRACK_NUMBER}, + {NULL, 0} +}; + +static void get_metadata (vorbis_decoder_t *this) { + + char **ptr=this->vc.user_comments; + while(*ptr){ + + char *comment = *ptr; + int i; + + lprintf("%s\n", comment); + + for (i = 0; vorbis_comment_keys[i].key != NULL; i++) { + + if ( !strncasecmp (vorbis_comment_keys[i].key, comment, + strlen(vorbis_comment_keys[i].key)) ) { + + lprintf ("known metadata %d %d\n", + i, vorbis_comment_keys[i].xine_metainfo_index); + + _x_meta_info_set_utf8(this->stream, vorbis_comment_keys[i].xine_metainfo_index, + comment + strlen(vorbis_comment_keys[i].key)); + + } + } + ++ptr; + } + + _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "vorbis"); +} + +static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { + + vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + + memset( &this->op, 0, sizeof(this->op) ); + this->op.packet = buf->content; + this->op.bytes = buf->size; + + if ( (buf->decoder_flags & BUF_FLAG_HEADER) && + !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { + lprintf ("%d headers to go\n", this->header_count); + + if (this->header_count) { + int res = 0; + + if (this->header_count == 3) + this->op.b_o_s = 1; + + + if( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ){ + /* error case; not a vorbis header */ + xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); + xine_hexdump(this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); + return; + } + + this->header_count--; + + if (!this->header_count) { + + int mode = AO_CAP_MODE_MONO; + + get_metadata (this); + + mode = _x_ao_channels2mode(this->vi.channels); + + this->convsize=MAX_NUM_SAMPLES/this->vi.channels; + + if (!this->output_open) { + this->output_open = this->stream->audio_out->open(this->stream->audio_out, + this->stream, + 16, + this->vi.rate, + mode) ; + + _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, + this->vi.bitrate_nominal); + + } + + /* OK, got and parsed all three headers. Initialize the Vorbis + * packet->PCM decoder. */ + lprintf("all three headers parsed. initializing decoder.\n"); + /* initialize central decode state */ + vorbis_synthesis_init(&this->vd,&this->vi); + /* initialize local state for most of the decode so multiple + * block decodes can proceed in parallel. We could init + * multiple vorbis_block structures for vd here */ + vorbis_block_init(&this->vd,&this->vb); + } + } + + } else if (this->output_open) { + + float **pcm; + int samples; + + if(vorbis_synthesis(&this->vb,&this->op)==0) + vorbis_synthesis_blockin(&this->vd,&this->vb); + + if (buf->pts!=0) + this->pts=buf->pts; + + while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ + + /* **pcm is a multichannel float vector. In stereo, for + * example, pcm[0][...] is left, and pcm[1][...] is right. + * samples is the size of each channel. Convert the float + * values (-1.<=range<=1.) to whatever PCM format and write + * it out + */ + + int i,j; + int clipflag=0; + int bout=(samplesconvsize?samples:this->convsize); + audio_buffer_t *audio_buffer; + + audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); + + /* convert floats to 16 bit signed ints (host order) and + interleave */ + for(i=0;ivi.channels;i++){ + ogg_int16_t *ptr=audio_buffer->mem+i; + float *mono=pcm[i]; + for(j=0;j32767){ + val=32767; + clipflag=1; + } + if(val<-32768){ + val=-32768; + clipflag=1; + } + *ptr=val; + ptr+=this->vi.channels; + } + } + + audio_buffer->vpts = this->pts; + this->pts=0; + audio_buffer->num_frames = bout; + + this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); + + buf->pts=0; + + /* tell libvorbis how many samples we actually consumed */ + vorbis_synthesis_read(&this->vd,bout); + } + } + lprintf("output not open\n"); +} + +static void vorbis_dispose (audio_decoder_t *this_gen) { + + vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; + + if( !this->header_count ) { + lprintf("deinitializing decoder\n"); + + vorbis_block_clear(&this->vb); + vorbis_dsp_clear(&this->vd); + } + + vorbis_comment_clear(&this->vc); + + vorbis_info_clear(&this->vi); /* must be called last */ + + if (this->output_open) + this->stream->audio_out->close (this->stream->audio_out, this->stream); + + lprintf("libvorbis instance destroyed\n"); + + free (this_gen); +} + +static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, + xine_stream_t *stream) { + + vorbis_decoder_t *this ; + + this = (vorbis_decoder_t *) xine_xmalloc (sizeof (vorbis_decoder_t)); + + this->audio_decoder.decode_data = vorbis_decode_data; + this->audio_decoder.reset = vorbis_reset; + this->audio_decoder.discontinuity = vorbis_discontinuity; + this->audio_decoder.dispose = vorbis_dispose; + this->stream = stream; + + this->output_open = 0; + this->header_count = 3; + this->convsize = 0; + + vorbis_info_init(&this->vi); + vorbis_comment_init(&this->vc); + + lprintf("libvorbis decoder instance created\n"); + + return (audio_decoder_t *) this; +} + +/* + * vorbis plugin class + */ + +static char *get_identifier (audio_decoder_class_t *this) { + return "vorbis"; +} + +static char *get_description (audio_decoder_class_t *this) { + return "vorbis audio decoder plugin"; +} + +static void dispose_class (audio_decoder_class_t *this) { + free (this); +} + +void *vorbis_init_plugin (xine_t *xine, void *data) { + + vorbis_class_t *this; + + this = (vorbis_class_t *) xine_xmalloc (sizeof (vorbis_class_t)); + + this->decoder_class.open_plugin = open_plugin; + this->decoder_class.get_identifier = get_identifier; + this->decoder_class.get_description = get_description; + this->decoder_class.dispose = dispose_class; + + return this; +} + +static uint32_t audio_types[] = { + BUF_AUDIO_VORBIS, 0 + }; + +const decoder_info_t dec_info_vorbis = { + audio_types, /* supported types */ + 5 /* priority */ +}; diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am index a2896abd3..1dec2eabf 100644 --- a/src/demuxers/Makefile.am +++ b/src/demuxers/Makefile.am @@ -12,10 +12,6 @@ xineinclude_HEADERS = demux.h noinst_HEADERS = asfheader.h qtpalette.h group_games.h group_audio.h id3.h ebml.h matroska.h iff.h flacutils.h -if ENABLE_VORBIS -ogg_module = xineplug_dmx_ogg.la -endif - if ENABLE_ASF asf_module = xineplug_dmx_asf.la endif @@ -33,7 +29,6 @@ image_module = xineplug_dmx_image.la endif xineplug_LTLIBRARIES = \ - $(ogg_module) \ $(asf_module) \ $(mng_module) \ $(image_module) \ @@ -59,10 +54,6 @@ xineplug_LTLIBRARIES = \ xineplug_dmx_iff.la \ xineplug_dmx_flv.la -xineplug_dmx_ogg_la_SOURCES = demux_ogg.c -xineplug_dmx_ogg_la_LIBADD = $(VORBIS_LIBS) $(SPEEX_LIBS) $(THEORA_LIBS) $(OGG_LIBS) $(XINE_LIB) -xineplug_dmx_ogg_la_CFLAGS = $(AM_CFLAGS) $(VORBIS_CFLAGS) $(SPEEX_CFLAGS) $(THEORA_CFLAGS) $(OGG_CFLAGS) - xineplug_dmx_avi_la_SOURCES = demux_avi.c xineplug_dmx_avi_la_LIBADD = $(XINE_LIB) diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c deleted file mode 100644 index f868018af..000000000 --- a/src/demuxers/demux_ogg.c +++ /dev/null @@ -1,2202 +0,0 @@ -/* - * Copyright (C) 2000-2004 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -/* - * $Id: demux_ogg.c,v 1.177 2007/03/29 19:38:51 dgp85 Exp $ - * - * demultiplexer for ogg streams - * - */ -/* 2003.02.09 (dilb) update of the handling for audio/video infos for strongarm cpus. */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef HAVE_SPEEX -#include -#include -#include -#include -#endif - -#ifdef HAVE_THEORA -#include -#endif - -#define LOG_MODULE "demux_ogg" -#define LOG_VERBOSE - -/* -#define LOG -*/ - -#define DEBUG_PACKETS 0 -#define DEBUG_PREVIEWS 0 -#define DEBUG_PTS 0 -#define DEBUG_VIDEO_PACKETS 0 - -#include "xine_internal.h" -#include "xineutils.h" -#include "demux.h" -#include "bswap.h" -#include "flacutils.h" - -#define CHUNKSIZE 8500 -#define PACKET_TYPE_HEADER 0x01 -#define PACKET_TYPE_COMMENT 0x03 -#define PACKET_TYPE_CODEBOOK 0x05 -#define PACKET_TYPE_BITS 0x07 -#define PACKET_LEN_BITS01 0xc0 -#define PACKET_LEN_BITS2 0x02 -#define PACKET_IS_SYNCPOINT 0x08 - -#define MAX_STREAMS 32 - -#define PTS_AUDIO 0 -#define PTS_VIDEO 1 - -#define WRAP_THRESHOLD 900000 - -#define SUB_BUFSIZE 1024 - -typedef struct chapter_entry_s { - int64_t start_pts; - char *name; -} chapter_entry_t; - -typedef struct chapter_info_s { - int current_chapter; - int max_chapter; - chapter_entry_t *entries; -} chapter_info_t; - -typedef struct stream_info_s { - ogg_stream_state oss; - uint32_t buf_types; - int headers; - int64_t header_granulepos; - int64_t factor; - int64_t quotient; - int resync; - char *language; - /* CMML, Ogg Skeleton stream information */ - int granuleshift; - /* Annodex v2 stream information */ - int hide_first_header; - int delivered_bos; - int delivered_eos; -} stream_info_t; - -typedef struct demux_ogg_s { - demux_plugin_t demux_plugin; - - xine_stream_t *stream; - fifo_buffer_t *audio_fifo; - fifo_buffer_t *video_fifo; - input_plugin_t *input; - int status; - - int frame_duration; - -#ifdef HAVE_THEORA - theora_info t_info; - theora_comment t_comment; -#endif - - ogg_sync_state oy; - ogg_page og; - - int64_t start_pts; - int64_t last_pts[2]; - - int time_length; - - int num_streams; - stream_info_t *si[MAX_STREAMS]; /* stream info */ - - int num_audio_streams; - int num_video_streams; - int unhandled_video_streams; - int num_spu_streams; - - off_t avg_bitrate; - - char *title; - chapter_info_t *chapter_info; - xine_event_queue_t *event_queue; - - uint8_t send_newpts:1; - uint8_t buf_flag_seek:1; - uint8_t keyframe_needed:1; - uint8_t ignore_keyframes:1; -} demux_ogg_t ; - -typedef struct { - demux_class_t demux_class; -} demux_ogg_class_t; - -typedef struct { - demux_class_t demux_class; -} demux_anx_class_t; - - -#ifdef HAVE_THEORA -static int intlog(int num) { - int ret=0; - - while(num>0){ - num=num/2; - ret=ret+1; - } - return(ret); -} -#endif - -static int get_stream (demux_ogg_t *this, int serno) { - /*finds the stream_num, which belongs to a ogg serno*/ - int i; - - for (i = 0; inum_streams; i++) { - if (this->si[i]->oss.serialno == serno) { - return i; - } - } - return -1; -} - -static int new_stream_info (demux_ogg_t *this, const int cur_serno) { - int stream_num; - - this->si[this->num_streams] = (stream_info_t *)xine_xmalloc(sizeof(stream_info_t)); - ogg_stream_init(&this->si[this->num_streams]->oss, cur_serno); - stream_num = this->num_streams; - this->si[stream_num]->buf_types = 0; - this->si[stream_num]->header_granulepos = -1; - this->si[stream_num]->headers = 0; - this->num_streams++; - - return stream_num; -} - -static int64_t get_pts (demux_ogg_t *this, int stream_num , int64_t granulepos ) { - /*calculates an pts from an granulepos*/ - if (granulepos<0) { - if ( this->si[stream_num]->header_granulepos>=0 ) { - /*return the smallest valid pts*/ - return 1; - } else - return 0; - } else if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA || - (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { - int64_t iframe, pframe; - int granuleshift; - granuleshift = this->si[stream_num]->granuleshift; - iframe = granulepos >> granuleshift; - pframe = granulepos - (iframe << granuleshift); - if (this->si[stream_num]->quotient) - return 1+((iframe+pframe) * this->si[stream_num]->factor / this->si[stream_num]->quotient); - else - return 0; - } else if (this->si[stream_num]->quotient) - return 1+(granulepos * this->si[stream_num]->factor / this->si[stream_num]->quotient); - else - return 0; -} - -static int read_ogg_packet (demux_ogg_t *this) { - char *buffer; - long bytes; - while (ogg_sync_pageout(&this->oy,&this->og)!=1) { - buffer = ogg_sync_buffer(&this->oy, CHUNKSIZE); - bytes = this->input->read(this->input, buffer, CHUNKSIZE); - ogg_sync_wrote(&this->oy, bytes); - if (bytes < CHUNKSIZE/2) { - return 0; - } - } - return 1; -} - -static void get_stream_length (demux_ogg_t *this) { - /*determine the streamlenght and set this->time_length accordingly. - ATTENTION:current_pos and oggbuffers will be destroyed by this function, - there will be no way to continue playback uninterrupted. - - You have to seek afterwards, because after get_stream_length, the - current_position is at the end of the file */ - - off_t filelength; - int done=0; - int stream_num; - - this->time_length=-1; - - if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) { - filelength=this->input->get_length(this->input); - - if (filelength!=-1) { - if (filelength>70000) { - this->demux_plugin.seek(&this->demux_plugin, - (off_t) ( (double)(filelength-65536)/filelength*65535), 0, 0); - } - done=0; - while (!done) { - if (!read_ogg_packet (this)) { - if (this->time_length) { - _x_stream_info_set(this->stream, XINE_STREAM_INFO_BITRATE, - ((int64_t) 8000*filelength)/this->time_length); - /*this is a fine place to compute avg_bitrate*/ - this->avg_bitrate= 8000*filelength/this->time_length; - } - return; - } - stream_num=get_stream(this, ogg_page_serialno (&this->og) ); - if (stream_num!=-1) { - if (this->time_length < (get_pts(this, stream_num, ogg_page_granulepos(&this->og) / 90))) - this->time_length = get_pts(this, stream_num, ogg_page_granulepos(&this->og)) / 90; - } - } - } - } -} - -#ifdef HAVE_THEORA -static void send_ogg_packet (demux_ogg_t *this, - fifo_buffer_t *fifo, - ogg_packet *op, - int64_t pts, - uint32_t decoder_flags, - int stream_num) { - - buf_element_t *buf; - - int done=0,todo=op->bytes; - int op_size = sizeof(ogg_packet); - - while (donebuffer_pool_alloc (fifo); - buf->decoder_flags = decoder_flags; - if (done==0) { - memcpy (buf->content, op, op_size); - offset=op_size; - buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_START; - } - - if (done+buf->max_size-offset < todo) { - memcpy (buf->content+offset, op->packet+done, buf->max_size-offset); - buf->size = buf->max_size; - done=done+buf->max_size-offset; - } else { - memcpy (buf->content+offset , op->packet+done, todo-done); - buf->size = todo-done+offset; - done=todo; - buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_END; - } - - buf->pts = pts; - if( this->input->get_length (this->input) ) - buf->extra_info->input_normpos = (int)( (double) this->input->get_current_pos (this->input) * - 65535 / this->input->get_length (this->input) ); - buf->extra_info->input_time = buf->pts / 90 ; - buf->type = this->si[stream_num]->buf_types; - - fifo->put (fifo, buf); - } -} -#endif - -/* redefine abs as macro to handle 64-bit diffs. - i guess llabs may not be available everywhere */ -#define abs(x) ( ((x)<0) ? -(x) : (x) ) - -static void check_newpts (demux_ogg_t *this, int64_t pts, int video, int preview) { - int64_t diff; - - llprintf(DEBUG_PTS, "new pts %" PRId64 " found in stream\n",pts); - - diff = pts - this->last_pts[video]; - - if (!preview && (pts>=0) && - (this->send_newpts || (this->last_pts[video] && abs(diff)>WRAP_THRESHOLD) ) ) { - - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "diff=%" PRId64 " (pts=%" PRId64 ", last_pts=%" PRId64 ")\n", diff, pts, this->last_pts[video]); - - if (this->buf_flag_seek) { - _x_demux_control_newpts(this->stream, pts, BUF_FLAG_SEEK); - this->buf_flag_seek = 0; - } else { - _x_demux_control_newpts(this->stream, pts, 0); - } - this->send_newpts = 0; - this->last_pts[1-video] = 0; - } - - if (!preview && (pts>=0) ) - this->last_pts[video] = pts; - - /* use pts for bitrate measurement */ - - /*compute avg_bitrate if time_length isn't set*/ - if ((pts>180000) && !(this->time_length)) { - this->avg_bitrate = this->input->get_current_pos (this->input) * 8 * 90000/ pts; - - if (this->avg_bitrate<1) - this->avg_bitrate = 1; - - } -} - -static void ogg_handle_event (demux_ogg_t *this) { - xine_event_t *event; - - while ((event = xine_event_get(this->event_queue))) { - switch(event->type) { - case XINE_EVENT_INPUT_NEXT: - { - if (this->chapter_info) { - int c_chap = this->chapter_info->current_chapter; - if (c_chap+1 < this->chapter_info->max_chapter) { - int start_time = this->chapter_info->entries[c_chap+1].start_pts / 90; - this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); - } - } - } - break; - case XINE_EVENT_INPUT_PREVIOUS: - { - if (this->chapter_info) { - int c_chap = this->chapter_info->current_chapter; - if (c_chap >= 1) { - int start_time = this->chapter_info->entries[c_chap-1].start_pts / 90; - this->demux_plugin.seek((demux_plugin_t *)this, 0, start_time, 1); - } - } - } - break; - } - xine_event_free(event); - } - return; -} - -/* - * utility function to read a LANGUAGE= line from the user_comments, - * to label audio and spu streams - */ -static void read_language_comment (demux_ogg_t *this, ogg_packet *op, int stream_num) { - char **ptr; - char *comment; - vorbis_comment vc; - vorbis_info vi; - - vorbis_comment_init(&vc); - vorbis_info_init(&vi); - - /* this is necessary to make libvorbis accept this vorbis_info*/ - vi.rate=1; - - if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { - ptr=vc.user_comments; - while(*ptr) { - comment=*ptr; - if ( !strncasecmp ("LANGUAGE=", comment, 9) ) { - this->si[stream_num]->language = strdup (comment + strlen ("LANGUAGE=") ); - } - ++ptr; - } - } - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); -} - -/* - * utility function to read CHAPTER*= and TITLE= from the user_comments, - * to name parts of the videostream - */ -static void read_chapter_comment (demux_ogg_t *this, ogg_packet *op) { - char **ptr; - char *comment; - vorbis_comment vc; - vorbis_info vi; - - vorbis_comment_init(&vc); - vorbis_info_init(&vi); - - /* this is necessary to make libvorbis accept this vorbis_info*/ - vi.rate=1; - - if ( vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { - char *chapter_time = 0; - char *chapter_name = 0; - int chapter_no = 0; - ptr=vc.user_comments; - while(*ptr) { - comment=*ptr; - if ( !strncasecmp ("TITLE=", comment,6) ) { - this->title = strdup (comment + strlen ("TITLE=") ); - _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, this->title); - } - if ( !chapter_time && strlen(comment) == 22 && - !strncasecmp ("CHAPTER" , comment, 7) && - isdigit(*(comment+7)) && isdigit(*(comment+8)) && - (*(comment+9) == '=')) { - - chapter_time = strdup(comment+10); - chapter_no = strtol(comment+7, NULL, 10); - } - if ( !chapter_name && !strncasecmp("CHAPTER", comment, 7) && - isdigit(*(comment+7)) && isdigit(*(comment+8)) && - !strncasecmp ("NAME=", comment+9, 5)) { - - if (strtol(comment+7,NULL,10) == chapter_no) { - chapter_name = strdup(comment+14); - } - } - if (chapter_time && chapter_name && chapter_no){ - int hour, min, sec, msec; - - lprintf("create chapter entry: no=%d name=%s time=%s\n", chapter_no, chapter_name, chapter_time); - hour= strtol(chapter_time, NULL, 10); - min = strtol(chapter_time+3, NULL, 10); - sec = strtol(chapter_time+6, NULL, 10); - msec = strtol(chapter_time+9, NULL, 10); - lprintf("time: %d %d %d %d\n", hour, min,sec,msec); - - if (!this->chapter_info) { - this->chapter_info = (chapter_info_t *)xine_xmalloc(sizeof(chapter_info_t)); - this->chapter_info->current_chapter = -1; - } - this->chapter_info->max_chapter = chapter_no; - this->chapter_info->entries = realloc( this->chapter_info->entries, chapter_no*sizeof(chapter_entry_t)); - this->chapter_info->entries[chapter_no-1].name = chapter_name; - this->chapter_info->entries[chapter_no-1].start_pts = (msec + (1000.0 * sec) + (60000.0 * min) + (3600000.0 * hour))*90; - - free (chapter_time); - chapter_no = 0; - chapter_time = chapter_name = 0; - } - ++ptr; - } - } - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); -} - -/* - * update the display of the title, if needed - */ -static void update_chapter_display (demux_ogg_t *this, int stream_num, ogg_packet *op) { - int chapter = 0; - int64_t pts = get_pts(this, stream_num, op->granulepos ); - - while (chapter < this->chapter_info->max_chapter && - this->chapter_info->entries[chapter].start_pts < pts) { - chapter++; - } - chapter--; - - if (chapter != this->chapter_info->current_chapter){ - xine_event_t uevent; - xine_ui_data_t data; - int title_len; - char *title; - - this->chapter_info->current_chapter = chapter; - if (chapter >= 0) { - char t_title[256]; - - if (this->title) { - snprintf(t_title, sizeof (t_title), "%s / %s", this->title, this->chapter_info->entries[chapter].name); - } else { - snprintf(t_title, sizeof (t_title), "%s", this->chapter_info->entries[chapter].name); - } - title = t_title; - } else { - title = this->title; - } - _x_meta_info_set(this->stream, XINE_META_INFO_TITLE, title); - lprintf("new TITLE: %s\n", title); - - uevent.type = XINE_EVENT_UI_SET_TITLE; - uevent.stream = this->stream; - uevent.data = &data; - uevent.data_length = sizeof(data); - title_len = strlen(title) + 1; - memcpy(data.str, title, title_len); - data.str_len = title_len; - xine_event_send(this->stream, &uevent); - } -} - -/* - * utility function to pack one ogg_packet into a xine - * buffer, fill out all needed fields - * and send it to the right fifo - */ - -static void send_ogg_buf (demux_ogg_t *this, - ogg_packet *op, - int stream_num, - uint32_t decoder_flags) { - - int hdrlen; - int normpos = 0; - - if( this->input->get_length (this->input) ) - normpos = (int)( (double) this->input->get_current_pos (this->input) * - 65535 / this->input->get_length (this->input) ); - - - hdrlen = (*op->packet & PACKET_LEN_BITS01) >> 6; - hdrlen |= (*op->packet & PACKET_LEN_BITS2) << 1; - - /* for Annodex files: the first packet after the AnxData info packet needs - * to have its BOS flag set: we set it here */ - if (!this->si[stream_num]->delivered_bos) { - op->b_o_s = 1; - this->si[stream_num]->delivered_bos = 1; - } - - if ( this->audio_fifo - && (this->si[stream_num]->buf_types & 0xFF000000) == BUF_AUDIO_BASE) { - uint8_t *data; - int size; - int64_t pts; - - if (op->packet[0] == PACKET_TYPE_COMMENT ) { - read_language_comment(this, op, stream_num); - } - - if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_SPEEX || - (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_FLAC || - (this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_AUDIO_VORBIS) { - data = op->packet; - size = op->bytes; - } else { - data = op->packet+1+hdrlen; - size = op->bytes-1-hdrlen; - } - llprintf(DEBUG_PACKETS, "audio data size %d\n", size); - - if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { - pts = get_pts(this, stream_num, op->granulepos ); - check_newpts( this, pts, PTS_AUDIO, decoder_flags ); - } else - pts = 0; - - llprintf(DEBUG_PACKETS, - "audiostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", - stream_num, - op->granulepos, - this->si[stream_num]->header_granulepos, - pts); - - _x_demux_send_data(this->audio_fifo, data, size, - pts, this->si[stream_num]->buf_types, decoder_flags, - normpos, - pts / 90, this->time_length, 0); - -#ifdef HAVE_THEORA - } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_VIDEO_THEORA) { - - int64_t pts; - theora_info t_info; - theora_comment t_comment; - - theora_info_init (&t_info); - theora_comment_init (&t_comment); - - /*Lets see if this is an Header*/ - if ((theora_decode_header(&t_info, &t_comment, op))>=0) { - decoder_flags=decoder_flags|BUF_FLAG_HEADER; - lprintf ("found an header\n"); - } - - if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { - pts = get_pts(this, stream_num, op->granulepos ); - check_newpts( this, pts, PTS_VIDEO, decoder_flags ); - } else - pts = 0; - - llprintf(DEBUG_PACKETS, - "theorastream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", - stream_num, - op->granulepos, - this->si[stream_num]->header_granulepos, - pts); - - send_ogg_packet (this, this->video_fifo, op, pts, decoder_flags, stream_num); - - theora_comment_clear (&t_comment); - theora_info_clear (&t_info); -#endif - - } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { - - uint8_t *data; - int size; - int64_t pts; - - llprintf(DEBUG_VIDEO_PACKETS, - "video buffer, type=%08x\n", this->si[stream_num]->buf_types); - - if (op->packet[0] == PACKET_TYPE_COMMENT ) { - read_chapter_comment(this, op); - }else{ - data = op->packet+1+hdrlen; - size = op->bytes-1-hdrlen; - - if ((op->granulepos != -1) || (this->si[stream_num]->header_granulepos != -1)) { - pts = get_pts(this, stream_num, op->granulepos ); - check_newpts( this, pts, PTS_VIDEO, decoder_flags ); - } else - pts = 0; - - llprintf(DEBUG_VIDEO_PACKETS, - "videostream %d op-gpos %" PRId64 " hdr-gpos %" PRId64 " pts %" PRId64 " \n", - stream_num, - op->granulepos, - this->si[stream_num]->header_granulepos, - pts); - - _x_demux_send_data(this->video_fifo, data, size, - pts, this->si[stream_num]->buf_types, decoder_flags, - normpos, - pts / 90, this->time_length, 0); - - if (this->chapter_info && op->granulepos != -1) { - update_chapter_display(this, stream_num, op); - } - } - } else if ((this->si[stream_num]->buf_types & 0xFFFF0000) == BUF_SPU_CMML) { - buf_element_t *buf; - uint32_t *val; - char *str; - - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - - buf->type = this->si[stream_num]->buf_types; - - buf->pts = get_pts (this, stream_num, op->granulepos); - - val = (uint32_t * )buf->content; - str = (char *)val; - - memcpy(str, op->packet, op->bytes); - str[op->bytes] = '\0'; - - buf->size = 12 + op->bytes + 1; - - lprintf ("CMML stream %d (bytes=%ld): PTS %"PRId64": %s\n", - stream_num, op->bytes, buf->pts, str); - - this->video_fifo->put (this->video_fifo, buf); - } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { - - buf_element_t *buf; - int i; - char *subtitle,*str; - int lenbytes; - int start,end; - uint32_t *val; - - for (i = 0, lenbytes = 0; i < hdrlen; i++) { - lenbytes = lenbytes << 8; - lenbytes += *((unsigned char *) op->packet + hdrlen - i); - } - - if (op->packet[0] == PACKET_TYPE_HEADER ) { - lprintf ("Textstream-header-packet\n"); - } else if (op->packet[0] == PACKET_TYPE_COMMENT ) { - lprintf ("Textstream-comment-packet\n"); - read_language_comment(this, op, stream_num); - } else { - subtitle = (char *)&op->packet[hdrlen + 1]; - - if ((strlen(subtitle) > 1) || (*subtitle != ' ')) { - start = op->granulepos; - end = start+lenbytes; - lprintf ("subtitlestream %d: %d -> %d :%s\n",stream_num,start,end,subtitle); - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - - buf->type = this->si[stream_num]->buf_types; - buf->pts = 0; - - val = (uint32_t * )buf->content; - *val++ = start; - *val++ = end; - str = (char *)val; - - memcpy (str, subtitle, 1+strlen(subtitle)); - - this->video_fifo->put (this->video_fifo, buf); - } - } - } else { - lprintf("unknown stream type %x\n", this->si[stream_num]->buf_types); - } -} - -static void decode_vorbis_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - vorbis_info vi; - vorbis_comment vc; - - this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS - +this->num_audio_streams++; - - this->si[stream_num]->headers = 3; - - vorbis_info_init(&vi); - vorbis_comment_init(&vc); - if (vorbis_synthesis_headerin(&vi, &vc, op) >= 0) { - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, vi.bitrate_nominal); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, vi.rate); - - this->si[stream_num]->factor = 90000; - this->si[stream_num]->quotient = vi.rate; - - if (vi.bitrate_nominal<1) - this->avg_bitrate += 100000; /* assume 100 kbit */ - else - this->avg_bitrate += vi.bitrate_nominal; - - } else { - this->si[stream_num]->factor = 900; - this->si[stream_num]->quotient = 441; - - this->si[stream_num]->headers = 0; - xine_log (this->stream->xine, XINE_LOG_MSG, - _("ogg: vorbis audio track indicated but no vorbis stream header found.\n")); - } - vorbis_comment_clear(&vc); - vorbis_info_clear(&vi); -} - -static void decode_speex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { -#ifdef HAVE_SPEEX - void *st; - SpeexMode *mode; - SpeexHeader *header; - - this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX - +this->num_audio_streams++; - - this->si[stream_num]->headers = 1; - - header = speex_packet_to_header (op->packet, op->bytes); - - if (header) { - int bitrate; - mode = (SpeexMode *) speex_mode_list[header->mode]; - - st = speex_decoder_init (mode); - - speex_decoder_ctl (st, SPEEX_GET_BITRATE, &bitrate); - - if (bitrate <= 1) - bitrate = 16000; /* assume 16 kbit */ - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); - - this->si[stream_num]->factor = 90000; - this->si[stream_num]->quotient = header->rate; - - this->avg_bitrate += bitrate; - - lprintf ("detected Speex stream,\trate %d\tbitrate %d\n", header->rate, bitrate); - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, header->rate); - this->si[stream_num]->headers += header->extra_headers; - } -#else - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "Speex stream detected, unable to play\n"); - - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; -#endif -} - -static void decode_video_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - buf_element_t *buf; - xine_bmiheader bih; - int channel; - - int16_t locbits_per_sample; - uint32_t locsubtype; - int32_t locsize, locdefault_len, locbuffersize, locwidth, locheight; - int64_t loctime_unit, locsamples_per_unit; - - /* read fourcc with machine endianness */ - locsubtype = *((uint32_t *)&op->packet[9]); - - /* everything else little endian */ - locsize = LE_32(&op->packet[13]); - loctime_unit = LE_64(&op->packet[17]); - locsamples_per_unit = LE_64(&op->packet[25]); - locdefault_len = LE_32(&op->packet[33]); - locbuffersize = LE_32(&op->packet[37]); - locbits_per_sample = LE_16(&op->packet[41]); - locwidth = LE_32(&op->packet[45]); - locheight = LE_32(&op->packet[49]); - - lprintf ("direct show filter created stream detected, hexdump:\n"); -#ifdef LOG - xine_hexdump (op->packet, op->bytes); -#endif - - channel = this->num_video_streams++; - - this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (locsubtype); - if( !this->si[stream_num]->buf_types ) - this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; - this->si[stream_num]->buf_types |= channel; - this->si[stream_num]->headers = 0; /* header is sent below */ - - lprintf ("subtype %.4s\n", (char*)&locsubtype); - lprintf ("time_unit %" PRId64 "\n", loctime_unit); - lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); - lprintf ("default_len %d\n", locdefault_len); - lprintf ("buffersize %d\n", locbuffersize); - lprintf ("bits_per_sample %d\n", locbits_per_sample); - lprintf ("width %d\n", locwidth); - lprintf ("height %d\n", locheight); - lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types); - - bih.biSize=sizeof(xine_bmiheader); - bih.biWidth = locwidth; - bih.biHeight= locheight; - bih.biPlanes= 0; - memcpy(&bih.biCompression, &locsubtype, 4); - bih.biBitCount= 0; - bih.biSizeImage=locwidth*locheight; - bih.biXPelsPerMeter=1; - bih.biYPelsPerMeter=1; - bih.biClrUsed=0; - bih.biClrImportant=0; - - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| - BUF_FLAG_FRAME_END; - this->frame_duration = loctime_unit * 9 / 1000; - this->si[stream_num]->factor = loctime_unit * 9; - this->si[stream_num]->quotient = 1000; - buf->decoder_info[0] = this->frame_duration; - memcpy (buf->content, &bih, sizeof (xine_bmiheader)); - buf->size = sizeof (xine_bmiheader); - buf->type = this->si[stream_num]->buf_types; - - /* video metadata */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_FOURCC, locsubtype); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, locwidth); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, locheight); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); - - this->avg_bitrate += 500000; /* FIXME */ - - this->video_fifo->put (this->video_fifo, buf); -} - -static void decode_audio_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - - if (this->audio_fifo) { - buf_element_t *buf; - int codec; - char str[5]; - int channel; - - int16_t locbits_per_sample, locchannels, locblockalign; - int32_t locsize, locdefault_len, locbuffersize, locavgbytespersec; - int64_t loctime_unit, locsamples_per_unit; - - locsize = LE_32(&op->packet[13]); - loctime_unit = LE_64(&op->packet[17]); - locsamples_per_unit = LE_64(&op->packet[25]); - locdefault_len = LE_32(&op->packet[33]); - locbuffersize = LE_32(&op->packet[37]); - locbits_per_sample = LE_16(&op->packet[41]); - locchannels = LE_16(&op->packet[45]); - locblockalign = LE_16(&op->packet[47]); - locavgbytespersec= LE_32(&op->packet[49]); - - lprintf ("direct show filter created audio stream detected, hexdump:\n"); -#ifdef LOG - xine_hexdump (op->packet, op->bytes); -#endif - - memcpy(str, &op->packet[9], 4); - str[4] = 0; - codec = strtoul(str, NULL, 16); - - channel= this->num_audio_streams++; - - this->si[stream_num]->buf_types = _x_formattag_to_buf_audio(codec); - if( this->si[stream_num]->buf_types ) { - this->si[stream_num]->buf_types |= channel; - } else { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ogg: unknown audio codec type 0x%x\n", codec); - this->si[stream_num]->buf_types = BUF_AUDIO_UNKNOWN; - /*break;*/ - } - - lprintf ("subtype 0x%x\n", codec); - lprintf ("time_unit %" PRId64 "\n", loctime_unit); - lprintf ("samples_per_unit %" PRId64 "\n", locsamples_per_unit); - lprintf ("default_len %d\n", locdefault_len); - lprintf ("buffersize %d\n", locbuffersize); - lprintf ("bits_per_sample %d\n", locbits_per_sample); - lprintf ("channels %d\n", locchannels); - lprintf ("blockalign %d\n", locblockalign); - lprintf ("avgbytespersec %d\n", locavgbytespersec); - lprintf ("buf_type %08x\n",this->si[stream_num]->buf_types); - - buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo); - buf->type = this->si[stream_num]->buf_types; - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - buf->decoder_info[0] = 0; - buf->decoder_info[1] = locsamples_per_unit; - buf->decoder_info[2] = locbits_per_sample; - buf->decoder_info[3] = locchannels; - this->audio_fifo->put (this->audio_fifo, buf); - - this->si[stream_num]->headers = 0; /* header already sent */ - this->si[stream_num]->factor = 90000; - this->si[stream_num]->quotient = locsamples_per_unit; - - this->avg_bitrate += locavgbytespersec*8; - - /* audio metadata */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC, codec); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, locchannels); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, locbits_per_sample); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, locsamples_per_unit); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, locavgbytespersec * 8); - - } else /* no audio_fifo there */ - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; -} - -static void decode_dshow_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - - lprintf ("older Direct Show filter-generated stream header detected. Hexdump:\n"); -#ifdef LOG - xine_hexdump (op->packet, op->bytes); -#endif - - this->si[stream_num]->headers = 0; /* header is sent below */ - - if ( (LE_32(&op->packet[96]) == 0x05589f80) && (op->bytes >= 184)) { - - buf_element_t *buf; - xine_bmiheader bih; - int channel; - uint32_t fcc; - - lprintf ("seems to be a video stream.\n"); - - channel = this->num_video_streams++; - fcc = *(uint32_t*)(op->packet+68); - lprintf ("fourcc %08x\n", fcc); - - this->si[stream_num]->buf_types = _x_fourcc_to_buf_video (fcc); - if( !this->si[stream_num]->buf_types ) - this->si[stream_num]->buf_types = BUF_VIDEO_UNKNOWN; - this->si[stream_num]->buf_types |= channel; - - bih.biSize = sizeof(xine_bmiheader); - bih.biWidth = LE_32(&op->packet[176]); - bih.biHeight = LE_32(&op->packet[180]); - bih.biPlanes = 0; - memcpy (&bih.biCompression, op->packet+68, 4); - bih.biBitCount = LE_16(&op->packet[182]); - if (!bih.biBitCount) - bih.biBitCount = 24; /* FIXME ? */ - bih.biSizeImage = (bih.biBitCount>>3)*bih.biWidth*bih.biHeight; - bih.biXPelsPerMeter = 1; - bih.biYPelsPerMeter = 1; - bih.biClrUsed = 0; - bih.biClrImportant = 0; - - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAMERATE| - BUF_FLAG_FRAME_END; - this->frame_duration = (*(int64_t*)(op->packet+164)) * 9 / 1000; - this->si[stream_num]->factor = (*(int64_t*)(op->packet+164)) * 9; - this->si[stream_num]->quotient = 1000; - - buf->decoder_info[0] = this->frame_duration; - memcpy (buf->content, &bih, sizeof (xine_bmiheader)); - buf->size = sizeof (xine_bmiheader); - buf->type = this->si[stream_num]->buf_types; - this->video_fifo->put (this->video_fifo, buf); - - lprintf ("subtype %.4s\n", (char*)&fcc); - lprintf ("buf_type %08x\n", this->si[stream_num]->buf_types); - lprintf ("video size %d x %d\n", bih.biWidth, bih.biHeight); - lprintf ("frame duration %d\n", this->frame_duration); - - /* video metadata */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, bih.biWidth); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, bih.biHeight); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); - - this->avg_bitrate += 500000; /* FIXME */ - - this->ignore_keyframes = 1; - - } else if (LE_32(&op->packet[96]) == 0x05589F81) { - -#if 0 - /* FIXME: no test streams */ - - buf_element_t *buf; - int codec; - char str[5]; - int channel; - int extra_size; - - extra_size = *(int16_t*)(op->packet+140); - format = *(int16_t*)(op->packet+124); - channels = *(int16_t*)(op->packet+126); - samplerate = *(int32_t*)(op->packet+128); - nAvgBytesPerSec = *(int32_t*)(op->packet+132); - nBlockAlign = *(int16_t*)(op->packet+136); - wBitsPerSample = *(int16_t*)(op->packet+138); - samplesize = (sh_a->wf->wBitsPerSample+7)/8; - cbSize = extra_size; - if(extra_size > 0) - memcpy(wf+sizeof(WAVEFORMATEX),op->packet+142,extra_size); -#endif - - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "FIXME, old audio format not handled\n"); - - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - - } else { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "old header detected but stream type is unknown\n"); - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - } -} - -static void decode_text_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - int channel=0; - uint32_t *val; - buf_element_t *buf; - - lprintf ("textstream detected.\n"); - this->si[stream_num]->headers = 2; - channel = this->num_spu_streams++; - this->si[stream_num]->buf_types = BUF_SPU_OGM | channel; - - /*send an empty spu to inform the video_decoder, that there is a stream*/ - buf = this->video_fifo->buffer_pool_alloc (this->video_fifo); - buf->type = this->si[stream_num]->buf_types; - buf->pts = 0; - val = (uint32_t * )buf->content; - *val++=0; - *val++=0; - *val++=0; - this->video_fifo->put (this->video_fifo, buf); -} - -static void decode_theora_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - -#ifdef HAVE_THEORA - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ogg: Theorastreamsupport is highly alpha at the moment\n"); - - if (theora_decode_header(&this->t_info, &this->t_comment, op) >= 0) { - - this->num_video_streams++; - - this->si[stream_num]->factor = (int64_t) 90000 * (int64_t) this->t_info.fps_denominator; - - if (!this->t_info.fps_numerator) { - this->t_info.fps_numerator = 1; /* FIXME: default value ? */ - } - this->si[stream_num]->quotient = this->t_info.fps_numerator; - - this->frame_duration = ((int64_t) 90000*this->t_info.fps_denominator); - this->frame_duration /= this->t_info.fps_numerator; - - this->si[stream_num]->granuleshift = intlog(this->t_info.keyframe_frequency_force-1); - - this->si[stream_num]->headers=3; - this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; - - _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->t_info.frame_width); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->t_info.frame_height); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, this->frame_duration); - - /*currently aspect_nominator and -denumerator are 0?*/ - if (this->t_info.aspect_denominator) { - int64_t ratio = ((int64_t) this->t_info.aspect_numerator * 10000); - - ratio /= this->t_info.aspect_denominator; - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, ratio); - } - - lprintf ("decoded theora header \n"); - lprintf ("frameduration %d\n",this->frame_duration); - lprintf ("w:%d h:%d \n",this->t_info.frame_width,this->t_info.frame_height); - lprintf ("an:%d ad:%d \n",this->t_info.aspect_numerator,this->t_info.aspect_denominator); - } else { - /*Rejected stream*/ - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, - "A theora header was rejected by libtheora\n"); - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - this->si[stream_num]->headers = 0; /* FIXME: don't know */ - } -#else - this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; - this->num_video_streams++; - this->unhandled_video_streams++; - _x_meta_info_set(this->stream, XINE_META_INFO_VIDEOCODEC, "theora"); -#endif -} - -static void decode_flac_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - xine_flac_metadata_header header; - xine_flac_streaminfo_block streaminfo; - buf_element_t *buf; - xine_waveformatex wave; - - /* Packet type */ - _x_assert(op->packet[0] == 0x7F); - - /* OggFLAC signature */ - _x_assert(op->packet[1] == 'F'); _x_assert(op->packet[2] == 'L'); - _x_assert(op->packet[3] == 'A'); _x_assert(op->packet[4] == 'C'); - - /* Version: supported only 1.0 */ - _x_assert(op->packet[5] == 1); _x_assert(op->packet[6] == 0); - - /* Header count */ - this->si[stream_num]->headers = 0/*BE_16(&op->packet[7]) +1*/; - - /* fLaC signature */ - _x_assert(op->packet[9] == 'f'); _x_assert(op->packet[10] == 'L'); - _x_assert(op->packet[11] == 'a'); _x_assert(op->packet[12] == 'C'); - - _x_parse_flac_metadata_header(&op->packet[13], &header); - - switch ( header.blocktype ) { - case FLAC_BLOCKTYPE_STREAMINFO: - _x_assert(header.length == FLAC_STREAMINFO_SIZE); - _x_parse_flac_streaminfo_block(&op->packet[17], &streaminfo); - break; - } - - this->si[stream_num]->buf_types = BUF_AUDIO_FLAC - +this->num_audio_streams++; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, streaminfo.samplerate); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_CHANNELS, streaminfo.channels); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITS, streaminfo.bits_per_sample); - - this->si[stream_num]->factor = 90000; - - buf = this->audio_fifo->buffer_pool_alloc(this->audio_fifo); - - buf->type = BUF_AUDIO_FLAC; - buf->decoder_flags = BUF_FLAG_HEADER|BUF_FLAG_STDHEADER|BUF_FLAG_FRAME_END; - - buf->decoder_info[0] = 0; - buf->decoder_info[1] = streaminfo.samplerate; - buf->decoder_info[2] = streaminfo.bits_per_sample; - buf->decoder_info[3] = streaminfo.channels; - buf->size = sizeof(xine_waveformatex) + FLAC_STREAMINFO_SIZE; - memcpy(buf->content+sizeof(xine_waveformatex), &op->packet[17], FLAC_STREAMINFO_SIZE); - xine_hexdump(&op->packet[17], FLAC_STREAMINFO_SIZE); - wave.cbSize = FLAC_STREAMINFO_SIZE; - memcpy(buf->content, &wave, sizeof(xine_waveformatex)); - - this->audio_fifo->put(this->audio_fifo, buf); - - /* Skip the Ogg framing info */ - op->bytes -= 9; - op->packet += 9; -} - -static void decode_annodex_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - lprintf ("Annodex stream detected\n"); - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - this->si[stream_num]->headers = 1; - this->si[stream_num]->header_granulepos = op->granulepos; - _x_meta_info_set(this->stream, XINE_META_INFO_SYSTEMLAYER, "Annodex"); -} - -static void decode_anxdata_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - int64_t granule_rate_n, granule_rate_d; - uint32_t secondary_headers; - char content_type[1024]; - int content_type_length; - - lprintf("AnxData stream detected\n"); - - /* read granule rate */ - granule_rate_n = LE_64(&op->packet[8]); - granule_rate_d = LE_64(&op->packet[16]); - secondary_headers = LE_32(&op->packet[24]); - - lprintf("granule_rate %" PRId64 "/%" PRId64 ", %d secondary headers\n", - granule_rate_n, granule_rate_d, secondary_headers); - - /* read "Content-Tyoe" MIME header */ - sscanf(&op->packet[28], "Content-Type: %1023s\r\n", content_type); - content_type_length = strlen(content_type); - - lprintf("Content-Type: %s (length:%d)\n", content_type, content_type_length); - - /* how many header packets in the AnxData stream? */ - this->si[stream_num]->headers = secondary_headers + 1; - this->si[stream_num]->hide_first_header = 1; - - /* set factor and quotient */ - this->si[stream_num]->factor = (int64_t) 90000 * granule_rate_d; - this->si[stream_num]->quotient = granule_rate_n; - - lprintf("factor: %" PRId64 ", quotient: %" PRId64 "\n", - this->si[stream_num]->factor, this->si[stream_num]->quotient); - - /* what type of stream are we dealing with? */ - if (!strncmp(content_type, "audio/x-vorbis", content_type_length)) { - this->si[stream_num]->buf_types = BUF_AUDIO_VORBIS; - this->num_audio_streams++; - } else if (!strncmp(content_type, "audio/x-speex", content_type_length)) { - this->num_audio_streams++; -#ifdef HAVE_SPEEX - this->si[stream_num]->buf_types = BUF_AUDIO_SPEEX; -#else - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; -#endif - } else if (!strncmp(content_type, "video/x-theora", content_type_length)) { - this->num_video_streams++; -#ifdef HAVE_THEORA - this->si[stream_num]->buf_types = BUF_VIDEO_THEORA; -#else - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; -#endif - } else if (!strncmp(content_type, "text/x-cmml", content_type_length)) { - unsigned int channel = this->num_spu_streams++; - this->si[stream_num]->headers = 0; - this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; - this->si[stream_num]->granuleshift = 0; - } else { - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - } - -} - -static void decode_cmml_header (demux_ogg_t *this, const int stream_num, ogg_packet *op) { - unsigned int channel = this->num_spu_streams++; - this->si[stream_num]->headers = 0; - this->si[stream_num]->buf_types = BUF_SPU_CMML | channel; - - this->si[stream_num]->factor = 90000 * LE_64(&op->packet[20]); - this->si[stream_num]->quotient = LE_64(&op->packet[12]); - this->si[stream_num]->granuleshift = (int)op->packet[28]; -} - -/* - * interpret stream start packages, send headers - */ -static void send_header (demux_ogg_t *this) { - - int stream_num = -1; - int cur_serno; - int done = 0; - ogg_packet op; - xine_event_t ui_event; - - lprintf ("detecting stream types...\n"); - - this->ignore_keyframes = 0; - - while (!done) { - if (!read_ogg_packet(this)) { - this->status = DEMUX_FINISHED; - return; - } - /* now we've got at least one new page */ - - cur_serno = ogg_page_serialno (&this->og); - - if (ogg_page_bos(&this->og)) { - lprintf ("beginning of stream\n"); - lprintf ("serial number %d\n", cur_serno); - - if( this->num_streams == MAX_STREAMS ) { - xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); - this->status = DEMUX_FINISHED; - return; - } - stream_num = new_stream_info(this, cur_serno); - - } else { - stream_num = get_stream(this, cur_serno); - if (stream_num == -1) { - xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: stream with no beginning!\n"); - this->status = DEMUX_FINISHED; - return; - } - } - - ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); - - while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { - - if (!this->si[stream_num]->buf_types) { - - /* detect buftype */ - if (!strncmp (&op.packet[1], "vorbis", 6)) { - decode_vorbis_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[0], "Speex", 5)) { - decode_speex_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[1], "video", 5)) { - decode_video_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[1], "audio", 5)) { - decode_audio_header(this, stream_num, &op); - } else if (op.bytes >= 142 - && !strncmp (&op.packet[1], "Direct Show Samples embedded in Ogg", 35) ) { - decode_dshow_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[1], "text", 4)) { - decode_text_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[1], "theora", 6)) { - decode_theora_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[1], "FLAC", 4)) { - decode_flac_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[0], "Annodex", 7)) { - decode_annodex_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[0], "AnxData", 7)) { - decode_anxdata_header(this, stream_num, &op); - } else if (!strncmp (&op.packet[0], "CMML", 4)) { - decode_cmml_header(this, stream_num, &op); - } else { - xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, - "demux_ogg: unknown stream type (signature >%.8s<). hex dump of bos packet follows:\n", - op.packet); - if(this->stream->xine->verbosity >= XINE_VERBOSITY_DEBUG) - xine_hexdump (op.packet, op.bytes); - - this->si[stream_num]->buf_types = BUF_CONTROL_NOP; - } - } - - /* send preview buffer */ - if (this->si[stream_num]->headers > 0 || - op.packet[0] == PACKET_TYPE_COMMENT) { - if (this->si[stream_num]->hide_first_header) - this->si[stream_num]->hide_first_header = 0; - else { - lprintf ("sending preview buffer of stream type %08x\n", - this->si[stream_num]->buf_types); - - send_ogg_buf (this, &op, stream_num, BUF_FLAG_HEADER); - this->si[stream_num]->headers --; - } - } - - /* are we finished ? */ - if (!ogg_page_bos(&this->og)) { - int i; - done = 1; - - for (i=0; inum_streams; i++) { - if (this->si[i]->headers > 0) - done = 0; - - llprintf(DEBUG_PREVIEWS, - "%d preview buffers left to send from stream %d\n", - this->si[i]->headers, i); - } - } - } - } - - ui_event.type = XINE_EVENT_UI_CHANNELS_CHANGED; - ui_event.data_length = 0; - xine_event_send(this->stream, &ui_event); - - /*get the streamlength*/ - get_stream_length (this); - -} - -static int demux_ogg_send_chunk (demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; - - int stream_num; - int cur_serno; - - ogg_packet op; - - ogg_handle_event(this); - - llprintf(DEBUG_PACKETS, "send package...\n"); - - if (!read_ogg_packet(this)) { - this->status = DEMUX_FINISHED; - lprintf ("EOF\n"); - return this->status; - } - - /* now we've got one new page */ - - cur_serno = ogg_page_serialno (&this->og); - stream_num = get_stream(this, cur_serno); - if (stream_num < 0) { - lprintf ("error: unknown stream, serialnumber %d\n", cur_serno); - - if (!ogg_page_bos(&this->og)) { - lprintf ("help, stream with no beginning!\n"); - } - lprintf ("adding late stream with serial number %d (all content will be discarded)\n", cur_serno); - - if( this->num_streams == MAX_STREAMS ) { - xprintf (this->stream->xine, XINE_VERBOSITY_LOG, "demux_ogg: MAX_STREAMS exceeded, aborting.\n"); - this->status = DEMUX_FINISHED; - return this->status; - } - stream_num = new_stream_info(this, cur_serno); - } - - ogg_stream_pagein(&this->si[stream_num]->oss, &this->og); - - if (ogg_page_bos(&this->og)) { - lprintf ("beginning of stream: serial number %d - discard\n", - ogg_page_serialno (&this->og)); - while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) ; - return this->status; - } - - /*while keyframeseeking only process videostream*/ - if (!this->ignore_keyframes && this->keyframe_needed - && ((this->si[stream_num]->buf_types & 0xFF000000) != BUF_VIDEO_BASE)) - return this->status; - - while (ogg_stream_packetout(&this->si[stream_num]->oss, &op) == 1) { - /* printf("demux_ogg: packet: %.8s\n", op.packet); */ - /* printf("demux_ogg: got a packet\n"); */ - - if ((*op.packet & PACKET_TYPE_HEADER) && - (this->si[stream_num]->buf_types!=BUF_VIDEO_THEORA) && (this->si[stream_num]->buf_types!=BUF_AUDIO_SPEEX) && (this->si[stream_num]->buf_types!=BUF_AUDIO_FLAC)) { - if (op.granulepos != -1) { - this->si[stream_num]->header_granulepos = op.granulepos; - lprintf ("header with granulepos, remembering granulepos\n"); - } else { - lprintf ("header => discard\n"); - } - continue; - } - - /*discard granulepos-less packets and to early audiopackets*/ - if (this->si[stream_num]->resync) { - if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_SPU_BASE) { - /*never drop subtitles*/ - this->si[stream_num]->resync=0; - } else if ((op.granulepos == -1) && (this->si[stream_num]->header_granulepos == -1)) { - continue; - } else { - - /*dump too early packets*/ - if ((get_pts(this,stream_num,op.granulepos)-this->start_pts) > -90000) - this->si[stream_num]->resync=0; - else - continue; - } - } - - if (!this->ignore_keyframes && this->keyframe_needed) { - lprintf ("keyframe needed... buf_type=%08x\n", this->si[stream_num]->buf_types); - if (this->si[stream_num]->buf_types == BUF_VIDEO_THEORA) { -#ifdef HAVE_THEORA - - int keyframe_granule_shift; - int64_t pframe=-1,iframe=-1; - - keyframe_granule_shift = this->si[stream_num]->granuleshift; - - if(op.granulepos>=0){ - iframe=op.granulepos>>keyframe_granule_shift; - pframe=op.granulepos-(iframe<stream->xine, XINE_VERBOSITY_DEBUG, - "seeking keyframe i %" PRId64 " p %" PRId64 "\n", iframe, pframe); - if (pframe!=0) - continue; - } else - continue; - this->keyframe_needed = 0; - this->start_pts=get_pts(this,stream_num,op.granulepos); -#endif - } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) { - - /*calculate the current pts*/ - if (op.granulepos!=-1) { - this->start_pts=get_pts(this, stream_num, op.granulepos); - } else if (this->start_pts!=-1) - this->start_pts=this->start_pts+this->frame_duration; - - /*seek the keyframe*/ - if ((*op.packet == PACKET_IS_SYNCPOINT) && (this->start_pts!=-1)) - this->keyframe_needed = 0; - else - continue; - - } else if ((this->si[stream_num]->buf_types & 0xFF000000) == BUF_VIDEO_BASE) continue; - } - send_ogg_buf (this, &op, stream_num, 0); - - /*delete used header_granulepos*/ - if (op.granulepos == -1) - this->si[stream_num]->header_granulepos = -1; - - } - if (ogg_page_eos(&this->og)) { - int i; - int finished_streams = 0; - - lprintf("end of stream, serialnumber %d\n", cur_serno); - this->si[stream_num]->delivered_eos = 1; - - /* check if all logical streams are finished */ - for (i = 0; i < this->num_streams; i++) { - finished_streams += this->si[i]->delivered_eos; - } - - /* if all streams are finished, perhaps a chained stream follows */ - if (finished_streams == this->num_streams) { - /* delete current logical streams */ - for (i = 0; i < this->num_streams; i++) { - ogg_stream_clear(&this->si[i]->oss); - if (this->si[i]->language) { - free (this->si[i]->language); - } - free (this->si[i]); - } - this->num_streams = 0; - this->num_audio_streams = 0; - this->num_video_streams = 0; - this->unhandled_video_streams = 0; - this->num_spu_streams = 0; - this->avg_bitrate = 1; - - /* try to read a chained stream */ - this->send_newpts = 1; - this->last_pts[0] = 0; - this->last_pts[1] = 0; - - /* send control buffer to avoid buffer leak */ - _x_demux_control_end(this->stream, 0); - _x_demux_control_start(this->stream); - send_header(this); - } - } - - return this->status; -} - -static void demux_ogg_dispose (demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; - int i; - - for (i=0; inum_streams; i++) { - ogg_stream_clear(&this->si[i]->oss); - - if (this->si[i]->language) { - free (this->si[i]->language); - } - free(this->si[i]); - } - - ogg_sync_clear(&this->oy); - -#ifdef HAVE_THEORA - theora_comment_clear (&this->t_comment); - theora_info_clear (&this->t_info); -#endif - - if (this->chapter_info){ - free (this->chapter_info->entries); - free (this->chapter_info); - } - if (this->title){ - free (this->title); - } - if (this->event_queue) - xine_event_dispose_queue (this->event_queue); - - free (this); -} - -static int demux_ogg_get_status (demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; - - return this->status; -} - -static void demux_ogg_send_headers (demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; - - this->video_fifo = this->stream->video_fifo; - this->audio_fifo = this->stream->audio_fifo; - - this->status = DEMUX_OK; - - /* - * send start buffers - */ - - this->last_pts[0] = 0; - this->last_pts[1] = 0; - - /* - * initialize ogg engine - */ - ogg_sync_init(&this->oy); - - this->num_streams = 0; - this->num_audio_streams = 0; - this->num_video_streams = 0; - this->num_spu_streams = 0; - this->avg_bitrate = 1; - - this->input->seek (this->input, 0, SEEK_SET); - - if (this->status == DEMUX_OK) { - _x_demux_control_start(this->stream); - send_header (this); - lprintf ("headers sent, avg bitrate is %" PRId64 "\n", this->avg_bitrate); - } - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_VIDEO, - this->num_video_streams > 0); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HANDLED, - this->num_video_streams > this->unhandled_video_streams); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_HAS_AUDIO, - this->num_audio_streams > 0); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_MAX_SPU_CHANNEL, - this->num_spu_streams); -} - -static int demux_ogg_seek (demux_plugin_t *this_gen, - off_t start_pos, int start_time, int playing) { - - demux_ogg_t *this = (demux_ogg_t *) this_gen; - int i; - start_time /= 1000; - start_pos = (off_t) ( (double) start_pos / 65535 * - this->input->get_length (this->input) ); - /* - * seek to start position - */ - - if (INPUT_IS_SEEKABLE(this->input)) { - - this->keyframe_needed = (this->num_video_streams>0); - - if ( (!start_pos) && (start_time)) { - if (this->time_length != -1) { - /*do the seek via time*/ - int current_time=-1; - off_t current_pos; - current_pos=this->input->get_current_pos(this->input); - - /*try to find out the current time*/ - if (this->last_pts[PTS_VIDEO]) { - current_time=this->last_pts[PTS_VIDEO]/90000; - } else if (this->last_pts[PTS_AUDIO]) { - current_time=this->last_pts[PTS_AUDIO]/90000; - } - - /*fixme, the file could grow, do something - about this->time_length using get_lenght to verify, that the stream - hasn` changed its length, otherwise no seek to "new" data is possible*/ - - lprintf ("seek to time %d called\n",start_time); - lprintf ("current time is %d\n",current_time); - - if (current_time > start_time) { - /*seek between beginning and current_pos*/ - - /*fixme - sometimes we seek backwards and during - keyframeseeking, we undo the seek*/ - - start_pos = start_time * current_pos - / current_time ; - } else { - /*seek between current_pos and end*/ - start_pos = current_pos + - ((start_time - current_time) * - ( this->input->get_length(this->input) - current_pos ) / - ( (this->time_length / 1000) - current_time) - ); - } - - lprintf ("current_pos is %" PRId64 "\n",current_pos); - lprintf ("new_pos is %" PRId64 "\n",start_pos); - - } else { - /*seek using avg_bitrate*/ - start_pos = start_time * this->avg_bitrate/8; - } - - lprintf ("seeking to %d seconds => %" PRId64 " bytes\n", - start_time, start_pos); - - } - - ogg_sync_reset(&this->oy); - - for (i=0; inum_streams; i++) { - this->si[i]->header_granulepos = -1; - ogg_stream_reset(&this->si[i]->oss); - } - - /*some strange streams have no syncpoint flag set at the beginning*/ - if (start_pos == 0) - this->keyframe_needed = 0; - - lprintf ("seek to %" PRId64 " called\n",start_pos); - - this->input->seek (this->input, start_pos, SEEK_SET); - - } - - /* fixme - this would be a nice position to do the following tasks - 1. adjust an ogg videostream to a keyframe - 2. compare the keyframe_pts with start_time. if the difference is to - high (e.g. larger than max keyframe_intervall, do a new seek or - continue reading - 3. adjust the audiostreams in such a way, that the - difference is not to high. - - In short words, do all the cleanups necessary to continue playback - without further actions - */ - - this->send_newpts = 1; - this->status = DEMUX_OK; - - if( !playing ) { - - this->buf_flag_seek = 0; - - } else { - if (start_pos!=0) { - this->buf_flag_seek = 1; - /*each stream has to continue with a packet that has an - granulepos*/ - for (i=0; inum_streams; i++) { - this->si[i]->resync = 1; - } - - this->start_pts=-1; - } - - _x_demux_flush_engine(this->stream); - } - - return this->status; -} - -static int demux_ogg_get_stream_length (demux_plugin_t *this_gen) { - - demux_ogg_t *this = (demux_ogg_t *) this_gen; - - if (this->time_length==-1){ - if (this->avg_bitrate) { - return (int)((int64_t)1000 * this->input->get_length (this->input) * 8 / - this->avg_bitrate); - } else { - return 0; - } - } else { - return this->time_length; - } -} - -static uint32_t demux_ogg_get_capabilities(demux_plugin_t *this_gen) { - demux_ogg_t *this = (demux_ogg_t *) this_gen; - int cap_chapter = 0; - - if (this->chapter_info) - cap_chapter = DEMUX_CAP_CHAPTERS; - - return DEMUX_CAP_SPULANG | DEMUX_CAP_AUDIOLANG | cap_chapter; -} - -static int format_lang_string (demux_ogg_t * this, uint32_t buf_mask, uint32_t buf_type, int channel, char *str) { - int stream_num; - - for (stream_num=0; stream_numnum_streams; stream_num++) { - if ((this->si[stream_num]->buf_types & buf_mask) == buf_type) { - if (this->si[stream_num]->language) { - if (snprintf (str, XINE_LANG_MAX, "%s", this->si[stream_num]->language) >= XINE_LANG_MAX) - /* the string got truncated */ - str[XINE_LANG_MAX - 2] = str[XINE_LANG_MAX - 3] = str[XINE_LANG_MAX - 4] = '.'; - /* TODO: provide long version in XINE_META_INFO_FULL_LANG */ - } else { - snprintf(str, XINE_LANG_MAX, "channel %d",channel); - } - return DEMUX_OPTIONAL_SUCCESS; - } - } - return DEMUX_OPTIONAL_UNSUPPORTED; -} - -static int demux_ogg_get_optional_data(demux_plugin_t *this_gen, - void *data, int data_type) { - - demux_ogg_t *this = (demux_ogg_t *) this_gen; - - char *str=(char *) data; - int channel = *((int *)data); - - switch (data_type) { - case DEMUX_OPTIONAL_DATA_SPULANG: - lprintf ("DEMUX_OPTIONAL_DATA_SPULANG channel = %d\n",channel); - if (channel==-1) { - strcpy( str, "none"); - return DEMUX_OPTIONAL_SUCCESS; - } else if ((channel>=0) && (channelnum_streams)) { - return format_lang_string (this, 0xFFFFFFFF, BUF_SPU_OGM+channel, channel, str); - } - return DEMUX_OPTIONAL_UNSUPPORTED; - case DEMUX_OPTIONAL_DATA_AUDIOLANG: - lprintf ("DEMUX_OPTIONAL_DATA_AUDIOLANG channel = %d\n",channel); - if (channel==-1) { - return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE, channel, str); - } else if ((channel>=0) && (channelnum_streams)) { - return format_lang_string (this, 0xFF00001F, BUF_AUDIO_BASE+channel, channel, str); - } - return DEMUX_OPTIONAL_UNSUPPORTED; - default: - return DEMUX_OPTIONAL_UNSUPPORTED; - } -} - -static int detect_ogg_content (int detection_method, demux_class_t *class_gen, - input_plugin_t *input) { - - switch (detection_method) { - - case METHOD_BY_CONTENT: { - uint8_t buf[4]; - - if (_x_demux_read_header(input, buf, 4) != 4) - return 0; - - if ((buf[0] == 'O') && (buf[1] == 'g') && (buf[2] == 'g') && - (buf[3] == 'S')) - return 1; - else - return 0; - } - - case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); - - if (_x_demux_check_extension (mrl, extensions)) - return 1; - else - return 0; - } - - case METHOD_EXPLICIT: - return 1; - - default: - return 0; - } -} - -static int detect_anx_content (int detection_method, demux_class_t *class_gen, - input_plugin_t *input) { - - if (detect_ogg_content(detection_method, class_gen, input) == 0) - return 0; - - switch (detection_method) { - -#define ANNODEX_SIGNATURE_SEARCH 128 - - case METHOD_BY_CONTENT: { - uint8_t buf[ANNODEX_SIGNATURE_SEARCH]; - int found_annodex_signature = 0; - const char *annodex_signature = "Annodex"; - int annodex_signature_length = 7; /* = strlen(annodex_signature) */ - int i, j; - - if (_x_demux_read_header(input, buf, ANNODEX_SIGNATURE_SEARCH) != - ANNODEX_SIGNATURE_SEARCH) - return 0; - - /* scan for 'Annodex' signature in the first 64 bytes */ - for (i = 0, j = 0; i < ANNODEX_SIGNATURE_SEARCH; i++) { - if (buf[i] == annodex_signature[j]) { - if (j >= annodex_signature_length) { - /* found signature */ - found_annodex_signature = 1; - break; - } else { - j++; - } - } - } - - if (found_annodex_signature) - return 1; - else - return 0; - } - -#undef ANNODEX_SIGNATURE_SEARCH - - case METHOD_BY_EXTENSION: { - const char *extensions, *mrl; - - mrl = input->get_mrl (input); - extensions = class_gen->get_extensions (class_gen); - - if (_x_demux_check_extension (mrl, extensions)) - return 1; - else - return 0; - } - - case METHOD_EXPLICIT: - return 1; - - default: - return 0; - } -} - -static demux_plugin_t *anx_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, - input_plugin_t *input) { - - demux_ogg_t *this; - - if (detect_anx_content(stream->content_detection_method, class_gen, input) == 0) - return NULL; - - /* - * if we reach this point, the input has been accepted. - */ - - this = xine_xmalloc (sizeof (demux_ogg_t)); - memset (this, 0, sizeof(demux_ogg_t)); - this->stream = stream; - this->input = input; - - /* the Annodex demuxer currently calls into exactly the same functions as - * the Ogg demuxer, which seems to make this function a bit redundant, but - * this design leaves us a bit more room to change an Annodex demuxer's - * behaviour in the future if necessary */ - this->demux_plugin.send_headers = demux_ogg_send_headers; - this->demux_plugin.send_chunk = demux_ogg_send_chunk; - this->demux_plugin.seek = demux_ogg_seek; - this->demux_plugin.dispose = demux_ogg_dispose; - this->demux_plugin.get_status = demux_ogg_get_status; - this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; - this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; - this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; - this->demux_plugin.demux_class = class_gen; - - this->status = DEMUX_FINISHED; - -#ifdef HAVE_THEORA - theora_info_init (&this->t_info); - theora_comment_init (&this->t_comment); -#endif - - this->chapter_info = 0; - this->title = 0; - this->event_queue = xine_event_new_queue (this->stream); - - return &this->demux_plugin; -} - -static demux_plugin_t *ogg_open_plugin (demux_class_t *class_gen, - xine_stream_t *stream, - input_plugin_t *input) { - - demux_ogg_t *this; - - if (detect_ogg_content(stream->content_detection_method, class_gen, input) == 0) - return NULL; - - /* - * if we reach this point, the input has been accepted. - */ - - this = xine_xmalloc (sizeof (demux_ogg_t)); - memset (this, 0, sizeof(demux_ogg_t)); - this->stream = stream; - this->input = input; - - this->demux_plugin.send_headers = demux_ogg_send_headers; - this->demux_plugin.send_chunk = demux_ogg_send_chunk; - this->demux_plugin.seek = demux_ogg_seek; - this->demux_plugin.dispose = demux_ogg_dispose; - this->demux_plugin.get_status = demux_ogg_get_status; - this->demux_plugin.get_stream_length = demux_ogg_get_stream_length; - this->demux_plugin.get_capabilities = demux_ogg_get_capabilities; - this->demux_plugin.get_optional_data = demux_ogg_get_optional_data; - this->demux_plugin.demux_class = class_gen; - - this->status = DEMUX_FINISHED; - -#ifdef HAVE_THEORA - theora_info_init (&this->t_info); - theora_comment_init (&this->t_comment); -#endif - - this->chapter_info = 0; - this->title = 0; - this->event_queue = xine_event_new_queue (this->stream); - - return &this->demux_plugin; -} - -/* - * Annodex demuxer class - */ - -static const char *anx_get_description (demux_class_t *this_gen) { - return "Annodex demux plugin"; -} - -static const char *anx_get_identifier (demux_class_t *this_gen) { - return "Annodex"; -} - -static const char *anx_get_extensions (demux_class_t *this_gen) { - return "anx axa axv"; -} - -static const char *anx_get_mimetypes (demux_class_t *this_gen) { - return "application/x-annodex: ogg: Annodex media;"; -} - -static void anx_class_dispose (demux_class_t *this_gen) { - demux_anx_class_t *this = (demux_anx_class_t *) this_gen; - - free (this); -} - -static void *anx_init_class (xine_t *xine, void *data) { - demux_anx_class_t *this; - - this = xine_xmalloc (sizeof (demux_anx_class_t)); - - this->demux_class.open_plugin = anx_open_plugin; - this->demux_class.get_description = anx_get_description; - this->demux_class.get_identifier = anx_get_identifier; - this->demux_class.get_mimetypes = anx_get_mimetypes; - this->demux_class.get_extensions = anx_get_extensions; - this->demux_class.dispose = anx_class_dispose; - - return this; -} - -/* - * ogg demuxer class - */ - -static const char *ogg_get_description (demux_class_t *this_gen) { - return "OGG demux plugin"; -} - -static const char *ogg_get_identifier (demux_class_t *this_gen) { - return "OGG"; -} - -static const char *ogg_get_extensions (demux_class_t *this_gen) { - return "ogg ogm spx"; -} - -static const char *ogg_get_mimetypes (demux_class_t *this_gen) { - return "audio/x-ogg: ogg: OggVorbis Audio;" - "audio/x-speex: ogg: Speex Audio;" - "application/x-ogg: ogg: Ogg Stream;" - "application/ogg: ogg: Ogg Stream;"; -} - -static void ogg_class_dispose (demux_class_t *this_gen) { - demux_ogg_class_t *this = (demux_ogg_class_t *) this_gen; - - free (this); -} - -static void *ogg_init_class (xine_t *xine, void *data) { - demux_ogg_class_t *this; - - this = xine_xmalloc (sizeof (demux_ogg_class_t)); - - this->demux_class.open_plugin = ogg_open_plugin; - this->demux_class.get_description = ogg_get_description; - this->demux_class.get_identifier = ogg_get_identifier; - this->demux_class.get_mimetypes = ogg_get_mimetypes; - this->demux_class.get_extensions = ogg_get_extensions; - this->demux_class.dispose = ogg_class_dispose; - - return this; -} - -/* - * exported plugin catalog entry - */ -static const demuxer_info_t demux_info_anx = { - 20 /* priority */ -}; - -static const demuxer_info_t demux_info_ogg = { - 10 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_DEMUX, 26, "ogg", XINE_VERSION_CODE, &demux_info_ogg, ogg_init_class }, - { PLUGIN_DEMUX, 26, "anx", XINE_VERSION_CODE, &demux_info_anx, anx_init_class }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/src/libxineadec/Makefile.am b/src/libxineadec/Makefile.am index 82099d659..c552d9a08 100644 --- a/src/libxineadec/Makefile.am +++ b/src/libxineadec/Makefile.am @@ -5,14 +5,6 @@ AM_LDFLAGS = $(xineplug_ldflags) EXTRA_DIST = fooaudio.c -if ENABLE_VORBIS -vorbis_module = xineplug_decode_vorbis.la -endif - -if ENABLE_SPEEX -speex_module = xineplug_decode_speex.la -endif - if ENABLE_MUSEPACK musepack_module = xineplug_decode_mpc.la endif @@ -54,8 +46,6 @@ $(top_builddir)/contrib/gsm610/libgsm610.la: xineplug_LTLIBRARIES = \ xineplug_decode_gsm610.la \ xineplug_decode_lpcm.la \ - $(vorbis_module) \ - $(speex_module) \ $(musepack_module) \ $(dts_module) \ $(mad_module) \ @@ -69,14 +59,6 @@ xineplug_decode_gsm610_la_CPPFLAGS = -I$(top_srcdir)/contrib/gsm610 xineplug_decode_lpcm_la_SOURCES = xine_lpcm_decoder.c xineplug_decode_lpcm_la_LIBADD = $(XINE_LIB) -xineplug_decode_vorbis_la_SOURCES = xine_vorbis_decoder.c -xineplug_decode_vorbis_la_LIBADD = $(XINE_LIB) $(VORBIS_LIBS) $(OGG_LIBS) -xineplug_decode_vorbis_la_CFLAGS = $(AM_CFLAGS) $(VORBIS_CFLAGS) - -xineplug_decode_speex_la_SOURCES = xine_speex_decoder.c -xineplug_decode_speex_la_LIBADD = $(XINE_LIB) $(SPEEX_LIBS) -xineplug_decode_speex_la_CFLAGS = $(AM_CFLAGS) $(SPEEX_CFLAGS) - xineplug_decode_mpc_la_SOURCES = xine_musepack_decoder.c xineplug_decode_mpc_la_DEPENDENCIES = $(MPCDEC_DEPS) xineplug_decode_mpc_la_LIBADD = $(XINE_LIB) $(MPCDEC_LIBS) diff --git a/src/libxineadec/xine_speex_decoder.c b/src/libxineadec/xine_speex_decoder.c deleted file mode 100644 index 034e726a6..000000000 --- a/src/libxineadec/xine_speex_decoder.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Copyright (C) 2000-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id: xine_decoder.c,v 1.22 2007/01/19 01:48:05 dgp85 Exp $ - * - * (ogg/)speex audio decoder plugin (libspeex wrapper) for xine - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#define LOG_MODULE "speex_decoder" -#define LOG_VERBOSE -/* -#define LOG -*/ -#define LOG_BUFFERS 0 - -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" - -#include - -#include -#include -#include -#include - -#define MAX_FRAME_SIZE 2000 - -typedef struct { - audio_decoder_class_t decoder_class; -} speex_class_t; - -typedef struct speex_decoder_s { - audio_decoder_t audio_decoder; - - int64_t pts; - - int output_sampling_rate; - int output_open; - int output_mode; - - /* speex stuff */ - void *st; - int frame_size; - int rate; - int nframes; - int channels; - SpeexBits bits; - SpeexStereoState stereo; - int expect_metadata; - - int header_count; - - xine_stream_t *stream; - -} speex_decoder_t; - - -static void speex_reset (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - speex_bits_init (&this->bits); -} - -static void speex_discontinuity (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - this->pts=0; -} - -/* Known speex comment keys from ogg123 sources*/ -static struct { - char *key; /* includes the '=' for programming convenience */ - int xine_metainfo_index; -} speex_comment_keys[] = { - {"ARTIST=", XINE_META_INFO_ARTIST}, - {"ALBUM=", XINE_META_INFO_ALBUM}, - {"TITLE=", XINE_META_INFO_TITLE}, - {"GENRE=", XINE_META_INFO_GENRE}, - {"DESCRIPTION=", XINE_META_INFO_COMMENT}, - {"DATE=", XINE_META_INFO_YEAR}, - {NULL, 0} -}; - -#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ - ((buf[base+2]<<16)&0xff0000)| \ - ((buf[base+1]<<8)&0xff00)| \ - (buf[base]&0xff)) - -static -void read_metadata (speex_decoder_t *this, char * comments, int length) -{ - char * c = comments; - int len, i, nb_fields; - char * end; - - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "speex"); - - if (length < 8) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - end = c+length; - len = readint (c, 0); - c += 4; - - if (c+len > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - -#ifdef LOG - /* Encoder */ - printf ("libspeex: "); - fwrite (c, 1, len, stdout); - printf ("\n"); -#endif - - c += len; - - if (c+4 > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - nb_fields = readint (c, 0); - c += 4; - - for (i = 0; i < nb_fields; i++) { - if (c+4 > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - - len = readint (c, 0); - c += 4; - if (c+len > end) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: invalid/corrupted comments\n"); - return; - } - -#ifdef LOG - printf ("libspeex: "); - fwrite (c, 1, len, stdout); - printf ("\n"); -#endif - - for (i = 0; speex_comment_keys[i].key != NULL; i++) { - - if ( !strncasecmp (speex_comment_keys[i].key, c, - strlen(speex_comment_keys[i].key)) ) { - int keylen = strlen(speex_comment_keys[i].key); - char meta_info[(len - keylen) + 1]; - - lprintf ("known metadata %d %d\n", - i, speex_comment_keys[i].xine_metainfo_index); - - snprintf(meta_info, (len - keylen), "%s", c + keylen); - _x_meta_info_set_utf8(this->stream, speex_comment_keys[i].xine_metainfo_index, meta_info); - } - } - - c += len; - } -} - -static void speex_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - llprintf (LOG_BUFFERS, "decode buf=%8p content=%8p flags=%08x\n", - buf, buf->content, buf->decoder_flags); - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - lprintf ("preview buffer, %d headers to go\n", this->header_count); - - if (this->header_count) { - - if (!this->st) { - SpeexMode * spx_mode; - SpeexHeader * spx_header; - int modeID; - int bitrate; - - speex_bits_init (&this->bits); - - spx_header = speex_packet_to_header (buf->content, buf->size); - - if (!spx_header) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: could not read Speex header\n"); - return; - } - - modeID = spx_header->mode; - spx_mode = (SpeexMode *) speex_mode_list[modeID]; - - if (spx_mode->bitstream_version != spx_header->mode_bitstream_version) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: incompatible Speex mode bitstream version\n"); - return; - } - - this->st = speex_decoder_init (spx_mode); - if (!this->st) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: decoder initialization failed\n"); - return; - } - - this->rate = spx_header->rate; - speex_decoder_ctl (this->st, SPEEX_SET_SAMPLING_RATE, &this->rate); - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_SAMPLERATE, - this->rate); - - this->channels = spx_header->nb_channels; - if (this->channels == 2) { - SpeexCallback callback; - - callback.callback_id = SPEEX_INBAND_STEREO; - callback.func = speex_std_stereo_request_handler; - callback.data = &this->stereo; - speex_decoder_ctl (this->st, SPEEX_SET_HANDLER, &callback); - } - - this->nframes = spx_header->frames_per_packet; - if (!this->nframes) this->nframes = 1; - - speex_decoder_ctl (this->st, SPEEX_GET_FRAME_SIZE, &this->frame_size); - - speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); - if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); - - this->header_count += spx_header->extra_headers; - this->expect_metadata = 1; - - free (spx_header); - } else if (this->expect_metadata) { - read_metadata (this, buf->content, buf->size); - } - - this->header_count--; - - if (!this->header_count) { - int mode = _x_ao_channels2mode(this->channels); - - if (!this->output_open) { - this->output_open = - this->stream->audio_out->open(this->stream->audio_out, - this->stream, - 16, - this->rate, - mode); - lprintf ("this->output_open after attempt is %d\n", this->output_open); - } - } - } - - } else if (this->output_open) { - int i, j; - - audio_buffer_t *audio_buffer; - - audio_buffer = - this->stream->audio_out->get_buffer (this->stream->audio_out); - - speex_bits_read_from (&this->bits, buf->content, buf->size); - - for (j = 0; j < this->nframes; j++) { - int ret; - int bitrate; - - ret = speex_decode_int (this->st, &this->bits, audio_buffer->mem); - - if (ret==-1) - break; - if (ret==-2) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding error, corrupted stream?\n"); - break; - } - if (speex_bits_remaining(&this->bits)<0) { - xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, "libspeex: Decoding overflow, corrupted stream?\n"); - break; - } - - if (this->channels == 2) { - speex_decode_stereo_int (audio_buffer->mem, this->frame_size, &this->stereo); - } - - speex_decoder_ctl (this->st, SPEEX_GET_BITRATE, &bitrate); - if (bitrate <= 1) bitrate = 16000; /* assume 16 kbit */ - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, bitrate); - - audio_buffer->vpts = this->pts; - this->pts=0; - audio_buffer->num_frames = this->frame_size; - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - buf->pts=0; - - } - } - else { - llprintf (LOG_BUFFERS, "output not open\n"); - } -} - -static void speex_dispose (audio_decoder_t *this_gen) { - - speex_decoder_t *this = (speex_decoder_t *) this_gen; - - if (this->st) { - speex_decoder_destroy (this->st); - } - speex_bits_destroy (&this->bits); - - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - - free (this_gen); -} - -static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, - xine_stream_t *stream) { - - speex_decoder_t *this ; - static SpeexStereoState init_stereo = SPEEX_STEREO_STATE_INIT; - - this = (speex_decoder_t *) xine_xmalloc (sizeof (speex_decoder_t)); - - this->audio_decoder.decode_data = speex_decode_data; - this->audio_decoder.reset = speex_reset; - this->audio_decoder.discontinuity = speex_discontinuity; - this->audio_decoder.dispose = speex_dispose; - this->stream = stream; - - this->output_open = 0; - this->header_count = 1; - this->expect_metadata = 0; - - this->st = NULL; - - this->channels = 1; - - memcpy (&this->stereo, &init_stereo, sizeof (SpeexStereoState)); - - return (audio_decoder_t *) this; -} - -/* - * speex plugin class - */ - -static char *get_identifier (audio_decoder_class_t *this) { - return "speex"; -} - -static char *get_description (audio_decoder_class_t *this) { - return "Speex audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - - speex_class_t *this; - - this = (speex_class_t *) xine_xmalloc (sizeof (speex_class_t)); - - this->decoder_class.open_plugin = open_plugin; - this->decoder_class.get_identifier = get_identifier; - this->decoder_class.get_description = get_description; - this->decoder_class.dispose = dispose_class; - - return this; -} - -static uint32_t audio_types[] = { - BUF_AUDIO_SPEEX, 0 - }; - -static const decoder_info_t dec_info_audio = { - audio_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_DECODER, 15, "speex", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/src/libxineadec/xine_vorbis_decoder.c b/src/libxineadec/xine_vorbis_decoder.c deleted file mode 100644 index 7fc1b9197..000000000 --- a/src/libxineadec/xine_vorbis_decoder.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2000-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id: xine_decoder.c,v 1.48 2006/12/04 13:59:38 dgp85 Exp $ - * - * (ogg/)vorbis audio decoder plugin (libvorbis wrapper) for xine - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#define LOG_MODULE "vorbis_decoder" -#define LOG_VERBOSE -/* -#define LOG -*/ - -#include "xine_internal.h" -#include "audio_out.h" -#include "buffer.h" - -#include -#include - -#define MAX_NUM_SAMPLES 4096 - -typedef struct { - audio_decoder_class_t decoder_class; -} vorbis_class_t; - -typedef struct vorbis_decoder_s { - audio_decoder_t audio_decoder; - - int64_t pts; - - int output_sampling_rate; - int output_open; - int output_mode; - - ogg_packet op; /* we must use this struct to sent data to libvorbis */ - - /* vorbis stuff */ - vorbis_info vi; /* stores static vorbis bitstream settings */ - vorbis_comment vc; - vorbis_dsp_state vd; /* central working state for packet->PCM decoder */ - vorbis_block vb; /* local working state for packet->PCM decoder */ - - int16_t convbuffer[MAX_NUM_SAMPLES]; - int convsize; - - int header_count; - - xine_stream_t *stream; - -} vorbis_decoder_t; - - -static void vorbis_reset (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - if( !this->header_count ) - vorbis_block_init(&this->vd,&this->vb); -} - -static void vorbis_discontinuity (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - this->pts=0; -} - -/* Known vorbis comment keys from ogg123 sources*/ -static const struct { - const char *key; /* includes the '=' for programming convenience */ - int xine_metainfo_index; -} vorbis_comment_keys[] = { - {"ARTIST=", XINE_META_INFO_ARTIST}, - {"ALBUM=", XINE_META_INFO_ALBUM}, - {"TITLE=", XINE_META_INFO_TITLE}, - {"GENRE=", XINE_META_INFO_GENRE}, - {"DESCRIPTION=", XINE_META_INFO_COMMENT}, - {"COMMENT=", XINE_META_INFO_COMMENT}, - {"DATE=", XINE_META_INFO_YEAR}, - {"TRACKNUMBER=", XINE_META_INFO_TRACK_NUMBER}, - {NULL, 0} -}; - -static void get_metadata (vorbis_decoder_t *this) { - - char **ptr=this->vc.user_comments; - while(*ptr){ - - char *comment = *ptr; - int i; - - lprintf("%s\n", comment); - - for (i = 0; vorbis_comment_keys[i].key != NULL; i++) { - - if ( !strncasecmp (vorbis_comment_keys[i].key, comment, - strlen(vorbis_comment_keys[i].key)) ) { - - lprintf ("known metadata %d %d\n", - i, vorbis_comment_keys[i].xine_metainfo_index); - - _x_meta_info_set_utf8(this->stream, vorbis_comment_keys[i].xine_metainfo_index, - comment + strlen(vorbis_comment_keys[i].key)); - - } - } - ++ptr; - } - - _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "vorbis"); -} - -static void vorbis_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - memset( &this->op, 0, sizeof(this->op) ); - this->op.packet = buf->content; - this->op.bytes = buf->size; - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - lprintf ("%d headers to go\n", this->header_count); - - if (this->header_count) { - int res = 0; - - if (this->header_count == 3) - this->op.b_o_s = 1; - - - if( (res = vorbis_synthesis_headerin(&this->vi,&this->vc,&this->op)) < 0 ){ - /* error case; not a vorbis header */ - xine_log(this->stream->xine, XINE_LOG_MSG, "libvorbis: this bitstream does not contain vorbis audio data. Following first 64 bytes (return: %d).\n", res); - xine_hexdump(this->op.packet, this->op.bytes < 64 ? this->op.bytes : 64); - return; - } - - this->header_count--; - - if (!this->header_count) { - - int mode = AO_CAP_MODE_MONO; - - get_metadata (this); - - mode = _x_ao_channels2mode(this->vi.channels); - - this->convsize=MAX_NUM_SAMPLES/this->vi.channels; - - if (!this->output_open) { - this->output_open = this->stream->audio_out->open(this->stream->audio_out, - this->stream, - 16, - this->vi.rate, - mode) ; - - _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_BITRATE, - this->vi.bitrate_nominal); - - } - - /* OK, got and parsed all three headers. Initialize the Vorbis - * packet->PCM decoder. */ - lprintf("all three headers parsed. initializing decoder.\n"); - /* initialize central decode state */ - vorbis_synthesis_init(&this->vd,&this->vi); - /* initialize local state for most of the decode so multiple - * block decodes can proceed in parallel. We could init - * multiple vorbis_block structures for vd here */ - vorbis_block_init(&this->vd,&this->vb); - } - } - - } else if (this->output_open) { - - float **pcm; - int samples; - - if(vorbis_synthesis(&this->vb,&this->op)==0) - vorbis_synthesis_blockin(&this->vd,&this->vb); - - if (buf->pts!=0) - this->pts=buf->pts; - - while ((samples=vorbis_synthesis_pcmout(&this->vd,&pcm))>0){ - - /* **pcm is a multichannel float vector. In stereo, for - * example, pcm[0][...] is left, and pcm[1][...] is right. - * samples is the size of each channel. Convert the float - * values (-1.<=range<=1.) to whatever PCM format and write - * it out - */ - - int i,j; - int clipflag=0; - int bout=(samplesconvsize?samples:this->convsize); - audio_buffer_t *audio_buffer; - - audio_buffer = this->stream->audio_out->get_buffer (this->stream->audio_out); - - /* convert floats to 16 bit signed ints (host order) and - interleave */ - for(i=0;ivi.channels;i++){ - ogg_int16_t *ptr=audio_buffer->mem+i; - float *mono=pcm[i]; - for(j=0;j32767){ - val=32767; - clipflag=1; - } - if(val<-32768){ - val=-32768; - clipflag=1; - } - *ptr=val; - ptr+=this->vi.channels; - } - } - - audio_buffer->vpts = this->pts; - this->pts=0; - audio_buffer->num_frames = bout; - - this->stream->audio_out->put_buffer (this->stream->audio_out, audio_buffer, this->stream); - - buf->pts=0; - - /* tell libvorbis how many samples we actually consumed */ - vorbis_synthesis_read(&this->vd,bout); - } - } - lprintf("output not open\n"); -} - -static void vorbis_dispose (audio_decoder_t *this_gen) { - - vorbis_decoder_t *this = (vorbis_decoder_t *) this_gen; - - if( !this->header_count ) { - lprintf("deinitializing decoder\n"); - - vorbis_block_clear(&this->vb); - vorbis_dsp_clear(&this->vd); - } - - vorbis_comment_clear(&this->vc); - - vorbis_info_clear(&this->vi); /* must be called last */ - - if (this->output_open) - this->stream->audio_out->close (this->stream->audio_out, this->stream); - - lprintf("libvorbis instance destroyed\n"); - - free (this_gen); -} - -static audio_decoder_t *open_plugin (audio_decoder_class_t *class_gen, - xine_stream_t *stream) { - - vorbis_decoder_t *this ; - - this = (vorbis_decoder_t *) xine_xmalloc (sizeof (vorbis_decoder_t)); - - this->audio_decoder.decode_data = vorbis_decode_data; - this->audio_decoder.reset = vorbis_reset; - this->audio_decoder.discontinuity = vorbis_discontinuity; - this->audio_decoder.dispose = vorbis_dispose; - this->stream = stream; - - this->output_open = 0; - this->header_count = 3; - this->convsize = 0; - - vorbis_info_init(&this->vi); - vorbis_comment_init(&this->vc); - - lprintf("libvorbis decoder instance created\n"); - - return (audio_decoder_t *) this; -} - -/* - * vorbis plugin class - */ - -static char *get_identifier (audio_decoder_class_t *this) { - return "vorbis"; -} - -static char *get_description (audio_decoder_class_t *this) { - return "vorbis audio decoder plugin"; -} - -static void dispose_class (audio_decoder_class_t *this) { - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - - vorbis_class_t *this; - - this = (vorbis_class_t *) xine_xmalloc (sizeof (vorbis_class_t)); - - this->decoder_class.open_plugin = open_plugin; - this->decoder_class.get_identifier = get_identifier; - this->decoder_class.get_description = get_description; - this->decoder_class.dispose = dispose_class; - - return this; -} - -static uint32_t audio_types[] = { - BUF_AUDIO_VORBIS, 0 - }; - -static const decoder_info_t dec_info_audio = { - audio_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_AUDIO_DECODER, 15, "vorbis", XINE_VERSION_CODE, &dec_info_audio, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; diff --git a/src/libxinevdec/Makefile.am b/src/libxinevdec/Makefile.am index 28a926a79..ac632dfd5 100644 --- a/src/libxinevdec/Makefile.am +++ b/src/libxinevdec/Makefile.am @@ -13,10 +13,6 @@ if ENABLE_GDK_PIXBUF gdkpixbuf_module = xineplug_decode_gdk_pixbuf.la endif -if ENABLE_THEORA -theora_module = xineplug_decode_theora.la -endif - xineplug_LTLIBRARIES = $(image_module) \ $(gdkpixbuf_module) \ $(theora_module) \ @@ -40,7 +36,3 @@ xineplug_decode_image_la_CFLAGS = $(AM_CFLAGS) $(WAND_CFLAGS) xineplug_decode_gdk_pixbuf_la_SOURCES = gdkpixbuf.c xineplug_decode_gdk_pixbuf_la_LIBADD = $(XINE_LIB) $(DYNAMIC_LD_LIBS) $(GDK_PIXBUF_LIBS) xineplug_decode_gdk_pixbuf_la_CFLAGS = $(AM_CFLAGS) $(GDK_PIXBUF_CFLAGS) - -xineplug_decode_theora_la_SOURCES = xine_theora_decoder.c -xineplug_decode_theora_la_LIBADD = $(XINE_LIB) $(OGG_LIBS) $(THEORA_LIBS) -xineplug_decode_theora_la_CFLAGS = $(AM_CFLAGS) $(OGG_CFLAGS) $(THEORA_CFLAGS) diff --git a/src/libxinevdec/xine_theora_decoder.c b/src/libxinevdec/xine_theora_decoder.c deleted file mode 100644 index 032f8800f..000000000 --- a/src/libxinevdec/xine_theora_decoder.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright (C) 2001-2003 the xine project - * - * This file is part of xine, a free video player. - * - * xine 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. - * - * xine 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 this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $Id: xine_decoder.c,v 1.26 2006/07/10 22:08:30 dgp85 Exp $ - * - * xine decoder plugin using libtheora - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOG_MODULE "theora_decoder" -#define LOG_VERBOSE -/* -#define LOG -*/ - -#include "xine_internal.h" -#include "video_out.h" -#include "buffer.h" -#include "metronom.h" -#include "xineutils.h" - -typedef struct theora_class_s { - video_decoder_class_t decoder_class; -} theora_class_t; - -typedef struct theora_decoder_s { - video_decoder_t theora_decoder; - theora_class_t *class; - theora_info t_info; - theora_comment t_comment; - theora_state t_state; - ogg_packet op; - yuv_buffer yuv; - xine_stream_t* stream; - int reject; - int op_max_size; - char* packet; - int done; - int width, height; - double ratio; - int offset_x, offset_y; - int frame_duration; - int skipframes; - int hp_read; - int initialized; -} theora_decoder_t; - -static void readin_op (theora_decoder_t *this, char* src, int size) { - if ( this->done+size > this->op_max_size) { - while (this->op_max_size < this->done+size) - this->op_max_size=this->op_max_size*2; - this->packet=realloc(this->packet, this->op_max_size); - this->op.packet=this->packet; - } - xine_fast_memcpy ( this->packet+this->done, src, size); - this->done=this->done+size; -} - -static void yuv2frame(yuv_buffer *yuv, vo_frame_t *frame, int offset_x, int offset_y) { - int i; - int crop_offset; - - /* fixme - direct rendering (exchaning pointers) may be possible. - * frame->base[0] = yuv->y could work if one could change the - * pitches[0,1,2] values, and rely on the drawing routine using - * the new pitches. With cropping and offsets, it's a bit trickier, - * but it would still be possible. - * Attempts at doing this have yielded nothing but SIGSEVs so far. - */ - - /* Copy yuv data onto the frame. Cropping and offset as specified - * by the frame_width, frame_height, offset_x and offset_y fields - * in the theora header is carried out. - */ - - crop_offset=offset_x+yuv->y_stride*offset_y; - for(i=0;iheight;i++) - xine_fast_memcpy(frame->base[0]+frame->pitches[0]*i, - yuv->y+crop_offset+yuv->y_stride*i, - frame->width); - - crop_offset=(offset_x/2)+(yuv->uv_stride)*(offset_y/2); - for(i=0;iheight/2;i++){ - xine_fast_memcpy(frame->base[1]+frame->pitches[1]*i, - yuv->u+crop_offset+yuv->uv_stride*i, - frame->width/2); - xine_fast_memcpy(frame->base[2]+frame->pitches[2]*i, - yuv->v+crop_offset+yuv->uv_stride*i, - frame->width/2); - - } -} - -static int collect_data (theora_decoder_t *this, buf_element_t *buf ) { - /* Assembles an ogg_packet which was sent with send_ogg_packet over xinebuffers */ - /* this->done, this->rejected, this->op and this->decoder->flags are needed*/ - int op_size = sizeof (ogg_packet); - - if (buf->decoder_flags & BUF_FLAG_FRAME_START) { - this->done=0; /*start from the beginnig*/ - this->reject=0;/*new packet - new try*/ - - /*copy the ogg_packet struct and the sum, correct the adress of the packet*/ - xine_fast_memcpy (&this->op, buf->content, op_size); - this->op.packet=this->packet; - - readin_op (this, buf->content + op_size, buf->size - op_size ); - /*read the rest of the data*/ - - } else { - if (this->done==0 || this->reject) { - /*we are starting to collect an packet without the beginnig - reject the rest*/ - printf ("libtheora: rejecting packet\n"); - this->reject=1; - return 0; - } - readin_op (this, buf->content, buf->size ); - } - - if ((buf->decoder_flags & BUF_FLAG_FRAME_END) && !this->reject) { - if ( this->done != this->op.bytes ) { - printf ("libtheora: A packet changed its size during transfer - rejected\n"); - printf (" size %d should be %ld\n", this->done , this->op.bytes); - this->op.bytes=this->done; - } - return 1; - } - return 0; -} - -static void theora_decode_data (video_decoder_t *this_gen, buf_element_t *buf) { - /* - * decode data from buf and feed decoded frames to - * video output - */ - theora_decoder_t *this = (theora_decoder_t *) this_gen; - vo_frame_t *frame; - yuv_buffer yuv; - int ret; - - if (!collect_data(this, buf)) return; - /*return, until a entire packets is collected*/ - - if ( (buf->decoder_flags & BUF_FLAG_HEADER) && - !(buf->decoder_flags & BUF_FLAG_STDHEADER) ) { - /*get the first 3 packets and decode the header during preview*/ - - if (this->hp_read==0) { - /*decode first hp*/ - if (theora_decode_header(&this->t_info, &this->t_comment, &this->op)>=0) { - this->hp_read++; - return; - } - } - - if (this->hp_read==1) { - /*decode three header packets*/ - if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { - printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); - } else { - this->hp_read++; - return; - } - } - - if (this->hp_read==2) { - if (theora_decode_header(&this->t_info, &this->t_comment,&this->op)) { - printf ("libtheora: Was unable to decode header #%d, corrupt stream?\n",this->hp_read); - } - /*headers are now decoded. initialize the decoder*/ - theora_decode_init (&this->t_state, &this->t_info); - - lprintf("theora stream is Theora %dx%d %.02f fps video.\n" - " frame content is %dx%d with offset (%d,%d).\n" - " pixel aspect is %d:%d.\n", - this->t_info.width,this->t_info.height, - (double)this->t_info.fps_numerator/this->t_info.fps_denominator, - this->t_info.frame_width, this->t_info.frame_height, - this->t_info.offset_x, this->t_info.offset_y, - this->t_info.aspect_numerator, this->t_info.aspect_denominator); - - this->frame_duration=((int64_t)90000*this->t_info.fps_denominator)/this->t_info.fps_numerator; - this->width=this->t_info.frame_width; - this->height=this->t_info.frame_height; - if (this->t_info.aspect_numerator==0 || this->t_info.aspect_denominator==0) - /* 0-values are undefined, so don't do any scaling. */ - this->ratio=(double)this->width/(double)this->height; - else - /* Yes, this video needs to be scaled. */ - this->ratio=(double)(this->width*this->t_info.aspect_numerator) / - (double)(this->height*this->t_info.aspect_denominator); - this->offset_x=this->t_info.offset_x; - this->offset_y=this->t_info.offset_y; - this->initialized=1; - this->hp_read++; - } - - } else if (buf->decoder_flags & BUF_FLAG_HEADER) { - /*ignore headerpackets*/ - - return; - - } else { - /*decode videodata*/ - - if (!this->initialized) { - printf ("libtheora: cannot decode stream without header\n"); - return; - } - - ret=theora_decode_packetin( &this->t_state, &this->op); - - if ( ret!=0) { - xprintf(this->stream->xine, XINE_VERBOSITY_LOG, "libtheora:Received an bad packet\n"); - } else if (!this->skipframes) { - - theora_decode_YUVout(&this->t_state,&yuv); - - /*fixme - aspectratio from theora is not considered*/ - frame = this->stream->video_out->get_frame( this->stream->video_out, - this->width, this->height, - this->ratio, - XINE_IMGFMT_YV12, - VO_BOTH_FIELDS); - yuv2frame(&yuv, frame, this->offset_x, this->offset_y); - - frame->pts = buf->pts; - frame->duration=this->frame_duration; - this->skipframes=frame->draw(frame, this->stream); - frame->free(frame); - } else { - this->skipframes=this->skipframes-1; - } - } -} - - -static void theora_flush (video_decoder_t *this_gen) { - /* - * flush out any frames that are still stored in the decoder - */ - theora_decoder_t *this = (theora_decoder_t *) this_gen; - this->skipframes=0; -} - -static void theora_reset (video_decoder_t *this_gen) { - /* - * reset decoder after engine flush (prepare for new - * video data not related to recently decoded data) - */ - theora_decoder_t *this = (theora_decoder_t *) this_gen; - this->skipframes=0; -} - -static void theora_discontinuity (video_decoder_t *this_gen) { - /* - * inform decoder that a time reference discontinuity has happened. - * that is, it must forget any currently held pts value - */ - theora_decoder_t *this = (theora_decoder_t *) this_gen; - this->skipframes=0; -} - -static void theora_dispose (video_decoder_t *this_gen) { - /* - * close down, free all resources - */ - - theora_decoder_t *this = (theora_decoder_t *) this_gen; - - lprintf ("dispose \n"); - - theora_clear (&this->t_state); - theora_comment_clear (&this->t_comment); - theora_info_clear (&this->t_info); - this->stream->video_out->close(this->stream->video_out, this->stream); - free (this->packet); - free (this); -} - -static video_decoder_t *theora_open_plugin (video_decoder_class_t *class_gen, xine_stream_t *stream) { - - /* - * open a new instance of this plugin class - */ - - theora_decoder_t *this ; - - this = (theora_decoder_t *) xine_xmalloc (sizeof (theora_decoder_t)); - - this->theora_decoder.decode_data = theora_decode_data; - this->theora_decoder.flush = theora_flush; - this->theora_decoder.reset = theora_reset; - this->theora_decoder.discontinuity = theora_discontinuity; - this->theora_decoder.dispose = theora_dispose; - - this->stream = stream; - this->class = (theora_class_t *) class_gen; - - this->op_max_size = 4096; - this->packet = malloc(this->op_max_size); - - this->done = 0; - - this->stream = stream; - - this->initialized = 0; - - theora_comment_init (&this->t_comment); - theora_info_init (&this->t_info); - stream->video_out->open (stream->video_out, stream); - - return &this->theora_decoder; - -} - -/* - * theora plugin class - */ - -static char *theora_get_identifier (video_decoder_class_t *this) { - /* - * return short, human readable identifier for this plugin class - */ - return "theora video"; -} - -static char *theora_get_description (video_decoder_class_t *this) { - /* - * return human readable (verbose = 1 line) description for - * this plugin class - */ - return "theora video decoder plugin"; -} - -static void theora_dispose_class (video_decoder_class_t *this) { - /* - * free all class-related resources - */ - free (this); -} - -static void *init_plugin (xine_t *xine, void *data) { - /*initialize our plugin*/ - theora_class_t *this; - - this = (theora_class_t *) xine_xmalloc (sizeof (theora_class_t)); - - this->decoder_class.open_plugin = theora_open_plugin; - this->decoder_class.get_identifier = theora_get_identifier; - this->decoder_class.get_description = theora_get_description; - this->decoder_class.dispose = theora_dispose_class; - - return this; -} - -/* - * exported plugin catalog entry - */ - -static uint32_t supported_types[] = { BUF_VIDEO_THEORA, 0 }; - -static const decoder_info_t dec_info_video = { - supported_types, /* supported types */ - 5 /* priority */ -}; - -const plugin_info_t xine_plugin_info[] EXPORTED = { - /* type, API, "name", version, special_info, init_function */ - { PLUGIN_VIDEO_DECODER, 18, "theora", XINE_VERSION_CODE, &dec_info_video, init_plugin }, - { PLUGIN_NONE, 0, "", 0, NULL, NULL } -}; -- cgit v1.2.3