diff options
author | Mike Melanson <mike@multimedia.cx> | 2002-08-12 00:16:54 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2002-08-12 00:16:54 +0000 |
commit | d6cb2c43bec1cb3194193afd29accdff9124a975 (patch) | |
tree | 4e079451116799b300d518cc8c2af27d4bb47d98 | |
parent | d85a0d15b414e12acebc11bd5a8d0834bd32351d (diff) | |
download | xine-lib-d6cb2c43bec1cb3194193afd29accdff9124a975.tar.gz xine-lib-d6cb2c43bec1cb3194193afd29accdff9124a975.tar.bz2 |
initial commit for Dr. Tim's Id CIN video decoder
CVS patchset: 2438
CVS date: 2002/08/12 00:16:54
-rw-r--r-- | src/libxinevdec/Makefile.am | 5 | ||||
-rw-r--r-- | src/libxinevdec/idcinvideo.c | 424 |
2 files changed, 428 insertions, 1 deletions
diff --git a/src/libxinevdec/Makefile.am b/src/libxinevdec/Makefile.am index 0af976c4c..04df1b283 100644 --- a/src/libxinevdec/Makefile.am +++ b/src/libxinevdec/Makefile.am @@ -11,7 +11,7 @@ lib_LTLIBRARIES = xineplug_decode_cinepak.la xineplug_decode_cyuv.la \ xineplug_decode_msvc.la xineplug_decode_roqvideo.la \ xineplug_decode_svq1.la xineplug_decode_fli.la \ xineplug_decode_rgb.la xineplug_decode_yuv.la \ - xineplug_decode_msrle.la + xineplug_decode_msrle.la xineplug_decode_idcinvideo.la xineplug_decode_cinepak_la_SOURCES = cinepak.c xineplug_decode_cinepak_la_LDFLAGS = -avoid-version -module @@ -40,6 +40,9 @@ xineplug_decode_yuv_la_LDFLAGS = -avoid-version -module xineplug_decode_msrle_la_SOURCES = msrle.c xineplug_decode_msrle_la_LDFLAGS = -avoid-version -module +xineplug_decode_idcinvideo_la_SOURCES = idcinvideo.c +xineplug_decode_idcinvideo_la_LDFLAGS = -avoid-version -module + noinst_HEADERS = svq1_codebooks.h debug: diff --git a/src/libxinevdec/idcinvideo.c b/src/libxinevdec/idcinvideo.c new file mode 100644 index 000000000..725eff548 --- /dev/null +++ b/src/libxinevdec/idcinvideo.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2000-2002 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 CIN Video Decoder by Dr. Tim Ferguson. For more information about + * the Id CIN format, visit: + * http://www.csse.monash.edu.au/~timf/ + * + * $Id: idcinvideo.c,v 1.1 2002/08/12 00:16:54 tmmm Exp $ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "video_out.h" +#include "buffer.h" +#include "xine_internal.h" +#include "xineutils.h" +#include "bswap.h" + +#define VIDEOBUFSIZE 128*1024 + +typedef struct idcinvideo_decoder_s { + video_decoder_t video_decoder; /* parent video decoder structure */ + + /* these are traditional variables in a video decoder object */ + vo_instance_t *video_out; /* object that will receive frames */ + uint64_t video_step; /* frame duration in pts units */ + int decoder_ok; /* current decoder status */ + int skipframes; + + unsigned char *buf; /* the accumulated buffer data */ + int bufsize; /* the maximum size of buf */ + int size; /* the current size of buf */ + + int width; /* the width of a video frame */ + int height; /* the height of a video frame */ + + unsigned char yuv_palette[256 * 4]; + yuv_planes_t yuv_planes; + +} idcinvideo_decoder_t; + +/************************************************************************** + * idcinvideo specific decode functions + *************************************************************************/ + +#define HUF_TOKENS 256 + +typedef struct +{ + long rate; + long width; + long channels; +} wavinfo_t; + +typedef struct +{ + int count; + unsigned char used; + int children[2]; +} hnode_t; + +static hnode_t huff_nodes[256][HUF_TOKENS*2]; +static int num_huff_nodes[256]; + +/* + * Decodes input Huffman data using the Huffman table. + */ +void huff_decode(idcinvideo_decoder_t *this) { + hnode_t *hnodes; + long i; + int prev; + unsigned char v = 0; + int bit_pos, node_num, dat_pos; + int width_countdown = this->width; + int plane_ptr = 0; + + prev = bit_pos = dat_pos = 0; + for(i = 0; i < (this->width * this->height); i++) { + node_num = num_huff_nodes[prev]; + hnodes = huff_nodes[prev]; + + while(node_num >= HUF_TOKENS) { + if(!bit_pos) { + if(dat_pos > this->size) { + printf("Huffman decode error.\n"); + return; + } + bit_pos = 8; + v = this->buf[dat_pos++]; + } + + node_num = hnodes[node_num].children[v & 0x01]; + v = v >> 1; + bit_pos--; + } + + this->yuv_planes.y[plane_ptr] = this->yuv_palette[node_num * 4 + 0]; + this->yuv_planes.u[plane_ptr] = this->yuv_palette[node_num * 4 + 1]; + this->yuv_planes.v[plane_ptr] = this->yuv_palette[node_num * 4 + 2]; + plane_ptr++; + width_countdown--; + if (!width_countdown) { + FINISH_LINE(this->yuv_planes, plane_ptr - this->width); + width_countdown = this->width; + plane_ptr += 2; + } + + prev = node_num; + } +} + +/* + * Find the lowest probability node in a Huffman table, and mark it as + * being assigned to a higher probability. + * Returns the node index of the lowest unused node, or -1 if all nodes + * are used. + */ +int huff_smallest_node(hnode_t *hnodes, int num_hnodes) { + int i; + int best, best_node; + + best = 99999999; + best_node = -1; + for(i = 0; i < num_hnodes; i++) { + if(hnodes[i].used) + continue; + if(!hnodes[i].count) + continue; + if(hnodes[i].count < best) { + best = hnodes[i].count; + best_node = i; + } + } + + if(best_node == -1) + return -1; + hnodes[best_node].used = 1; + return best_node; +} + +/* + * Build the Huffman tree using the generated/loaded probabilities histogram. + * + * On completion: + * huff_nodes[prev][i < HUF_TOKENS] - are the nodes at the base of the tree. + * huff_nodes[prev][i >= HUF_TOKENS] - are used to construct the tree. + * num_huff_nodes[prev] - contains the index to the root node of the tree. + * That is: huff_nodes[prev][num_huff_nodes[prev]] is the root node. + */ +void huff_build_tree(int prev) { + hnode_t *node, *hnodes; + int num_hnodes, i; + + num_hnodes = HUF_TOKENS; + hnodes = huff_nodes[prev]; + for(i = 0; i < HUF_TOKENS * 2; i++) + hnodes[i].used = 0; + + while (1) { + node = &hnodes[num_hnodes]; /* next free node */ + + /* pick two lowest counts */ + node->children[0] = huff_smallest_node(hnodes, num_hnodes); + if(node->children[0] == -1) + break; /* reached the root node */ + + node->children[1] = huff_smallest_node(hnodes, num_hnodes); + if(node->children[1] == -1) + break; /* reached the root node */ + + /* combine nodes probability for new node */ + node->count = hnodes[node->children[0]].count + + hnodes[node->children[1]].count; + num_hnodes++; + } + + num_huff_nodes[prev] = num_hnodes - 1; +} + + +/************************************************************************** + * xine video plugin functions + *************************************************************************/ + +static int idcinvideo_can_handle (video_decoder_t *this_gen, int buf_type) { + + return (buf_type == BUF_VIDEO_IDCIN); +} + +/* + * This function is responsible is called to initialize the video decoder + * for use. Initialization usually involves setting up the fields in your + * private video decoder object. + */ +static void idcinvideo_init (video_decoder_t *this_gen, + vo_instance_t *video_out) { + idcinvideo_decoder_t *this = (idcinvideo_decoder_t *) this_gen; + + /* set our own video_out object to the one that xine gives us */ + this->video_out = video_out; + + /* indicate that the decoder is not quite ready yet */ + this->decoder_ok = 0; +} + +/* + * This function receives a buffer of data from the demuxer layer and + * figures out how to handle it based on its header flags. + */ +static void idcinvideo_decode_data (video_decoder_t *this_gen, + buf_element_t *buf) { + + idcinvideo_decoder_t *this = (idcinvideo_decoder_t *) this_gen; + palette_entry_t *palette; + unsigned char *histograms; + int i, j, histogram_index = 0; + + vo_frame_t *img; /* video out frame */ + + /* a video decoder does not care about this flag (?) */ + if (buf->decoder_flags & BUF_FLAG_PREVIEW) + return; + + /* load the palette */ + if ((buf->decoder_flags & BUF_FLAG_SPECIAL) && + (buf->decoder_info[1] == BUF_SPECIAL_PALETTE)) { + palette = (palette_entry_t *)buf->decoder_info[3]; + for (i = 0; i < buf->decoder_info[2]; i++) { + this->yuv_palette[i * 4 + 0] = + COMPUTE_Y(palette[i].r, palette[i].g, palette[i].b); + this->yuv_palette[i * 4 + 1] = + COMPUTE_U(palette[i].r, palette[i].g, palette[i].b); + this->yuv_palette[i * 4 + 2] = + COMPUTE_V(palette[i].r, palette[i].g, palette[i].b); + } + } + + /* initialize the Huffman tables */ + if ((buf->decoder_flags & BUF_FLAG_SPECIAL) && + (buf->decoder_info[1] == BUF_SPECIAL_IDCIN_HUFFMAN_TABLE)) { + histograms = (unsigned char *)buf->decoder_info[2]; + for (i = 0; i < 256; i++) { + for(j = 0; j < HUF_TOKENS; j++) + huff_nodes[i][j].count = histograms[histogram_index++]; + huff_build_tree(i); + } + + } + + if (buf->decoder_flags & BUF_FLAG_HEADER) { /* need to initialize */ + this->video_out->open (this->video_out); + + if(this->buf) + free(this->buf); + + this->width = (buf->content[0] << 8) | buf->content[1]; + this->height = (buf->content[2] << 8) | buf->content[3]; + this->video_step = buf->decoder_info[1]; + + if (this->buf) + free (this->buf); + this->bufsize = VIDEOBUFSIZE; + this->buf = malloc(this->bufsize); + this->size = 0; + + this->video_out->open (this->video_out); + this->decoder_ok = 1; + + init_yuv_planes(&this->yuv_planes, this->width, this->height); + + return; + } else if (this->decoder_ok) { + + if (this->size + buf->size > this->bufsize) { + this->bufsize = this->size + 2 * buf->size; + this->buf = realloc (this->buf, this->bufsize); + } + + xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size); + + this->size += buf->size; + + if (buf->decoder_flags & BUF_FLAG_FRAMERATE) + this->video_step = buf->decoder_info[0]; + + if (buf->decoder_flags & BUF_FLAG_FRAME_END) { + + img = this->video_out->get_frame (this->video_out, + this->width, this->height, + 42, IMGFMT_YUY2, VO_BOTH_FIELDS); + + img->duration = this->video_step; + img->pts = buf->pts; + img->bad_frame = 0; + + huff_decode(this); + yuv444_to_yuy2(&this->yuv_planes, img->base[0], img->pitches[0]); + + if (img->copy) { + int height = img->height; + uint8_t *src[3]; + + src[0] = img->base[0]; + + while ((height -= 16) >= 0) { + img->copy(img, src); + src[0] += 16 * img->pitches[0]; + } + } + + img->draw(img); + img->free(img); + + this->size = 0; + } + } +} + +/* + * This function is called when xine needs to flush the system. Not + * sure when or if this is used or even if it needs to do anything. + */ +static void idcinvideo_flush (video_decoder_t *this_gen) { +} + +/* + * This function resets the video decoder. + */ +static void idcinvideo_reset (video_decoder_t *this_gen) { + idcinvideo_decoder_t *this = (idcinvideo_decoder_t *) this_gen; + + this->size = 0; +} + +/* + * This function is called when xine shuts down the decoder. It should + * free any memory and release any other resources allocated during the + * execution of the decoder. + */ +static void idcinvideo_close (video_decoder_t *this_gen) { + idcinvideo_decoder_t *this = (idcinvideo_decoder_t *) this_gen; + + if (this->buf) { + free (this->buf); + this->buf = NULL; + } + + if (this->decoder_ok) { + this->decoder_ok = 0; + this->video_out->close(this->video_out); + } +} + +/* + * This function returns the human-readable ID string to identify + * this decoder. + */ +static char *idcinvideo_get_id(void) { + return "Id CIN Video"; +} + +/* + * This function frees the video decoder instance allocated to the decoder. + */ +static void idcinvideo_dispose (video_decoder_t *this_gen) { + free (this_gen); +} + +/* + * This function should be the plugin's only advertised function to the + * outside world. It allows xine to query the plugin module for the addresses + * to the necessary functions in the video decoder object. The video + * decoder object also has a priority field which allows different decoder + * plugins for the same buffer types to coexist peacefully. The higher the + * priority number, the more precedence a decoder has. E.g., 9 beats 1. + */ +video_decoder_t *init_video_decoder_plugin (int iface_version, xine_t *xine) { + + idcinvideo_decoder_t *this ; + + if (iface_version != 10) { + printf( "idcinvideo: plugin doesn't support plugin API version %d.\n" + "idcinvideo: this means there's a version mismatch between xine and this " + "idcinvideo: decoder plugin.\nInstalling current plugins should help.\n", + iface_version); + return NULL; + } + + this = (idcinvideo_decoder_t *) malloc (sizeof (idcinvideo_decoder_t)); + memset(this, 0, sizeof (idcinvideo_decoder_t)); + + this->video_decoder.interface_version = iface_version; + this->video_decoder.can_handle = idcinvideo_can_handle; + this->video_decoder.init = idcinvideo_init; + this->video_decoder.decode_data = idcinvideo_decode_data; + this->video_decoder.flush = idcinvideo_flush; + this->video_decoder.reset = idcinvideo_reset; + this->video_decoder.close = idcinvideo_close; + this->video_decoder.get_identifier = idcinvideo_get_id; + this->video_decoder.dispose = idcinvideo_dispose; + this->video_decoder.priority = 1; + + return (video_decoder_t *) this; +} |