ref: 49dc43fd64bb77001494be6721380895f1bba971
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 sz > 0 ? (Bwrite(out, p, sz) != sz ? -1 : 0) : 0; } int ivfpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key) { u8int d[0x20], *x, *y, *e; 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; e = x + ctx->codec.priv.sz; 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; if(y+len > e){ werrstr("sps out of range"); goto err; } ctx->ps[ctx->nps].p = malloc(4+len); memmove(ctx->ps[ctx->nps].p, x, 4); memmove(ctx->ps[ctx->nps].p+4, y, len); ctx->ps[ctx->nps++].n = 4+len; ctx->frid++; y += len; } /* pps */ n = *y++; for(i = 0; i < n; i++){ len = y[0] << 8 | y[1]; y += 2; if(y+len > e){ werrstr("pps out of range"); goto err; } ctx->ps[ctx->nps].p = malloc(4+len); memmove(ctx->ps[ctx->nps].p, x, 4); memmove(ctx->ps[ctx->nps].p+4, y, len); ctx->ps[ctx->nps++].n = 4+len; ctx->frid++; y += len; } } } if(key && ctx->fmt == FmtAvc1){ for(i = 0; i < ctx->nps; i++) ivfframe(out, ctx->ps[i].p, ctx->ps[i].n, 0, 0); } if(ivfframe(out, p->data, p->sz, ts, ctx->fmt == FmtAvc1) != 0) goto err; ctx->frid++; } return 0; err: werrstr("ivfpacket: %r"); return -1; }