libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
mediaduration.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <cstddef>
14#include <iterator>
15#include <promeki/namespace.h>
16#include <promeki/string.h>
17#include <promeki/error.h>
18#include <promeki/result.h>
19#include <promeki/framenumber.h>
20#include <promeki/framecount.h>
21#include <promeki/datatype.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
25class DataStream;
26
62class MediaDuration {
63 public:
64 PROMEKI_DATATYPE(MediaDuration, DataTypeMediaDuration, 1)
65
66
67 Error writeToStream(DataStream &s) const;
69 template <uint32_t V> static Result<MediaDuration> readFromStream(DataStream &s);
70
79 struct FrameRange {
80 FrameNumber start;
81 FrameNumber end;
82
92 class Iterator {
93 public:
94 using iterator_category = std::forward_iterator_tag;
95 using value_type = FrameNumber;
96 using difference_type = std::ptrdiff_t;
97 using pointer = const FrameNumber *;
98 using reference = const FrameNumber &;
99
100 Iterator() = default;
101 explicit Iterator(const FrameNumber &v) : _cur(v) {}
102
103 reference operator*() const { return _cur; }
104 pointer operator->() const { return &_cur; }
105 Iterator &operator++() {
106 ++_cur;
107 return *this;
108 }
109 Iterator operator++(int) {
110 Iterator o = *this;
111 ++_cur;
112 return o;
113 }
114 bool operator==(const Iterator &other) const {
115 return _cur == other._cur;
116 }
117 bool operator!=(const Iterator &other) const {
118 return _cur != other._cur;
119 }
120
121 private:
122 FrameNumber _cur;
123 };
124
126 FrameRange() = default;
127
131 FrameRange(const FrameNumber &s, const FrameNumber &e) : start(s), end(e) {}
132
134 bool isValid() const {
135 return start.isValid() && end.isValid() && end.value() >= start.value();
136 }
137
144 FrameCount count() const {
145 if (!isValid()) return FrameCount::unknown();
146 return FrameCount(end.value() - start.value() + 1);
147 }
148
158 bool contains(const FrameNumber &frame) const {
159 if (!isValid() || !frame.isValid()) return false;
160 return frame.value() >= start.value() && frame.value() <= end.value();
161 }
162
164 bool operator==(const FrameRange &other) const {
165 return start == other.start && end == other.end;
166 }
168 bool operator!=(const FrameRange &other) const { return !(*this == other); }
169
182 FrameRange &shift(int64_t n) {
183 start += n;
184 end += n;
185 return *this;
186 }
187
189 FrameRange &operator+=(int64_t n) { return shift(n); }
191 FrameRange &operator-=(int64_t n) { return shift(-n); }
192
194 friend FrameRange operator+(FrameRange r, int64_t n) {
195 r.shift(n);
196 return r;
197 }
199 friend FrameRange operator-(FrameRange r, int64_t n) {
200 r.shift(-n);
201 return r;
202 }
203
213 friend Iterator begin(const FrameRange &r) { return Iterator(r.start); }
214
222 friend Iterator end(const FrameRange &r) {
223 if (!r.isValid()) return Iterator(r.start);
224 return Iterator(FrameNumber(r.end.value() + 1));
225 }
226 };
227
242 static Result<MediaDuration> fromString(const String &str);
243
250 static MediaDuration fromFrameRange(const FrameRange &range) {
251 return MediaDuration(range.start, range.count());
252 }
253
255 MediaDuration() = default;
256
260 MediaDuration(const FrameNumber &start, const FrameCount &length) : _start(start), _length(length) {}
261
268 bool isValid() const { return _start.isValid() && _length.isValid(); }
269
271 bool isUnknown() const { return _start.isUnknown() || _length.isUnknown(); }
272
274 bool isInfinite() const { return _length.isInfinite(); }
275
277 bool isEmpty() const { return _length.isEmpty(); }
278
280 const FrameNumber &start() const { return _start; }
281
283 const FrameCount &length() const { return _length; }
284
287 void setStart(const FrameNumber &s) { _start = s; }
288
291 void setLength(const FrameCount &c) { _length = c; }
292
303 void setEnd(const FrameNumber &e);
304
315 FrameNumber end() const;
316
330 bool contains(const FrameNumber &frame) const;
331
336 void addToStart(int64_t n) { _start += n; }
337
342 void addToEnd(int64_t n) { _length += n; }
343
345 MediaDuration &operator+=(const FrameCount &c) {
346 _length += c;
347 return *this;
348 }
350 MediaDuration &operator-=(const FrameCount &c) {
351 _length -= c;
352 return *this;
353 }
354
367 Result<FrameRange> toFrameRange() const;
368
370 bool operator==(const MediaDuration &other) const {
371 return _start == other._start && _length == other._length;
372 }
374 bool operator!=(const MediaDuration &other) const { return !(*this == other); }
375
391 bool operator<(const MediaDuration &other) const {
392 if (isUnknown() || other.isUnknown()) return false;
393 if (_start != other._start) return _start < other._start;
394 return _length < other._length;
395 }
403 bool operator<=(const MediaDuration &other) const {
404 if (isUnknown() || other.isUnknown()) return false;
405 return *this == other || *this < other;
406 }
408 bool operator>(const MediaDuration &other) const { return other < *this; }
410 bool operator>=(const MediaDuration &other) const {
411 if (isUnknown() || other.isUnknown()) return false;
412 return *this == other || other < *this;
413 }
414
428 bool contains(const MediaDuration &other) const;
429
431 bool overlaps(const MediaDuration &other) const;
432
449 MediaDuration intersect(const MediaDuration &other) const;
450
464 bool canAppend(const MediaDuration &other) const;
465
480 Error append(const MediaDuration &other);
481
495 bool canPrepend(const MediaDuration &other) const;
496
510 Error prepend(const MediaDuration &other);
511
518 String toString() const;
519
521 operator String() const { return toString(); }
522
523 private:
524 FrameNumber _start;
525 FrameCount _length;
526};
527
529inline MediaDuration operator+(MediaDuration d, const FrameCount &c) {
530 d += c;
531 return d;
532}
534inline MediaDuration operator-(MediaDuration d, const FrameCount &c) {
535 d -= c;
536 return d;
537}
538
539PROMEKI_NAMESPACE_END
540
541PROMEKI_FORMAT_VIA_TOSTRING(promeki::MediaDuration);
542
550template <> struct std::hash<promeki::MediaDuration> {
551 size_t operator()(const promeki::MediaDuration &v) const noexcept {
552 size_t h = std::hash<promeki::FrameNumber>()(v.start());
553 size_t k = std::hash<promeki::FrameCount>()(v.length());
554 // Standard boost::hash_combine mix.
555 return h ^ (k + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));
556 }
557};
558
562template <> struct std::hash<promeki::MediaDuration::FrameRange> {
563 size_t operator()(const promeki::MediaDuration::FrameRange &v) const noexcept {
564 size_t h = std::hash<promeki::FrameNumber>()(v.start);
565 size_t k = std::hash<promeki::FrameNumber>()(v.end);
566 return h ^ (k + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));
567 }
568};
569
570#endif // PROMEKI_ENABLE_CORE