use crate::Fraction;
use packbytes::{ByteArray, FromBytes, ToBytes};
use std::io;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Frame<A = Vec<u8>> {
pub header: Header,
pub payload: A,
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PayloadPosition {
pub position: u64,
pub full_length: usize,
pub padding_start: usize,
pub padding_end: usize,
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Header {
Video(Video),
Audio(Audio),
RawInfo(RawInfo),
RawCapture(RawCapture),
WavInfo(WavInfo),
Exposure(Exposure),
Lens(Lens),
ExtendedLens(ExtendedLens),
Rtci(Rtci),
Idnt(Idnt),
Xref(XrefHeader),
Info,
DualIso(DualIso),
Marker(Marker),
Style(Style),
ElectronicLevel(ElectronicLevel),
WhiteBalance(WhiteBalance),
Debug(DebugHeader),
Version,
Dark(Dark),
Unknown([u8; 4]),
}
pub trait MlvHeader {
const MAGIC_BYTES: [u8; 4];
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Video {
pub number: u32,
pub crop_x: u16,
pub crop_y: u16,
pub pan_x: u16,
pub pan_y: u16,
}
impl MlvHeader for Video {
const MAGIC_BYTES: [u8; 4] = *b"VIDF";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Audio {
pub number: u32,
}
impl MlvHeader for Audio {
const MAGIC_BYTES: [u8; 4] = *b"AUDF";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RawInfo {
pub res_x: u16,
pub res_y: u16,
pub api_version: u32,
pub buffer: u32,
pub height: u32,
pub width: u32,
pub pitch: i32,
pub frame_size: u32,
pub bits_per_pixel: u32,
pub black_level: i32,
pub white_level: i32,
pub origin: [i32; 2],
pub size: [i32; 2],
pub dng_active_area: [i32; 4],
pub exposure_bias: [i32; 2],
pub cfa_pattern: i32,
pub calibration_illuminant: i32,
pub color_matrix: [Fraction; 9],
pub dynamic_range: i32,
}
impl MlvHeader for RawInfo {
const MAGIC_BYTES: [u8; 4] = *b"RAWI";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RawCapture {
pub sensor_x: u16,
pub sensor_y: u16,
pub sensor_crop: u16,
pub reserved: u16,
pub binning_x: u8,
pub skipping_x: u8,
pub binning_y: u8,
pub skipping_y: u8,
pub offset_x: i16,
pub offset_y: i16,
}
impl MlvHeader for RawCapture {
const MAGIC_BYTES: [u8; 4] = *b"RAWC";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WavInfo {
pub format: u16,
pub channels: u16,
pub sample_rate: u32,
pub bytes_per_second: u32,
pub block_align: u16,
pub bits_per_sample: u16,
}
impl MlvHeader for WavInfo {
const MAGIC_BYTES: [u8; 4] = *b"WAVI";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Exposure {
pub iso_mode: u32,
pub iso_value: u32,
pub iso_analog: u32,
pub digital_gain: u32,
pub shutter_value: u64,
}
impl MlvHeader for Exposure {
const MAGIC_BYTES: [u8; 4] = *b"EXPO";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Lens {
pub focal_len: u16,
pub focal_dist: u16,
pub aperture: u16,
pub stabilizer_mode: u8,
pub autofocus_mode: u8,
pub flags: u32,
pub lens_id: u32,
pub lens_name: [u8; 32],
pub lens_serial: [u8; 32],
}
impl MlvHeader for Lens {
const MAGIC_BYTES: [u8; 4] = *b"LENS";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ExtendedLens {
pub focal_len_min: u16,
pub focal_len_max: u16,
pub aperture_min: u16,
pub aperture_max: u16,
pub verion: u32,
pub extender_info: u8,
pub capabilities: u8,
pub chipped: u8,
}
impl MlvHeader for ExtendedLens {
const MAGIC_BYTES: [u8; 4] = *b"ELNS";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Rtci {
pub sec: u16,
pub min: u16,
pub hour: u16,
pub mday: u16,
pub mon: u16,
pub year: u16,
pub wday: u16,
pub yday: u16,
pub is_dst: u16,
pub gmtoff: u16,
pub zone: [u8; 8],
}
impl MlvHeader for Rtci {
const MAGIC_BYTES: [u8; 4] = *b"RTCI";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Idnt {
pub camera_name: [u8; 32],
pub camera_model: u32,
pub camera_serial: [u8; 32],
}
impl MlvHeader for Idnt {
const MAGIC_BYTES: [u8; 4] = *b"IDNT";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Xref {
pub filenumber: u16,
pub empty: u8,
pub frame_type: u8,
pub frame_offset: u64,
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct XrefHeader {
pub frame_type: u8,
pub entry_count: u32,
}
impl MlvHeader for XrefHeader {
const MAGIC_BYTES: [u8; 4] = *b"XREF";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Info;
impl MlvHeader for Info {
const MAGIC_BYTES: [u8; 4] = *b"INFO";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DualIso {
pub dual_mode: u32,
pub iso_value: u32,
}
impl MlvHeader for DualIso {
const MAGIC_BYTES: [u8; 4] = *b"DISO";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Marker {
pub mark_type: u32,
}
impl MlvHeader for Marker {
const MAGIC_BYTES: [u8; 4] = *b"MARK";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Style {
pub pic_style_id: u32,
pub contrast: i32,
pub sharpness: i32,
pub saturation: i32,
pub colortone: i32,
pub pic_style_name: [u8; 16],
}
impl MlvHeader for Style {
const MAGIC_BYTES: [u8; 4] = *b"STYL";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ElectronicLevel {
pub roll: u32,
pub pitch: u32,
}
impl MlvHeader for ElectronicLevel {
const MAGIC_BYTES: [u8; 4] = *b"ELVL";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct WhiteBalance {
pub mode: u32,
pub kelvin: u32,
pub gain_r: u32,
pub gain_g: u32,
pub gain_b: u32,
pub gm: u32,
pub ba: u32,
}
impl MlvHeader for WhiteBalance {
const MAGIC_BYTES: [u8; 4] = *b"WBAL";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DebugHeader {
pub info_type: u32,
pub len: u32,
}
impl MlvHeader for DebugHeader {
const MAGIC_BYTES: [u8; 4] = *b"DEBG";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Version;
impl MlvHeader for Version {
const MAGIC_BYTES: [u8; 4] = *b"VERS";
}
#[derive(Clone, Copy, Debug, FromBytes, ToBytes)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Dark {
pub samples_averaged: u32,
pub camera_model: u32,
pub res_x: u16,
pub res_y: u16,
pub raw_width: u32,
pub ram_height: u32,
pub bits_per_pixel: u32,
pub black_level: u32,
pub white_level: u32,
pub fps: Fraction,
pub iso_mode: u32,
pub iso_value: u32,
pub iso_analog: u32,
pub digital_gain: u32,
pub shutter_value: u64,
pub binning_x: u8,
pub skipping_x: u8,
pub binning_y: u8,
pub skipping_y: u8,
}
impl MlvHeader for Dark {
const MAGIC_BYTES: [u8; 4] = *b"DARK";
}
#[inline]
fn read_head<H: FromBytes, R: io::Read>(reader: &mut R, rem: &mut usize) -> io::Result<H> {
let headsize = H::Bytes::SIZE;
if *rem < headsize {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Frame size too small",
));
}
*rem -= headsize;
H::read_packed(reader)
}
impl Frame {
pub fn read<R: io::Read>(reader: &mut R) -> io::Result<(Self, u64)> {
let mut magic = [0; 4];
reader.read_exact(&mut magic)?;
let size = u32::read_packed(reader)? as usize;
if size < 16 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Frame size too small",
));
}
let timestamp = u64::read_packed(reader)?;
let mut rem = size - 16;
let mut payload_size = None;
let header = match magic {
Video::MAGIC_BYTES => {
let header = read_head::<Video, _>(reader, &mut rem)?.into();
let frame_space = u32::read_packed(reader)? as usize;
if (frame_space + 4) > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Video frame space too large",
));
}
let mut throwaway = vec![0; frame_space];
reader.read_exact(&mut throwaway)?;
rem = rem.saturating_sub(frame_space + 4);
header
}
Audio::MAGIC_BYTES => {
let header = read_head::<Audio, _>(reader, &mut rem)?.into();
let frame_space = u32::read_packed(reader)? as usize;
if (frame_space + 4) > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Audio frame space too large",
));
}
let mut throwaway = vec![0; frame_space];
reader.read_exact(&mut throwaway)?;
rem = rem.saturating_sub(frame_space + 4);
header
}
RawInfo::MAGIC_BYTES => read_head::<RawInfo, _>(reader, &mut rem)?.into(),
RawCapture::MAGIC_BYTES => read_head::<RawCapture, _>(reader, &mut rem)?.into(),
WavInfo::MAGIC_BYTES => read_head::<WavInfo, _>(reader, &mut rem)?.into(),
Exposure::MAGIC_BYTES => read_head::<Exposure, _>(reader, &mut rem)?.into(),
Lens::MAGIC_BYTES => read_head::<Lens, _>(reader, &mut rem)?.into(),
ExtendedLens::MAGIC_BYTES => read_head::<ExtendedLens, _>(reader, &mut rem)?.into(),
Rtci::MAGIC_BYTES => read_head::<Rtci, _>(reader, &mut rem)?.into(),
Idnt::MAGIC_BYTES => read_head::<Idnt, _>(reader, &mut rem)?.into(),
XrefHeader::MAGIC_BYTES => read_head::<XrefHeader, _>(reader, &mut rem)?.into(),
Info::MAGIC_BYTES => Header::Info,
DualIso::MAGIC_BYTES => read_head::<DualIso, _>(reader, &mut rem)?.into(),
Marker::MAGIC_BYTES => read_head::<Marker, _>(reader, &mut rem)?.into(),
Style::MAGIC_BYTES => read_head::<Style, _>(reader, &mut rem)?.into(),
ElectronicLevel::MAGIC_BYTES => {
read_head::<ElectronicLevel, _>(reader, &mut rem)?.into()
}
WhiteBalance::MAGIC_BYTES => read_head::<WhiteBalance, _>(reader, &mut rem)?.into(),
DebugHeader::MAGIC_BYTES => {
let header = read_head::<Dark, _>(reader, &mut rem)?.into();
payload_size = Some(u32::read_packed(reader)? as usize);
rem = rem.saturating_sub(4);
header
}
Version::MAGIC_BYTES => {
payload_size = Some(u32::read_packed(reader)? as usize);
rem = rem.saturating_sub(4);
Header::Version
}
Dark::MAGIC_BYTES => read_head::<Dark, _>(reader, &mut rem)?.into(),
_ => Header::Unknown(magic),
};
let payload_size = payload_size.unwrap_or(rem);
if payload_size > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Declared data length too large",
));
}
let mut payload = vec![0; payload_size];
reader.read_exact(&mut payload)?;
if payload_size < rem {
let mut r = rem - payload_size;
let mut buf = [0; 4];
while r > 4 {
reader.read_exact(&mut buf)?;
r -= 4;
}
reader.read_exact(&mut buf[..r])?;
}
Ok((Frame { header, payload }, timestamp))
}
}
impl Frame<PayloadPosition> {
pub fn read_position<R: io::Read + io::Seek>(reader: &mut R) -> io::Result<(Self, u64)> {
let mut magic = [0; 4];
reader.read_exact(&mut magic)?;
let size = u32::read_packed(reader)? as usize;
if size < 16 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Frame size too small",
));
}
let timestamp = u64::read_packed(reader)?;
let mut rem = size - 16;
let mut padding_start = 0;
let mut payload_size = None;
let header = match magic {
Video::MAGIC_BYTES => {
let header = read_head::<Video, _>(reader, &mut rem)?.into();
let frame_space = u32::read_packed(reader)? as usize;
if (frame_space + 4) > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Video frame space too large",
));
}
rem = rem.saturating_sub(4);
padding_start = frame_space;
header
}
Audio::MAGIC_BYTES => {
let header = read_head::<Audio, _>(reader, &mut rem)?.into();
let frame_space = u32::read_packed(reader)? as usize;
if (frame_space + 4) > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Audio frame space too large",
));
}
rem = rem.saturating_sub(4);
padding_start = frame_space;
header
}
RawInfo::MAGIC_BYTES => read_head::<RawInfo, _>(reader, &mut rem)?.into(),
RawCapture::MAGIC_BYTES => read_head::<RawCapture, _>(reader, &mut rem)?.into(),
WavInfo::MAGIC_BYTES => read_head::<WavInfo, _>(reader, &mut rem)?.into(),
Exposure::MAGIC_BYTES => read_head::<Exposure, _>(reader, &mut rem)?.into(),
Lens::MAGIC_BYTES => read_head::<Lens, _>(reader, &mut rem)?.into(),
ExtendedLens::MAGIC_BYTES => read_head::<ExtendedLens, _>(reader, &mut rem)?.into(),
Rtci::MAGIC_BYTES => read_head::<Rtci, _>(reader, &mut rem)?.into(),
Idnt::MAGIC_BYTES => read_head::<Idnt, _>(reader, &mut rem)?.into(),
XrefHeader::MAGIC_BYTES => read_head::<XrefHeader, _>(reader, &mut rem)?.into(),
Info::MAGIC_BYTES => Header::Info,
DualIso::MAGIC_BYTES => read_head::<DualIso, _>(reader, &mut rem)?.into(),
Marker::MAGIC_BYTES => read_head::<Marker, _>(reader, &mut rem)?.into(),
Style::MAGIC_BYTES => read_head::<Style, _>(reader, &mut rem)?.into(),
ElectronicLevel::MAGIC_BYTES => {
read_head::<ElectronicLevel, _>(reader, &mut rem)?.into()
}
WhiteBalance::MAGIC_BYTES => read_head::<WhiteBalance, _>(reader, &mut rem)?.into(),
DebugHeader::MAGIC_BYTES => {
let header = read_head::<Dark, _>(reader, &mut rem)?.into();
payload_size = Some(u32::read_packed(reader)? as usize);
rem = rem.saturating_sub(4);
header
}
Version::MAGIC_BYTES => {
payload_size = Some(u32::read_packed(reader)? as usize);
rem = rem.saturating_sub(4);
Header::Version
}
Dark::MAGIC_BYTES => read_head::<Dark, _>(reader, &mut rem)?.into(),
_ => Header::Unknown(magic),
};
let payload_size = payload_size.unwrap_or(rem);
if payload_size > rem {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"Declared data length too large",
));
}
let padding_end = rem - payload_size;
let full_length = rem;
let position = reader.stream_position()?;
let payload = PayloadPosition {
position,
full_length,
padding_start,
padding_end,
};
Ok((Frame { header, payload }, timestamp))
}
}
#[inline]
fn write_head<H, W>(h: H, writer: &mut W, size: &mut usize, ts: u64) -> io::Result<()>
where
H: MlvHeader + ToBytes,
W: io::Write,
{
let headsize = H::Bytes::SIZE;
*size += headsize;
writer.write_all(&H::MAGIC_BYTES)?;
(*size as u32).write_packed(writer)?;
ts.write_packed(writer)?;
h.write_packed(writer)
}
impl<A: AsRef<[u8]>> Frame<A> {
pub fn write<W: io::Write>(&self, writer: &mut W, timestamp: u64) -> io::Result<()> {
let payload = self.payload.as_ref();
let mut written_size = payload.len() + 16;
let mut padding_len = 0;
match self.header {
Header::Video(h) => {
let headsize = <Video as ToBytes>::Bytes::SIZE;
written_size += headsize;
writer.write_all(&Video::MAGIC_BYTES)?;
(written_size as u32 + 4).write_packed(writer)?;
timestamp.write_packed(writer)?;
h.write_packed(writer)?;
0_u32.write_packed(writer)?
}
Header::Audio(h) => {
let headsize = <Audio as ToBytes>::Bytes::SIZE;
written_size += headsize;
writer.write_all(&Audio::MAGIC_BYTES)?;
(written_size as u32 + 4).write_packed(writer)?;
timestamp.write_packed(writer)?;
h.write_packed(writer)?;
0_u32.write_packed(writer)?
}
Header::RawInfo(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::RawCapture(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::WavInfo(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Exposure(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Lens(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::ExtendedLens(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Rtci(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Idnt(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Xref(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Info => {
writer.write_all(&Info::MAGIC_BYTES)?;
(written_size as u32).write_packed(writer)?;
timestamp.write_packed(writer)?;
}
Header::DualIso(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Marker(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Style(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::ElectronicLevel(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::WhiteBalance(h) => write_head(h, writer, &mut written_size, timestamp)?,
Header::Debug(h) => {
padding_len = (4 - (written_size % 4)) % 4;
written_size += padding_len;
write_head(h, writer, &mut written_size, timestamp)?;
}
Header::Version => {
padding_len = (4 - (written_size % 4)) % 4;
written_size += padding_len;
writer.write_all(&Version::MAGIC_BYTES)?;
(written_size as u32).write_packed(writer)?;
timestamp.write_packed(writer)?;
}
Header::Dark(h) => write_head(h, writer, &mut written_size, timestamp)?,
_ => {
writer.write_all(b"NULL")?;
(written_size as u32).write_packed(writer)?;
timestamp.write_packed(writer)?;
}
};
writer.write_all(payload)?;
writer.write_all(&vec![0; padding_len])
}
}
impl PayloadPosition {
pub const fn length(&self) -> usize {
self.full_length - self.padding_start - self.padding_end
}
pub const fn start(&self) -> u64 {
self.position + self.padding_start as u64
}
}
impl Header {
#[inline]
pub const fn magic_bytes(&self) -> [u8; 4] {
match *self {
Header::Video(_) => Video::MAGIC_BYTES,
Header::Audio(_) => Audio::MAGIC_BYTES,
Header::RawInfo(_) => RawInfo::MAGIC_BYTES,
Header::RawCapture(_) => RawCapture::MAGIC_BYTES,
Header::WavInfo(_) => WavInfo::MAGIC_BYTES,
Header::Exposure(_) => Exposure::MAGIC_BYTES,
Header::Lens(_) => Lens::MAGIC_BYTES,
Header::ExtendedLens(_) => ExtendedLens::MAGIC_BYTES,
Header::Rtci(_) => Rtci::MAGIC_BYTES,
Header::Idnt(_) => Idnt::MAGIC_BYTES,
Header::Xref(_) => XrefHeader::MAGIC_BYTES,
Header::Info => Info::MAGIC_BYTES,
Header::DualIso(_) => DualIso::MAGIC_BYTES,
Header::Marker(_) => Marker::MAGIC_BYTES,
Header::Style(_) => Style::MAGIC_BYTES,
Header::ElectronicLevel(_) => ElectronicLevel::MAGIC_BYTES,
Header::WhiteBalance(_) => WhiteBalance::MAGIC_BYTES,
Header::Debug(_) => DebugHeader::MAGIC_BYTES,
Header::Version => Version::MAGIC_BYTES,
Header::Dark(_) => Dark::MAGIC_BYTES,
Header::Unknown(mb) => mb,
}
}
#[inline]
pub const fn size(&self) -> usize {
match *self {
Header::Video(_) => <Video as ToBytes>::Bytes::SIZE,
Header::Audio(_) => <Audio as ToBytes>::Bytes::SIZE,
Header::RawInfo(_) => <RawInfo as ToBytes>::Bytes::SIZE,
Header::RawCapture(_) => <RawCapture as ToBytes>::Bytes::SIZE,
Header::WavInfo(_) => <WavInfo as ToBytes>::Bytes::SIZE,
Header::Exposure(_) => <Exposure as ToBytes>::Bytes::SIZE,
Header::Lens(_) => <Lens as ToBytes>::Bytes::SIZE,
Header::ExtendedLens(_) => <ExtendedLens as ToBytes>::Bytes::SIZE,
Header::Rtci(_) => <Rtci as ToBytes>::Bytes::SIZE,
Header::Idnt(_) => <Idnt as ToBytes>::Bytes::SIZE,
Header::Xref(_) => <XrefHeader as ToBytes>::Bytes::SIZE,
Header::Info => <Info as ToBytes>::Bytes::SIZE,
Header::DualIso(_) => <DualIso as ToBytes>::Bytes::SIZE,
Header::Marker(_) => <Marker as ToBytes>::Bytes::SIZE,
Header::Style(_) => <Style as ToBytes>::Bytes::SIZE,
Header::ElectronicLevel(_) => <ElectronicLevel as ToBytes>::Bytes::SIZE,
Header::WhiteBalance(_) => <WhiteBalance as ToBytes>::Bytes::SIZE,
Header::Debug(_) => <DebugHeader as ToBytes>::Bytes::SIZE,
Header::Version => <Version as ToBytes>::Bytes::SIZE,
Header::Dark(_) => <Dark as ToBytes>::Bytes::SIZE,
Header::Unknown(_) => 0,
}
}
}
impl Video {
pub const fn from_frame_number(number: u32) -> Self {
Self {
number,
crop_x: 0,
crop_y: 0,
pan_x: 0,
pan_y: 0,
}
}
}
impl From<Video> for Header {
fn from(h: Video) -> Header {
Header::Video(h)
}
}
impl From<Audio> for Header {
fn from(h: Audio) -> Header {
Header::Audio(h)
}
}
impl From<RawInfo> for Header {
fn from(h: RawInfo) -> Header {
Header::RawInfo(h)
}
}
impl From<RawCapture> for Header {
fn from(h: RawCapture) -> Header {
Header::RawCapture(h)
}
}
impl From<WavInfo> for Header {
fn from(h: WavInfo) -> Header {
Header::WavInfo(h)
}
}
impl From<Exposure> for Header {
fn from(h: Exposure) -> Header {
Header::Exposure(h)
}
}
impl From<Lens> for Header {
fn from(h: Lens) -> Header {
Header::Lens(h)
}
}
impl From<ExtendedLens> for Header {
fn from(h: ExtendedLens) -> Header {
Header::ExtendedLens(h)
}
}
impl From<Rtci> for Header {
fn from(h: Rtci) -> Header {
Header::Rtci(h)
}
}
impl From<Idnt> for Header {
fn from(h: Idnt) -> Header {
Header::Idnt(h)
}
}
impl From<XrefHeader> for Header {
fn from(h: XrefHeader) -> Header {
Header::Xref(h)
}
}
impl From<DualIso> for Header {
fn from(h: DualIso) -> Header {
Header::DualIso(h)
}
}
impl From<Marker> for Header {
fn from(h: Marker) -> Header {
Header::Marker(h)
}
}
impl From<Style> for Header {
fn from(h: Style) -> Header {
Header::Style(h)
}
}
impl From<ElectronicLevel> for Header {
fn from(h: ElectronicLevel) -> Header {
Header::ElectronicLevel(h)
}
}
impl From<WhiteBalance> for Header {
fn from(h: WhiteBalance) -> Header {
Header::WhiteBalance(h)
}
}
impl From<DebugHeader> for Header {
fn from(h: DebugHeader) -> Header {
Header::Debug(h)
}
}
impl From<Dark> for Header {
fn from(h: Dark) -> Header {
Header::Dark(h)
}
}