diff options
author | Andreas Heinchen <heinchen@users.sourceforge.net> | 2003-04-30 08:49:38 +0000 |
---|---|---|
committer | Andreas Heinchen <heinchen@users.sourceforge.net> | 2003-04-30 08:49:38 +0000 |
commit | 7c37edf153ed35a0e753b47fb573e155671f97d3 (patch) | |
tree | 62cfa5db0221b774b702a62c4a45c15213e5c700 /src/libtheora/xine_decoder.c | |
parent | 4f1dc4c3cebf7ba10aa9b59866c4e2f7a0bfd852 (diff) | |
download | xine-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.c | 361 |
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 } +}; |