Initial commit
This commit is contained in:
72
ackit/ogg.py
Normal file
72
ackit/ogg.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""Minimal Ogg page reader/writer."""
|
||||
import struct
|
||||
|
||||
|
||||
def _crc_table():
|
||||
t = []
|
||||
for i in range(256):
|
||||
r = i << 24
|
||||
for _ in range(8):
|
||||
r = ((r << 1) ^ 0x04C11DB7) if r & 0x80000000 else (r << 1)
|
||||
t.append(r & 0xFFFFFFFF)
|
||||
return t
|
||||
|
||||
|
||||
_T = _crc_table()
|
||||
|
||||
|
||||
def ogg_crc(b: bytes) -> int:
|
||||
c = 0
|
||||
for x in b:
|
||||
c = ((c << 8) & 0xFFFFFFFF) ^ _T[((c >> 24) & 0xFF) ^ x]
|
||||
return c
|
||||
|
||||
|
||||
def read_packets(b: bytes):
|
||||
"""Return list of (packet_bytes, granule_of_page_if_packet_ends_page_else_None)."""
|
||||
pos = 0
|
||||
out = []
|
||||
cur = b""
|
||||
while pos + 27 <= len(b):
|
||||
if b[pos:pos + 4] != b"OggS":
|
||||
raise ValueError("lost Ogg sync at %d" % pos)
|
||||
htype, gran, serial, seq, crc, nseg = struct.unpack_from("<BqIIIB", b, pos + 5)
|
||||
segs = b[pos + 27: pos + 27 + nseg]
|
||||
p = pos + 27 + nseg
|
||||
ends = []
|
||||
for s in segs:
|
||||
cur += b[p:p + s]
|
||||
p += s
|
||||
if s < 255:
|
||||
ends.append(cur)
|
||||
cur = b""
|
||||
for i, pk in enumerate(ends):
|
||||
out.append((pk, gran if i == len(ends) - 1 else None))
|
||||
pos = p
|
||||
return out
|
||||
|
||||
|
||||
class OggWriter:
|
||||
def __init__(self, serial=0x41434B54):
|
||||
self.serial = serial
|
||||
self.seq = 0
|
||||
self.out = bytearray()
|
||||
|
||||
def page(self, packets, granule, bos=False, eos=False):
|
||||
segs = bytearray()
|
||||
body = bytearray()
|
||||
for pk in packets:
|
||||
n = len(pk)
|
||||
while n >= 255:
|
||||
segs.append(255); n -= 255
|
||||
segs.append(n)
|
||||
body += pk
|
||||
hdr = struct.pack("<4sBBqIIIB", b"OggS", 0, (2 if bos else 0) | (4 if eos else 0),
|
||||
granule, self.serial, self.seq, 0, len(segs)) + bytes(segs)
|
||||
page = bytearray(hdr + body)
|
||||
struct.pack_into("<I", page, 22, ogg_crc(page))
|
||||
self.out += page
|
||||
self.seq += 1
|
||||
|
||||
def bytes(self):
|
||||
return bytes(self.out)
|
||||
Reference in New Issue
Block a user