1use crate::TsError;
52
53#[derive(Debug, Clone)]
55pub struct Descriptor<'a> {
56 pub tag: u8,
58 pub data: &'a [u8],
60 pub body: DescriptorBody<'a>,
63}
64
65#[derive(Debug, Clone)]
67pub enum DescriptorBody<'a> {
68 VideoStream(VideoStreamDescriptor),
70 AudioStream(AudioStreamDescriptor),
72 Hierarchy(HierarchyDescriptor),
76 Registration {
80 format_identifier: [u8; 4],
81 additional_identification_info: &'a [u8],
82 },
83 DataStreamAlignment(DataStreamAlignmentDescriptor),
85 TargetBackgroundGrid(TargetBackgroundGridDescriptor),
90 VideoWindow(VideoWindowDescriptor),
94 Ca(CaDescriptor<'a>),
96 Iso639Language(Vec<Iso639Language>),
98 SystemClock(SystemClockDescriptor),
100 MultiplexBufferUtilization(MultiplexBufferUtilizationDescriptor),
102 Copyright(CopyrightDescriptor<'a>),
104 MaximumBitrate(MaximumBitrateDescriptor),
106 SmoothingBuffer(SmoothingBufferDescriptor),
108 Std(StdDescriptor),
110 Ibp(IbpDescriptor),
113 AvcVideo(AvcVideoDescriptor),
115 HevcVideo(HevcVideoDescriptor),
117 Service(ServiceDescriptor<'a>),
121 ShortEvent(ShortEventDescriptor<'a>),
125 Raw,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
144pub struct ServiceDescriptor<'a> {
145 pub service_type: u8,
149 pub service_provider_name: &'a [u8],
151 pub service_name: &'a [u8],
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq)]
171pub struct ShortEventDescriptor<'a> {
172 pub language_code: [u8; 3],
175 pub event_name: &'a [u8],
177 pub text: &'a [u8],
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub struct VideoStreamDescriptor {
185 pub multiple_frame_rate_flag: bool,
187 pub frame_rate_code: u8,
189 pub mpeg_1_only_flag: bool,
191 pub constrained_parameter_flag: bool,
193 pub still_picture_flag: bool,
195 pub profile_and_level_indication: Option<u8>,
197 pub chroma_format: Option<u8>,
199 pub frame_rate_extension_flag: Option<bool>,
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
205pub struct AudioStreamDescriptor {
206 pub free_format_flag: bool,
208 pub id: bool,
211 pub layer: u8,
213 pub variable_rate_audio_indicator: bool,
215}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub struct HierarchyDescriptor {
235 pub hierarchy_type: HierarchyType,
239 pub hierarchy_layer_index: u8,
242 pub hierarchy_embedded_layer_index: u8,
247 pub hierarchy_channel: u8,
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
261pub enum HierarchyType {
262 Mpeg2SpatialScalability,
264 Mpeg2SnrScalability,
266 Mpeg2TemporalScalability,
268 Mpeg2DataPartitioning,
270 Mpeg2AudioExtension,
272 PrivateStream,
274 Mpeg2MultiviewProfile,
276 BaseLayer,
279 Reserved(u8),
282 Unknown(u8),
286}
287
288impl HierarchyType {
289 pub fn from_nibble(value: u8) -> Self {
292 match value & 0x0F {
293 1 => HierarchyType::Mpeg2SpatialScalability,
294 2 => HierarchyType::Mpeg2SnrScalability,
295 3 => HierarchyType::Mpeg2TemporalScalability,
296 4 => HierarchyType::Mpeg2DataPartitioning,
297 5 => HierarchyType::Mpeg2AudioExtension,
298 6 => HierarchyType::PrivateStream,
299 7 => HierarchyType::Mpeg2MultiviewProfile,
300 15 => HierarchyType::BaseLayer,
301 other => HierarchyType::Reserved(other),
302 }
303 }
304
305 pub fn as_nibble(self) -> u8 {
310 match self {
311 HierarchyType::Mpeg2SpatialScalability => 1,
312 HierarchyType::Mpeg2SnrScalability => 2,
313 HierarchyType::Mpeg2TemporalScalability => 3,
314 HierarchyType::Mpeg2DataPartitioning => 4,
315 HierarchyType::Mpeg2AudioExtension => 5,
316 HierarchyType::PrivateStream => 6,
317 HierarchyType::Mpeg2MultiviewProfile => 7,
318 HierarchyType::BaseLayer => 15,
319 HierarchyType::Reserved(v) => v & 0x0F,
320 HierarchyType::Unknown(v) => v,
321 }
322 }
323
324 pub fn is_base_layer(self) -> bool {
327 matches!(self, HierarchyType::BaseLayer)
328 }
329}
330
331#[derive(Debug, Clone, Copy, PartialEq, Eq)]
333pub struct CaDescriptor<'a> {
334 pub ca_system_id: u16,
336 pub ca_pid: u16,
338 pub private_data: &'a [u8],
340}
341
342#[derive(Debug, Clone, Copy, PartialEq, Eq)]
344pub struct Iso639Language {
345 pub language: [u8; 3],
347 pub audio_type: u8,
350}
351
352#[derive(Debug, Clone, Copy, PartialEq, Eq)]
354pub struct AvcVideoDescriptor {
355 pub profile_idc: u8,
357 pub constraint_set_and_compat: u8,
360 pub level_idc: u8,
362 pub avc_still_present: bool,
364 pub avc_24_hour_picture_flag: bool,
366 pub frame_packing_sei_not_present_flag: bool,
369}
370
371#[derive(Debug, Clone, Copy, PartialEq, Eq)]
389pub struct DataStreamAlignmentDescriptor {
390 pub alignment_type: u8,
392}
393
394#[derive(Debug, Clone, Copy, PartialEq, Eq)]
423pub struct TargetBackgroundGridDescriptor {
424 pub horizontal_size: u16,
426 pub vertical_size: u16,
428 pub aspect_ratio_information: u8,
430}
431
432#[derive(Debug, Clone, Copy, PartialEq, Eq)]
462pub struct VideoWindowDescriptor {
463 pub horizontal_offset: u16,
465 pub vertical_offset: u16,
467 pub window_priority: u8,
470}
471
472#[derive(Debug, Clone, Copy, PartialEq, Eq)]
479pub struct SystemClockDescriptor {
480 pub external_clock_reference: bool,
483 pub clock_accuracy_integer: u8,
485 pub clock_accuracy_exponent: u8,
487}
488
489#[derive(Debug, Clone, Copy, PartialEq, Eq)]
499pub struct CopyrightDescriptor<'a> {
500 pub copyright_identifier: u32,
503 pub additional_copyright_info: &'a [u8],
506}
507
508#[derive(Debug, Clone, Copy, PartialEq, Eq)]
513pub struct MaximumBitrateDescriptor {
514 pub maximum_bitrate: u32,
516}
517
518impl MaximumBitrateDescriptor {
519 pub fn bits_per_second(self) -> u64 {
523 (self.maximum_bitrate as u64) * 400
524 }
525}
526
527#[derive(Debug, Clone, Copy, PartialEq, Eq)]
546pub struct SmoothingBufferDescriptor {
547 pub sb_leak_rate: u32,
550 pub sb_size: u32,
553}
554
555impl SmoothingBufferDescriptor {
556 pub fn leak_rate_bits_per_second(self) -> u64 {
560 (self.sb_leak_rate as u64) * 400
561 }
562
563 pub fn leak_rate_bytes_per_second(self) -> u64 {
566 (self.sb_leak_rate as u64) * 50
567 }
568
569 pub fn buffer_size_bytes(self) -> u64 {
573 self.sb_size as u64
574 }
575}
576
577#[derive(Debug, Clone, Copy, PartialEq, Eq)]
584pub struct StdDescriptor {
585 pub leak_valid_flag: bool,
587}
588
589#[derive(Debug, Clone, Copy, PartialEq, Eq)]
623pub struct MultiplexBufferUtilizationDescriptor {
624 pub bound_valid_flag: bool,
627 pub ltw_offset_lower_bound: u16,
630 pub ltw_offset_upper_bound: u16,
633}
634
635#[derive(Debug, Clone, Copy, PartialEq, Eq)]
663pub struct IbpDescriptor {
664 pub closed_gop_flag: bool,
666 pub identical_gop_flag: bool,
668 pub max_gop_length: u16,
671}
672
673impl IbpDescriptor {
674 pub fn is_well_formed(self) -> bool {
679 self.max_gop_length != 0
680 }
681}
682
683#[derive(Debug, Clone, Copy, PartialEq, Eq)]
685pub struct HevcVideoDescriptor {
686 pub profile_space: u8,
688 pub tier_flag: bool,
690 pub profile_idc: u8,
692 pub profile_compatibility_indication: u32,
694 pub progressive_source_flag: bool,
696 pub interlaced_source_flag: bool,
698 pub non_packed_constraint_flag: bool,
700 pub frame_only_constraint_flag: bool,
702 pub level_idc: u8,
704 pub temporal_layer_subset_flag: bool,
706 pub hevc_still_present_flag: bool,
708 pub hevc_24hr_picture_present_flag: bool,
710 pub temporal_id_min: Option<u8>,
713 pub temporal_id_max: Option<u8>,
716}
717
718pub fn iter_descriptors(block: &[u8]) -> DescriptorIter<'_> {
726 DescriptorIter { rest: block }
727}
728
729#[derive(Debug)]
731pub struct DescriptorIter<'a> {
732 rest: &'a [u8],
733}
734
735impl<'a> Iterator for DescriptorIter<'a> {
736 type Item = Result<Descriptor<'a>, TsError>;
737
738 fn next(&mut self) -> Option<Self::Item> {
739 if self.rest.is_empty() {
740 return None;
741 }
742 if self.rest.len() < 2 {
743 let have = self.rest.len();
744 self.rest = &[][..];
745 return Some(Err(TsError::Truncated {
746 what: "descriptor header",
747 have,
748 need: 2,
749 }));
750 }
751 let tag = self.rest[0];
752 let len = self.rest[1] as usize;
753 if self.rest.len() < 2 + len {
754 let have = self.rest.len() - 2;
755 self.rest = &[][..];
756 return Some(Err(TsError::Truncated {
757 what: "descriptor body",
758 have,
759 need: len,
760 }));
761 }
762 let data = &self.rest[2..2 + len];
763 self.rest = &self.rest[2 + len..];
764 Some(Ok(Descriptor {
765 tag,
766 data,
767 body: decode_body(tag, data),
768 }))
769 }
770}
771
772pub fn parse_descriptors(block: &[u8]) -> Result<Vec<Descriptor<'_>>, TsError> {
775 iter_descriptors(block).collect()
776}
777
778fn decode_body<'a>(tag: u8, data: &'a [u8]) -> DescriptorBody<'a> {
779 match tag {
780 0x02 => decode_video_stream(data).unwrap_or(DescriptorBody::Raw),
781 0x03 => decode_audio_stream(data).unwrap_or(DescriptorBody::Raw),
782 0x04 => decode_hierarchy(data).unwrap_or(DescriptorBody::Raw),
783 0x05 => decode_registration(data).unwrap_or(DescriptorBody::Raw),
784 0x06 => decode_data_stream_alignment(data).unwrap_or(DescriptorBody::Raw),
785 0x07 => decode_target_background_grid(data).unwrap_or(DescriptorBody::Raw),
786 0x08 => decode_video_window(data).unwrap_or(DescriptorBody::Raw),
787 0x09 => decode_ca(data).unwrap_or(DescriptorBody::Raw),
788 0x0A => decode_iso639_language(data).unwrap_or(DescriptorBody::Raw),
789 0x0B => decode_system_clock(data).unwrap_or(DescriptorBody::Raw),
790 0x0C => decode_multiplex_buffer_utilization(data).unwrap_or(DescriptorBody::Raw),
791 0x0D => decode_copyright(data).unwrap_or(DescriptorBody::Raw),
792 0x0E => decode_maximum_bitrate(data).unwrap_or(DescriptorBody::Raw),
793 0x10 => decode_smoothing_buffer(data).unwrap_or(DescriptorBody::Raw),
794 0x11 => decode_std(data).unwrap_or(DescriptorBody::Raw),
795 0x12 => decode_ibp(data).unwrap_or(DescriptorBody::Raw),
796 0x28 => decode_avc_video(data).unwrap_or(DescriptorBody::Raw),
797 0x38 => decode_hevc_video(data).unwrap_or(DescriptorBody::Raw),
798 0x48 => decode_service(data).unwrap_or(DescriptorBody::Raw),
799 0x4D => decode_short_event(data).unwrap_or(DescriptorBody::Raw),
800 _ => DescriptorBody::Raw,
801 }
802}
803
804fn decode_service(data: &[u8]) -> Option<DescriptorBody<'_>> {
805 if data.len() < 2 {
812 return None;
813 }
814 let service_type = data[0];
815 let provider_len = data[1] as usize;
816 let provider_start = 2usize;
817 let provider_end = provider_start.checked_add(provider_len)?;
818 if provider_end >= data.len() {
820 return None;
821 }
822 let service_provider_name = &data[provider_start..provider_end];
823 let name_len = data[provider_end] as usize;
824 let name_start = provider_end + 1;
825 let name_end = name_start.checked_add(name_len)?;
826 if name_end > data.len() {
827 return None;
828 }
829 let service_name = &data[name_start..name_end];
830 Some(DescriptorBody::Service(ServiceDescriptor {
831 service_type,
832 service_provider_name,
833 service_name,
834 }))
835}
836
837fn decode_short_event(data: &[u8]) -> Option<DescriptorBody<'_>> {
838 if data.len() < 4 {
845 return None;
846 }
847 let language_code = [data[0], data[1], data[2]];
848 let name_len = data[3] as usize;
849 let name_start = 4usize;
850 let name_end = name_start.checked_add(name_len)?;
851 if name_end >= data.len() {
853 return None;
854 }
855 let event_name = &data[name_start..name_end];
856 let text_len = data[name_end] as usize;
857 let text_start = name_end + 1;
858 let text_end = text_start.checked_add(text_len)?;
859 if text_end > data.len() {
860 return None;
861 }
862 let text = &data[text_start..text_end];
863 Some(DescriptorBody::ShortEvent(ShortEventDescriptor {
864 language_code,
865 event_name,
866 text,
867 }))
868}
869
870fn decode_video_stream(data: &[u8]) -> Option<DescriptorBody<'_>> {
871 if data.is_empty() {
872 return None;
873 }
874 let b0 = data[0];
875 let multiple_frame_rate_flag = (b0 & 0b1000_0000) != 0;
876 let frame_rate_code = (b0 >> 3) & 0b0000_1111;
877 let mpeg_1_only_flag = (b0 & 0b0000_0100) != 0;
878 let constrained_parameter_flag = (b0 & 0b0000_0010) != 0;
879 let still_picture_flag = (b0 & 0b0000_0001) != 0;
880 let (profile_and_level_indication, chroma_format, frame_rate_extension_flag) =
881 if !mpeg_1_only_flag && data.len() >= 3 {
882 let pli = data[1];
883 let b2 = data[2];
884 let chroma = (b2 >> 6) & 0b11;
885 let fre = (b2 & 0b0010_0000) != 0;
886 (Some(pli), Some(chroma), Some(fre))
887 } else {
888 (None, None, None)
889 };
890 Some(DescriptorBody::VideoStream(VideoStreamDescriptor {
891 multiple_frame_rate_flag,
892 frame_rate_code,
893 mpeg_1_only_flag,
894 constrained_parameter_flag,
895 still_picture_flag,
896 profile_and_level_indication,
897 chroma_format,
898 frame_rate_extension_flag,
899 }))
900}
901
902fn decode_audio_stream(data: &[u8]) -> Option<DescriptorBody<'_>> {
903 if data.is_empty() {
904 return None;
905 }
906 let b0 = data[0];
907 let free_format_flag = (b0 & 0b1000_0000) != 0;
908 let id = (b0 & 0b0100_0000) != 0;
909 let layer = (b0 >> 4) & 0b0000_0011;
910 let variable_rate_audio_indicator = (b0 & 0b0000_1000) != 0;
911 Some(DescriptorBody::AudioStream(AudioStreamDescriptor {
912 free_format_flag,
913 id,
914 layer,
915 variable_rate_audio_indicator,
916 }))
917}
918
919fn decode_hierarchy(data: &[u8]) -> Option<DescriptorBody<'_>> {
920 if data.len() < 4 {
926 return None;
927 }
928 let hierarchy_type = HierarchyType::from_nibble(data[0]);
929 let hierarchy_layer_index = data[1] & 0b0011_1111;
930 let hierarchy_embedded_layer_index = data[2] & 0b0011_1111;
931 let hierarchy_channel = data[3] & 0b0011_1111;
932 Some(DescriptorBody::Hierarchy(HierarchyDescriptor {
933 hierarchy_type,
934 hierarchy_layer_index,
935 hierarchy_embedded_layer_index,
936 hierarchy_channel,
937 }))
938}
939
940fn decode_registration(data: &[u8]) -> Option<DescriptorBody<'_>> {
941 if data.len() < 4 {
942 return None;
943 }
944 let mut format_identifier = [0u8; 4];
945 format_identifier.copy_from_slice(&data[..4]);
946 Some(DescriptorBody::Registration {
947 format_identifier,
948 additional_identification_info: &data[4..],
949 })
950}
951
952fn decode_ca(data: &[u8]) -> Option<DescriptorBody<'_>> {
953 if data.len() < 4 {
954 return None;
955 }
956 let ca_system_id = u16::from_be_bytes([data[0], data[1]]);
957 let ca_pid = (((data[2] & 0b0001_1111) as u16) << 8) | (data[3] as u16);
958 Some(DescriptorBody::Ca(CaDescriptor {
959 ca_system_id,
960 ca_pid,
961 private_data: &data[4..],
962 }))
963}
964
965fn decode_iso639_language(data: &[u8]) -> Option<DescriptorBody<'_>> {
966 if data.len() % 4 != 0 {
967 return None;
968 }
969 let mut langs = Vec::with_capacity(data.len() / 4);
970 for chunk in data.chunks_exact(4) {
971 let mut language = [0u8; 3];
972 language.copy_from_slice(&chunk[..3]);
973 langs.push(Iso639Language {
974 language,
975 audio_type: chunk[3],
976 });
977 }
978 Some(DescriptorBody::Iso639Language(langs))
979}
980
981fn decode_data_stream_alignment(data: &[u8]) -> Option<DescriptorBody<'_>> {
982 if data.is_empty() {
983 return None;
984 }
985 Some(DescriptorBody::DataStreamAlignment(
986 DataStreamAlignmentDescriptor {
987 alignment_type: data[0],
988 },
989 ))
990}
991
992fn decode_target_background_grid(data: &[u8]) -> Option<DescriptorBody<'_>> {
993 if data.len() < 4 {
1001 return None;
1002 }
1003 let horizontal_size = ((data[0] as u16) << 6) | ((data[1] >> 2) as u16);
1004 let vertical_size = (((data[1] & 0b0000_0011) as u16) << 12)
1005 | ((data[2] as u16) << 4)
1006 | ((data[3] >> 4) as u16);
1007 let aspect_ratio_information = data[3] & 0b0000_1111;
1008 Some(DescriptorBody::TargetBackgroundGrid(
1009 TargetBackgroundGridDescriptor {
1010 horizontal_size,
1011 vertical_size,
1012 aspect_ratio_information,
1013 },
1014 ))
1015}
1016
1017fn decode_video_window(data: &[u8]) -> Option<DescriptorBody<'_>> {
1018 if data.len() < 4 {
1027 return None;
1028 }
1029 let horizontal_offset = ((data[0] as u16) << 6) | ((data[1] >> 2) as u16);
1030 let vertical_offset = (((data[1] & 0b0000_0011) as u16) << 12)
1031 | ((data[2] as u16) << 4)
1032 | ((data[3] >> 4) as u16);
1033 let window_priority = data[3] & 0b0000_1111;
1034 Some(DescriptorBody::VideoWindow(VideoWindowDescriptor {
1035 horizontal_offset,
1036 vertical_offset,
1037 window_priority,
1038 }))
1039}
1040
1041fn decode_system_clock(data: &[u8]) -> Option<DescriptorBody<'_>> {
1042 if data.len() < 2 {
1046 return None;
1047 }
1048 let b0 = data[0];
1049 let b1 = data[1];
1050 let external_clock_reference = (b0 & 0b1000_0000) != 0;
1051 let clock_accuracy_integer = b0 & 0b0011_1111;
1052 let clock_accuracy_exponent = (b1 >> 5) & 0b0000_0111;
1053 Some(DescriptorBody::SystemClock(SystemClockDescriptor {
1054 external_clock_reference,
1055 clock_accuracy_integer,
1056 clock_accuracy_exponent,
1057 }))
1058}
1059
1060fn decode_multiplex_buffer_utilization(data: &[u8]) -> Option<DescriptorBody<'_>> {
1061 if data.len() < 4 {
1071 return None;
1072 }
1073 let bound_valid_flag = (data[0] & 0b1000_0000) != 0;
1074 let ltw_offset_lower_bound = (((data[0] & 0b0111_1111) as u16) << 8) | (data[1] as u16);
1075 let ltw_offset_upper_bound = (((data[2] & 0b0111_1111) as u16) << 8) | (data[3] as u16);
1076 Some(DescriptorBody::MultiplexBufferUtilization(
1077 MultiplexBufferUtilizationDescriptor {
1078 bound_valid_flag,
1079 ltw_offset_lower_bound,
1080 ltw_offset_upper_bound,
1081 },
1082 ))
1083}
1084
1085fn decode_copyright(data: &[u8]) -> Option<DescriptorBody<'_>> {
1086 if data.len() < 4 {
1089 return None;
1090 }
1091 let copyright_identifier = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
1092 Some(DescriptorBody::Copyright(CopyrightDescriptor {
1093 copyright_identifier,
1094 additional_copyright_info: &data[4..],
1095 }))
1096}
1097
1098fn decode_maximum_bitrate(data: &[u8]) -> Option<DescriptorBody<'_>> {
1099 if data.len() < 3 {
1102 return None;
1103 }
1104 let maximum_bitrate =
1105 (((data[0] & 0b0011_1111) as u32) << 16) | ((data[1] as u32) << 8) | (data[2] as u32);
1106 Some(DescriptorBody::MaximumBitrate(MaximumBitrateDescriptor {
1107 maximum_bitrate,
1108 }))
1109}
1110
1111fn decode_smoothing_buffer(data: &[u8]) -> Option<DescriptorBody<'_>> {
1112 if data.len() < 6 {
1121 return None;
1122 }
1123 let sb_leak_rate =
1124 (((data[0] & 0b0011_1111) as u32) << 16) | ((data[1] as u32) << 8) | (data[2] as u32);
1125 let sb_size =
1126 (((data[3] & 0b0011_1111) as u32) << 16) | ((data[4] as u32) << 8) | (data[5] as u32);
1127 Some(DescriptorBody::SmoothingBuffer(SmoothingBufferDescriptor {
1128 sb_leak_rate,
1129 sb_size,
1130 }))
1131}
1132
1133fn decode_std(data: &[u8]) -> Option<DescriptorBody<'_>> {
1134 if data.is_empty() {
1136 return None;
1137 }
1138 Some(DescriptorBody::Std(StdDescriptor {
1139 leak_valid_flag: (data[0] & 0b0000_0001) != 0,
1140 }))
1141}
1142
1143fn decode_ibp(data: &[u8]) -> Option<DescriptorBody<'_>> {
1144 if data.len() < 2 {
1153 return None;
1154 }
1155 let closed_gop_flag = (data[0] & 0b1000_0000) != 0;
1156 let identical_gop_flag = (data[0] & 0b0100_0000) != 0;
1157 let max_gop_length = (((data[0] & 0b0011_1111) as u16) << 8) | (data[1] as u16);
1158 Some(DescriptorBody::Ibp(IbpDescriptor {
1159 closed_gop_flag,
1160 identical_gop_flag,
1161 max_gop_length,
1162 }))
1163}
1164
1165fn decode_avc_video(data: &[u8]) -> Option<DescriptorBody<'_>> {
1166 if data.len() < 4 {
1167 return None;
1168 }
1169 let profile_idc = data[0];
1170 let constraint_set_and_compat = data[1];
1171 let level_idc = data[2];
1172 let flags = data[3];
1173 let avc_still_present = (flags & 0b1000_0000) != 0;
1174 let avc_24_hour_picture_flag = (flags & 0b0100_0000) != 0;
1175 let frame_packing_sei_not_present_flag = (flags & 0b0010_0000) != 0;
1176 Some(DescriptorBody::AvcVideo(AvcVideoDescriptor {
1177 profile_idc,
1178 constraint_set_and_compat,
1179 level_idc,
1180 avc_still_present,
1181 avc_24_hour_picture_flag,
1182 frame_packing_sei_not_present_flag,
1183 }))
1184}
1185
1186fn decode_hevc_video(data: &[u8]) -> Option<DescriptorBody<'_>> {
1187 if data.len() < 13 {
1189 return None;
1190 }
1191 let b0 = data[0];
1192 let profile_space = (b0 >> 6) & 0b11;
1193 let tier_flag = (b0 & 0b0010_0000) != 0;
1194 let profile_idc = b0 & 0b0001_1111;
1195 let profile_compatibility_indication = u32::from_be_bytes([data[1], data[2], data[3], data[4]]);
1196 let b5 = data[5];
1197 let progressive_source_flag = (b5 & 0b1000_0000) != 0;
1198 let interlaced_source_flag = (b5 & 0b0100_0000) != 0;
1199 let non_packed_constraint_flag = (b5 & 0b0010_0000) != 0;
1200 let frame_only_constraint_flag = (b5 & 0b0001_0000) != 0;
1201 let level_idc = data[12];
1205 let (temporal_layer_subset_flag, hevc_still_present_flag, hevc_24hr_picture_present_flag) =
1206 if data.len() >= 14 {
1207 let b13 = data[13];
1208 (
1209 (b13 & 0b1000_0000) != 0,
1210 (b13 & 0b0100_0000) != 0,
1211 (b13 & 0b0010_0000) != 0,
1212 )
1213 } else {
1214 (false, false, false)
1215 };
1216 let (temporal_id_min, temporal_id_max) = if temporal_layer_subset_flag && data.len() >= 16 {
1217 let lo = (data[14] >> 5) & 0b111;
1220 let hi = (data[15] >> 5) & 0b111;
1221 (Some(lo), Some(hi))
1222 } else {
1223 (None, None)
1224 };
1225 Some(DescriptorBody::HevcVideo(HevcVideoDescriptor {
1226 profile_space,
1227 tier_flag,
1228 profile_idc,
1229 profile_compatibility_indication,
1230 progressive_source_flag,
1231 interlaced_source_flag,
1232 non_packed_constraint_flag,
1233 frame_only_constraint_flag,
1234 level_idc,
1235 temporal_layer_subset_flag,
1236 hevc_still_present_flag,
1237 hevc_24hr_picture_present_flag,
1238 temporal_id_min,
1239 temporal_id_max,
1240 }))
1241}
1242
1243#[cfg(test)]
1244mod tests {
1245 use super::*;
1246
1247 fn tlv(tag: u8, body: &[u8]) -> Vec<u8> {
1248 let mut v = vec![tag, body.len() as u8];
1249 v.extend_from_slice(body);
1250 v
1251 }
1252
1253 #[test]
1254 fn iter_empty_block_yields_none() {
1255 let mut it = iter_descriptors(&[]);
1256 assert!(it.next().is_none());
1257 }
1258
1259 #[test]
1260 fn unknown_tag_passes_through_as_raw() {
1261 let block = tlv(0x42, &[0xAA, 0xBB, 0xCC]);
1262 let d = iter_descriptors(&block).next().unwrap().unwrap();
1263 assert_eq!(d.tag, 0x42);
1264 assert_eq!(d.data, &[0xAA, 0xBB, 0xCC]);
1265 assert!(matches!(d.body, DescriptorBody::Raw));
1266 }
1267
1268 #[test]
1269 fn two_descriptors_back_to_back() {
1270 let mut block = Vec::new();
1271 block.extend_from_slice(&tlv(0x05, b"HDMV"));
1272 block.extend_from_slice(&tlv(0x09, &[0x09, 0x00, 0xE5, 0x00, 0xAB, 0xCD]));
1273 let v: Vec<_> = iter_descriptors(&block).collect();
1274 assert_eq!(v.len(), 2);
1275 let d0 = v[0].as_ref().unwrap();
1276 assert_eq!(d0.tag, 0x05);
1277 match &d0.body {
1278 DescriptorBody::Registration {
1279 format_identifier,
1280 additional_identification_info,
1281 } => {
1282 assert_eq!(format_identifier, b"HDMV");
1283 assert!(additional_identification_info.is_empty());
1284 }
1285 other => panic!("expected Registration, got {other:?}"),
1286 }
1287 let d1 = v[1].as_ref().unwrap();
1288 assert_eq!(d1.tag, 0x09);
1289 match &d1.body {
1290 DescriptorBody::Ca(ca) => {
1291 assert_eq!(ca.ca_system_id, 0x0900);
1292 assert_eq!(ca.ca_pid, 0x0500);
1293 assert_eq!(ca.private_data, &[0xAB, 0xCD]);
1294 }
1295 other => panic!("expected Ca, got {other:?}"),
1296 }
1297 }
1298
1299 #[test]
1300 fn truncated_header_surfaces_error_then_stops() {
1301 let block = [0x05u8]; let mut it = iter_descriptors(&block);
1303 let err = it.next().expect("one error").unwrap_err();
1304 assert!(matches!(err, TsError::Truncated { .. }));
1305 assert!(it.next().is_none());
1306 }
1307
1308 #[test]
1309 fn truncated_body_surfaces_error_then_stops() {
1310 let mut block = vec![0x05u8, 0x08]; block.extend_from_slice(&[0xAA, 0xBB]); let mut it = iter_descriptors(&block);
1313 let err = it.next().expect("one error").unwrap_err();
1314 assert!(matches!(err, TsError::Truncated { .. }));
1315 assert!(it.next().is_none());
1316 }
1317
1318 #[test]
1319 fn registration_descriptor_decodes_hdmv_with_trailer() {
1320 let block = tlv(0x05, b"HDMV\x88\x99");
1321 let d = iter_descriptors(&block).next().unwrap().unwrap();
1322 match &d.body {
1323 DescriptorBody::Registration {
1324 format_identifier,
1325 additional_identification_info,
1326 } => {
1327 assert_eq!(format_identifier, b"HDMV");
1328 assert_eq!(additional_identification_info, &[0x88, 0x99]);
1329 }
1330 other => panic!("expected Registration, got {other:?}"),
1331 }
1332 }
1333
1334 #[test]
1335 fn iso639_language_descriptor_two_entries() {
1336 let body = [b'e', b'n', b'g', 0x00, b'j', b'p', b'n', 0x02];
1338 let block = tlv(0x0A, &body);
1339 let d = iter_descriptors(&block).next().unwrap().unwrap();
1340 match &d.body {
1341 DescriptorBody::Iso639Language(langs) => {
1342 assert_eq!(langs.len(), 2);
1343 assert_eq!(&langs[0].language, b"eng");
1344 assert_eq!(langs[0].audio_type, 0);
1345 assert_eq!(&langs[1].language, b"jpn");
1346 assert_eq!(langs[1].audio_type, 2);
1347 }
1348 other => panic!("expected Iso639Language, got {other:?}"),
1349 }
1350 }
1351
1352 #[test]
1353 fn iso639_language_bad_length_falls_back_to_raw() {
1354 let body = [b'e', b'n', b'g', 0x00, 0xFF];
1356 let block = tlv(0x0A, &body);
1357 let d = iter_descriptors(&block).next().unwrap().unwrap();
1358 assert!(matches!(d.body, DescriptorBody::Raw));
1359 assert_eq!(d.data, &body);
1360 }
1361
1362 #[test]
1363 fn video_stream_descriptor_mpeg2_three_bytes() {
1364 let body = [4u8 << 3, 0x44u8, 0b01 << 6];
1368 let block = tlv(0x02, &body);
1369 let d = iter_descriptors(&block).next().unwrap().unwrap();
1370 match &d.body {
1371 DescriptorBody::VideoStream(v) => {
1372 assert!(!v.multiple_frame_rate_flag);
1373 assert_eq!(v.frame_rate_code, 4);
1374 assert!(!v.mpeg_1_only_flag);
1375 assert_eq!(v.profile_and_level_indication, Some(0x44));
1376 assert_eq!(v.chroma_format, Some(0b01));
1377 assert_eq!(v.frame_rate_extension_flag, Some(false));
1378 }
1379 other => panic!("expected VideoStream, got {other:?}"),
1380 }
1381 }
1382
1383 #[test]
1384 fn video_stream_descriptor_mpeg1_one_byte() {
1385 let body = [(3 << 3) | 0b0000_0101];
1387 let block = tlv(0x02, &body);
1388 let d = iter_descriptors(&block).next().unwrap().unwrap();
1389 match &d.body {
1390 DescriptorBody::VideoStream(v) => {
1391 assert!(v.mpeg_1_only_flag);
1392 assert_eq!(v.frame_rate_code, 3);
1393 assert!(v.still_picture_flag);
1394 assert!(v.profile_and_level_indication.is_none());
1395 assert!(v.chroma_format.is_none());
1396 assert!(v.frame_rate_extension_flag.is_none());
1397 }
1398 other => panic!("expected VideoStream, got {other:?}"),
1399 }
1400 }
1401
1402 #[test]
1403 fn audio_stream_descriptor_layer_ii() {
1404 let body = [(1u8 << 6) | (0b10 << 4) | (1 << 3)];
1406 let block = tlv(0x03, &body);
1407 let d = iter_descriptors(&block).next().unwrap().unwrap();
1408 match &d.body {
1409 DescriptorBody::AudioStream(a) => {
1410 assert!(!a.free_format_flag);
1411 assert!(a.id);
1412 assert_eq!(a.layer, 0b10);
1413 assert!(a.variable_rate_audio_indicator);
1414 }
1415 other => panic!("expected AudioStream, got {other:?}"),
1416 }
1417 }
1418
1419 #[test]
1420 fn ca_descriptor_min_no_private_data() {
1421 let body = [0x4A, 0xAA, 0xE1 , 0x23];
1423 let block = tlv(0x09, &body);
1424 let d = iter_descriptors(&block).next().unwrap().unwrap();
1425 match &d.body {
1426 DescriptorBody::Ca(ca) => {
1427 assert_eq!(ca.ca_system_id, 0x4AAA);
1428 assert_eq!(ca.ca_pid, 0x0123);
1429 assert!(ca.private_data.is_empty());
1430 }
1431 other => panic!("expected Ca, got {other:?}"),
1432 }
1433 }
1434
1435 #[test]
1436 fn avc_video_descriptor_typical_values() {
1437 let body = [100, 0x00, 41, 0x00];
1440 let block = tlv(0x28, &body);
1441 let d = iter_descriptors(&block).next().unwrap().unwrap();
1442 match &d.body {
1443 DescriptorBody::AvcVideo(a) => {
1444 assert_eq!(a.profile_idc, 100);
1445 assert_eq!(a.level_idc, 41);
1446 assert!(!a.avc_still_present);
1447 assert!(!a.frame_packing_sei_not_present_flag);
1448 }
1449 other => panic!("expected AvcVideo, got {other:?}"),
1450 }
1451 }
1452
1453 #[test]
1454 fn hevc_video_descriptor_min_13_bytes() {
1455 let b0 = (1u8 << 5) | 2;
1457 let compat: u32 = 0x6000_0000;
1458 let b5: u8 = 0b1011_0000;
1460 let level_idc: u8 = 153;
1461 let body = vec![
1462 b0,
1463 (compat >> 24) as u8,
1464 (compat >> 16) as u8,
1465 (compat >> 8) as u8,
1466 compat as u8,
1467 b5,
1468 0,
1469 0,
1470 0,
1471 0,
1472 0,
1473 0,
1474 level_idc,
1475 ];
1476 let block = tlv(0x38, &body);
1478 let d = iter_descriptors(&block).next().unwrap().unwrap();
1479 match &d.body {
1480 DescriptorBody::HevcVideo(h) => {
1481 assert_eq!(h.profile_space, 0);
1482 assert!(h.tier_flag);
1483 assert_eq!(h.profile_idc, 2);
1484 assert_eq!(h.profile_compatibility_indication, compat);
1485 assert!(h.progressive_source_flag);
1486 assert!(!h.interlaced_source_flag);
1487 assert!(h.non_packed_constraint_flag);
1488 assert!(h.frame_only_constraint_flag);
1489 assert_eq!(h.level_idc, level_idc);
1490 assert!(!h.temporal_layer_subset_flag);
1491 assert!(h.temporal_id_min.is_none());
1492 assert!(h.temporal_id_max.is_none());
1493 }
1494 other => panic!("expected HevcVideo, got {other:?}"),
1495 }
1496 }
1497
1498 #[test]
1499 fn hevc_video_descriptor_with_temporal_layer_subset() {
1500 let mut body = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0, 0, 120];
1501 body.push(0b1010_0000);
1503 body.push(1 << 5);
1505 body.push(4 << 5);
1506 let block = tlv(0x38, &body);
1507 let d = iter_descriptors(&block).next().unwrap().unwrap();
1508 match &d.body {
1509 DescriptorBody::HevcVideo(h) => {
1510 assert!(h.temporal_layer_subset_flag);
1511 assert!(h.hevc_24hr_picture_present_flag);
1512 assert_eq!(h.temporal_id_min, Some(1));
1513 assert_eq!(h.temporal_id_max, Some(4));
1514 }
1515 other => panic!("expected HevcVideo, got {other:?}"),
1516 }
1517 }
1518
1519 #[test]
1520 fn data_stream_alignment_video_access_unit() {
1521 let block = tlv(0x06, &[0x02]);
1523 let d = iter_descriptors(&block).next().unwrap().unwrap();
1524 match &d.body {
1525 DescriptorBody::DataStreamAlignment(a) => {
1526 assert_eq!(a.alignment_type, 0x02);
1527 }
1528 other => panic!("expected DataStreamAlignment, got {other:?}"),
1529 }
1530 }
1531
1532 #[test]
1533 fn data_stream_alignment_empty_body_falls_back_to_raw() {
1534 let block = tlv(0x06, &[]);
1535 let d = iter_descriptors(&block).next().unwrap().unwrap();
1536 assert!(matches!(d.body, DescriptorBody::Raw));
1537 }
1538
1539 #[test]
1540 fn system_clock_descriptor_external_ref_off() {
1541 let b0 = 0b0100_1010u8;
1544 let b1 = 0b0110_0000u8;
1545 let block = tlv(0x0B, &[b0, b1]);
1546 let d = iter_descriptors(&block).next().unwrap().unwrap();
1547 match &d.body {
1548 DescriptorBody::SystemClock(s) => {
1549 assert!(!s.external_clock_reference);
1550 assert_eq!(s.clock_accuracy_integer, 10);
1551 assert_eq!(s.clock_accuracy_exponent, 3);
1552 }
1553 other => panic!("expected SystemClock, got {other:?}"),
1554 }
1555 }
1556
1557 #[test]
1558 fn system_clock_descriptor_external_ref_on() {
1559 let block = tlv(0x0B, &[0b1000_0000, 0b0000_0000]);
1562 let d = iter_descriptors(&block).next().unwrap().unwrap();
1563 match &d.body {
1564 DescriptorBody::SystemClock(s) => {
1565 assert!(s.external_clock_reference);
1566 assert_eq!(s.clock_accuracy_integer, 0);
1567 assert_eq!(s.clock_accuracy_exponent, 0);
1568 }
1569 other => panic!("expected SystemClock, got {other:?}"),
1570 }
1571 }
1572
1573 #[test]
1574 fn maximum_bitrate_descriptor_typical() {
1575 let b0 = 0b1100_0000 | 0b0001_0010; let block = tlv(0x0E, &[b0, 0x34, 0x56]);
1580 let d = iter_descriptors(&block).next().unwrap().unwrap();
1581 match &d.body {
1582 DescriptorBody::MaximumBitrate(m) => {
1583 assert_eq!(m.maximum_bitrate, 0x12_3456);
1584 assert_eq!(m.bits_per_second(), 0x12_3456u64 * 400);
1586 }
1587 other => panic!("expected MaximumBitrate, got {other:?}"),
1588 }
1589 }
1590
1591 #[test]
1592 fn maximum_bitrate_descriptor_zero_bitrate() {
1593 let block = tlv(0x0E, &[0b1100_0000, 0x00, 0x00]);
1595 let d = iter_descriptors(&block).next().unwrap().unwrap();
1596 match &d.body {
1597 DescriptorBody::MaximumBitrate(m) => {
1598 assert_eq!(m.maximum_bitrate, 0);
1599 assert_eq!(m.bits_per_second(), 0);
1600 }
1601 other => panic!("expected MaximumBitrate, got {other:?}"),
1602 }
1603 }
1604
1605 #[test]
1606 fn maximum_bitrate_descriptor_short_body_falls_back_to_raw() {
1607 let block = tlv(0x0E, &[0xC0, 0x00]); let d = iter_descriptors(&block).next().unwrap().unwrap();
1609 assert!(matches!(d.body, DescriptorBody::Raw));
1610 }
1611
1612 #[test]
1613 fn std_descriptor_leak_valid_set() {
1614 let block = tlv(0x11, &[0b1111_1111]);
1616 let d = iter_descriptors(&block).next().unwrap().unwrap();
1617 match &d.body {
1618 DescriptorBody::Std(s) => assert!(s.leak_valid_flag),
1619 other => panic!("expected Std, got {other:?}"),
1620 }
1621 }
1622
1623 #[test]
1624 fn std_descriptor_leak_valid_unset() {
1625 let block = tlv(0x11, &[0b1111_1110]);
1626 let d = iter_descriptors(&block).next().unwrap().unwrap();
1627 match &d.body {
1628 DescriptorBody::Std(s) => assert!(!s.leak_valid_flag),
1629 other => panic!("expected Std, got {other:?}"),
1630 }
1631 }
1632
1633 #[test]
1634 fn smoothing_buffer_descriptor_typical_values() {
1635 let leak: u32 = 0x09_C400;
1641 let size: u32 = 0x00_C000;
1642 let body = [
1643 0b1100_0000 | ((leak >> 16) as u8 & 0b0011_1111),
1644 (leak >> 8) as u8,
1645 leak as u8,
1646 0b1100_0000 | ((size >> 16) as u8 & 0b0011_1111),
1647 (size >> 8) as u8,
1648 size as u8,
1649 ];
1650 let block = tlv(0x10, &body);
1651 let d = iter_descriptors(&block).next().unwrap().unwrap();
1652 match &d.body {
1653 DescriptorBody::SmoothingBuffer(sb) => {
1654 assert_eq!(sb.sb_leak_rate, leak);
1655 assert_eq!(sb.sb_size, size);
1656 assert_eq!(sb.leak_rate_bits_per_second(), 256_000_000);
1658 assert_eq!(sb.leak_rate_bytes_per_second(), 32_000_000);
1660 assert_eq!(sb.buffer_size_bytes(), 49_152);
1661 }
1662 other => panic!("expected SmoothingBuffer, got {other:?}"),
1663 }
1664 }
1665
1666 #[test]
1667 fn smoothing_buffer_descriptor_zero_fields() {
1668 let block = tlv(0x10, &[0u8; 6]);
1671 let d = iter_descriptors(&block).next().unwrap().unwrap();
1672 match &d.body {
1673 DescriptorBody::SmoothingBuffer(sb) => {
1674 assert_eq!(sb.sb_leak_rate, 0);
1675 assert_eq!(sb.sb_size, 0);
1676 assert_eq!(sb.leak_rate_bits_per_second(), 0);
1677 assert_eq!(sb.buffer_size_bytes(), 0);
1678 }
1679 other => panic!("expected SmoothingBuffer, got {other:?}"),
1680 }
1681 }
1682
1683 #[test]
1684 fn smoothing_buffer_descriptor_max_22bit_fields() {
1685 let max22: u32 = 0x003F_FFFF;
1689 let body = [0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8];
1690 let block = tlv(0x10, &body);
1691 let d = iter_descriptors(&block).next().unwrap().unwrap();
1692 match &d.body {
1693 DescriptorBody::SmoothingBuffer(sb) => {
1694 assert_eq!(sb.sb_leak_rate, max22);
1695 assert_eq!(sb.sb_size, max22);
1696 assert_eq!(sb.leak_rate_bits_per_second(), (max22 as u64) * 400);
1697 assert_eq!(sb.buffer_size_bytes(), max22 as u64);
1698 }
1699 other => panic!("expected SmoothingBuffer, got {other:?}"),
1700 }
1701 }
1702
1703 #[test]
1704 fn smoothing_buffer_descriptor_short_body_falls_back_to_raw() {
1705 let block = tlv(0x10, &[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
1707 let d = iter_descriptors(&block).next().unwrap().unwrap();
1708 assert!(matches!(d.body, DescriptorBody::Raw));
1709 assert_eq!(d.data.len(), 5);
1710 }
1711
1712 #[test]
1713 fn smoothing_buffer_descriptor_lives_in_pmt_program_info() {
1714 let mut block = Vec::new();
1719 block.extend_from_slice(&tlv(0x0A, &[b'f', b'r', b'a', 0x00]));
1720 let leak: u32 = 0x0001_0000; let size: u32 = 0x0000_4000; let sb_body = [
1723 ((leak >> 16) as u8) & 0b0011_1111,
1724 (leak >> 8) as u8,
1725 leak as u8,
1726 ((size >> 16) as u8) & 0b0011_1111,
1727 (size >> 8) as u8,
1728 size as u8,
1729 ];
1730 block.extend_from_slice(&tlv(0x10, &sb_body));
1731 block.extend_from_slice(&tlv(0x11, &[0b1111_1111]));
1732 let v = parse_descriptors(&block).unwrap();
1733 assert_eq!(v.len(), 3);
1734 assert_eq!(v[0].tag, 0x0A);
1735 assert_eq!(v[1].tag, 0x10);
1736 match &v[1].body {
1737 DescriptorBody::SmoothingBuffer(sb) => {
1738 assert_eq!(sb.sb_leak_rate, leak);
1739 assert_eq!(sb.sb_size, size);
1740 }
1741 other => panic!("expected SmoothingBuffer, got {other:?}"),
1742 }
1743 assert_eq!(v[2].tag, 0x11);
1744 match &v[2].body {
1745 DescriptorBody::Std(s) => assert!(s.leak_valid_flag),
1746 other => panic!("expected Std, got {other:?}"),
1747 }
1748 }
1749
1750 #[test]
1751 fn copyright_descriptor_identifier_only_no_trailer() {
1752 let body = [0x49, 0x53, 0x42, 0x43];
1755 let block = tlv(0x0D, &body);
1756 let d = iter_descriptors(&block).next().unwrap().unwrap();
1757 match &d.body {
1758 DescriptorBody::Copyright(c) => {
1759 assert_eq!(c.copyright_identifier, 0x4953_4243);
1760 assert!(c.additional_copyright_info.is_empty());
1761 }
1762 other => panic!("expected Copyright, got {other:?}"),
1763 }
1764 }
1765
1766 #[test]
1767 fn copyright_descriptor_with_trailing_info() {
1768 let body = [0x00, 0x00, 0x00, 0x01, 0xDE, 0xAD, 0xBE, 0xEF, 0x42];
1771 let block = tlv(0x0D, &body);
1772 let d = iter_descriptors(&block).next().unwrap().unwrap();
1773 match &d.body {
1774 DescriptorBody::Copyright(c) => {
1775 assert_eq!(c.copyright_identifier, 0x0000_0001);
1776 assert_eq!(c.additional_copyright_info, &[0xDE, 0xAD, 0xBE, 0xEF, 0x42]);
1777 }
1778 other => panic!("expected Copyright, got {other:?}"),
1779 }
1780 }
1781
1782 #[test]
1783 fn copyright_descriptor_short_body_falls_back_to_raw() {
1784 let block = tlv(0x0D, &[0xAA, 0xBB, 0xCC]);
1786 let d = iter_descriptors(&block).next().unwrap().unwrap();
1787 assert!(matches!(d.body, DescriptorBody::Raw));
1788 assert_eq!(d.data, &[0xAA, 0xBB, 0xCC]);
1789 }
1790
1791 #[test]
1792 fn copyright_descriptor_zero_body_falls_back_to_raw() {
1793 let block = tlv(0x0D, &[]);
1797 let d = iter_descriptors(&block).next().unwrap().unwrap();
1798 assert!(matches!(d.body, DescriptorBody::Raw));
1799 assert!(d.data.is_empty());
1800 }
1801
1802 #[test]
1803 fn copyright_descriptor_in_pmt_program_info_alongside_other_tags() {
1804 let mut block = Vec::new();
1809 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
1810 let cid: u32 = 0x4953_524E; let trailer = [0x12, 0x34];
1812 let mut copy_body = Vec::new();
1813 copy_body.extend_from_slice(&cid.to_be_bytes());
1814 copy_body.extend_from_slice(&trailer);
1815 block.extend_from_slice(&tlv(0x0D, ©_body));
1816 let leak: u32 = 0x0001_0000;
1817 let size: u32 = 0x0000_4000;
1818 let sb_body = [
1819 ((leak >> 16) as u8) & 0b0011_1111,
1820 (leak >> 8) as u8,
1821 leak as u8,
1822 ((size >> 16) as u8) & 0b0011_1111,
1823 (size >> 8) as u8,
1824 size as u8,
1825 ];
1826 block.extend_from_slice(&tlv(0x10, &sb_body));
1827 let v = parse_descriptors(&block).unwrap();
1828 assert_eq!(v.len(), 3);
1829 assert_eq!(v[0].tag, 0x0A);
1830 assert_eq!(v[1].tag, 0x0D);
1831 match &v[1].body {
1832 DescriptorBody::Copyright(c) => {
1833 assert_eq!(c.copyright_identifier, cid);
1834 assert_eq!(c.additional_copyright_info, &trailer);
1835 }
1836 other => panic!("expected Copyright, got {other:?}"),
1837 }
1838 assert_eq!(v[2].tag, 0x10);
1839 assert!(matches!(v[2].body, DescriptorBody::SmoothingBuffer(_)));
1840 }
1841
1842 #[test]
1843 fn hierarchy_descriptor_spatial_scalability_layer() {
1844 let body = [
1848 0b1111_0001, 0b1100_0000 | 5, 0b1100_0000 | 15, 0b1100_0000, ];
1853 let block = tlv(0x04, &body);
1854 let d = iter_descriptors(&block).next().unwrap().unwrap();
1855 match &d.body {
1856 DescriptorBody::Hierarchy(h) => {
1857 assert_eq!(h.hierarchy_type, HierarchyType::Mpeg2SpatialScalability);
1858 assert_eq!(h.hierarchy_type.as_nibble(), 1);
1859 assert!(!h.hierarchy_type.is_base_layer());
1860 assert_eq!(h.hierarchy_layer_index, 5);
1861 assert_eq!(h.hierarchy_embedded_layer_index, 15);
1862 assert_eq!(h.hierarchy_channel, 0);
1863 }
1864 other => panic!("expected Hierarchy, got {other:?}"),
1865 }
1866 }
1867
1868 #[test]
1869 fn hierarchy_descriptor_base_layer_marker() {
1870 let body = [
1875 0b0000_1111, 0b0000_0001, 0b0011_1111, 0b0000_0010, ];
1880 let block = tlv(0x04, &body);
1881 let d = iter_descriptors(&block).next().unwrap().unwrap();
1882 match &d.body {
1883 DescriptorBody::Hierarchy(h) => {
1884 assert_eq!(h.hierarchy_type, HierarchyType::BaseLayer);
1885 assert!(h.hierarchy_type.is_base_layer());
1886 assert_eq!(h.hierarchy_layer_index, 1);
1887 assert_eq!(h.hierarchy_embedded_layer_index, 0x3F);
1888 assert_eq!(h.hierarchy_channel, 2);
1889 }
1890 other => panic!("expected Hierarchy, got {other:?}"),
1891 }
1892 }
1893
1894 #[test]
1895 fn hierarchy_descriptor_all_typed_variants_round_trip() {
1896 let mapped = [
1900 (1u8, HierarchyType::Mpeg2SpatialScalability),
1901 (2, HierarchyType::Mpeg2SnrScalability),
1902 (3, HierarchyType::Mpeg2TemporalScalability),
1903 (4, HierarchyType::Mpeg2DataPartitioning),
1904 (5, HierarchyType::Mpeg2AudioExtension),
1905 (6, HierarchyType::PrivateStream),
1906 (7, HierarchyType::Mpeg2MultiviewProfile),
1907 (15, HierarchyType::BaseLayer),
1908 ];
1909 for (raw, expected) in mapped {
1910 let decoded = HierarchyType::from_nibble(raw);
1911 assert_eq!(decoded, expected, "wire nibble {raw}");
1912 assert_eq!(decoded.as_nibble(), raw, "round-trip for {raw}");
1913 }
1914 assert!(HierarchyType::BaseLayer.is_base_layer());
1915 for (_, t) in mapped[..7].iter().copied() {
1917 assert!(!t.is_base_layer());
1918 }
1919 }
1920
1921 #[test]
1922 fn hierarchy_descriptor_reserved_values_preserve_raw_nibble() {
1923 for raw in [0u8, 8, 9, 10, 11, 12, 13, 14] {
1927 let decoded = HierarchyType::from_nibble(raw);
1928 assert_eq!(decoded, HierarchyType::Reserved(raw));
1929 assert_eq!(decoded.as_nibble(), raw);
1930 assert!(!decoded.is_base_layer());
1931 }
1932 assert_eq!(HierarchyType::Unknown(0xAB).as_nibble(), 0xAB);
1935 }
1936
1937 #[test]
1938 fn hierarchy_descriptor_high_nibble_ignored_in_type_byte() {
1939 let body = [0b1010_0011, 0, 0, 0]; let block = tlv(0x04, &body);
1944 let d = iter_descriptors(&block).next().unwrap().unwrap();
1945 match &d.body {
1946 DescriptorBody::Hierarchy(h) => {
1947 assert_eq!(h.hierarchy_type, HierarchyType::Mpeg2TemporalScalability);
1948 }
1949 other => panic!("expected Hierarchy, got {other:?}"),
1950 }
1951 }
1952
1953 #[test]
1954 fn hierarchy_descriptor_short_body_falls_back_to_raw() {
1955 let block = tlv(0x04, &[0x0F, 0xC0, 0xC0]);
1957 let d = iter_descriptors(&block).next().unwrap().unwrap();
1958 assert!(matches!(d.body, DescriptorBody::Raw));
1959 assert_eq!(d.data, &[0x0F, 0xC0, 0xC0]);
1960 }
1961
1962 #[test]
1963 fn hierarchy_descriptor_max_6bit_index_fields() {
1964 let body = [
1968 0b0000_0010, 0xFF, 0xFF, 0xFF, ];
1973 let block = tlv(0x04, &body);
1974 let d = iter_descriptors(&block).next().unwrap().unwrap();
1975 match &d.body {
1976 DescriptorBody::Hierarchy(h) => {
1977 assert_eq!(h.hierarchy_type, HierarchyType::Mpeg2SnrScalability);
1978 assert_eq!(h.hierarchy_layer_index, 0x3F);
1979 assert_eq!(h.hierarchy_embedded_layer_index, 0x3F);
1980 assert_eq!(h.hierarchy_channel, 0x3F);
1981 }
1982 other => panic!("expected Hierarchy, got {other:?}"),
1983 }
1984 }
1985
1986 #[test]
1987 fn hierarchy_descriptor_in_pmt_es_info_alongside_other_tags() {
1988 let mut block = Vec::new();
1993 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
1994 let h_body = [
1995 0b0000_0001, 0b0000_0010, 0b0000_0000, 0b0000_0001, ];
2000 block.extend_from_slice(&tlv(0x04, &h_body));
2001 block.extend_from_slice(&tlv(0x0E, &[0b1100_0000, 0x00, 0x64]));
2002 let v = parse_descriptors(&block).unwrap();
2003 assert_eq!(v.len(), 3);
2004 assert_eq!(v[0].tag, 0x0A);
2005 assert_eq!(v[1].tag, 0x04);
2006 match &v[1].body {
2007 DescriptorBody::Hierarchy(h) => {
2008 assert_eq!(h.hierarchy_type, HierarchyType::Mpeg2SpatialScalability);
2009 assert_eq!(h.hierarchy_layer_index, 2);
2010 assert_eq!(h.hierarchy_embedded_layer_index, 0);
2011 assert_eq!(h.hierarchy_channel, 1);
2012 }
2013 other => panic!("expected Hierarchy, got {other:?}"),
2014 }
2015 assert_eq!(v[2].tag, 0x0E);
2016 assert!(matches!(v[2].body, DescriptorBody::MaximumBitrate(_)));
2017 }
2018
2019 #[test]
2020 fn multiplex_buffer_utilization_descriptor_bounds_valid() {
2021 let lower: u16 = 0x1234; let upper: u16 = 0x5678; let body = [
2028 0x80 | ((lower >> 8) as u8 & 0x7F),
2029 lower as u8,
2030 (upper >> 8) as u8 & 0x7F,
2031 upper as u8,
2032 ];
2033 let block = tlv(0x0C, &body);
2034 let d = iter_descriptors(&block).next().unwrap().unwrap();
2035 match &d.body {
2036 DescriptorBody::MultiplexBufferUtilization(m) => {
2037 assert!(m.bound_valid_flag);
2038 assert_eq!(m.ltw_offset_lower_bound, lower);
2039 assert_eq!(m.ltw_offset_upper_bound, upper);
2040 }
2041 other => panic!("expected MultiplexBufferUtilization, got {other:?}"),
2042 }
2043 }
2044
2045 #[test]
2046 fn multiplex_buffer_utilization_descriptor_bounds_invalid() {
2047 let body = [0x7F, 0xFF, 0x7F, 0xFF];
2052 let block = tlv(0x0C, &body);
2053 let d = iter_descriptors(&block).next().unwrap().unwrap();
2054 match &d.body {
2055 DescriptorBody::MultiplexBufferUtilization(m) => {
2056 assert!(!m.bound_valid_flag);
2057 assert_eq!(m.ltw_offset_lower_bound, 0x7FFF);
2058 assert_eq!(m.ltw_offset_upper_bound, 0x7FFF);
2059 }
2060 other => panic!("expected MultiplexBufferUtilization, got {other:?}"),
2061 }
2062 }
2063
2064 #[test]
2065 fn multiplex_buffer_utilization_descriptor_short_body_falls_back_to_raw() {
2066 let block = tlv(0x0C, &[0xA0, 0x00, 0x00]);
2068 let d = iter_descriptors(&block).next().unwrap().unwrap();
2069 assert!(matches!(d.body, DescriptorBody::Raw));
2070 assert_eq!(d.data, &[0xA0, 0x00, 0x00]);
2071 }
2072
2073 #[test]
2074 fn multiplex_buffer_utilization_descriptor_reserved_bit_ignored_on_read() {
2075 let lower = 0x0000u16;
2079 let upper = 0x0001u16; let with_reserved_zero = [0x80, 0x00, (upper >> 8) as u8, upper as u8];
2081 let with_reserved_one = [0x80, 0x00, ((upper >> 8) as u8) | 0x80, upper as u8];
2082 let block0 = tlv(0x0C, &with_reserved_zero);
2083 let block1 = tlv(0x0C, &with_reserved_one);
2084 let d0 = iter_descriptors(&block0).next().unwrap().unwrap();
2085 let d1 = iter_descriptors(&block1).next().unwrap().unwrap();
2086 let unwrap = |b: &DescriptorBody<'_>| match b {
2087 DescriptorBody::MultiplexBufferUtilization(m) => *m,
2088 other => panic!("expected MultiplexBufferUtilization, got {other:?}"),
2089 };
2090 let m0 = unwrap(&d0.body);
2091 let m1 = unwrap(&d1.body);
2092 assert_eq!(m0.ltw_offset_lower_bound, lower);
2093 assert_eq!(m0.ltw_offset_upper_bound, upper);
2094 assert_eq!(m0, m1);
2095 }
2096
2097 #[test]
2098 fn multiplex_buffer_utilization_descriptor_max_15bit_bounds() {
2099 let body = [0xFF, 0xFF, 0xFF, 0xFF];
2106 let block = tlv(0x0C, &body);
2107 let d = iter_descriptors(&block).next().unwrap().unwrap();
2108 match &d.body {
2109 DescriptorBody::MultiplexBufferUtilization(m) => {
2110 assert!(m.bound_valid_flag);
2111 assert_eq!(m.ltw_offset_lower_bound, 0x7FFF);
2112 assert_eq!(m.ltw_offset_upper_bound, 0x7FFF);
2113 }
2114 other => panic!("expected MultiplexBufferUtilization, got {other:?}"),
2115 }
2116 }
2117
2118 #[test]
2119 fn multiplex_buffer_utilization_descriptor_in_es_info_list() {
2120 let mut block = Vec::new();
2124 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
2125 block.extend_from_slice(&tlv(0x10, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]));
2127 block.extend_from_slice(&tlv(0x0C, &[0x81, 0x00, 0x02, 0x00]));
2131 let v = parse_descriptors(&block).unwrap();
2132 assert_eq!(v.len(), 3);
2133 assert_eq!(v[0].tag, 0x0A);
2134 assert_eq!(v[1].tag, 0x10);
2135 assert_eq!(v[2].tag, 0x0C);
2136 match &v[2].body {
2137 DescriptorBody::MultiplexBufferUtilization(m) => {
2138 assert!(m.bound_valid_flag);
2139 assert_eq!(m.ltw_offset_lower_bound, 0x0100);
2140 assert_eq!(m.ltw_offset_upper_bound, 0x0200);
2141 }
2142 other => panic!("expected MultiplexBufferUtilization, got {other:?}"),
2143 }
2144 }
2145
2146 #[test]
2147 fn parse_descriptors_helper_collects_all() {
2148 let mut block = Vec::new();
2149 block.extend_from_slice(&tlv(0x05, b"HDMV"));
2150 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
2151 block.extend_from_slice(&tlv(0xFF, &[]));
2152 let v = parse_descriptors(&block).unwrap();
2153 assert_eq!(v.len(), 3);
2154 assert_eq!(v[0].tag, 0x05);
2155 assert_eq!(v[1].tag, 0x0A);
2156 assert_eq!(v[2].tag, 0xFF);
2157 assert!(matches!(v[2].body, DescriptorBody::Raw));
2158 assert!(v[2].data.is_empty());
2159 }
2160
2161 #[test]
2162 fn ibp_descriptor_all_flags_set_max_length() {
2163 let block = tlv(0x12, &[0xFF, 0xFF]);
2167 let d = iter_descriptors(&block).next().unwrap().unwrap();
2168 assert_eq!(d.tag, 0x12);
2169 match &d.body {
2170 DescriptorBody::Ibp(ibp) => {
2171 assert!(ibp.closed_gop_flag);
2172 assert!(ibp.identical_gop_flag);
2173 assert_eq!(ibp.max_gop_length, 0x3FFF);
2174 assert!(ibp.is_well_formed());
2175 }
2176 other => panic!("expected Ibp, got {other:?}"),
2177 }
2178 }
2179
2180 #[test]
2181 fn ibp_descriptor_flags_clear_typical_length() {
2182 let block = tlv(0x12, &[0x00, 0x0F]);
2186 let d = iter_descriptors(&block).next().unwrap().unwrap();
2187 match &d.body {
2188 DescriptorBody::Ibp(ibp) => {
2189 assert!(!ibp.closed_gop_flag);
2190 assert!(!ibp.identical_gop_flag);
2191 assert_eq!(ibp.max_gop_length, 15);
2192 assert!(ibp.is_well_formed());
2193 }
2194 other => panic!("expected Ibp, got {other:?}"),
2195 }
2196 }
2197
2198 #[test]
2199 fn ibp_descriptor_closed_only_mid_length() {
2200 let block = tlv(0x12, &[0x81, 0x2C]);
2204 let d = iter_descriptors(&block).next().unwrap().unwrap();
2205 match &d.body {
2206 DescriptorBody::Ibp(ibp) => {
2207 assert!(ibp.closed_gop_flag);
2208 assert!(!ibp.identical_gop_flag);
2209 assert_eq!(ibp.max_gop_length, 0x012C);
2210 }
2211 other => panic!("expected Ibp, got {other:?}"),
2212 }
2213 }
2214
2215 #[test]
2216 fn ibp_descriptor_identical_only_mid_length() {
2217 let block = tlv(0x12, &[0x40, 0x2A]);
2221 let d = iter_descriptors(&block).next().unwrap().unwrap();
2222 match &d.body {
2223 DescriptorBody::Ibp(ibp) => {
2224 assert!(!ibp.closed_gop_flag);
2225 assert!(ibp.identical_gop_flag);
2226 assert_eq!(ibp.max_gop_length, 42);
2227 }
2228 other => panic!("expected Ibp, got {other:?}"),
2229 }
2230 }
2231
2232 #[test]
2233 fn ibp_descriptor_forbidden_zero_max_gop_length_flagged() {
2234 let block = tlv(0x12, &[0x00, 0x00]);
2237 let d = iter_descriptors(&block).next().unwrap().unwrap();
2238 match &d.body {
2239 DescriptorBody::Ibp(ibp) => {
2240 assert_eq!(ibp.max_gop_length, 0);
2241 assert!(!ibp.is_well_formed());
2242 }
2243 other => panic!("expected Ibp, got {other:?}"),
2244 }
2245 }
2246
2247 #[test]
2248 fn ibp_descriptor_truncated_falls_back_to_raw() {
2249 let block = tlv(0x12, &[0xFF]);
2253 let d = iter_descriptors(&block).next().unwrap().unwrap();
2254 assert_eq!(d.tag, 0x12);
2255 assert!(matches!(d.body, DescriptorBody::Raw));
2256 assert_eq!(d.data, &[0xFF]);
2257 }
2258
2259 #[test]
2260 fn ibp_descriptor_in_es_info_list_with_neighbours() {
2261 let mut block = Vec::new();
2265 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
2266 block.extend_from_slice(&tlv(0x12, &[0x80, 0x12]));
2269 block.extend_from_slice(&tlv(0x11, &[0x01]));
2271 let v = parse_descriptors(&block).unwrap();
2272 assert_eq!(v.len(), 3);
2273 assert_eq!(v[0].tag, 0x0A);
2274 assert_eq!(v[1].tag, 0x12);
2275 assert_eq!(v[2].tag, 0x11);
2276 match &v[1].body {
2277 DescriptorBody::Ibp(ibp) => {
2278 assert!(ibp.closed_gop_flag);
2279 assert!(!ibp.identical_gop_flag);
2280 assert_eq!(ibp.max_gop_length, 18);
2281 assert!(ibp.is_well_formed());
2282 }
2283 other => panic!("expected Ibp, got {other:?}"),
2284 }
2285 }
2286
2287 #[test]
2288 fn target_background_grid_descriptor_typical_sd() {
2289 let block = tlv(0x07, &[0x0B, 0x40, 0x24, 0x03]);
2299 let d = iter_descriptors(&block).next().unwrap().unwrap();
2300 assert_eq!(d.tag, 0x07);
2301 match &d.body {
2302 DescriptorBody::TargetBackgroundGrid(g) => {
2303 assert_eq!(g.horizontal_size, 720);
2304 assert_eq!(g.vertical_size, 576);
2305 assert_eq!(g.aspect_ratio_information, 3);
2306 }
2307 other => panic!("expected TargetBackgroundGrid, got {other:?}"),
2308 }
2309 }
2310
2311 #[test]
2312 fn target_background_grid_descriptor_max_fields() {
2313 let block = tlv(0x07, &[0xFF, 0xFF, 0xFF, 0xFF]);
2321 let d = iter_descriptors(&block).next().unwrap().unwrap();
2322 match &d.body {
2323 DescriptorBody::TargetBackgroundGrid(g) => {
2324 assert_eq!(g.horizontal_size, 0x3FFF);
2325 assert_eq!(g.vertical_size, 0x3FFF);
2326 assert_eq!(g.aspect_ratio_information, 0xF);
2327 }
2328 other => panic!("expected TargetBackgroundGrid, got {other:?}"),
2329 }
2330 }
2331
2332 #[test]
2333 fn target_background_grid_descriptor_all_zero() {
2334 let block = tlv(0x07, &[0x00, 0x00, 0x00, 0x00]);
2335 let d = iter_descriptors(&block).next().unwrap().unwrap();
2336 match &d.body {
2337 DescriptorBody::TargetBackgroundGrid(g) => {
2338 assert_eq!(g.horizontal_size, 0);
2339 assert_eq!(g.vertical_size, 0);
2340 assert_eq!(g.aspect_ratio_information, 0);
2341 }
2342 other => panic!("expected TargetBackgroundGrid, got {other:?}"),
2343 }
2344 }
2345
2346 #[test]
2347 fn target_background_grid_descriptor_short_body_falls_back_to_raw() {
2348 let block = tlv(0x07, &[0x0B, 0x40, 0x24]);
2351 let d = iter_descriptors(&block).next().unwrap().unwrap();
2352 assert_eq!(d.tag, 0x07);
2353 assert!(matches!(d.body, DescriptorBody::Raw));
2354 assert_eq!(d.data, &[0x0B, 0x40, 0x24]);
2355 }
2356
2357 #[test]
2358 fn target_background_grid_descriptor_in_es_info_list_with_neighbours() {
2359 let mut block = Vec::new();
2369 block.extend_from_slice(&tlv(0x0A, &[b'e', b'n', b'g', 0x00]));
2370 block.extend_from_slice(&tlv(0x07, &[0x1E, 0x00, 0x43, 0x81]));
2371 block.extend_from_slice(&tlv(0x11, &[0x01]));
2372 let v = parse_descriptors(&block).unwrap();
2373 assert_eq!(v.len(), 3);
2374 assert_eq!(v[0].tag, 0x0A);
2375 assert_eq!(v[1].tag, 0x07);
2376 assert_eq!(v[2].tag, 0x11);
2377 match &v[1].body {
2378 DescriptorBody::TargetBackgroundGrid(g) => {
2379 assert_eq!(g.horizontal_size, 1920);
2380 assert_eq!(g.vertical_size, 1080);
2381 assert_eq!(g.aspect_ratio_information, 1);
2382 }
2383 other => panic!("expected TargetBackgroundGrid, got {other:?}"),
2384 }
2385 }
2386
2387 #[test]
2388 fn video_window_descriptor_typical_offsets() {
2389 let block = tlv(0x08, &[0x05, 0x00, 0x0F, 0x05]);
2399 let d = iter_descriptors(&block).next().unwrap().unwrap();
2400 assert_eq!(d.tag, 0x08);
2401 match &d.body {
2402 DescriptorBody::VideoWindow(w) => {
2403 assert_eq!(w.horizontal_offset, 320);
2404 assert_eq!(w.vertical_offset, 240);
2405 assert_eq!(w.window_priority, 5);
2406 }
2407 other => panic!("expected VideoWindow, got {other:?}"),
2408 }
2409 }
2410
2411 #[test]
2412 fn video_window_descriptor_max_fields() {
2413 let block = tlv(0x08, &[0xFF, 0xFF, 0xFF, 0xFF]);
2420 let d = iter_descriptors(&block).next().unwrap().unwrap();
2421 match &d.body {
2422 DescriptorBody::VideoWindow(w) => {
2423 assert_eq!(w.horizontal_offset, 0x3FFF);
2424 assert_eq!(w.vertical_offset, 0x3FFF);
2425 assert_eq!(w.window_priority, 0xF);
2426 }
2427 other => panic!("expected VideoWindow, got {other:?}"),
2428 }
2429 }
2430
2431 #[test]
2432 fn video_window_descriptor_all_zero() {
2433 let block = tlv(0x08, &[0x00, 0x00, 0x00, 0x00]);
2434 let d = iter_descriptors(&block).next().unwrap().unwrap();
2435 match &d.body {
2436 DescriptorBody::VideoWindow(w) => {
2437 assert_eq!(w.horizontal_offset, 0);
2438 assert_eq!(w.vertical_offset, 0);
2439 assert_eq!(w.window_priority, 0);
2440 }
2441 other => panic!("expected VideoWindow, got {other:?}"),
2442 }
2443 }
2444
2445 #[test]
2446 fn video_window_descriptor_short_body_falls_back_to_raw() {
2447 let block = tlv(0x08, &[0x05, 0x00, 0x0F]);
2450 let d = iter_descriptors(&block).next().unwrap().unwrap();
2451 assert_eq!(d.tag, 0x08);
2452 assert!(matches!(d.body, DescriptorBody::Raw));
2453 assert_eq!(d.data, &[0x05, 0x00, 0x0F]);
2454 }
2455
2456 #[test]
2457 fn video_window_descriptor_pairs_with_grid_in_es_info_list() {
2458 let mut block = Vec::new();
2468 block.extend_from_slice(&tlv(0x07, &[0x1E, 0x00, 0x43, 0x81]));
2469 block.extend_from_slice(&tlv(0x08, &[0x01, 0x90, 0x03, 0x27]));
2470 let v = parse_descriptors(&block).unwrap();
2471 assert_eq!(v.len(), 2);
2472 assert_eq!(v[0].tag, 0x07);
2473 assert_eq!(v[1].tag, 0x08);
2474 match &v[0].body {
2475 DescriptorBody::TargetBackgroundGrid(g) => {
2476 assert_eq!(g.horizontal_size, 1920);
2477 assert_eq!(g.vertical_size, 1080);
2478 }
2479 other => panic!("expected TargetBackgroundGrid, got {other:?}"),
2480 }
2481 match &v[1].body {
2482 DescriptorBody::VideoWindow(w) => {
2483 assert_eq!(w.horizontal_offset, 100);
2484 assert_eq!(w.vertical_offset, 50);
2485 assert_eq!(w.window_priority, 7);
2486 }
2487 other => panic!("expected VideoWindow, got {other:?}"),
2488 }
2489 }
2490
2491 #[test]
2492 fn service_descriptor_decodes_names_and_type() {
2493 let mut body = vec![0x01];
2496 body.push(4);
2497 body.extend_from_slice(b"Prov");
2498 body.push(9);
2499 body.extend_from_slice(b"Channel 1");
2500 let block = tlv(0x48, &body);
2501 let d = iter_descriptors(&block).next().unwrap().unwrap();
2502 assert_eq!(d.tag, 0x48);
2503 match d.body {
2504 DescriptorBody::Service(s) => {
2505 assert_eq!(s.service_type, 0x01);
2506 assert_eq!(s.service_provider_name, b"Prov");
2507 assert_eq!(s.service_name, b"Channel 1");
2508 }
2509 other => panic!("expected Service, got {other:?}"),
2510 }
2511 }
2512
2513 #[test]
2514 fn service_descriptor_empty_provider_name() {
2515 let mut body = vec![0x11]; body.push(0);
2518 body.push(3);
2519 body.extend_from_slice(b"HD1");
2520 let block = tlv(0x48, &body);
2521 let d = iter_descriptors(&block).next().unwrap().unwrap();
2522 match d.body {
2523 DescriptorBody::Service(s) => {
2524 assert_eq!(s.service_type, 0x11);
2525 assert!(s.service_provider_name.is_empty());
2526 assert_eq!(s.service_name, b"HD1");
2527 }
2528 other => panic!("expected Service, got {other:?}"),
2529 }
2530 }
2531
2532 #[test]
2533 fn service_descriptor_truncated_falls_back_to_raw() {
2534 let block = tlv(0x48, &[0x01, 0x09, b'X', b'Y']);
2536 let d = iter_descriptors(&block).next().unwrap().unwrap();
2537 assert_eq!(d.tag, 0x48);
2538 assert!(matches!(d.body, DescriptorBody::Raw));
2539 assert_eq!(d.data, &[0x01, 0x09, b'X', b'Y']);
2540 }
2541
2542 #[test]
2543 fn short_event_descriptor_decodes_name_and_text() {
2544 let mut body = Vec::new();
2546 body.extend_from_slice(b"eng");
2547 body.push(4);
2548 body.extend_from_slice(b"News");
2549 body.push(14);
2550 body.extend_from_slice(b"Daily bulletin");
2551 let block = tlv(0x4D, &body);
2552 let d = iter_descriptors(&block).next().unwrap().unwrap();
2553 assert_eq!(d.tag, 0x4D);
2554 match d.body {
2555 DescriptorBody::ShortEvent(s) => {
2556 assert_eq!(&s.language_code, b"eng");
2557 assert_eq!(s.event_name, b"News");
2558 assert_eq!(s.text, b"Daily bulletin");
2559 }
2560 other => panic!("expected ShortEvent, got {other:?}"),
2561 }
2562 }
2563
2564 #[test]
2565 fn short_event_descriptor_empty_text() {
2566 let mut body = Vec::new();
2568 body.extend_from_slice(b"fre");
2569 body.push(5);
2570 body.extend_from_slice(b"Match");
2571 body.push(0);
2572 let block = tlv(0x4D, &body);
2573 let d = iter_descriptors(&block).next().unwrap().unwrap();
2574 match d.body {
2575 DescriptorBody::ShortEvent(s) => {
2576 assert_eq!(&s.language_code, b"fre");
2577 assert_eq!(s.event_name, b"Match");
2578 assert!(s.text.is_empty());
2579 }
2580 other => panic!("expected ShortEvent, got {other:?}"),
2581 }
2582 }
2583
2584 #[test]
2585 fn short_event_descriptor_truncated_falls_back_to_raw() {
2586 let block = tlv(0x4D, &[b'e', b'n', b'g', 0x09, b'X', b'Y']);
2588 let d = iter_descriptors(&block).next().unwrap().unwrap();
2589 assert_eq!(d.tag, 0x4D);
2590 assert!(matches!(d.body, DescriptorBody::Raw));
2591 }
2592}