⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coder.c

📁 本程序可以对文件进行算术编码处理 解码处理等
💻 C
字号:
/******************************************************************************
File:		coder.c

Authors: 	John Carpinelli   (johnfc@ecr.mu.oz.au)
	 	Wayne Salamonsen  (wbs@mundil.cs.mu.oz.au)

Purpose:	Data compression using a word-based model and revised 
		arithmetic coding method.

Based on: 	A. Moffat, R. Neal, I.H. Witten, "Arithmetic Coding Revisted",
		Proc. IEEE Data Compression Conference, Snowbird, Utah, 
		March 1995.

		Low-Precision Arithmetic Coding Implementation by 
		Radford M. Neal



Copyright 1995 John Carpinelli and Wayne Salamonsen, All Rights Reserved.

These programs are supplied free of charge for research purposes only,
and may not sold or incorporated into any commercial product.  There is
ABSOLUTELY NO WARRANTY of any sort, nor any undertaking that they are
fit for ANY PURPOSE WHATSOEVER.  Use them at your own risk.  If you do
happen to find a bug, or have modifications to suggest, please report
the same to Alistair Moffat, alistair@cs.mu.oz.au.  The copyright
notice above and this statement of conditions must remain an integral
part of each and every copy made of these files.

******************************************************************************/
#include <stdio.h>
#include "coder.h"

unsigned long	L;				/* lower bound */
unsigned long	R;				/* code range */
unsigned long	V;				/* current code value */
unsigned long 	r;				/* normalized range */

int 		bits_outstanding;		/* follow bit count */
int	 	buffer;				/* I/O buffer */
int		bits_to_go;			/* bits left in buffer */
unsigned int	bytes_input, bytes_output;	/* I/O counters */


/*
 *
 * responsible for outputing the bit passed to it and an opposite number of
 * bit equal to the value stored in bits_outstanding
 *
 */
#define BIT_PLUS_FOLLOW(b)		\
do                                      \
{ 	  			        \
    OUTPUT_BIT((b));           		\
    while (bits_outstanding > 0)	\
    { 					\
	OUTPUT_BIT(!(b));      		\
	bits_outstanding -= 1;    	\
    } 	                		\
} while (0)


/*
 *
 * responsible for outputting one bit. adds the bit to a buffer 
 * and once the buffer has 8 bits, it outputs a character
 *
 */
#define OUTPUT_BIT(b)            	\
do { 					\
    buffer >>= 1;             		\
    if (b) 				\
	buffer |= 1 << (BYTE_SIZE-1);	\
    bits_to_go -= 1;            	\
    if (bits_to_go == 0)        	\
    { 					\
	putc(buffer, stdout); 		\
	bytes_output += 1;		\
        bits_to_go = BYTE_SIZE;      	\
    }	                       		\
} while (0)


/*
 *
 * reads in bits from encoded file 
 * reads in a char at a time into a buffer i.e 8 bits
 *
 */
#define ADD_NEXT_INPUT_BIT(v) 		\
do { 					\
    bits_to_go -= 1;			\
    if (bits_to_go < 0) 		\
    { 					\
	buffer = getc(stdin);		\
	bits_to_go = BYTE_SIZE - 1;	\
    } 					\
    v += v + (buffer & 1); 		\
    buffer >>= 1; 			\
} while (0) 

/*
 * output code bits until the range as been expanded
 * to above QUARTER
 */
#define ENCODE_RENORMALISE		\
do {					\
    while (R < QUARTER)			\
    {					\
        if (L >= HALF)			\
    	{				\
    	    BIT_PLUS_FOLLOW(1);		\
    	    L -= HALF;			\
    	}				\
    	else if (L+R <= HALF)		\
    	{				\
    	    BIT_PLUS_FOLLOW(0);		\
    	}				\
    	else 				\
    	{				\
    	    bits_outstanding++;		\
    	    L -= QUARTER;		\
    	}				\
    	L += L;				\
    	R += R;				\
    }					\
} while (0)


/*
 * input code bits until range has been expanded to
 * more than QUARTER. Mimics encoder.
 */
#define DECODE_RENORMALISE		\
do {					\
    while (R < QUARTER)			\
    {					\
    	if (L >= HALF)			\
    	{				\
    	    V -= HALF;			\
    	    L -= HALF;			\
    	    bits_outstanding = 0;	\
    	}				\
    	else if (L+R <= HALF)		\
    	{				\
    	    bits_outstanding = 0;	\
    	}				\
    	else				\
    	{				\
    	    V -= QUARTER;		\
    	    L -= QUARTER;		\
    	    bits_outstanding++;		\
    	}				\
    	L += L;				\
    	R += R;				\
    	ADD_NEXT_INPUT_BIT(V);		\
    }					\
} while (0)



