use eye_hal::error::{Error, ErrorKind, Result};
use eye_hal::platform::Context as PlatformContext;
use eye_hal::platform::{Device as PlatformDevice, Stream as PlatformStream};
use eye_hal::traits::{Context, Device as DeviceTrait};
use eye_hal::{control, stream};
use crate::colorconvert::codec;
use crate::colorconvert::stream::CodecStream;
pub struct Device<'a> {
inner: PlatformDevice<'a>,
}
impl<'a> Device<'a> {
pub fn new(dev: PlatformDevice<'a>) -> Result<Self> {
Ok(Device { inner: dev })
}
pub fn with_uri<S: AsRef<str>>(uri: S) -> Result<Self> {
let uri = uri.as_ref();
let ctx = PlatformContext::all().next().ok_or(Error::new(
ErrorKind::Other,
"no platform context available",
))?;
let inner = ctx.open_device(uri)?;
Self::new(inner)
}
}
impl<'a> DeviceTrait<'a> for Device<'a> {
type Stream = PlatformStream<'a>;
fn streams(&self) -> Result<Vec<stream::Descriptor>> {
let mut streams = self.inner.streams()?;
for blueprint in codec::blueprints() {
for chain in blueprint.src_fmts().iter().zip(blueprint.dst_fmts().iter()) {
if streams
.iter()
.find(|stream| stream.pixfmt == *chain.0)
.is_some()
&& streams
.iter()
.find(|stream| stream.pixfmt == *chain.1)
.is_none()
{
let _streams: Vec<stream::Descriptor> = streams
.iter()
.filter_map(|stream| {
if stream.pixfmt == *chain.0 {
Some(stream.clone())
} else {
None
}
})
.collect();
_streams.into_iter().for_each(|stream| {
streams.push(stream::Descriptor {
width: stream.width,
height: stream.height,
pixfmt: chain.1.clone(),
interval: stream.interval,
});
});
}
}
}
Ok(streams)
}
fn start_stream(&self, desc: &stream::Descriptor) -> Result<Self::Stream> {
let native_streams = self.inner.streams()?;
if let Some(_) = native_streams
.iter()
.find(|stream| stream.pixfmt == desc.pixfmt)
{
return self.inner.start_stream(desc);
}
let blueprints: Vec<Box<dyn codec::Blueprint>> = codec::blueprints()
.into_iter()
.filter(|bp| {
bp.dst_fmts()
.iter()
.find(|pixfmt| **pixfmt == desc.pixfmt)
.is_some()
})
.collect();
let src_fmt = if let Some(pixfmt) = blueprints.iter().find_map(|bp| {
for pixfmt in bp.src_fmts() {
match native_streams.iter().find(|desc| desc.pixfmt == pixfmt) {
Some(desc) => return Some(desc.pixfmt.clone()),
None => continue,
}
}
None
}) {
pixfmt
} else {
return Err(Error::new(
ErrorKind::Other,
"no codec blueprint for native pixfmt",
));
};
let blueprint = if let Some(bp) = blueprints.into_iter().find(|bp| {
bp.src_fmts()
.into_iter()
.find(|pixfmt| *pixfmt == src_fmt)
.is_some()
}) {
bp
} else {
return Err(Error::new(
ErrorKind::Other,
format!("no codec blueprint for {} -> {}", src_fmt, desc.pixfmt),
));
};
let inparams = codec::Parameters {
pixfmt: src_fmt.clone(),
width: desc.width,
height: desc.height,
};
let outparams = codec::Parameters {
pixfmt: desc.pixfmt.clone(),
width: desc.width,
height: desc.height,
};
let codec = match blueprint.instantiate(inparams, outparams) {
Ok(instance) => instance,
Err(_e) => {
return Err(Error::new(
ErrorKind::Other,
"failed to create codec instance",
))
}
};
let mut source_fmt = desc.clone();
source_fmt.pixfmt = src_fmt;
let native_stream = self.inner.start_stream(&source_fmt)?;
return Ok(PlatformStream::Custom(Box::new(CodecStream {
inner: native_stream,
codec,
buf: Vec::new(),
})));
}
fn controls(&self) -> Result<Vec<control::Descriptor>> {
self.inner.controls()
}
fn control(&self, id: u32) -> Result<control::State> {
self.inner.control(id)
}
fn set_control(&mut self, id: u32, val: &control::State) -> Result<()> {
self.inner.set_control(id, val)
}
}