blob: a12b8263d3fdb7e2f54874fac8a2bc357c69b939 [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);
}
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,
#[error("Unexpected ioctl error: {0}")]
IoctlError(Error),
}
pub fn encoder_cmd(fd: &impl AsRawFd, command: EncoderCommand) -> Result<(), EncoderCmdError> {
let mut enc_cmd = 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() }
};
match unsafe { ioctl::vidioc_encoder_cmd(fd.as_raw_fd(), &mut enc_cmd) } {
Ok(_) => Ok(()),
Err(Error::Sys(Errno::EBUSY)) => Err(EncoderCmdError::DrainInProgress),
Err(Error::Sys(Errno::EINVAL)) => Err(EncoderCmdError::UnsupportedCommand),
Err(e) => Err(EncoderCmdError::IoctlError(e)),
}
}