Skip to main content

linux_media/
media_entity_desc.rs

1use std::ffi::CStr;
2use std::os::fd::{AsRawFd, BorrowedFd};
3
4use linux_media_sys as media;
5use serde::{Deserialize, Serialize};
6
7use crate::error;
8use crate::ioctl;
9use crate::{EntityId, MediaEntity, MediaEntityFlags, MediaEntityFunctions, Version};
10
11#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
12pub struct MediaEntityDesc {
13    /// Entity ID, set by the application. When the ID is or’ed with MEDIA_ENT_ID_FLAG_NEXT, the driver clears the flag and returns the first entity with a larger ID. Do not expect that the ID will always be the same for each instance of the device. In other words, do not hardcode entity IDs in an application.
14    pub id: EntityId,
15    /// Entity name. This name must be unique within the media topology.
16    pub name: String,
17    /// Entity type.
18    pub r#type: MediaEntityFunctions,
19    /// Entity flags.
20    pub flags: MediaEntityFlags,
21    /// Number of pads
22    pub pads: usize,
23    /// Total number of outbound links.
24    /// Inbound links are not counted in this field.
25    pub links: usize,
26}
27
28impl MediaEntityDesc {
29    pub fn from_fd<F>(fd: F, entity: EntityId) -> error::Result<Self>
30    where
31        F: AsRawFd,
32    {
33        unsafe {
34            let mut desc: media::media_entity_desc = std::mem::zeroed();
35            desc.id = entity.into();
36            ioctl!(fd, media::MEDIA_IOC_ENUM_ENTITIES, &mut desc)?;
37            Ok(desc.into())
38        }
39    }
40
41    pub fn id(&self) -> EntityId {
42        self.id
43    }
44
45    pub fn name(&self) -> &str {
46        &self.name
47    }
48
49    pub fn r#type(&self) -> MediaEntityFunctions {
50        self.r#type.clone()
51    }
52
53    pub fn flags(&self) -> MediaEntityFlags {
54        self.flags
55    }
56
57    pub fn pads(&self) -> usize {
58        self.pads
59    }
60
61    pub fn links(&self) -> usize {
62        self.links
63    }
64}
65
66impl From<media::media_entity_desc> for MediaEntityDesc {
67    fn from(desc: media::media_entity_desc) -> Self {
68        Self {
69            id: desc.id.into(),
70            name: unsafe {
71                CStr::from_ptr(desc.name.as_ptr())
72                    .to_string_lossy()
73                    .to_string()
74            },
75            r#type: desc.type_.try_into().unwrap(),
76            flags: desc.flags.try_into().unwrap(),
77            pads: desc.pads.try_into().unwrap(),
78            links: desc.links.try_into().unwrap(),
79        }
80    }
81}
82
83/// Iterates over all MediaEntities.
84///
85/// # Details
86/// Iterates over all MediaEntities with an ID greater than or equal to the stored ID.
87/// Enumerated items are in ascending order of ID.
88#[derive(Debug)]
89pub struct MediaEntityIter<'a> {
90    fd: BorrowedFd<'a>,
91    media_version: Version,
92    id: EntityId,
93    // next item descriptor
94    desc: Option<MediaEntityDesc>,
95}
96
97impl<'a> MediaEntityIter<'a> {
98    pub fn new(fd: BorrowedFd<'a>, media_version: Version, id: EntityId) -> Self {
99        Self {
100            fd,
101            media_version,
102            id,
103            desc: Self::desc(fd, id),
104        }
105    }
106
107    fn desc(fd: BorrowedFd<'_>, id: EntityId) -> Option<MediaEntityDesc> {
108        unsafe {
109            let mut desc: media::media_entity_desc = std::mem::zeroed();
110            desc.id = Into::<u32>::into(id);
111            if ioctl!(fd, media::MEDIA_IOC_ENUM_ENTITIES, &mut desc).is_ok() {
112                Some(desc.into())
113            } else {
114                None
115            }
116        }
117    }
118}
119
120impl<'a> Iterator for MediaEntityIter<'a> {
121    type Item = MediaEntity;
122    fn next(&mut self) -> Option<Self::Item> {
123        match self.desc.clone() {
124            Some(desc) => {
125                let entity = MediaEntity::from_desc(self.media_version, desc);
126                if let Some(desc) =
127                    Self::desc(self.fd, self.id | media::MEDIA_ENT_ID_FLAG_NEXT.into())
128                {
129                    self.id = desc.id.into();
130                    self.desc = Some(desc);
131                } else {
132                    self.desc = None;
133                }
134                Some(entity)
135            }
136            None => None,
137        }
138    }
139}