use crate::ioctl;
use crate::Media;
use bitflags::bitflags;
use core::ffi::CStr;
use core::fmt;
use core::mem;
use nix::{errno::Errno, libc::c_char};
use std::os::fd::AsRawFd;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum EntityFunction {
IfVidDecoder = 0x2001,
IfAudDecoder = 0x2002,
AudioCapture = 0x3001,
AudioPlayback = 0x3002,
AudioMixer = 0x3003,
ProcVideoComposer = 0x4001,
ProcVideoPixelFormatter = 0x4002,
ProcVideoPixelEncConv = 0x4003,
ProcVideoLut = 0x4004,
ProcVideoScaler = 0x4005,
ProcVideoStatistics = 0x4006,
ProcVideoEncoder = 0x4007,
ProcVideoDecoder = 0x4008,
ProcVideoIsp = 0x4009,
VidMux = 0x5001,
VidIfBridge = 0x5002,
AtvDecoder = 0x20004,
DvDecoder = 0x6001,
DvEncoder = 0x6002,
V4L = 0x10001,
CameraSensor = 0x20001,
Unknown,
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct EntityFlags: u32 {
const DEFAULT = 0b001;
const CONNECTOR = 0b010;
}
}
#[repr(C)]
pub struct Entity {
id: u32,
name: [c_char; 64],
function: EntityFunction,
flags: EntityFlags,
reserved: [u32; 5],
}
impl fmt::Debug for Entity {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Entity")
.field("id", &self.id)
.field("name", &self.name())
.field("function", &self.function)
.field("flags", &self.flags)
.finish()
}
}
impl Entity {
pub fn id(&self) -> u32 {
self.id
}
pub fn name(&self) -> &str {
unsafe {
let c_str = CStr::from_ptr(self.name.as_ptr());
std::str::from_utf8_unchecked(c_str.to_bytes())
}
}
pub fn function(&self) -> EntityFunction {
self.function
}
pub fn flags(&self) -> EntityFlags {
self.flags
}
}
#[derive(Debug, Clone, Copy)]
#[repr(u32)]
pub enum InterfaceType {
V4LVideo = 0x200,
V4LVbi = 0x201,
V4LRadio = 0x202,
V4LSubdev = 0x203,
V4LSwradio = 0x204,
V4LTouch = 0x205,
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InterfaceFlags: u32 {
}
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct InterfaceDevnode {
pub major: u32,
pub minor: u32,
}
#[repr(C)]
union InterfacePayload {
devnode: InterfaceDevnode,
raw: [u32; 16],
}
#[repr(C)]
pub struct Interface {
id: u32,
intf_type: InterfaceType,
flags: InterfaceFlags,
reserved: [u32; 9],
payload: InterfacePayload,
}
impl fmt::Debug for Interface {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Interface")
.field("id", &self.id)
.field("type", &self.intf_type)
.field("flags", &self.flags)
.field("payload", &unsafe { self.payload.devnode })
.finish()
}
}
impl Interface {
pub fn id(&self) -> u32 {
self.id
}
pub fn intf_type(&self) -> InterfaceType {
self.intf_type
}
pub fn flags(&self) -> InterfaceFlags {
self.flags
}
pub fn devnode(&self) -> InterfaceDevnode {
unsafe { self.payload.devnode }
}
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Default)]
pub struct PadFlags: u32 {
const SINK = 0b001;
const SOURCE = 0b010;
const MUST_CONNECT = 0b100;
}
}
#[repr(C)]
pub struct Pad {
id: u32,
entity_id: u32,
flags: PadFlags,
index: u32,
reserved: [u32; 4],
}
impl fmt::Debug for Pad {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Pad")
.field("id", &self.id)
.field("entity_id", &self.entity_id)
.field("flags", &self.flags)
.field("index", &self.index)
.finish()
}
}
impl Pad {
pub fn id(&self) -> u32 {
self.id
}
pub fn entity_id(&self) -> u32 {
self.entity_id
}
pub fn flags(&self) -> PadFlags {
self.flags
}
pub fn index(&self) -> u32 {
self.index
}
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Default)]
pub struct LinkFlags: u32 {
const ENABLED = 0b001;
const IMMUTABLE = 0b010;
const DYNAMIC = 0b100;
const DATA_LINK = 0x00000000;
const INTERFACE_LINK = 0x10000000;
}
}
#[repr(C)]
pub struct Link {
id: u32,
source_id: u32,
sink_id: u32,
flags: LinkFlags,
reserved: [u32; 6],
}
impl fmt::Debug for Link {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("Link")
.field("id", &self.id)
.field("source_id", &self.source_id)
.field("sink_id", &self.sink_id)
.field("flags", &self.flags)
.finish()
}
}
impl Link {
pub fn id(&self) -> u32 {
self.id
}
pub fn source_id(&self) -> u32 {
self.source_id
}
pub fn sink_id(&self) -> u32 {
self.sink_id
}
pub fn flags(&self) -> LinkFlags {
self.flags
}
}
#[derive(Debug, Default)]
#[repr(C)]
pub struct Topology {
topology_version: u64,
num_entities: u32,
reserved1: u32,
ptr_entities: u64,
num_interfaces: u32,
reserved2: u32,
ptr_interfaces: u64,
num_pads: u32,
reserved3: u32,
ptr_pads: u64,
num_links: u32,
reserved4: u32,
ptr_links: u64,
}
impl Drop for Topology {
fn drop(&mut self) {
Self::get_vec::<Entity>(self.ptr_entities, self.num_entities);
Self::get_vec::<Interface>(self.ptr_interfaces, self.num_interfaces);
Self::get_vec::<Pad>(self.ptr_pads, self.num_pads);
Self::get_vec::<Link>(self.ptr_links, self.num_links);
}
}
impl Topology {
pub(crate) fn from_media(media: &Media) -> Result<Topology, Errno> {
let mut data = Topology::default();
unsafe { ioctl::get_topology(media.as_raw_fd(), &mut data) }?;
let mut entities: Vec<Entity> = Vec::with_capacity(data.num_entities as usize);
let mut interfaces: Vec<Interface> = Vec::with_capacity(data.num_interfaces as usize);
let mut pads: Vec<Pad> = Vec::with_capacity(data.num_pads as usize);
let mut links: Vec<Link> = Vec::with_capacity(data.num_links as usize);
data.ptr_entities = entities.as_mut_ptr() as u64;
data.ptr_interfaces = interfaces.as_mut_ptr() as u64;
data.ptr_pads = pads.as_mut_ptr() as u64;
data.ptr_links = links.as_mut_ptr() as u64;
unsafe {
ioctl::get_topology(media.as_raw_fd(), &mut data)?;
entities.set_len(data.num_entities as usize);
interfaces.set_len(data.num_interfaces as usize);
pads.set_len(data.num_pads as usize);
links.set_len(data.num_links as usize);
}
mem::forget(entities);
mem::forget(interfaces);
mem::forget(pads);
mem::forget(links);
Ok(data)
}
pub fn version(&self) -> u64 {
self.topology_version
}
fn get_vec<T>(ptr: u64, num: u32) -> Vec<T> {
unsafe { Vec::from_raw_parts(ptr as *mut T, num as usize, num as usize) }
}
fn get_slice<'a, T>(ptr: u64, num: u32) -> &'a [T] {
unsafe { std::slice::from_raw_parts(ptr as *const T, num as usize) }
}
pub fn entities(&self) -> &[Entity] {
Self::get_slice::<Entity>(self.ptr_entities, self.num_entities)
}
pub fn interfaces(&self) -> &[Interface] {
Self::get_slice::<Interface>(self.ptr_interfaces, self.num_interfaces)
}
pub fn pads(&self) -> &[Pad] {
Self::get_slice::<Pad>(self.ptr_pads, self.num_pads)
}
pub fn links(&self) -> &[Link] {
Self::get_slice::<Link>(self.ptr_links, self.num_links)
}
pub fn get_entity(&self, id: u32) -> Option<&Entity> {
for entity in self.entities() {
if entity.id == id {
return Some(entity);
}
}
None
}
pub fn get_interface(&self, id: u32) -> Option<&Interface> {
for interface in self.interfaces() {
if interface.id == id {
return Some(interface);
}
}
None
}
pub fn get_pad(&self, id: u32) -> Option<&Pad> {
for pad in self.pads() {
if pad.id == id {
return Some(pad);
}
}
None
}
pub fn get_pads_for_entity(&self, entity_id: u32) -> Vec<&Pad> {
let mut pads = Vec::new();
for pad in self.pads() {
if pad.entity_id == entity_id {
pads.push(pad);
}
}
pads
}
pub fn get_link_by_source_id(&self, source_id: u32) -> Option<&Link> {
for link in self.links() {
if link.source_id == source_id {
return Some(link);
}
}
None
}
pub fn get_link_by_sink_id(&self, sink_id: u32) -> Option<&Link> {
for link in self.links() {
if link.sink_id == sink_id {
return Some(link);
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_size (
($t:ty, $sz:expr) => (
assert_eq!(::std::mem::size_of::<$t>(), $sz);
);
);
#[test]
fn size() {
assert_size!(Entity, 96);
assert_size!(InterfaceDevnode, 8);
assert_size!(InterfacePayload, 64);
assert_size!(Interface, 112);
assert_size!(Pad, 32);
assert_size!(Link, 40);
assert_size!(Topology, 72);
}
}