mirror of
https://github.com/danog/libdvb.git
synced 2024-11-26 20:04:39 +01:00
Add DMX API
This commit is contained in:
parent
38f2db4e38
commit
983725c618
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "libdvb-rs"
|
||||
version = "0.4.3"
|
||||
description = "Safer pure-Rust interface for DVB-API v5 devices in Linux"
|
||||
version = "0.4.4"
|
||||
description = "Safer and feature-complete pure-Rust interface for DVB-API v5 devices in Linux"
|
||||
authors = ["Cesbo Developers Team <info@cesbo.com>", "Daniil Gentili <daniil@daniil.it>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
|
182
src/dmx/mod.rs
182
src/dmx/mod.rs
@ -1 +1,183 @@
|
||||
use {
|
||||
anyhow::{Context, Result},
|
||||
nix::{ioctl_write_int_bad, ioctl_none_bad, ioctl_write_ptr, request_code_none},
|
||||
std::{
|
||||
fs::{File, OpenOptions},
|
||||
os::unix::{
|
||||
fs::{OpenOptionsExt},
|
||||
io::{AsRawFd, RawFd},
|
||||
},
|
||||
},
|
||||
sys::*,
|
||||
};
|
||||
|
||||
|
||||
pub mod sys;
|
||||
|
||||
/// A reference to the demux device and device information
|
||||
#[derive(Debug)]
|
||||
pub struct DmxDevice {
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl AsRawFd for DmxDevice {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.file.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl DmxDevice {
|
||||
fn open(adapter: u32, device: u32, is_write: bool) -> Result<Self> {
|
||||
let path = format!("/dev/dvb/adapter{}/demux{}", adapter, device);
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(is_write)
|
||||
.custom_flags(::nix::libc::O_NONBLOCK)
|
||||
.open(&path)
|
||||
.with_context(|| format!("DMX: failed to open device {}", &path))?;
|
||||
|
||||
Ok(DmxDevice {
|
||||
file,
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempts to open frontend device in read-only mode
|
||||
#[inline]
|
||||
pub fn open_ro(adapter: u32, device: u32) -> Result<Self> {
|
||||
Self::open(adapter, device, false)
|
||||
}
|
||||
|
||||
/// Attempts to open frontend device in read-write mode
|
||||
#[inline]
|
||||
pub fn open_rw(adapter: u32, device: u32) -> Result<Self> {
|
||||
Self::open(adapter, device, true)
|
||||
}
|
||||
|
||||
/// Attempts to set demux PES filter parameters.
|
||||
/// By a PES filter is meant a filter that is based just on the packet identifier (PID),
|
||||
/// i.e. no PES header or payload filtering capability is supported.
|
||||
///
|
||||
/// There is a flag field where it is possible to state whether a section should be CRC-checked,
|
||||
/// whether the filter should be a “one-shot” filter, i.e. if the filtering operation should be stopped
|
||||
/// after the first section is received, and whether the filtering operation should be started immediately
|
||||
/// (without waiting for a DMX_START ioctl call).
|
||||
pub fn set_pes_filter(&self, filter: &DmxPesFilterParams) -> Result<()> {
|
||||
// DMX_SET_PES_FILTER
|
||||
ioctl_write_ptr!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
b'o',
|
||||
44,
|
||||
DmxPesFilterParams
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd(), filter as *const _) }.context("DMX: set PES filter")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
/// Tries to add multiple PIDs to a transport stream filter previously set up with
|
||||
/// set_pes_filter and output equal to DMX_OUT_TSDEMUX_TAP.
|
||||
pub fn add_pid(&self, pid: u16) -> Result<()> {
|
||||
// DMX_ADD_PID
|
||||
ioctl_write_ptr!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
b'o',
|
||||
51,
|
||||
u16
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd(), &pid as *const _) }.context("DMX: add PID")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This ioctl call allows to remove a PID when multiple PIDs are set on a transport stream filter,
|
||||
/// e. g. a filter previously set up with output equal to DMX_OUT_TSDEMUX_TAP,
|
||||
/// created via either set_pes_filter or add_pid.
|
||||
pub fn remove_pid(&self, pid: u16) -> Result<()> {
|
||||
// DMX_REMOVE_PID
|
||||
ioctl_write_ptr!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
b'o',
|
||||
52,
|
||||
u16
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd(), &pid as *const _) }.context("DMX: remove PID")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to set demux SCT filter parameters.
|
||||
/// A timeout may be defined stating number of seconds to wait for a section to be loaded.
|
||||
/// A value of 0 means that no timeout should be applied.
|
||||
/// Finally there is a flag field where it is possible to state whether a section should be CRC-checked,
|
||||
/// whether the filter should be a “one-shot” filter, i.e. if the filtering operation should be stopped
|
||||
/// after the first section is received, and whether the filtering operation should be started immediately
|
||||
/// (without waiting for a DMX_START ioctl call).
|
||||
///
|
||||
/// If a filter was previously set-up, this filter will be canceled, and the receive buffer will be flushed.
|
||||
pub fn set_filter(&self, filter: &DmxSctFilterParams) -> Result<()> {
|
||||
// DMX_SET_FILTER
|
||||
ioctl_write_ptr!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
b'o',
|
||||
43,
|
||||
DmxSctFilterParams
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd(), filter as *const _) }.context("DMX: set SCT filter")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to set the size of the circular buffer used for filtered data.
|
||||
/// The default size is two maximum sized sections,
|
||||
/// i.e. if this function is not called a buffer size of 2 * 4096 bytes will be used.
|
||||
pub fn set_buffer_size(&self, size: u32) -> Result<()> {
|
||||
// DMX_SET_BUFFER_SIZE
|
||||
ioctl_write_int_bad!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
request_code_none!(b'o', 45)
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd(), size as _) }.context("DMX: set buffer size")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to start the actual filtering operation defined via the ioctl calls set_filter or set_pes_filter.
|
||||
pub fn start(&self) -> Result<()> {
|
||||
// DMX_START
|
||||
ioctl_none_bad!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
request_code_none!(b'o', 41)
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd()) }.context("DMX: start")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempts to stop the actual filtering operation defined via the ioctl calls set_filter or set_pes_filter and started via start.
|
||||
pub fn stop(&self) -> Result<()> {
|
||||
// DMX_STOP
|
||||
ioctl_none_bad!(
|
||||
#[inline]
|
||||
ioctl_call,
|
||||
request_code_none!(b'o', 42)
|
||||
);
|
||||
|
||||
unsafe { ioctl_call(self.as_raw_fd()) }.context("DMX: stop")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
145
src/dmx/sys.rs
145
src/dmx/sys.rs
@ -1,127 +1,154 @@
|
||||
use {
|
||||
crate::ioctl::{
|
||||
IoctlInt,
|
||||
io_none,
|
||||
io_write,
|
||||
},
|
||||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use strum::FromRepr;
|
||||
|
||||
pub use {
|
||||
dmx_output::*,
|
||||
dmx_input::*,
|
||||
dmx_ts_pes::*,
|
||||
dmx_filter_flags::*,
|
||||
DmxOutput::*,
|
||||
DmxInput::*,
|
||||
DmxTsPes::*,
|
||||
};
|
||||
|
||||
|
||||
/// Output for the demux
|
||||
mod dmx_output {
|
||||
#[repr(u32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
|
||||
pub enum DmxOutput {
|
||||
/// Streaming directly to decoder
|
||||
pub const DMX_OUT_DECODER: u32 = 0;
|
||||
DMX_OUT_DECODER = 0,
|
||||
/// Output going to a memory buffer (to be retrieved via the read command).
|
||||
/// Delivers the stream output to the demux device on which the ioctl
|
||||
/// is called.
|
||||
pub const DMX_OUT_TAP: u32 = 1;
|
||||
DMX_OUT_TAP = 1,
|
||||
/// Output multiplexed into a new TS (to be retrieved by reading from the
|
||||
/// logical DVR device). Routes output to the logical DVR device
|
||||
/// `/dev/dvb/adapter?/dvr?`, which delivers a TS multiplexed from all
|
||||
/// filters for which DMX_OUT_TS_TAP was specified.
|
||||
pub const DMX_OUT_TS_TAP: u32 = 2;
|
||||
DMX_OUT_TS_TAP = 2,
|
||||
/// Like DMX_OUT_TS_TAP but retrieved from the DMX device.
|
||||
pub const DMX_OUT_TSDEMUX_TAP: u32 = 3;
|
||||
DMX_OUT_TSDEMUX_TAP = 3
|
||||
}
|
||||
|
||||
|
||||
/// Input from the demux
|
||||
mod dmx_input {
|
||||
#[repr(u32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
|
||||
pub enum DmxInput {
|
||||
/// Input from a front-end device
|
||||
pub const DMX_IN_FRONTEND: u32 = 0;
|
||||
DMX_IN_FRONTEND = 0,
|
||||
/// Input from the logical DVR device
|
||||
pub const DMX_IN_DVR: u32 = 1;
|
||||
DMX_IN_DVR = 1
|
||||
}
|
||||
|
||||
|
||||
/// type of the PES filter
|
||||
mod dmx_ts_pes {
|
||||
#[repr(u32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, FromRepr)]
|
||||
pub enum DmxTsPes {
|
||||
/// first audio PID
|
||||
pub const DMX_PES_AUDIO0: u32 = 0;
|
||||
DMX_PES_AUDIO0 = 0,
|
||||
/// first video PID
|
||||
pub const DMX_PES_VIDEO0: u32 = 1;
|
||||
DMX_PES_VIDEO0 = 1,
|
||||
/// first teletext PID
|
||||
pub const DMX_PES_TELETEXT0: u32 = 2;
|
||||
DMX_PES_TELETEXT0 = 2,
|
||||
/// first subtitle PID
|
||||
pub const DMX_PES_SUBTITLE0: u32 = 3;
|
||||
DMX_PES_SUBTITLE0 = 3,
|
||||
/// first Program Clock Reference PID
|
||||
pub const DMX_PES_PCR0: u32 = 4;
|
||||
DMX_PES_PCR0 = 4,
|
||||
|
||||
/// second audio PID.
|
||||
pub const DMX_PES_AUDIO1: u32 = 5;
|
||||
DMX_PES_AUDIO1 = 5,
|
||||
/// second video PID.
|
||||
pub const DMX_PES_VIDEO1: u32 = 6;
|
||||
DMX_PES_VIDEO1 = 6,
|
||||
/// second teletext PID.
|
||||
pub const DMX_PES_TELETEXT1: u32 = 7;
|
||||
DMX_PES_TELETEXT1 = 7,
|
||||
/// second subtitle PID.
|
||||
pub const DMX_PES_SUBTITLE1: u32 = 8;
|
||||
DMX_PES_SUBTITLE1 = 8,
|
||||
/// second Program Clock Reference PID.
|
||||
pub const DMX_PES_PCR1: u32 = 9;
|
||||
DMX_PES_PCR1 = 9,
|
||||
|
||||
/// third audio PID.
|
||||
pub const DMX_PES_AUDIO2: u32 = 10;
|
||||
DMX_PES_AUDIO2 = 10,
|
||||
/// third video PID.
|
||||
pub const DMX_PES_VIDEO2: u32 = 11;
|
||||
DMX_PES_VIDEO2 = 11,
|
||||
/// third teletext PID.
|
||||
pub const DMX_PES_TELETEXT2: u32 = 12;
|
||||
DMX_PES_TELETEXT2 = 12,
|
||||
/// third subtitle PID.
|
||||
pub const DMX_PES_SUBTITLE2: u32 = 13;
|
||||
DMX_PES_SUBTITLE2 = 13,
|
||||
/// third Program Clock Reference PID.
|
||||
pub const DMX_PES_PCR2: u32 = 14;
|
||||
DMX_PES_PCR2 = 14,
|
||||
|
||||
/// fourth audio PID.
|
||||
pub const DMX_PES_AUDIO3: u32 = 15;
|
||||
DMX_PES_AUDIO3 = 15,
|
||||
/// fourth video PID.
|
||||
pub const DMX_PES_VIDEO3: u32 = 16;
|
||||
DMX_PES_VIDEO3 = 16,
|
||||
/// fourth teletext PID.
|
||||
pub const DMX_PES_TELETEXT3: u32 = 17;
|
||||
DMX_PES_TELETEXT3 = 17,
|
||||
/// fourth subtitle PID.
|
||||
pub const DMX_PES_SUBTITLE3: u32 = 18;
|
||||
DMX_PES_SUBTITLE3 = 18,
|
||||
/// fourth Program Clock Reference PID.
|
||||
pub const DMX_PES_PCR3: u32 = 19;
|
||||
DMX_PES_PCR3 = 19,
|
||||
|
||||
/// any other PID.
|
||||
pub const DMX_PES_OTHER: u32 = 20;
|
||||
DMX_PES_OTHER = 20,
|
||||
}
|
||||
|
||||
|
||||
/// Flags for the demux filter
|
||||
mod dmx_filter_flags {
|
||||
/// Only deliver sections where the CRC check succeeded
|
||||
pub const DMX_CHECK_CRC: u32 = 1;
|
||||
/// Disable the section filter after one section has been delivered
|
||||
pub const DMX_ONESHOT: u32 = 2;
|
||||
/// Start filter immediately without requiring a `DMX_START`
|
||||
pub const DMX_IMMEDIATE_START: u32 = 4;
|
||||
bitflags! {
|
||||
/// Flags for the demux filter
|
||||
#[repr(C)]
|
||||
pub struct DmxFilterFlags : u32 {
|
||||
/// Only deliver sections where the CRC check succeeded
|
||||
const DMX_CHECK_CRC = 1;
|
||||
/// Disable the section filter after one section has been delivered
|
||||
const DMX_ONESHOT = 2;
|
||||
/// Start filter immediately without requiring a `DMX_START`
|
||||
const DMX_IMMEDIATE_START = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Specifies Packetized Elementary Stream (PES) filter parameters
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DmxPesFilterParams {
|
||||
/// PID to be filtered. 8192 to pass all PID's
|
||||
pub pid: u16,
|
||||
/// Demux input, as specified by `DMX_IN_*`
|
||||
pub input: u32,
|
||||
pub input: DmxInput,
|
||||
/// Demux output, as specified by `DMX_OUT_*`
|
||||
pub output: u32,
|
||||
pub output: DmxOutput,
|
||||
/// Type of the pes filter, as specified by `DMX_PES_*`
|
||||
pub pes_type: u32,
|
||||
pub pes_type: DmxTsPes,
|
||||
/// Demux PES flags
|
||||
pub flags: u32,
|
||||
pub flags: DmxFilterFlags,
|
||||
}
|
||||
|
||||
pub const DMX_FILTER_SIZE: usize = 16;
|
||||
|
||||
pub const DMX_START: IoctlInt = io_none(b'o', 41);
|
||||
pub const DMX_STOP: IoctlInt = io_none(b'o', 42);
|
||||
pub const DMX_SET_PES_FILTER: IoctlInt = io_write::<DmxPesFilterParams>(b'o', 44);
|
||||
pub const DMX_SET_BUFFER_SIZE: IoctlInt = io_none(b'o', 45);
|
||||
/// Specifies demux section header filter parameters
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DmxFilter {
|
||||
/// Bit array with bits to be matched at the section header
|
||||
pub filter: [u8; DMX_FILTER_SIZE],
|
||||
/// Bits that are valid at the filter bit array
|
||||
pub mask: [u8; DMX_FILTER_SIZE],
|
||||
/// Mode of match: if bit is zero, it will match if equal (positive match); if bit is one, it will match if the bit is negated.
|
||||
pub mode: [u8; DMX_FILTER_SIZE],
|
||||
}
|
||||
|
||||
/// Specifies Section header (SCT) filter parameters
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DmxSctFilterParams {
|
||||
/// PID to be filtered. 8192 to pass all PID's
|
||||
pub pid: u16,
|
||||
/// Section header filter, as defined by DmxFilter
|
||||
pub filter: DmxFilter,
|
||||
/// Maximum time to filter, in milliseconds
|
||||
pub timeout: u32,
|
||||
/// Extra flags for the section filter, as specified by DmxFilterFlags
|
||||
pub flags: DmxFilterFlags
|
||||
}
|
@ -5,9 +5,11 @@ extern crate anyhow;
|
||||
pub mod ca;
|
||||
pub mod fe;
|
||||
pub mod net;
|
||||
pub mod dmx;
|
||||
|
||||
pub use {
|
||||
ca::CaDevice,
|
||||
fe::{FeDevice, FeStatus},
|
||||
net::NetDevice,
|
||||
dmx::DmxDevice,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user