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,271 @@
1
+ from dataclasses import dataclass
2
+ from typing import List, Self
3
+
4
+ from gaussian_splatting import GaussianModel
5
+
6
+ from ..payload import Payload
7
+ from .interface import (
8
+ InterframeCodecInterface,
9
+ InterframeCodecContext,
10
+ InterframeEncoderInitConfig,
11
+ )
12
+
13
+
14
+ @dataclass
15
+ class CombinedPayload(Payload):
16
+ """
17
+ Combined payload containing multiple sub-codec payloads.
18
+ """
19
+ payloads: List[Payload]
20
+
21
+ def to(self, device) -> Self:
22
+ """
23
+ Move the Payload to the specified device.
24
+
25
+ Args:
26
+ device: The target device (e.g., 'cpu', 'cuda', torch.device).
27
+
28
+ Returns:
29
+ A new CombinedPayload instance with all sub-payloads on the target device.
30
+ """
31
+ return CombinedPayload(
32
+ payloads=[p.to(device) for p in self.payloads],
33
+ )
34
+
35
+
36
+ @dataclass
37
+ class CombinedInterframeEncoderInitConfig(InterframeEncoderInitConfig):
38
+ """
39
+ Combined encoder initialization configuration containing multiple sub-codec configs.
40
+ """
41
+ init_configs: List[InterframeEncoderInitConfig]
42
+
43
+
44
+ @dataclass
45
+ class CombinedInterframeCodecContext(InterframeCodecContext):
46
+ """
47
+ Combined context containing multiple sub-codec contexts.
48
+ """
49
+ contexts: List[InterframeCodecContext]
50
+
51
+
52
+ class CombinedInterframeCodecInterface(InterframeCodecInterface):
53
+ """
54
+ A codec that combines multiple InterframeCodecInterface instances.
55
+
56
+ Each method calls the corresponding method on all sub-codecs and combines
57
+ their outputs.
58
+ """
59
+
60
+ def __init__(self, interfaces: List[InterframeCodecInterface]):
61
+ """
62
+ Initialize the combined codec with a list of sub-codecs.
63
+
64
+ Args:
65
+ interfaces: List of InterframeCodecInterface instances to combine.
66
+ """
67
+ if not interfaces:
68
+ raise ValueError("At least one interface must be provided")
69
+ self.interfaces = interfaces
70
+
71
+ def decode_interframe(
72
+ self, payload: CombinedPayload, prev_context: CombinedInterframeCodecContext
73
+ ) -> CombinedInterframeCodecContext:
74
+ """
75
+ Decode a delta payload to reconstruct the next frame's context.
76
+
77
+ Calls decode_interframe on all sub-codecs and combines their contexts.
78
+
79
+ Args:
80
+ payload: The delta payload containing individual payloads for each sub-codec.
81
+ prev_context: The context of the previous frame containing individual contexts for each sub-codec.
82
+
83
+ Returns:
84
+ A CombinedInterframeCodecContext containing all sub-codec contexts.
85
+ """
86
+ # Call decode_interframe on each sub-codec
87
+ contexts = []
88
+ for interface, payload, prev_context in zip(self.interfaces, payload.payloads, prev_context.contexts):
89
+ context = interface.decode_interframe(payload, prev_context)
90
+ contexts.append(context)
91
+ return CombinedInterframeCodecContext(contexts=contexts)
92
+
93
+ def encode_interframe(
94
+ self,
95
+ prev_context: CombinedInterframeCodecContext,
96
+ next_context: CombinedInterframeCodecContext,
97
+ ) -> CombinedPayload:
98
+ """
99
+ Encode the difference between two consecutive frames.
100
+
101
+ Calls encode_interframe on all sub-codecs and combines their payloads.
102
+
103
+ Args:
104
+ prev_context: The context of the previous frame containing individual contexts for each sub-codec.
105
+ next_context: The context of the next frame containing individual contexts for each sub-codec.
106
+
107
+ Returns:
108
+ A CombinedPayload containing all sub-codec payloads.
109
+ """
110
+ # Call encode_interframe on each sub-codec
111
+ payloads = []
112
+ for interface, prev_context, next_context in zip(self.interfaces, prev_context.contexts, next_context.contexts):
113
+ payload = interface.encode_interframe(prev_context, next_context)
114
+ payloads.append(payload)
115
+ return CombinedPayload(payloads=payloads)
116
+
117
+ def decode_keyframe(self, payload: CombinedPayload) -> CombinedInterframeCodecContext:
118
+ """
119
+ Decode a keyframe payload to create initial context.
120
+
121
+ Calls decode_keyframe on all sub-codecs and combines their contexts.
122
+
123
+ Args:
124
+ payload: The keyframe payload containing individual payloads for each sub-codec.
125
+
126
+ Returns:
127
+ A CombinedInterframeCodecContext containing all sub-codec contexts.
128
+ """
129
+ # Call decode_keyframe on each sub-codec
130
+ contexts = []
131
+ for interface, payload in zip(self.interfaces, payload.payloads):
132
+ context = interface.decode_keyframe(payload)
133
+ contexts.append(context)
134
+ return CombinedInterframeCodecContext(contexts=contexts)
135
+
136
+ def decode_keyframe_for_encode(
137
+ self, payload: CombinedPayload, context: CombinedInterframeCodecContext
138
+ ) -> CombinedInterframeCodecContext:
139
+ """
140
+ Decode a keyframe payload during encoding to avoid error accumulation.
141
+
142
+ Calls decode_keyframe_for_encode on all sub-codecs and combines their contexts.
143
+
144
+ Args:
145
+ payload: The keyframe payload containing individual payloads for each sub-codec.
146
+ context: The original context containing individual contexts for each sub-codec.
147
+
148
+ Returns:
149
+ A CombinedInterframeCodecContext containing all sub-codec reconstructed contexts.
150
+ """
151
+ # Call decode_keyframe_for_encode on each sub-codec
152
+ contexts = []
153
+ for interface, sub_payload, sub_context in zip(
154
+ self.interfaces, payload.payloads, context.contexts
155
+ ):
156
+ reconstructed = interface.decode_keyframe_for_encode(sub_payload, sub_context)
157
+ contexts.append(reconstructed)
158
+ return CombinedInterframeCodecContext(contexts=contexts)
159
+
160
+ def decode_interframe_for_encode(
161
+ self, payload: CombinedPayload, prev_context: CombinedInterframeCodecContext
162
+ ) -> CombinedInterframeCodecContext:
163
+ """
164
+ Decode an interframe payload during encoding to avoid error accumulation.
165
+
166
+ Calls decode_interframe_for_encode on all sub-codecs and combines their contexts.
167
+
168
+ Args:
169
+ payload: The interframe payload containing individual payloads for each sub-codec.
170
+ prev_context: The previous context containing individual contexts for each sub-codec.
171
+
172
+ Returns:
173
+ A CombinedInterframeCodecContext containing all sub-codec reconstructed contexts.
174
+ """
175
+ # Call decode_interframe_for_encode on each sub-codec
176
+ contexts = []
177
+ for interface, sub_payload, sub_prev_context in zip(
178
+ self.interfaces, payload.payloads, prev_context.contexts
179
+ ):
180
+ reconstructed = interface.decode_interframe_for_encode(sub_payload, sub_prev_context)
181
+ contexts.append(reconstructed)
182
+ return CombinedInterframeCodecContext(contexts=contexts)
183
+
184
+ def encode_keyframe(
185
+ self, context: CombinedInterframeCodecContext
186
+ ) -> CombinedPayload:
187
+ """
188
+ Encode the first frame as a keyframe.
189
+
190
+ Calls encode_keyframe on all sub-codecs and combines their payloads.
191
+
192
+ Args:
193
+ context: The context of the first frame containing individual contexts for each sub-codec.
194
+
195
+ Returns:
196
+ A CombinedPayload containing all sub-codec payloads.
197
+ """
198
+ # Call encode_keyframe on each sub-codec
199
+ payloads = []
200
+ for interface, context in zip(self.interfaces, context.contexts):
201
+ payload = interface.encode_keyframe(context)
202
+ payloads.append(payload)
203
+ return CombinedPayload(payloads=payloads)
204
+
205
+ def keyframe_to_context(
206
+ self, frame: GaussianModel, init_config: CombinedInterframeEncoderInitConfig
207
+ ) -> CombinedInterframeCodecContext:
208
+ """
209
+ Convert a keyframe to a Context.
210
+
211
+ Calls keyframe_to_context on all sub-codecs and combines their contexts.
212
+
213
+ Args:
214
+ frame: The GaussianModel frame to convert.
215
+ init_config: Encoder initialization configuration containing individual configs for each sub-codec.
216
+
217
+ Returns:
218
+ A CombinedInterframeCodecContext containing all sub-codec contexts.
219
+ """
220
+ # Call keyframe_to_context on each sub-codec
221
+ contexts = []
222
+ for interface, init_config in zip(self.interfaces, init_config.init_configs):
223
+ context = interface.keyframe_to_context(frame, init_config)
224
+ contexts.append(context)
225
+ return CombinedInterframeCodecContext(contexts=contexts)
226
+
227
+ def interframe_to_context(
228
+ self,
229
+ frame: GaussianModel,
230
+ prev_context: CombinedInterframeCodecContext,
231
+ ) -> CombinedInterframeCodecContext:
232
+ """
233
+ Convert a frame to a Context using the previous context as reference.
234
+
235
+ Calls interframe_to_context on all sub-codecs and combines their contexts.
236
+
237
+ Args:
238
+ frame: The GaussianModel frame to convert.
239
+ prev_context: The context from the previous frame containing individual contexts for each sub-codec.
240
+
241
+ Returns:
242
+ A CombinedInterframeCodecContext containing all sub-codec contexts.
243
+ """
244
+ # Call interframe_to_context on each sub-codec
245
+ contexts = []
246
+ for interface, prev_context in zip(self.interfaces, prev_context.contexts):
247
+ context = interface.interframe_to_context(frame, prev_context)
248
+ contexts.append(context)
249
+ return CombinedInterframeCodecContext(contexts=contexts)
250
+
251
+ def context_to_frame(
252
+ self, context: CombinedInterframeCodecContext, frame: GaussianModel
253
+ ) -> GaussianModel:
254
+ """
255
+ Convert a Context back to a frame.
256
+
257
+ Calls context_to_frame on all sub-codecs sequentially, applying each
258
+ context to the frame in order.
259
+
260
+ Args:
261
+ context: The Context to convert containing individual contexts for each sub-codec.
262
+ frame: An empty GaussianModel or one from previous pipeline steps.
263
+ This frame will be modified in-place by each sub-codec.
264
+
265
+ Returns:
266
+ The modified GaussianModel with the frame data.
267
+ """
268
+ # Apply each context sequentially to the frame
269
+ for interface, context in zip(self.interfaces, context.contexts):
270
+ frame = interface.context_to_frame(context, frame)
271
+ return frame
@@ -0,0 +1,99 @@
1
+ from typing import Iterator, Optional
2
+
3
+ import torch
4
+
5
+ from gaussian_splatting import GaussianModel
6
+
7
+ from ..decoder import AbstractDecoder
8
+ from ..deserializer import AbstractDeserializer
9
+ from ..payload import Payload
10
+ from .interface import InterframeCodecContext, InterframeCodecInterface
11
+
12
+
13
+ class InterframeDecoder(AbstractDecoder):
14
+ """
15
+ Decoder that uses inter-frame decompression.
16
+
17
+ This decoder maintains an internal Context state and decodes frames
18
+ by applying deltas to the previous frame's context. The first frame
19
+ is decoded as a keyframe, and subsequent frames are decoded as deltas.
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ deserializer: AbstractDeserializer,
25
+ interface: InterframeCodecInterface,
26
+ payload_device: str | torch.device | None = None,
27
+ device: str | torch.device | None = None,
28
+ ):
29
+ """
30
+ Initialize the inter-frame decoder.
31
+
32
+ Args:
33
+ deserializer: The deserializer to use for converting bytes to Payload.
34
+ interface: The InterframeCodecInterface instance that provides decoding methods.
35
+ payload_device: The target device for input Payloads before
36
+ unpacking (e.g., 'cpu', 'cuda'). If None, no device
37
+ transfer is performed.
38
+ device: The target device for output GaussianModel frames
39
+ (e.g., 'cpu', 'cuda'). If None, no device transfer is performed.
40
+ """
41
+ super().__init__(deserializer, payload_device, device)
42
+ self._interface = interface
43
+ self._prev_context: Optional[InterframeCodecContext] = None
44
+
45
+ def create_empty_frame(self) -> GaussianModel:
46
+ """
47
+ Create an empty GaussianModel for frame reconstruction.
48
+
49
+ This method is called before `context_to_frame` to provide a frame
50
+ that will be populated with data. Override this method if your
51
+ GaussianModel contains custom data or attributes that are not part of
52
+ the standard GaussianModel(), such as additional fields or custom
53
+ initialization logic.
54
+
55
+ Returns:
56
+ An empty GaussianModel instance.
57
+ """
58
+ return GaussianModel(sh_degree=3)
59
+
60
+ def unpack(self, payload: Payload) -> Iterator[GaussianModel]:
61
+ """
62
+ Unpack frame(s) from a Payload using inter-frame decoding.
63
+
64
+ The first payload is decoded as a keyframe. Subsequent payloads
65
+ are decoded as deltas from the previous frame.
66
+
67
+ Args:
68
+ payload: A Payload instance to unpack.
69
+
70
+ Yields:
71
+ Unpacked GaussianModel instances.
72
+ """
73
+ if self._prev_context is None:
74
+ # First frame: decode as keyframe
75
+ current_context = self._interface.decode_keyframe(payload)
76
+ else:
77
+ # Subsequent frames: decode as delta from previous
78
+ current_context = self._interface.decode_interframe(
79
+ payload, self._prev_context
80
+ )
81
+
82
+ # Update the previous context for next frame
83
+ self._prev_context = current_context
84
+
85
+ # Convert context back to frame
86
+ frame = self.create_empty_frame()
87
+ yield self._interface.context_to_frame(current_context, frame)
88
+
89
+ def flush_unpack(self) -> Iterator[GaussianModel]:
90
+ """
91
+ Flush any remaining buffered frames from the unpacking stage.
92
+
93
+ For inter-frame decoding, there are no buffered frames to flush.
94
+
95
+ Yields:
96
+ No frames (empty iterator).
97
+ """
98
+ return
99
+ yield # Make this a generator
@@ -0,0 +1,92 @@
1
+ from typing import Iterator, Optional
2
+
3
+ from gaussian_splatting import GaussianModel
4
+
5
+ from ..encoder import AbstractEncoder
6
+ from ..payload import Payload
7
+ from ..serializer import AbstractSerializer
8
+ from .interface import InterframeCodecContext, InterframeEncoderInitConfig, InterframeCodecInterface
9
+
10
+
11
+ class InterframeEncoder(AbstractEncoder):
12
+ """
13
+ Encoder that uses inter-frame compression.
14
+
15
+ This encoder maintains an internal Context state and encodes frames
16
+ as differences from the previous frame. The first frame is encoded
17
+ as a keyframe, and subsequent frames are encoded as deltas.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ serializer: AbstractSerializer,
23
+ interface: InterframeCodecInterface,
24
+ init_config: InterframeEncoderInitConfig,
25
+ payload_device=None,
26
+ ):
27
+ """
28
+ Initialize the inter-frame encoder.
29
+
30
+ Args:
31
+ serializer: The serializer to use for converting Payload to bytes.
32
+ interface: The InterframeCodecInterface instance that provides encoding methods.
33
+ init_config: Configuration parameters for keyframe initialization.
34
+ payload_device: The target device for encoded Payloads before
35
+ serialization (e.g., 'cpu', 'cuda'). If None, no device
36
+ transfer is performed.
37
+ """
38
+ super().__init__(serializer, payload_device)
39
+ self._interface = interface
40
+ self._init_config = init_config
41
+ self._prev_context: Optional[InterframeCodecContext] = None
42
+
43
+ def pack(self, frame: GaussianModel) -> Iterator[Payload]:
44
+ """
45
+ Pack a single frame into Payload objects using inter-frame encoding.
46
+
47
+ The first frame is encoded as a keyframe. Subsequent frames are
48
+ encoded as deltas from the previous frame.
49
+
50
+ Args:
51
+ frame: A GaussianModel instance to pack.
52
+
53
+ Yields:
54
+ Packed Payload instances.
55
+ """
56
+ if self._prev_context is None:
57
+ # First frame: convert and encode as keyframe
58
+ current_context = self._interface.keyframe_to_context(frame, self._init_config)
59
+ payload = self._interface.encode_keyframe(current_context)
60
+ # Decode back to get reconstructed context (avoid error accumulation)
61
+ reconstructed_context = self._interface.decode_keyframe_for_encode(
62
+ payload, current_context
63
+ )
64
+ else:
65
+ # Subsequent frames: convert and encode as delta from previous
66
+ current_context = self._interface.interframe_to_context(
67
+ frame, self._prev_context
68
+ )
69
+ payload = self._interface.encode_interframe(
70
+ self._prev_context, current_context
71
+ )
72
+ # Decode back to get reconstructed context (avoid error accumulation)
73
+ reconstructed_context = self._interface.decode_interframe_for_encode(
74
+ payload, self._prev_context
75
+ )
76
+
77
+ # Use reconstructed context as previous for next frame
78
+ self._prev_context = reconstructed_context
79
+
80
+ yield payload
81
+
82
+ def flush_pack(self) -> Iterator[Payload]:
83
+ """
84
+ Flush any remaining buffered payloads from the packing stage.
85
+
86
+ For inter-frame encoding, there are no buffered payloads to flush.
87
+
88
+ Yields:
89
+ No payloads (empty iterator).
90
+ """
91
+ return
92
+ yield # Make this a generator
@@ -0,0 +1,221 @@
1
+ from abc import ABC, abstractmethod
2
+ from dataclasses import dataclass
3
+
4
+ from gaussian_splatting import GaussianModel
5
+
6
+ from ..payload import Payload
7
+
8
+
9
+ @dataclass
10
+ class InterframeEncoderInitConfig:
11
+ """
12
+ Configuration for initializing the encoder when encoding the first frame (keyframe).
13
+
14
+ This dataclass is passed to `keyframe_to_context()` when the encoder processes
15
+ the first frame. It contains encoder-specific settings that determine how the
16
+ encoding context is initialized, such as quality settings, compression levels,
17
+ or algorithm parameters.
18
+
19
+ Subclasses should define specific fields for their encoding scheme.
20
+
21
+ Note:
22
+ This config is only used by the encoder during keyframe processing.
23
+ Configurations shared by both encoder and decoder should be stored
24
+ in InterframeCodecInterface.
25
+ """
26
+ pass
27
+
28
+
29
+ @dataclass
30
+ class InterframeCodecContext:
31
+ """
32
+ Context data for inter-frame encoding/decoding.
33
+
34
+ This dataclass holds the state information needed to encode/decode
35
+ frames relative to a reference frame. Both encoder and decoder
36
+ maintain their own InterframeCodecContext instances.
37
+
38
+ Subclasses should define specific fields for their encoding scheme.
39
+
40
+ Note:
41
+ This is for encoder/decoder runtime state (e.g., reference frame data,
42
+ accumulated statistics). Encoder initialization config should be stored
43
+ in InterframeEncoderInitConfig. Shared configurations should be stored
44
+ in InterframeCodecInterface.
45
+ """
46
+ pass
47
+
48
+
49
+ class InterframeCodecInterface(ABC):
50
+ """
51
+ Abstract interface for inter-frame encoding/decoding algorithms.
52
+
53
+ This interface defines the methods required to implement inter-frame
54
+ compression, where frames are encoded as differences from previous frames.
55
+
56
+ Design Guidelines:
57
+ - InterframeCodecInterface: Store configurations shared by both encoder
58
+ and decoder (e.g., algorithm parameters that affect both encoding and
59
+ decoding, such as quantization tables or codebook sizes).
60
+ - InterframeCodecContext: Store encoder/decoder runtime state (e.g.,
61
+ reference frame data, accumulated statistics). Each side maintains
62
+ its own context instance.
63
+ - InterframeEncoderInitConfig: Store encoder initialization config that
64
+ is passed to `keyframe_to_context()` when encoding the first frame
65
+ (e.g., quality settings, compression levels).
66
+ """
67
+
68
+ @abstractmethod
69
+ def decode_interframe(self, payload: Payload, prev_context: InterframeCodecContext) -> InterframeCodecContext:
70
+ """
71
+ Decode a delta payload to reconstruct the next frame's context.
72
+
73
+ Args:
74
+ payload: The delta payload containing the difference data.
75
+ prev_context: The context of the previous frame.
76
+
77
+ Returns:
78
+ The reconstructed context for the current frame.
79
+ """
80
+ pass
81
+
82
+ @abstractmethod
83
+ def encode_interframe(self, prev_context: InterframeCodecContext, next_context: InterframeCodecContext) -> Payload:
84
+ """
85
+ Encode the difference between two consecutive frames.
86
+
87
+ Args:
88
+ prev_context: The context of the previous frame.
89
+ next_context: The context of the next frame.
90
+
91
+ Returns:
92
+ A payload containing the delta information.
93
+ """
94
+ pass
95
+
96
+ @abstractmethod
97
+ def decode_keyframe(self, payload: Payload) -> InterframeCodecContext:
98
+ """
99
+ Decode a keyframe payload to create initial context.
100
+
101
+ Args:
102
+ payload: The keyframe payload containing full frame data.
103
+
104
+ Returns:
105
+ The context for the first/key frame.
106
+ """
107
+ pass
108
+
109
+ @abstractmethod
110
+ def decode_keyframe_for_encode(self, payload: Payload, context: InterframeCodecContext) -> InterframeCodecContext:
111
+ """
112
+ Decode a keyframe payload during encoding to avoid error accumulation.
113
+
114
+ This method is used by the encoder after encoding a keyframe. It decodes
115
+ the payload back to get the reconstructed context that the decoder would
116
+ produce, which should be used as the reference for encoding subsequent
117
+ frames instead of the original context.
118
+
119
+ Unlike `decode_keyframe()`, this method may reuse data from the original
120
+ encoding context (passed as `context`) for efficiency, since certain
121
+ information may not need to be re-decoded during encoding.
122
+
123
+ Args:
124
+ payload: The keyframe payload that was just encoded.
125
+ context: The original context used for encoding this keyframe.
126
+
127
+ Returns:
128
+ The reconstructed context as the decoder would produce it.
129
+ """
130
+ pass
131
+
132
+ def decode_interframe_for_encode(
133
+ self, payload: Payload, prev_context: InterframeCodecContext
134
+ ) -> InterframeCodecContext:
135
+ """
136
+ Decode an interframe payload during encoding to avoid error accumulation.
137
+
138
+ This method is used by the encoder after encoding an interframe. It decodes
139
+ the payload back to get the reconstructed context that the decoder would
140
+ produce, which should be used as the reference for encoding subsequent
141
+ frames instead of the original context.
142
+
143
+ Unlike `decode_interframe()`, this method may reuse data from the previous
144
+ context for efficiency, since certain information (like codec parameters)
145
+ can be obtained from the context without re-decoding from the payload.
146
+
147
+ Args:
148
+ payload: The interframe payload that was just encoded.
149
+ prev_context: The previous frame's context (reconstructed version).
150
+
151
+ Returns:
152
+ The reconstructed context as the decoder would produce it.
153
+ """
154
+ return self.decode_interframe(payload, prev_context)
155
+
156
+ @abstractmethod
157
+ def encode_keyframe(self, context: InterframeCodecContext) -> Payload:
158
+ """
159
+ Encode the first frame as a keyframe.
160
+
161
+ Args:
162
+ context: The context of the first frame.
163
+
164
+ Returns:
165
+ A payload containing the full keyframe data.
166
+ """
167
+ pass
168
+
169
+ @abstractmethod
170
+ def keyframe_to_context(self, frame: GaussianModel, init_config: InterframeEncoderInitConfig) -> InterframeCodecContext:
171
+ """
172
+ Convert a keyframe to a Context.
173
+
174
+ This method is called by the encoder when processing the first frame.
175
+ The init_config provides encoder-specific settings for initializing
176
+ the encoding context.
177
+
178
+ Args:
179
+ frame: The GaussianModel frame to convert.
180
+ init_config: Encoder initialization configuration.
181
+
182
+ Returns:
183
+ The corresponding Context representation.
184
+ """
185
+ pass
186
+
187
+ @abstractmethod
188
+ def interframe_to_context(
189
+ self,
190
+ frame: GaussianModel,
191
+ prev_context: InterframeCodecContext,
192
+ ) -> InterframeCodecContext:
193
+ """
194
+ Convert a frame to a Context using the previous context as reference.
195
+
196
+ Args:
197
+ frame: The GaussianModel frame to convert.
198
+ prev_context: The context from the previous frame.
199
+
200
+ Returns:
201
+ The corresponding Context representation.
202
+ """
203
+ pass
204
+
205
+ @abstractmethod
206
+ def context_to_frame(self, context: InterframeCodecContext, frame: GaussianModel) -> GaussianModel:
207
+ """
208
+ Convert a Context back to a frame.
209
+
210
+ This method populates the provided GaussianModel with data from the
211
+ context and returns it.
212
+
213
+ Args:
214
+ context: The Context to convert.
215
+ frame: An empty GaussianModel or one from previous pipeline steps.
216
+ This frame will be modified in-place with the context data.
217
+
218
+ Returns:
219
+ The modified GaussianModel with the frame data.
220
+ """
221
+ pass