www.pudn.com > sfalic-03-src.rar.rar > cdfstat.c
/* 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#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 >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 =0 !!! */ { const unsigned int ithcodelen=( pcounters[i]+=GolombCodeLen(curval, i) ); if (ithcodelen bestcode=bestcode; /* zapamietaj wyznaczony */ if(bestcodelen>wm_trigger) /* czy polowic liczniki? */ for (i=0; 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 bestcode, &codeword, &codewordlen); ENCODE(codeword, codewordlen) } updatemodel(findbucket(uncompressedrow[stopidx-1]), uncompressedrow[stopidx] , _bpp); stopidx=i+(tabrand() & waitmask); } for (; i 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 =0 !!! */ { const unsigned int ithcodelen=( pcounters[i]+=GolombCodeLen(curval, i) ); if (ithcodelen bestcode=bestcode; /* zapamietaj wyznaczony */ if(bestcodelen>wm_trigger) /* czy polowic liczniki? */ for (i=0; 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 bestcode, &codeword, &codewordlen); ENCODE(codeword, codewordlen) } updatemodel8bpp(findbucket8bpp(uncompressedrow[stopidx-1]), uncompressedrow[stopidx] , _bpp); stopidx=i+(tabrand() & waitmask); } for (; i 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 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); } /* ustawia parametry modelu: ncodes, searchstart, modelrows i finalbuckets*/ /* oraz parametry nicjalizacji modelu dla statfillstructures(): repfirst/next, mulsize i evoluted */ void findmodelparams(const int bpp, const int evol) { unsigned int bsize, /* rozmiar kubelka - liczba kontekstow*/ bstart, bend, /* poczatek i koniec kubelka zakres: 0 do levels-1*/ repcntr; /* ewolucja kubelkow licznik pom. */ assert((bpp<=16) && (bpp>0)); _bpp=bpp; /* ustawione */ if (bpp>8) ncounters=16; else ncounters=8; levels=0x1< =levels) /* jezeli nastepny kubelek mialbyby byc mniejszy od tego */ bend=levels-1; /* to je polacz */ if (!b_lo_ptrs) /* jeszcze nie ustalono dlugosci tablic indeksow? */ { if (bend==levels-1) /* ten kubelek jest ostatni - wszystkie beda w pierwszej tablicy*/ b_lo_ptrs=levels; else if (bsize>=256) /* ten kubelek moze byc w drugiej tablicy */ { b_lo_ptrs=bstart; assert(bstart); /* poprzedni istnieje */ } } nbuckets++; } while (bend < levels-1); b_hi_ptrs=(255+levels-b_lo_ptrs)>>8; /* czyli ceil((levels-b_lo_ptrs)/256) */ } /* na podstawie zm. glob. wypelnia model */ /* liczniki sa zerowane przy alokacji przez caloc()*/ void statfillstructures() { unsigned int bsize, /* rozmiar kubelka - liczba kontekstow*/ bstart, /* poczatek i koniec kubelka zakres: 0 do levels-1*/ bend, /* koniec kubelka */ repcntr, /* ewolucja kubelkow licznik pom. */ bnumber; /* numer kolejny kubelka */ COUNTER * freecounter=pc; /* poczatek wolnego miejsca w tablicy licznikow */ bnumber=0; repcntr=repfirst+1; /* generujemy pierwszy kubelek */ bsize=firstsize; do /* generujemy kolejne kubelki */ { if (bnumber) /* poczatek kubelka */ bstart=bend+1; else bstart=0; if (!--repcntr) /* rozmiar kubelka */ { repcntr=repnext; bsize*=mulsize; } bend=bstart+bsize-1; /* koniec kubelka */ if (bend+bsize>=levels) /* jezeli nastepny kubelek mialbyby byc mniejszy od tego */ bend=levels-1; /* to je polacz */ pb[bnumber].bestcode=_bpp-1; pb[bnumber].pcounters=freecounter; freecounter+=ncounters; if (bstart =b_lo_ptrs); i=(bstart-b_lo_ptrs)>>8; iend=(bend-b_lo_ptrs)>>8; for(;i<=iend; i++) b_ptr_hi[i]=pb+bnumber; } bnumber++; } while (bend < levels-1); assert(freecounter-pc==nbuckets*ncounters); return; } /* parametry, przydzial pamieci i wypelnienie */ void statinitmodel(const int bpp, const int evol, const int init8bpp) { assert(!pb); assert(!pc); assert(bpp>=1); assert(bpp<=16); findmodelparams(bpp, evol); if(init8bpp) { assert(!b_hi_ptrs); assert(b_lo_ptrs==(0x1U<<_bpp)); } assert(b_lo_ptrs); b_ptr_lo=(p_s_bucket *)clamalloc(b_lo_ptrs * sizeof(p_s_bucket)); if (!b_ptr_lo) exitit("no memory for model allocation", 4); if(b_hi_ptrs) /* to moze byc ==0 */ { b_ptr_hi=(p_s_bucket *)clamalloc(b_hi_ptrs * sizeof(p_s_bucket)); if (!b_ptr_hi) exitit("no memory for model allocation", 4); } pb=(s_bucket *)clamalloc( (size_t)nbuckets * sizeof(s_bucket) ); if (!pb) exitit("no memory for model allocation", 4); /* alokujemy i zerujemy liczniki - nie malloc a calloc */ pc=(COUNTER *)clacalloc( (size_t)nbuckets, sizeof(COUNTER) * MAXNUMCODES ); if (!pc) exitit("no memory for model allocation", 4); statfillstructures(); } /* zwolnienie pamieci */ void statfreemodel() { assert(pb); assert(pc); clafree(pc); pc=NULL; clafree(pb); pb=NULL; if(b_hi_ptrs) clafree(b_ptr_hi); clafree(b_ptr_lo); } /* funkcje eksportowane */ void statinitcoder(const int bpp, const int maxclen, const int evol, const int init8bpp) { assert(bpp<=MAXNUMCODES); statinitmodel(bpp, evol, init8bpp); familyinit(bpp, maxclen); stabrand(); wmidx=wmistart; set_wm_trigger(wmidx); wmileft=wminext; waitcnt=0; } void statfreecoder() { statfreemodel(); familyfree(); } void statinitdecoder(const int bpp, const int maxclen, const int evol, const int width, struct bitinstatus *bs) { assert(bpp<=MAXNUMCODES); statinitmodel(bpp, evol, 0); familyinit(bpp, maxclen); stabrand(); wmidx=wmistart; set_wm_trigger(wmidx); wmileft=wminext; waitcnt=0; bitinstatusinit(bs); } void statfreedecoder() { statfreemodel(); familyfree(); } /* przeprowadz kompresje zmieniajac wmidx, wskaznik do tablicy pikseli i jej dlugosc */ /* zwroc 0-ok, 1-blad */ void statcompressrow(PIXEL context, const PIXEL * uncompressedrow, unsigned int width, BYTE * compressedrow, unsigned int * fullbytes, unsigned int * bitsused) { while ((wmimax > (int)wmidx) && (wmileft<=width)) /*podzial w buforze */ { if (wmileft) { statcompressrowwm(context, uncompressedrow, wmileft, bppmask[wmidx], compressedrow, fullbytes, bitsused); context=*(uncompressedrow+wmileft-1); uncompressedrow+=wmileft; width-=wmileft; } wmidx++; set_wm_trigger(wmidx); wmileft=wminext; } if (width) { statcompressrowwm(context, uncompressedrow, width, bppmask[wmidx], compressedrow, fullbytes, bitsused); if (wmimax > (int)wmidx) wmileft-=width; } assert((int)wmidx<=wmimax); assert(wmidx<=32); assert(wminext>0); } void statcompressrow8bpp(BYTE context, const BYTE * uncompressedrow, unsigned int width, BYTE * compressedrow, unsigned int * fullbytes, unsigned int * bitsused) { while ((wmimax > (int)wmidx) && (wmileft<=width)) /*podzial w buforze */ { if (wmileft) { statcompressrowwm8bpp(context, uncompressedrow, wmileft, bppmask[wmidx], compressedrow, fullbytes, bitsused); context=*(uncompressedrow+wmileft-1); uncompressedrow+=wmileft; width-=wmileft; } wmidx++; set_wm_trigger(wmidx); wmileft=wminext; } if (width) { statcompressrowwm8bpp(context, uncompressedrow, width, bppmask[wmidx], compressedrow, fullbytes, bitsused); if (wmimax > (int)wmidx) wmileft-=width; } assert((int)wmidx<=wmimax); assert(wmidx<=32); assert(wminext>0); } /* przeprowadz dekompresje zmieniajac wmidx, wskaznik do tablicy pikseli i jej dlugosc */ /* zwroc 0-ok, 1-blad */ int statdecompressrow(PIXEL context, PIXEL * uncompressedrow, unsigned int width, struct bitinstatus *bs) { int result; while ((wmimax > (int)wmidx) && (wmileft<=width)) /*podzial w buforze */ { if (wmileft) { result=statdecompressrowwm(context, uncompressedrow, wmileft, bppmask[wmidx], bs); context=*(uncompressedrow+wmileft-1); uncompressedrow+=wmileft; width-=wmileft; } wmidx++; set_wm_trigger(wmidx); wmileft=wminext; } if (width) { result=statdecompressrowwm(context, uncompressedrow, width, bppmask[wmidx], bs); if (wmimax > (int)wmidx) wmileft-=width; } assert((int)wmidx<=wmimax); assert(wmidx<=32); assert(wminext>0); return result; }