shithub: treason

ref: 2a330793160ce56ce985e1723725188b235c26c5
dir: treason/decoder_h264.c

View raw version
#include <h264bsd_decoder.h>
#include <h264bsd_util.h>
#include <thread.h>
#include "frame.h"
#include "stream.h"
#include "decoder.h"
#include "misc.h"

#pragma lib "../h264bsd/src/libh264bsd.$M.a"

typedef struct Aux Aux;

struct Aux {
	storage_t c;
};

static void
decode(void *x)
{
	uvlong lasttimestamp;
	Decoder *d;
	Channel *c;
	Frame *f;
	Streamframe sf;
	Aux *a;
	int res, off;
	u32int used, nerr, isidr, picid;
	u32int realw, realh, w, h, crop, left, top;
	u8int *pic;

	d = x;
	a = d->aux;
	lasttimestamp = 0;
	realw = 0;
	realh = 0;
	for(res = 0; res >= 0 && (res = Sread(d->s, &sf)) == 0 && sf.sz > 0;){
		off = 0;
next:
		if((res = h264bsdDecode(&a->c, sf.buf+off, sf.sz-off, 0, &used)) < 0){
			werrstr("h264bsdDecode: %r (%d)", res);
			break;
		}
		off += used;
		switch(res){
		case H264BSD_PIC_RDY:
			if((pic = h264bsdNextOutputPicture(&a->c, &picid, &isidr, &nerr)) == nil){
				werrstr("nil pic");
				res = -1;
			}else if((f = malloc(sizeof(*f) + w*h*3)) != nil){
				f->w = w;
				f->h = realh;
				f->crop.left = left;
				f->crop.top = top;
				f->crop.right = realw;
				f->crop.bottom = realh;
				yuv420_rgb24(w, h, pic, pic+w*h, pic+w*h*5/4, w, w/2, f->rgb, w*3);
				f->dt = (sf.timestamp - lasttimestamp) * d->timebase * 1000000000ULL;
				lasttimestamp = sf.timestamp;

				if(sendp(d->frames, f) < 0){
					free(f);
					goto done;
				}
			}
			break;

		case H264BSD_HDRS_RDY:
			h264bsdCroppingParams(&a->c, &crop, &left, &w, &top, &h);
			if(!crop){
				w = h264bsdPicWidth(&a->c) * 16;
				h = h264bsdPicHeight(&a->c) * 16;
			}
			realw = w;
			realh = h;
			if(w & 15)
				w += 16 - (w & 15);
			if(h & 15)
				h += 16 - (h & 15);
			break;

		case H264BSD_RDY:
			break;

		case H264BSD_ERROR:
	        res = -1;
	        werrstr("decoding error: %r");
			break;

		case H264BSD_PARAM_SET_ERROR:
	        res = -1;
			werrstr("param set error: %r");
			break;
		}

		if(off < sf.sz)
			goto next;
	}
	if(res != 0)
		fprint(2, "h264: %r\n");

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

	threadexits(nil);
}

static int
h264open(Decoder *d)
{
	Aux *a;
	int res;

	a = calloc(1, sizeof(*a));
	if((res = h264bsdInit(&a->c, HANTRO_FALSE)) != 0){
		werrstr("h264bsdInit: %d", res);
		free(a);
		return -1;
	}
	d->aux = a;
	proccreate(decode, d, 65536);

	return res;
}

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

Decoderops h264ops = {
	.open = h264open,
	.close = h264close,
};