ref: 0f11e462ff527785f39740913f0067cb962e2bd7
dir: /ivf.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "common.h"
#include "packet.h"
enum {
Timedenum = 1000ULL,
};
static int
ivfframe(Biobuf *out, u8int *p, int sz, uvlong ts, int avcsplit)
{
u8int d[12];
int n, len;
d[0] = sz;
d[1] = sz >> 8;
d[2] = sz >> 16;
d[3] = sz >> 24;
d[4] = ts;
d[5] = ts >> 8;
d[6] = ts >> 16;
d[7] = ts >> 24;
d[8] = ts >> 32;
d[9] = ts >> 40;
d[10] = ts >> 48;
d[11] = ts >> 56;
if(Bwrite(out, d, 12) != 12)
return -1;
if(avcsplit){
for(n = 0; n < sz; n += len+4){
len = p[n+0]<<24 | p[n+1]<<16 | p[n+2]<<8 | p[n+3];
p[n+0] = 0;
p[n+1] = 0;
p[n+2] = 0;
p[n+3] = 1;
}
}
return Bwrite(out, p, sz) != sz ? -1 : 0;
}
int
ivfpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts)
{
u8int d[0x20], *x, *y;
int i, n, len;
uvlong dur;
dur = ctx->duration / 1000000ULL;
ts = ts / 1000000ULL;
for(; np > 0; np--, p++){
if(ctx->frid == 0){
memmove(d, "DKIF", 4);
d[4] = 0;
d[5] = 0;
d[6] = 0x20;
d[7] = 0;
if(ctx->fmt == FmtAv01)
memmove(d+8, "AV01", 4);
else if(ctx->fmt == FmtAvc1)
memmove(d+8, "AVC1", 4);
else if(ctx->fmt == FmtVp08)
memmove(d+8, "VP80", 4);
else if(ctx->fmt == FmtVp09)
memmove(d+8, "VP90", 4);
else{
werrstr("unsupported video format %T", ctx->fmt);
goto err;
}
d[12] = ctx->video.width;
d[13] = ctx->video.width >> 8;
d[14] = ctx->video.height;
d[15] = ctx->video.height >> 8;
/* timebase denum */
d[16] = Timedenum;
d[17] = Timedenum >> 8;
d[18] = Timedenum >> 16;
d[19] = Timedenum >> 24;
/* timebase num */
d[20] = 1;
d[21] = 0;
d[22] = 0;
d[23] = 0;
/* FIXME is it a "number of frames" or "total duration?" */
d[24] = dur;
d[25] = dur >> 8;
d[26] = dur >> 16;
d[27] = dur >> 24;
d[28] = dur >> 32; /* FIXME is it 64 bits? */
d[29] = dur >> 40;
d[30] = dur >> 48;
d[31] = dur >> 56;
if(Bwrite(out, d, 0x20) != 0x20)
goto err;
if(ctx->codec.priv.sz > 0){
if(ctx->fmt != FmtAvc1){
werrstr("no idea what to do with codec private data for non-AVC1");
goto err;
}
x = ctx->codec.priv.data;
if(x[0] != 1){
werrstr("avc config: invalid version %d", x[0]);
goto err;
}
if((x[4] & 3) != 3){
werrstr("avc config: NAL size %d not implemented", (x[4] & 3)+1);
goto err;
}
/* sps */
x[0] = 0;
x[1] = 0;
x[2] = 0;
x[3] = 1;
n = x[5] & 0x1f;
y = x+6;
for(i = 0; i < n; i++){
len = y[0] << 8 | y[1];
y += 2;
memmove(x+4, y, len);
if(ivfframe(out, x, 4+len, 0, 0) != 0)
goto err;
ctx->frid++;
y += len;
}
/* pps */
n = *y++;
for(i = 0; i < n; i++){
len = y[0] << 8 | y[1];
y += 2;
memmove(x+4, y, len);
if(ivfframe(out, x, 4+len, 0, 0) != 0)
goto err;
ctx->frid++;
y += len;
}
}
}
if(ivfframe(out, p->data, p->sz, ts, ctx->fmt == FmtAvc1) != 0)
goto err;
ctx->frid++;
}
return 0;
err:
werrstr("ivfpacket: %r");
return -1;
}