Skip to main content

linux_media/
media_link.rs

1use std::marker::PhantomData;
2
3use derive_more::{From, Into};
4use linux_media_sys as media;
5use serde::{Deserialize, Serialize};
6
7use crate::error;
8use crate::media_entity::EntityId;
9use crate::media_interface::InterfaceId;
10use crate::media_pad::PadId;
11
12#[derive(
13    Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, From, Into, Serialize, Deserialize,
14)]
15pub struct LinkId(u32);
16
17bitflags::bitflags! {
18    #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
19    pub struct MediaLinkFlags: u32 {
20        /// The link is enabled and can be used to transfer media data. When two or more links target a sink pad, only one of them can be enabled at a time.
21        const Enabled = media::MEDIA_LNK_FL_ENABLED;
22        /// The link enabled state can’t be modified at runtime. An immutable link is always enabled.
23        const Immutable = media::MEDIA_LNK_FL_IMMUTABLE;
24        /// The link enabled state can be modified during streaming. This flag is set by drivers and is read-only for applications.
25        const Dynamic = media::MEDIA_LNK_FL_DYNAMIC;
26    }
27}
28
29impl TryFrom<u32> for MediaLinkFlags {
30    type Error = error::Error;
31    fn try_from(v: u32) -> error::Result<Self> {
32        MediaLinkFlags::from_bits(v & !media::MEDIA_LNK_FL_LINK_TYPE)
33            .ok_or_else(|| error::Error::LinkFlagsParseError { from: v })
34    }
35}
36
37#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
38pub struct PadIdOr<T>(u32, PhantomData<T>);
39
40#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
41pub enum LinkType {
42    /// MEDIA_LNK_FL_DATA_LINK
43    /// On pad to pad links: unique IDs for the source/sink pad.
44    DataLink { source_id: PadId, sink_id: PadId },
45    /// MEDIA_LNK_FL_INTERFACE_LINK
46    /// On interface to entity links: unique IDs for the interface/entity.
47    InterfaceLink {
48        source_id: InterfaceId,
49        sink_id: EntityId,
50    },
51    /// MEDIA_LNK_FL_ANCILLARY_LINK for links that represent a physical relationship between two entities. The link may or may not be immutable, so applications must not assume either case.
52    AncillaryLink {
53        source_id: PadIdOr<InterfaceId>,
54        sink_id: PadIdOr<EntityId>,
55    },
56}
57
58#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
59pub struct MediaLink {
60    id: LinkId,
61    r#type: LinkType,
62    flags: MediaLinkFlags,
63}
64
65impl MediaLink {
66    pub fn new(id: LinkId, r#type: LinkType, flags: MediaLinkFlags) -> Self {
67        Self { id, r#type, flags }
68    }
69
70    /// Unique ID for the link. Do not expect that the ID will always be the same for each instance of the device. In other words, do not hardcode link IDs in an application.
71    pub fn id(&self) -> LinkId {
72        self.id
73    }
74
75    pub fn r#type(&self) -> &LinkType {
76        &self.r#type
77    }
78
79    pub fn flags(&self) -> MediaLinkFlags {
80        self.flags
81    }
82}
83
84impl From<media::media_v2_link> for MediaLink {
85    fn from(link: media::media_v2_link) -> Self {
86        let r#type = match link.flags & media::MEDIA_LNK_FL_LINK_TYPE {
87            media::MEDIA_LNK_FL_DATA_LINK => LinkType::DataLink {
88                source_id: link.source_id.into(),
89                sink_id: link.sink_id.into(),
90            },
91            media::MEDIA_LNK_FL_INTERFACE_LINK => LinkType::InterfaceLink {
92                source_id: link.source_id.into(),
93                sink_id: link.sink_id.into(),
94            },
95            #[cfg(has_linux_media_sys__MEDIA_LNK_FL_ANCILLARY_LINK)]
96            media::MEDIA_LNK_FL_ANCILLARY_LINK => LinkType::AncillaryLink {
97                source_id: PadIdOr(link.source_id, PhantomData),
98                sink_id: PadIdOr(link.sink_id, PhantomData),
99            },
100            other => unreachable!("link type should not be there: {}", other),
101        };
102        Self {
103            id: link.id.into(),
104            r#type,
105            flags: link.flags.try_into().unwrap(),
106        }
107    }
108}