ref: 4a9ad7222f0a90576a0b8bcefcda73747c5c5a97
parent: 50e8d89a65b18a2371bfc76b63e49554923ff862
author: Sigrid Haflínudóttir <[email protected]>
date: Mon Sep 7 12:00:16 EDT 2020
simplify player's logic and fix timing
--- a/src/av19.c
+++ b/src/av19.c
@@ -16,8 +16,9 @@
typedef struct Player Player;
struct Frame {
- Dav1dPicture pic;
- uvlong n;
+ u8int *rgb;
+ int w, h;
+ uvlong dt;
};
struct Player {
@@ -24,22 +25,16 @@
Dav1dData data;
Dav1dContext *c;
DemuxerContext *dc;
- Channel *done;
+ Channel *frames, *done;
+ double timebase;
uvlong fps;
uvlong lastframe;
- uvlong n;
};
-// FIXME why does it need this much?
-int mainstacksize = 512*1024;
+int mainstacksize = 128*1024;
static Player *curplayer;
static Image *curim;
-static Channel **converters;
-static QLock framelock;
-static uvlong todisplay;
-static int resize = 1;
-static int maxframes;
/* yuv→rgb by Adrien Descamps */
@@ -143,7 +138,7 @@
static void
freeframe(Frame *f)
{
- dav1d_picture_unref(&f->pic);
+ free(f->rgb);
free(f);
}
@@ -177,76 +172,120 @@
}
static void
-drawframe(void)
+drawframe(Frame *f)
{
- uvlong thisframe, start;
+ uvlong x, end, left;
static uvlong delay;
+ Rectangle r;
- thisframe = curplayer->lastframe + 1000000000ULL/curplayer->fps - delay;
- while(nanosec() < thisframe)
- sleep(10);
-
lockdisplay(display);
- start = nanosec();
+
+ 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(curplayer->lastframe == 0)
+ curplayer->lastframe = nanosec();
+
+ end = curplayer->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();
draw(screen, screen->r, curim, nil, ZP);
flushimage(display, 1);
unlockdisplay(display);
- delay = nanosec() - start;
- curplayer->lastframe = start;
+
+ delay = nanosec() - x;
+ curplayer->lastframe += f->dt;
+
+ freeframe(f);
}
static void
playerproc(void *aux)
{
+ Dav1dPicture pic;
+ uvlong lasttimestamp;
Player *p;
Frame *f;
int res;
p = aux;
-
+ lasttimestamp = 0;
+ memset(&pic, 0, sizeof(pic));
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;
+ res = dav1d_get_picture(p->c, &pic);
+ if(res < 0){
+ if(res != DAV1D_ERR(EAGAIN)){
+ fprint(2, "dav1d_get_picture: %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);
+ f->w = pic.p.w;
+ f->h = pic.p.h;
+ if((f->rgb = malloc(f->w*f->h*3)) != nil){
+ yuv420_rgb24(f->w, f->h, pic.data[0], pic.data[1], pic.data[2], pic.stride[0], pic.stride[1], f->rgb, f->w*3);
+ f->dt = (pic.m.timestamp - lasttimestamp) * p->timebase * 1000000000ULL;
+ lasttimestamp = pic.m.timestamp;
+ dav1d_picture_unref(&pic);
+
+ if(sendp(p->frames, f) < 0){
+ freeframe(f);
break;
}
}else{
- f->n = p->n++;
- sendp(converters[f->n % maxframes], f);
+ freeframe(f);
}
}
+
+ res = dav1d_send_data(p->c, &p->data);
+ if(res < 0){
+ if(res != DAV1D_ERR(EAGAIN)){
+ fprint(2, "dav1d_send_data: %d\n", res);
+ break;
+ }
+ }
}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
+ /* drain */
+ while(dav1d_get_picture(p->c, &pic) >= 0)
+ dav1d_picture_unref(&pic);
+ input_close(p->dc);
+ dav1d_close(&p->c);
+
sendul(p->done, 1);
threadexits(nil);
}
-static void
-freeplayer(Player *p)
-{
- // FIXME
- chanfree(p->done);
- free(p);
-}
-
static Player *
newplayer(char *filename)
{
Player *p;
- unsigned fps[2], timebase[2], total;
+ unsigned fps[2], timebase[2], total, threads;
Dav1dSettings av1s;
+ char *s;
p = calloc(1, sizeof(*p));
if(input_open(&p->dc, "ivf", filename, fps, &total, timebase) < 0){
@@ -253,15 +292,16 @@
werrstr("input_open");
goto err;
}
- p->fps = fps[0]/fps[1]; // FIXME that's not precise
+ p->timebase = (double)timebase[1]/(double)timebase[0];
if(input_read(p->dc, &p->data) < 0){
werrstr("input_read");
goto err;
}
+ threads = atoi((s = getenv("NPROC")) != nil ? s : "1");
dav1d_default_settings(&av1s);
- av1s.n_frame_threads = maxframes;
- av1s.n_tile_threads = maxframes;
+ av1s.n_frame_threads = threads;
+ av1s.n_tile_threads = threads;
if(dav1d_open(&p->c, &av1s) != 0){
werrstr("dav1d_open");
@@ -268,10 +308,10 @@
goto err;
}
+ p->frames = chancreate(sizeof(Frame*), 0);
p->done = chancreate(sizeof(ulong), 0);
- p->lastframe = 0;
- proccreate(playerproc, p, mainstacksize);
+ proccreate(playerproc, p, 16384);
return p;
err:
@@ -281,76 +321,17 @@
}
static void
-rgbready(uchar *rgb, int w, int h, uvlong n)
+closeplayer(Player *p)
{
- Rectangle r;
-
- r = Rect(0,0,w,h);
- for(;;){
- qlock(&framelock);
- if(todisplay == n){
- if(curim != nil && Dx(curim->r) != w){
- freeimage(curim);
- curim = nil;
- }
- if(curim == nil)
- curim = allocimage(display, r, RGB24, 0, DNofill);
- loadimage(curim, r, rgb, w*h*3);
- free(rgb);
- drawframe();
- todisplay++;
- qunlock(&framelock);
- break;
- }
- qunlock(&framelock);
- sleep(10);
- }
+ chanclose(p->frames);
+ chanclose(p->done);
}
-static void
-converterproc(void *c)
-{
- Frame *f;
- uchar *rgb;
- Dav1dPicture *p;
- uchar *out;
- int w, h;
-
- for(; (f = recvp(c)) != nil;){
- p = &f->pic;
- if((rgb = malloc(p->p.w * p->p.h * 3)) != nil){
- yuv420_rgb24(p->p.w, p->p.h, p->data[0], p->data[1], p->data[2], p->stride[0], p->stride[1], rgb, p->p.w*3);
- w = p->p.w;
- h = p->p.h;
-
- if(resize){
- w = Dx(screen->r);
- h = Dy(screen->r);
- if((out = malloc(w*h*3)) != nil){
- stbir_resize_uint8_generic(
- rgb, p->p.w, p->p.h, p->p.w*3,
- out, w, h, w*3,
- 3, -1, 0,
- STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL, STBIR_COLORSPACE_LINEAR,
- NULL);
- }
- free(rgb);
- rgb = out;
- }
- if(rgb != nil)
- rgbready(rgb, w, h, f->n);
- }
-
- freeframe(f);
- }
-
- threadexits(nil);
-}
-
void
threadmain(int argc, char **argv)
{
enum {
+ Cframe,
Cplayerdone,
Cmouse,
Ckeyboard,
@@ -357,14 +338,15 @@
Cresize,
Cnum,
};
+ Frame *frame;
Mousectl *mctl;
Keyboardctl *kctl;
- char *s;
Rune key;
Mouse m;
- int i, end, done;
+ int i, end, done, res;
Alt a[Cnum+1] =
{
+ [Cframe] = { nil, &frame, CHANRCV },
[Cplayerdone] = { nil, nil, CHANRCV },
[Cmouse] = { nil, &m, CHANRCV },
[Ckeyboard] = { nil, &key, CHANRCV },
@@ -392,24 +374,20 @@
a[Cresize].c = mctl->resizec;
a[Ckeyboard].c = kctl->c;
- maxframes = atoi((s = getenv("NPROC")) != nil ? s : "1");
- if(maxframes < 1)
- maxframes = 1;
- converters = calloc(maxframes, sizeof(*converters));
- for(i = 0; i < maxframes; i++){
- converters[i] = chancreate(sizeof(Frame*), 0);
- proccreate(converterproc, converters[i], 4096);
- }
-
for(end = i = 0; !end && i < argc; i++){
- todisplay = 0;
if((curplayer = newplayer(argv[0])) == nil)
sysfatal("%r");
+ a[Cframe].c = curplayer->frames;
a[Cplayerdone].c = curplayer->done;
for(done = 0; !done && !end;){
- switch(alt(a)){
+ res = alt(a);
+ switch(res){
+ case Cframe:
+ drawframe(frame);
+ break;
+
case Cplayerdone:
done = 1;
break;
@@ -422,28 +400,21 @@
end = 1;
break;
}
- if(key == 'r')
- resize = !resize;
break;
case Cresize:
- qlock(&framelock);
+ lockdisplay(display);
if(getwindow(display, Refnone) < 0)
sysfatal("getwindow: %r");
- lockdisplay(display);
freeimage(curim);
curim = nil;
unlockdisplay(display);
- qunlock(&framelock);
break;
}
}
- freeplayer(curplayer);
+ closeplayer(curplayer);
}
-
- for(i = 0; i < nelem(converters); i++)
- chanclose(converters[i]);
threadexitsall(nil);
}
--- a/src/plan9_thread.c
+++ b/src/plan9_thread.c
@@ -3,6 +3,10 @@
#include </sys/include/thread.h>
#include "thread.h"
+enum {
+ Magic = 1325465,
+};
+
void
dav1d_set_thread_name(const char *const name)
{
@@ -49,9 +53,9 @@
pthread_once(pthread_once_t *once, void (*init_routine)(void))
{
qlock(once);
- if (once->done != 12345) {
+ if (once->done != Magic) {
init_routine();
- once->done = 12345;
+ once->done = Magic;
}
qunlock(once);
return 0;
@@ -89,6 +93,7 @@
int
pthread_cond_init(pthread_cond_t *const cond, const void *const attr)
{
+ USED(attr);
memset(cond, 0, sizeof(*cond));
cond->l = &cond->lock;
return 0;
@@ -97,6 +102,7 @@
int
pthread_cond_destroy(pthread_cond_t *const cond)
{
+ USED(cond);
return 0;
}
--- a/tools/input/input.c
+++ b/tools/input/input.c
@@ -72,6 +72,7 @@
DemuxerContext *c;
int res, i;
+ impl = NULL;
if (name) {
for (i = 0; demuxers[i]; i++) {
if (!strcmp(demuxers[i]->name, name)) {