libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
cea608xds.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
13#include <cstdint>
14#include <promeki/cea708cdp.h>
15#include <promeki/datetime.h>
16#include <promeki/list.h>
17#include <promeki/map.h>
18#include <promeki/namespace.h>
19#include <promeki/optional.h>
20#include <promeki/sharedptr.h>
21#include <promeki/string.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
43enum class Cea608XdsClass : uint8_t {
44 Current = 0,
45 Future = 1,
46 Channel = 2,
47 Misc = 3,
48 PublicSvc = 4,
49 Reserved = 5,
50 PrivateData = 6,
51 Unknown = 7
52};
53
75enum class Cea608XdsRatingSystem : uint8_t {
76 Mpaa = 0,
77 UsTvParental = 1,
78 CanadianEnglish = 2,
79 CanadianFrench = 3,
80};
81
90enum class Cea608XdsMpaaRating : uint8_t {
91 NotApplicable = 0,
92 G = 1,
93 Pg = 2,
94 Pg13 = 3,
95 R = 4,
96 Nc17 = 5,
97 X = 6,
98 NotRated = 7,
99};
100
123struct Cea608XdsContentAdvisory {
125 Cea608XdsRatingSystem system = Cea608XdsRatingSystem::UsTvParental;
127 uint8_t level = 0;
129 Cea608XdsMpaaRating mpaa = Cea608XdsMpaaRating::NotApplicable;
130 bool violence = false;
131 bool sexual = false;
132 bool language = false;
133 bool dialog = false;
134 bool fantasyViolence = false;
135
136 bool operator==(const Cea608XdsContentAdvisory &o) const {
137 return system == o.system && level == o.level && mpaa == o.mpaa
138 && violence == o.violence && sexual == o.sexual
139 && language == o.language && dialog == o.dialog
140 && fantasyViolence == o.fantasyViolence;
141 }
142 bool operator!=(const Cea608XdsContentAdvisory &o) const { return !(*this == o); }
143
155 String ratingName() const;
156};
157
170struct Cea608XdsProgramId {
171 uint8_t minute = 0;
172 uint8_t hour = 0;
173 uint8_t date = 1;
174 uint8_t month = 1;
175 bool tapeDelay = false;
176 // Per CEA-608-E §9.5.1.1: "The D, L, and Z bits are
177 // ignored by the decoder when processing this packet."
178 // We don't expose those bits — the @c D, @c L, @c Z
179 // semantics live in the Time-of-Day packet
180 // (§9.5.4.1), surfaced via @ref Cea608XdsPacket::
181 // timeOfDayDstFlag / timeOfDayLeapYearFlag /
182 // timeOfDayZeroSecondsFlag.
183
184 bool operator==(const Cea608XdsProgramId &o) const {
185 return minute == o.minute && hour == o.hour && date == o.date
186 && month == o.month && tapeDelay == o.tapeDelay;
187 }
188 bool operator!=(const Cea608XdsProgramId &o) const { return !(*this == o); }
189};
190
210struct Cea608XdsProgramLength {
211 uint8_t lengthHours = 0;
212 uint8_t lengthMinutes = 0;
213 uint8_t elapsedHours = 0;
214 uint8_t elapsedMinutes = 0;
215 uint8_t elapsedSeconds = 0;
216 bool hasElapsedTime = false;
217 bool hasElapsedSeconds = false;
218
219 bool operator==(const Cea608XdsProgramLength &o) const {
220 return lengthHours == o.lengthHours && lengthMinutes == o.lengthMinutes
221 && elapsedHours == o.elapsedHours && elapsedMinutes == o.elapsedMinutes
222 && elapsedSeconds == o.elapsedSeconds
223 && hasElapsedTime == o.hasElapsedTime
224 && hasElapsedSeconds == o.hasElapsedSeconds;
225 }
226 bool operator!=(const Cea608XdsProgramLength &o) const { return !(*this == o); }
227};
228
237enum class Cea608XdsCgmsControl : uint8_t {
238 CopyFree = 0,
239 NoMoreCopies = 1,
240 CopyOnce = 2,
241 CopyNever = 3,
242};
243
252enum class Cea608XdsApsControl : uint8_t {
253 Off = 0,
254 PspOnly = 1,
255 Psp2LineSplitBurst = 2,
256 Psp4LineSplitBurst = 3,
257};
258
283struct Cea608XdsCgmsA {
284 Cea608XdsCgmsControl cgms = Cea608XdsCgmsControl::CopyFree;
285 Optional<Cea608XdsApsControl> aps;
286 bool analogSourceBit = false;
287 bool redistributionControl = false;
288
289 bool operator==(const Cea608XdsCgmsA &o) const {
290 return cgms == o.cgms && aps == o.aps
291 && analogSourceBit == o.analogSourceBit
292 && redistributionControl == o.redistributionControl;
293 }
294 bool operator!=(const Cea608XdsCgmsA &o) const { return !(*this == o); }
295};
296
317struct Cea608XdsAspectRatio {
318 uint8_t startLine = 0;
319 uint8_t endLine = 0;
320 bool squeezed = false;
321
322 bool operator==(const Cea608XdsAspectRatio &o) const {
323 return startLine == o.startLine && endLine == o.endLine && squeezed == o.squeezed;
324 }
325 bool operator!=(const Cea608XdsAspectRatio &o) const { return !(*this == o); }
326};
327
333enum class Cea608XdsLanguage : uint8_t {
334 Unknown = 0,
335 English = 1,
336 Spanish = 2,
337 French = 3,
338 German = 4,
339 Italian = 5,
340 Other = 6,
341 None = 7,
342};
343
349enum class Cea608XdsMainAudioType : uint8_t {
350 Unknown = 0,
351 Mono = 1,
352 SimulatedStereo = 2,
353 TrueStereo = 3,
354 StereoSurround = 4,
355 DataService = 5,
356 Other = 6,
357 None = 7,
358};
359
365enum class Cea608XdsSecondAudioType : uint8_t {
366 Unknown = 0,
367 Mono = 1,
368 VideoDescriptions = 2,
369 NonProgramAudio = 3,
370 SpecialEffects = 4,
371 DataService = 5,
372 Other = 6,
373 None = 7,
374};
375
386struct Cea608XdsAudioServices {
387 Cea608XdsLanguage mainLanguage = Cea608XdsLanguage::Unknown;
388 Cea608XdsMainAudioType mainType = Cea608XdsMainAudioType::Unknown;
389 Cea608XdsLanguage sapLanguage = Cea608XdsLanguage::Unknown;
390 Cea608XdsSecondAudioType sapType = Cea608XdsSecondAudioType::Unknown;
391
392 bool operator==(const Cea608XdsAudioServices &o) const {
393 return mainLanguage == o.mainLanguage && mainType == o.mainType
394 && sapLanguage == o.sapLanguage && sapType == o.sapType;
395 }
396 bool operator!=(const Cea608XdsAudioServices &o) const { return !(*this == o); }
397};
398
410struct Cea608XdsCaptionService {
411 Cea608XdsLanguage language = Cea608XdsLanguage::Unknown;
412 bool fieldTwo = false;
413 bool channelTwo = false;
414 bool textMode = false;
415
416 bool operator==(const Cea608XdsCaptionService &o) const {
417 return language == o.language && fieldTwo == o.fieldTwo
418 && channelTwo == o.channelTwo && textMode == o.textMode;
419 }
420 bool operator!=(const Cea608XdsCaptionService &o) const { return !(*this == o); }
421};
422
431struct Cea608XdsTapeDelay {
432 uint8_t hours = 0;
433 uint8_t minutes = 0;
434
435 bool operator==(const Cea608XdsTapeDelay &o) const {
436 return hours == o.hours && minutes == o.minutes;
437 }
438 bool operator!=(const Cea608XdsTapeDelay &o) const { return !(*this == o); }
439};
440
452struct Cea608XdsImpulseCaptureId {
453 Cea608XdsProgramId programId;
454 uint8_t lengthMinutes = 0;
455 uint8_t lengthHours = 0;
456
457 bool operator==(const Cea608XdsImpulseCaptureId &o) const {
458 return programId == o.programId
459 && lengthMinutes == o.lengthMinutes
460 && lengthHours == o.lengthHours;
461 }
462 bool operator!=(const Cea608XdsImpulseCaptureId &o) const { return !(*this == o); }
463};
464
475struct Cea608XdsSupplementalDataLocation {
476 bool fieldTwo = false;
477 uint8_t lineNumber = 0;
478
479 bool operator==(const Cea608XdsSupplementalDataLocation &o) const {
480 return fieldTwo == o.fieldTwo && lineNumber == o.lineNumber;
481 }
482 bool operator!=(const Cea608XdsSupplementalDataLocation &o) const { return !(*this == o); }
483};
484
490struct Cea608XdsChannelMapHeader {
491 uint16_t channelCount = 0;
492 uint8_t version = 0;
493
494 bool operator==(const Cea608XdsChannelMapHeader &o) const {
495 return channelCount == o.channelCount && version == o.version;
496 }
497 bool operator!=(const Cea608XdsChannelMapHeader &o) const { return !(*this == o); }
498};
499
510struct Cea608XdsChannelMapPacket {
511 uint16_t userChannel = 0;
512 bool remapped = false;
513 uint16_t tuneChannel = 0;
514 String channelId;
515
516 bool operator==(const Cea608XdsChannelMapPacket &o) const {
517 return userChannel == o.userChannel && remapped == o.remapped
518 && tuneChannel == o.tuneChannel && channelId == o.channelId;
519 }
520 bool operator!=(const Cea608XdsChannelMapPacket &o) const { return !(*this == o); }
521};
522
537struct Cea608XdsWrsame {
538 String eventCode;
539 uint8_t countySlice = 0;
540 uint8_t stateCode = 0;
541 uint16_t countyCode = 0;
542 uint8_t durationQuarters = 0;
543
544 bool operator==(const Cea608XdsWrsame &o) const {
545 return eventCode == o.eventCode && countySlice == o.countySlice
546 && stateCode == o.stateCode && countyCode == o.countyCode
547 && durationQuarters == o.durationQuarters;
548 }
549 bool operator!=(const Cea608XdsWrsame &o) const { return !(*this == o); }
550};
551
570struct Cea608XdsCompositePacket1 {
574 List<uint8_t> programTypeKeywords;
579 uint8_t contentAdvisoryByte1 = 0;
581 uint8_t lengthMinutes = 0;
582 uint8_t lengthHours = 0;
584 uint8_t elapsedMinutes = 0;
585 uint8_t elapsedHours = 0;
587 String title;
588
589 bool operator==(const Cea608XdsCompositePacket1 &o) const {
590 return programTypeKeywords == o.programTypeKeywords
591 && contentAdvisoryByte1 == o.contentAdvisoryByte1
592 && lengthMinutes == o.lengthMinutes
593 && lengthHours == o.lengthHours
594 && elapsedMinutes == o.elapsedMinutes
595 && elapsedHours == o.elapsedHours
596 && title == o.title;
597 }
598 bool operator!=(const Cea608XdsCompositePacket1 &o) const { return !(*this == o); }
599};
600
617struct Cea608XdsCompositePacket2 {
618 Cea608XdsProgramId programId;
619 Cea608XdsAudioServices audioServices;
620 List<Cea608XdsCaptionService> captionServices;
621 String callLetters;
622 Optional<int> nativeChannel;
623 String networkName;
624
625 bool operator==(const Cea608XdsCompositePacket2 &o) const {
626 return programId == o.programId
627 && audioServices == o.audioServices
628 && captionServices == o.captionServices
629 && callLetters == o.callLetters
630 && nativeChannel == o.nativeChannel
631 && networkName == o.networkName;
632 }
633 bool operator!=(const Cea608XdsCompositePacket2 &o) const { return !(*this == o); }
634};
635
646struct Cea608XdsTimeZone {
647 int8_t utcOffsetHours = 0;
648 bool observesDst = false;
649
650 bool operator==(const Cea608XdsTimeZone &o) const {
651 return utcOffsetHours == o.utcOffsetHours && observesDst == o.observesDst;
652 }
653 bool operator!=(const Cea608XdsTimeZone &o) const { return !(*this == o); }
654};
655
674struct Cea608XdsPacket {
676 Cea608XdsClass class_ = Cea608XdsClass::Unknown;
681 uint8_t type = 0;
687 List<uint8_t> payload;
688
693 bool isOutOfBand() const { return (type & 0x40) != 0; }
694
700 String text() const;
701
705 String programName() const;
706
710 String networkName() const;
711
715 String callLetters() const;
716
730 Optional<int> nativeChannel() const;
731
746 Optional<DateTime> timeOfDay() const;
747
757 bool timeOfDayDstFlag() const;
758
763 bool timeOfDayLeapYearFlag() const;
764
771 bool timeOfDayTapeDelayFlag() const;
772
780 bool timeOfDayZeroSecondsFlag() const;
781
792 Optional<Cea608XdsContentAdvisory> contentAdvisory() const;
793
802 Optional<Cea608XdsProgramId> programId() const;
803
811 bool isProgramIdEndOfProgramSentinel() const;
812
818 Optional<Cea608XdsProgramLength> programLength() const;
819
828 List<uint8_t> programTypeKeywords() const;
829
834 Optional<Cea608XdsAspectRatio> aspectRatio() const;
835
842 Optional<Cea608XdsCgmsA> cgmsA() const;
843
848 Optional<uint16_t> transmissionSignalId() const;
849
854 Optional<Cea608XdsTimeZone> timeZone() const;
855
861 Optional<Cea608XdsAudioServices> audioServices() const;
862
870 List<Cea608XdsCaptionService> captionServices() const;
871
876 Optional<Cea608XdsTapeDelay> tapeDelay() const;
877
883 Optional<Cea608XdsImpulseCaptureId> impulseCaptureId() const;
884
892 List<Cea608XdsSupplementalDataLocation> supplementalDataLocations() const;
893
899 Optional<uint16_t> outOfBandChannel() const;
900
906 Optional<uint16_t> channelMapPointer() const;
907
912 Optional<Cea608XdsChannelMapHeader> channelMapHeader() const;
913
918 Optional<Cea608XdsChannelMapPacket> channelMapPacket() const;
919
925 Optional<Cea608XdsWrsame> wrsame() const;
926
931 String nwsMessage() const;
932
939 String programDescriptionRow() const;
940
946 int programDescriptionRowIndex() const;
947
953 Optional<Cea608XdsCompositePacket1> compositePacket1() const;
954
960 Optional<Cea608XdsCompositePacket2> compositePacket2() const;
961
967 static String programTypeName(uint8_t keywordByte);
968
994 List<uint8_t> encode() const;
995
996 bool operator==(const Cea608XdsPacket &o) const {
997 return class_ == o.class_ && type == o.type && payload == o.payload;
998 }
999 bool operator!=(const Cea608XdsPacket &o) const { return !(*this == o); }
1000};
1001
1006uint8_t xdsStartByte(Cea608XdsClass cls);
1007
1012uint8_t xdsContinueByte(Cea608XdsClass cls);
1013
1026uint8_t xdsChecksum(uint32_t classAndType, uint32_t informational);
1027
1028struct Cea608XdsExtractorImpl; // Pimpl — defined in cea608xds.cpp.
1029
1087class Cea608XdsExtractor {
1088 public:
1094 static constexpr int MaxInFlight = 4;
1095
1102 static constexpr int MaxPayloadBytes = 32;
1103
1104 Cea608XdsExtractor();
1105
1109 void reset();
1110
1133 void processPair(uint8_t b1, uint8_t b2);
1134
1147 void pushFrame(const Cea708Cdp::CcDataList &data);
1148
1153 List<Cea608XdsPacket> drain();
1154
1157 size_t pending() const;
1158
1164 uint32_t checksumFailures() const;
1165
1172 uint32_t oversizedPackets() const;
1173
1174 private:
1175 SharedPtr<Cea608XdsExtractorImpl> _d;
1176};
1177
1178PROMEKI_NAMESPACE_END
1179
1180#endif // PROMEKI_ENABLE_PROAV