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.
Files changed (50) hide show
  1. gsvvcompressor/__init__.py +13 -0
  2. gsvvcompressor/__main__.py +243 -0
  3. gsvvcompressor/combinations/__init__.py +84 -0
  4. gsvvcompressor/combinations/registry.py +52 -0
  5. gsvvcompressor/combinations/vq_xyz_1mask.py +89 -0
  6. gsvvcompressor/combinations/vq_xyz_1mask_zstd.py +103 -0
  7. gsvvcompressor/combinations/vq_xyz_draco.py +468 -0
  8. gsvvcompressor/combinations/vq_xyz_draco_2pass.py +156 -0
  9. gsvvcompressor/combinations/vq_xyz_zstd.py +106 -0
  10. gsvvcompressor/compress/__init__.py +5 -0
  11. gsvvcompressor/compress/zstd.py +144 -0
  12. gsvvcompressor/decoder.py +155 -0
  13. gsvvcompressor/deserializer.py +42 -0
  14. gsvvcompressor/draco/__init__.py +34 -0
  15. gsvvcompressor/draco/draco_decoder.exe +0 -0
  16. gsvvcompressor/draco/draco_encoder.exe +0 -0
  17. gsvvcompressor/draco/dracoreduced3dgs.cp311-win_amd64.pyd +0 -0
  18. gsvvcompressor/draco/interface.py +339 -0
  19. gsvvcompressor/draco/serialize.py +235 -0
  20. gsvvcompressor/draco/twopass.py +359 -0
  21. gsvvcompressor/encoder.py +122 -0
  22. gsvvcompressor/interframe/__init__.py +11 -0
  23. gsvvcompressor/interframe/combine.py +271 -0
  24. gsvvcompressor/interframe/decoder.py +99 -0
  25. gsvvcompressor/interframe/encoder.py +92 -0
  26. gsvvcompressor/interframe/interface.py +221 -0
  27. gsvvcompressor/interframe/twopass.py +226 -0
  28. gsvvcompressor/io/__init__.py +31 -0
  29. gsvvcompressor/io/bytes.py +103 -0
  30. gsvvcompressor/io/config.py +78 -0
  31. gsvvcompressor/io/gaussian_model.py +127 -0
  32. gsvvcompressor/movecameras.py +33 -0
  33. gsvvcompressor/payload.py +34 -0
  34. gsvvcompressor/serializer.py +42 -0
  35. gsvvcompressor/vq/__init__.py +15 -0
  36. gsvvcompressor/vq/interface.py +324 -0
  37. gsvvcompressor/vq/singlemask.py +127 -0
  38. gsvvcompressor/vq/twopass.py +1 -0
  39. gsvvcompressor/xyz/__init__.py +26 -0
  40. gsvvcompressor/xyz/dense.py +39 -0
  41. gsvvcompressor/xyz/interface.py +382 -0
  42. gsvvcompressor/xyz/knn.py +141 -0
  43. gsvvcompressor/xyz/quant.py +143 -0
  44. gsvvcompressor/xyz/size.py +44 -0
  45. gsvvcompressor/xyz/twopass.py +1 -0
  46. gsvvcompressor-1.2.0.dist-info/METADATA +690 -0
  47. gsvvcompressor-1.2.0.dist-info/RECORD +50 -0
  48. gsvvcompressor-1.2.0.dist-info/WHEEL +5 -0
  49. gsvvcompressor-1.2.0.dist-info/licenses/LICENSE +21 -0
  50. gsvvcompressor-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,13 @@
