cdfstat.c

来自「一个简单而且快速的无损压缩算法。包含源代码实现」· C语言 代码 · 共 710 行 · 第 1/2 页

C
710
字号
/* kod podzielony na 2 czesci, gorna do zoptymalizowana, dolna nie-krytyczna */


/* funkcje krytyczne dla predkosci, nie eksportowane */

#include "tabrand.h"
#include "cdfstat.h"
#include "cfamily.h"
#include <assert.h>

#include "encodecodeword.h"


/* uzywane w findbucket() */
static p_s_bucket * b_ptr_lo;	/* tablica wskaznikow na kubelki - czesc lo */
static p_s_bucket * b_ptr_hi;	/* tablica wskaznikow na kubelki - czesc hi */
static unsigned int
			b_lo_ptrs;		/* rozmiar tablicy b_lo_ptrs */
static unsigned int
			b_hi_ptrs;

/* uzywane w updatemodel() */
static unsigned int 
			wm_trigger;	/* prog dla polowienia licznikow, jezeli trigger z taskparams<>0 */
						/* to wm_trigger=trigger, else wm_trigger wyznaczany funkcja set_wm_trigger dla evol i wm */

/* uzywany w statdecompressrow() i statcompressrow() */
static unsigned int 
			waitcnt;		/* globalny licznik pominiec aktualizacji modelu */
							
static unsigned int 
			_bpp;			/* lokalna kopia bpp z taskparams */


/*zwraca wskaznik do kubelka, ktory zawiera kontekst val */
static s_bucket * findbucket(const unsigned int val)
{
	assert(val<(0x1U<<_bpp));

	if (val<b_lo_ptrs)
		return b_ptr_lo[val];
	else
		return b_ptr_hi[(val-b_lo_ptrs)>>8];
}


/* aktualizacja kubelka modelu na podstawie zakodowanego symbolu curval */
static void updatemodel(s_bucket * const bucket, const unsigned int curval, 
						const unsigned int bpp)
{ 
	COUNTER * const pcounters=bucket->pcounters;
	unsigned int i;		
	unsigned int bestcode;
	unsigned int bestcodelen;

	/* uaktualnij liczniki i wyznacz wartosc i indeks najmniejszego */
	/* zaczynajac od najwiekszego indeksu  --  bpp==ncodes*/

	bestcode=bpp-1;
	bestcodelen=( pcounters[bestcode]+=GolombCodeLen(curval, bestcode) );

	for (i=bpp-2; i<bpp; i--) /* UWAGA: warunek i<bpp dla signed int i bylby i>=0 !!! */
	{
		const unsigned int ithcodelen=( pcounters[i]+=GolombCodeLen(curval, i) );

		if (ithcodelen<bestcodelen)
		{
			bestcode=i;
			bestcodelen=ithcodelen;
		}
	}

	bucket->bestcode=bestcode; /* zapamietaj wyznaczony */

	if(bestcodelen>wm_trigger)	/* czy polowic liczniki? */
		for (i=0; i<bpp; i++) /* polowimy */
			pcounters[i]>>=1;
}


