ref: 24a65311b538504923aaee04393fd363c2a63356
dir: /ogg.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "common.h" static int sgszs[256]; static int packet(Biobuf *out, Framectx *ctx, int htype, u8int *buf, int sz, 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; 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; n = 1 + (sz > 0 ? (sz-1)/255 : 0); h[26] = n; if(n+27 >= nelem(h)){ werrstr("frame is too large"); return -1; } for(i = 0, psz = sz; i < n && i < nelem(h)-27; i++){ h[27+i] = min(255, psz); psz -= h[27+i]; if(psz == 0) break; } n += 27; crc = crc32(crc32(0, h, n), buf, sz); h[22] = crc >> 24; h[23] = crc >> 16; h[24] = crc >> 8; h[25] = crc; if(Bwrite(out, h, n) != n || Bwrite(out, buf, sz) != sz) return -1; return 0; } int oggpacket(Biobuf *out, Framectx *ctx, u8int *buf, int sz, uvlong ts) { /* magic vendor len list len */ u8int opuscomment[] = {'O','p','u','s','T','a','g','s', 0,0,0,0, 0,0,0,0}; int r, i, nsg, dsz, total; u8int *d; u64int gr; gr = ts * 48 / 1000000; r = 0; if(ctx->frid == 0){ /* first packet? */ ctx->frid; d = ctx->codec.priv.data; dsz = ctx->codec.priv.sz; /* id/codec setup header always goes first */ if(ctx->codec.priv.sz > 0){ /* if we have codec setup data, write it */ if(ctx->fmt == FmtVorbis){ nsg = *d++; dsz--; for(i = 0, total = 0; i < nsg && dsz > 0; i++, total += sgszs[i]){ sgszs[i] = 0; do{ sgszs[i] += *d; dsz--; }while(*d++ == 0xff); } if(total > dsz){ werrstr("vorbis setup data out of bounds"); goto err; } for(i = 0; i < nsg && dsz > 0; d += sgszs[i], dsz -= sgszs[i], i++){ if(packet(out, ctx, i == 0 ? 2 : 0, d, sgszs[i], 0) != 0) goto err; } if(dsz > 0) r = packet(out, ctx, 0, d, dsz, 0); }else{ r = packet(out, ctx, 2, d, dsz, 0); } sz = 0; /* don't duplicate it */ }else{ /* otherwise let's hope the first packet has that data itself */ r = packet(out, ctx, 2, buf, sz, 0); } if(r != 0) goto err; /* comment */ if(ctx->fmt == FmtOpus) r = packet(out, ctx, 0, opuscomment, sizeof(opuscomment), 0); if(r != 0) goto err; } if(sz > 0 && packet(out, ctx, 0, buf, sz, gr) != 0) goto err; return 0; err: werrstr("oggpacket: %r"); return -1; }