summaryrefslogtreecommitdiff
path: root/src/libtheora/xine_decoder.c
diff options
context:
space:
mode:
authorAndreas Heinchen <heinchen@users.sourceforge.net>2003-04-30 08:49:38 +0000
committerAndreas Heinchen <heinchen@users.sourceforge.net>2003-04-30 08:49:38 +0000
commit7c37edf153ed35a0e753b47fb573e155671f97d3 (patch)
tree62cfa5db0221b774b702a62c4a45c15213e5c700 /src/libtheora/xine_decoder.c
parent4f1dc4c3cebf7ba10aa9b59866c4e2f7a0bfd852 (diff)
downloadxine-lib-7c37edf153ed35a0e753b47fb573e155671f97d3.tar.gz
xine-lib-7c37edf153ed35a0e753b47fb573e155671f97d3.tar.bz2
added support for theora
CVS patchset: 4717 CVS date: 2003/04/30 08:49:38
Diffstat (limited to 'src/libtheora/xine_decoder.c')
-rw-r--r--src/libtheora/xine_decoder.c361
1 files changed, 361 insertions, 0 deletions
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 }
+};