#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MxfOpPattern {
Op1a,
Op1b,
OpAtom,
}
impl MxfOpPattern {
pub fn name(&self) -> &'static str {
match self {
MxfOpPattern::Op1a => "OP1a",
MxfOpPattern::Op1b => "OP1b",
MxfOpPattern::OpAtom => "OPAtom",
}
}
}
#[derive(Debug, Clone)]
pub struct MxfTrack {
pub track_id: u32,
pub essence_type: String,
pub duration_frames: u32,
pub sample_rate: (u32, u32),
}
#[derive(Debug, Clone)]
pub struct MxfExport {
pub op_pattern: MxfOpPattern,
pub tracks: Vec<MxfTrack>,
pub package_name: String,
}
pub fn new_mxf_export(package_name: &str, op: MxfOpPattern) -> MxfExport {
MxfExport {
op_pattern: op,
tracks: Vec::new(),
package_name: package_name.to_string(),
}
}
pub fn mxf_add_track(
export: &mut MxfExport,
track_id: u32,
essence_type: &str,
duration: u32,
rate_num: u32,
rate_den: u32,
) {
export.tracks.push(MxfTrack {
track_id,
essence_type: essence_type.to_string(),
duration_frames: duration,
sample_rate: (rate_num, rate_den),
});
}
pub fn mxf_track_count(export: &MxfExport) -> usize {
export.tracks.len()
}
pub fn mxf_duration_frames(export: &MxfExport) -> u32 {
export
.tracks
.iter()
.map(|t| t.duration_frames)
.max()
.unwrap_or(0)
}
pub fn validate_mxf(export: &MxfExport) -> bool {
!export.package_name.is_empty() && export.tracks.iter().all(|t| t.sample_rate.1 > 0)
}
pub fn mxf_header_bytes(export: &MxfExport) -> Vec<u8> {
let mut out = Vec::new();
out.extend_from_slice(&[0x06, 0x0e, 0x2b, 0x34, 0x02, 0x05, 0x01, 0x01]);
out.extend_from_slice(&(export.tracks.len() as u32).to_le_bytes());
out
}
pub fn mxf_size_estimate(export: &MxfExport) -> usize {
512 + export
.tracks
.iter()
.map(|t| t.duration_frames as usize * 64)
.sum::<usize>()
}
pub fn mxf_find_track_by_type<'a>(export: &'a MxfExport, etype: &str) -> Option<&'a MxfTrack> {
export.tracks.iter().find(|t| t.essence_type == etype)
}
pub fn mxf_op_name(export: &MxfExport) -> &'static str {
export.op_pattern.name()
}
#[cfg(test)]
mod tests {
use super::*;
fn sample() -> MxfExport {
let mut exp = new_mxf_export("MyPackage", MxfOpPattern::Op1a);
mxf_add_track(&mut exp, 1, "JPEG2000", 100, 24, 1);
mxf_add_track(&mut exp, 2, "PCM", 2400, 48000, 1);
exp
}
#[test]
fn test_track_count() {
assert_eq!(mxf_track_count(&sample()), 2);
}
#[test]
fn test_duration() {
assert_eq!(mxf_duration_frames(&sample()), 2400);
}
#[test]
fn test_validate() {
assert!(validate_mxf(&sample()));
}
#[test]
fn test_header_bytes() {
let exp = sample();
let hdr = mxf_header_bytes(&exp);
assert_eq!(&hdr[0..4], &[0x06, 0x0e, 0x2b, 0x34]);
}
#[test]
fn test_size_estimate() {
assert!(mxf_size_estimate(&sample()) > 512);
}
#[test]
fn test_find_by_type() {
let exp = sample();
assert!(mxf_find_track_by_type(&exp, "JPEG2000").is_some());
assert!(mxf_find_track_by_type(&exp, "H264").is_none());
}
#[test]
fn test_op_name() {
let exp = sample();
assert_eq!(mxf_op_name(&exp), "OP1a");
}
#[test]
fn test_op_pattern_names() {
assert_eq!(MxfOpPattern::Op1b.name(), "OP1b");
assert_eq!(MxfOpPattern::OpAtom.name(), "OPAtom");
}
#[test]
fn test_empty_duration() {
let exp = new_mxf_export("empty", MxfOpPattern::OpAtom);
assert_eq!(mxf_duration_frames(&exp), 0);
}
}