shithub: treason

ref: 339de1879aec67a053cc0bdf11bb47d3eaf290a2
dir: /dec_av1.c/

View raw version
#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;
};

struct Stream {
	Streamhdr;
};

static char *layout[] = {
	[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.offset = f.offset;
	data->m.timestamp = f.timestamp;

	return 0;
}

static void
decode(void *x)
{
	uvlong lasttimestamp;
	Dav1dPicture pic;
	Dav1dData data;
	Decoder *d;
	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(nbrecvp(d->stop) != 0){
			print("received stop\n");
			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((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);
	sendp(d->finished, nil);
	free(a);

	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;
	}
	proccreate(decode, d, 16384);
	d->aux = a;
	d->s->ops.alloc = allocdata;

	return 0;
}

static void
av1close(Decoder *d)
{
	USED(d);
}

Decoderops av1ops = {
	.open = av1open,
	.close = av1close,
};