Skip to main content

zencodec_media/
limits.rs

1//! Structural limits for containers and the queues between stages.
2//!
3//! [`zencodec::ResourceLimits`] keeps bounding decoded pixels, frames,
4//! duration and memory. [`MediaLimits`] bounds what a container parser and a
5//! session hold before any pixel exists: packet sizes, track counts, header
6//! and index sizes, queue depths. Each is checked before the allocation it
7//! guards. A refusal is a [`MediaLimitExceeded`] naming the
8//! [`zencodec::LimitKind`].
9
10use core::fmt;
11
12use zencodec::LimitKind;
13
14/// Caps on container structure and queue depth.
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16#[non_exhaustive]
17pub struct MediaLimits {
18    /// Largest packet payload, in bytes.
19    pub max_packet_bytes: usize,
20    /// Most tracks one container may declare.
21    pub max_tracks: u32,
22    /// Most header bytes read before the first packet.
23    pub max_header_bytes: u64,
24    /// Most entries in an index or sample table.
25    pub max_table_entries: u64,
26    /// Most packets queued between two stages.
27    pub max_queued_packets: usize,
28    /// Most decoded frames a codec session holds for output.
29    pub max_queued_frames: usize,
30}
31
32impl MediaLimits {
33    /// Untrusted-input defaults: 64 MiB packets, 64 tracks, 256 MiB of
34    /// headers, 4 Mi table entries, 64 queued packets, 8 queued frames.
35    pub const DEFAULT: Self = Self {
36        max_packet_bytes: 64 << 20,
37        max_tracks: 64,
38        max_header_bytes: 256 << 20,
39        max_table_entries: 4 << 20,
40        max_queued_packets: 64,
41        max_queued_frames: 8,
42    };
43
44    /// The largest packet payload.
45    pub const fn with_max_packet_bytes(mut self, n: usize) -> Self {
46        self.max_packet_bytes = n;
47        self
48    }
49
50    /// The most tracks.
51    pub const fn with_max_tracks(mut self, n: u32) -> Self {
52        self.max_tracks = n;
53        self
54    }
55
56    /// The most header bytes.
57    pub const fn with_max_header_bytes(mut self, n: u64) -> Self {
58        self.max_header_bytes = n;
59        self
60    }
61
62    /// The most index or table entries.
63    pub const fn with_max_table_entries(mut self, n: u64) -> Self {
64        self.max_table_entries = n;
65        self
66    }
67
68    /// The most queued packets.
69    pub const fn with_max_queued_packets(mut self, n: usize) -> Self {
70        self.max_queued_packets = n;
71        self
72    }
73
74    /// The most queued frames.
75    pub const fn with_max_queued_frames(mut self, n: usize) -> Self {
76        self.max_queued_frames = n;
77        self
78    }
79
80    /// Refuse a packet of `bytes` bytes over the cap.
81    ///
82    /// # Errors
83    ///
84    /// [`LimitKind::PacketBytes`] over the cap.
85    pub fn check_packet_bytes(&self, bytes: u64) -> Result<(), MediaLimitExceeded> {
86        MediaLimitExceeded::check(LimitKind::PacketBytes, bytes, self.max_packet_bytes as u64)
87    }
88
89    /// Refuse a container declaring more than `max_tracks` tracks.
90    ///
91    /// # Errors
92    ///
93    /// [`LimitKind::Tracks`] over the cap.
94    pub fn check_tracks(&self, tracks: u64) -> Result<(), MediaLimitExceeded> {
95        MediaLimitExceeded::check(LimitKind::Tracks, tracks, u64::from(self.max_tracks))
96    }
97
98    /// Refuse a header of `bytes` bytes over the cap.
99    ///
100    /// # Errors
101    ///
102    /// [`LimitKind::HeaderBytes`] over the cap.
103    pub fn check_header_bytes(&self, bytes: u64) -> Result<(), MediaLimitExceeded> {
104        MediaLimitExceeded::check(LimitKind::HeaderBytes, bytes, self.max_header_bytes)
105    }
106
107    /// Refuse a table of `entries` entries over the cap.
108    ///
109    /// # Errors
110    ///
111    /// [`LimitKind::TableEntries`] over the cap.
112    pub fn check_table_entries(&self, entries: u64) -> Result<(), MediaLimitExceeded> {
113        MediaLimitExceeded::check(LimitKind::TableEntries, entries, self.max_table_entries)
114    }
115}
116
117impl Default for MediaLimits {
118    fn default() -> Self {
119        Self::DEFAULT
120    }
121}
122
123/// A structural limit was exceeded.
124#[derive(Clone, Copy, Debug, PartialEq, Eq)]
125#[non_exhaustive]
126pub struct MediaLimitExceeded {
127    /// Which cap.
128    pub kind: LimitKind,
129    /// What the input asked for.
130    pub requested: u64,
131    /// The cap.
132    pub limit: u64,
133}
134
135impl MediaLimitExceeded {
136    /// `Err` when `requested` exceeds `limit`.
137    ///
138    /// # Errors
139    ///
140    /// The exceeded limit.
141    pub const fn check(kind: LimitKind, requested: u64, limit: u64) -> Result<(), Self> {
142        if requested > limit {
143            Err(Self {
144                kind,
145                requested,
146                limit,
147            })
148        } else {
149            Ok(())
150        }
151    }
152}
153
154impl fmt::Display for MediaLimitExceeded {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        write!(
157            f,
158            "{:?} limit exceeded: {} > {}",
159            self.kind, self.requested, self.limit
160        )
161    }
162}
163
164impl core::error::Error for MediaLimitExceeded {}