diff options
Diffstat (limited to 'appl/wm/mpeg/decode.b')
| -rw-r--r-- | appl/wm/mpeg/decode.b | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/appl/wm/mpeg/decode.b b/appl/wm/mpeg/decode.b new file mode 100644 index 00000000..16906c99 --- /dev/null +++ b/appl/wm/mpeg/decode.b @@ -0,0 +1,831 @@ +implement Mpegd; + +include "sys.m"; +include "mpegio.m"; + +sys: Sys; +idct: IDCT; + +Mpegi, Picture, Slice, MacroBlock, YCbCr, Pair: import Mpegio; + +intra_tab := array[64] of { + 8, 16, 19, 22, 26, 27, 29, 34, + 16, 16, 22, 24, 27, 29, 34, 37, + 19, 22, 26, 27, 29, 34, 34, 38, + 22, 22, 26, 27, 29, 34, 37, 40, + 22, 26, 27, 29, 32, 35, 40, 48, + 26, 27, 29, 32, 35, 40, 48, 58, + 26, 27, 29, 34, 38, 46, 56, 69, + 27, 29, 35, 38, 46, 56, 69, 83, +}; + +nintra_tab := array[64] of { * => 16 }; + +CLOFF: con 256; + +intraQ, nintraQ: array of int; +rtmp: array of array of int; +rflag := array[6] of int; +rforw, dforw, rback, dback: int; +rforw2, dforw2, rback2, dback2: int; +ydb, ydf, cdb, cdf: int; +vflags: int; +past := array[3] of int; +pinit := array[3] of { * => 128 * 8 }; +zeros := array[64] of { * => 0 }; +zeros1: array of int; +clamp := array[CLOFF + 256 + CLOFF] of byte; +width, height, w2, h2: int; +mpi, mps, yadj, cadj, yskip: int; +I, B0: ref YCbCr; +Ps := array[2] of ref YCbCr; +Rs := array[2] of ref YCbCr; +P, B, R, M, N: ref YCbCr; +pn: int = 0; +rn: int = 0; + +zig := array[64] of { + 0, 1, 8, 16, 9, 2, 3, 10, 17, + 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +}; + +init(m: ref Mpegi) +{ + sys = load Sys Sys->PATH; + idct = load IDCT IDCT->PATH; + if (idct == nil) { + sys->print("could not open %s: %r\n", IDCT->PATH); + exit; + } + idct->init(); + width = m.width; + height = m.height; + w2 = width >> 1; + h2 = height >> 1; + mps = width >> 4; + mpi = mps * height >> 4; + yskip = 8 * width; + yadj = 16 * width - (width - 16); + cadj = 8 * w2 - (w2 - 8); + I = frame(); + Ps[0] = frame(); + Ps[1] = frame(); + Rs[0] = Ps[0]; + Rs[1] = Ps[1]; + B0 = frame(); + for (i := 0; i < CLOFF; i++) + clamp[i] = byte 0; + for (i = 0; i < 256; i++) + clamp[i + CLOFF] = byte i; + for (i = CLOFF + 256; i < CLOFF + 256 + CLOFF; i++) + clamp[i] = byte 255; + if (m.intra == nil) + intraQ = intra_tab; + else + intraQ = zigof(m.intra); + if (m.nintra == nil) + nintraQ = nintra_tab; + else + nintraQ = zigof(m.nintra); + rtmp = array[6] of array of int; + for (i = 0; i < 6; i++) + rtmp[i] = array[64] of int; + zeros1 = zeros[1:]; +} + +zarray(n: int, v: byte): array of byte +{ + return array[n] of { * => v }; +} + +frame(): ref YCbCr +{ + y := zarray(width * height, byte 0); + b := zarray(w2 * h2, byte 128); + r := zarray(w2 * h2, byte 128); + return ref YCbCr(y, b, r); +} + +zigof(a: array of int): array of int +{ + z := array[64] of int; + for (i := 0; i < 64; i++) + z[zig[i]] = a[i]; + return z; +} + +invQ_intra(a: array of Pair, q: int, b: array of int) +{ + (nil, t) := a[0]; + b[0] = t * 8; + b[1:] = zeros1; + n := 1; + i := 1; + while (n < len a) { + (r, l) := a[n++]; + i += r; + x := zig[i++]; + if (l > 0) { + v := l * q * intraQ[x] >> 3; + if (v > 2047) + b[x] = 2047; + else + b[x] = (v - 1) | 1; + } else { + v := (l * q * intraQ[x] + 7) >> 3; + if (v < -2048) + b[x] = -2048; + else + b[x] = v | 1; + } + #sys->print("%d %d %d %d\n", x, r, l, b[x]); + } +} + +invQ_nintra(a: array of Pair, q: int, b: array of int) +{ + b[0:] = zeros; + i := 0; + for (n := 0; n < len a; n++) { + (r, l) := a[n]; + i += r; + if (l == 0) { + raisex("zero level"); + i++; + continue; + } + x := zig[i++]; + if (l > 0) { + v := ((l << 1) + 1) * q * nintraQ[x] >> 4; + if (v > 2047) + b[x] = 2047; + else + b[x] = (v - 1) | 1; + } else { + v := (((l << 1) - 1) * q * nintraQ[x] + 15) >> 4; + if (v < -2048) + b[x] = -2048; + else + b[x] = v | 1; + } + #sys->print("%d %d %d %d\n", x, r, l, b[x]); + } +} + +yzero(v: array of byte, base: int) +{ + x := 0; + i := 8; + do { + n := base; + j := 8; + do + v[n++] = byte 0; + while (--j > 0); + base += width; + } while (--i > 0); +} + +czero(v: array of byte, base: int) +{ + x := 0; + i := 8; + do { + n := base; + j := 8; + do + v[n++] = byte 128; + while (--j > 0); + base += w2; + } while (--i > 0); + +} + +blockzero(d: ref YCbCr) +{ + yzero(d.Y, ybase); + yzero(d.Y, ybase + 8); + yzero(d.Y, ybase + yskip); + yzero(d.Y, ybase + 8 + yskip); + czero(d.Cb, cbase); + czero(d.Cr, cbase); +} + +ydistr(a: array of int, v: array of byte, base: int) +{ + x := 0; + i := 8; + do { + n := base; + j := 8; + do + v[n++] = clamp[a[x++] + CLOFF]; + while (--j > 0); + base += width; + } while (--i > 0); +} + +cdistr(a: array of int, v: array of byte, base: int) +{ + x := 0; + i := 8; + do { + n := base; + j := 8; + do + v[n++] = clamp[a[x++] + CLOFF]; + while (--j > 0); + base += w2; + } while (--i > 0); + +} + +invQ_intra_block(b: array of array of Pair, q: int, pred: int, d: ref YCbCr) +{ + a, dc: array of int; + if (pred) + dc = past; + else + dc = pinit; + p := dc[0]; + for (i := 0; i < 4; i++) { + a = rtmp[i]; + #sys->print("%d\n", i); + invQ_intra(b[i], q, a); + p += a[0]; + a[0] = p; + #sys->print("%d\n", a[0]); + idct->idct(a); + } + past[0] = p; + for (i = 4; i < 6; i++) { + p = dc[i - 3]; + a = rtmp[i]; + #sys->print("%d\n", i); + invQ_intra(b[i], q, a); + p += a[0]; + a[0] = p; + #sys->print("%d\n", a[0]); + past[i - 3] = p; + idct->idct(a); + } + ydistr(rtmp[0], d.Y, ybase); + ydistr(rtmp[1], d.Y, ybase + 8); + ydistr(rtmp[2], d.Y, ybase + yskip); + ydistr(rtmp[3], d.Y, ybase + 8 + yskip); + cdistr(rtmp[4], d.Cb, cbase); + cdistr(rtmp[5], d.Cr, cbase); +} + +invQ_nintra_block(b: array of array of Pair, q: int) +{ + for (i := 0; i < 6; i++) { + p := b[i]; + if (p != nil) { + a := rtmp[i]; + #sys->print("%d\n", i); + invQ_nintra(p, q, a); + idct->idct(a); + rflag[i] = 1; + } else + rflag[i] = 0; + } +} + +mbr, ybase, cbase: int; + +nextmb() +{ + if (--mbr == 0) { + ybase += yadj; + cbase += cadj; + mbr = mps; + } else { + ybase += 16; + cbase += 8; + } +} + +copyblock(s, d: array of byte, b, n, w: int) +{ + i := 8; + do { + d[b:] = s[b:b+n]; + b += w; + } while (--i > 0); +} + +copyblockdisp(s, d: array of byte, b, n, w, p: int) +{ + i := 8; + p += b; + do { + d[b:] = s[p:p+n]; + b += w; + p += w; + } while (--i > 0); +} + +interpblock(s0, s1, d: array of byte, b, n, w, p0, p1: int) +{ + i := 8; + do { + dx := b; + s0x := b + p0; + s1x := b + p1; + j := n; + do + d[dx++] = byte ((int s0[s0x++] + int s1[s1x++] + 1) >> 1); + while (--j > 0); + b += w; + } while (--i > 0); +} + +deltablock(s: array of byte, r: array of int, d: array of byte, b, w, o: int) +{ + rx := 0; + i := 8; + do { + dx := b; + sx := b + o; + j := 8; + do + d[dx++] = clamp[CLOFF + int s[sx++] + r[rx++]]; + while (--j > 0); + b += w; + } while (--i > 0); +} + +deltainterpblock(s0, s1: array of byte, r: array of int, d: array of byte, b, w, o0, o1: int) +{ + rx := 0; + i := 8; + do { + dx := b; + s0x := b + o0; + s1x := b + o1; + j := 8; + do + d[dx++] = clamp[CLOFF + ((int s0[s0x++] + int s1[s1x++] + 1) >> 1) + r[rx++]]; + while (--j > 0); + b += w; + } while (--i > 0); +} + +dispblock(s, d: array of byte, n, b, w, o: int) +{ + if (rflag[n]) + deltablock(s, rtmp[n], d, b, w, o); + else + copyblockdisp(s, d, b, 8, w, o); +} + +genblock(s0, s1, d: array of byte, n, b, w, o0, o1: int) +{ + if (rflag[n]) + deltainterpblock(s0, s1, rtmp[n], d, b, w, o0, o1); + else + interpblock(s0, s1, d, b, 8, w, o0, o1); +} + +copymb() +{ + copyblock(R.Y, P.Y, ybase, 16, width); + copyblock(R.Y, P.Y, ybase + yskip, 16, width); + copyblock(R.Cb, P.Cb, cbase, 8, w2); + copyblock(R.Cr, P.Cr, cbase, 8, w2); +} + +deltamb() +{ + dispblock(R.Y, P.Y, 0, ybase, width, 0); + dispblock(R.Y, P.Y, 1, ybase + 8, width, 0); + dispblock(R.Y, P.Y, 2, ybase + yskip, width, 0); + dispblock(R.Y, P.Y, 3, ybase + 8 + yskip, width, 0); + dispblock(R.Cb, P.Cb, 4, cbase, w2, 0); + dispblock(R.Cr, P.Cr, 5, cbase, w2, 0); +} + +copymbforw() +{ + copyblockdisp(N.Y, B.Y, ybase, 16, width, ydf); + copyblockdisp(N.Y, B.Y, ybase + yskip, 16, width, ydf); + copyblockdisp(N.Cb, B.Cb, cbase, 8, w2, cdf); + copyblockdisp(N.Cr, B.Cr, cbase, 8, w2, cdf); +} + +copymbback() +{ + copyblockdisp(M.Y, B.Y, ybase, 16, width, ydb); + copyblockdisp(M.Y, B.Y, ybase + yskip, 16, width, ydb); + copyblockdisp(M.Cb, B.Cb, cbase, 8, w2, cdb); + copyblockdisp(M.Cr, B.Cr, cbase, 8, w2, cdb); +} + +copymbbackforw() +{ + interpblock(M.Y, N.Y, B.Y, ybase, 16, width, ydb, ydf); + interpblock(M.Y, N.Y, B.Y, ybase + yskip, 16, width, ydb, ydf); + interpblock(M.Cb, N.Cb, B.Cb, cbase, 8, w2, cdb, cdf); + interpblock(M.Cr, N.Cr, B.Cr, cbase, 8, w2, cdb, cdf); +} + +deltambforw() +{ + dispblock(N.Y, B.Y, 0, ybase, width, ydf); + dispblock(N.Y, B.Y, 1, ybase + 8, width, ydf); + dispblock(N.Y, B.Y, 2, ybase + yskip, width, ydf); + dispblock(N.Y, B.Y, 3, ybase + 8 + yskip, width, ydf); + dispblock(N.Cb, B.Cb, 4, cbase, w2, cdf); + dispblock(N.Cr, B.Cr, 5, cbase, w2, cdf); +} + +deltambback() +{ + dispblock(M.Y, B.Y, 0, ybase, width, ydb); + dispblock(M.Y, B.Y, 1, ybase + 8, width, ydb); + dispblock(M.Y, B.Y, 2, ybase + yskip, width, ydb); + dispblock(M.Y, B.Y, 3, ybase + 8 + yskip, width, ydb); + dispblock(M.Cb, B.Cb, 4, cbase, w2, cdb); + dispblock(M.Cr, B.Cr, 5, cbase, w2, cdb); +} + +deltambbackforw() +{ + genblock(M.Y, N.Y, B.Y, 0, ybase, width, ydb, ydf); + genblock(M.Y, N.Y, B.Y, 1, ybase + 8, width, ydb, ydf); + genblock(M.Y, N.Y, B.Y, 2, ybase + yskip, width, ydb, ydf); + genblock(M.Y, N.Y, B.Y, 3, ybase + 8 + yskip, width, ydb, ydf); + genblock(M.Cb, N.Cb, B.Cb, 4, cbase, w2, cdb, cdf); + genblock(M.Cr, N.Cr, B.Cr, 5, cbase, w2, cdb, cdf); +} + +deltambinterp() +{ + case vflags & (Mpegio->MB_MF | Mpegio->MB_MB) { + Mpegio->MB_MF => + deltambforw(); + Mpegio->MB_MB => + deltambback(); + Mpegio->MB_MF | Mpegio->MB_MB => + deltambbackforw(); + * => + raisex("bad vflags"); + } +} + +interpmb() +{ + case vflags & (Mpegio->MB_MF | Mpegio->MB_MB) { + Mpegio->MB_MF => + copymbforw(); + Mpegio->MB_MB => + copymbback(); + Mpegio->MB_MF | Mpegio->MB_MB => + copymbbackforw(); + * => + raisex("bad vflags"); + } +} + +Idecode(p: ref Picture): ref YCbCr +{ + sa := p.slices; + n := 0; + mbr = mps; + ybase = 0; + cbase = 0; + for (i := 0; i < len sa; i++) { + pred := 0; + ba := sa[i].blocks; + for (j := 0; j < len ba; j++) { + invQ_intra_block(ba[j].rls, ba[j].qscale, pred, I); + nextmb(); + n++; + pred = 1; + } + } + if (n != mpi) + raisex("I mb count"); + R = I; + Rs[rn] = I; + rn ^= 1; + return I; +} + +Pdecode(p: ref Picture): ref YCbCr +{ + rforwp, dforwp: int; + md, c: int; + P = Ps[pn]; + N = R; + B = P; + pn ^= 1; + fs := 1 << p.forwfc; + fsr := fs << 5; + fsmin := -(fs << 4); + fsmax := (fs << 4) - 1; + sa := p.slices; + n := 0; + mbr = mps; + ybase = 0; + cbase = 0; + for (i := 0; i < len sa; i++) { + pred := 0; + ipred := 0; + ba := sa[i].blocks; + for (j := 0; j < len ba; j++) { + mb := ba[j]; + while (n < mb.addr) { + copymb(); + ipred = 0; + pred = 0; + nextmb(); + n++; + } + if (mb.flags & Mpegio->MB_I) { + invQ_intra_block(mb.rls, mb.qscale, ipred, P); + #blockzero(P); + ipred = 1; + pred = 0; + } else { + if (mb.flags & Mpegio->MB_MF) { + if (fs == 1 || mb.mhfc == 0) + md = mb.mhfc; + else if ((c = mb.mhfc) < 0) + md = (c + 1) * fs - mb.mhfr - 1; + else + md = (c - 1) * fs + mb.mhfr + 1; + if (pred) + md += rforwp; + if (md > fsmax) + rforw = md - fsr; + else if (md < fsmin) + rforw = md + fsr; + else + rforw = md; + rforwp = rforw; + if (fs == 1 || mb.mvfc == 0) + md = mb.mvfc; + else if ((c = mb.mvfc) < 0) + md = (c + 1) * fs - mb.mvfr - 1; + else + md = (c - 1) * fs + mb.mvfr + 1; + if (pred) + md += dforwp; + if (md > fsmax) + dforw = md - fsr; + else if (md < fsmin) + dforw = md + fsr; + else + dforw = md; + dforwp = dforw; + if (p.flags & Mpegio->FPFV) { + rforw2 = rforw; + dforw2 = dforw; + rforw <<= 1; + dforw <<= 1; + ydf = rforw2 + dforw2 * width; + cdf = (rforw2 >> 1) + (dforw2 >> 1) * w2; + } else { + if (rforw < 0) + rforw2 = (rforw + 1) >> 1; + else + rforw2 = rforw >> 1; + if (dforw < 0) + dforw2 = (dforw + 1) >> 1; + else + dforw2 = dforw >> 1; + ydf = (rforw >> 1) + (dforw >> 1) * width; + cdf = (rforw2 >> 1) + (dforw2 >> 1) * w2; + } + pred = 1; + if (mb.rls != nil) { + invQ_nintra_block(mb.rls, mb.qscale); + deltambforw(); + } else + copymbforw(); + } else { + if (mb.rls == nil) + raisex("empty delta"); + invQ_nintra_block(mb.rls, mb.qscale); + deltamb(); + pred = 0; + } + ipred = 0; + } + nextmb(); + n++; + } + } + while (n < mpi) { + copymb(); + nextmb(); + n++; + } + R = P; + Rs[rn] = P; + rn ^= 1; + return P; +} + +Bdecode(p: ref Mpegio->Picture): ref Mpegio->YCbCr +{ + return Bdecode2(p, Rs[rn ^ 1], Rs[rn]); +} + +Bdecode2(p: ref Mpegio->Picture, f0, f1: ref Mpegio->YCbCr): ref Mpegio->YCbCr +{ + rforwp, dforwp, rbackp, dbackp: int; + md, c: int; + M = f0; + N = f1; + B = B0; + fs := 1 << p.forwfc; + fsr := fs << 5; + fsmin := -(fs << 4); + fsmax := (fs << 4) - 1; + bs := 1 << p.backfc; + bsr := bs << 5; + bsmin := -(bs << 4); + bsmax := (bs << 4) - 1; + sa := p.slices; + n := 0; + mbr = mps; + ybase = 0; + cbase = 0; + for (i := 0; i < len sa; i++) { + ipred := 0; + rback = 0; + rforw = 0; + dback = 0; + dforw = 0; + rbackp = 0; + rforwp = 0; + dbackp = 0; + dforwp = 0; + rback2 = 0; + rforw2 = 0; + dback2 = 0; + dforw2 = 0; + ydb = 0; + ydf = 0; + cdb = 0; + cdf = 0; + ba := sa[i].blocks; + for (j := 0; j < len ba; j++) { + mb := ba[j]; + while (n < mb.addr) { + interpmb(); + nextmb(); + ipred = 0; + n++; + } + if (mb.flags & Mpegio->MB_I) { + invQ_intra_block(mb.rls, mb.qscale, ipred, B); + ipred = 1; + rback = 0; + rforw = 0; + dback = 0; + dforw = 0; + rbackp = 0; + rforwp = 0; + dbackp = 0; + dforwp = 0; + rback2 = 0; + rforw2 = 0; + dback2 = 0; + dforw2 = 0; + ydb = 0; + ydf = 0; + cdb = 0; + cdf = 0; + } else { + if (mb.flags & Mpegio->MB_MF) { + if (fs == 1 || mb.mhfc == 0) + md = mb.mhfc; + else if ((c = mb.mhfc) < 0) + md = (c + 1) * fs - mb.mhfr - 1; + else + md = (c - 1) * fs + mb.mhfr + 1; + md += rforwp; + if (md > fsmax) + rforw = md - fsr; + else if (md < fsmin) + rforw = md + fsr; + else + rforw = md; + rforwp = rforw; + if (fs == 1 || mb.mvfc == 0) + md = mb.mvfc; + else if ((c = mb.mvfc) < 0) + md = (c + 1) * fs - mb.mvfr - 1; + else + md = (c - 1) * fs + mb.mvfr + 1; + md += dforwp; + if (md > fsmax) + dforw = md - fsr; + else if (md < fsmin) + dforw = md + fsr; + else + dforw = md; + dforwp = dforw; + if (p.flags & Mpegio->FPFV) { + rforw2 = rforw; + dforw2 = dforw; + rforw <<= 1; + dforw <<= 1; + ydf = rforw2 + dforw2 * width; + cdf = (rforw2 >> 1) + (dforw2 >> 1) * w2; + } else { + if (rforw < 0) + rforw2 = (rforw + 1) >> 1; + else + rforw2 = rforw >> 1; + if (dforw < 0) + dforw2 = (dforw + 1) >> 1; + else + dforw2 = dforw >> 1; + ydf = (rforw >> 1) + (dforw >> 1) * width; + cdf = (rforw2 >> 1) + (dforw2 >> 1) * w2; + } + } + if (mb.flags & Mpegio->MB_MB) { + if (bs == 1 || mb.mhbc == 0) + md = mb.mhbc; + else if ((c = mb.mhbc) < 0) + md = (c + 1) * bs - mb.mhbr - 1; + else + md = (c - 1) * bs + mb.mhbr + 1; + md += rbackp; + if (md > bsmax) + rback = md - bsr; + else if (md < bsmin) + rback = md + bsr; + else + rback = md; + rbackp = rback; + if (bs == 1 || mb.mvbc == 0) + md = mb.mvbc; + else if ((c = mb.mvbc) < 0) + md = (c + 1) * bs - mb.mvbr - 1; + else + md = (c - 1) * bs + mb.mvbr + 1; + md += dbackp; + if (md > bsmax) + dback = md - bsr; + else if (md < bsmin) + dback = md + bsr; + else + dback = md; + dbackp = dback; + if (p.flags & Mpegio->FPBV) { + rback2 = rback; + dback2 = dback; + rback <<= 1; + dback <<= 1; + ydb = rback2 + dback2 * width; + cdb = (rback2 >> 1) + (dback2 >> 1) * w2; + } else { + if (rback < 0) + rback2 = (rback + 1) >> 1; + else + rback2 = rback >> 1; + if (dback < 0) + dback2 = (dback + 1) >> 1; + else + dback2 = dback >> 1; + ydb = (rback >> 1) + (dback >> 1) * width; + cdb = (rback2 >> 1) + (dback2 >> 1) * w2; + } + } + vflags = mb.flags; + if (mb.rls != nil) { + invQ_nintra_block(mb.rls, mb.qscale); + deltambinterp(); + } else + interpmb(); + ipred = 0; + } + nextmb(); + n++; + } + } + while (n < mpi) { + interpmb(); + nextmb(); + n++; + } + return B; +} + +raisex(nil: string) +{ + raise "decode error"; +} |
