ref: 1726aef226fe5b6dcd7b61cd106d1ddf4bb432a0
dir: /decoder_av1.c/
#include <dav1d.h>
#include "frame.h"
#include "stream.h"
#include "decoder.h"
#include "misc.h"
#pragma lib "../dav1d/src/libdav1d.$M.a"
typedef struct Aux Aux;
struct Aux {
Dav1dContext *c;
};
static char *layouts[] = {
[DAV1D_PIXEL_LAYOUT_I400] = "i400",
[DAV1D_PIXEL_LAYOUT_I420] = "i420",
[DAV1D_PIXEL_LAYOUT_I422] = "i422",
[DAV1D_PIXEL_LAYOUT_I444] = "i444",
};
static u8int *
allocdata(void *data, int sz)
{
return dav1d_data_create(data, sz);
}
static int
readframe(Stream *s, Dav1dData *data)
{
Streamframe f;
s->ops.aux = data;
if(Sread(s, &f) != 0)
return -1;
data->m.timestamp = f.timestamp;
return 0;
}
static void
decode(void *x)
{
uvlong lasttimestamp;
Dav1dPicture pic;
Dav1dData data;
Decoder *d;
Channel *c;
Frame *f;
Aux *a;
int res;
d = x;
a = d->aux;
lasttimestamp = 0;
memset(&pic, 0, sizeof(pic));
for(res = 0, data.sz = 0; data.sz > 0 || (res = readframe(d->s, &data)) == 0;){
if(data.sz == 0)
break;
res = dav1d_get_picture(a->c, &pic);
if(res < 0){
if(res != DAV1D_ERR(EAGAIN)){
werrstr("dav1d_get_picture: %d", res);
break;
}
}else if(pic.p.layout != DAV1D_PIXEL_LAYOUT_I420){
if(pic.p.layout >= 0 && pic.p.layout < nelem(layouts))
werrstr("%s", layouts[pic.p.layout]);
else
werrstr("??? (%d)", pic.p.layout);
werrstr("unsupported pixel layout: %r");
res = -1;
break;
}else if(pic.p.bpc != 8){
werrstr("unsupported bits per component: %d", pic.p.bpc);
res = -1;
break;
}else if((f = malloc(sizeof(*f) + pic.p.w*pic.p.h*3)) != nil){
f->w = pic.p.w;
f->h = pic.p.h;
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) * d->timebase * 1000000000ULL;
lasttimestamp = pic.m.timestamp;
dav1d_picture_unref(&pic);
if(sendp(d->frames, f) < 0){
free(f);
break;
}
}
res = dav1d_send_data(a->c, &data);
if(res < 0){
if(res != DAV1D_ERR(EAGAIN)){
werrstr("dav1d_send_data: %d", res);
break;
}
}
}
if(res != 0)
fprint(2, "av1: %r\n");
if(data.sz > 0)
dav1d_data_unref(&data);
/* drain */
while(dav1d_get_picture(a->c, &pic) >= 0)
dav1d_picture_unref(&pic);
dav1d_close(&a->c);
free(a);
c = d->finished;
sendp(c, res == 0 ? nil : "error");
chanclose(c);
threadexits(nil);
}
static int
av1open(Decoder *d)
{
Dav1dSettings av1s;
Aux *a;
int res;
a = calloc(1, sizeof(*a));
dav1d_default_settings(&av1s);
av1s.n_frame_threads = nproc;
av1s.n_tile_threads = nproc;
if((res = dav1d_open(&a->c, &av1s)) != 0){
werrstr("dav1d_open: %d", res);
free(a);
return -1;
}
d->aux = a;
d->s->ops.alloc = allocdata;
proccreate(decode, d, 16384);
return 0;
}
static void
av1close(Decoder *d)
{
USED(d);
}
Decoderops av1ops = {
.open = av1open,
.close = av1close,
};