ref: 80719550be738385d1deddf193c6321a1e80f3a1
dir: /src/av19.c/
#include "dav1d.h" #include "tools/input/input.h" #include <draw.h> #include <memdraw.h> #include <mouse.h> #include <keyboard.h> #include <yuv_rgb.h> // FIXME this is most likely slow #include <tos.h> /* FIXME this one is slow as hell #define STB_IMAGE_RESIZE_IMPLEMENTATION #define STBIR_MALLOC(x,u) malloc(x) #define STBIR_FREE(x,u) free(x) #define STBIR_ASSERT(x) assert(x) typedef uintptr size_t; #include <stb_image_resize.h> */ typedef struct Frame Frame; typedef struct Player Player; struct Frame { Dav1dPicture pic; }; struct Player { Dav1dData data; Dav1dContext *c; DemuxerContext *dc; Channel *frames; Channel *done; uvlong fps; uvlong lastframe; }; // FIXME why does it need this much? int mainstacksize = 512*1024; static Player *curplayer; static Image *curframe; static char *layout[] = { [DAV1D_PIXEL_LAYOUT_I400] = "i400", [DAV1D_PIXEL_LAYOUT_I420] = "i420", [DAV1D_PIXEL_LAYOUT_I422] = "i422", [DAV1D_PIXEL_LAYOUT_I444] = "i444", }; static int dav1d_loadimage(Rectangle r, Image **oim, Dav1dPicture *p) { Image *im; uchar *rgb, t; int w, h, i; if(*oim == nil) *oim = allocimage(display, r, RGB24, 0, DNofill); im = *oim; w = p->p.w; h = p->p.h; if((rgb = malloc(w*h*3)) == nil) return -1; yuv420_rgb24(w, h, p->data[0], p->data[1], p->data[2], p->stride[0], p->stride[1], rgb, w*3, YCBCR_JPEG); /* uchar *out; if((out = malloc(Dx(r)*Dy(r)*3)) == nil){ free(rgb); return -1; } stbir_resize_uint8_generic( rgb, w, h, w*3, out, Dx(r), Dy(r), Dx(r)*3, 3, -1, 0, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL, STBIR_COLORSPACE_LINEAR, NULL); free(rgb); rgb = out; */ w = Dx(r); h = Dy(r); for(i = 0; i < w*h; i++){ t = rgb[i*3+2]; rgb[i*3+2] = rgb[i*3+0]; rgb[i*3+0] = t; } loadimage(im, Rect(0,0,w,h), rgb, w*h*3); free(rgb); return 0; } static void freeframe(Frame *f) { dav1d_picture_unref(&f->pic); free(f); } static uvlong nanosec(void) { static uvlong fasthz, xstart; uvlong x, div; if(fasthz == ~0ULL) return nsec() - xstart; if(fasthz == 0){ if((fasthz = _tos->cyclefreq) == 0){ fasthz = ~0ULL; xstart = nsec(); fprint(2, "cyclefreq not available, falling back to nsec()\n"); fprint(2, "you might want to disable aux/timesync\n"); return 0; }else{ cycles(&xstart); } } cycles(&x); x -= xstart; /* this is ugly */ for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL); return x / (fasthz / div); } static void gotframe(Frame *f) { int res; Point size = subpt(screen->r.max, screen->r.min); Rectangle r = (Rectangle){Pt(0, 0), size}; uvlong thisframe, start, dt; static uvlong delay; start = nanosec(); dt = 0; lockdisplay(display); r.max.x = f->pic.p.w; r.max.y = f->pic.p.h; res = dav1d_loadimage(r, &curframe, &f->pic); freeframe(f); dt += nanosec()-start; if(res == 0){ thisframe = curplayer->lastframe + 1000000000ULL/curplayer->fps - delay; while(nanosec() < thisframe) sleep(10); dt += nanosec() - thisframe; start = nanosec(); draw(screen, screen->r, curframe, nil, ZP); flushimage(display, 1); curplayer->lastframe = start; dt += nanosec()-start; } unlockdisplay(display); delay = dt; } static void playerproc(void *aux) { Player *p; Frame *f; int res; p = aux; do{ res = dav1d_send_data(p->c, &p->data); if(res < 0 && res != DAV1D_ERR(EAGAIN)){ fprint(2, "dav1d_send_data: %d\n", res); break; }else{ f = calloc(1, sizeof(*f)); if((res = dav1d_get_picture(p->c, &f->pic)) < 0){ if(res != DAV1D_ERR(EAGAIN)){ fprint(2, "dav1d_get_picture: %d\n", res); break; } }else{ sendp(p->frames, f); } } }while(p->data.sz > 0 || input_read(p->dc, &p->data) == 0); if(p->data.sz > 0) dav1d_data_unref(&p->data); // FIXME there might be more here sendul(p->done, 1); threadexits(nil); } static void freeplayer(Player *p) { // FIXME chanfree(p->frames); chanfree(p->done); free(p); } static Player * newplayer(char *filename) { Player *p; unsigned fps[2], timebase[2], total; Dav1dSettings av1s; p = calloc(1, sizeof(*p)); if(input_open(&p->dc, "ivf", filename, fps, &total, timebase) < 0){ werrstr("input_open"); goto err; } p->fps = fps[0]/fps[1]; // FIXME that's not precise if(input_read(p->dc, &p->data) < 0){ werrstr("input_read"); goto err; } dav1d_default_settings(&av1s); av1s.n_frame_threads = 1; // FIXME threads av1s.n_tile_threads = 1; // FIXME threads if(dav1d_open(&p->c, &av1s) != 0){ werrstr("dav1d_open"); goto err; } p->frames = chancreate(sizeof(Frame*), 30); // FIXME prerender? p->done = chancreate(sizeof(ulong), 0); p->lastframe = 0; proccreate(playerproc, p, mainstacksize); return p; err: werrstr("%s: %r", filename); free(p); return nil; } void threadmain(int argc, char **argv) { enum { Cplayerframes, Cplayerdone, Cmouse, Ckeyboard, Cresize, Cnum, }; Mousectl *mctl; Keyboardctl *kctl; Frame *frame; Rune key; Mouse m; int i, end, done; Alt a[Cnum+1] = { [Cplayerframes] = { nil, &frame, CHANRCV }, [Cplayerdone] = { nil, nil, CHANRCV }, [Cmouse] = { nil, &m, CHANRCV }, [Ckeyboard] = { nil, &key, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, [Cnum] = { nil, nil, CHANEND }, }; ARGBEGIN{ }ARGEND if(argc < 1) sysfatal("usage"); srand(nanosec()); if(initdraw(nil, nil, "treason") < 0) sysfatal("initdraw: %r"); display->locking = 1; unlockdisplay(display); if((mctl = initmouse(nil, screen)) == nil) sysfatal("initmouse: %r"); if((kctl = initkeyboard(nil)) == nil) sysfatal("initkeyboard: %r"); a[Cmouse].c = mctl->c; a[Cresize].c = mctl->resizec; a[Ckeyboard].c = kctl->c; for(end = i = 0; !end && i < argc; i++){ if((curplayer = newplayer(argv[0])) == nil) sysfatal("%r"); a[Cplayerframes].c = curplayer->frames; a[Cplayerdone].c = curplayer->done; for(done = 0; !done && !end;){ switch(alt(a)){ case Cplayerframes: gotframe(frame); break; case Cplayerdone: done = 1; break; case Cmouse: break; case Ckeyboard: if(key == 'q' || key == Kdel){ end = 1; break; } break; case Cresize: if(getwindow(display, Refnone) < 0) sysfatal("getwindow: %r"); freeimage(curframe); curframe = nil; break; } } freeplayer(curplayer); } threadexitsall(nil); }