summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--configure.ac21
-rw-r--r--m4/Makefile.am1
-rw-r--r--m4/theora.m496
-rw-r--r--src/demuxers/Makefile.am4
-rw-r--r--src/demuxers/demux_ogg.c263
-rw-r--r--src/libtheora/Makefile.am34
-rw-r--r--src/libtheora/xine_decoder.c361
-rw-r--r--src/xine-engine/buffer.h4
9 files changed, 735 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b71950fa..c0fe0c94b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+xine-lib (1-beta12)
+ * playback of theorastreams added
+
xine-lib (1-beta11)
* fix bugs in selecting ogm subtitles
* fix multiple lines subtitles' display in OGM container
diff --git a/configure.ac b/configure.ac
index 2bc910cf9..8449a3b28 100644
--- a/configure.ac
+++ b/configure.ac
@@ -605,6 +605,19 @@ AM_PATH_OGG(
AM_CONDITIONAL(HAVE_VORBIS, [test x"$no_ogg" != "xyes" -a x"$no_vorbis" != "xyes"])
dnl ---------------------------------------------
+dnl Ogg/Theora libs.
+dnl ---------------------------------------------
+
+echo "these are your cflags before ampath_blabla $CFLAGS "
+
+AM_PATH_OGG(
+ [ AM_PATH_THEORA(AC_DEFINE(HAVE_THEORA,1,[Define this if you have theora]),
+ AC_MSG_RESULT([*** All OGG/THEORA dependent parts will be disabled ***]))
+ ],
+ AC_MSG_RESULT([*** All of OGG/Theora dependent parts will be disabled ***]))
+AM_CONDITIONAL(HAVE_THEORA, [test x"$no_ogg" != "xyes" -a x"$no_theora" != "xyes"])
+
+dnl ---------------------------------------------
dnl check for libFLAC
dnl ---------------------------------------------
AM_PATH_LIBFLAC([],
@@ -1339,6 +1352,7 @@ src/libspudec/Makefile
src/libspucc/Makefile
src/libsputext/Makefile
src/libvorbis/Makefile
+src/libtheora/Makefile
src/libw32dll/Makefile
src/libw32dll/wine/Makefile
src/libw32dll/DirectShow/Makefile
@@ -1439,7 +1453,7 @@ echo " - ac3"
if test x"$enable_asf" = "xyes"; then
echo " - asf"
fi
-if test x"$no_oggvorbis" = "xno"; then
+if test x"$no_vorbis" != "xyes"; then
echo " - ogg"
fi
if test x"$have_libmng" = "xyes"; then
@@ -1470,6 +1484,9 @@ fi
if test x"$have_libpng" = "xyes"; then
echo " - png"
fi
+if test x"$no_theora" != "xyes"; then
+ echo " - theora"
+fi
echo ""
dnl audio decoders
@@ -1480,7 +1497,7 @@ echo " - linear pcm - roqaudio"
echo " - log pcm - gsm610"
echo " - ffmpeg - interplayaudio"
echo " - nosefart"
-if test x"$no_oggvorbis" = "xno"; then
+if test x"$no_vorbis" != "xyes"; then
echo " - vorbis"
fi
if test x"$enable_w32dll" = "xyes"; then
diff --git a/m4/Makefile.am b/m4/Makefile.am
index 435152e61..b9b7a4736 100644
--- a/m4/Makefile.am
+++ b/m4/Makefile.am
@@ -31,6 +31,7 @@ EXTRA_DIST = \
progtest.m4 \
sdl.m4 \
vorbis.m4 \
+ theora.m4 \
xine.m4 \
_xine.m4 \
xvid.m4
diff --git a/m4/theora.m4 b/m4/theora.m4
new file mode 100644
index 000000000..2769c9d10
--- /dev/null
+++ b/m4/theora.m4
@@ -0,0 +1,96 @@
+# Configure paths for libtheora
+# Andreas Heinchen <andreas.heinchen@gmx.de> 04-18-2003
+# Shamelessly adapted from Jack Moffitt's version for libvorbis
+# who had stolen it from Owen Taylor and Manish Singh
+
+dnl AM_PATH_THEORA([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libtheora, and define THEORA_CFLAGS and THEORA_LIBS
+dnl
+AC_DEFUN([AM_PATH_THEORA],
+[dnl
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(theora-prefix,[ --with-theora-prefix=PFX Prefix where libtheora is installed (optional)], theora_prefix="$withval", theora_prefix="")
+AC_ARG_ENABLE(theoratest, [ --disable-theoratest Do not try to compile and run a test Vorbis program],, enable_theoratest=yes)
+
+ if test x$theora_prefix != x ; then
+ theora_args="$theora_args --prefix=$theora_prefix"
+ THEORA_CFLAGS="-I$theora_prefix/include"
+ THEORA_LIBDIR="-L$theora_prefix/lib"
+ fi
+
+ THEORA_LIBS="$THEORA_LIBDIR -ltheora -lm"
+
+ AC_MSG_CHECKING(for Theora)
+ no_theora=""
+
+
+ if test "x$enable_theoratest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $THEORA_CFLAGS"
+ echo "these are your cflags $CFLAGS"
+ LIBS="$LIBS $THEORA_LIBS $OGG_LIBS"
+dnl
+dnl Now check if the installed Theora is sufficiently new.
+dnl
+ rm -f conf.theoratest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <theora/theora.h>
+
+int main ()
+{
+ system("touch conf.theoratest");
+ return 0;
+}
+
+],, no_theora=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+ if test "x$no_theora" = x ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$1], , :, [$1])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.theoratest ; then
+ :
+ else
+ echo "*** Could not run Theora test program, checking why..."
+ CFLAGS="$CFLAGS $THEORA_CFLAGS"
+ LIBS="$LIBS $THEORA_LIBS $OGG_LIBS"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <theora/theora.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding Theora or finding the wrong"
+ echo "*** version of Theora. If it is not finding Theora, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means Theora was incorrectly installed"
+ echo "*** or that you have moved Theora since it was installed." ])
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+ THEORA_CFLAGS=""
+ THEORA_LIBS=""
+ THEORAFILE_LIBS=""
+ THEORAENC_LIBS=""
+ ifelse([$2], , :, [$2])
+ fi
+ AC_SUBST(THEORA_CFLAGS)
+ AC_SUBST(THEORA_LIBS)
+ AC_SUBST(THEORAFILE_LIBS)
+ AC_SUBST(THEORAENC_LIBS)
+ rm -f conf.theoratest
+])
diff --git a/src/demuxers/Makefile.am b/src/demuxers/Makefile.am
index c709b8734..d627e56a3 100644
--- a/src/demuxers/Makefile.am
+++ b/src/demuxers/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS = $(OGG_CFLAGS) @ANSI_FLAGS@
+AM_CFLAGS = $(THEORA_CFLAGS) $(OGG_CFLAGS) @ANSI_FLAGS@
LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic
@@ -46,7 +46,7 @@ lib_LTLIBRARIES = $(ogg_module) $(asf_module) $(mng_module) $(image_module) \
xineplug_dmx_yuv_frames.la
xineplug_dmx_ogg_la_SOURCES = demux_ogg.c
-xineplug_dmx_ogg_la_LIBADD = $(OGG_LIBS) $(VORBIS_LIBS) $(XINELIB)
+xineplug_dmx_ogg_la_LIBADD = $(OGG_LIBS) $(VORBIS_LIBS) $(THEORA_LIBS) $(XINELIB)
xineplug_dmx_ogg_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
xineplug_dmx_avi_la_SOURCES = demux_avi.c
diff --git a/src/demuxers/demux_ogg.c b/src/demuxers/demux_ogg.c
index cffe156c3..713e4f79b 100644
--- a/src/demuxers/demux_ogg.c
+++ b/src/demuxers/demux_ogg.c
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2000-2003 the xine project
*
@@ -18,7 +17,7 @@
* 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.85 2003/04/27 17:40:59 heinchen Exp $
+ * $Id: demux_ogg.c,v 1.86 2003/04/30 08:49:39 heinchen Exp $
*
* demultiplexer for ogg streams
*
@@ -39,13 +38,17 @@
#include <ogg/ogg.h>
#include <vorbis/codec.h>
+#ifdef HAVE_THEORA
+#include <theora/theora.h>
+#endif
+
#include "xine_internal.h"
#include "xineutils.h"
#include "demux.h"
-/*
+
#define LOG
- */
+
#define CHUNKSIZE 8500
#define PACKET_TYPE_HEADER 0x01
@@ -75,8 +78,12 @@ typedef struct demux_ogg_s {
input_plugin_t *input;
+#ifdef HAVE_THEORA
+ theora_info t_info;
+#endif
+
int status;
-
+
int frame_duration;
ogg_sync_state oy;
@@ -87,8 +94,8 @@ typedef struct demux_ogg_s {
uint32_t buf_types[MAX_STREAMS];
int preview_buffers[MAX_STREAMS];
int64_t header_granulepos[MAX_STREAMS];
- int factor[MAX_STREAMS];
- int quotient[MAX_STREAMS];
+ int64_t factor[MAX_STREAMS];
+ int64_t quotient[MAX_STREAMS];
int num_streams;
@@ -104,6 +111,7 @@ typedef struct demux_ogg_s {
int keyframe_needed;
int ignore_keyframes;
int time_length;
+
} demux_ogg_t ;
@@ -117,6 +125,15 @@ typedef struct {
config_values_t *config;
} demux_ogg_class_t;
+static int intlog(int num) {
+ int ret=0;
+ while(num>0){
+ num=num/2;
+ ret=ret+1;
+ }
+ return(ret);
+}
+
static int get_stream (demux_ogg_t *this, int serno)
{
int i;
@@ -129,13 +146,30 @@ static int get_stream (demux_ogg_t *this, int serno)
}
static int get_pts (demux_ogg_t *this, int stream_num , int64_t granulepos ) {
- if (this->quotient[stream_num])
+ /*calculates an pts from an granulepos*/
+ if (granulepos<0) {
+ if ( this->header_granulepos[stream_num]>=0 )
+ return get_pts (this, stream_num, this->header_granulepos[stream_num]);
+ else
+ return 0;
+
+#ifdef HAVE_THEORA
+ } else if (this->buf_types[stream_num]==BUF_VIDEO_THEORA) {
+ int64_t iframe,pframe;
+ int keyframe_granule_shift;
+ keyframe_granule_shift=intlog(this->t_info.keyframe_frequency_force-1);
+ iframe=granulepos>>keyframe_granule_shift;
+ pframe=granulepos-(iframe<<keyframe_granule_shift);
+ return ((iframe + pframe)*this->frame_duration);
+#endif
+
+ } else if (this->quotient[stream_num])
return (granulepos*this->factor[stream_num]/this->quotient[stream_num]);
else
return 0;
}
-static int read_ogg_page (demux_ogg_t *this) {
+static int read_ogg_packet (demux_ogg_t *this) {
char *buffer;
long bytes;
while (ogg_sync_pageout(&this->oy,&this->og)!=1) {
@@ -162,6 +196,69 @@ static void hex_dump (uint8_t *p, int length) {
}
}
+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) {
+ /*this little function is used to send an entire ogg-packet through
+ xine buffers to the appropiate decoder, where recieve_ogg_packet should be called to collect the
+ buffers and reassemble them to an ogg packet*/
+
+ buf_element_t *buf;
+
+ int done=0,todo=op->bytes;
+ int op_size = sizeof(ogg_packet);
+
+ /* nasty hack to pack op as well as (vorbis) content
+ in one xine buffer */
+
+ buf = fifo->buffer_pool_alloc (fifo);
+ memcpy (buf->content, op, op_size);
+
+ if ( buf->max_size > op_size + todo ) {
+ memcpy (buf->content + op_size , op->packet, todo);
+ done=todo;
+ buf->decoder_flags = BUF_FLAG_FRAME_START | BUF_FLAG_FRAME_END | decoder_flags;
+ buf->size = op_size + done;
+ } else {
+ memcpy (buf->content + op_size , op->packet, buf->max_size - op_size );
+ done=done+ buf->max_size - op_size;
+ buf->decoder_flags = BUF_FLAG_FRAME_START | decoder_flags;
+ buf->size = buf->max_size;
+ }
+
+ buf->pts = pts;
+ buf->extra_info->input_pos = this->input->get_current_pos (this->input);
+ buf->extra_info->input_time = buf->pts / 90 ;
+ buf->type = this->buf_types[stream_num] ;
+
+ this->video_fifo->put (this->video_fifo, buf);
+
+ while (done<todo) {
+ buf = fifo->buffer_pool_alloc (fifo);
+ if (done+buf->max_size < todo) {
+ memcpy (buf->content, op->packet+done, buf->max_size);
+ buf->size = buf->max_size;
+ done=done+buf->max_size;
+ buf->decoder_flags = decoder_flags;
+ } else {
+ memcpy (buf->content, op->packet+done, todo-done);
+ buf->size = todo-done;
+ done=todo;
+ buf->decoder_flags = BUF_FLAG_FRAME_END | decoder_flags;
+ }
+
+ buf->pts = pts;
+ buf->extra_info->input_pos = this->input->get_current_pos (this->input);
+ buf->extra_info->input_time = buf->pts / 90 ;
+ buf->type = this->buf_types[stream_num] ;
+
+ fifo->put (fifo, buf);
+ }
+}
+
/* redefine abs as macro to handle 64-bit diffs.
i guess llabs may not be available everywhere */
#define abs(x) ( ((x)<0) ? -(x) : (x) )
@@ -225,7 +322,7 @@ static void send_ogg_buf (demux_ogg_t *this,
if ( this->audio_fifo
&& (this->buf_types[stream_num] & 0xFF000000) == BUF_AUDIO_BASE) {
buf_element_t *buf;
-
+
buf = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
if ((this->buf_types[stream_num] & 0xFFFF0000) == BUF_AUDIO_VORBIS) {
@@ -273,8 +370,34 @@ static void send_ogg_buf (demux_ogg_t *this,
this->audio_fifo->put (this->audio_fifo, buf);
+#ifdef HAVE_THEORA
+ } else if ((this->buf_types[stream_num] & 0xFFFF0000) == BUF_VIDEO_THEORA) {
+
+ int64_t pts;
+ theora_info test;
+
+ /*Lets see if this is an Header*/
+ if ((theora_decode_header(&test,op))>=0) {
+ decoder_flags=decoder_flags|BUF_FLAG_HEADER;
+#ifdef LOG
+ printf ("demux_ogg: found an header\n");
+#endif
+ }
+
+ if (op->granulepos!=-1) {
+ pts = get_pts (this, stream_num, op->granulepos);
+ check_newpts( this, pts, PTS_VIDEO, decoder_flags );
+ } else if (this->header_granulepos[stream_num]!=-1) {
+ pts = get_pts (this, stream_num, this->header_granulepos[stream_num]);
+ this->header_granulepos[stream_num]=-1;
+ check_newpts( this, pts, PTS_VIDEO, decoder_flags );
+ } else
+ pts=0;
+ send_ogg_packet (this, this->video_fifo, op, pts, decoder_flags, stream_num);
+#endif
+
} else if ((this->buf_types[stream_num] & 0xFF000000) == BUF_VIDEO_BASE) {
-
+
buf_element_t *buf;
int todo, done;
@@ -314,7 +437,7 @@ static void send_ogg_buf (demux_ogg_t *this,
buf->pts = 0;
#ifdef LOG
- printf ("demux_ogg: video granulepos %lld, pts %lld, time %d\n", op->granulepos, buf->pts, buf->pts / 90);
+ printf ("demux_ogg: video granulepos %lld, pts %lld, time %lld\n", op->granulepos, buf->pts, buf->pts / 90);
#endif
buf->extra_info->input_pos = this->input->get_current_pos (this->input);
@@ -350,6 +473,9 @@ static void send_ogg_buf (demux_ogg_t *this,
#endif
} else {
subtitle = (char *)&op->packet[hdrlen + 1];
+#ifdef LOG
+ printf ("demux_ogg: subtitle %d -> %d :%s\n",start,end,subtitle);
+#endif
if ((strlen(subtitle) > 1) || (*subtitle != ' ')) {
start = op->granulepos;
@@ -387,7 +513,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
int filelength,position;
ogg_packet op;
-
+
#ifdef LOG
printf ("demux_ogg: detecting stream types...\n");
#endif
@@ -395,7 +521,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
this->ignore_keyframes = 0;
while (!done) {
- if (!read_ogg_page(this)) {
+ if (!read_ogg_packet(this)) {
this->status = DEMUX_FINISHED;
return;
}
@@ -497,7 +623,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
if( !this->buf_types[stream_num] )
this->buf_types[stream_num] = BUF_VIDEO_UNKNOWN;
this->buf_types[stream_num] |= channel;
- this->preview_buffers[stream_num] = 1; /* FIXME: don't know */
+ this->preview_buffers[stream_num] = 5; /* FIXME: don't know */
#ifdef LOG
printf ("demux_ogg: subtype %.4s\n", &locsubtype);
@@ -623,7 +749,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
buf->decoder_info[3] = locchannels;
this->audio_fifo->put (this->audio_fifo, buf);
- this->preview_buffers[stream_num] = 1; /* FIXME: don't know */
+ this->preview_buffers[stream_num] = 5; /* FIXME: don't know */
this->factor[stream_num] = 90000;
this->quotient[stream_num] = locsamples_per_unit;
@@ -654,7 +780,7 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
printf ("demux_ogg: older direct show filter-generated stream header detected.\n");
hex_dump (op.packet, op.bytes);
#endif
- this->preview_buffers[stream_num] = 1; /* FIXME: don't know */
+ this->preview_buffers[stream_num] = 5; /* FIXME: don't know */
if ( (*(int32_t*)(op.packet+96)==0x05589f80) && (op.bytes>=184)) {
@@ -763,9 +889,6 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
}
} else if (!strncmp (&op.packet[1], "text", 4)) {
int channel=0;
- uint32_t *val;
- buf_element_t *buf;
-
#ifdef LOG
printf ("demux_ogg: textstream detected.\n");
#endif
@@ -773,15 +896,38 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
channel= this->num_spu_streams++;
this->buf_types[stream_num] = 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->buf_types[stream_num];
- buf->pts = 0;
- val = (uint32_t * )buf->content;
- *val++=0;
- *val++=0;
- *val++=0;
- this->video_fifo->put (this->video_fifo, buf);
+#ifdef HAVE_THEORA
+ } else if (!strncmp (&op.packet[1], "theora", 4)) {
+ int channel;
+ printf ("demux_ogg: Theorastreamsupport is highly alpha at the moment\n");
+
+ if (theora_decode_header(&this->t_info, &op)>=0) {
+
+ this->num_video_streams++;
+
+ this->factor[stream_num] = (int64_t) 90000 * (int64_t) this->t_info.fps_denominator;
+ this->quotient[stream_num] = this->t_info.fps_numerator;
+
+ this->frame_duration = ((int64_t) 90000*this->t_info.fps_denominator)/this->t_info.fps_numerator;
+
+ this->preview_buffers[stream_num]=1;
+ this->buf_types[stream_num] = BUF_VIDEO_THEORA;
+
+ this->stream->stream_info[XINE_STREAM_INFO_VIDEO_WIDTH]
+ = this->t_info.width;
+ this->stream->stream_info[XINE_STREAM_INFO_VIDEO_HEIGHT]
+ = this->t_info.height;
+ this->stream->stream_info[XINE_STREAM_INFO_FRAME_DURATION]
+ = ((int64_t) 90000*this->t_info.fps_denominator)/this->t_info.fps_numerator;
+
+
+ } else {
+ /*Rejected stream*/
+ printf ("demux_ogg: A theora header was rejected by libtheora\n");
+ this->buf_types[stream_num] = BUF_CONTROL_NOP;
+ this->preview_buffers[stream_num] = 5; /* FIXME: don't know */
+ }
+#endif
} else {
printf ("demux_ogg: unknown stream type (signature >%.8s<). hex dump of bos packet follows:\n",
@@ -838,16 +984,15 @@ static void demux_ogg_send_header (demux_ogg_t *this) {
this->demux_plugin.seek((demux_plugin_t *)this, (off_t) filelength-65536 ,0);
done=0;
while (!done) {
- if (!read_ogg_page (this))
+ if (!read_ogg_packet (this))
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)))
+ 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;
}
}
- this->demux_plugin.seek((demux_plugin_t *)this, position,0);
}
}
}
@@ -863,13 +1008,14 @@ static void demux_ogg_send_content (demux_ogg_t *this) {
printf ("demux_ogg: send package...\n");
#endif
- if (!read_ogg_page(this)) {
+ if (!read_ogg_packet(this)) {
this->status = DEMUX_FINISHED;
#ifdef LOG
- printf ("demux_ogg: EOF\n");
+ printf ("demux_ogg: EOF\n");
#endif
return;
}
+
/* now we've got one new page */
cur_serno = ogg_page_serialno (&this->og);
@@ -894,10 +1040,10 @@ static void demux_ogg_send_content (demux_ogg_t *this) {
ogg_stream_pagein(&this->oss[stream_num], &this->og);
if (ogg_page_bos(&this->og)) {
-#ifdef LOG
+
printf ("demux_ogg: beginning of stream\ndemux_ogg: serial number %d - discard\n",
ogg_page_serialno (&this->og));
-#endif
+
while (ogg_stream_packetout(&this->oss[stream_num], &op) == 1) ;
return;
}
@@ -906,7 +1052,7 @@ static void demux_ogg_send_content (demux_ogg_t *this) {
/* printf("demux_ogg: packet: %.8s\n", op.packet); */
/* printf("demux_ogg: got a packet\n"); */
- if (*op.packet & PACKET_TYPE_HEADER) {
+ if ((*op.packet & PACKET_TYPE_HEADER) && (this->buf_types[stream_num]!=BUF_VIDEO_THEORA)) {
if (op.granulepos!=-1) {
this->header_granulepos[stream_num]=op.granulepos;
#ifdef LOG
@@ -920,7 +1066,7 @@ static void demux_ogg_send_content (demux_ogg_t *this) {
continue;
}
- if (this->buf_flag_seek)
+ if ((this->buf_flag_seek) && (this->buf_types[stream_num]!=BUF_VIDEO_THEORA))
if ((op.granulepos==-1) && (this->header_granulepos[stream_num]==-1)) continue;
@@ -928,7 +1074,30 @@ static void demux_ogg_send_content (demux_ogg_t *this) {
#ifdef LOG
printf ("demux_ogg: keyframe needed... buf_type=%08x\n", this->buf_types[stream_num]);
#endif
- if (((this->buf_types[stream_num] & 0xFF000000) == BUF_VIDEO_BASE) &&
+ if (this->buf_types[stream_num] == BUF_VIDEO_THEORA) {
+#ifdef HAVE_THEORA
+
+ int keyframe_granule_shift;
+ int64_t pframe=-1,iframe=-1;
+
+ keyframe_granule_shift=intlog(this->t_info.keyframe_frequency_force-1);
+
+ /*replace the 1 with 0 and you will deactivate keyframeseeking*/
+ if (1) {
+ if(op.granulepos>=0){
+ iframe=op.granulepos>>keyframe_granule_shift;
+ pframe=op.granulepos-(iframe<<keyframe_granule_shift);
+ printf ("seeking keyframe i %lld p %lld\n",iframe,pframe);
+ if (pframe!=0)
+ continue;
+ } else
+ continue;
+ this->keyframe_needed = 0;
+ } else
+ this->keyframe_needed = 0;
+
+#endif
+ } else if (((this->buf_types[stream_num] & 0xFF000000) == BUF_VIDEO_BASE) &&
(*op.packet == PACKET_IS_SYNCPOINT)) {
/*
printf("keyframe: l%ld b%ld e%ld g%ld p%ld str%d\n",
@@ -1018,12 +1187,19 @@ static int demux_ogg_seek (demux_plugin_t *this_gen,
/*
* seek to start position
*/
+#ifdef LOG
+ printf ("demux_ogg: seek called\n");
+#endif
if (this->input->get_capabilities(this->input) & INPUT_CAP_SEEKABLE) {
this->keyframe_needed = (this->num_video_streams>0);
if ( (!start_pos) && (start_time)) {
- start_pos = start_time * this->avg_bitrate/8;
+ if (this->time_length!=-1)
+ start_pos = start_time * 1000 * this->input->get_length(this->input) / this->time_length ;
+ else
+ start_pos = start_time * this->avg_bitrate/8;
+
#ifdef LOG
printf ("demux_ogg: seeking to %d seconds => %lld bytes\n",
start_time, start_pos);
@@ -1031,11 +1207,6 @@ static int demux_ogg_seek (demux_plugin_t *this_gen,
}
ogg_sync_reset(&this->oy);
-
- /*some strange streams have no syncpoint flag set at the beginning*/
- if (start_pos == 0)
- this->keyframe_needed = 0;
-
this->input->seek (this->input, start_pos, SEEK_SET);
}
@@ -1224,7 +1395,7 @@ static void *init_class (xine_t *xine, void *data) {
plugin_info_t xine_plugin_info[] = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_DEMUX, 21, "ogg", XINE_VERSION_CODE, NULL, init_class },
+ { PLUGIN_DEMUX, 20, "ogg", XINE_VERSION_CODE, NULL, init_class },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
diff --git a/src/libtheora/Makefile.am b/src/libtheora/Makefile.am
new file mode 100644
index 000000000..7ac49ef19
--- /dev/null
+++ b/src/libtheora/Makefile.am
@@ -0,0 +1,34 @@
+##
+## Process this file with automake to produce Makefile.in
+##
+
+AM_CFLAGS = $(THEORA_CFLAGS)
+
+LIBTOOL = $(SHELL) $(top_builddir)/libtool-nofpic
+
+libdir = $(XINE_PLUGINDIR)
+
+if HAVE_THEORA
+theora_module = xineplug_decode_theora.la
+endif
+
+lib_LTLIBRARIES = $(theora_module)
+
+xineplug_decode_theora_la_SOURCES = xine_decoder.c
+xineplug_decode_theora_la_LIBADD = $(OGG_LIBS) $(THEORA_LIBS)
+xineplug_decode_theora_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
+
+debug:
+# @$(MAKE) CFLAGS="$(DEBUG_CFLAGS) $(OGG_CFLAGS) $(THEORA_CFLAGS)"
+ @$(MAKE) CFLAGS="$(DEBUG_CFLAGS)"
+
+install-debug: debug
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+mostlyclean-generic:
+ -rm -f *~ \#* .*~ .\#*
+
+maintainer-clean-generic:
+ -@echo "This command is intended for maintainers to use;"
+ -@echo "it deletes files that may require special tools to rebuild."
+ -rm -f Makefile.in
diff --git a/src/libtheora/xine_decoder.c b/src/libtheora/xine_decoder.c
new file mode 100644
index 000000000..136a24e88
--- /dev/null
+++ b/src/libtheora/xine_decoder.c
@@ -0,0 +1,361 @@
+/*
+ * 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.1 2003/04/30 08:49:40 heinchen Exp $
+ *
+ * xine decoder plugin using libtheora
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <pthread.h>
+#include <math.h>
+#include <assert.h>
+#include <theora/theora.h>
+#include "xine_internal.h"
+#include "video_out.h"
+#include "buffer.h"
+#include "metronom.h"
+#include "xineutils.h"
+
+/*
+#define LOG
+*/
+
+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_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;
+ int initialized;
+ int frame_duration;
+ int keyframe_granule_shift;
+ int skipframes;
+} theora_decoder_t;
+
+static int intlog(int num) {
+ int ret=0;
+ while(num>0){
+ num=num/2;
+ ret=ret+1;
+ }
+ return(ret);
+}
+
+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;
+ }
+ memcpy ( this->packet+this->done, src, size);
+ this->done=this->done+size;
+}
+
+static void show_op_stats (theora_decoder_t *this) {
+ printf (" : size %ld\n",this->op.bytes);
+}
+
+static void yuv2frame(yuv_buffer *yuv, vo_frame_t *frame) {
+ int i;
+ for(i=0;i<yuv->y_height;i++)
+ memcpy(frame->base[0]+yuv->y_width*i,
+ yuv->y+yuv->y_stride*i,
+ yuv->y_width);
+ for(i=0;i<yuv->uv_height;i++){
+ memcpy(frame->base[2]+yuv->uv_width*i,
+ yuv->v+yuv->uv_stride*i,
+ yuv->uv_width);
+ memcpy(frame->base[1]+yuv->uv_width*i,
+ yuv->u+yuv->uv_stride*i,
+ yuv->uv_width);
+ }
+}
+
+static int collect_data (theora_decoder_t *this, buf_element_t *buf ) {
+ /* Assembles an ogg_packet which was send 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*/
+ 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);
+ show_op_stats(this);
+ 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;
+
+ if ((buf->decoder_flags & BUF_FLAG_HEADER) && !this->initialized) {
+ if (theora_decode_header(&this->t_info,&this->op)>=0) {
+ theora_decode_init (&this->t_state,&this->t_info);
+ this->keyframe_granule_shift=intlog(this->t_info.keyframe_frequency_force-1);
+ this->initialized=1;
+ this->frame_duration=((int64_t)90000*this->t_info.fps_denominator)/this->t_info.fps_numerator;
+#ifdef LOG
+ printf("libtheora: theora stream is Theora %dx%d %.02f fps video.\n",
+ this->t_info.width,this->t_info.height,
+ (double)this->t_info.fps_numerator/this->t_info.fps_denominator);
+#endif
+ this->width=this->t_info.width;
+ this->height=this->t_info.height;
+ } else
+ printf ("libtheora: Header could not be decoded.\n");
+ } else if (buf->decoder_flags & BUF_FLAG_HEADER) {
+ theora_clear(&this->t_state);
+ theora_decode_header(&this->t_info,&this->op);
+ theora_decode_init(&this->t_state,&this->t_info);
+ } else if (!(buf->decoder_flags & BUF_FLAG_PREVIEW)) {
+
+ if (!this->initialized) {
+ return;
+ }
+
+#ifdef LOG
+ printf ("libtheora: decoding i %lld p %lld\n",this->iframe,this->pframe);
+#endif
+
+ ret=theora_decode_packetin( &this->t_state, &this->op);
+
+ if ( ret!=0) {
+ printf ("libtheora:Recieved an bad packet\n");
+ } else if (!this->skipframes) {
+
+ int64_t iframe,pframe;
+
+ theora_decode_YUVout(&this->t_state,&yuv);
+
+ iframe=this->t_state.granulepos>>this->keyframe_granule_shift;
+ pframe=this->t_state.granulepos-(iframe<<this->keyframe_granule_shift);
+#ifdef LOG
+ printf ("libtheora: decoded i %lld p %lld\n",iframe,pframe);
+#endif
+ frame = this->stream->video_out->get_frame( this->stream->video_out,
+ this->width, this->height,
+ ASPECT_SQUARE,
+ XINE_IMGFMT_YV12,
+ VO_BOTH_FIELDS);
+ yuv2frame(&yuv, frame);
+
+ frame->pts = this->frame_duration* (iframe+pframe);
+
+ frame->duration=this->frame_duration;
+ this->skipframes=frame->draw(frame, this->stream);
+ frame->free(frame);
+ this->done=0;
+ } else
+ this->skipframes=0;
+ theora_decode_YUVout(&this->t_state,&yuv);
+ }
+}
+
+
+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;
+
+ printf ("libtheora: dispose \n");
+
+ theora_clear (&this->t_state);
+ 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 ;
+
+ printf ("You are trying to decoda an theorastream. Theora is in the moment\n");
+ printf ("aplha, xiph is developing on it. If the stream could not be played back\n");
+ printf ("go to http://xine.sourceforge.net and grab the latest release of xine.\n");
+
+ this = (theora_decoder_t *) malloc (sizeof (theora_decoder_t));
+ memset(this, 0, 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;
+
+ 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 "experimental 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 *) malloc (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 decoder_info_t dec_info_video = {
+ supported_types, /* supported types */
+ 5 /* priority */
+};
+
+plugin_info_t xine_plugin_info[] = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_VIDEO_DECODER, 14, "theora", XINE_VERSION_CODE, &dec_info_video, init_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h
index afe8defdc..ae9c30365 100644
--- a/src/xine-engine/buffer.h
+++ b/src/xine-engine/buffer.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: buffer.h,v 1.109 2003/04/23 16:15:01 mroi Exp $
+ * $Id: buffer.h,v 1.110 2003/04/30 08:49:40 heinchen Exp $
*
*
* contents:
@@ -144,7 +144,7 @@ extern "C" {
#define BUF_VIDEO_YUV_FRAMES 0x023B0000 /* uncompressed YUV, delivered by v4l input plugin */
#define BUF_VIDEO_HUFFYUV 0x023C0000
#define BUF_VIDEO_IMAGE 0x023D0000
-
+#define BUF_VIDEO_THEORA 0x023E0000
/* audio buffer types: (please keep in sync with buffer_types.c) */