blob: 449c0d557276538391cdd6f27abd8dfe5e28026f [file] [log] [blame]
use crate::bindings;
use nix::errno::Errno;
use nix::Error;
use std::{mem, os::unix::io::AsRawFd};
use thiserror::Error;
#[doc(hidden)]
mod ioctl {
use crate::bindings::v4l2_encoder_cmd;
nix::ioctl_readwrite!(vidioc_encoder_cmd, b'V', 77, v4l2_encoder_cmd);
nix::ioctl_readwrite!(vidioc_try_encoder_cmd, b'V', 78, v4l2_encoder_cmd);
}
#[derive(Debug, Clone, Copy)]
pub enum EncoderCommand {
Start,
Stop(bool),
Pause,
Resume,
}
#[derive(Debug, Error)]
pub enum EncoderCmdError {
#[error("Drain already in progress")]
DrainInProgress,
#[error("Command not supported by device")]
UnsupportedCommand(EncoderCommand),
#[error("Unexpected ioctl error: {0}")]
IoctlError(Error),
}
fn map_nix_error(error: nix::Error, command: EncoderCommand) -> EncoderCmdError {
match error {
Error::Sys(Errno::EBUSY) => EncoderCmdError::DrainInProgress,
Error::Sys(Errno::EINVAL) => EncoderCmdError::UnsupportedCommand(command),
e => EncoderCmdError::IoctlError(e),
}
}
impl From<EncoderCommand> for bindings::v4l2_encoder_cmd {
fn from(command: EncoderCommand) -> Self {
bindings::v4l2_encoder_cmd {
cmd: match &command {
EncoderCommand::Start => bindings::V4L2_ENC_CMD_START,
EncoderCommand::Stop(_) => bindings::V4L2_ENC_CMD_STOP,
EncoderCommand::Pause => bindings::V4L2_ENC_CMD_PAUSE,
EncoderCommand::Resume => bindings::V4L2_ENC_CMD_RESUME,
},
flags: match &command {
EncoderCommand::Stop(at_gop) if *at_gop => bindings::V4L2_ENC_CMD_STOP_AT_GOP_END,
_ => 0,
},
..unsafe { mem::zeroed() }
}
}
}
pub fn encoder_cmd(fd: &impl AsRawFd, command: EncoderCommand) -> Result<(), EncoderCmdError> {
let mut enc_cmd = bindings::v4l2_encoder_cmd::from(command);
match unsafe { ioctl::vidioc_encoder_cmd(fd.as_raw_fd(), &mut enc_cmd) } {
Ok(_) => Ok(()),
Err(e) => Err(map_nix_error(e, command)),
}
}
pub fn try_encoder_cmd(fd: &impl AsRawFd, command: EncoderCommand) -> Result<(), EncoderCmdError> {
let mut enc_cmd = bindings::v4l2_encoder_cmd::from(command);
match unsafe { ioctl::vidioc_try_encoder_cmd(fd.as_raw_fd(), &mut enc_cmd) } {
Ok(_) => Ok(()),
Err(e) => Err(map_nix_error(e, command)),
}
}