mod capture_thread;
use crate::{
bindings,
device::{
poller::{DeviceEvent, PollError, PollEvent, Poller, Waker},
queue::{
direction::{Capture, Output},
handles_provider::HandlesProvider,
BuffersAllocated, CreateQueueError, FormatBuilder, GetCaptureBufferByIndex,
GetFreeBufferError, GetFreeCaptureBuffer, GetFreeOutputBuffer, OutputQueueableProvider,
Queue, QueueInit, RequestBuffersError,
},
AllocatedQueue, Device, DeviceConfig, DeviceOpenError, Stream, TryDequeue,
},
ioctl::{
self, subscribe_event, BufferCapabilities, DqBufError, FormatFlags, StreamOnError,
V4l2BufferFromError,
},
memory::{BufferHandles, PrimitiveBufferHandles},
};
use capture_thread::CaptureThread;
use log::{debug, error, info, trace};
use std::{
convert::TryFrom,
io,
path::Path,
sync::{atomic::AtomicUsize, mpsc, Arc},
task::Wake,
thread::JoinHandle,
};
use thiserror::Error;
use super::*;
pub trait DecoderState {}
pub struct Decoder<S: DecoderState> {
device: Arc<Device>,
state: S,
}
pub struct AwaitingOutputFormat {
output_queue: Queue<Output, QueueInit>,
capture_queue: Queue<Capture, QueueInit>,
}
impl DecoderState for AwaitingOutputFormat {}
#[derive(Debug, Error)]
pub enum DecoderOpenError {
#[error("error while opening device")]
DeviceOpenError(#[from] DeviceOpenError),
#[error("error while creating queue")]
CreateQueueError(#[from] CreateQueueError),
#[error("specified device is not a stateful decoder")]
NotAStatefulDecoder,
}
impl Decoder<AwaitingOutputFormat> {
pub fn open(path: &Path) -> Result<Self, DecoderOpenError> {
let config = DeviceConfig::new().non_blocking_dqbuf();
let device = Arc::new(Device::open(path, config)?);
let capture_queue = Queue::get_capture_mplane_queue(device.clone())?;
let output_queue = Queue::get_output_mplane_queue(device.clone())?;
output_queue
.format_iter()
.find(|fmt| fmt.flags.contains(FormatFlags::COMPRESSED))
.and(
capture_queue
.format_iter()
.find(|fmt| !fmt.flags.contains(FormatFlags::COMPRESSED)),
)
.ok_or(DecoderOpenError::NotAStatefulDecoder)
.map(|_| ())?;
if output_queue
.get_capabilities()
.contains(BufferCapabilities::SUPPORTS_REQUESTS)
{
return Err(DecoderOpenError::NotAStatefulDecoder);
}
Ok(Decoder {
device,
state: AwaitingOutputFormat {
output_queue,
capture_queue,
},
})
}
pub fn set_output_format<F>(mut self, f: F) -> anyhow::Result<Decoder<AwaitingOutputBuffers>>
where
F: FnOnce(FormatBuilder) -> anyhow::Result<()>,
{
let builder = self.state.output_queue.change_format()?;
f(builder)?;
Ok(Decoder {
device: self.device,
state: AwaitingOutputBuffers {
output_queue: self.state.output_queue,
capture_queue: self.state.capture_queue,
},
})
}
}
pub struct AwaitingOutputBuffers {
output_queue: Queue<Output, QueueInit>,
capture_queue: Queue<Capture, QueueInit>,
}
impl DecoderState for AwaitingOutputBuffers {}
impl Decoder<AwaitingOutputBuffers> {
pub fn allocate_output_buffers_generic<OP: BufferHandles>(
self,
memory_type: OP::SupportedMemoryType,
num_buffers: usize,
) -> Result<Decoder<ReadyToDecode<OP>>, RequestBuffersError> {
Ok(Decoder {
device: self.device,
state: ReadyToDecode {
output_queue: self
.state
.output_queue
.request_buffers_generic::<OP>(memory_type, num_buffers as u32)?,
capture_queue: self.state.capture_queue,
poll_wakeups_counter: None,
},
})
}
pub fn allocate_output_buffers<OP: PrimitiveBufferHandles>(
self,
num_output: usize,
) -> Result<Decoder<ReadyToDecode<OP>>, RequestBuffersError> {
self.allocate_output_buffers_generic(OP::MEMORY_TYPE, num_output)
}
}
pub struct ReadyToDecode<OP: BufferHandles> {
output_queue: Queue<Output, BuffersAllocated<OP>>,
capture_queue: Queue<Capture, QueueInit>,
poll_wakeups_counter: Option<Arc<AtomicUsize>>,
}
impl<OP: BufferHandles> DecoderState for ReadyToDecode<OP> {}
#[derive(Debug, Error)]
pub enum StartDecoderError {
#[error("error while creating poller")]
CannotCreatePoller(nix::Error),
#[error("cannot subscribe to decoder event")]
SubscribeEventError(#[from] ioctl::SubscribeEventError),
#[error("error while enabling event")]
CannotEnableEvent(nix::Error),
#[error("error while creating capture thread")]
CannotCreateCaptureThread(io::Error),
#[error("error while activating capture thread")]
CannotStartCaptureThread(io::Error),
#[error("error while starting the output queue")]
StreamOnError(#[from] StreamOnError),
}
impl<OP: BufferHandles> Decoder<ReadyToDecode<OP>> {
pub fn set_poll_counter(mut self, poll_wakeups_counter: Arc<AtomicUsize>) -> Self {
self.state.poll_wakeups_counter = Some(poll_wakeups_counter);
self
}
#[allow(clippy::type_complexity)]
pub fn start<P, InputDoneCb, DecoderEventCb, FormatChangedCb>(
self,
input_done_cb: InputDoneCb,
decoder_event_cb: DecoderEventCb,
set_capture_format_cb: FormatChangedCb,
) -> Result<
Decoder<Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>>,
StartDecoderError,
>
where
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
for<'a> Queue<Capture, BuffersAllocated<P::HandleType>>:
GetFreeCaptureBuffer<'a, P::HandleType> + GetCaptureBufferByIndex<'a, P::HandleType>,
{
subscribe_event(
&*self.device,
ioctl::EventType::SourceChange(0),
ioctl::SubscribeEventFlags::empty(),
)?;
let mut output_poller =
Poller::new(Arc::clone(&self.device)).map_err(StartDecoderError::CannotCreatePoller)?;
output_poller
.enable_event(DeviceEvent::OutputReady)
.map_err(StartDecoderError::CannotEnableEvent)?;
let (command_sender, command_receiver) = mpsc::channel::<DecoderCommand>();
let (response_sender, response_receiver) = mpsc::channel::<CaptureThreadResponse>();
let mut decoder_thread = CaptureThread::new(
&self.device,
self.state.capture_queue,
decoder_event_cb,
set_capture_format_cb,
command_receiver,
response_sender,
)
.map_err(StartDecoderError::CannotCreateCaptureThread)?;
let command_waker = Arc::clone(&decoder_thread.command_waker);
if let Some(counter) = &self.state.poll_wakeups_counter {
output_poller.set_poll_counter(Arc::clone(counter));
decoder_thread.poller.set_poll_counter(Arc::clone(counter));
}
let handle = std::thread::Builder::new()
.name("V4L2 Decoder".into())
.spawn(move || decoder_thread.run())
.map_err(StartDecoderError::CannotStartCaptureThread)?;
self.state.output_queue.stream_on()?;
Ok(Decoder {
device: self.device,
state: Decoding {
output_queue: self.state.output_queue,
input_done_cb,
output_poller,
command_waker,
command_sender,
response_receiver,
handle,
},
})
}
}
#[derive(Debug)]
enum DecoderCommand {
Drain(bool),
Flush,
Stop,
}
#[derive(Debug)]
enum CaptureThreadResponse {
DrainDone(Result<bool, DrainError>),
FlushDone(anyhow::Result<()>),
}
pub struct Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>
where
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
output_queue: Queue<Output, BuffersAllocated<OP>>,
input_done_cb: InputDoneCb,
output_poller: Poller,
command_waker: Arc<Waker>,
command_sender: mpsc::Sender<DecoderCommand>,
response_receiver: mpsc::Receiver<CaptureThreadResponse>,
handle: JoinHandle<CaptureThread<P, DecoderEventCb, FormatChangedCb>>,
}
impl<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb> DecoderState
for Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>
where
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
}
#[derive(Debug, Error)]
pub enum SendCommandError {
#[error("error while queueing the message")]
SendError,
}
#[derive(Debug, Error)]
pub enum StopError {
#[error("error while sending the stop command to the capture thread")]
SendCommand(#[from] SendCommandError),
#[error("error while waiting for the decoder thread to finish")]
Join,
#[error("error while stopping the OUTPUT queue")]
Streamoff(#[from] ioctl::StreamOffError),
}
#[derive(Debug, Error)]
pub enum DrainError {
#[error("cannot drain now: output format not yet determined")]
TryAgain,
#[error("error while sending the flush command to the capture thread")]
SendCommand(#[from] SendCommandError),
#[error("error while waiting for the decoder thread to drain")]
RecvError(#[from] mpsc::RecvError),
#[error("error while draining on the capture thread")]
CaptureThreadError(anyhow::Error),
}
#[derive(Debug, Error)]
pub enum FlushError {
#[error("error while stopping the OUTPUT queue")]
StreamoffError(#[from] ioctl::StreamOffError),
#[error("error while sending the flush command to the capture thread")]
SendCommand(#[from] SendCommandError),
#[error("error while waiting for the decoder thread to flush")]
RecvError(#[from] mpsc::RecvError),
#[error("error while flushing on the capture thread")]
CaptureThreadError(anyhow::Error),
#[error("error while starting the OUTPUT queue")]
StreamonError(#[from] ioctl::StreamOnError),
}
#[allow(type_alias_bounds)]
type CanceledBuffers<OP: BufferHandles> =
Vec<<Queue<Output, BuffersAllocated<OP>> as Stream>::Canceled>;
impl<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>
Decoder<Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>>
where
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
pub fn num_output_buffers(&self) -> usize {
self.state.output_queue.num_buffers()
}
fn send_command(&self, command: DecoderCommand) -> Result<(), SendCommandError> {
trace!("Sending command: {:?}", command);
self.state
.command_sender
.send(command)
.map_err(|_| SendCommandError::SendError)?;
self.state.command_waker.wake_by_ref();
Ok(())
}
pub fn get_output_format<O: TryFrom<bindings::v4l2_format>>(
&self,
) -> Result<O, ioctl::GFmtError> {
self.state.output_queue.get_format()
}
pub fn stop(self) -> Result<CanceledBuffers<OP>, StopError> {
debug!("Stop requested");
self.send_command(DecoderCommand::Stop)?;
match self.state.handle.join() {
Ok(_) => (),
Err(_) => return Err(StopError::Join),
}
Ok(self.state.output_queue.stream_off()?)
}
pub fn drain(&self, blocking: bool) -> Result<bool, DrainError> {
debug!("Drain requested");
self.send_command(DecoderCommand::Drain(blocking))?;
match self.state.response_receiver.recv()? {
CaptureThreadResponse::DrainDone(response) => match response {
Ok(completed) => Ok(completed),
Err(e) => {
error!("Error while draining on the capture thread: {}", e);
Err(e)
}
},
r => {
error!(
"Unexpected capture thread response received while draining: {:?}",
r
);
Err(DrainError::CaptureThreadError(anyhow::anyhow!(
"Unexpected response while draining"
)))
}
}
}
pub fn flush(&self) -> Result<(), FlushError> {
debug!("Flush requested");
let canceled_buffers = self.state.output_queue.stream_off()?;
self.send_command(DecoderCommand::Flush)?;
for buffer in canceled_buffers {
(self.state.input_done_cb)(CompletedInputBuffer::Canceled(buffer));
}
match self.state.response_receiver.recv()? {
CaptureThreadResponse::FlushDone(response) => match response {
Ok(()) => (),
Err(e) => {
error!("Error while flushing on the capture thread: {}", e);
return Err(FlushError::CaptureThreadError(e));
}
},
r => {
error!(
"Unexpected capture thread response received while flushing: {:?}",
r
);
return Err(FlushError::CaptureThreadError(anyhow::anyhow!(
"Unexpected response while flushing"
)));
}
}
self.state.output_queue.stream_on()?;
debug!("Flush complete");
Ok(())
}
fn dequeue_output_buffers(&self) -> Result<(), DqBufError<V4l2BufferFromError>> {
let output_queue = &self.state.output_queue;
while output_queue.num_queued_buffers() > 0 {
match output_queue.try_dequeue() {
Ok(buf) => {
(self.state.input_done_cb)(CompletedInputBuffer::Dequeued(buf));
}
Err(DqBufError::IoctlError(ioctl::DqBufIoctlError::NotReady)) => break,
Err(e) => return Err(e),
}
}
Ok(())
}
fn wait_for_output_buffer(&mut self) -> Result<(), GetBufferError> {
for event in self.state.output_poller.poll(None)? {
match event {
PollEvent::Device(DeviceEvent::OutputReady) => {
self.dequeue_output_buffers()?;
}
_ => panic!("Unexpected return from OUTPUT queue poll!"),
}
}
Ok(())
}
}
impl<'a, OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb> OutputQueueableProvider<'a, OP>
for Decoder<Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>>
where
Queue<Output, BuffersAllocated<OP>>: OutputQueueableProvider<'a, OP>,
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
type Queueable =
<Queue<Output, BuffersAllocated<OP>> as OutputQueueableProvider<'a, OP>>::Queueable;
}
#[derive(Debug, Error)]
pub enum GetBufferError {
#[error("error while dequeueing buffer")]
DequeueError(#[from] DqBufError<V4l2BufferFromError>),
#[error("error during poll")]
PollError(#[from] PollError),
#[error("error while obtaining buffer")]
GetFreeBufferError(#[from] GetFreeBufferError),
}
impl<'a, OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>
GetFreeOutputBuffer<'a, OP, GetBufferError>
for Decoder<Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>>
where
Queue<Output, BuffersAllocated<OP>>: GetFreeOutputBuffer<'a, OP>,
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
fn try_get_free_buffer(&'a self) -> Result<Self::Queueable, GetBufferError> {
self.dequeue_output_buffers()?;
Ok(self.state.output_queue.try_get_free_buffer()?)
}
}
impl<'a, OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>
Decoder<Decoding<OP, P, InputDoneCb, DecoderEventCb, FormatChangedCb>>
where
Self: GetFreeOutputBuffer<'a, OP, GetBufferError>,
OP: BufferHandles,
P: HandlesProvider,
InputDoneCb: InputDoneCallback<OP>,
DecoderEventCb: DecoderEventCallback<P>,
FormatChangedCb: FormatChangedCallback<P>,
{
pub fn num_queued_buffers(&self) -> usize {
self.state.output_queue.num_queued_buffers()
}
pub fn get_buffer(
&'a mut self,
) -> Result<<Self as OutputQueueableProvider<'a, OP>>::Queueable, GetBufferError> {
let output_queue = &self.state.output_queue;
if output_queue.num_queued_buffers() == output_queue.num_buffers() {
self.wait_for_output_buffer()?;
}
self.try_get_free_buffer()
}
pub fn kick(&self) -> Result<(), DqBufError<V4l2BufferFromError>> {
info!("Kick!");
self.dequeue_output_buffers()
}
}