ref: 190e3848a9ecf54d0b1a5863d1ed653f0fa24ae8
dir: /ivf.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "stream.h"
struct Stream {
Streamhdr;
Biobuf *b;
u8int *buf;
int bufsz;
};
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 |= x<<(i*8), i++){
if((x = Bgetc(b)) < 0){
werrstr("failed to read 8 bytes");
return -1;
}
}
return 0;
}
static Stream *
ivfopen(char *filename, Streaminfo *info, int *failed)
{
Biobuf *b;
Stream *s;
u16int hlen, w, h;
u32int tbdenum, tbnum;
char tmp[6];
if((b = Bopen(filename, OREAD)) == nil)
return nil;
if(Bread(b, tmp, 6) != 6 || memcmp(tmp, "DKIF", 4) != 0 || Bu16le(b, &hlen) < 0){
Bterm(b);
return nil;
}
if((s = calloc(1, sizeof(*s))) == nil)
goto err;
if(hlen < 0x20 || Bread(b, tmp, 4) != 4){
werrstr("invalid header: hlen=%d", hlen);
goto err;
}
if(memcmp(tmp, "AV01", 4) != 0){ /* nothing else is supported yet */
werrstr("unsupported format %.*s", 4, tmp);
goto err;
}
info->fmt = FmtAV1;
if(Bu16le(b, &w) < 0 || Bu16le(b, &h) < 0 || Bu32le(b, &tbdenum) < 0 || Bu32le(b, &tbnum) < 0){
werrstr("invalid header: %r");
goto err;
}
info->w = w;
info->h = h;
info->timebase.denum = tbdenum;
info->timebase.num = tbnum;
if(Bseek(b, hlen, 0) != hlen){
werrstr("invalid IVF stream");
goto err;
}
s->b = b;
return s;
err:
*failed = 1;
Bterm(b);
free(s);
return nil;
}
static void
ivfclose(Stream *s)
{
Bterm(s->b);
free(s->buf);
free(s);
}
static int
ivfread(Stream *s, Streamframe *f)
{
u64int timestamp;
u32int sz;
u8int *buf;
f->offset = Boffset(s->b);
if(Bu32le(s->b, &sz) < 0 || Bu64le(s->b, ×tamp) || (int)sz < 0)
return -1;
buf = s->buf;
if(s->ops.alloc != nil)
buf = s->ops.alloc(s->ops.aux, sz);
else if(sz > s->bufsz){
if((buf = realloc(s->buf, sz)) == nil){
werrstr("frame is too big: %d bytes", sz);
return -1;
}
s->buf = buf;
}
if(Bread(s->b, buf, sz) != sz){
werrstr("short read");
return -1;
}
f->buf = buf;
f->sz = sz;
f->timestamp = timestamp;
return 0;
}
static vlong
ivfoffset(Stream *s)
{
return Boffset(s->b);
}
Streamops ivfops = {
.open = ivfopen,
.close = ivfclose,
.read = ivfread,
};