shithub: rtmp

ref: f68aad9c7e2b465cffecdd033e3a4c6612dfa40c
dir: /ivf.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "ivf.h"
#include "util.h"

#define Zns₀ (~0ULL)

static int
Bu16le(Biobuf *b, u16int *o)
{
	int x;

	x = Bgetc(b);
	x |= Bgetc(b)<<8;
	*o = x;
	if(x < 0)
		werrstr("failed to read 2 bytes");

	return x < 0 ? -1 : 0;
}

static int
Bu32le(Biobuf *b, u32int *o)
{
	int x, i;

	*o = 0;
	for(i = 0; i < 4; *o |= x<<(i*8), i++){
		if((x = Bgetc(b)) < 0){
			werrstr("failed to read 4 bytes");
			return -1;
		}
	}

	return 0;
}

static int
Bu64le(Biobuf *b, u64int *o)
{
	int x, i;

	*o = 0;
	for(i = 0; i < 8; *o |= (uvlong)x<<(i*8), i++){
		if((x = Bgetc(b)) < 0){
			werrstr("failed to read 8 bytes");
			return -1;
		}
	}

	return 0;
}

int
ivfopen(Biobuf *v, IVF *ivf)
{
	u16int hlen;
	u8int b[6];

	if(Bread(v, b, 6) != 6 || Bu16le(v, &hlen) < 0 ||
	   hlen < 0x20 || memcmp(b, "DKIF", 4) != 0 ||
	   Bread(v, b, 4) != 4){
		werrstr("invalid header");
		goto err;
	}
	memmove(ivf->type, b, 4);
	ivf->v = v;
	ivf->type[4] = 0;
	ivf->ns₀ = Zns₀;
	if(Bu16le(v, &ivf->w) < 0 ||
	   Bu16le(v, &ivf->h) < 0 ||
	   Bu32le(v, &ivf->tbdenum) < 0 ||
	   Bu32le(v, &ivf->tbnum) < 0){
		werrstr("invalid data");
		goto err;
	}
	if(Bseek(v, hlen, 0) != hlen){
		werrstr("broken stream");
		goto err;
	}

	return 0;
err:
	werrstr("ivfopen: %r");
	return -1;
}

static u64int
ivfns(IVF *ivf, u64int ts)
{
	return ts * (ivf->tbnum * 1000000000ULL / ivf->tbdenum);
}

int
ivfread(IVF *ivf, IVFrame *f)
{
	u64int ts;
	u32int sz;
	int n;

	if(Bu32le(ivf->v, &sz) < 0 || Bu64le(ivf->v, &ts) < 0 || (int)sz < 0){
		/* eof */
		f->sz = 0;
		return 0;
	}
	if(sz > f->bufsz){
		f->bufsz = sz*2;
		f->buf = erealloc(f->buf, sz*2);
	}
	if((n = Bread(ivf->v, f->buf, sz)) != sz){
		werrstr("short read (%d < %d)", n, sz);
		goto err;
	}
	if(ivf->ns₀ == Zns₀)
		ivf->ns₀ = ivfns(ivf, ts);
	f->sz = sz;
	f->ns = ivfns(ivf, ts) - ivf->ns₀;

	return 0;
err:
	werrstr("ivfread: %r");
	return -1;
}