/* dla stalego waitmask przeprowadz kompresje */
/* argumenty: kontekst pierwszego piksela, tablica pikseli, dlugosc tablicy, waitmask */
/* tablica na bitowo zapisane slowa kodowe i jej zmienne stanu */
static void statcompressrowwm(const PIXEL firstcontext, const PIXEL uncompressedrow[],  
							  const unsigned int width, const unsigned int waitmask,
							  BYTE compressedrow[], 
							  unsigned int * const fullbytes, unsigned int * const bitsused)
{
	unsigned int i;

	unsigned int stopidx; /* piksel na ktorym zatrzymuje sie petla wewnetrzna */

	ENCODE_START(compressedrow, fullbytes, bitsused)

	
	assert(width);

	{	/* element zerowy */
			unsigned int codeword, codewordlen ;

			GolombCoding(uncompressedrow[0], 
						 findbucket(firstcontext)->bestcode, 
						 &codeword, &codewordlen);
			ENCODE(codeword, codewordlen)

			if (waitcnt)
				waitcnt--;
			else
			{
				waitcnt=(tabrand() & waitmask);
				updatemodel(findbucket(firstcontext), 
							uncompressedrow[0] , _bpp);
			}
	}

	i=1;
	stopidx=i+waitcnt;

	while (stopidx<width) /* kodujemy grupe pikseli i aktualizujemy model po ostatnim z grupy */
	{
		for (; i<=stopidx; i++)
		{
			unsigned int codeword, codewordlen ;

			GolombCoding(uncompressedrow[i], 
						findbucket(uncompressedrow[i-1])->bestcode, 
						&codeword, &codewordlen);
			ENCODE(codeword, codewordlen)
		}

		updatemodel(findbucket(uncompressedrow[stopidx-1]), 
						uncompressedrow[stopidx] , _bpp);
		stopidx=i+(tabrand() & waitmask);
	}

	for (; i<width; i++)	/* ewentualna ostatnia grupa pikseli, po ktorej nie ma aktualizacji */
	{
		unsigned int codeword, codewordlen ;

		GolombCoding(uncompressedrow[i], 
					findbucket(uncompressedrow[i-1])->bestcode, 
					&codeword, &codewordlen);
		ENCODE(codeword, codewordlen)
	}

	ENCODE_STOP(compressedrow, fullbytes, bitsused)

	waitcnt=stopidx-width;
}


/* powyzsze w wariancie dla do 8 bpp */
static s_bucket * findbucket8bpp(const unsigned int val)
{
	assert(val<(0x1U<<_bpp));

	return b_ptr_lo[val];
}


static void updatemodel8bpp(s_bucket * const bucket, const unsigned int curval, 
							const unsigned int bpp)
{ 
	COUNTER * const pcounters=bucket->pcounters;
	unsigned int i;		
	unsigned int bestcode;
	unsigned int bestcodelen;

	/* uaktualnij liczniki i wyznacz wartosc i indeks najmniejszego */
	/* zaczynajac od najwiekszego indeksu  --  bpp==ncodes*/

	bestcode=bpp-1;
	bestcodelen=( pcounters[bestcode]+=GolombCodeLen(curval, bestcode) );

	for (i=bpp-2; i<bpp; i--) /* UWAGA: warunek i<bpp dla signed int i bylby i>=0 !!! */
	{
		const unsigned int ithcodelen=( pcounters[i]+=GolombCodeLen(curval, i) );

		if (ithcodelen<bestcodelen)
		{
			bestcode=i;
			bestcodelen=ithcodelen;
		}
	}

	bucket->bestcode=bestcode; /* zapamietaj wyznaczony */

	if(bestcodelen>wm_trigger)	/* czy polowic liczniki? */
		for (i=0; i<bpp; i++) /* polowimy */
			pcounters[i]>>=1;
}


static void statcompressrowwm8bpp(const BYTE firstcontext, const BYTE uncompressedrow[],  
							  const unsigned int width, const unsigned int waitmask,
							  BYTE compressedrow[], 
							  unsigned int * const fullbytes, unsigned int * const bitsused)
{
	unsigned int i;
	unsigned int stopidx; /* piksel na ktorym zatrzymuje sie petla wewnetrzna */

	ENCODE_START(compressedrow, fullbytes, bitsused)

	assert(width);

	{	/* element zerowy */
			unsigned int codeword, codewordlen ;

			GolombCoding(uncompressedrow[0], 
						 findbucket8bpp(firstcontext)->bestcode, 
						 &codeword, &codewordlen);
			ENCODE(codeword, codewordlen)

			if (waitcnt)
				waitcnt--;
			else
			{
				waitcnt=(tabrand() & waitmask);
				updatemodel8bpp(findbucket8bpp(firstcontext), 
								uncompressedrow[0] , _bpp);
			}
	}

	i=1;
	stopidx=i+waitcnt;

	while (stopidx<width) /* kodujemy grupe pikseli i aktualizujemy model po ostatnim z grupy */
	{
		for (; i<=stopidx; i++)
		{
			unsigned int codeword, codewordlen ;

			GolombCoding(uncompressedrow[i], 
						findbucket8bpp(uncompressedrow[i-1])->bestcode, 
						&codeword, &codewordlen);
			ENCODE(codeword, codewordlen)
		}

		updatemodel8bpp(findbucket8bpp(uncompressedrow[stopidx-1]), 
						uncompressedrow[stopidx] , _bpp);
		stopidx=i+(tabrand() & waitmask);
	}

	for (; i<width; i++)	/* ewentualna ostatnia grupa pikseli, po ktorej nie ma aktualizacji */
	{
		unsigned int codeword, codewordlen ;

		GolombCoding(uncompressedrow[i], 
					findbucket8bpp(uncompressedrow[i-1])->bestcode, 
					&codeword, &codewordlen);
		ENCODE(codeword, codewordlen)
	}

	ENCODE_STOP(compressedrow, fullbytes, bitsused)

	waitcnt=stopidx-width;
}


