gsvvcompressor 1.2.0__cp311-cp311-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gsvvcompressor/__init__.py +13 -0
- gsvvcompressor/__main__.py +243 -0
- gsvvcompressor/combinations/__init__.py +84 -0
- gsvvcompressor/combinations/registry.py +52 -0
- gsvvcompressor/combinations/vq_xyz_1mask.py +89 -0
- gsvvcompressor/combinations/vq_xyz_1mask_zstd.py +103 -0
- gsvvcompressor/combinations/vq_xyz_draco.py +468 -0
- gsvvcompressor/combinations/vq_xyz_draco_2pass.py +156 -0
- gsvvcompressor/combinations/vq_xyz_zstd.py +106 -0
- gsvvcompressor/compress/__init__.py +5 -0
- gsvvcompressor/compress/zstd.py +144 -0
- gsvvcompressor/decoder.py +155 -0
- gsvvcompressor/deserializer.py +42 -0
- gsvvcompressor/draco/__init__.py +34 -0
- gsvvcompressor/draco/draco_decoder.exe +0 -0
- gsvvcompressor/draco/draco_encoder.exe +0 -0
- gsvvcompressor/draco/dracoreduced3dgs.cp311-win_amd64.pyd +0 -0
- gsvvcompressor/draco/interface.py +339 -0
- gsvvcompressor/draco/serialize.py +235 -0
- gsvvcompressor/draco/twopass.py +359 -0
- gsvvcompressor/encoder.py +122 -0
- gsvvcompressor/interframe/__init__.py +11 -0
- gsvvcompressor/interframe/combine.py +271 -0
- gsvvcompressor/interframe/decoder.py +99 -0
- gsvvcompressor/interframe/encoder.py +92 -0
- gsvvcompressor/interframe/interface.py +221 -0
- gsvvcompressor/interframe/twopass.py +226 -0
- gsvvcompressor/io/__init__.py +31 -0
- gsvvcompressor/io/bytes.py +103 -0
- gsvvcompressor/io/config.py +78 -0
- gsvvcompressor/io/gaussian_model.py +127 -0
- gsvvcompressor/movecameras.py +33 -0
- gsvvcompressor/payload.py +34 -0
- gsvvcompressor/serializer.py +42 -0
- gsvvcompressor/vq/__init__.py +15 -0
- gsvvcompressor/vq/interface.py +324 -0
- gsvvcompressor/vq/singlemask.py +127 -0
- gsvvcompressor/vq/twopass.py +1 -0
- gsvvcompressor/xyz/__init__.py +26 -0
- gsvvcompressor/xyz/dense.py +39 -0
- gsvvcompressor/xyz/interface.py +382 -0
- gsvvcompressor/xyz/knn.py +141 -0
- gsvvcompressor/xyz/quant.py +143 -0
- gsvvcompressor/xyz/size.py +44 -0
- gsvvcompressor/xyz/twopass.py +1 -0
- gsvvcompressor-1.2.0.dist-info/METADATA +690 -0
- gsvvcompressor-1.2.0.dist-info/RECORD +50 -0
- gsvvcompressor-1.2.0.dist-info/WHEEL +5 -0
- gsvvcompressor-1.2.0.dist-info/licenses/LICENSE +21 -0
- gsvvcompressor-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VQ + XYZ quantization + Zstd compression encoder/decoder combination.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from ..compress.zstd import ZstdSerializer, ZstdDeserializer
|
|
9
|
+
from ..interframe.combine import (
|
|
10
|
+
CombinedInterframeCodecInterface,
|
|
11
|
+
CombinedInterframeEncoderInitConfig,
|
|
12
|
+
)
|
|
13
|
+
from ..interframe.encoder import InterframeEncoder
|
|
14
|
+
from ..interframe.decoder import InterframeDecoder
|
|
15
|
+
from ..vq.interface import VQInterframeCodecInterface, VQInterframeCodecConfig
|
|
16
|
+
from ..xyz.interface import XYZQuantInterframeCodecInterface, XYZQuantInterframeCodecConfig
|
|
17
|
+
from .registry import register_encoder, register_decoder
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def VQXYZZstdEncoder(
|
|
21
|
+
vq_config: VQInterframeCodecConfig,
|
|
22
|
+
xyz_config: XYZQuantInterframeCodecConfig,
|
|
23
|
+
zstd_level: int = 7,
|
|
24
|
+
payload_device: Optional[str] = None,
|
|
25
|
+
) -> InterframeEncoder:
|
|
26
|
+
"""Create an encoder combining VQ + XYZ quantization + Zstd compression."""
|
|
27
|
+
vq_interface = VQInterframeCodecInterface()
|
|
28
|
+
xyz_interface = XYZQuantInterframeCodecInterface()
|
|
29
|
+
combined_interface = CombinedInterframeCodecInterface([xyz_interface, vq_interface])
|
|
30
|
+
combined_config = CombinedInterframeEncoderInitConfig(
|
|
31
|
+
init_configs=[xyz_config, vq_config]
|
|
32
|
+
)
|
|
33
|
+
serializer = ZstdSerializer(level=zstd_level)
|
|
34
|
+
return InterframeEncoder(
|
|
35
|
+
serializer=serializer,
|
|
36
|
+
interface=combined_interface,
|
|
37
|
+
init_config=combined_config,
|
|
38
|
+
payload_device=payload_device,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def VQXYZZstdDecoder(
|
|
43
|
+
payload_device: Optional[str] = None,
|
|
44
|
+
device: Optional[str] = None,
|
|
45
|
+
) -> InterframeDecoder:
|
|
46
|
+
"""Create a decoder for VQ + XYZ quantization + Zstd compressed data."""
|
|
47
|
+
vq_interface = VQInterframeCodecInterface()
|
|
48
|
+
xyz_interface = XYZQuantInterframeCodecInterface()
|
|
49
|
+
combined_interface = CombinedInterframeCodecInterface([xyz_interface, vq_interface])
|
|
50
|
+
deserializer = ZstdDeserializer()
|
|
51
|
+
return InterframeDecoder(
|
|
52
|
+
deserializer=deserializer,
|
|
53
|
+
interface=combined_interface,
|
|
54
|
+
payload_device=payload_device,
|
|
55
|
+
device=device,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class VQXYZZstdEncoderConfig:
|
|
61
|
+
"""Configuration for VQ + XYZ + Zstd encoder."""
|
|
62
|
+
vq: VQInterframeCodecConfig = field(default_factory=VQInterframeCodecConfig)
|
|
63
|
+
xyz: XYZQuantInterframeCodecConfig = field(default_factory=XYZQuantInterframeCodecConfig)
|
|
64
|
+
zstd_level: int = 7
|
|
65
|
+
payload_device: Optional[str] = None
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class VQXYZZstdDecoderConfig:
|
|
70
|
+
"""Configuration for VQ + XYZ + Zstd decoder."""
|
|
71
|
+
payload_device: Optional[str] = None
|
|
72
|
+
device: Optional[str] = None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def build_vqxyzzstd_encoder(config: VQXYZZstdEncoderConfig) -> InterframeEncoder:
|
|
76
|
+
"""Build encoder from configuration."""
|
|
77
|
+
return VQXYZZstdEncoder(
|
|
78
|
+
vq_config=config.vq,
|
|
79
|
+
xyz_config=config.xyz,
|
|
80
|
+
zstd_level=config.zstd_level,
|
|
81
|
+
payload_device=config.payload_device,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def build_vqxyzzstd_decoder(config: VQXYZZstdDecoderConfig) -> InterframeDecoder:
|
|
86
|
+
"""Build decoder from configuration."""
|
|
87
|
+
return VQXYZZstdDecoder(
|
|
88
|
+
payload_device=config.payload_device,
|
|
89
|
+
device=config.device,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Register
|
|
94
|
+
register_encoder(
|
|
95
|
+
"vqxyzzstd",
|
|
96
|
+
build_vqxyzzstd_encoder,
|
|
97
|
+
VQXYZZstdEncoderConfig,
|
|
98
|
+
"VQ + XYZ quantization + Zstd compression",
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
register_decoder(
|
|
102
|
+
"vqxyzzstd",
|
|
103
|
+
build_vqxyzzstd_decoder,
|
|
104
|
+
VQXYZZstdDecoderConfig,
|
|
105
|
+
"VQ + XYZ quantization + Zstd decompression",
|
|
106
|
+
)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Zstandard-based streaming serialization and deserialization.
|
|
3
|
+
|
|
4
|
+
Uses cloudpickle + length-prefix framing + zstd compression for efficient
|
|
5
|
+
streaming of Payload objects. This approach can serialize almost anything
|
|
6
|
+
including nested custom classes, torch.Tensor, and numpy.ndarray.
|
|
7
|
+
|
|
8
|
+
WARNING: cloudpickle uses pickle under the hood. Do NOT use with untrusted
|
|
9
|
+
data sources. Only use with trusted data (local files, same-process, etc.).
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import struct
|
|
13
|
+
from typing import Iterator
|
|
14
|
+
|
|
15
|
+
import cloudpickle as pickle
|
|
16
|
+
import zstandard as zstd
|
|
17
|
+
|
|
18
|
+
from ..deserializer import AbstractDeserializer
|
|
19
|
+
from ..payload import Payload
|
|
20
|
+
from ..serializer import AbstractSerializer
|
|
21
|
+
|
|
22
|
+
# 4-byte big-endian length prefix (max 4GB per object)
|
|
23
|
+
_LEN = struct.Struct(">I")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ZstdSerializer(AbstractSerializer):
|
|
27
|
+
"""
|
|
28
|
+
Streaming serializer using cloudpickle + length-prefix framing + zstd.
|
|
29
|
+
|
|
30
|
+
Each Payload is pickled, prefixed with its length, then compressed
|
|
31
|
+
incrementally using zstd streaming compression.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def __init__(self, level: int = 7):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the serializer.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
level: Zstd compression level (1-22). Default is 7.
|
|
40
|
+
"""
|
|
41
|
+
self._compressor = zstd.ZstdCompressor(level=level).compressobj()
|
|
42
|
+
|
|
43
|
+
def serialize_frame(self, payload: Payload) -> Iterator[bytes]:
|
|
44
|
+
"""
|
|
45
|
+
Serialize and compress a Payload object.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
payload: A Payload instance to serialize.
|
|
49
|
+
|
|
50
|
+
Yields:
|
|
51
|
+
Compressed byte chunks (may yield zero chunks if buffered).
|
|
52
|
+
"""
|
|
53
|
+
# Pickle the payload
|
|
54
|
+
pickled = pickle.dumps(payload, protocol=pickle.DEFAULT_PROTOCOL)
|
|
55
|
+
# Add length prefix framing
|
|
56
|
+
framed = _LEN.pack(len(pickled)) + pickled
|
|
57
|
+
# Compress incrementally
|
|
58
|
+
out = self._compressor.compress(framed)
|
|
59
|
+
if out:
|
|
60
|
+
yield out
|
|
61
|
+
|
|
62
|
+
def flush(self) -> Iterator[bytes]:
|
|
63
|
+
"""
|
|
64
|
+
Flush remaining compressed data.
|
|
65
|
+
|
|
66
|
+
Yields:
|
|
67
|
+
Final compressed byte chunks.
|
|
68
|
+
"""
|
|
69
|
+
tail = self._compressor.flush()
|
|
70
|
+
if tail:
|
|
71
|
+
yield tail
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class ZstdDeserializer(AbstractDeserializer):
|
|
75
|
+
"""
|
|
76
|
+
Streaming deserializer using zstd + length-prefix framing + cloudpickle.
|
|
77
|
+
|
|
78
|
+
Decompresses incoming bytes incrementally, buffers until a complete
|
|
79
|
+
length-prefixed frame is available, then unpickles and yields Payloads.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
def __init__(self):
|
|
83
|
+
"""Initialize the deserializer."""
|
|
84
|
+
self._decompressor = zstd.ZstdDecompressor().decompressobj()
|
|
85
|
+
self._buffer = bytearray()
|
|
86
|
+
|
|
87
|
+
def deserialize_frame(self, data: bytes) -> Iterator[Payload]:
|
|
88
|
+
"""
|
|
89
|
+
Decompress and deserialize bytes to Payload objects.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
data: Compressed bytes to deserialize.
|
|
93
|
+
|
|
94
|
+
Yields:
|
|
95
|
+
Complete Payload objects as they become available.
|
|
96
|
+
"""
|
|
97
|
+
# Decompress and add to buffer
|
|
98
|
+
decompressed = self._decompressor.decompress(data)
|
|
99
|
+
if decompressed:
|
|
100
|
+
self._buffer.extend(decompressed)
|
|
101
|
+
|
|
102
|
+
# Yield complete frames
|
|
103
|
+
yield from self._extract_payloads()
|
|
104
|
+
|
|
105
|
+
def flush(self) -> Iterator[Payload]:
|
|
106
|
+
"""
|
|
107
|
+
Flush any remaining buffered data.
|
|
108
|
+
|
|
109
|
+
Yields:
|
|
110
|
+
Any remaining Payload objects in the buffer.
|
|
111
|
+
"""
|
|
112
|
+
# Try to extract any remaining complete payloads
|
|
113
|
+
yield from self._extract_payloads()
|
|
114
|
+
|
|
115
|
+
# If there's leftover data, it's incomplete/corrupted
|
|
116
|
+
if self._buffer:
|
|
117
|
+
raise ValueError(
|
|
118
|
+
f"Incomplete data in buffer: {len(self._buffer)} bytes remaining"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
def _extract_payloads(self) -> Iterator[Payload]:
|
|
122
|
+
"""
|
|
123
|
+
Extract complete payloads from the buffer.
|
|
124
|
+
|
|
125
|
+
Yields:
|
|
126
|
+
Complete Payload objects.
|
|
127
|
+
"""
|
|
128
|
+
while True:
|
|
129
|
+
# Need at least length prefix
|
|
130
|
+
if len(self._buffer) < _LEN.size:
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
# Read length
|
|
134
|
+
(length,) = _LEN.unpack(self._buffer[: _LEN.size])
|
|
135
|
+
|
|
136
|
+
# Check if we have complete frame
|
|
137
|
+
if len(self._buffer) < _LEN.size + length:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
# Extract and unpickle payload
|
|
141
|
+
pickled = bytes(self._buffer[_LEN.size: _LEN.size + length])
|
|
142
|
+
del self._buffer[: _LEN.size + length]
|
|
143
|
+
|
|
144
|
+
yield pickle.loads(pickled)
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Iterator, Self
|
|
3
|
+
|
|
4
|
+
import torch
|
|
5
|
+
|
|
6
|
+
from gaussian_splatting import GaussianModel
|
|
7
|
+
|
|
8
|
+
from .deserializer import AbstractDeserializer
|
|
9
|
+
from .payload import Payload
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AbstractDecoder(ABC):
|
|
13
|
+
"""
|
|
14
|
+
Abstract base class for decompression algorithms.
|
|
15
|
+
|
|
16
|
+
This decoder uses a two-stage process:
|
|
17
|
+
1. Deserialize bytes to Payload objects (via the deserializer)
|
|
18
|
+
2. Unpack Payloads to frames (via `unpack`)
|
|
19
|
+
|
|
20
|
+
Subclasses must implement `unpack` and `flush_unpack`, and provide
|
|
21
|
+
a deserializer. This design separates frame unpacking logic from
|
|
22
|
+
deserialization format.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
deserializer: AbstractDeserializer,
|
|
28
|
+
payload_device: str | torch.device | None = None,
|
|
29
|
+
device: str | torch.device | None = None,
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
Initialize the decoder.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
deserializer: The deserializer to use for converting bytes to Payload.
|
|
36
|
+
payload_device: The target device for input Payloads before
|
|
37
|
+
unpacking (e.g., 'cpu', 'cuda'). If None, no device
|
|
38
|
+
transfer is performed.
|
|
39
|
+
device: The target device for output GaussianModel frames
|
|
40
|
+
(e.g., 'cpu', 'cuda'). If None, no device transfer is performed.
|
|
41
|
+
"""
|
|
42
|
+
self._deserializer = deserializer
|
|
43
|
+
self._payload_device = payload_device
|
|
44
|
+
self._device = device
|
|
45
|
+
|
|
46
|
+
def to(self, device: str | torch.device | None) -> Self:
|
|
47
|
+
"""Set the device for decoded models.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
device: The device to move models to after decoding.
|
|
51
|
+
Can be a string like "cuda" or "cpu", a torch.device, or None.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
self for method chaining.
|
|
55
|
+
"""
|
|
56
|
+
self._device = device
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
@abstractmethod
|
|
60
|
+
def unpack(self, payload: Payload) -> Iterator[GaussianModel]:
|
|
61
|
+
"""
|
|
62
|
+
Unpack frame(s) from a Payload.
|
|
63
|
+
|
|
64
|
+
This method reconstructs the original frame(s) from the Payload object.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
payload: A Payload instance to unpack.
|
|
68
|
+
|
|
69
|
+
Yields:
|
|
70
|
+
Unpacked GaussianModel instances. May yield zero, one, or multiple
|
|
71
|
+
models. When the iterator is exhausted, all frames for this payload
|
|
72
|
+
have been yielded.
|
|
73
|
+
"""
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
@abstractmethod
|
|
77
|
+
def flush_unpack(self) -> Iterator[GaussianModel]:
|
|
78
|
+
"""
|
|
79
|
+
Flush any remaining buffered frames from the unpacking stage.
|
|
80
|
+
|
|
81
|
+
This method should be called after all payloads have been unpacked
|
|
82
|
+
to ensure any remaining buffered frames are output.
|
|
83
|
+
|
|
84
|
+
Yields:
|
|
85
|
+
Remaining buffered GaussianModel instances. May yield zero, one,
|
|
86
|
+
or multiple models until all buffered data has been flushed.
|
|
87
|
+
"""
|
|
88
|
+
pass
|
|
89
|
+
|
|
90
|
+
def decode_frame(self, data: bytes) -> Iterator[GaussianModel]:
|
|
91
|
+
"""
|
|
92
|
+
Decode a single chunk of compressed data.
|
|
93
|
+
|
|
94
|
+
This method deserializes the bytes to Payloads and then unpacks
|
|
95
|
+
the original frames.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
data: A bytes object containing compressed data to decode.
|
|
99
|
+
|
|
100
|
+
Yields:
|
|
101
|
+
Decoded GaussianModel instances. May yield zero, one, or multiple
|
|
102
|
+
models. When the iterator is exhausted, all frames for this data
|
|
103
|
+
chunk have been decoded.
|
|
104
|
+
"""
|
|
105
|
+
for payload in self._deserializer.deserialize_frame(data):
|
|
106
|
+
if self._payload_device is not None:
|
|
107
|
+
payload = payload.to(self._payload_device)
|
|
108
|
+
for model in self.unpack(payload):
|
|
109
|
+
if self._device is not None:
|
|
110
|
+
model.to(self._device)
|
|
111
|
+
yield model
|
|
112
|
+
|
|
113
|
+
def flush(self) -> Iterator[GaussianModel]:
|
|
114
|
+
"""
|
|
115
|
+
Flush any remaining buffered data from both deserialization and unpacking.
|
|
116
|
+
|
|
117
|
+
This method should be called after all data has been decoded
|
|
118
|
+
to ensure any remaining buffered frames are output.
|
|
119
|
+
|
|
120
|
+
Yields:
|
|
121
|
+
Remaining buffered GaussianModel instances. May yield zero, one,
|
|
122
|
+
or multiple models until all buffered data has been flushed.
|
|
123
|
+
"""
|
|
124
|
+
# Flush deserialization stage and unpack any remaining payloads
|
|
125
|
+
for payload in self._deserializer.flush():
|
|
126
|
+
if self._payload_device is not None:
|
|
127
|
+
payload = payload.to(self._payload_device)
|
|
128
|
+
for model in self.unpack(payload):
|
|
129
|
+
if self._device is not None:
|
|
130
|
+
model.to(self._device)
|
|
131
|
+
yield model
|
|
132
|
+
|
|
133
|
+
# Flush unpacking stage
|
|
134
|
+
for model in self.flush_unpack():
|
|
135
|
+
if self._device is not None:
|
|
136
|
+
model.to(self._device)
|
|
137
|
+
yield model
|
|
138
|
+
|
|
139
|
+
def decode_stream(self, stream: Iterator[bytes]) -> Iterator[GaussianModel]:
|
|
140
|
+
"""
|
|
141
|
+
Decode a stream of compressed byte chunks into GaussianModel frames.
|
|
142
|
+
|
|
143
|
+
This method processes each chunk, deserializing and unpacking frames.
|
|
144
|
+
It handles the flush logic for both deserialization and unpacking stages.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
stream: An iterator that yields bytes objects to decode.
|
|
148
|
+
|
|
149
|
+
Yields:
|
|
150
|
+
Decoded GaussianModel instances for each processed chunk or flush.
|
|
151
|
+
"""
|
|
152
|
+
for data in stream:
|
|
153
|
+
yield from self.decode_frame(data)
|
|
154
|
+
|
|
155
|
+
yield from self.flush()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Iterator
|
|
3
|
+
|
|
4
|
+
from .payload import Payload
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AbstractDeserializer(ABC):
|
|
8
|
+
"""
|
|
9
|
+
Abstract base class for deserializing bytes to Payload objects.
|
|
10
|
+
|
|
11
|
+
Subclasses must implement `deserialize_frame` and `flush` methods to define
|
|
12
|
+
the specific deserialization logic for byte sequences into Payload.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def deserialize_frame(self, data: bytes) -> Iterator[Payload]:
|
|
17
|
+
"""
|
|
18
|
+
Deserialize a chunk of bytes to Payload objects.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
data: A bytes object containing serialized data to deserialize.
|
|
22
|
+
|
|
23
|
+
Yields:
|
|
24
|
+
Deserialized Payload instances. May yield zero, one, or multiple
|
|
25
|
+
payloads depending on available data. When the iterator is exhausted,
|
|
26
|
+
all complete payloads from this data chunk have been yielded.
|
|
27
|
+
"""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def flush(self) -> Iterator[Payload]:
|
|
32
|
+
"""
|
|
33
|
+
Flush any remaining buffered data.
|
|
34
|
+
|
|
35
|
+
This method should be called after all data has been deserialized
|
|
36
|
+
to ensure any remaining buffered payloads are output.
|
|
37
|
+
|
|
38
|
+
Yields:
|
|
39
|
+
Remaining buffered Payload instances. May yield zero, one, or
|
|
40
|
+
multiple payloads until all buffered data has been flushed.
|
|
41
|
+
"""
|
|
42
|
+
pass
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Draco-based compression for reduced 3DGS data.
|
|
3
|
+
|
|
4
|
+
This module provides:
|
|
5
|
+
- DracoPayload: Payload structure for Draco-compatible data
|
|
6
|
+
- TwoPassDracoPayload: DracoPayload with num_points field for two-pass serialization
|
|
7
|
+
- DracoInterframeCodecTranscodingInterface: Abstract interface for payload transcoding
|
|
8
|
+
- DracoInterframeCodecInterface: Wrapper codec that transcodes to/from DracoPayload
|
|
9
|
+
- DracoSerializer/DracoDeserializer: Streaming serialization using Draco encoding
|
|
10
|
+
- TwoPassDracoSerializer/TwoPassDracoDeserializer: Two-pass serialization for batched compression
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from .interface import (
|
|
14
|
+
DracoInterframeCodecInterface,
|
|
15
|
+
DracoInterframeCodecTranscodingInterface,
|
|
16
|
+
DracoPayload,
|
|
17
|
+
)
|
|
18
|
+
from .serialize import DracoDeserializer, DracoSerializer
|
|
19
|
+
from .twopass import (
|
|
20
|
+
TwoPassDracoDeserializer,
|
|
21
|
+
TwoPassDracoPayload,
|
|
22
|
+
TwoPassDracoSerializer,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"DracoPayload",
|
|
27
|
+
"TwoPassDracoPayload",
|
|
28
|
+
"DracoInterframeCodecTranscodingInterface",
|
|
29
|
+
"DracoInterframeCodecInterface",
|
|
30
|
+
"DracoSerializer",
|
|
31
|
+
"DracoDeserializer",
|
|
32
|
+
"TwoPassDracoSerializer",
|
|
33
|
+
"TwoPassDracoDeserializer",
|
|
34
|
+
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|