#include <u.h>#include <libc.h>#include <bio.h>#include "common.h"#include "packet.h" static intpacket(Biobuf *out, Packetctx *ctx, int htype, Packet *p, int np, uvlong granule){ /* magic ver htype granule serial seq checksum page segments segsz */ /* segsz 0 4 5 6 14 18 22 26 27 */ u8int h[28+255] = {'O','g','g','S', 0, 0, 0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0, 0}; u32int crc; int psz, i, n, ntot, ip; if(ctx->frid == 0 && ctx->fmt == FmtTheora && np > 0 && p->sz > 41){ if(memcmp(p->data, "\x80theora", 7) != 0){ werrstr("invalid Theora packet"); return -1; } ctx->kfgshift = ((p->data[40]<<8 | p->data[41]) >> 5) & 0x1f; } h[5] = htype; h[6] = granule; h[7] = granule >> 8; h[8] = granule >> 16; h[9] = granule >> 24; h[10] = granule >> 32; h[11] = granule >> 40; h[12] = granule >> 48; h[13] = granule >> 56; h[14] = ctx->trackuid; h[15] = ctx->trackuid >> 8; h[16] = ctx->trackuid >> 16; h[17] = ctx->trackuid >> 24; h[18] = ctx->frid; h[19] = ctx->frid >> 8; h[20] = ctx->frid >> 16; h[21] = ctx->frid >> 24; ctx->frid++; h[22] = 0; h[23] = 0; h[24] = 0; h[25] = 0; for(ntot = ip = 0; ip < np; ip++){ n = 1 + p[ip].sz/255; if(27+ntot+n >= nelem(h)){ werrstr("frame is too large"); return -1; } for(i = 0, psz = p[ip].sz; i < n; i++){ h[27+ntot+i] = min(255, psz); if(psz == 0) break; psz -= h[27+ntot+i]; } ntot += n; } h[26] = ntot; ntot += 27; for(ip = 0, crc = crc32(0, h, ntot); ip < np; ip++) crc = crc32(crc, p[ip].data, p[ip].sz); h[22] = crc >> 24; h[23] = crc >> 16; h[24] = crc >> 8; h[25] = crc; if(Bwrite(out, h, ntot) != ntot) return -1; for(ip = 0; ip < np; ip++){ if(Bwrite(out, p[ip].data, p[ip].sz) != p[ip].sz) return -1; } return 0;} intoggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key){ /* magic vendor len list len */ u8int opuscomment[] = {'O','p','u','s','T','a','g','s', 0,0,0,0, 0,0,0,0}; int i, nsg, dsz, total; u8int *d; u64int gr; int sgszs[4]; Packet onep; USED(key); ts += ctx->seekpreroll - ctx->discardpad; if(ctx->frid == 0){ /* first packet? */ d = ctx->codec.priv.data; dsz = ctx->codec.priv.sz; if(dsz < 1){ werrstr("codec private data missing"); goto err; } /* id/codec setup header always goes first */ if(ctx->fmt == FmtVorbis || ctx->fmt == FmtTheora){ i = *d++; dsz--; for(nsg = 0, total = 0; i > 0 && dsz > 0; total += sgszs[nsg], nsg++){ sgszs[nsg] = 0; do{ sgszs[nsg] += *d; dsz--; i--; }while(*d++ == 0xff); } if(total > dsz){ werrstr("setup data out of bounds"); goto err; } for(i = 0; i < nsg && dsz > 0; d += sgszs[i], dsz -= sgszs[i], i++){ onep.data = d; onep.sz = sgszs[i]; if(packet(out, ctx, i == 0 ? 2 : 0, &onep, 1, 0) != 0) goto err; } } if(dsz > 0){ /* either leftovers or other codecs, write as is */ onep.data = d; onep.sz = dsz; if(packet(out, ctx, 2, &onep, 1, 0) != 0) goto err; } if(ctx->fmt == FmtOpus){ /* Opus requires a comment */ onep.data = opuscomment; onep.sz = sizeof(opuscomment); if(packet(out, ctx, 0, &onep, 1, 0) != 0) goto err; } } if(ctx->fmt == FmtTheora){ ctx->nonkey++; /* FIXME VREV 1 vs 0 diff here, to make it work with 0 */ if(key){ ctx->key += ctx->nonkey; ctx->nonkey = 0; } gr = (uvlong)ctx->key<<ctx->kfgshift | ctx->nonkey; }else{ gr = (ts * 48) / 1000000; } if(np > 0 && packet(out, ctx, ctx->discardpad ? 4 : 0, p, np, gr) != 0) goto err; return 0;err: werrstr("oggpacket: %r"); return -1;}
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "common.h"
#include "packet.h"
static int
packet(Biobuf *out, Packetctx *ctx, int htype, Packet *p, int np, uvlong granule)
{
/* magic ver htype granule serial seq checksum page segments segsz */
/* segsz 0 4 5 6 14 18 22 26 27 */
u8int h[28+255] = {'O','g','g','S', 0, 0, 0,0,0,0,0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0, 0};
u32int crc;
int psz, i, n, ntot, ip;
if(ctx->frid == 0 && ctx->fmt == FmtTheora && np > 0 && p->sz > 41){
if(memcmp(p->data, "\x80theora", 7) != 0){
werrstr("invalid Theora packet");
return -1;
}
ctx->kfgshift = ((p->data[40]<<8 | p->data[41]) >> 5) & 0x1f;
}
h[5] = htype;
h[6] = granule;
h[7] = granule >> 8;
h[8] = granule >> 16;
h[9] = granule >> 24;
h[10] = granule >> 32;
h[11] = granule >> 40;
h[12] = granule >> 48;
h[13] = granule >> 56;
h[14] = ctx->trackuid;
h[15] = ctx->trackuid >> 8;
h[16] = ctx->trackuid >> 16;
h[17] = ctx->trackuid >> 24;
h[18] = ctx->frid;
h[19] = ctx->frid >> 8;
h[20] = ctx->frid >> 16;
h[21] = ctx->frid >> 24;
ctx->frid++;
h[22] = 0;
h[23] = 0;
h[24] = 0;
h[25] = 0;
for(ntot = ip = 0; ip < np; ip++){
n = 1 + p[ip].sz/255;
if(27+ntot+n >= nelem(h)){
werrstr("frame is too large");
return -1;
}
for(i = 0, psz = p[ip].sz; i < n; i++){
h[27+ntot+i] = min(255, psz);
if(psz == 0)
break;
psz -= h[27+ntot+i];
}
ntot += n;
}
h[26] = ntot;
ntot += 27;
for(ip = 0, crc = crc32(0, h, ntot); ip < np; ip++)
crc = crc32(crc, p[ip].data, p[ip].sz);
h[22] = crc >> 24;
h[23] = crc >> 16;
h[24] = crc >> 8;
h[25] = crc;
if(Bwrite(out, h, ntot) != ntot)
return -1;
for(ip = 0; ip < np; ip++){
if(Bwrite(out, p[ip].data, p[ip].sz) != p[ip].sz)
return -1;
}
return 0;
}
int
oggpacket(Biobuf *out, Packetctx *ctx, Packet *p, int np, uvlong ts, int key)
{
/* magic vendor len list len */
u8int opuscomment[] = {'O','p','u','s','T','a','g','s', 0,0,0,0, 0,0,0,0};
int i, nsg, dsz, total;
u8int *d;
u64int gr;
int sgszs[4];
Packet onep;
USED(key);
ts += ctx->seekpreroll - ctx->discardpad;
if(ctx->frid == 0){ /* first packet? */
d = ctx->codec.priv.data;
dsz = ctx->codec.priv.sz;
if(dsz < 1){
werrstr("codec private data missing");
goto err;
}
/* id/codec setup header always goes first */
if(ctx->fmt == FmtVorbis || ctx->fmt == FmtTheora){
i = *d++;
dsz--;
for(nsg = 0, total = 0; i > 0 && dsz > 0; total += sgszs[nsg], nsg++){
sgszs[nsg] = 0;
do{
sgszs[nsg] += *d;
dsz--;
i--;
}while(*d++ == 0xff);
}
if(total > dsz){
werrstr("setup data out of bounds");
goto err;
}
for(i = 0; i < nsg && dsz > 0; d += sgszs[i], dsz -= sgszs[i], i++){
onep.data = d;
onep.sz = sgszs[i];
if(packet(out, ctx, i == 0 ? 2 : 0, &onep, 1, 0) != 0)
goto err;
}
}
if(dsz > 0){ /* either leftovers or other codecs, write as is */
onep.data = d;
onep.sz = dsz;
if(packet(out, ctx, 2, &onep, 1, 0) != 0)
goto err;
}
if(ctx->fmt == FmtOpus){ /* Opus requires a comment */
onep.data = opuscomment;
onep.sz = sizeof(opuscomment);
if(packet(out, ctx, 0, &onep, 1, 0) != 0)
goto err;
}
}
if(ctx->fmt == FmtTheora){
ctx->nonkey++; /* FIXME VREV 1 vs 0 diff here, to make it work with 0 */
if(key){
ctx->key += ctx->nonkey;
ctx->nonkey = 0;
}
gr = (uvlong)ctx->key<<ctx->kfgshift | ctx->nonkey;
}else{
gr = (ts * 48) / 1000000;
}
if(np > 0 && packet(out, ctx, ctx->discardpad ? 4 : 0, p, np, gr) != 0)
goto err;
return 0;
err:
werrstr("oggpacket: %r");
return -1;
}