diff options
Diffstat (limited to 'appl/wm/mpeg/mpegio.b')
| -rw-r--r-- | appl/wm/mpeg/mpegio.b | 870 |
1 files changed, 870 insertions, 0 deletions
diff --git a/appl/wm/mpeg/mpegio.b b/appl/wm/mpeg/mpegio.b new file mode 100644 index 00000000..3206776b --- /dev/null +++ b/appl/wm/mpeg/mpegio.b @@ -0,0 +1,870 @@ +implement Mpegio; + +# +# MPEG ISO 11172 IO module. +# + +include "sys.m"; +include "mpegio.m"; + +sys: Sys; + +init() +{ + sys = load Sys Sys->PATH; +} + +raisex(s: string) +{ + raise MEXCEPT + s; +} + +prepare(fd: ref Sys->FD, name: string): ref Mpegi +{ + m := ref Mpegi; + m.fd = fd; + m.name = name; + m.seek = 0; + m.looked = 0; + m.index = 0; + m.size = 0; + m.buff = array[MBSZ] of byte; + return m; +} + +Mpegi.startsys(m: self ref Mpegi) +{ + # 2.4.3.2 + m.xnextsc(PACK_SC); + m.packhdr(); + m.xnextsc(SYSHD_SC); + m.syssz = m.getw(); + m.boundmr = m.get22("boundmr"); + m.syspar = m.getw(); + if ((m.syspar & 16r20) == 0 || m.getb() != 16rFF) + m.fmterr("syspar"); + t := m.syssz - 6; + if (t <= 0 || (t % 3) != 0) + m.fmterr("syssz"); + t /= 3; + m.nstream = t; + m.streams = array[t] of Stream; + for (i := 0; i < t; i++) { + v := m.getb(); + if ((v & 16r80) == 0) + m.fmterr("streamid"); + w := m.getb(); + if ((w & 16rC0) != 16rC0) + m.fmterr("stream mark"); + m.streams[i] = (byte v, byte ((w >> 5) & 1), ((w & 16r1F) << 8) | m.getb(), nil); + } +} + +Mpegi.packetcp(m: self ref Mpegi): int +{ + while ((c := m.nextsc()) != STREAM_EC) { + case c { + PACK_SC => + m.packhdr(); + SYSHD_SC => + m.syshdr(); + * => + if (c < STREAM_BASE) + m.fmterr(sys->sprint("stream code %x", c)); + # 2.4.3.3 + l := m.getw(); + fd := m.getfd(c); + if (fd != nil) { + if (c != PRIVSTREAM2) + l -= m.stamps(); + if (m.log != nil) + sys->fprint(m.log, "%x %d %d\n", c & 16rFF, m.tell(), l); + m.cpn(fd, l); + } else + m.skipn(l); + return 1; + } + } + return 0; +} + +Mpegi.getfd(m: self ref Mpegi, c: int): ref Sys->FD +{ + id := byte c; + n := m.nstream; + for (i := 0; i < n; i++) { + if (m.streams[i].id == id) + return m.streams[i].fd; + } + return nil; +} + +Mpegi.packhdr(m: self ref Mpegi) +{ + # 2.4.3.2 + t := m.getb(); + if ((t & 16rF1) != 16r21) + m.fmterr("pack tag"); + m.packt0 = (t >> 1) & 7; + v := m.getb() << 22; + t = m.getb(); + if ((t & 1) == 0) + m.fmterr("packt mark 1"); + v |= ((t & ~1) << 15) | (m.getb() << 7); + t = m.getb(); + if ((t & 1) == 0) + m.fmterr("packt mark 2"); + m.packt1 = v | (t >> 1); + m.packmr = m.get22("packmr"); +} + +Mpegi.syshdr(m: self ref Mpegi) +{ + l := m.getw(); + if (l != m.syssz) + m.fmterr("syshdr size mismatch"); + m.skipn(l); +} + +Mpegi.stamps(m: self ref Mpegi): int +{ + # 2.4.3.3 + n := 1; + while ((c := m.getb()) == 16rFF) + n++; + if ((c >> 6) == 1) { + m.getb(); + c = m.getb(); + n += 2; + } + case c >> 4 { + 2 => + m.skipn(4); + n += 4; + 3 => + m.skipn(9); + n += 9; + * => + if (c != 16rF) + m.fmterr("stamps"); + } + return n; +} + +Mpegi.streaminit(m: self ref Mpegi, c: int) +{ + m.inittables(); + m.sid = c; + s := m.peeksc(); + if (s == PACK_SC) { + m.startsys(); + f := 0; + id := byte m.sid; + for (i := 0; i < m.nstream; i++) { + if (m.streams[i].id == id) { + f = 1; + break; + } + } + if (!f) + m.fmterr(sys->sprint("%x: stream not found", c)); + m.sseek(); + } else if (s == SEQUENCE_SC) { + m.sresid = -1; + m.slim = m.size; + } else + m.fmterr(sys->sprint("start code = %x", s)); + m.sbits = 0; +} + +Mpegi.sseek(m: self ref Mpegi) +{ + while ((c := m.nextsc()) != STREAM_EC) { + case c { + PACK_SC => + m.packhdr(); + SYSHD_SC => + m.syshdr(); + * => + if (c < STREAM_BASE) + m.fmterr(sys->sprint("stream code %x", c)); + # 2.4.3.3 + l := m.getw(); + if (c == m.sid) { + if (c != PRIVSTREAM2) + l -= m.stamps(); + n := m.size - m.index; + if (l <= n) { + m.slim = m.index + l; + m.sresid = 0; + } else { + m.slim = m.size; + m.sresid = l - n; + } + return; + } else + m.skipn(l); + } + } + m.fmterr("end of stream"); +} + +Mpegi.getpicture(m: self ref Mpegi, detail: int): ref Picture +{ + g := 0; + for (;;) { + case c := m.snextsc() { + SEQUENCE_SC => + m.seqhdr(); + GROUP_SC => + m.grphdr(); + g = 1; + PICTURE_SC => + p := m.picture(detail); + if (g) + p.flags |= GSTART; + return p; + SEQUENCE_EC => + return nil; + * => + m.fmterr(sys->sprint("start code %x", c)); + } + } +} + +Mpegi.seqhdr(m: self ref Mpegi) +{ + # 2.4.2.3 + c := m.sgetb(); + d := m.sgetb(); + m.width = (c << 4) | (d >> 4); + m.height = ((d & 16rF) << 8) | m.sgetb(); + c = m.sgetb(); + m.aspect = c >> 4; + m.frames = c & 16rF; + m.rate = m.sgetn(18); + m.smarker(); + m.vbv = m.sgetn(10); + m.flags = 0; + if (m.sgetn(1)) + m.flags |= CONSTRAINED; + if (m.sgetn(1)) + m.intra = m.getquant(); + if (m.sgetn(1)) + m.nintra = m.getquant(); + if (m.speeksc() == EXTENSION_SC) + m.sseeksc(); + if (m.speeksc() == USER_SC) + m.sseeksc(); +} + +Mpegi.grphdr(m: self ref Mpegi) +{ + # 2.4.2.4 + v := m.sgetb() << 17; + v |= m.sgetb() << 9; + v |= m.sgetb() << 1; + c := m.sgetb(); + m.smpte = v | (c >> 7); + if (c & (1 << 6)) + m.flags |= CLOSED; + else + m.flags &= ~CLOSED; + if (c & (1 << 5)) + m.flags |= BROKEN; + else + m.flags &= ~BROKEN; + if (m.speeksc() == EXTENSION_SC) + m.sseeksc(); + if (m.speeksc() == USER_SC) + m.sseeksc(); +} + +Mpegi.getquant(m: self ref Mpegi): array of int +{ + a := array[64] of int; + for (i := 0; i < 64; i++) + a[i] = m.sgetn(8); + return a; +} + +Mpegi.picture(m: self ref Mpegi, detail: int): ref Picture +{ + # 2.4.2.5 + p := ref Picture; + p.temporal = m.sgetn(10); + p.ptype = m.sgetn(3); + p.vbvdelay = m.sgetn(16); + p.flags = 0; + if (p.ptype == PPIC || p.ptype == BPIC) { + if (m.sgetn(1)) + p.flags |= FPFV; + p.forwfc = m.sgetn(3); + if (p.forwfc == 0) + m.fmterr("forwfc"); + p.forwfc--; + if (p.ptype == BPIC) { + if (m.sgetn(1)) + p.flags |= FPBV; + p.backfc = m.sgetn(3); + if (p.backfc == 0) + m.fmterr("backfc"); + p.backfc--; + } else + p.backfc = 0; + } else { + p.forwfc = 0; + p.backfc = 0; + } + while (m.sgetn(1)) + m.sgetn(8); + if (m.speeksc() == EXTENSION_SC) + m.sseeksc(); + if (m.speeksc() == USER_SC) + m.sseeksc(); + p.seek = m.tell() - 3; + if (m.sresid < 0) + p.eos = -1; + else + p.eos = m.seek - m.size + m.slim + m.sresid; + if (detail) + m.detail(p); + else + m.skipdetail(); + return p; +} + +Mpegi.detail(m: self ref Mpegi, p: ref Picture) +{ + l: list of ref Slice; + p.addr = -1; + while ((c := m.speeksc()) >= SLICE1_SC && c <= SLICEN_SC) + l = m.slice(p) :: l; + if (l == nil) + m.fmterr("slice sc"); + n := len l; + a := array[n] of ref Slice; + while (--n >= 0) { + a[n] = hd l; + l = tl l; + } + p.slices = a; +} + +Mpegi.skipdetail(m: self ref Mpegi) +{ + while ((c := m.speeksc()) >= SLICE1_SC && c <= SLICEN_SC) { + m.looked = 0; + m.sseeksc(); + } +} + +ESC, EOB, C0, C1, C2, C3, C4, C5, C6, C7: con -(iota + 1); + +include "mai.tab"; +include "mbi.tab"; +include "mbp.tab"; +include "mbb.tab"; +include "motion.tab"; +include "cbp.tab"; +include "cdc.tab"; +include "ydc.tab"; +include "rl0f.tab"; +include "rl0n.tab"; +include "c0.tab"; +include "c1.tab"; +include "c2.tab"; +include "c3.tab"; +include "c4.tab"; +include "c5.tab"; +include "c6.tab"; +include "c7.tab"; + +mbif := array[] of { + MB_I, + MB_I | MB_Q, +}; + +mbpf := array[] of { + MB_MF, + MB_P, + MB_P | MB_Q, + MB_P | MB_MF, + MB_P | MB_MF | MB_Q, + MB_I, + MB_I | MB_Q, +}; + +mbbf := array[] of { + MB_MF, + MB_MB, + MB_MB | MB_MF, + MB_P | MB_MF, + MB_P | MB_MF | MB_Q, + MB_P | MB_MB, + MB_P | MB_MB | MB_Q, + MB_P | MB_MB | MB_MF, + MB_P | MB_MB | MB_MF | MB_Q, + MB_I, + MB_I | MB_Q, +}; + +c_bits := array[] of { + c1_bits, + c2_bits, + c3_bits, + c4_bits, + c5_bits, + c6_bits, + c7_bits, +}; + +c_tables: array of array of Pair; + +patcode := array[] of { + 1<<5, 1<<4, 1<<3, 1<<2, 1<<1, 1<<0, +}; + +Mpegi.inittables() +{ + if (c_tables == nil) { + c_tables = array[] of { + c1_table, + c2_table, + c3_table, + c4_table, + c5_table, + c6_table, + c7_table, + }; + } +} + +Mpegi.slice(m: self ref Mpegi, p: ref Picture): ref Slice +{ + m.snextsc(); + s := ref Slice; + q := m.sgetn(5); + while (m.sgetn(1)) + m.sgetn(8); + x := p.addr; + l: list of ref MacroBlock; + while (m.speekn(23) != 0) { + while (m.speekn(11) == 16rF) + m.sbits -= 11; + while (m.speekn(11) == 16r8) { + x += 33; + m.sbits -= 11; + } + i := m.svlc(mai_table, mai_bits, "mai"); + x += i; + b := ref MacroBlock; + b.addr = x; + case p.ptype { + IPIC => + b.flags = mbif[m.svlc(mbi_table, mbi_bits, "mbi")]; + PPIC => + b.flags = mbpf[m.svlc(mbp_table, mbp_bits, "mbp")]; + BPIC => + b.flags = mbbf[m.svlc(mbb_table, mbb_bits, "mbb")]; + DPIC => + if (!m.sgetn(1)) + m.fmterr("mbd flags"); + b.flags = MB_I; + * => + m.fmterr("ptype"); + } + if (b.flags & MB_Q) + q = m.sgetn(5); + b.qscale = q; + if (b.flags & MB_MF) { + i = m.svlc(motion_table, motion_bits, "mhfc"); + b.mhfc = i; + if (i != 0 && p.forwfc != 0) + b.mhfr = m.sgetn(p.forwfc); + i = m.svlc(motion_table, motion_bits, "mvfc"); + b.mvfc = i; + if (i != 0 && p.forwfc != 0) + b.mvfr = m.sgetn(p.forwfc); + } + if (b.flags & MB_MB) { + i = m.svlc(motion_table, motion_bits, "mhbc"); + b.mhbc = i; + if (i != 0 && p.backfc != 0) + b.mhbr = m.sgetn(p.backfc); + i = m.svlc(motion_table, motion_bits, "mvbc"); + b.mvbc = i; + if (i != 0 && p.backfc != 0) + b.mvbr = m.sgetn(p.backfc); + } + if (b.flags & MB_I) + i = 16r3F; + else if (b.flags & MB_P) + i = m.svlc(cbp_table, cbp_bits, "cbp"); + else + i = 0; + b.pcode = i; + if (i != 0) { + b.rls = array[6] of array of Pair; + for (j := 0; j < 6; j++) { + if (i & patcode[j]) { + rl: list of Pair; + R, L: int; + if (b.flags & MB_I) { + if (j < 4) + L = m.svlc(ydc_table, ydc_bits, "ydc"); + else + L = m.svlc(cdc_table, cdc_bits, "cdc"); + if (L != 0) + L = m.sdiffn(L); + rl = (0, L) :: nil; + } else + rl = m.sdct(rl0f_table, "rl0f") :: nil; + if (p.ptype != DPIC) { + for (;;) { + (R, L) = m.sdct(rl0n_table, "rl0n"); + if (R == EOB) + break; + rl = (R, L) :: rl; + } + } + mn := len rl; + ma := array[mn] of Pair; + while (--mn >= 0) { + ma[mn] = hd rl; + rl = tl rl; + } + b.rls[j] = ma; + } + } + } + l = b :: l; + } + p.addr = x; + if (l == nil) + m.fmterr("macroblock"); + n := len l; + a := array[n] of ref MacroBlock; + while (--n >= 0) { + a[n] = hd l; + l = tl l; + } + s.blocks = a; + return s; +} + +Mpegi.cpn(m: self ref Mpegi, fd: ref Sys->FD, n: int) +{ + for (;;) { + r := m.size - m.index; + if (r >= n) { + if (sys->write(fd, m.buff[m.index:], n) < 0) + raisex(X_WRITE); + m.index += n; + return; + } + if (sys->write(fd, m.buff[m.index:], r) < 0) + raisex(X_WRITE); + m.fill(); + n -= r; + } +} + +Mpegi.fill(m: self ref Mpegi) +{ + n := sys->read(m.fd, m.buff, MBSZ); + if (n < 0) { + m.error = sys->sprint("%r"); + raisex(X_READ); + } + if (n == 0) + raisex(X_EOF); + m.seek += n; + m.index = 0; + m.size = n; +} + +Mpegi.tell(m: self ref Mpegi): int +{ + return m.seek - m.size + m.index; +} + +Mpegi.skipn(m: self ref Mpegi, n: int) +{ + for (;;) { + r := m.size - m.index; + if (r >= n) { + m.index += n; + return; + } + n -= r; + m.fill(); + } +} + +Mpegi.getb(m: self ref Mpegi): int +{ + if (m.index == m.size) + m.fill(); + return int m.buff[m.index++]; +} + +Mpegi.getw(m: self ref Mpegi): int +{ + t := m.getb(); + return (t << 8) | m.getb(); +} + +Mpegi.get22(m: self ref Mpegi, s: string): int +{ + u := m.getb(); + if ((u & 16r80) == 0) + m.fmterr(s + " mark 0"); + v := m.getb(); + w := m.getb(); + if ((w & 1) == 0) + m.fmterr(s + " mark 1"); + return ((u & 16r7F) << 15) | (v << 7) | (w >> 1); +} + +Mpegi.getsc(m: self ref Mpegi): int +{ + if (m.getb() != 0 || m.getb() != 0) + m.fmterr("start code 0s"); + while ((c := m.getb()) == 0) + ; + if (c != 1) + m.fmterr("start code 1"); + return 16r100 | m.getb(); +} + +Mpegi.nextsc(m: self ref Mpegi): int +{ + if (m.looked) { + m.looked = 0; + return m.value; + } else + return m.getsc(); +} + +Mpegi.peeksc(m: self ref Mpegi): int +{ + if (!m.looked) { + m.value = m.getsc(); + m.looked = 1; + } + return m.value; +} + +Mpegi.xnextsc(m: self ref Mpegi, x: int) +{ + c := m.nextsc(); + if (c != x) + m.fmterr(sys->sprint("startcode %x, got %x", x, c)); +} + +Mpegi.sfill(m: self ref Mpegi) +{ + r := m.sresid; + if (r < 0) { + m.fill(); + m.slim = m.size; + } else if (r > 0) { + m.fill(); + if (r <= m.size) { + m.slim = r; + m.sresid = 0; + } else { + m.slim = m.size; + m.sresid = r - m.size; + } + } else + m.sseek(); +} + +bits := array[] of { + 0, + 16r1, 16r3, 16r7, 16rF, + 16r1F, 16r3F, 16r7F, 16rFF, + 16r1FF, 16r3FF, 16r7FF, 16rFFF, + 16r1FFF, 16r3FFF, 16r7FFF, 16rFFFF, + 16r1FFFF, 16r3FFFF, 16r7FFFF, 16rFFFFF, + 16r1FFFFF, 16r3FFFFF, 16r7FFFFF, 16rFFFFFF, + 16r1FFFFFF, 16r3FFFFFF, 16r7FFFFFF, 16rFFFFFFF, + 16r1FFFFFFF, 16r3FFFFFFF, 16r7FFFFFFF, int 16rFFFFFFFF, +}; + +sign := array[] of { + 0, + 16r1, 16r2, 16r4, 16r8, + 16r10, 16r20, 16r40, 16r80, +}; + +Mpegi.sgetn(m: self ref Mpegi, n: int): int +{ + b := m.sbits; + v := m.svalue; + if (b < n) { + do { + v = (v << 8) | m.sgetb(); + b += 8; + } while (b < n); + m.svalue = v; + } + b -= n; + m.sbits = b; + return (v >> b) & bits[n]; +} + +Mpegi.sdiffn(m: self ref Mpegi, n: int): int +{ + i := m.sgetn(n); + if (i & sign[n]) + return i; + else + return i - bits[n]; +} + +Mpegi.speekn(m: self ref Mpegi, n: int): int +{ + b := m.sbits; + v := m.svalue; + if (b < n) { + do { + v = (v << 8) | m.sgetb(); + b += 8; + } while (b < n); + m.sbits = b; + m.svalue = v; + } + return (v >> (b - n)) & bits[n]; +} + +Mpegi.sgetb(m: self ref Mpegi): int +{ + if (m.index == m.slim) + m.sfill(); + return int m.buff[m.index++]; +} + +Mpegi.smarker(m: self ref Mpegi) +{ + if (!m.sgetn(1)) + m.fmterr("marker"); +} + +Mpegi.sgetsc(m: self ref Mpegi): int +{ + b := m.sbits; + if (b >= 8) { + if (b >= 16) { + if (b >= 24) { + case m.svalue & 16rFFFFFF { + 0 => + break; + 1 => + m.sbits = 0; + return 16r100 | m.sgetb(); + * => + m.fmterr("start code 0s - 3"); + } + } else if ((m.svalue & 16rFFFF) != 0) + m.fmterr("start code 0s - 2"); + } else if ((m.svalue & 16rFF) != 0 || m.sgetb() != 0) + m.fmterr("start code 0s - 1"); + } else if (m.sgetb() != 0 || m.sgetb() != 0) + m.fmterr("start code 0s"); + m.sbits = 0; + while ((c := m.sgetb()) == 0) + ; + if (c != 1) + m.fmterr("start code 1"); + return 16r100 | m.sgetb(); +} + +Mpegi.snextsc(m: self ref Mpegi): int +{ + if (m.looked) { + m.looked = 0; + return m.value; + } else + return m.sgetsc(); +} + +Mpegi.speeksc(m: self ref Mpegi): int +{ + if (!m.looked) { + m.value = m.sgetsc(); + m.looked = 1; + } + return m.value; +} + +Mpegi.sseeksc(m: self ref Mpegi) +{ + n := 0; + for (;;) { + case m.sgetb() { + 0 => + n++; + 1 => + if (n >= 2) { + m.value = 16r100 | m.sgetb(); + m.looked = 1; + return; + } + n = 0; + * => + n = 0; + } + } +} + +Mpegi.svlc(m: self ref Mpegi, a: array of Pair, n: int, s: string): int +{ + (b, v) := a[m.speekn(n)]; + if (v == UNDEF) + m.fmterr(s + " vlc"); + m.sbits -= b; + return v; +} + +Mpegi.sdct(m: self ref Mpegi, a: array of Triple, s: string): Pair +{ + (b, l, r) := a[m.speekn(rl0f_bits)]; + m.sbits -= b; + if (r < 0) { + case r { + EOB => + break; + ESC => + r = m.sgetn(6); + l = m.sgetn(8); + if (l == 0) { + l = m.sgetn(8); + if (l < 128) + m.fmterr(s + " esc +7"); + } else if (l == 128) { + l = m.sgetn(8) - 256; + if (l > -128) + m.fmterr(s + " esc -7"); + } else + l = (l << 24) >> 24; + C0 => + (b, l, r) = c0_table[m.speekn(c0_bits)]; + if (r == UNDEF) + m.fmterr(s + " c0 vlc"); + m.sbits -= b; + * => + r = C1 - r; + (l, r) = c_tables[r][m.sgetn(c_bits[r])]; + } + } + return (r, l); +} + +Mpegi.fmterr(m: self ref Mpegi, s: string) +{ + m.error = s; + raisex(X_FORMAT); +} |