1
+ from .decoder import AbstractDecoder
2
+ from .deserializer import AbstractDeserializer
3
+ from .encoder import AbstractEncoder
4
+ from .payload import Payload
5
+ from .serializer import AbstractSerializer
6
+
7
+ __all__ = [
8
+ "Payload",
9
+ "AbstractEncoder",
10
+ "AbstractDecoder",
11
+ "AbstractSerializer",
12
+ "AbstractDeserializer",
13
+ ]
@@ -0,0 +1,243 @@
1
+ """
2
+ Command-line interface for gsvvcompressor.
3
+
4
+ This module provides encode and decode subcommands for each registered
5
+ encoder/decoder combination.
6
+
7
+ Usage:
8
+ python -m gsvvcompressor encode <codec_name> [options]
9
+ python -m gsvvcompressor decode <codec_name> [options]
10
+
11
+ Example:
12
+ python -m gsvvcompressor encode vqxyzzstd \
13
+ input.first_frame_path=data/frame_0000.ply \
14
+ input.subsequent_format="data/frame_{:04d}.ply" \
15
+ output.path=compressed.bin
16
+
17
+ python -m gsvvcompressor decode vqxyzzstd \
18
+ input.path=compressed.bin \
19
+ output.first_frame_path=decoded/frame_0000.ply \
20
+ output.subsequent_format="decoded/frame_{:04d}.ply"
21
+
22
+ Hydra options:
23
+ --help Show configuration schema
24
+ --cfg job Show resolved configuration
25
+ --info config Show config search path
26
+ """
27
+
28
+ import logging
29
+ import sys
30
+ from dataclasses import field, make_dataclass
31
+ from typing import Iterable, Iterator, List, Type, TypeVar
32
+
33
+ import hydra
34
+ from hydra.core.config_store import ConfigStore
35
+ from hydra.core.global_hydra import GlobalHydra
36
+ from omegaconf import DictConfig
37
+
38
+ from .combinations import ENCODERS, DECODERS
39
+ from .io import (
40
+ FrameReaderConfig,
41
+ FrameWriterConfig,
42
+ BytesReaderConfig,
43
+ BytesWriterConfig,
44
+ build_frame_reader,
45
+ build_frame_writer,
46
+ build_bytes_reader,
47
+ build_bytes_writer,
48
+ )
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ # =============================================================================
54
+ # Progress Logging Utilities
55
+ # =============================================================================
56
+
57
+ def iter_with_progress(iterable: Iterator, desc: str) -> Iterator:
58
+ """Wrap an iterable to log progress for each item."""
59
+ for i, item in enumerate(iterable):
60
+ logger.info(f"{desc} {i}")
61
+ yield item
62
+ logger.info(f"{desc} finished")
63
+
64
+
65
+ def format_size(size: int) -> str:
66
+ """Format byte size to human-readable string (KB, MB, GB, etc.)."""
67
+ for unit in ("B", "KB", "MB", "GB", "TB"):
68
+ if abs(size) < 1024:
69
+ return f"{size:.2f} {unit}"
70
+ size /= 1024
71
+ return f"{size:.2f} PB"
72
+
73
+
74
+ def iter_with_size_logging(iterable: Iterator[bytes], desc: str) -> Iterator[bytes]:
75
+ """Wrap a bytes iterable to log the size of each item."""
76
+ total_size = 0
77
+ for i, item in enumerate(iterable):
78
+ size = len(item)
79
+ total_size += size
80
+ logger.info(f"{desc} {i}: {format_size(size)} (total: {format_size(total_size)})")
81
+ yield item
82
+ logger.info(f"{desc} finished, total size: {format_size(total_size)}")
83
+
84
+
85
+ # =============================================================================
86
+ # Dynamic Config Generation
87
+ # =============================================================================
88
+
89
+ def make_encode_config(codec_config_cls: Type) -> Type:
90
+ """Dynamically create an encode config dataclass for a given codec."""
91
+ return make_dataclass(
92
+ f"Encode{codec_config_cls.__name__}",
93
+ [
94
+ ("input", FrameReaderConfig, field(default_factory=FrameReaderConfig)),
95
+ ("output", BytesWriterConfig, field(default_factory=BytesWriterConfig)),
96
+ ("codec", codec_config_cls, field(default_factory=codec_config_cls)),
97
+ ],
98
+ )
99
+
100
+
101
+ def make_decode_config(codec_config_cls: Type) -> Type:
102
+ """Dynamically create a decode config dataclass for a given codec."""
103
+ return make_dataclass(
104
+ f"Decode{codec_config_cls.__name__}",
105
+ [
106
+ ("input", BytesReaderConfig, field(default_factory=BytesReaderConfig)),
107
+ ("output", FrameWriterConfig, field(default_factory=FrameWriterConfig)),
108
+ ("codec", codec_config_cls, field(default_factory=codec_config_cls)),
109
+ ],
110
+ )
111
+
112
+
113
+ # =============================================================================
114
+ # Encode/Decode Functions
115
+ # =============================================================================
116
+
117
+ def do_encode(cfg: DictConfig, codec_name: str) -> None:
118
+ """Execute the encoding process with resolved config."""
119
+ encoder_entry = ENCODERS[codec_name]
120
+
121
+ # Build components from config
122
+ frame_reader = build_frame_reader(cfg.input)
123
+ bytes_writer = build_bytes_writer(cfg.output)
124
+
125
+ # Build encoder from codec config
126
+ encoder = encoder_entry.factory(cfg.codec)
127
+
128
+ logger.info(f"Encoding with {codec_name}...")
129
+ logger.info(f" Input: {cfg.input.first_frame_path}")
130
+ logger.info(f" Output: {cfg.output.path}")
131
+
132
+ # Read frames and encode
133
+ frame_stream = iter_with_progress(frame_reader.read(), "Reading frame")
134
+ encoded_stream = iter_with_progress(encoder.encode_stream(frame_stream), "Encoded chunk")
135
+
136
+ # Write encoded bytes with size logging
137
+ bytes_writer.write(iter_with_size_logging(encoded_stream, "Writing chunk"))
138
+
139
+ logger.info("Encoding complete!")
140
+
141
+
142
+ def do_decode(cfg: DictConfig, codec_name: str) -> None:
143
+ """Execute the decoding process with resolved config."""
144
+ decoder_entry = DECODERS[codec_name]
145
+
146
+ # Build components from config
147
+ bytes_reader = build_bytes_reader(cfg.input)
148
+ frame_writer = build_frame_writer(cfg.output)
149
+
150
+ # Build decoder from codec config
151
+ decoder = decoder_entry.factory(cfg.codec)
152
+
153
+ logger.info(f"Decoding with {codec_name}...")
154
+ logger.info(f" Input: {cfg.input.path}")
155
+ logger.info(f" Output: {cfg.output.first_frame_path}")
156
+
157
+ # Read bytes and decode
158
+ bytes_stream = iter_with_size_logging(bytes_reader.read(), "Reading chunk")
159
+ decoded_stream = iter_with_progress(decoder.decode_stream(bytes_stream), "Decoded frame")
160
+
161
+ # Write decoded frames
162
+ frame_writer.write(iter_with_progress(decoded_stream, "Writing frame"))
163
+
164
+ logger.info("Decoding complete!")
165
+
166
+
167
+ def run_encode(codec_name: str, hydra_args: List[str]) -> None:
168
+ """Run encoding with Hydra configuration."""
169
+ encoder_entry = ENCODERS[codec_name]
170
+ config_cls = make_encode_config(encoder_entry.config_class)
171
+
172
+ # Clear and register config
173
+ GlobalHydra.instance().clear()
174
+ cs = ConfigStore.instance()
175
+ cs.store(name="config", node=config_cls)
176
+
177
+ @hydra.main(version_base=None, config_path=None, config_name="config")
178
+ def _main(cfg: DictConfig) -> None:
179
+ do_encode(cfg, codec_name)
180
+
181
+ sys.argv = [sys.argv[0]] + hydra_args
182
+ _main()
183
+
184
+
185
+ def run_decode(codec_name: str, hydra_args: List[str]) -> None:
186
+ """Run decoding with Hydra configuration."""
187
+ decoder_entry = DECODERS[codec_name]
188
+ config_cls = make_decode_config(decoder_entry.config_class)
189
+
190
+ # Clear and register config
191
+ GlobalHydra.instance().clear()
192
+ cs = ConfigStore.instance()
193
+ cs.store(name="config", node=config_cls)
194
+
195
+ @hydra.main(version_base=None, config_path=None, config_name="config")
196
+ def _main(cfg: DictConfig) -> None:
197
+ do_decode(cfg, codec_name)
198
+
199
+ sys.argv = [sys.argv[0]] + hydra_args
200
+ _main()
201
+
202
+
203
+ # =============================================================================
204
+ # Main Entry Point
205
+ # =============================================================================
206
+
207
+ def main() -> None:
208
+ """Main entry point for the CLI."""
209
+ logging.basicConfig(
210
+ level=logging.INFO,
211
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
212
+ )
213
+
214
+ if len(sys.argv) < 2 or sys.argv[1] in ("--help", "-h", "help"):
215
+ print("Usage: python -m gsvvcompressor <encode|decode> <codec> [options]")
216
+ print(f" Encoders: {list(ENCODERS.keys())}")
217
+ print(f" Decoders: {list(DECODERS.keys())}")
218
+ print("Use --help after codec name for configuration options.")
219
+ sys.exit(0 if len(sys.argv) >= 2 else 1)
220
+
221
+ command = sys.argv[1]
222
+ if command not in ("encode", "decode"):
223
+ sys.exit(f"Error: Unknown command '{command}'. Use 'encode' or 'decode'.")
224
+
225
+ if len(sys.argv) < 3:
226
+ sys.exit(f"Error: Please specify a codec for {command}. Available: {list(ENCODERS.keys() if command == 'encode' else DECODERS.keys())}")
227
+
228
+ codec_name = sys.argv[2]
229
+ registry = ENCODERS if command == "encode" else DECODERS
230
+ if codec_name not in registry:
231
+ sys.exit(f"Error: Unknown {command}r '{codec_name}'. Available: {list(registry.keys())}")
232
+
233
+ # Remaining args go to Hydra (--help, --cfg, overrides, etc.)
234
+ hydra_args = sys.argv[3:]
235
+
236
+ if command == "encode":
237
+ run_encode(codec_name, hydra_args)
238
+ else:
239
+ run_decode(codec_name, hydra_args)
240
+
241
+
242
+ if __name__ == "__main__":
243
+ main()
@@ -0,0 +1,84 @@
1
+ """
2
+ Combination modules for composing multiple codec components.
3
+ """
4
+
5
+ from .registry import (
6
+ ENCODERS,
7
+ DECODERS,
8
+ register_encoder,
9
+ register_decoder,
10
+ EncoderEntry,
11
+ DecoderEntry,
12
+ )
13
+
14
+ # Import to trigger registration
15
+ from . import vq_xyz_zstd
16
+ from . import vq_xyz_1mask_zstd
17
+ from . import vq_xyz_draco
18
+ from . import vq_xyz_draco_2pass
19
+
20
+ from .vq_xyz_zstd import (
21
+ VQXYZZstdEncoderConfig,
22
+ VQXYZZstdDecoderConfig,
23
+ VQXYZZstdEncoder,
24
+ VQXYZZstdDecoder,
25
+ build_vqxyzzstd_encoder,
26
+ build_vqxyzzstd_decoder,
27
+ )
28
+ from .vq_xyz_1mask_zstd import (
29
+ VQXYZ1MaskZstdEncoder,
30
+ VQXYZ1MaskZstdDecoder,
31
+ build_vqxyz1maskzstd_encoder,
32
+ build_vqxyz1maskzstd_decoder,
33
+ )
34
+ from .vq_xyz_draco import (
35
+ VQXYZDracoEncoderConfig,
36
+ VQXYZDracoDecoderConfig,
37
+ VQXYZDracoEncoder,
38
+ VQXYZDracoDecoder,
39
+ build_vqxyzdraco_encoder,
40
+ build_vqxyzdraco_decoder,
41
+ )
42
+ from .vq_xyz_draco_2pass import (
43
+ VQXYZDraco2PassEncoderConfig,
44
+ VQXYZDraco2PassDecoderConfig,
45
+ VQXYZDraco2PassEncoder,
46
+ VQXYZDraco2PassDecoder,
47
+ build_vqxyzdraco2pass_encoder,
48
+ build_vqxyzdraco2pass_decoder,
49
+ )
50
+
51
+ __all__ = [
52
+ "ENCODERS",
53
+ "DECODERS",
54
+ "register_encoder",
55
+ "register_decoder",
56
+ "EncoderEntry",
57
+ "DecoderEntry",
58
+ # VQ + XYZ + Zstd
59
+ "VQXYZZstdEncoderConfig",
60
+ "VQXYZZstdDecoderConfig",
61
+ "VQXYZZstdEncoder",
62
+ "VQXYZZstdDecoder",
63
+ "build_vqxyzzstd_encoder",
64
+ "build_vqxyzzstd_decoder",
65
+ # VQ (single merged mask) + XYZ + Zstd
66
+ "VQXYZ1MaskZstdEncoder",
67
+ "VQXYZ1MaskZstdDecoder",
68
+ "build_vqxyz1maskzstd_encoder",
69
+ "build_vqxyz1maskzstd_decoder",
70
+ # VQ + XYZ + Draco
71
+ "VQXYZDracoEncoderConfig",
72
+ "VQXYZDracoDecoderConfig",
73
+ "VQXYZDracoEncoder",
74
+ "VQXYZDracoDecoder",
75
+ "build_vqxyzdraco_encoder",
76
+ "build_vqxyzdraco_decoder",
77
+ # VQ + XYZ + Two-Pass Draco
78
+ "VQXYZDraco2PassEncoderConfig",
79
+ "VQXYZDraco2PassDecoderConfig",
80
+ "VQXYZDraco2PassEncoder",
81
+ "VQXYZDraco2PassDecoder",
82
+ "build_vqxyzdraco2pass_encoder",
83
+ "build_vqxyzdraco2pass_decoder",
84
+ ]
@@ -0,0 +1,52 @@
1
+ """
2
+ Global registry for encoder and decoder combinations.
3
+ """
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Callable, Dict, Type
7
+
8
+ from ..encoder import AbstractEncoder
9
+ from ..decoder import AbstractDecoder
10
+
11
+
12
+ @dataclass
13
+ class EncoderEntry:
14
+ """Entry in the encoder registry."""
15
+ name: str
16
+ factory: Callable[..., AbstractEncoder]
17
+ config_class: Type
18
+ description: str = ""
19
+
20
+
21
+ @dataclass
22
+ class DecoderEntry:
23
+ """Entry in the decoder registry."""
24
+ name: str
25
+ factory: Callable[..., AbstractDecoder]
26
+ config_class: Type
27
+ description: str = ""
28
+
29
+
30
+ # Global registries
31
+ ENCODERS: Dict[str, EncoderEntry] = {}
32
+ DECODERS: Dict[str, DecoderEntry] = {}
33
+
34
+
35
+ def register_encoder(
36
+ name: str,
37
+ factory: Callable[..., AbstractEncoder],
38
+ config_class: Type,
39
+ description: str = "",
40
+ ) -> None:
41
+ """Register an encoder."""
42
+ ENCODERS[name] = EncoderEntry(name, factory, config_class, description)
43
+
44
+
45
+ def register_decoder(
46
+ name: str,
47
+ factory: Callable[..., AbstractDecoder],
48
+ config_class: Type,
49
+ description: str = "",
50
+ ) -> None:
51
+ """Register a decoder."""
52
+ DECODERS[name] = DecoderEntry(name, factory, config_class, description)
@@ -0,0 +1,89 @@
1
+ """
2
+ VQ + XYZ quantization combined codec interface with merged mask.
3
+
4
+ This module provides the combined VQ + XYZ codec interface that uses a single
5
+ merged mask for interframe encoding.
6
+ """
7
+
8
+ from ..interframe.combine import (
9
+ CombinedInterframeCodecInterface,
10
+ CombinedInterframeCodecContext,
11
+ CombinedPayload,
12
+ )
13
+ from ..vq.interface import VQInterframeCodecContext
14
+ from ..vq.singlemask import VQMergeMaskInterframeCodecInterface, VQMergeMaskInterframePayload
15
+ from ..xyz.interface import (
16
+ XYZQuantInterframeCodecInterface,
17
+ XYZQuantInterframeCodecContext,
18
+ XYZQuantInterframePayload,
19
+ )
20
+
21
+
22
+ class VQXYZQuantMergeMaskInterframeCodecInterface(CombinedInterframeCodecInterface):
23
+ """
24
+ Combined VQ + XYZ codec with single merged mask for interframe encoding.
25
+
26
+ This interface extends CombinedInterframeCodecInterface but uses a single merged mask
27
+ (OR of XYZ mask and all VQ attribute masks) for interframe payloads. Both XYZ and VQ
28
+ payloads use the same mask, improving compression efficiency.
29
+
30
+ Assumes interfaces order: [xyz_interface, vq_interface]
31
+ """
32
+
33
+ def __init__(self):
34
+ """
35
+ Initialize the combined codec with XYZ and VQ interfaces.
36
+ """
37
+ xyz_interface = XYZQuantInterframeCodecInterface()
38
+ vq_interface = VQMergeMaskInterframeCodecInterface()
39
+ super().__init__([xyz_interface, vq_interface])
40
+ self.xyz_interface = xyz_interface
41
+ self.vq_interface = vq_interface
42
+
43
+ def encode_interframe(
44
+ self,
45
+ prev_context: CombinedInterframeCodecContext,
46
+ next_context: CombinedInterframeCodecContext,
47
+ ) -> CombinedPayload:
48
+ """
49
+ Encode the difference between two consecutive frames.
50
+
51
+ Calls super to get individual payloads, then merges masks (OR) and
52
+ re-extracts data using the merged mask.
53
+
54
+ Args:
55
+ prev_context: The context of the previous frame.
56
+ next_context: The context of the next frame.
57
+
58
+ Returns:
59
+ A CombinedPayload with XYZ and VQ payloads using the same merged mask.
60
+ """
61
+ # Get original payloads from parent
62
+ original_payload: CombinedPayload = super().encode_interframe(prev_context, next_context)
63
+ xyz_original: XYZQuantInterframePayload = original_payload.payloads[0]
64
+ vq_original: VQMergeMaskInterframePayload = original_payload.payloads[1]
65
+
66
+ # Merge masks: XYZ mask OR VQ mask
67
+ merged_mask = xyz_original.xyz_mask | vq_original.ids_mask
68
+
69
+ # Get next context data
70
+ xyz_next_context: XYZQuantInterframeCodecContext = next_context.contexts[0]
71
+ vq_next_context: VQInterframeCodecContext = next_context.contexts[1]
72
+
73
+ # Create XYZ payload with merged mask
74
+ xyz_payload = XYZQuantInterframePayload(
75
+ xyz_mask=merged_mask,
76
+ quantized_xyz=xyz_next_context.quantized_xyz[merged_mask],
77
+ )
78
+
79
+ # Create VQ payload with merged mask
80
+ changed_ids_dict = {}
81
+ for key, next_ids in vq_next_context.ids_dict.items():
82
+ changed_ids_dict[key] = next_ids[merged_mask]
83
+
84
+ vq_payload = VQMergeMaskInterframePayload(
85
+ ids_mask=merged_mask,
86
+ ids_dict=changed_ids_dict,
87
+ )
88
+
89
+ return CombinedPayload(payloads=[xyz_payload, vq_payload])
@@ -0,0 +1,103 @@
1
+ """
2
+ VQ + XYZ quantization with single merged mask + Zstd compression encoder/decoder combination.
3
+
4
+ This module provides a combined codec where VQ and XYZ share a single merged mask
5
+ for interframe encoding, improving compression efficiency.
6
+ """
7
+
8
+ from dataclasses import dataclass, field
9
+ from typing import Optional
10
+
11
+ from ..compress.zstd import ZstdSerializer, ZstdDeserializer
12
+ from ..interframe.combine import CombinedInterframeEncoderInitConfig
13
+ from ..interframe.encoder import InterframeEncoder
14
+ from ..interframe.decoder import InterframeDecoder
15
+ from ..vq.interface import VQInterframeCodecConfig
16
+ from ..xyz.interface import XYZQuantInterframeCodecConfig
17
+ from .registry import register_encoder, register_decoder
18
+ from .vq_xyz_1mask import VQXYZQuantMergeMaskInterframeCodecInterface
19
+
20
+
21
+ def VQXYZ1MaskZstdEncoder(
22
+ vq_config: VQInterframeCodecConfig,
23
+ xyz_config: XYZQuantInterframeCodecConfig,
24
+ zstd_level: int = 7,
25
+ payload_device: Optional[str] = None,
26
+ ) -> InterframeEncoder:
27
+ """Create an encoder combining VQ + XYZ quantization with merged mask + Zstd compression."""
28
+ combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
29
+ combined_config = CombinedInterframeEncoderInitConfig(
30
+ init_configs=[xyz_config, vq_config]
31
+ )
32
+ serializer = ZstdSerializer(level=zstd_level)
33
+ return InterframeEncoder(
34
+ serializer=serializer,
35
+ interface=combined_interface,
36
+ init_config=combined_config,
37
+ payload_device=payload_device,
38
+ )
39
+
40
+
41
+ def VQXYZ1MaskZstdDecoder(
42
+ payload_device: Optional[str] = None,
43
+ device: Optional[str] = None,
44
+ ) -> InterframeDecoder:
45
+ """Create a decoder for VQ + XYZ quantization with merged mask + Zstd compressed data."""
46
+ combined_interface = VQXYZQuantMergeMaskInterframeCodecInterface()
47
+ deserializer = ZstdDeserializer()
48
+ return InterframeDecoder(
49
+ deserializer=deserializer,
50
+ interface=combined_interface,
51
+ payload_device=payload_device,
52
+ device=device,
53
+ )
54
+
55
+
56
+ @dataclass
57
+ class VQXYZ1MaskZstdEncoderConfig:
58
+ """Configuration for VQ + XYZ (merged mask) + Zstd encoder."""
59
+ vq: VQInterframeCodecConfig = field(default_factory=VQInterframeCodecConfig)
60
+ xyz: XYZQuantInterframeCodecConfig = field(default_factory=XYZQuantInterframeCodecConfig)
61
+ zstd_level: int = 7
62
+ payload_device: Optional[str] = None
63
+
64
+
65
+ @dataclass
66
+ class VQXYZ1MaskZstdDecoderConfig:
67
+ """Configuration for VQ + XYZ (merged mask) + Zstd decoder."""
68
+ payload_device: Optional[str] = None
69
+ device: Optional[str] = None
70
+
71
+
72
+ def build_vqxyz1maskzstd_encoder(config: VQXYZ1MaskZstdEncoderConfig) -> InterframeEncoder:
73
+ """Build encoder from configuration."""
74
+ return VQXYZ1MaskZstdEncoder(
75
+ vq_config=config.vq,
76
+ xyz_config=config.xyz,
77
+ zstd_level=config.zstd_level,
78
+ payload_device=config.payload_device,
79
+ )
80
+
81
+
82
+ def build_vqxyz1maskzstd_decoder(config: VQXYZ1MaskZstdDecoderConfig) -> InterframeDecoder:
83
+ """Build decoder from configuration."""
84
+ return VQXYZ1MaskZstdDecoder(
85
+ payload_device=config.payload_device,
86
+ device=config.device,
87
+ )
88
+
89
+
90
+ # Register
91
+ register_encoder(
92
+ "vqxyz1maskzstd",
93
+ build_vqxyz1maskzstd_encoder,
94
+ VQXYZ1MaskZstdEncoderConfig,
95
+ "VQ + XYZ quantization (merged mask) + Zstd compression",
96
+ )
97
+
98
+ register_decoder(
99
+ "vqxyz1maskzstd",
100
+ build_vqxyz1maskzstd_decoder,
101
+ VQXYZ1MaskZstdDecoderConfig,
102
+ "VQ + XYZ quantization (merged mask) + Zstd decompression",
103
+ )