/* obszar nie-krytyczny */

#include "cfamily.h"
#include "cdftypes.h"
#include "exitit.h"
#include "bppmask.h"
#include "ceillog2.h"
#include "taskparams.h" 
#include "clalloc.h" 


static COUNTER * pc=NULL;	/* pomocniczy do dealokacji i alokacji tablic licznikow (hurtem) */

static s_bucket * pb=NULL;	/* tablica kubelkow */


/* ustawiane przez findmodelparams(), uzywane przez statfillstructures() */
static unsigned int 
			repfirst,		/* ile kubelkow takich jak pierwszy */
			firstsize,		/* rozmiar pierwszego kubelka */
			repnext,			/* po ile razy powtarzac kolejne rozmiary */
			mulsize,			/* skok wielkosci rozmiaru */
			levels;			/* liczba poziomow jasnosci piksela */
static unsigned int
			nbuckets;		/* liczba kubelkow */

static unsigned int
			ncounters;		/* liczba licznikow alokowanych dla kubelka */

static unsigned int 
			wmidx,	/* aktualny index waitmask */
			wmileft;	/* ile jeszcze symboli zakodowac z aktualnym wmidx */

static const unsigned short besttrigtab[4][11]={ /* tablica wartosci do wyznaczenia wm_trigger przez set_wm_trigger() */
											     /*w komentatrzach evol */
	/* 1 */	{ 550, 900, 800, 700, 500, 350, 300, 200, 180, 180, 160 },
	/* 3 */	{ 110, 550, 900, 800, 550, 400, 350, 250, 140, 160, 140 },
	/* 5 */	{ 100, 120, 550, 900, 700, 500, 400, 300, 220, 250, 160 },
	/* 6 */	{  30,	30,  30,  30,  30, 250, 400, 400, 300, 220, 220 }
	};



/* dla stalego waitmask przeprowadz de kompresje, wskaznik do tablicy pikseli i jej dlugosc */
/* zwroc 0-ok, 1-blad */
static int statdecompressrowwm(PIXEL context, PIXEL * uncompressedrow, 
						const unsigned int width, const unsigned int waitmask,
						struct bitinstatus *bs)
{
	unsigned int 
			_waitcnt=waitcnt;
	struct bitinstatus
			_bs=*bs;

	unsigned int i;

	for (i=0; i<width; i++)
	{
		s_bucket * const bucket=findbucket(context);

		context=uncompressedrow[i]=GolombDecoding(bucket->bestcode, &_bs);

		if (_waitcnt) 
			_waitcnt--;
		else
		{
			_waitcnt=(tabrand() & waitmask);
			updatemodel(bucket, context, _bpp);
		}
	}

	waitcnt=_waitcnt;
	*bs=_bs;
	return 0;
}


/* ustaw wm_trigger dla danego waitmask */
void set_wm_trigger(unsigned int wm)
{
	if (trigger)
	{
		wm_trigger=trigger;
		return;
	}

	if (wm>10)
		wm=10;

	assert(evol<7);

	wm_trigger=besttrigtab[evol/2][wm];

	assert(wm_trigger<=2000);
	assert(wm_trigger>=1);
}

⌨️ 快捷键说明

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