ref: 76825c1dcb8790254983ea504ef1e7347ea3d91c
dir: /main.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <mouse.h> #include <keyboard.h> #include <thread.h> #include "frame.h" #include "misc.h" #include "stream.h" #include "decoder.h" int mainstacksize = 128*1024; static Image *curim; static uvlong lastframe; static uvlong lastframeaudio; static int audiofd = -1; static void drawframe(Frame *f) { uvlong x, end, left; static uvlong delay; Rectangle r; lockdisplay(display); if(curim != nil && (Dx(curim->r) != f->w || Dy(curim->r) != f->h)){ freeimage(curim); curim = nil; } r = Rect(0,0,f->w,f->h); if(curim == nil) curim = allocimage(display, r, RGB24, 0, DNofill); loadimage(curim, r, f->rgb, f->w*f->h*3); if(lastframe == 0) lastframe = nanosec(); end = lastframe + f->dt - delay; while(1){ x = nanosec(); if(x >= end) break; left = end - x; if(left > 750000000ULL) sleep(70); else if(left > 250000000ULL) sleep(20); else if(left > 100000000ULL) sleep(1); } x = nanosec(); if(Dx(r) < Dx(screen->r) && Dy(r) < Dy(screen->r)) r = rectsubpt(screen->r, divpt(Pt(Dx(r)-Dx(screen->r), Dy(r)-Dy(screen->r)), 2)); else r = screen->r; draw(screen, r, curim, nil, ZP); flushimage(display, 1); unlockdisplay(display); delay = nanosec() - x; lastframe += f->dt; free(f); } static void runaudio(Stream *s) { Streamframe f; if(s == nil) return; if(audiofd == -1 && (audiofd = open("/dev/audio", OWRITE)) < 0){ fprint(2, "runaudio: %r"); audiofd = -2; } if(audiofd < 0 || lastframe < lastframeaudio) return; if(Sread(s, &f) != 0) return; write(audiofd, f.buf, f.sz); lastframeaudio = f.timestamp + f.dt; } static void usage(void) { fprint(2, "usage: %s [-a AUDIO] file.mp4\n", argv0); threadexitsall("usage"); } void threadmain(int argc, char **argv) { enum { Cframe, Cplayerdone, Cmouse, Ckeyboard, Cresize, Cnum, }; Frame *frame; Mousectl *mctl; Keyboardctl *kctl; Rune key; Mouse m; char *s, *audio; Stream *stream, *svideo, *saudio; Decoder *d; int i, j, end, done, res, nstreams; Alt a[Cnum+1] = { [Cframe] = { nil, &frame, CHANRCV }, [Cplayerdone] = { nil, nil, CHANRCV }, [Cmouse] = { nil, &m, CHANRCV }, [Ckeyboard] = { nil, &key, CHANRCV }, [Cresize] = { nil, nil, CHANRCV }, [Cnum] = { nil, nil, CHANEND }, }; debug = 0; audio = nil; ARGBEGIN{ case 'a': if(audio != nil){ fprint(2, "only one audio file can be specified\n"); usage(); } audio = EARGF(usage()); break; case 'd': debug++; break; }ARGEND if(argc < 1) usage(); nproc = atoi((s = getenv("NPROC")) != nil ? s : "1"); if(nproc < 1) nproc = 1; srand(nanosec()); if(initdraw(nil, nil, "treason") < 0) sysfatal("initdraw: %r"); flushimage(display, 1); 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; saudio = nil; if(audio != nil) saudio = Sopen(audio, &nstreams); for(end = i = 0; !end && i < argc; i++){ draw(screen, screen->r, display->black, nil, ZP); if((stream = Sopen(argv[i], &nstreams)) == nil) sysfatal("%r"); svideo = nil; for(j = 0; j < nstreams; j++){ if(stream[j].type == Svideo && svideo == nil) svideo = stream+j; else if(stream[j].type == Saudio && saudio == nil) saudio = stream+j; else Sclose(stream+j); } if(svideo == nil) sysfatal("%s: no video", argv[i]); if((d = Dopen(svideo)) == nil) sysfatal("%r"); a[Cframe].c = d->frames; a[Cplayerdone].c = d->finished; lastframe = 0; lastframeaudio = 0; for(done = 0; !done && !end;){ res = alt(a); switch(res){ case Cframe: drawframe(frame); runaudio(saudio); break; case Cplayerdone: done = 1; break; case Cmouse: break; case Ckeyboard: end = key == 'q' || key == Kdel; done = key == '\n'; break; case Cresize: lockdisplay(display); if(getwindow(display, Refnone) < 0) sysfatal("getwindow: %r"); freeimage(curim); curim = nil; draw(screen, screen->r, display->black, nil, ZP); flushimage(display, 1); unlockdisplay(display); break; } } Sclose(saudio); saudio = nil; Dclose(d); for(i = 0; i < nstreams; i++) Sclose(stream+i); free(stream); } threadexitsall(nil); }