Skip to main content

dvb_si/descriptors/
avc_video.rs

1//! AVC Video Descriptor — ISO/IEC 13818-1 §2.6.64 (tag 0x28).
2//!
3//! Describes the profile, level, and constraint flags for an AVC/H.264
4//! video elementary stream.
5
6use super::descriptor_body;
7use crate::error::{Error, Result};
8use dvb_common::{Parse, Serialize};
9
10/// Descriptor tag for AVC_video_descriptor.
11pub const TAG: u8 = 0x28;
12const HEADER_LEN: usize = 2;
13const BODY_LEN: u8 = 4;
14
15/// AVC Video Descriptor.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
19pub struct AvcVideoDescriptor {
20    /// AVC profile_idc.
21    pub profile_idc: u8,
22    /// Constraint set 0 flag.
23    pub constraint_set0_flag: bool,
24    /// Constraint set 1 flag.
25    pub constraint_set1_flag: bool,
26    /// Constraint set 2 flag.
27    pub constraint_set2_flag: bool,
28    /// Constraint set 3 flag.
29    pub constraint_set3_flag: bool,
30    /// Constraint set 4 flag.
31    pub constraint_set4_flag: bool,
32    /// Constraint set 5 flag.
33    pub constraint_set5_flag: bool,
34    /// AVC compatible flags (2 bits).
35    pub avc_compatible_flags: u8,
36    /// AVC level_idc.
37    pub level_idc: u8,
38    /// AVC still present flag.
39    pub avc_still_present: bool,
40    /// AVC 24 hour picture flag.
41    pub avc_24_hour_picture_flag: bool,
42    /// Frame packing SEI not present flag.
43    pub frame_packing_sei_not_present_flag: bool,
44}
45
46impl<'a> Parse<'a> for AvcVideoDescriptor {
47    type Error = crate::error::Error;
48
49    fn parse(bytes: &'a [u8]) -> Result<Self> {
50        let body = descriptor_body(
51            bytes,
52            TAG,
53            "AvcVideoDescriptor",
54            "unexpected tag for AVC_video_descriptor",
55        )?;
56        if body.len() < (BODY_LEN as usize) {
57            return Err(Error::InvalidDescriptor {
58                tag: TAG,
59                reason: "AVC_video_descriptor too short",
60            });
61        }
62        let b0 = body[0]; // profile_idc
63        let b1 = body[1]; // constraint_set0_flag..avc_compatible_flags
64        let b2 = body[2]; // level_idc
65        let b3 = body[3]; // avc_still_present..reserved
66
67        Ok(Self {
68            profile_idc: b0,
69            constraint_set0_flag: (b1 & 0x80) != 0,
70            constraint_set1_flag: (b1 & 0x40) != 0,
71            constraint_set2_flag: (b1 & 0x20) != 0,
72            constraint_set3_flag: (b1 & 0x10) != 0,
73            constraint_set4_flag: (b1 & 0x08) != 0,
74            constraint_set5_flag: (b1 & 0x04) != 0,
75            avc_compatible_flags: b1 & 0x03,
76            level_idc: b2,
77            avc_still_present: (b3 & 0x80) != 0,
78            avc_24_hour_picture_flag: (b3 & 0x40) != 0,
79            frame_packing_sei_not_present_flag: (b3 & 0x20) != 0,
80        })
81    }
82}
83
84impl Serialize for AvcVideoDescriptor {
85    type Error = crate::error::Error;
86
87    fn serialized_len(&self) -> usize {
88        HEADER_LEN + (BODY_LEN as usize)
89    }
90
91    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
92        let len = self.serialized_len();
93        if buf.len() < len {
94            return Err(Error::OutputBufferTooSmall {
95                need: len,
96                have: buf.len(),
97            });
98        }
99        buf[0] = TAG;
100        buf[1] = BODY_LEN;
101        buf[HEADER_LEN] = self.profile_idc;
102        buf[HEADER_LEN + 1] = ((self.constraint_set0_flag as u8) << 7)
103            | ((self.constraint_set1_flag as u8) << 6)
104            | ((self.constraint_set2_flag as u8) << 5)
105            | ((self.constraint_set3_flag as u8) << 4)
106            | ((self.constraint_set4_flag as u8) << 3)
107            | ((self.constraint_set5_flag as u8) << 2)
108            | (self.avc_compatible_flags & 0x03);
109        buf[HEADER_LEN + 2] = self.level_idc;
110        buf[HEADER_LEN + 3] = ((self.avc_still_present as u8) << 7)
111            | ((self.avc_24_hour_picture_flag as u8) << 6)
112            | ((self.frame_packing_sei_not_present_flag as u8) << 5);
113        Ok(len)
114    }
115}
116
117impl<'a> crate::traits::DescriptorDef<'a> for AvcVideoDescriptor {
118    const TAG: u8 = TAG;
119    const NAME: &'static str = "AVC_VIDEO";
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn round_trip() {
128        let orig = AvcVideoDescriptor {
129            profile_idc: 0x4D,
130            constraint_set0_flag: true,
131            constraint_set1_flag: false,
132            constraint_set2_flag: false,
133            constraint_set3_flag: true,
134            constraint_set4_flag: false,
135            constraint_set5_flag: true,
136            avc_compatible_flags: 0x03,
137            level_idc: 0x29,
138            avc_still_present: false,
139            avc_24_hour_picture_flag: true,
140            frame_packing_sei_not_present_flag: false,
141        };
142        let mut buf = vec![0u8; orig.serialized_len()];
143        orig.serialize_into(&mut buf).unwrap();
144        let reparsed = AvcVideoDescriptor::parse(&buf).unwrap();
145        assert_eq!(orig, reparsed);
146    }
147
148    #[test]
149    fn parse_rejects_wrong_tag() {
150        let err = AvcVideoDescriptor::parse(&[0x02, 4, 0x00, 0x00, 0x00, 0x00]).unwrap_err();
151        assert!(matches!(err, Error::InvalidDescriptor { tag: 0x02, .. }));
152    }
153
154    #[test]
155    fn parse_rejects_too_short() {
156        // length=2 with a present 2-byte body (< BODY_LEN=4) hits the
157        // descriptor's own length check → InvalidDescriptor.
158        let err = AvcVideoDescriptor::parse(&[TAG, 2, 0x00, 0x00]).unwrap_err();
159        assert!(matches!(err, Error::InvalidDescriptor { tag: TAG, .. }));
160    }
161}