shithub: treason

ref: 82b18def5d91a37c264fdc4b4860ea2af664acfc
dir: treason/decoder_vpx.c

View raw version
#include <vpx_codec.h>
#include <vpx_decoder.h>
#include <vpx_image.h>
#include <vp8dx.h>
#include "frame.h"
#include "stream.h"
#include "decoder.h"
#include "misc.h"

#pragma lib "../libvpx/libvpx.$M.a"

typedef struct Aux Aux;

struct Aux {
	vpx_codec_ctx_t ctx;
};

static void
decode(void *x)
{
	uvlong lasttimestamp;
	Decoder *d;
	Channel *c;
	Frame *f;
	Streamframe sf;
	Aux *a;
	int res;
	u8int *pic;
    vpx_codec_iter_t iter;
    uvlong start;
    vpx_image_t *im;

	threadsetname("decoder/vpx");
	d = x;
	a = d->aux;
	lasttimestamp = 0;
	memset(&pic, 0, sizeof(pic));
	for(res = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0;){
		start = nanosec();
		if((res = vpx_codec_decode(&a->ctx, sf.buf, sf.sz, NULL, 0)) != 0){
			werrstr("vpx_codec_decode failed");
			break;
		}
		d->decodetime = nanosec() - start;

		for(iter = nil;;){
			if((im = vpx_codec_get_frame(&a->ctx, &iter)) == nil)
				break;
			if(im->fmt != VPX_IMG_FMT_I420){
				vpx_img_free(im);
				werrstr("images other than YUV420 aren't supported");
				res = -1;
				break;
			}

			if((f = newframe(im->d_w, im->d_h, im->planes, im->stride[0], im->stride[1])) != nil){
				f->crop.left = 0;
				f->crop.top = 0;
				f->crop.right = im->d_w;
				f->crop.bottom = im->d_h;
				f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL;
				lasttimestamp = sf.timestamp;
				vpx_img_free(im);

				if(sendp(d->frames, f) < 0){
					free(f);
					goto done;
				}
			}
		}
	}
	if(res != 0)
		fprint(2, "vpx: %r\n");

done:
	vpx_codec_destroy(&a->ctx);
	free(a);
	c = d->finished;
	sendp(c, res == 0 ? nil : "error");
	chanclose(c);

	threadexits(nil);
}

static int
vpxopen(Decoder *d)
{
	Aux *a;
	vpx_codec_iface_t *iface;
	vpx_codec_dec_cfg_t cfg = {nproc, 0, 0};

	a = calloc(1, sizeof(*a));
	iface = d->s->fmt == FmtVP9 ? vpx_codec_vp9_dx() : vpx_codec_vp8_dx();

	if(vpx_codec_dec_init(&a->ctx, iface, &cfg, 0) != 0){
		werrstr("vpx_codec_dec_init failed");
		free(a);
		return -1;
	}

	d->aux = a;
	proccreate(decode, d, 65536);

	return 0;
}

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

Decoderops vpxops = {
	.open = vpxopen,
	.close = vpxclose,
};