/*
 *
 * encode a symbol given its low, high and total frequencies
 *
 */
void 
arithmetic_encode(unsigned int low, unsigned int high, unsigned int total)
{
    unsigned long temp; 

#ifndef SHIFT_ADD
    r = R/total;
    temp = r*low;
    L += temp;
    if (high < total)
	R = r*(high-low);
    else
	R -= temp;
#else
{
    int i, nShifts;
    unsigned long numerator, denominator;
    unsigned long temp2;

    /*
     * calculate r = R/total, temp = r*low and temp2 = r*high
     * using shifts and adds 
     */
    numerator = R;
    nShifts = CODE_BITS - f_bits - 1;
    denominator = total << nShifts;
    r = 0;
    temp = 0;
    temp2 = 0;
    for (i = nShifts;; i--) 
    {
        if (numerator >= denominator) 
	{ 
	    numerator -= denominator; 
	    r++; 
	    temp += low;
	    temp2 += high;
	}
	if (i == 0) break;
        numerator <<= 1; r <<= 1; temp <<= 1; temp2 <<= 1;
    }
    L += temp;
    if (high < total)
	R = temp2 - temp;
    else
	R -= temp;
}
#endif

    ENCODE_RENORMALISE;

    if (bits_outstanding >= MAX_BITS_OUTSTANDING)
    {
	finish_encode();
	start_encode();
    }
}



/*
 *
 * decode the target value using the current total frequency
 * and the coder's state variables
 *
 */
unsigned 
int arithmetic_decode_target(unsigned int total)
{
    unsigned long target;
    
#ifndef SHIFT_ADD
    r = R/total;
    target = (V-L)/r;
#else 
{	
    int i, nShifts;
    unsigned long numerator, denominator;

    /* divide r = R/total using shifts and adds */
    numerator = R;
    nShifts = CODE_BITS - f_bits - 1;
    denominator = total << nShifts;
    r = 0;
    for (i = nShifts;; i--) 
    {
        if (numerator >= denominator) 
	{ 
	    numerator -= denominator; 
	    r++; 
	}
	if (i == 0) break;
        numerator <<= 1; r <<= 1;
    }

    /* divide V-L by r using shifts and adds */
    if (r < (1 << (CODE_BITS - f_bits - 1)))
	nShifts = f_bits;
    else
	nShifts = f_bits - 1;
    numerator = V - L;
    denominator = r << nShifts;
    target = 0;
    for (i = nShifts;; i--) 
    {
        if (numerator >= denominator) 
	{ 
	    numerator -= denominator; 
	    target++; 
	}
	if (i == 0) break;
        numerator <<= 1; target <<= 1;
    }
}
#endif
    return (target >= total? total-1 : target);
}



/*
 *
 * decode the next input symbol
 *
 */
void 
arithmetic_decode(unsigned int low, unsigned int high, unsigned int total)
{     
    unsigned int temp;

#ifndef SHIFT_ADD
    /* assume r has been set by decode_target */
    temp = r*low;
    L += temp;
    if (high < total)
	R = r*(high-low);
    else
	R -= temp;
#else
{
    int i, nShifts;
    unsigned long temp2;
    
    /* calculate r*low and r*high using shifts and adds */
    r <<= f_bits;
    temp = 0;
    nShifts = CODE_BITS - f_bits - 1;
    temp2 = 0;
    for (i = nShifts;; i--) 
    {
	if (r >= HALF)
	{ 
	    temp += low;
	    temp2 += high;
	}
	if (i == 0) break;
        r <<= 1; temp <<= 1; temp2 <<= 1;
    }
    L += temp;
    if (high < total)
	R = temp2 - temp;
    else
	R -= temp;
 }
#endif

    DECODE_RENORMALISE;

    if (bits_outstanding >= MAX_BITS_OUTSTANDING)
    {
	finish_decode();	
	start_decode();
    }
}



/*
 * 
 * encode a binary symbol using specialised binary encoding
 * algorithm
 *
 */
