#ifndef HYPERDRM_CONTINUITY_H #define HYPERDRM_CONTINUITY_H /* Zero population is missing data, while populated bin zero is real black. */ static inline bool histogram_populated(const Histogram hist[16]){ for(unsigned r=0;r<16;r++)for(unsigned c=0;c<3;c++){ uint64_t total=0;for(unsigned b=0;b<256;b++)total+=hist[r].bins[c][b]; if(!total)return false; } return true; } typedef struct {unsigned char last[16][3],from[16][3];uint64_t valid_at,fade_at,missing_at;bool available,fading,holding;} Continuity; static inline void continuity_seed(Continuity *s,const unsigned char colors[16][3],uint64_t now){ memcpy(s->last,colors,sizeof(s->last));memcpy(s->from,colors,sizeof(s->from));s->valid_at=now;s->available=true;s->fading=true;s->fade_at=0;s->missing_at=0;s->holding=false; } static inline void continuity_mix(const unsigned char from[16][3],const unsigned char to[16][3],unsigned elapsed,unsigned char out[16][3]){ if(elapsed>500)elapsed=500; for(unsigned r=0;r<16;r++)for(unsigned c=0;c<3;c++)out[r][c]=(from[r][c]*(500-elapsed)+to[r][c]*elapsed+250)/500; } static inline bool continuity_frame(Continuity *s,bool valid,const unsigned char input[16][3],uint64_t now,unsigned char out[16][3]){ if(!valid){ if(!s->missing_at)s->missing_at=now; s->holding=s->available && now-s->missing_at<1500; if(s->holding)memcpy(out,s->last,sizeof(s->last)); return s->holding; } if(s->holding){memcpy(s->from,s->last,sizeof(s->from));s->fading=true;s->fade_at=0;} s->holding=false;s->missing_at=0; /* Near-black codec rounding is valid darkness, not a lost measurement. */ bool black=true;for(unsigned r=0;r<16;r++)for(unsigned c=0;c<3;c++)if(input[r][c]>3)black=false; if(black)s->fading=false; if(s->fading){if(!s->fade_at)s->fade_at=now;continuity_mix(s->from,input,(unsigned)(now-s->fade_at),out);if(now-s->fade_at>=500)s->fading=false;} else memcpy(out,input,sizeof(s->last)); memcpy(s->last,out,sizeof(s->last));s->available=true;s->valid_at=now;return true; } #endif