1use crate::diagnostics::codes::ValidationCode;
4use crate::diagnostics::{Category, Severity};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum St2067_3Code {
11 ContentKindUnknown,
13 SourceEncodingNoEssenceDescriptorList,
15 SourceEncodingUnresolved,
17 EssenceDescriptorListEmpty,
19 ContentVersionListEmpty,
21 ContentVersionIdInvalid,
23 ContentVersionLabelTextMissing,
25 LocaleLanguageTagInvalid,
27 TrackIdNotUnique,
29 MarkerOffsetOutOfRange,
31 MarkerLabelUnknown,
33 SegmentDuration,
35 ContentVersionIdDuplicate,
37 SegmentDurationIntegerEditUnits,
39}
40
41macro_rules! define_st2067_3_enum {
44 ($name:ident, $prefix:literal) => {
47 define_st2067_3_enum!(@inner $name, $prefix, None);
48 };
49 ($name:ident, $prefix:literal, $previous:literal) => {
52 define_st2067_3_enum!(@inner $name, $prefix, Some($previous));
53 };
54 (@inner $name:ident, $prefix:literal, $previous:expr) => {
55 #[allow(non_camel_case_types)]
56 #[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
57 pub enum $name {
58 ContentKindUnknown,
59 SourceEncodingNoEssenceDescriptorList,
60 SourceEncodingUnresolved,
61 EssenceDescriptorListEmpty,
62 ContentVersionListEmpty,
63 ContentVersionIdInvalid,
64 ContentVersionLabelTextMissing,
65 LocaleLanguageTagInvalid,
66 TrackIdNotUnique,
67 MarkerOffsetOutOfRange,
68 MarkerLabelUnknown,
69 SegmentDuration,
70 ContentVersionIdDuplicate,
71 SegmentDurationIntegerEditUnits,
72 }
73
74 impl $name {
75 pub fn for_code(r: St2067_3Code) -> &'static str {
76 match r {
77 St2067_3Code::ContentKindUnknown => {
78 concat!($prefix, ":5.5.1.2/ContentKindUnknown")
79 }
80 St2067_3Code::SourceEncodingNoEssenceDescriptorList => {
81 concat!($prefix, ":6.4.2/SourceEncodingNoEssenceDescriptorList")
82 }
83 St2067_3Code::SourceEncodingUnresolved => {
84 concat!($prefix, ":6.4.2/SourceEncodingUnresolved")
85 }
86 St2067_3Code::EssenceDescriptorListEmpty => {
87 concat!($prefix, ":6.4.2/EssenceDescriptorListEmpty")
88 }
89 St2067_3Code::ContentVersionListEmpty => {
90 concat!($prefix, ":6.11/ContentVersionListEmpty")
91 }
92 St2067_3Code::ContentVersionIdInvalid => {
93 concat!($prefix, ":6.11/ContentVersionIdInvalid")
94 }
95 St2067_3Code::ContentVersionLabelTextMissing => {
96 concat!($prefix, ":6.11/ContentVersionLabelTextMissing")
97 }
98 St2067_3Code::LocaleLanguageTagInvalid => {
99 concat!($prefix, ":6.12/LocaleLanguageTagInvalid")
100 }
101 St2067_3Code::TrackIdNotUnique => concat!($prefix, ":7.3/TrackIdNotUnique"),
102 St2067_3Code::MarkerOffsetOutOfRange => {
103 concat!($prefix, ":7.4/MarkerOffsetOutOfRange")
104 }
105 St2067_3Code::MarkerLabelUnknown => concat!($prefix, ":7.4/MarkerLabelUnknown"),
106 St2067_3Code::SegmentDuration => concat!($prefix, ":7.2.2/SegmentDuration"),
107 St2067_3Code::ContentVersionIdDuplicate => {
108 concat!($prefix, ":6.1.9/ContentVersionIdDuplicate")
109 }
110 St2067_3Code::SegmentDurationIntegerEditUnits => {
111 concat!($prefix, ":7.3/SegmentDurationIntegerEditUnits")
112 }
113 }
114 }
115
116 pub const ALL: &'static [Self] = &[
117 Self::ContentKindUnknown,
118 Self::SourceEncodingNoEssenceDescriptorList,
119 Self::SourceEncodingUnresolved,
120 Self::EssenceDescriptorListEmpty,
121 Self::ContentVersionListEmpty,
122 Self::ContentVersionIdInvalid,
123 Self::ContentVersionLabelTextMissing,
124 Self::LocaleLanguageTagInvalid,
125 Self::TrackIdNotUnique,
126 Self::MarkerOffsetOutOfRange,
127 Self::MarkerLabelUnknown,
128 Self::SegmentDuration,
129 Self::ContentVersionIdDuplicate,
130 Self::SegmentDurationIntegerEditUnits,
131 ];
132 }
133
134 impl ValidationCode for $name {
135 fn code(&self) -> &'static str {
136 match self {
137 Self::ContentKindUnknown => concat!($prefix, ":5.5.1.2/ContentKindUnknown"),
138 Self::SourceEncodingNoEssenceDescriptorList => {
139 concat!($prefix, ":6.4.2/SourceEncodingNoEssenceDescriptorList")
140 }
141 Self::SourceEncodingUnresolved => {
142 concat!($prefix, ":6.4.2/SourceEncodingUnresolved")
143 }
144 Self::EssenceDescriptorListEmpty => {
145 concat!($prefix, ":6.4.2/EssenceDescriptorListEmpty")
146 }
147 Self::ContentVersionListEmpty => {
148 concat!($prefix, ":6.11/ContentVersionListEmpty")
149 }
150 Self::ContentVersionIdInvalid => {
151 concat!($prefix, ":6.11/ContentVersionIdInvalid")
152 }
153 Self::ContentVersionLabelTextMissing => {
154 concat!($prefix, ":6.11/ContentVersionLabelTextMissing")
155 }
156 Self::LocaleLanguageTagInvalid => {
157 concat!($prefix, ":6.12/LocaleLanguageTagInvalid")
158 }
159 Self::TrackIdNotUnique => concat!($prefix, ":7.3/TrackIdNotUnique"),
160 Self::MarkerOffsetOutOfRange => concat!($prefix, ":7.4/MarkerOffsetOutOfRange"),
161 Self::MarkerLabelUnknown => concat!($prefix, ":7.4/MarkerLabelUnknown"),
162 Self::SegmentDuration => concat!($prefix, ":7.2.2/SegmentDuration"),
163 Self::ContentVersionIdDuplicate => {
164 concat!($prefix, ":6.1.9/ContentVersionIdDuplicate")
165 }
166 Self::SegmentDurationIntegerEditUnits => {
167 concat!($prefix, ":7.3/SegmentDurationIntegerEditUnits")
168 }
169 }
170 }
171 fn description(&self) -> &'static str {
172 match self {
173 Self::ContentKindUnknown => {
174 "ContentKind uses an unrecognized value under the SMPTE scope."
175 }
176 Self::SourceEncodingNoEssenceDescriptorList => {
177 "SourceEncoding present but EssenceDescriptorList absent."
178 }
179 Self::SourceEncodingUnresolved => {
180 "SourceEncoding does not match any EssenceDescriptor Id."
181 }
182 Self::EssenceDescriptorListEmpty => {
183 "EssenceDescriptorList present but contains no descriptors."
184 }
185 Self::ContentVersionListEmpty => "ContentVersionList present but empty.",
186 Self::ContentVersionIdInvalid => "ContentVersion/Id is empty (shall be a URI).",
187 Self::ContentVersionLabelTextMissing => "ContentVersion/LabelText is absent.",
188 Self::LocaleLanguageTagInvalid => {
189 "Locale language tag does not conform to RFC 5646."
190 }
191 Self::TrackIdNotUnique => "TrackId is not unique within a segment.",
192 Self::MarkerOffsetOutOfRange => {
193 "Marker offset exceeds resource effective duration."
194 }
195 Self::MarkerLabelUnknown => {
196 "Marker label is not a recognized SMPTE standard value."
197 }
198 Self::SegmentDuration => {
199 "All virtual tracks in a segment must span the same number of edit units."
200 }
201 Self::ContentVersionIdDuplicate => {
202 "No two ContentVersion elements shall have identical Id values."
203 }
204 Self::SegmentDurationIntegerEditUnits => {
205 "Sequence duration shall be an integer number of Composition Edit Units."
206 }
207 }
208 }
209 fn default_severity(&self) -> Severity {
210 match self {
211 Self::ContentKindUnknown => Severity::Warning,
212 Self::SourceEncodingNoEssenceDescriptorList => Severity::Error,
213 Self::SourceEncodingUnresolved => Severity::Error,
214 Self::EssenceDescriptorListEmpty => Severity::Error,
215 Self::ContentVersionListEmpty => Severity::Error,
216 Self::ContentVersionIdInvalid => Severity::Error,
217 Self::ContentVersionLabelTextMissing => Severity::Warning,
218 Self::LocaleLanguageTagInvalid => Severity::Warning,
219 Self::TrackIdNotUnique => Severity::Error,
220 Self::MarkerOffsetOutOfRange => Severity::Error,
221 Self::MarkerLabelUnknown => Severity::Warning,
222 Self::SegmentDuration => Severity::Error,
223 Self::ContentVersionIdDuplicate => Severity::Error,
224 Self::SegmentDurationIntegerEditUnits => Severity::Error,
225 }
226 }
227 fn category(&self) -> Category {
228 match self {
229 Self::ContentKindUnknown => Category::Metadata,
230 Self::SourceEncodingNoEssenceDescriptorList => Category::Reference,
231 Self::SourceEncodingUnresolved => Category::Reference,
232 Self::EssenceDescriptorListEmpty => Category::Structure,
233 Self::ContentVersionListEmpty => Category::Structure,
234 Self::ContentVersionIdInvalid => Category::Metadata,
235 Self::ContentVersionLabelTextMissing => Category::Metadata,
236 Self::LocaleLanguageTagInvalid => Category::Metadata,
237 Self::TrackIdNotUnique => Category::Structure,
238 Self::MarkerOffsetOutOfRange => Category::Timing,
239 Self::MarkerLabelUnknown => Category::Metadata,
240 Self::SegmentDuration => Category::Timing,
241 Self::ContentVersionIdDuplicate => Category::Structure,
242 Self::SegmentDurationIntegerEditUnits => Category::Timing,
243 }
244 }
245 fn previous_identical_edition(&self) -> Option<&'static str> {
246 $previous
247 }
248 fn example(&self) -> Option<&'static str> {
249 Some(match self {
250 Self::ContentKindUnknown =>
251 "<ContentKind scope=\"http://www.smpte-ra.org/schemas/2067-3/2013/content-kind\">Banana</ContentKind>",
252 Self::SourceEncodingNoEssenceDescriptorList =>
253 "<Resource><SourceEncoding>urn:uuid:…</SourceEncoding></Resource> <!-- but the CPL has no <EssenceDescriptorList> -->",
254 Self::SourceEncodingUnresolved =>
255 "<SourceEncoding>urn:uuid:aaaa…</SourceEncoding> <!-- no EssenceDescriptor with that Id -->",
256 Self::EssenceDescriptorListEmpty =>
257 "<EssenceDescriptorList></EssenceDescriptorList>",
258 Self::ContentVersionListEmpty =>
259 "<ContentVersionList></ContentVersionList>",
260 Self::ContentVersionIdInvalid =>
261 "<ContentVersion><Id></Id>…</ContentVersion>",
262 Self::ContentVersionLabelTextMissing =>
263 "<ContentVersion><Id>urn:uuid:…</Id></ContentVersion> <!-- no <LabelText> -->",
264 Self::LocaleLanguageTagInvalid =>
265 "<Locale><LanguageList><Language>english</Language></LanguageList></Locale> <!-- not RFC 5646 -->",
266 Self::TrackIdNotUnique =>
267 "<Sequence><TrackId>urn:uuid:abc…</TrackId>…</Sequence><Sequence><TrackId>urn:uuid:abc…</TrackId>…</Sequence> <!-- same TrackId in two sequences of one segment -->",
268 Self::MarkerOffsetOutOfRange =>
269 "<Marker><Offset>120</Offset></Marker> <!-- resource IntrinsicDuration=100 -->",
270 Self::MarkerLabelUnknown =>
271 "<Marker><Label>NotARealMarker</Label></Marker>",
272 Self::SegmentDuration =>
273 "Segment with MainImageSequence duration = 24f and MainAudioSequence duration = 25f",
274 Self::ContentVersionIdDuplicate =>
275 "<ContentVersion><Id>urn:uuid:a…</Id></ContentVersion><ContentVersion><Id>urn:uuid:a…</Id></ContentVersion>",
276 Self::SegmentDurationIntegerEditUnits =>
277 "Sequence duration = 12.5 edit units (must be an integer multiple of the Composition Edit Unit)",
278 })
279 }
280 }
281
282 impl From<$name> for String {
283 fn from(c: $name) -> String {
284 c.code().to_string()
285 }
286 }
287 };
288}
289
290define_st2067_3_enum!(St2067_3_2013, "ST2067-3:2013");
291define_st2067_3_enum!(St2067_3_2016, "ST2067-3:2016", "ST2067-3:2013");