Ocean
Loading...
Searching...
No Matches
DataSerializer.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_IO_SERIALIZATION_DATA_SERIALIZER_H
9#define META_OCEAN_IO_SERIALIZATION_DATA_SERIALIZER_H
10
12
14#include "ocean/base/Thread.h"
15
16#include "ocean/io/Bitstream.h"
19
20#include <atomic>
21
22namespace Ocean
23{
24
25namespace IO
26{
27
28namespace Serialization
29{
30
31/**
32 * This class implements the base class for data serializers.
33 * Data serializers are used to serialize and deserialize data samples across multiple channels.<br>
34 * Each channel can have a different sample type, name, and content type, allowing heterogeneous data to be organized and streamed together.<br>
35 * The class provides a thread-based architecture where the actual serialization/deserialization happens asynchronously in a background thread.<br>
36 * Derived classes (InputDataSerializer and OutputDataSerializer) implement the specific read or write functionality.
37 * @ingroup ioserialization
38 */
39class OCEAN_IO_SERIALIZATION_EXPORT DataSerializer : protected Thread
40{
41 public:
42
43 /// Definition of a channel id.
44 using ChannelId = uint32_t;
45
46 /**
47 * Returns an invalid channel id.
48 * @return The invalid channel id
49 */
50 static constexpr ChannelId invalidChannelId();
51
52 /**
53 * This class holds channel configuration (sample type, name, and content type).
54 * A channel configuration uniquely identifies the type and purpose of a data channel without including the runtime channel id.<br>
55 * The sample type describes the class type of data samples (e.g., "DataSampleFrame"), the name provides a user-friendly identifier (e.g., "camera_left"), and the content type describes the semantic meaning of the data (e.g., "RGB_FRAME").
56 */
58 {
59 public:
60
61 /**
62 * Definition of a hash function for ChannelConfiguration objects.
63 */
64 struct Hash
65 {
66 /**
67 * Calculates the hash value for a given channel configuration.
68 * @param channelConfiguration The channel configuration for which the hash will be calculated
69 * @return The hash value
70 */
71 inline size_t operator()(const ChannelConfiguration& channelConfiguration) const;
72 };
73
74 public:
75
76 /**
77 * Creates a new invalid channel configuration.
78 */
80
81 /**
82 * Creates a new channel configuration with given sample type, name, and content type.
83 * @param sampleType The sample type
84 * @param name The name of the channel
85 * @param contentType The content type
86 */
87 inline ChannelConfiguration(const std::string& sampleType, const std::string& name, const std::string& contentType);
88
89 /**
90 * Returns the sample type.
91 * @return The sample type
92 */
93 inline const std::string& sampleType() const;
94
95 /**
96 * Returns the name of the channel.
97 * @return The channel name
98 */
99 inline const std::string& name() const;
100
101 /**
102 * Returns the content type.
103 * @return The content type
104 */
105 inline const std::string& contentType() const;
106
107 /**
108 * Returns whether this channel configuration is valid.
109 * @return True, if all fields (sample type, name, and content type) are non-empty
110 */
111 inline bool isValid() const;
112
113 /**
114 * Returns whether two channel configurations are equal.
115 * @param channelConfiguration The second channel configuration to compare
116 * @return True, if both configurations are equal
117 */
118 inline bool operator==(const ChannelConfiguration& channelConfiguration) const;
119
120 protected:
121
122 /// The sample type.
123 std::string sampleType_;
124
125 /// The name of the channel.
126 std::string name_;
127
128 /// The content type.
129 std::string contentType_;
130 };
131
132 /**
133 * This class implements a channel with configuration and channel id.
134 * A channel extends ChannelConfiguration by adding a unique channel id that is assigned at runtime during serialization.<br>
135 * The channel id is used to efficiently identify and route data samples within the serialization stream.
136 */
137 class OCEAN_IO_SERIALIZATION_EXPORT Channel : public ChannelConfiguration
138 {
139 public:
140
141 /**
142 * Definition of a hash function for Channel objects.
143 */
144 struct Hash
145 {
146 /**
147 * Calculates the hash value for a given channel.
148 * @param channel The channel for which the hash will be calculated
149 * @return The hash value
150 */
151 inline size_t operator()(const Channel& channel) const;
152 };
153
154 public:
155
156 /**
157 * Creates a new invalid channel.
158 */
159 Channel() = default;
160
161 /**
162 * Creates a new channel with given configuration and channel id.
163 * @param channelConfiguration The channel configuration
164 * @param channelId The channel id
165 */
166 inline Channel(const ChannelConfiguration& channelConfiguration, const ChannelId channelId);
167
168 /**
169 * Returns the channel id.
170 * @return The channel id
171 */
172 inline ChannelId channelId() const;
173
174 /**
175 * Returns whether this channel is valid.
176 * @return True, if the channel id is valid and the configuration is valid
177 */
178 inline bool isValid() const;
179
180 /**
181 * Returns whether two channels are equal.
182 * @param channel The second channel to compare
183 * @return True, if both channels are equal
184 */
185 inline bool operator==(const Channel& channel) const;
186
187 protected:
188
189 /// The channel id.
190 ChannelId channelId_ = invalidChannelId();
191 };
192
193 /// Definition of a vector holding channels.
194 using Channels = std::vector<Channel>;
195
196 protected:
197
198 /**
199 * Definition of individual states the serializer can have.
200 */
201 enum State
202 {
203 /// The serializer has not yet been initialized or started.
205 /// The serializer has been initialized and is ready to start.
207 /// The serializer has been started and is currently actively processing data samples.
209 /// The serializer is currently stopping but may still process remaining data samples.
211 /// The serializer has been stopped and all active processing of data samples has finished. However, there may still be samples left which could be requested by the user.
212 S_STOPPED
213 };
214
215 /// Definition of a map mapping channel configurations to channel ids.
216 using ChannelConfigurationMap = std::unordered_map<ChannelConfiguration, ChannelId, ChannelConfiguration::Hash>;
217
218 /// Definition of a pair holding a channel id and a unique data sample.
219 using SamplePair = std::pair<ChannelId, UniqueDataSample>;
220
221 /**
222 * This class implements a data sample holding channel configuration information.
223 * This internal class is used to serialize channel configuration as a special sample type, allowing the configuration to be embedded in the data stream alongside regular samples.<br>
224 * When a new channel is encountered during playback, the configuration sample is read first to establish the channel's metadata.
225 */
227 public DataSample,
229 {
230 public:
231
232 /**
233 * Creates a new invalid data sample channel configuration.
234 */
236
237 /**
238 * Creates a new data sample channel configuration from a data sample and channel configuration.
239 * @param sample The data sample
240 * @param channelConfiguration The channel configuration
241 */
242 inline explicit DataSampleChannelConfiguration(const DataSample& sample, const ChannelConfiguration& channelConfiguration);
243
244 /**
245 * Creates a new data sample channel configuration from a data timestamp and channel configuration.
246 * @param dataTimestamp The data timestamp
247 * @param channelConfiguration The channel configuration
248 * @param sampleCreationTimestamp The timestamp when the sample was created, this timestamp is not serialized and is only used to automatically determine the playback timestamp
249 */
250 inline explicit DataSampleChannelConfiguration(const DataTimestamp& dataTimestamp, const ChannelConfiguration& channelConfiguration, const Timestamp sampleCreationTimestamp = Timestamp(true));
251
252 /**
253 * Reads the sample from an input bitstream.
254 * @param inputBitstream The input bitstream from which the sample will be read
255 * @return True, if succeeded
256 */
257 inline bool readSample(InputBitstream& inputBitstream) override;
258
259 /**
260 * Writes the sample to an output bitstream.
261 * @param outputBitstream The output bitstream to which the sample will be written
262 * @return True, if succeeded
263 */
264 inline bool writeSample(OutputBitstream& outputBitstream) const override;
265
266 /**
267 * Returns the type of the sample.
268 * @return The sample type
269 */
270 inline const std::string& type() const override;
271 };
272
273 public:
274
275 /**
276 * Destructs the data serializer.
277 */
278 virtual ~DataSerializer() = default;
279
280 /**
281 * Starts the serializer.
282 * @return True, if succeeded
283 */
284 virtual bool start() = 0;
285
286 /**
287 * Stops the serializer.
288 * This function sets a stopping flag and returns immediately; it does not wait for the serializer to actually stop.
289 * The background thread will check the stopping flag and terminate asynchronously.
290 * Use stopAndWait() to wait until the serializer has fully stopped, or poll hasStopped() to check if it has stopped.
291 * @return True, if the stop request was accepted; False, if the serializer was not started
292 * @see stopAndWait(), hasStopped().
293 */
294 virtual bool stop() = 0;
295
296 /**
297 * Stops the serializer and waits until the serializer has stopped.
298 * @param timeout The timeout in seconds, with range (0, infinity)
299 * @return True, if the serializer stopped within the given timeout
300 */
301 virtual bool stopAndWait(const double timeout = 60.0);
302
303 /**
304 * Returns whether the serializer has been started.
305 * @return True, if so
306 */
307 [[nodiscard]] virtual bool isStarted() const = 0;
308
309 /**
310 * Returns whether the serializer has stopped but does not check whether remaining samples have not yet been processed or retrieved.
311 * @return True, if so
312 */
313 [[nodiscard]] virtual bool hasStopped() const;
314
315 /**
316 * Returns whether the serializer has stopped and all remaining samples have been processed or retrieved.
317 * @return True, if so
318 * @see DataSerializer::hasFinished().
319 */
320 [[nodiscard]] virtual bool hasFinished() const = 0;
321
322 protected:
323
324 /**
325 * Returns whether the given channel value has the configuration bit set.
326 * @param channelValue The channel value to check
327 * @return True, if the channel value is a configuration channel id
328 */
329 [[nodiscard]] static constexpr bool isConfigurationChannelId(const uint32_t channelValue);
330
331 /**
332 * Creates a configuration channel id from a regular channel id by setting the highest bit.
333 * @param channelId The channel id
334 * @return The configuration channel id
335 */
336 [[nodiscard]] static constexpr uint32_t makeConfigurationChannelId(const ChannelId channelId);
337
338 /**
339 * Extracts the channel id from a channel value by clearing the configuration bit.
340 * @param channelValue The channel value
341 * @return The channel id
342 */
343 [[nodiscard]] static constexpr ChannelId extractChannelId(const uint32_t channelValue);
344
345 protected:
346
347 /// The timestamp when the serializer was started.
349
350 /// The current state of the serializer.
351 State state_ = S_IDLE;
352
353 /// True, if the serializer succeeded; False, if an error occurred.
354 std::atomic<bool> succeeded_ = true;
355
356 /// The lock for thread-safe access.
357 mutable Lock lock_;
358};
359
364
366{
367 size_t seed = std::hash<std::string>()(channelConfiguration.sampleType_);
368 seed ^= std::hash<std::string>{}(channelConfiguration.name_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
369 seed ^= std::hash<std::string>{}(channelConfiguration.contentType_) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
370
371 return seed;
372}
373
374inline DataSerializer::ChannelConfiguration::ChannelConfiguration(const std::string& sampleType, const std::string& name, const std::string& contentType) :
376 name_(name),
378{
379 // nothing to do here
380}
381
383{
384 return sampleType_;
385}
386
387inline const std::string& DataSerializer::ChannelConfiguration::name() const
388{
389 return name_;
390}
391
393{
394 return contentType_;
395}
396
398{
399 return !sampleType_.empty() && !name_.empty() && !contentType_.empty();
400}
401
402inline bool DataSerializer::ChannelConfiguration::operator==(const ChannelConfiguration& channelConfiguration) const
403{
404 return sampleType_ == channelConfiguration.sampleType_ && name_ == channelConfiguration.name_ && contentType_ == channelConfiguration.contentType_;
405}
406
407inline size_t DataSerializer::Channel::Hash::operator()(const Channel& channel) const
408{
409 size_t seed = std::hash<uint32_t>()(channel.channelId_);
410 seed ^= ChannelConfiguration::Hash{}(channel) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
411
412 return seed;
413}
414
415inline DataSerializer::Channel::Channel(const ChannelConfiguration& channelConfiguration, const ChannelId channelId) :
416 ChannelConfiguration(channelConfiguration),
417 channelId_(channelId)
418{
419 // nothing to do here
420}
421
423{
424 return channelId_;
425}
426
428{
429 return channelId_ != invalidChannelId() && ChannelConfiguration::isValid();
430}
431
432inline bool DataSerializer::Channel::operator==(const Channel& channel) const
433{
434 return channelId_ == channel.channelId_ && ChannelConfiguration::operator==(channel);
435}
436
437constexpr bool DataSerializer::isConfigurationChannelId(const uint32_t channelValue)
438{
439 constexpr uint32_t highestBit = 1u << 31u;
440
441 return channelValue & highestBit;
442}
443
444constexpr uint32_t DataSerializer::makeConfigurationChannelId(const ChannelId channelId)
445{
446 ocean_assert(channelId != invalidChannelId());
447 ocean_assert(!isConfigurationChannelId(channelId));
448
449 constexpr uint32_t highestBit = 1u << 31u;
450
451 return channelId | highestBit;
452}
453
455{
456 constexpr uint32_t highestBit = 1u << 31u;
457
458 return ChannelId(channelValue & ~highestBit);
459}
460
462 DataSample(sample),
463 ChannelConfiguration(channelConfiguration)
464{
465 // nothing to do here
466}
467
468inline DataSerializer::DataSampleChannelConfiguration::DataSampleChannelConfiguration(const DataTimestamp& dataTimestamp, const ChannelConfiguration& channelConfiguration, const Timestamp sampleCreationTimestamp) :
469 DataSample(dataTimestamp, sampleCreationTimestamp),
470 ChannelConfiguration(channelConfiguration)
471{
472 // nothing to do here
473}
474
476{
477 if (!DataSample::readSample(inputBitstream))
478 {
479 return false;
480 }
481
482 return inputBitstream.read<std::string>(sampleType_) && inputBitstream.read<std::string>(name_) && inputBitstream.read<std::string>(contentType_);
483}
484
486{
487 if (!DataSample::writeSample(outputBitstream))
488 {
489 return false;
490 }
491
492 return outputBitstream.write<std::string>(sampleType_) && outputBitstream.write<std::string>(name_) && outputBitstream.write<std::string>(contentType_);
493}
494
496{
497 return sampleType_;
498}
499
500}
501
502}
503
504}
505
506#endif // META_OCEAN_IO_SERIALIZATION_DATA_SERIALIZER_H
This class implements an input bitstream.
Definition Bitstream.h:51
bool read(T &value)
Reads a value from the bitstream and moves the internal position inside the bitstream accordingly.
This class implements an output bitstream.
Definition Bitstream.h:215
bool write(const T &value)
Writes a data object to the stream and moves the internal position inside the bitstream accordingly.
This class implements a base class for data samples.
Definition DataSample.h:50
virtual bool readSample(InputBitstream &inputBitstream)
Reads the sample from an input bitstream.
virtual bool writeSample(OutputBitstream &outputBitstream) const
Writes the sample to an output bitstream.
This class holds channel configuration (sample type, name, and content type).
Definition DataSerializer.h:58
bool operator==(const ChannelConfiguration &channelConfiguration) const
Returns whether two channel configurations are equal.
Definition DataSerializer.h:402
std::string name_
The name of the channel.
Definition DataSerializer.h:126
std::string contentType_
The content type.
Definition DataSerializer.h:129
ChannelConfiguration()=default
Creates a new invalid channel configuration.
bool isValid() const
Returns whether this channel configuration is valid.
Definition DataSerializer.h:397
const std::string & sampleType() const
Returns the sample type.
Definition DataSerializer.h:382
const std::string & contentType() const
Returns the content type.
Definition DataSerializer.h:392
const std::string & name() const
Returns the name of the channel.
Definition DataSerializer.h:387
std::string sampleType_
The sample type.
Definition DataSerializer.h:123
This class implements a channel with configuration and channel id.
Definition DataSerializer.h:138
Channel()=default
Creates a new invalid channel.
bool operator==(const Channel &channel) const
Returns whether two channels are equal.
Definition DataSerializer.h:432
ChannelId channelId() const
Returns the channel id.
Definition DataSerializer.h:422
bool isValid() const
Returns whether this channel is valid.
Definition DataSerializer.h:427
ChannelId channelId_
The channel id.
Definition DataSerializer.h:190
This class implements a data sample holding channel configuration information.
Definition DataSerializer.h:229
bool readSample(InputBitstream &inputBitstream) override
Reads the sample from an input bitstream.
Definition DataSerializer.h:475
DataSampleChannelConfiguration()=default
Creates a new invalid data sample channel configuration.
bool writeSample(OutputBitstream &outputBitstream) const override
Writes the sample to an output bitstream.
Definition DataSerializer.h:485
const std::string & type() const override
Returns the type of the sample.
Definition DataSerializer.h:495
This class implements the base class for data serializers.
Definition DataSerializer.h:40
static constexpr uint32_t makeConfigurationChannelId(const ChannelId channelId)
Creates a configuration channel id from a regular channel id by setting the highest bit.
Definition DataSerializer.h:444
static constexpr ChannelId invalidChannelId()
Returns an invalid channel id.
Definition DataSerializer.h:360
std::unordered_map< ChannelConfiguration, ChannelId, ChannelConfiguration::Hash > ChannelConfigurationMap
Definition of a map mapping channel configurations to channel ids.
Definition DataSerializer.h:216
Timestamp startTimestamp_
The timestamp when the serializer was started.
Definition DataSerializer.h:348
virtual bool hasStopped() const
Returns whether the serializer has stopped but does not check whether remaining samples have not yet ...
std::pair< ChannelId, UniqueDataSample > SamplePair
Definition of a pair holding a channel id and a unique data sample.
Definition DataSerializer.h:219
std::vector< Channel > Channels
Definition of a vector holding channels.
Definition DataSerializer.h:194
Lock lock_
The lock for thread-safe access.
Definition DataSerializer.h:357
static constexpr bool isConfigurationChannelId(const uint32_t channelValue)
Returns whether the given channel value has the configuration bit set.
Definition DataSerializer.h:437
virtual bool start()=0
Starts the serializer.
virtual bool stop()=0
Stops the serializer.
virtual bool isStarted() const =0
Returns whether the serializer has been started.
uint32_t ChannelId
Definition of a channel id.
Definition DataSerializer.h:44
virtual bool stopAndWait(const double timeout=60.0)
Stops the serializer and waits until the serializer has stopped.
State
Definition of individual states the serializer can have.
Definition DataSerializer.h:202
@ S_IDLE
The serializer has not yet been initialized or started.
Definition DataSerializer.h:204
@ S_INITIALIZED
The serializer has been initialized and is ready to start.
Definition DataSerializer.h:206
@ S_STARTED
The serializer has been started and is currently actively processing data samples.
Definition DataSerializer.h:208
@ S_STOPPING
The serializer is currently stopping but may still process remaining data samples.
Definition DataSerializer.h:210
virtual ~DataSerializer()=default
Destructs the data serializer.
virtual bool hasFinished() const =0
Returns whether the serializer has stopped and all remaining samples have been processed or retrieved...
static constexpr ChannelId extractChannelId(const uint32_t channelValue)
Extracts the channel id from a channel value by clearing the configuration bit.
Definition DataSerializer.h:454
This class implements a data timestamp which can hold either a double or int64_t value.
Definition DataTimestamp.h:32
This class implements a recursive lock object.
Definition Lock.h:31
This class implements a thread.
Definition Thread.h:115
This class implements a timestamp.
Definition Timestamp.h:64
The namespace covering the entire Ocean framework.
Definition Accessor.h:15
Definition of a hash function for Channel objects.
Definition DataSerializer.h:145
size_t operator()(const Channel &channel) const
Calculates the hash value for a given channel.
Definition DataSerializer.h:407
Definition of a hash function for ChannelConfiguration objects.
Definition DataSerializer.h:65
size_t operator()(const ChannelConfiguration &channelConfiguration) const
Calculates the hash value for a given channel configuration.
Definition DataSerializer.h:365