void
binary_arithmetic_encode(int c0, int c1, int bit)
{
    int LPS, cLPS, rLPS;

    if (c0 < c1) 
    {
	LPS = 0;
	cLPS = c0;
    } else {
	LPS = 1;
	cLPS = c1;
    }
#ifndef SHIFT_ADD
    r = R / (c0+c1);
    rLPS = r * cLPS;
#else
{	
    int i, nShifts;
    unsigned long int numerator, denominator;

    numerator = R;
    nShifts = CODE_BITS - f_bits - 1;
    denominator = (c0 + c1) << nShifts;
    r = 0;
    rLPS = 0;
    for (i = nShifts;; i--) 
    {
	if (numerator >= denominator) 
	{ 
	    numerator -= denominator; 
	    r++;
	    rLPS += cLPS;
	}
	if (i == 0) break;
	numerator <<= 1; r <<= 1; rLPS <<= 1;
    }
}
#endif
    if (bit == LPS) 
    {
	L += R - rLPS;
	R = rLPS;
    } else {
	R -= rLPS;
    }

    /* renormalise, as for arith_encode */
    ENCODE_RENORMALISE;

    if (bits_outstanding > MAX_BITS_OUTSTANDING)
    {
	finish_encode();
	start_encode();
    }
}



/*
 *
 * decode a binary symbol given the frequencies of 1 and 0 for
 * the context
 *
 */
int
binary_arithmetic_decode(int c0, int c1)
{
    int LPS, cLPS, rLPS, bit;

    if (c0 < c1) 
    {
	LPS = 0;
	cLPS = c0;
    } else {
	LPS = 1;
	cLPS = c1;
    }
#ifndef SHIFT_ADD
    r = R / (c0+c1);
    rLPS = r * cLPS;
#else 
{
    int i, nShifts;
    unsigned long int numerator, denominator;

    numerator = R;
    nShifts = CODE_BITS - f_bits - 1;
    denominator = (c0 + c1) << nShifts;
    r = 0;
    rLPS = 0;
    for (i = nShifts;; i--) 
    {
	if (numerator >= denominator) 
	{ 
	    numerator -= denominator; 
	    r++;
	    rLPS += cLPS;
	}
	if (i == 0) break;
	numerator <<= 1; r <<= 1; rLPS <<= 1;
    }
}
#endif
    if ((V-L) >= (R-rLPS)) 
    {
	bit = LPS;
	L += R - rLPS;
	R = rLPS;
    } else {
	bit = (1-LPS);
	R -= rLPS;
    }

    /* renormalise, as for arith_decode */
    DECODE_RENORMALISE;

    if (bits_outstanding > MAX_BITS_OUTSTANDING)
    {
	finish_decode();	
	start_decode();
    }
    return(bit);
}




/*
 *
 * start the encoder
 *
 */
void 
start_encode(void)
{
    L = 0;
    R = HALF-1;
    bits_outstanding = 0;
}



/*
 *
 * finish encoding by outputting follow bits and three further
 * bits to make the last symbol unambiguous
 * could tighten this to two extra bits in some cases,
 * but does anybody care?
 *
 */
void 
finish_encode(void)
{
    int bits, i;
    const int nbits = 3;

    bits = (L+(R>>1)) >> (CODE_BITS-nbits);
    for (i = 1; i <= nbits; i++)     	/* output the nbits integer bits */
        BIT_PLUS_FOLLOW(((bits >> (nbits-i)) & 1));
}



/*
 *
 * start the decoder
 *
 */
void 
start_decode(void)
{
    int 	i;
    static	fill_V = 1;
    
    if (fill_V)
    {
	V = 0;
	for (i = 0; i<CODE_BITS; i++)
	    ADD_NEXT_INPUT_BIT(V);
	fill_V = 0;
    }
    L = 0;
    R = HALF - 1;
    bits_outstanding = 0;
}


/*
 *
 * finish decoding by consuming the disambiguating bits generated
 * by finish_encode
 *
 */
void 
finish_decode(void)
{
    int i;
    const int nbits = 3;

    for (i = 1; i <= nbits; i++)
	ADD_NEXT_INPUT_BIT(V);	
    bits_outstanding = 0;
}


/*
 *
 * initialize the bit output function
 *
 */
void 
startoutputtingbits(void)
{
    buffer = 0;
    bits_to_go = BYTE_SIZE;
}


/*
 *
 * start the bit input function
 *
 */
void 
startinputtingbits(void)
{
    bits_to_go = 0;
}



/*
 *
 * complete outputting bits
 *
 */
void 
doneoutputtingbits(void)
{
    putc(buffer >> bits_to_go, stdout);
    bytes_output += 1;
}


/*
 *
 * complete inputting bits
 *
 */
void 
doneinputtingbits(void)
{
    bits_to_go = 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -