#include #include #include #include #include #include "temporal_antialias.hh" #include #define TARGET_FPS 30.0 static const struct { unsigned which_window; const char* imgfn; unsigned begin_frame; unsigned end_frame; } plot[] = { // We have a maximum of 5 windows. { 0, "test0.png", 25285/4, 38425/4 }, // black { 1, "test1.png", 27364/4, 38407/4 }, // with two lines { 2, "test2.png", 33884/4, 38391/4 }, // with barcode { 3, "test3.png", 37987/4, 38374/4 }, // with digits, except first { 0, "test4.png", 38539/4, 50000 }, // with Bisqwit { 1, "test5.png", 39521/4, 50000 }, // with book { 2, "test6.png", 41541/4, 50000 }, // with Max }; struct FrameToInterpolate: public std::vector { template FrameToInterpolate(T... p) : std::vector(p...) { } void donewith() { std::vector tmp; tmp.swap(*this); } }; struct ActiveWindow { gdImagePtr im; unsigned which_plot; int framecounter; }; static void FullyWrite(int fd, const void* b, unsigned length) { const unsigned char* buf = (const unsigned char*) b; Retry:; int result = write(fd, buf, length); if(result == -1 && errno==EAGAIN) goto Retry; if(result == -1 && errno==EINTR) goto Retry; if(result <= 0) { perror("write"); throw errno; return; } length -= result; buf += result; if(length) goto Retry; } static void FullyRead(int fd, void* b, unsigned length) { unsigned char* buf = (unsigned char*) b; Retry:; int result = read(fd, buf, length); if(result == -1 && errno==EAGAIN) goto Retry; if(result == -1 && errno==EINTR) goto Retry; if(result <= 0) { perror("read"); throw errno; return; } length -= result; buf += result; if(length) goto Retry; } void SafeRead(void* b, unsigned length, FILE* fp) { FullyRead(fileno(fp), b, length); } int main() { TemporalAntialias antialias(1 / TARGET_FPS); std::list windows; const unsigned InHeight = 406; const unsigned Width = 720; //const unsigned OutWidth = InWidth + 256; const unsigned OutHeight = 480; int out_frame=2; // Latency int out_frame_frac=0; for(unsigned in_frame=0; ; ++in_frame) { static unsigned char framebuffer[Width * InHeight*3]; SafeRead(framebuffer, sizeof(framebuffer), stdin); double in_when = in_frame / 120.0; antialias.Feed(in_when, FrameToInterpolate(framebuffer, framebuffer+sizeof(framebuffer))); while(antialias.Avail()) { std::vector buffer( Width * InHeight * 3 ); auto interp = [&](const std::vector& frame, int weight) -> void { for(size_t a=0; a result( Width * OutHeight * 4); double fadein = (in_when - 9) / 1.5; if(fadein < 0) fadein = 0; if(fadein > 1) fadein = 1; int beginx = 0; int beginy = OutHeight-InHeight; if(in_when < 175) beginy = beginy/2; else if(in_when < (175+3)) beginy = beginy/2 + (beginy/2 * (in_when-175) / 3.0); #pragma omp parallel for schedule(static) for(unsigned y=0; y= top && y < bottom) for(unsigned x=0; x 0.0) { for(unsigned x=0; x 1) fade2 = 1; if(xfade > 1) xfade = 3 - xfade*2; double fade = fadein * xfade; if(fade < 0) fade = 0; if(fade > 1) fade = 1; int f = (((x/4+y/4))&1); if(!f) fade = 0; int r = r0 * fade2, g = g0 * fade2, b = b0 * fade2; r = r + (0x24*f - r) * fade; g = g + (0x4B*f - g) * fade; b = b + (0x5B*f - b) * fade; *(unsigned*)&result[x*4 + y*Width*4] = r*0x10000+g*0x100+b; } } if(y >= bottom) //if(fadein > 0.0) { for(unsigned x=0; x 1) fade2 = 1; if(xfade > 1) xfade = 3 - xfade*2; double fade = fadein * xfade; if(fade < 0) fade = 0; if(fade > 1) fade = 1; int f = (((x/4+y/4))&1); if(!f) fade = 0; int r = r0 * fade2, g = g0 * fade2, b = b0 * fade2; r = r + (0x24*f - r) * fade; g = g + (0x4B*f - g) * fade; b = b + (0x5B*f - b) * fade; *(unsigned*)&result[x*4 + y*Width*4] = r*0x10000+g*0x100+b; } } } for(auto& p: plot) if(p.begin_frame == out_frame && out_frame_frac == 0) { FILE* fp = fopen(p.imgfn, "rb"); windows.push_back( { gdImageCreateFromPng(fp), unsigned(&p-&plot[0]), 0 } ); const unsigned bright = 0x9999AA, dim = 0x222255; const unsigned W = 123, H = 74; for(unsigned y=0; ywhich_plot]; if(out_frame > p.end_frame + vanish_time) { gdImageDestroy(j->im); windows.erase(j); continue; } unsigned beginy = 0; unsigned beginx = 40 + p.which_window * 160; double pos = (j->framecounter - 4.99) / 8.0; if(pos < 0.0) pos = 0.0; unsigned repeat = 10; double pos2 = 1.0; if(out_frame >= p.end_frame) { pos2 = 1.0 - (out_frame - p.end_frame) / double(vanish_time); if(pos2 < 0) pos2 = 0; } do_repeat:; if(pos > 1.0) pos = 1.0; #pragma omp parallel for schedule(static) for(unsigned y=0; yim, x/4, y+4); c >>= (8*(x%4)); c &= 0xFF; /*unsigned b = buffer[(x&~3)+0 + y*256*4] / 4194304; unsigned g = buffer[(x&~3)+1 + y*256*4] / 4194304; unsigned r = buffer[(x&~3)+2 + y*256*4] / 4194304; unsigned rgb = (r<<16)+(g<<8)+(b); if(p.which_window < 2) d = c; else if(rgb == 0) d >>= 1; else if(d != 0) { if(rgb == 0x8583FF || rgb == 0x9283FF || rgb == 0x9385FF || rgb == 0x9285FF) { // d = d; } else d = c; } else*/ d = c; } } if(pos > 0.0 && pos < 1.0 && repeat > 0) { --repeat; pos += 1 / 10.0 / 7.0; goto do_repeat; } ++j->framecounter; } if(++out_frame_frac >= 1) { out_frame_frac = 0; ++out_frame; } fwrite(&result[0], result.size(), 1, stdout); } } }