feat(iphone): python topology codec
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
"""AVLiveWire topology payload codec.
|
||||
|
||||
Mirror of the Swift `TopologyPayload` (shared/AVLiveWire). Layout
|
||||
(big-endian): u16 jointCount; per joint [u8 nameLen + utf8 name];
|
||||
then per joint i16 parent (-1 = root).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
|
||||
|
||||
def encode_topology(names: list[str], parents: list[int]) -> bytes:
|
||||
out = bytearray()
|
||||
out += struct.pack(">H", len(names))
|
||||
for nm in names:
|
||||
b = nm.encode("utf-8")[:255]
|
||||
out.append(len(b))
|
||||
out += b
|
||||
for p in parents:
|
||||
out += struct.pack(">h", p)
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def decode_topology(payload: bytes):
|
||||
"""Return (joint_names, parents) or None if malformed."""
|
||||
if len(payload) < 2:
|
||||
return None
|
||||
n = struct.unpack(">H", payload[:2])[0]
|
||||
o = 2
|
||||
names: list[str] = []
|
||||
for _ in range(n):
|
||||
if o >= len(payload):
|
||||
return None
|
||||
ln = payload[o]
|
||||
o += 1
|
||||
if o + ln > len(payload):
|
||||
return None
|
||||
names.append(payload[o:o + ln].decode("utf-8", "replace"))
|
||||
o += ln
|
||||
if o + n * 2 > len(payload):
|
||||
return None
|
||||
parents = list(struct.unpack(">" + "h" * n, payload[o:o + n * 2]))
|
||||
return names, parents
|
||||
@@ -0,0 +1,28 @@
|
||||
"""AVLiveWire topology payload round-trip (mirror of Swift TopologyPayload)."""
|
||||
from data_only_viz.arkit_topology import decode_topology, encode_topology
|
||||
|
||||
|
||||
def test_round_trip():
|
||||
names = ["root_joint", "hips_joint", "left_arm_joint"]
|
||||
parents = [-1, 0, 1]
|
||||
payload = encode_topology(names, parents)
|
||||
out = decode_topology(payload)
|
||||
assert out is not None
|
||||
got_names, got_parents = out
|
||||
assert got_names == names
|
||||
assert got_parents == parents
|
||||
|
||||
|
||||
def test_empty():
|
||||
payload = encode_topology([], [])
|
||||
out = decode_topology(payload)
|
||||
assert out == ([], [])
|
||||
|
||||
|
||||
def test_rejects_truncated():
|
||||
# Claims 3 joints, provides no body.
|
||||
assert decode_topology(b"\x00\x03") is None
|
||||
|
||||
|
||||
def test_rejects_too_short():
|
||||
assert decode_topology(b"\x00") is None
|
||||
Reference in New Issue
Block a user