gsvvcompressor 1.2.0__cp310-cp310-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.cp310-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,690 @@
1
+ Metadata-Version: 2.4
2
+ Name: gsvvcompressor
3
+ Version: 1.2.0
4
+ Summary: A compression library for Gaussian Splatting video/volumetric data with vector quantization and inter-frame encoding
5
+ Author-email: Howard Yin <yindaheng98@gmail.com>
6
+ Maintainer-email: Howard Yin <yindaheng98@gmail.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/yindaheng98/gsvvcompressor
9
+ Project-URL: Documentation, https://github.com/yindaheng98/gsvvcompressor#readme
10
+ Project-URL: Repository, https://github.com/yindaheng98/gsvvcompressor
11
+ Project-URL: Issues, https://github.com/yindaheng98/gsvvcompressor/issues
12
+ Keywords: gaussian-splatting,3dgs,compression,video-compression,volumetric-video,vector-quantization,zstd,pytorch,deep-learning
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Classifier: Topic :: Multimedia :: Video
25
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: torch>=2.0.0
30
+ Requires-Dist: numpy>=1.21.0
31
+ Requires-Dist: cloudpickle>=2.0.0
32
+ Requires-Dist: zstandard>=0.18.0
33
+ Requires-Dist: hydra-core>=1.3.0
34
+ Requires-Dist: omegaconf>=2.3.0
35
+ Requires-Dist: gaussian-splatting
36
+ Requires-Dist: reduced-3dgs
37
+ Requires-Dist: gscompressor
38
+ Dynamic: license-file
39
+
40
+ # gsvvcompressor
41
+
42
+ A modular video compression framework for Gaussian Splatting models (3DGS). This library provides a flexible, extensible architecture for encoding and decoding sequences of `GaussianModel` frames using inter-frame compression techniques.
43
+
44
+ ## Installation
45
+
46
+ Install from GitHub:
47
+
48
+ ```sh
49
+ pip install git+https://github.com/yindaheng98/gsvvcompressor.git@master
50
+ ```
51
+
52
+ Or clone and install locally:
53
+
54
+ ```sh
55
+ git clone https://github.com/yindaheng98/gsvvcompressor.git
56
+ cd gsvvcompressor
57
+ pip install -e .
58
+ ```
59
+
60
+ ### Requirements
61
+
62
+ - Python >= 3.9
63
+ - PyTorch >= 2.0.0
64
+ - Dependencies are automatically installed (numpy, cloudpickle, zstandard, hydra-core, etc.)
65
+
66
+ ## Quick Start
67
+
68
+ ### Command-Line Interface
69
+
70
+ Encode a sequence of GaussianModel frames:
71
+
72
+ ```sh
73
+ python -m gsvvcompressor encode vqxyzzstd \
74
+ input.first_frame_path=data/frame_0000.ply \
75
+ input.subsequent_format="data/frame_{:04d}.ply" \
76
+ output.path=compressed.bin
77
+ ```
78
+
79
+ Decode compressed data back to frames:
80
+
81
+ ```sh
82
+ python -m gsvvcompressor decode vqxyzzstd \
83
+ input.path=compressed.bin \
84
+ output.first_frame_path=decoded/frame_0000.ply \
85
+ output.subsequent_format="decoded/frame_{:04d}.ply"
86
+ ```
87
+
88
+ ### Programmatic Usage
89
+
90
+ ```python
91
+ from gsvvcompressor.combinations import VQXYZZstdEncoder, VQXYZZstdDecoder
92
+ from gsvvcompressor.vq import VQInterframeCodecConfig
93
+ from gsvvcompressor.xyz import XYZQuantInterframeCodecConfig
94
+ from gsvvcompressor.io import FrameReader, FrameWriter, BytesReader, BytesWriter
95
+
96
+ # Create encoder
97
+ encoder = VQXYZZstdEncoder(
98
+ vq_config=VQInterframeCodecConfig(num_clusters=256),
99
+ xyz_config=XYZQuantInterframeCodecConfig(alpha=0.2),
100
+ zstd_level=7,
101
+ )
102
+
103
+ # Read frames and encode
104
+ frame_reader = FrameReader(
105
+ first_frame_path="data/frame_0000.ply",
106
+ subsequent_format="data/frame_{:04d}.ply",
107
+ start_index=1,
108
+ )
109
+ encoded_stream = encoder.encode_stream(frame_reader.read())
110
+
111
+ # Write compressed output
112
+ bytes_writer = BytesWriter("compressed.bin")
113
+ bytes_writer.write(encoded_stream)
114
+
115
+ # Decode
116
+ decoder = VQXYZZstdDecoder()
117
+ bytes_reader = BytesReader("compressed.bin")
118
+ decoded_stream = decoder.decode_stream(bytes_reader.read())
119
+
120
+ # Write decoded frames
121
+ frame_writer = FrameWriter(
122
+ first_frame_path="decoded/frame_0000.ply",
123
+ subsequent_format="decoded/frame_{:04d}.ply",
124
+ start_index=1,
125
+ )
126
+ frame_writer.write(decoded_stream)
127
+ ```
128
+
129
+ ## Architecture Overview
130
+
131
+ The library uses a layered, modular architecture that separates concerns into distinct components:
132
+
133
+ ```
134
+ ┌─────────────────────────────────────────────────────────────────────┐
135
+ │ GaussianModel Stream │
136
+ └─────────────────────────────────────────────────────────────────────┘
137
+
138
+
139
+ ┌─────────────────────────────────────────────────────────────────────┐
140
+ │ AbstractEncoder / AbstractDecoder │
141
+ │ ┌───────────────────────────────────────────────────────────────┐ │
142
+ │ │ InterframeEncoder / InterframeDecoder │ │
143
+ │ │ ┌─────────────────────────────────────────────────────────┐ │ │
144
+ │ │ │ CombinedInterframeCodecInterface │ │ │
145
+ │ │ │ ┌─────────────────┐ ┌─────────────────────────────┐ │ │ │
146
+ │ │ │ │ XYZ Codec │ │ VQ Codec │ │ │ │
147
+ │ │ │ │ (coordinates) │ │ (attributes) │ │ │ │
148
+ │ │ │ └─────────────────┘ └─────────────────────────────┘ │ │ │
149
+ │ │ └─────────────────────────────────────────────────────────┘ │ │
150
+ │ └───────────────────────────────────────────────────────────────┘ │
151
+ └─────────────────────────────────────────────────────────────────────┘
152
+
153
+
154
+ ┌─────────────────────────────────────────────────────────────────────┐
155
+ │ Payload │
156
+ └─────────────────────────────────────────────────────────────────────┘
157
+
158
+
159
+ ┌─────────────────────────────────────────────────────────────────────┐
160
+ │ AbstractSerializer / AbstractDeserializer │
161
+ │ ┌───────────────────────────────────────────────────────────────┐ │
162
+ │ │ ZstdSerializer / ZstdDeserializer │ │
163
+ │ │ (cloudpickle + length-prefix framing + zstd compression) │ │
164
+ │ └───────────────────────────────────────────────────────────────┘ │
165
+ └─────────────────────────────────────────────────────────────────────┘
166
+
167
+
168
+ ┌─────────────────────────────────────────────────────────────────────┐
169
+ │ Bytes Stream │
170
+ └─────────────────────────────────────────────────────────────────────┘
171
+ ```
172
+
173
+ ## Core Abstract Classes
174
+
175
+ ### Payload
176
+
177
+ `Payload` is the abstract base class for intermediate data structures that flow between the encoding/decoding stages and the serialization/deserialization stages.
178
+
179
+ ```python
180
+ from gsvvcompressor import Payload
181
+
182
+ @dataclass
183
+ class MyPayload(Payload):
184
+ data: torch.Tensor
185
+
186
+ def to(self, device) -> Self:
187
+ return MyPayload(data=self.data.to(device))
188
+ ```
189
+
190
+ ### AbstractEncoder and AbstractDecoder
191
+
192
+ These are the top-level abstract classes that define the encoding/decoding interface. They use a two-stage process:
193
+
194
+ **Encoding Pipeline:**
195
+ 1. `pack(frame)` → Converts `GaussianModel` to `Payload`
196
+ 2. `serialize_frame(payload)` → Converts `Payload` to `bytes`
197
+
198
+ **Decoding Pipeline:**
199
+ 1. `deserialize_frame(data)` → Converts `bytes` to `Payload`
200
+ 2. `unpack(payload)` → Converts `Payload` to `GaussianModel`
201
+
202
+ ```python
203
+ from gsvvcompressor import AbstractEncoder, AbstractDecoder
204
+
205
+ class MyEncoder(AbstractEncoder):
206
+ def pack(self, frame: GaussianModel) -> Iterator[Payload]:
207
+ # Convert frame to payload(s)
208
+ yield MyPayload(...)
209
+
210
+ def flush_pack(self) -> Iterator[Payload]:
211
+ # Flush any buffered payloads
212
+ return
213
+ yield
214
+
215
+ class MyDecoder(AbstractDecoder):
216
+ def unpack(self, payload: Payload) -> Iterator[GaussianModel]:
217
+ # Convert payload to frame(s)
218
+ yield reconstructed_frame
219
+
220
+ def flush_unpack(self) -> Iterator[GaussianModel]:
221
+ # Flush any buffered frames
222
+ return
223
+ yield
224
+ ```
225
+
226
+ ### AbstractSerializer and AbstractDeserializer
227
+
228
+ These classes handle the conversion between `Payload` objects and `bytes`.
229
+
230
+ ```python
231
+ from gsvvcompressor import AbstractSerializer, AbstractDeserializer
232
+
233
+ class MySerializer(AbstractSerializer):
234
+ def serialize_frame(self, payload: Payload) -> Iterator[bytes]:
235
+ yield serialized_bytes
236
+
237
+ def flush(self) -> Iterator[bytes]:
238
+ yield remaining_bytes
239
+
240
+ class MyDeserializer(AbstractDeserializer):
241
+ def deserialize_frame(self, data: bytes) -> Iterator[Payload]:
242
+ yield deserialized_payload
243
+
244
+ def flush(self) -> Iterator[Payload]:
245
+ yield remaining_payloads
246
+ ```
247
+
248
+ ## Inter-frame Compression
249
+
250
+ The `interframe` module provides infrastructure for inter-frame compression, where frames are encoded as differences from previous frames.
251
+
252
+ ### InterframeCodecInterface
253
+
254
+ This is the core abstract interface for implementing inter-frame codecs. It defines methods for:
255
+
256
+ - **Keyframe encoding/decoding**: First frame contains full data
257
+ - **Interframe encoding/decoding**: Subsequent frames contain only differences
258
+ - **Context management**: Converting between frames and codec-specific contexts
259
+
260
+ ```python
261
+ from gsvvcompressor.interframe import (
262
+ InterframeCodecInterface,
263
+ InterframeCodecContext,
264
+ InterframeEncoderInitConfig,
265
+ )
266
+
267
+ class MyCodecInterface(InterframeCodecInterface):
268
+ def keyframe_to_context(self, frame: GaussianModel, init_config) -> MyContext:
269
+ """Convert a keyframe to codec context (encoder only)."""
270
+ ...
271
+
272
+ def interframe_to_context(self, frame: GaussianModel, prev_context) -> MyContext:
273
+ """Convert a frame using previous context as reference (encoder only)."""
274
+ ...
275
+
276
+ def encode_keyframe(self, context: MyContext) -> MyKeyframePayload:
277
+ """Encode context as keyframe payload."""
278
+ ...
279
+
280
+ def encode_interframe(self, prev_context, next_context) -> MyInterframePayload:
281
+ """Encode difference between two contexts."""
282
+ ...
283
+
284
+ def decode_keyframe(self, payload: MyKeyframePayload) -> MyContext:
285
+ """Decode keyframe payload to context."""
286
+ ...
287
+
288
+ def decode_interframe(self, payload, prev_context) -> MyContext:
289
+ """Decode interframe payload using previous context."""
290
+ ...
291
+
292
+ def context_to_frame(self, context: MyContext, frame: GaussianModel) -> GaussianModel:
293
+ """Convert context back to frame (decoder only)."""
294
+ ...
295
+ ```
296
+
297
+ ### InterframeEncoder and InterframeDecoder
298
+
299
+ These classes implement `AbstractEncoder` and `AbstractDecoder` using an `InterframeCodecInterface`:
300
+
301
+ ```python
302
+ from gsvvcompressor.interframe import InterframeEncoder, InterframeDecoder
303
+
304
+ # Create encoder with a codec interface
305
+ encoder = InterframeEncoder(
306
+ serializer=my_serializer,
307
+ interface=my_codec_interface,
308
+ init_config=my_init_config,
309
+ )
310
+
311
+ # Create decoder
312
+ decoder = InterframeDecoder(
313
+ deserializer=my_deserializer,
314
+ interface=my_codec_interface,
315
+ )
316
+ ```
317
+
318
+ ### CombinedInterframeCodecInterface
319
+
320
+ This class allows combining multiple `InterframeCodecInterface` instances into a single codec. Each sub-codec processes different aspects of the frame data:
321
+
322
+ ```python
323
+ from gsvvcompressor.interframe.combine import CombinedInterframeCodecInterface
324
+
325
+ # Combine XYZ (coordinates) and VQ (attributes) codecs
326
+ combined = CombinedInterframeCodecInterface([
327
+ xyz_interface, # Handles xyz coordinates
328
+ vq_interface, # Handles other attributes (rotation, scaling, etc.)
329
+ ])
330
+ ```
331
+
332
+ ## Built-in Codec Implementations
333
+
334
+ ### VQ (Vector Quantization) Codec
335
+
336
+ The VQ codec uses vector quantization to compress Gaussian model attributes (rotation, opacity, scaling, features). It maintains a codebook generated from the keyframe.
337
+
338
+ ```python
339
+ from gsvvcompressor.vq import VQInterframeCodecInterface, VQInterframeCodecConfig
340
+
341
+ vq_config = VQInterframeCodecConfig(
342
+ num_clusters=256, # Default clusters for each attribute
343
+ num_clusters_rotation_re=256, # Clusters for rotation real part
344
+ num_clusters_rotation_im=256, # Clusters for rotation imaginary part
345
+ num_clusters_opacity=256, # Clusters for opacity
346
+ num_clusters_scaling=256, # Clusters for scaling
347
+ num_clusters_features_dc=256, # Clusters for DC features
348
+ max_sh_degree=3, # Maximum SH degree
349
+ tol=1e-6, # K-means tolerance
350
+ max_iter=500, # K-means max iterations
351
+ )
352
+
353
+ vq_interface = VQInterframeCodecInterface()
354
+ ```
355
+
356
+ **How it works:**
357
+ - **Keyframe**: Runs K-means clustering to generate codebooks, stores codebooks + cluster IDs
358
+ - **Interframe**: Uses existing codebooks to find nearest cluster IDs, stores only changed IDs with masks
359
+
360
+ ### XYZ Quantization Codec
361
+
362
+ The XYZ codec quantizes the 3D coordinates of Gaussian splats using uniform quantization with adaptive step sizes.
363
+
364
+ ```python
365
+ from gsvvcompressor.xyz import XYZQuantInterframeCodecInterface, XYZQuantInterframeCodecConfig
366
+
367
+ xyz_config = XYZQuantInterframeCodecConfig(
368
+ k=1, # K-th nearest neighbor for step size estimation
369
+ sample_size=10000, # Points to sample for NN estimation
370
+ seed=42, # Random seed
371
+ quantile=0.05, # Quantile of NN distances for scale estimation
372
+ alpha=0.2, # Scaling factor for step size
373
+ min_step=None, # Optional minimum step size
374
+ max_step=None, # Optional maximum step size
375
+ tolerance=0, # Tolerance for change detection
376
+ )
377
+
378
+ xyz_interface = XYZQuantInterframeCodecInterface()
379
+ ```
380
+
381
+ **How it works:**
382
+ - **Keyframe**: Computes quantization config (step_size, origin) from point distribution, stores config + quantized coordinates
383
+ - **Interframe**: Uses existing config to quantize coordinates, stores only changed coordinates with masks
384
+
385
+ ### Zstd Serializer
386
+
387
+ The Zstd serializer uses cloudpickle for serialization with zstandard compression:
388
+
389
+ ```python
390
+ from gsvvcompressor.compress.zstd import ZstdSerializer, ZstdDeserializer
391
+
392
+ serializer = ZstdSerializer(level=7) # Compression level 1-22
393
+ deserializer = ZstdDeserializer()
394
+ ```
395
+
396
+ ## Pre-built Combinations
397
+
398
+ ### VQXYZZstd
399
+
400
+ A ready-to-use encoder/decoder combining VQ + XYZ quantization + Zstd compression:
401
+
402
+ ```python
403
+ from gsvvcompressor.combinations import (
404
+ VQXYZZstdEncoder,
405
+ VQXYZZstdDecoder,
406
+ VQXYZZstdEncoderConfig,
407
+ VQXYZZstdDecoderConfig,
408
+ )
409
+
410
+ # Direct construction
411
+ encoder = VQXYZZstdEncoder(
412
+ vq_config=VQInterframeCodecConfig(...),
413
+ xyz_config=XYZQuantInterframeCodecConfig(...),
414
+ zstd_level=7,
415
+ payload_device="cpu",
416
+ )
417
+
418
+ decoder = VQXYZZstdDecoder(payload_device="cpu")
419
+
420
+ # Or from config
421
+ from gsvvcompressor.combinations import build_vqxyzzstd_encoder, build_vqxyzzstd_decoder
422
+
423
+ encoder_config = VQXYZZstdEncoderConfig(
424
+ vq=VQInterframeCodecConfig(...),
425
+ xyz=XYZQuantInterframeCodecConfig(...),
426
+ zstd_level=7,
427
+ )
428
+ encoder = build_vqxyzzstd_encoder(encoder_config)
429
+ ```
430
+
431
+ ## Registry System
432
+
433
+ The `combinations` module provides a registry for encoder/decoder combinations:
434
+
435
+ ```python
436
+ from gsvvcompressor.combinations import (
437
+ ENCODERS,
438
+ DECODERS,
439
+ register_encoder,
440
+ register_decoder,
441
+ )
442
+
443
+ # List available codecs
444
+ print(ENCODERS.keys()) # ['vqxyzzstd', ...]
445
+ print(DECODERS.keys()) # ['vqxyzzstd', ...]
446
+
447
+ # Register a custom codec
448
+ register_encoder(
449
+ name="mycodec",
450
+ factory=build_my_encoder,
451
+ config_class=MyEncoderConfig,
452
+ description="My custom encoder",
453
+ )
454
+ ```
455
+
456
+ ## IO Module
457
+
458
+ The `io` module provides utilities for reading and writing frames and bytes:
459
+
460
+ ```python
461
+ from gsvvcompressor.io import (
462
+ FrameReader,
463
+ FrameWriter,
464
+ BytesReader,
465
+ BytesWriter,
466
+ )
467
+
468
+ # Read GaussianModel frames
469
+ reader = FrameReader(
470
+ first_frame_path="data/frame_0000.ply",
471
+ subsequent_format="data/frame_{:04d}.ply",
472
+ start_index=1,
473
+ sh_degree=3,
474
+ )
475
+ for frame in reader.read():
476
+ process(frame)
477
+
478
+ # Write GaussianModel frames
479
+ writer = FrameWriter(
480
+ first_frame_path="output/frame_0000.ply",
481
+ subsequent_format="output/frame_{:04d}.ply",
482
+ start_index=1,
483
+ )
484
+ writer.write(frame_iterator)
485
+
486
+ # Read/write bytes
487
+ bytes_reader = BytesReader("compressed.bin", chunk_size=65536)
488
+ bytes_writer = BytesWriter("output.bin")
489
+ ```
490
+
491
+ ## Creating a Custom Codec
492
+
493
+ To create a custom inter-frame codec:
494
+
495
+ ### 1. Define Payload Classes
496
+
497
+ ```python
498
+ from dataclasses import dataclass
499
+ from gsvvcompressor import Payload
500
+
501
+ @dataclass
502
+ class MyKeyframePayload(Payload):
503
+ # Full frame data
504
+ data: torch.Tensor
505
+
506
+ def to(self, device):
507
+ return MyKeyframePayload(data=self.data.to(device))
508
+
509
+ @dataclass
510
+ class MyInterframePayload(Payload):
511
+ # Delta data only
512
+ mask: torch.Tensor
513
+ delta: torch.Tensor
514
+
515
+ def to(self, device):
516
+ return MyInterframePayload(
517
+ mask=self.mask.to(device),
518
+ delta=self.delta.to(device),
519
+ )
520
+ ```
521
+
522
+ ### 2. Define Context and Config
523
+
524
+ ```python
525
+ from gsvvcompressor.interframe import InterframeCodecContext, InterframeEncoderInitConfig
526
+
527
+ @dataclass
528
+ class MyCodecConfig(InterframeEncoderInitConfig):
529
+ quality: int = 10
530
+
531
+ @dataclass
532
+ class MyCodecContext(InterframeCodecContext):
533
+ encoded_data: torch.Tensor
534
+ quality: int
535
+ ```
536
+
537
+ ### 3. Implement the Interface
538
+
539
+ ```python
540
+ from gsvvcompressor.interframe import InterframeCodecInterface
541
+
542
+ class MyCodecInterface(InterframeCodecInterface):
543
+ def keyframe_to_context(self, frame, init_config):
544
+ # Encode frame to context
545
+ return MyCodecContext(
546
+ encoded_data=encode(frame, init_config.quality),
547
+ quality=init_config.quality,
548
+ )
549
+
550
+ def interframe_to_context(self, frame, prev_context):
551
+ # Encode frame using previous context
552
+ return MyCodecContext(
553
+ encoded_data=encode(frame, prev_context.quality),
554
+ quality=prev_context.quality,
555
+ )
556
+
557
+ def encode_keyframe(self, context):
558
+ return MyKeyframePayload(data=context.encoded_data)
559
+
560
+ def encode_interframe(self, prev_context, next_context):
561
+ # Compute delta
562
+ mask = prev_context.encoded_data != next_context.encoded_data
563
+ delta = next_context.encoded_data[mask]
564
+ return MyInterframePayload(mask=mask, delta=delta)
565
+
566
+ def decode_keyframe(self, payload):
567
+ return MyCodecContext(encoded_data=payload.data, quality=0)
568
+
569
+ def decode_interframe(self, payload, prev_context):
570
+ new_data = prev_context.encoded_data.clone()
571
+ new_data[payload.mask] = payload.delta
572
+ return MyCodecContext(encoded_data=new_data, quality=prev_context.quality)
573
+
574
+ def context_to_frame(self, context, frame):
575
+ # Decode context to frame
576
+ frame._xyz = decode(context.encoded_data)
577
+ return frame
578
+ ```
579
+
580
+ ### 4. Build the Encoder/Decoder
581
+
582
+ ```python
583
+ from gsvvcompressor.interframe import InterframeEncoder, InterframeDecoder
584
+ from gsvvcompressor.compress.zstd import ZstdSerializer, ZstdDeserializer
585
+
586
+ def build_my_encoder(config):
587
+ return InterframeEncoder(
588
+ serializer=ZstdSerializer(level=7),
589
+ interface=MyCodecInterface(),
590
+ init_config=config,
591
+ )
592
+
593
+ def build_my_decoder(config):
594
+ return InterframeDecoder(
595
+ deserializer=ZstdDeserializer(),
596
+ interface=MyCodecInterface(),
597
+ )
598
+ ```
599
+
600
+ ### 5. Register (Optional)
601
+
602
+ ```python
603
+ from gsvvcompressor.combinations import register_encoder, register_decoder
604
+
605
+ register_encoder("mycodec", build_my_encoder, MyCodecConfig, "My custom codec")
606
+ register_decoder("mycodec", build_my_decoder, MyCodecConfig, "My custom codec")
607
+ ```
608
+
609
+ ## Project Structure
610
+
611
+ ```
612
+ gsvvcompressor/
613
+ ├── __init__.py # Core exports: Payload, AbstractEncoder/Decoder, AbstractSerializer/Deserializer
614
+ ├── __main__.py # CLI entry point
615
+ ├── payload.py # Payload abstract base class
616
+ ├── encoder.py # AbstractEncoder base class
617
+ ├── decoder.py # AbstractDecoder base class
618
+ ├── serializer.py # AbstractSerializer base class
619
+ ├── deserializer.py # AbstractDeserializer base class
620
+ ├── combinations/ # Pre-built codec combinations
621
+ │ ├── __init__.py
622
+ │ ├── registry.py # Encoder/decoder registry
623
+ │ └── vq_xyz_zstd.py # VQ + XYZ + Zstd combination
624
+ ├── compress/ # Compression implementations
625
+ │ ├── __init__.py
626
+ │ └── zstd.py # Zstd serializer/deserializer
627
+ ├── interframe/ # Inter-frame compression infrastructure
628
+ │ ├── __init__.py
629
+ │ ├── interface.py # InterframeCodecInterface and related classes
630
+ │ ├── encoder.py # InterframeEncoder
631
+ │ ├── decoder.py # InterframeDecoder
632
+ │ ├── combine.py # CombinedInterframeCodecInterface
633
+ │ └── twopass.py # Two-pass encoding utilities
634
+ ├── io/ # Input/output utilities
635
+ │ ├── __init__.py
636
+ │ ├── bytes.py # BytesReader/Writer
637
+ │ ├── config.py # Configuration dataclasses
638
+ │ └── gaussian_model.py # FrameReader/Writer
639
+ ├── vq/ # Vector quantization codec
640
+ │ ├── __init__.py
641
+ │ ├── interface.py # VQInterframeCodecInterface
642
+ │ └── twopass.py # Two-pass VQ utilities
643
+ └── xyz/ # XYZ coordinate codec
644
+ ├── __init__.py
645
+ ├── interface.py # XYZQuantInterframeCodecInterface
646
+ ├── quant.py # Quantization functions
647
+ └── ... # Other XYZ utilities
648
+ ```
649
+
650
+ ## Class Hierarchy
651
+
652
+ ```
653
+ Payload (ABC)
654
+ ├── VQKeyframePayload
655
+ ├── VQInterframePayload
656
+ ├── XYZQuantKeyframePayload
657
+ ├── XYZQuantInterframePayload
658
+ └── CombinedPayload
659
+
660
+ AbstractEncoder (ABC)
661
+ └── InterframeEncoder
662
+
663
+ AbstractDecoder (ABC)
664
+ └── InterframeDecoder
665
+
666
+ AbstractSerializer (ABC)
667
+ └── ZstdSerializer
668
+
669
+ AbstractDeserializer (ABC)
670
+ └── ZstdDeserializer
671
+
672
+ InterframeCodecInterface (ABC)
673
+ ├── VQInterframeCodecInterface
674
+ ├── XYZQuantInterframeCodecInterface
675
+ └── CombinedInterframeCodecInterface
676
+
677
+ InterframeEncoderInitConfig
678
+ ├── VQInterframeCodecConfig
679
+ ├── XYZQuantInterframeCodecConfig
680
+ └── CombinedInterframeEncoderInitConfig
681
+
682
+ InterframeCodecContext
683
+ ├── VQInterframeCodecContext
684
+ ├── XYZQuantInterframeCodecContext
685
+ └── CombinedInterframeCodecContext
686
+ ```
687
+
688
+ ## License
689
+
690
+ See [LICENSE](LICENSE) for details.