#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct EdlEvent {
pub event_num: u32,
pub reel: String,
pub channels: String,
pub transition: String,
pub src_in: String,
pub src_out: String,
pub rec_in: String,
pub rec_out: String,
}
#[derive(Debug, Clone)]
pub struct EdlExport {
pub title: String,
pub fcm: String,
pub events: Vec<EdlEvent>,
}
pub fn frames_to_timecode(frames: u32, fps: u32) -> String {
let fps = fps.max(1);
let f = frames % fps;
let s = (frames / fps) % 60;
let m = (frames / fps / 60) % 60;
let h = frames / fps / 3600;
format!("{:02}:{:02}:{:02}:{:02}", h, m, s, f)
}
pub fn new_edl_export(title: &str, drop_frame: bool) -> EdlExport {
EdlExport {
title: title.to_string(),
fcm: if drop_frame {
"DROP FRAME".to_string()
} else {
"NON-DROP FRAME".to_string()
},
events: Vec::new(),
}
}
#[allow(clippy::too_many_arguments)]
pub fn edl_add_event(
export: &mut EdlExport,
reel: &str,
channels: &str,
transition: &str,
src_in: &str,
src_out: &str,
rec_in: &str,
rec_out: &str,
) {
let event_num = export.events.len() as u32 + 1;
export.events.push(EdlEvent {
event_num,
reel: reel.to_string(),
channels: channels.to_string(),
transition: transition.to_string(),
src_in: src_in.to_string(),
src_out: src_out.to_string(),
rec_in: rec_in.to_string(),
rec_out: rec_out.to_string(),
});
}
pub fn edl_event_count(export: &EdlExport) -> usize {
export.events.len()
}
pub fn edl_to_string(export: &EdlExport) -> String {
let mut out = format!("TITLE: {}\nFCM: {}\n\n", export.title, export.fcm);
for ev in &export.events {
out.push_str(&format!(
"{:03} {} {} {} {} {} {} {}\n",
ev.event_num,
ev.reel,
ev.channels,
ev.transition,
ev.src_in,
ev.src_out,
ev.rec_in,
ev.rec_out,
));
}
out
}
pub fn edl_size_bytes(export: &EdlExport) -> usize {
edl_to_string(export).len()
}
pub fn events_for_reel<'a>(export: &'a EdlExport, reel: &str) -> Vec<&'a EdlEvent> {
export.events.iter().filter(|e| e.reel == reel).collect()
}
pub fn validate_edl(export: &EdlExport) -> bool {
!export.title.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_edl() -> EdlExport {
let mut exp = new_edl_export("MY_EDIT", false);
edl_add_event(
&mut exp,
"A001",
"V",
"C",
"01:00:00:00",
"01:00:04:00",
"01:00:00:00",
"01:00:04:00",
);
edl_add_event(
&mut exp,
"B002",
"V",
"C",
"01:00:04:00",
"01:00:08:00",
"01:00:04:00",
"01:00:08:00",
);
exp
}
#[test]
fn test_event_count() {
assert_eq!(edl_event_count(&sample_edl()), 2);
}
#[test]
fn test_to_string_title() {
assert!(edl_to_string(&sample_edl()).contains("MY_EDIT"));
}
#[test]
fn test_to_string_event() {
assert!(edl_to_string(&sample_edl()).contains("A001"));
}
#[test]
fn test_validate() {
assert!(validate_edl(&sample_edl()));
}
#[test]
fn test_events_for_reel() {
let exp = sample_edl();
assert_eq!(events_for_reel(&exp, "A001").len(), 1);
assert_eq!(events_for_reel(&exp, "B002").len(), 1);
assert_eq!(events_for_reel(&exp, "C003").len(), 0);
}
#[test]
fn test_frames_to_timecode() {
let tc = frames_to_timecode(0, 24);
assert_eq!(tc, "00:00:00:00");
}
#[test]
fn test_frames_to_timecode_24fps() {
let tc = frames_to_timecode(24, 24);
assert_eq!(tc, "00:00:01:00");
}
#[test]
fn test_edl_size_positive() {
assert!(edl_size_bytes(&sample_edl()) > 0);
}
#[test]
fn test_fcm_drop_frame() {
let exp = new_edl_export("X", true);
assert!(exp.fcm.contains("DROP FRAME"));
}
}