diff options
Diffstat (limited to 'thirdparty/libtheora/huffdec.c')
-rw-r--r-- | thirdparty/libtheora/huffdec.c | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/thirdparty/libtheora/huffdec.c b/thirdparty/libtheora/huffdec.c new file mode 100644 index 0000000000..8cf27f0341 --- /dev/null +++ b/thirdparty/libtheora/huffdec.c @@ -0,0 +1,489 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: + last mod: $Id: huffdec.c 16503 2009-08-22 18:14:02Z giles $ + + ********************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <ogg/ogg.h> +#include "huffdec.h" +#include "decint.h" + + +/*The ANSI offsetof macro is broken on some platforms (e.g., older DECs).*/ +#define _ogg_offsetof(_type,_field)\ + ((size_t)((char *)&((_type *)0)->_field-(char *)0)) + +/*The number of internal tokens associated with each of the spec tokens.*/ +static const unsigned char OC_DCT_TOKEN_MAP_ENTRIES[TH_NDCT_TOKENS]={ + 1,1,1,4,8,1,1,8,1,1,1,1,1,2,2,2,2,4,8,2,2,2,4,2,2,2,2,2,8,2,4,8 +}; + +/*The map from external spec-defined tokens to internal tokens. + This is constructed so that any extra bits read with the original token value + can be masked off the least significant bits of its internal token index. + In addition, all of the tokens which require additional extra bits are placed + at the start of the list, and grouped by type. + OC_DCT_REPEAT_RUN3_TOKEN is placed first, as it is an extra-special case, so + giving it index 0 may simplify comparisons on some architectures. + These requirements require some substantial reordering.*/ +static const unsigned char OC_DCT_TOKEN_MAP[TH_NDCT_TOKENS]={ + /*OC_DCT_EOB1_TOKEN (0 extra bits)*/ + 15, + /*OC_DCT_EOB2_TOKEN (0 extra bits)*/ + 16, + /*OC_DCT_EOB3_TOKEN (0 extra bits)*/ + 17, + /*OC_DCT_REPEAT_RUN0_TOKEN (2 extra bits)*/ + 88, + /*OC_DCT_REPEAT_RUN1_TOKEN (3 extra bits)*/ + 80, + /*OC_DCT_REPEAT_RUN2_TOKEN (4 extra bits)*/ + 1, + /*OC_DCT_REPEAT_RUN3_TOKEN (12 extra bits)*/ + 0, + /*OC_DCT_SHORT_ZRL_TOKEN (3 extra bits)*/ + 48, + /*OC_DCT_ZRL_TOKEN (6 extra bits)*/ + 14, + /*OC_ONE_TOKEN (0 extra bits)*/ + 56, + /*OC_MINUS_ONE_TOKEN (0 extra bits)*/ + 57, + /*OC_TWO_TOKEN (0 extra bits)*/ + 58, + /*OC_MINUS_TWO_TOKEN (0 extra bits)*/ + 59, + /*OC_DCT_VAL_CAT2 (1 extra bit)*/ + 60, + 62, + 64, + 66, + /*OC_DCT_VAL_CAT3 (2 extra bits)*/ + 68, + /*OC_DCT_VAL_CAT4 (3 extra bits)*/ + 72, + /*OC_DCT_VAL_CAT5 (4 extra bits)*/ + 2, + /*OC_DCT_VAL_CAT6 (5 extra bits)*/ + 4, + /*OC_DCT_VAL_CAT7 (6 extra bits)*/ + 6, + /*OC_DCT_VAL_CAT8 (10 extra bits)*/ + 8, + /*OC_DCT_RUN_CAT1A (1 extra bit)*/ + 18, + 20, + 22, + 24, + 26, + /*OC_DCT_RUN_CAT1B (3 extra bits)*/ + 32, + /*OC_DCT_RUN_CAT1C (4 extra bits)*/ + 12, + /*OC_DCT_RUN_CAT2A (2 extra bits)*/ + 28, + /*OC_DCT_RUN_CAT2B (3 extra bits)*/ + 40 +}; + +/*These three functions are really part of the bitpack.c module, but + they are only used here. + Declaring local static versions so they can be inlined saves considerable + function call overhead.*/ + +static oc_pb_window oc_pack_refill(oc_pack_buf *_b,int _bits){ + const unsigned char *ptr; + const unsigned char *stop; + oc_pb_window window; + int available; + window=_b->window; + available=_b->bits; + ptr=_b->ptr; + stop=_b->stop; + /*This version of _refill() doesn't bother setting eof because we won't + check for it after we've started decoding DCT tokens.*/ + if(ptr>=stop)available=OC_LOTS_OF_BITS; + while(available<=OC_PB_WINDOW_SIZE-8){ + available+=8; + window|=(oc_pb_window)*ptr++<<OC_PB_WINDOW_SIZE-available; + if(ptr>=stop)available=OC_LOTS_OF_BITS; + } + _b->ptr=ptr; + if(_bits>available)window|=*ptr>>(available&7); + _b->bits=available; + return window; +} + + +/*Read in bits without advancing the bit pointer. + Here we assume 0<=_bits&&_bits<=32.*/ +static long oc_pack_look(oc_pack_buf *_b,int _bits){ + oc_pb_window window; + int available; + long result; + window=_b->window; + available=_b->bits; + if(_bits==0)return 0; + if(_bits>available)_b->window=window=oc_pack_refill(_b,_bits); + result=window>>OC_PB_WINDOW_SIZE-_bits; + return result; +} + +/*Advance the bit pointer.*/ +static void oc_pack_adv(oc_pack_buf *_b,int _bits){ + /*We ignore the special cases for _bits==0 and _bits==32 here, since they are + never used actually used. + OC_HUFF_SLUSH (defined below) would have to be at least 27 to actually read + 32 bits in a single go, and would require a 32 GB lookup table (assuming + 8 byte pointers, since 4 byte pointers couldn't fit such a table).*/ + _b->window<<=_bits; + _b->bits-=_bits; +} + + +/*The log_2 of the size of a lookup table is allowed to grow to relative to + the number of unique nodes it contains. + E.g., if OC_HUFF_SLUSH is 2, then at most 75% of the space in the tree is + wasted (each node will have an amortized cost of at most 20 bytes when using + 4-byte pointers). + Larger numbers can decode tokens with fewer read operations, while smaller + numbers may save more space (requiring as little as 8 bytes amortized per + node, though there will be more nodes). + With a sample file: + 32233473 read calls are required when no tree collapsing is done (100.0%). + 19269269 read calls are required when OC_HUFF_SLUSH is 0 (59.8%). + 11144969 read calls are required when OC_HUFF_SLUSH is 1 (34.6%). + 10538563 read calls are required when OC_HUFF_SLUSH is 2 (32.7%). + 10192578 read calls are required when OC_HUFF_SLUSH is 3 (31.6%). + Since a value of 1 gets us the vast majority of the speed-up with only a + small amount of wasted memory, this is what we use.*/ +#define OC_HUFF_SLUSH (1) + + +/*Determines the size in bytes of a Huffman tree node that represents a + subtree of depth _nbits. + _nbits: The depth of the subtree. + If this is 0, the node is a leaf node. + Otherwise 1<<_nbits pointers are allocated for children. + Return: The number of bytes required to store the node.*/ +static size_t oc_huff_node_size(int _nbits){ + size_t size; + size=_ogg_offsetof(oc_huff_node,nodes); + if(_nbits>0)size+=sizeof(oc_huff_node *)*(1<<_nbits); + return size; +} + +static oc_huff_node *oc_huff_node_init(char **_storage,size_t _size,int _nbits){ + oc_huff_node *ret; + ret=(oc_huff_node *)*_storage; + ret->nbits=(unsigned char)_nbits; + (*_storage)+=_size; + return ret; +} + + +/*Determines the size in bytes of a Huffman tree. + _nbits: The depth of the subtree. + If this is 0, the node is a leaf node. + Otherwise storage for 1<<_nbits pointers are added for children. + Return: The number of bytes required to store the tree.*/ +static size_t oc_huff_tree_size(const oc_huff_node *_node){ + size_t size; + size=oc_huff_node_size(_node->nbits); + if(_node->nbits){ + int nchildren; + int i; + nchildren=1<<_node->nbits; + for(i=0;i<nchildren;i+=1<<_node->nbits-_node->nodes[i]->depth){ + size+=oc_huff_tree_size(_node->nodes[i]); + } + } + return size; +} + + +/*Unpacks a sub-tree from the given buffer. + _opb: The buffer to unpack from. + _binodes: The nodes to store the sub-tree in. + _nbinodes: The number of nodes available for the sub-tree. + Return: 0 on success, or a negative value on error.*/ +static int oc_huff_tree_unpack(oc_pack_buf *_opb, + oc_huff_node *_binodes,int _nbinodes){ + oc_huff_node *binode; + long bits; + int nused; + if(_nbinodes<1)return TH_EBADHEADER; + binode=_binodes; + nused=0; + bits=oc_pack_read1(_opb); + if(oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER; + /*Read an internal node:*/ + if(!bits){ + int ret; + nused++; + binode->nbits=1; + binode->depth=1; + binode->nodes[0]=_binodes+nused; + ret=oc_huff_tree_unpack(_opb,_binodes+nused,_nbinodes-nused); + if(ret>=0){ + nused+=ret; + binode->nodes[1]=_binodes+nused; + ret=oc_huff_tree_unpack(_opb,_binodes+nused,_nbinodes-nused); + } + if(ret<0)return ret; + nused+=ret; + } + /*Read a leaf node:*/ + else{ + int ntokens; + int token; + int i; + bits=oc_pack_read(_opb,OC_NDCT_TOKEN_BITS); + if(oc_pack_bytes_left(_opb)<0)return TH_EBADHEADER; + /*Find out how many internal tokens we translate this external token into.*/ + ntokens=OC_DCT_TOKEN_MAP_ENTRIES[bits]; + if(_nbinodes<2*ntokens-1)return TH_EBADHEADER; + /*Fill in a complete binary tree pointing to the internal tokens.*/ + for(i=1;i<ntokens;i<<=1){ + int j; + binode=_binodes+nused; + nused+=i; + for(j=0;j<i;j++){ + binode[j].nbits=1; + binode[j].depth=1; + binode[j].nodes[0]=_binodes+nused+2*j; + binode[j].nodes[1]=_binodes+nused+2*j+1; + } + } + /*And now the leaf nodes with those tokens.*/ + token=OC_DCT_TOKEN_MAP[bits]; + for(i=0;i<ntokens;i++){ + binode=_binodes+nused++; + binode->nbits=0; + binode->depth=1; + binode->token=token+i; + } + } + return nused; +} + +/*Finds the depth of shortest branch of the given sub-tree. + The tree must be binary. + _binode: The root of the given sub-tree. + _binode->nbits must be 0 or 1. + Return: The smallest depth of a leaf node in this sub-tree. + 0 indicates this sub-tree is a leaf node.*/ +static int oc_huff_tree_mindepth(oc_huff_node *_binode){ + int depth0; + int depth1; + if(_binode->nbits==0)return 0; + depth0=oc_huff_tree_mindepth(_binode->nodes[0]); + depth1=oc_huff_tree_mindepth(_binode->nodes[1]); + return OC_MINI(depth0,depth1)+1; +} + +/*Finds the number of internal nodes at a given depth, plus the number of + leaves at that depth or shallower. + The tree must be binary. + _binode: The root of the given sub-tree. + _binode->nbits must be 0 or 1. + Return: The number of entries that would be contained in a jump table of the + given depth.*/ +static int oc_huff_tree_occupancy(oc_huff_node *_binode,int _depth){ + if(_binode->nbits==0||_depth<=0)return 1; + else{ + return oc_huff_tree_occupancy(_binode->nodes[0],_depth-1)+ + oc_huff_tree_occupancy(_binode->nodes[1],_depth-1); + } +} + +/*Makes a copy of the given Huffman tree. + _node: The Huffman tree to copy. + Return: The copy of the Huffman tree.*/ +static oc_huff_node *oc_huff_tree_copy(const oc_huff_node *_node, + char **_storage){ + oc_huff_node *ret; + ret=oc_huff_node_init(_storage,oc_huff_node_size(_node->nbits),_node->nbits); + ret->depth=_node->depth; + if(_node->nbits){ + int nchildren; + int i; + int inext; + nchildren=1<<_node->nbits; + for(i=0;i<nchildren;){ + ret->nodes[i]=oc_huff_tree_copy(_node->nodes[i],_storage); + inext=i+(1<<_node->nbits-ret->nodes[i]->depth); + while(++i<inext)ret->nodes[i]=ret->nodes[i-1]; + } + } + else ret->token=_node->token; + return ret; +} + +static size_t oc_huff_tree_collapse_size(oc_huff_node *_binode,int _depth){ + size_t size; + int mindepth; + int depth; + int loccupancy; + int occupancy; + if(_binode->nbits!=0&&_depth>0){ + return oc_huff_tree_collapse_size(_binode->nodes[0],_depth-1)+ + oc_huff_tree_collapse_size(_binode->nodes[1],_depth-1); + } + depth=mindepth=oc_huff_tree_mindepth(_binode); + occupancy=1<<mindepth; + do{ + loccupancy=occupancy; + occupancy=oc_huff_tree_occupancy(_binode,++depth); + } + while(occupancy>loccupancy&&occupancy>=1<<OC_MAXI(depth-OC_HUFF_SLUSH,0)); + depth--; + size=oc_huff_node_size(depth); + if(depth>0){ + size+=oc_huff_tree_collapse_size(_binode->nodes[0],depth-1); + size+=oc_huff_tree_collapse_size(_binode->nodes[1],depth-1); + } + return size; +} + +static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode, + char **_storage); + +/*Fills the given nodes table with all the children in the sub-tree at the + given depth. + The nodes in the sub-tree with a depth less than that stored in the table + are freed. + The sub-tree must be binary and complete up until the given depth. + _nodes: The nodes table to fill. + _binode: The root of the sub-tree to fill it with. + _binode->nbits must be 0 or 1. + _level: The current level in the table. + 0 indicates that the current node should be stored, regardless of + whether it is a leaf node or an internal node. + _depth: The depth of the nodes to fill the table with, relative to their + parent.*/ +static void oc_huff_node_fill(oc_huff_node **_nodes, + oc_huff_node *_binode,int _level,int _depth,char **_storage){ + if(_level<=0||_binode->nbits==0){ + int i; + _binode->depth=(unsigned char)(_depth-_level); + _nodes[0]=oc_huff_tree_collapse(_binode,_storage); + for(i=1;i<1<<_level;i++)_nodes[i]=_nodes[0]; + } + else{ + _level--; + oc_huff_node_fill(_nodes,_binode->nodes[0],_level,_depth,_storage); + _nodes+=1<<_level; + oc_huff_node_fill(_nodes,_binode->nodes[1],_level,_depth,_storage); + } +} + +/*Finds the largest complete sub-tree rooted at the current node and collapses + it into a single node. + This procedure is then applied recursively to all the children of that node. + _binode: The root of the sub-tree to collapse. + _binode->nbits must be 0 or 1. + Return: The new root of the collapsed sub-tree.*/ +static oc_huff_node *oc_huff_tree_collapse(oc_huff_node *_binode, + char **_storage){ + oc_huff_node *root; + size_t size; + int mindepth; + int depth; + int loccupancy; + int occupancy; + depth=mindepth=oc_huff_tree_mindepth(_binode); + occupancy=1<<mindepth; + do{ + loccupancy=occupancy; + occupancy=oc_huff_tree_occupancy(_binode,++depth); + } + while(occupancy>loccupancy&&occupancy>=1<<OC_MAXI(depth-OC_HUFF_SLUSH,0)); + depth--; + if(depth<=1)return oc_huff_tree_copy(_binode,_storage); + size=oc_huff_node_size(depth); + root=oc_huff_node_init(_storage,size,depth); + root->depth=_binode->depth; + oc_huff_node_fill(root->nodes,_binode,depth,depth,_storage); + return root; +} + +/*Unpacks a set of Huffman trees, and reduces them to a collapsed + representation. + _opb: The buffer to unpack the trees from. + _nodes: The table to fill with the Huffman trees. + Return: 0 on success, or a negative value on error.*/ +int oc_huff_trees_unpack(oc_pack_buf *_opb, + oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]){ + int i; + for(i=0;i<TH_NHUFFMAN_TABLES;i++){ + oc_huff_node nodes[511]; + char *storage; + size_t size; + int ret; + /*Unpack the full tree into a temporary buffer.*/ + ret=oc_huff_tree_unpack(_opb,nodes,sizeof(nodes)/sizeof(*nodes)); + if(ret<0)return ret; + /*Figure out how big the collapsed tree will be.*/ + size=oc_huff_tree_collapse_size(nodes,0); + storage=(char *)_ogg_calloc(1,size); + if(storage==NULL)return TH_EFAULT; + /*And collapse it.*/ + _nodes[i]=oc_huff_tree_collapse(nodes,&storage); + } + return 0; +} + +/*Makes a copy of the given set of Huffman trees. + _dst: The array to store the copy in. + _src: The array of trees to copy.*/ +int oc_huff_trees_copy(oc_huff_node *_dst[TH_NHUFFMAN_TABLES], + const oc_huff_node *const _src[TH_NHUFFMAN_TABLES]){ + int i; + for(i=0;i<TH_NHUFFMAN_TABLES;i++){ + size_t size; + char *storage; + size=oc_huff_tree_size(_src[i]); + storage=(char *)_ogg_calloc(1,size); + if(storage==NULL){ + while(i-->0)_ogg_free(_dst[i]); + return TH_EFAULT; + } + _dst[i]=oc_huff_tree_copy(_src[i],&storage); + } + return 0; +} + +/*Frees the memory used by a set of Huffman trees. + _nodes: The array of trees to free.*/ +void oc_huff_trees_clear(oc_huff_node *_nodes[TH_NHUFFMAN_TABLES]){ + int i; + for(i=0;i<TH_NHUFFMAN_TABLES;i++)_ogg_free(_nodes[i]); +} + +/*Unpacks a single token using the given Huffman tree. + _opb: The buffer to unpack the token from. + _node: The tree to unpack the token with. + Return: The token value.*/ +int oc_huff_token_decode(oc_pack_buf *_opb,const oc_huff_node *_node){ + long bits; + while(_node->nbits!=0){ + bits=oc_pack_look(_opb,_node->nbits); + _node=_node->nodes[bits]; + oc_pack_adv(_opb,_node->depth); + } + return _node->token; +} |