1use crate::diagnostics::codes::ValidationCode;
4use crate::diagnostics::{Category, Severity};
5
6macro_rules! impl_into_string {
7 ($t:ty) => {
8 impl From<$t> for String {
9 fn from(c: $t) -> String {
10 <$t as ValidationCode>::code(&c).to_string()
11 }
12 }
13 };
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
22pub enum St2067_21_2020 {
23 AppIdMismatch,
25}
26
27impl ValidationCode for St2067_21_2020 {
28 fn code(&self) -> &'static str {
29 match self {
30 Self::AppIdMismatch => "ST2067-21:2020:7.1/AppIdMismatch",
31 }
32 }
33 fn description(&self) -> &'static str {
34 match self {
35 Self::AppIdMismatch =>
36 "Application identifier in CPL ExtensionProperties does not match the expected App2E URI.",
37 }
38 }
39 fn default_severity(&self) -> Severity {
40 Severity::Warning
41 }
42 fn category(&self) -> Category {
43 Category::Metadata
44 }
45}
46
47impl St2067_21_2020 {
48 pub const ALL: &'static [Self] = &[Self::AppIdMismatch];
49}
50
51impl_into_string!(St2067_21_2020);
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
64pub enum St2067_21_2023 {
65 FrameRate,
68 Resolution,
70
71 EmptyLanguageTag,
74 MalformedLanguageTag,
76 RegionCode,
78
79 ColorSystem,
82
83 RequiredStoredWidth,
86 RequiredStoredHeight,
88 RequiredSampleRate,
90 RequiredFrameLayout,
92 RequiredColorPrimaries,
94 RequiredTransferCharacteristic,
96 RequiredPictureCompression,
98 RequiredComponentDepth,
100
101 RequiredChannelCount,
104 RequiredQuantizationBits,
106
107 AlphaTransparency,
110 CodingEquations,
112 ColorPrimaries,
114 FieldDominance,
116 FrameLayout,
118 FrameLayoutInterlaced,
120 ImageAlignmentOffset,
122 ImageEndOffset,
124 ImageStartOffset,
126 SampledHeight,
128 SampledWidth,
130 SampledXOffset,
132 SampledYOffset,
134 StoredF2Offset,
136 TransferCharacteristic,
138
139 TransferCharacteristicUnknown,
142
143 CodingEquationsUnknown,
146
147 ColorPrimariesUnknown,
150
151 J2KRequired,
154
155 AlphaMaxRef,
158 AlphaMinRef,
160 ComponentMaxRef,
162 ComponentMinRef,
164 Palette,
166 PaletteLayout,
168 ScanningDirection,
170
171 ComponentRefValues,
174
175 AlphaSampleDepth,
178 ColorSiting,
180 ComponentDepth,
182 HorizontalSubsampling,
184 PaddingBits,
186 ReversedByteOrder,
188 VerticalSubsampling,
190
191 BlackRefLevel,
194 ColorRange,
196 WhiteRefLevel,
198
199 AudioSampleRate,
202 QuantizationBits,
204
205 CodingStyle,
208 J2CLayout,
210 J2KExtendedCapabilities,
212 Jpeg2000SubDescriptor,
214
215 J2KHtNotAllowed,
218 J2K4KResolution,
220 J2K2KResolution,
222 J2KBcpResolution,
224
225 ApplicationIdentification,
228 ContentMaturityRatingAgency,
230 ContentMaturityRatingAgencyUri,
232
233 HomogeneousImageEssence,
236
237 AppIdMismatch,
240
241 SegmentDurationMultiple,
244
245 MaxCLLMaxFALL,
248}
249
250impl ValidationCode for St2067_21_2023 {
251 fn code(&self) -> &'static str {
252 match self {
253 Self::FrameRate => "ST2067-21:2023:5.2/FrameRate",
254 Self::Resolution => "ST2067-21:2023:5.2/Resolution",
255 Self::EmptyLanguageTag => "ST2067-21:2023:5.3/EmptyLanguageTag",
256 Self::MalformedLanguageTag => "ST2067-21:2023:5.3/MalformedLanguageTag",
257 Self::RegionCode => "ST2067-21:2023:5.3/RegionCode",
258 Self::ColorSystem => "ST2067-21:2023:6.2/ColorSystem",
259 Self::RequiredStoredWidth => "ST2067-21:2023:6.2/Required-StoredWidth",
260 Self::RequiredStoredHeight => "ST2067-21:2023:6.2/Required-StoredHeight",
261 Self::RequiredSampleRate => "ST2067-21:2023:6.2/Required-SampleRate",
262 Self::RequiredFrameLayout => "ST2067-21:2023:6.2/Required-FrameLayout",
263 Self::RequiredColorPrimaries => "ST2067-21:2023:6.2/Required-ColorPrimaries",
264 Self::RequiredTransferCharacteristic => {
265 "ST2067-21:2023:6.2/Required-TransferCharacteristic"
266 }
267 Self::RequiredPictureCompression => "ST2067-21:2023:6.2/Required-PictureCompression",
268 Self::RequiredComponentDepth => "ST2067-21:2023:6.2/Required-ComponentDepth",
269 Self::RequiredChannelCount => "ST2067-21:2023:6.5/Required-ChannelCount",
270 Self::RequiredQuantizationBits => "ST2067-21:2023:6.5/Required-QuantizationBits",
271 Self::AlphaTransparency => "ST2067-21:2023:6.2.1/AlphaTransparency",
272 Self::CodingEquations => "ST2067-21:2023:6.2.1/CodingEquations",
273 Self::ColorPrimaries => "ST2067-21:2023:6.2.1/ColorPrimaries",
274 Self::FieldDominance => "ST2067-21:2023:6.2.1/FieldDominance",
275 Self::FrameLayout => "ST2067-21:2023:6.2.1/FrameLayout",
276 Self::FrameLayoutInterlaced => "ST2067-21:2023:6.2.1/FrameLayoutInterlaced",
277 Self::ImageAlignmentOffset => "ST2067-21:2023:6.2.1/ImageAlignmentOffset",
278 Self::ImageEndOffset => "ST2067-21:2023:6.2.1/ImageEndOffset",
279 Self::ImageStartOffset => "ST2067-21:2023:6.2.1/ImageStartOffset",
280 Self::SampledHeight => "ST2067-21:2023:6.2.1/SampledHeight",
281 Self::SampledWidth => "ST2067-21:2023:6.2.1/SampledWidth",
282 Self::SampledXOffset => "ST2067-21:2023:6.2.1/SampledXOffset",
283 Self::SampledYOffset => "ST2067-21:2023:6.2.1/SampledYOffset",
284 Self::StoredF2Offset => "ST2067-21:2023:6.2.1/StoredF2Offset",
285 Self::TransferCharacteristic => "ST2067-21:2023:6.2.1/TransferCharacteristic",
286 Self::TransferCharacteristicUnknown => "ST2067-21:2023:6.2.2/TransferCharacteristic",
287 Self::CodingEquationsUnknown => "ST2067-21:2023:6.2.3/CodingEquations",
288 Self::ColorPrimariesUnknown => "ST2067-21:2023:6.2.4/ColorPrimaries",
289 Self::J2KRequired => "ST2067-21:2023:6.2.5/J2KRequired",
290 Self::AlphaMaxRef => "ST2067-21:2023:6.3/AlphaMaxRef",
291 Self::AlphaMinRef => "ST2067-21:2023:6.3/AlphaMinRef",
292 Self::ComponentMaxRef => "ST2067-21:2023:6.3/ComponentMaxRef",
293 Self::ComponentMinRef => "ST2067-21:2023:6.3/ComponentMinRef",
294 Self::Palette => "ST2067-21:2023:6.3/Palette",
295 Self::PaletteLayout => "ST2067-21:2023:6.3/PaletteLayout",
296 Self::ScanningDirection => "ST2067-21:2023:6.3/ScanningDirection",
297 Self::ComponentRefValues => "ST2067-21:2023:6.3.2/ComponentRefValues",
298 Self::AlphaSampleDepth => "ST2067-21:2023:6.4/AlphaSampleDepth",
299 Self::ColorSiting => "ST2067-21:2023:6.4/ColorSiting",
300 Self::ComponentDepth => "ST2067-21:2023:6.4/ComponentDepth",
301 Self::HorizontalSubsampling => "ST2067-21:2023:6.4/HorizontalSubsampling",
302 Self::PaddingBits => "ST2067-21:2023:6.4/PaddingBits",
303 Self::ReversedByteOrder => "ST2067-21:2023:6.4/ReversedByteOrder",
304 Self::VerticalSubsampling => "ST2067-21:2023:6.4/VerticalSubsampling",
305 Self::BlackRefLevel => "ST2067-21:2023:6.4.3/BlackRefLevel",
306 Self::ColorRange => "ST2067-21:2023:6.4.3/ColorRange",
307 Self::WhiteRefLevel => "ST2067-21:2023:6.4.3/WhiteRefLevel",
308 Self::AudioSampleRate => "ST2067-21:2023:6.5/AudioSampleRate",
309 Self::QuantizationBits => "ST2067-21:2023:6.5/QuantizationBits",
310 Self::CodingStyle => "ST2067-21:2023:6.5.2/CodingStyle",
311 Self::J2CLayout => "ST2067-21:2023:6.5.2/J2CLayout",
312 Self::J2KExtendedCapabilities => "ST2067-21:2023:6.5.2/J2KExtendedCapabilities",
313 Self::Jpeg2000SubDescriptor => "ST2067-21:2023:6.5.2/JPEG2000SubDescriptor",
314 Self::J2KHtNotAllowed => "ST2067-21:2023:6.2.5/J2K-HT-Not-Allowed",
315 Self::J2K4KResolution => "ST2067-21:2023:6.2.5/J2K-4K-Resolution",
316 Self::J2K2KResolution => "ST2067-21:2023:6.2.5/J2K-2K-Resolution",
317 Self::J2KBcpResolution => "ST2067-21:2023:6.2.5/J2K-BCP-Resolution",
318 Self::ApplicationIdentification => "ST2067-21:2023:7.1/ApplicationIdentification",
319 Self::ContentMaturityRatingAgency => "ST2067-21:2023:7.1/ContentMaturityRating-Agency",
320 Self::ContentMaturityRatingAgencyUri => {
321 "ST2067-21:2023:7.1/ContentMaturityRating-Agency-URI"
322 }
323 Self::HomogeneousImageEssence => "ST2067-21:2023:7.2/HomogeneousImageEssence",
324 Self::AppIdMismatch => "ST2067-21:2023:7.1/AppIdMismatch",
325 Self::SegmentDurationMultiple => "ST2067-21:2023:7.4/SegmentDurationMultiple",
326 Self::MaxCLLMaxFALL => "ST2067-21:2023:7.5/MaxCLLMaxFALL",
327 }
328 }
329
330 fn description(&self) -> &'static str {
331 match self {
332 Self::FrameRate => "Frame rate is not in the permitted set for App2E.",
333 Self::Resolution => "Image resolution is not in the permitted set for App2E.",
334 Self::EmptyLanguageTag => "Locale language tag is empty.",
335 Self::MalformedLanguageTag => "Locale language tag is not a valid BCP-47 subtag.",
336 Self::RegionCode => "Region subtag in a language tag is not valid.",
337 Self::ColorSystem => "Color system designator is not in the permitted set.",
338 Self::RequiredStoredWidth => "RGBA/CDCI descriptor is missing the required StoredWidth field.",
339 Self::RequiredStoredHeight => "RGBA/CDCI descriptor is missing the required StoredHeight field.",
340 Self::RequiredSampleRate => "RGBA/CDCI descriptor is missing the required SampleRate field.",
341 Self::RequiredFrameLayout => "RGBA/CDCI descriptor is missing the required FrameLayout field.",
342 Self::RequiredColorPrimaries => "RGBA/CDCI descriptor is missing the required ColorPrimaries field.",
343 Self::RequiredTransferCharacteristic => "RGBA/CDCI descriptor is missing the required TransferCharacteristic field.",
344 Self::RequiredPictureCompression => "RGBA/CDCI descriptor is missing the required PictureCompression field.",
345 Self::RequiredComponentDepth => "CDCI descriptor is missing the required ComponentDepth field.",
346 Self::RequiredChannelCount => "WavePCM descriptor is missing the required ChannelCount field.",
347 Self::RequiredQuantizationBits => "WavePCM descriptor is missing the required QuantizationBits field.",
348 Self::AlphaTransparency => "Alpha transparency mode is not permitted in App2E.",
349 Self::CodingEquations => "CodingEquations field is absent from the picture descriptor (Table 8).",
350 Self::ColorPrimaries => "ColorPrimaries field is absent from the picture descriptor (Table 8).",
351 Self::FieldDominance => "FieldDominance value is not permitted for the declared FrameLayout.",
352 Self::FrameLayout => "FrameLayout value is not in the permitted set for App2E.",
353 Self::FrameLayoutInterlaced => "FrameLayout declares interlaced content, which is not permitted in App2E.",
354 Self::ImageAlignmentOffset => "ImageAlignmentOffset must be zero.",
355 Self::ImageEndOffset => "ImageEndOffset must be zero.",
356 Self::ImageStartOffset => "ImageStartOffset must be zero.",
357 Self::SampledHeight => "SampledHeight must equal StoredHeight.",
358 Self::SampledWidth => "SampledWidth must equal StoredWidth.",
359 Self::SampledXOffset => "SampledXOffset must be zero.",
360 Self::SampledYOffset => "SampledYOffset must be zero.",
361 Self::StoredF2Offset => "StoredF2Offset must be zero.",
362 Self::TransferCharacteristic => "TransferCharacteristic field is absent from the picture descriptor (Table 8).",
363 Self::TransferCharacteristicUnknown => "TransferCharacteristic UL is present but not a recognized value.",
364 Self::CodingEquationsUnknown => "CodingEquations UL is present but not a recognized value.",
365 Self::ColorPrimariesUnknown => "ColorPrimaries UL is present but not a recognized value.",
366 Self::J2KRequired => "Video essence is not JPEG 2000 encoded as required by App2E.",
367 Self::AlphaMaxRef => "AlphaMaxRef value is not permitted.",
368 Self::AlphaMinRef => "AlphaMinRef value is not permitted.",
369 Self::ComponentMaxRef => "ComponentMaxRef value is not in the permitted range.",
370 Self::ComponentMinRef => "ComponentMinRef value is not in the permitted range.",
371 Self::Palette => "Palette is present; palette images are not permitted in App2E.",
372 Self::PaletteLayout => "PaletteLayout is present; palette layout is not permitted in App2E.",
373 Self::ScanningDirection => "ScanningDirection value is not in the permitted set.",
374 Self::ComponentRefValues => "Component max/min reference values are inconsistent with bit depth.",
375 Self::AlphaSampleDepth => "AlphaSampleDepth value is not permitted.",
376 Self::ColorSiting => "ColorSiting value is not in the permitted set.",
377 Self::ComponentDepth => "ComponentDepth value is not in the permitted set (8 / 10 / 12 / 16).",
378 Self::HorizontalSubsampling => "HorizontalSubsampling value is not in the permitted set.",
379 Self::PaddingBits => "PaddingBits must be zero.",
380 Self::ReversedByteOrder => "ReversedByteOrder flag is set; byte reversal is not permitted.",
381 Self::VerticalSubsampling => "VerticalSubsampling value is not in the permitted set.",
382 Self::BlackRefLevel => "BlackRefLevel value is inconsistent with ComponentDepth.",
383 Self::ColorRange => "ColorRange value is not in the permitted set.",
384 Self::WhiteRefLevel => "WhiteRefLevel value is inconsistent with ComponentDepth.",
385 Self::AudioSampleRate => "Audio sample rate must be 48 000 Hz.",
386 Self::QuantizationBits => "QuantizationBits must be 16 or 24.",
387 Self::CodingStyle => "JPEG 2000 codestream coding style is not compliant.",
388 Self::J2CLayout => "JPEG 2000 codestream layout does not meet App2E requirements.",
389 Self::J2KExtendedCapabilities => "JPEG 2000 extended capabilities are declared but not permitted.",
390 Self::Jpeg2000SubDescriptor => "JPEG2000SubDescriptor is absent or incomplete.",
391 Self::J2KHtNotAllowed => "JPEG 2000 HT (ISO 15444-15) is not permitted by App2E 2020.",
392 Self::J2K4KResolution => "JPEG 2000 IMF 4K Profile: stored resolution is outside the permitted range.",
393 Self::J2K2KResolution => "JPEG 2000 IMF 2K Profile: stored resolution is outside the permitted range.",
394 Self::J2KBcpResolution => "JPEG 2000 Broadcast Contribution Profile: stored resolution is outside the permitted range.",
395 Self::ApplicationIdentification => "ApplicationIdentification is required for App2E compositions.",
396 Self::ContentMaturityRatingAgency => "ContentMaturityRating Agency is empty.",
397 Self::ContentMaturityRatingAgencyUri => "ContentMaturityRating Agency is not a valid xs:anyURI.",
398 Self::HomogeneousImageEssence => "All image essence in a composition shall use the same color system.",
399 Self::AppIdMismatch => "Application identifier in CPL ExtensionProperties does not match the expected App2E URI.",
400 Self::SegmentDurationMultiple => "Segment duration must be an integer multiple of 5 edit units.",
401 Self::MaxCLLMaxFALL => "MaxCLL / MaxFALL HDR metadata is absent; recommended for HDR content.",
402 }
403 }
404
405 fn default_severity(&self) -> Severity {
406 match self {
407 Self::MaxCLLMaxFALL => Severity::Info,
408 Self::AppIdMismatch | Self::Jpeg2000SubDescriptor => Severity::Warning,
409 Self::ContentMaturityRatingAgency | Self::ContentMaturityRatingAgencyUri => {
410 Severity::Error
411 }
412 _ => Severity::Error,
413 }
414 }
415
416 fn category(&self) -> Category {
417 match self {
418 Self::EmptyLanguageTag
419 | Self::MalformedLanguageTag
420 | Self::RegionCode
421 | Self::AppIdMismatch
422 | Self::ApplicationIdentification
423 | Self::ContentMaturityRatingAgency
424 | Self::ContentMaturityRatingAgencyUri => Category::Metadata,
425
426 Self::RequiredChannelCount
427 | Self::RequiredQuantizationBits
428 | Self::AudioSampleRate
429 | Self::QuantizationBits => Category::Audio,
430
431 Self::J2KRequired
432 | Self::CodingStyle
433 | Self::J2CLayout
434 | Self::J2KExtendedCapabilities
435 | Self::Jpeg2000SubDescriptor
436 | Self::J2KHtNotAllowed
437 | Self::J2K4KResolution
438 | Self::J2K2KResolution
439 | Self::J2KBcpResolution
440 | Self::RequiredStoredWidth
441 | Self::RequiredStoredHeight
442 | Self::RequiredSampleRate
443 | Self::RequiredFrameLayout
444 | Self::RequiredColorPrimaries
445 | Self::RequiredTransferCharacteristic
446 | Self::RequiredPictureCompression
447 | Self::RequiredComponentDepth => Category::Encoding,
448
449 Self::SegmentDurationMultiple => Category::Timing,
450
451 _ => Category::Video,
452 }
453 }
454}
455
456impl St2067_21_2023 {
457 pub const ALL: &'static [Self] = &[
458 Self::FrameRate,
459 Self::Resolution,
460 Self::EmptyLanguageTag,
461 Self::MalformedLanguageTag,
462 Self::RegionCode,
463 Self::ColorSystem,
464 Self::RequiredStoredWidth,
465 Self::RequiredStoredHeight,
466 Self::RequiredSampleRate,
467 Self::RequiredFrameLayout,
468 Self::RequiredColorPrimaries,
469 Self::RequiredTransferCharacteristic,
470 Self::RequiredPictureCompression,
471 Self::RequiredComponentDepth,
472 Self::RequiredChannelCount,
473 Self::RequiredQuantizationBits,
474 Self::AlphaTransparency,
475 Self::CodingEquations,
476 Self::ColorPrimaries,
477 Self::FieldDominance,
478 Self::FrameLayout,
479 Self::FrameLayoutInterlaced,
480 Self::ImageAlignmentOffset,
481 Self::ImageEndOffset,
482 Self::ImageStartOffset,
483 Self::SampledHeight,
484 Self::SampledWidth,
485 Self::SampledXOffset,
486 Self::SampledYOffset,
487 Self::StoredF2Offset,
488 Self::TransferCharacteristic,
489 Self::TransferCharacteristicUnknown,
490 Self::CodingEquationsUnknown,
491 Self::ColorPrimariesUnknown,
492 Self::J2KRequired,
493 Self::AlphaMaxRef,
494 Self::AlphaMinRef,
495 Self::ComponentMaxRef,
496 Self::ComponentMinRef,
497 Self::Palette,
498 Self::PaletteLayout,
499 Self::ScanningDirection,
500 Self::ComponentRefValues,
501 Self::AlphaSampleDepth,
502 Self::ColorSiting,
503 Self::ComponentDepth,
504 Self::HorizontalSubsampling,
505 Self::PaddingBits,
506 Self::ReversedByteOrder,
507 Self::VerticalSubsampling,
508 Self::BlackRefLevel,
509 Self::ColorRange,
510 Self::WhiteRefLevel,
511 Self::AudioSampleRate,
512 Self::QuantizationBits,
513 Self::CodingStyle,
514 Self::J2CLayout,
515 Self::J2KExtendedCapabilities,
516 Self::Jpeg2000SubDescriptor,
517 Self::J2KHtNotAllowed,
518 Self::J2K4KResolution,
519 Self::J2K2KResolution,
520 Self::J2KBcpResolution,
521 Self::ApplicationIdentification,
522 Self::ContentMaturityRatingAgency,
523 Self::ContentMaturityRatingAgencyUri,
524 Self::HomogeneousImageEssence,
525 Self::AppIdMismatch,
526 Self::SegmentDurationMultiple,
527 Self::MaxCLLMaxFALL,
528 ];
529}
530
531impl_into_string!(St2067_21_2023);
532
533#[derive(Debug, Clone, Copy, PartialEq, Eq, strum::EnumIter)]
539pub enum St2067_21_2025 {
540 FNTimedText,
542 HICTimedText,
544}
545
546impl ValidationCode for St2067_21_2025 {
547 fn code(&self) -> &'static str {
548 match self {
549 Self::FNTimedText => "ST2067-21:2025:5.6/FNTimedText",
550 Self::HICTimedText => "ST2067-21:2025:5.6/HICTimedText",
551 }
552 }
553 fn description(&self) -> &'static str {
554 match self {
555 Self::FNTimedText => {
556 "Timed text track designated as Forced Narrative (FN) does not comply with §5.6."
557 }
558 Self::HICTimedText => {
559 "Timed text track designated as HI-Caption (HIC) does not comply with §5.6."
560 }
561 }
562 }
563 fn default_severity(&self) -> Severity {
564 Severity::Error
565 }
566 fn category(&self) -> Category {
567 Category::Subtitle
568 }
569}
570
571impl St2067_21_2025 {
572 pub const ALL: &'static [Self] = &[Self::FNTimedText, Self::HICTimedText];
573}
574
575impl_into_string!(St2067_21_2025);