Skip to main content

denise_video/
error.rs

1//! What can go wrong between a file and a plane.
2
3use std::path::PathBuf;
4
5/// Video errors: enumeration, negotiation, streaming, scanout.
6#[derive(Debug)]
7#[non_exhaustive]
8pub enum VideoError {
9    /// A device node would not open.
10    Open {
11        /// The node that failed.
12        path: PathBuf,
13        /// The underlying error.
14        source: std::io::Error,
15    },
16
17    /// No decoder on this board accepts any of the offered assets.
18    ///
19    /// The menu is two codecs wide precisely so this stays unreachable on a
20    /// Raspberry Pi — a kiosk that ships both files always has a playable one.
21    NothingPlayable,
22
23    /// An ioctl against the decoder failed.
24    V4l2 {
25        /// Which call.
26        what: &'static str,
27        /// The errno.
28        source: rustix::io::Errno,
29    },
30
31    /// The decoder produced a frame format the plane path does not handle.
32    UnsupportedFormat(u32),
33
34    /// The stream never yielded a decodable picture.
35    NoFrames,
36
37    /// A DRM call on the plane path failed.
38    Drm {
39        /// Which call.
40        what: &'static str,
41        /// The underlying error.
42        source: std::io::Error,
43    },
44
45    /// No video plane on the CRTC supports the decoder's output format.
46    NoPlane,
47}
48
49impl std::fmt::Display for VideoError {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        match self {
52            Self::Open { path, source } => {
53                write!(f, "could not open {}: {source}", path.display())
54            }
55            Self::NothingPlayable => f.write_str("no hardware decoder accepts any offered asset"),
56            Self::V4l2 { what, source } => write!(f, "V4L2 {what} failed: {source}"),
57            Self::UnsupportedFormat(format) => write!(
58                f,
59                "decoder produced unsupported pixel format {format:#010x}"
60            ),
61            Self::NoFrames => f.write_str(
62                "the stream produced no decoded frames — not an Annex-B elementary stream?",
63            ),
64            Self::Drm { what, source } => write!(f, "DRM {what} failed: {source}"),
65            Self::NoPlane => f.write_str("no DRM plane accepts the decoded format on this CRTC"),
66        }
67    }
68}
69
70impl std::error::Error for VideoError {
71    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
72        match self {
73            Self::Open { source, .. } | Self::Drm { source, .. } => Some(source),
74            Self::V4l2 { source, .. } => Some(source),
75            Self::NothingPlayable | Self::UnsupportedFormat(_) | Self::NoFrames | Self::NoPlane => {
76                None
77            }
78        }
79    }
80}
81
82impl VideoError {
83    pub(crate) fn v4l2(what: &'static str, source: rustix::io::Errno) -> Self {
84        Self::V4l2 { what, source }
85    }
86
87    pub(crate) fn drm(what: &'static str, source: impl Into<std::io::Error>) -> Self {
88        Self::Drm {
89            what,
90            source: source.into(),
91        }
92    }
93}