mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-13 22:12:12 +00:00
craft-aaf: use referenced slot rates for source offsets
* craft-aaf: use referenced slot rate for source offsets
This commit is contained in:
1 parent
c95885f6d9
commit
3728fd1ffb
4 files changed
+60
-3
No files matched your search
@@ -386,7 +386,6 @@ impl R<'_> {
|
||||
|
||||
fn clip(&mut self, c: &Obj, rate: (i64, i64), kind: CKind, master_key: Option<String>) -> CItem {
|
||||
let len = units_to_ticks(len_of(c), rate.0, rate.1);
|
||||
let start = units_to_ticks(c.i64(pid::START_TIME).unwrap_or(0), rate.0, rate.1);
|
||||
let name = tagged_values(c, pid::COMPONENT_USER_COMMENTS).into_iter().find(|(k, _)| k == "Clip Name").map(|(_, v)| v).unwrap_or_default();
|
||||
let (Some(id), Some(slot)) = (c.mob_id(pid::SOURCE_ID), c.u32(pid::SOURCE_MOB_SLOT_ID)) else { return CItem::Filler(len) };
|
||||
if id == [0; 32] {
|
||||
@@ -395,6 +394,13 @@ impl R<'_> {
|
||||
if let Some(mob) = self.mobs.get(&id).copied().filter(|m| m.class == cls::COMPOSITION_MOB) {
|
||||
return self.nest_clip(c, NestClip { mob, mob_id: id, slot_id: slot, rate, kind, name });
|
||||
}
|
||||
let source_rate = self
|
||||
.mobs
|
||||
.get(&id)
|
||||
.and_then(|mob| mob.objs(pid::SLOTS).iter().find(|s| s.u32(pid::SLOT_ID) == Some(slot)))
|
||||
.and_then(|s| rate_of(s, pid::EDIT_RATE))
|
||||
.unwrap_or(rate);
|
||||
let start = units_to_ticks(c.i64(pid::START_TIME).unwrap_or(0), source_rate.0, source_rate.1);
|
||||
match self.resolve(id, slot, start, kind, master_key, 0) {
|
||||
Some((source, t)) => CItem::Clip(CClip { len, source, start: t, gain: None, name }),
|
||||
None => CItem::Filler(len),
|
||||
@@ -491,9 +497,15 @@ impl R<'_> {
|
||||
if mob.class == cls::MASTER_MOB {
|
||||
let key = master_key.unwrap_or_else(|| hex(&id));
|
||||
let clip = first_clip(seg)?;
|
||||
let inner = units_to_ticks(clip.i64(pid::START_TIME).unwrap_or(0), rate.0, rate.1);
|
||||
let next = clip.mob_id(pid::SOURCE_ID)?;
|
||||
let next_slot = clip.u32(pid::SOURCE_MOB_SLOT_ID)?;
|
||||
let source_rate = self
|
||||
.mobs
|
||||
.get(&next)
|
||||
.and_then(|m| m.objs(pid::SLOTS).iter().find(|s| s.u32(pid::SLOT_ID) == Some(next_slot)))
|
||||
.and_then(|s| rate_of(s, pid::EDIT_RATE))
|
||||
.unwrap_or(rate);
|
||||
let inner = units_to_ticks(clip.i64(pid::START_TIME).unwrap_or(0), source_rate.0, source_rate.1);
|
||||
if next == [0; 32] {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -473,6 +473,27 @@ fn audio_tracks_keep_their_names() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sound_source_offsets_use_audio_sample_rate_on_disk() {
|
||||
let doc = crate::testdoc::sound_only(None);
|
||||
let bytes = written(&doc, false);
|
||||
let root = store::read(&bytes).unwrap();
|
||||
let mut all = Vec::new();
|
||||
walk(&root, &mut all);
|
||||
let starts: Vec<i64> = all.iter().filter(|o| o.class == cls::SOURCE_CLIP).filter_map(|o| o.i64(pid::START_TIME)).collect();
|
||||
assert!(starts.contains(&19_200), "expected 0.4 seconds at 48 kHz: {starts:?}");
|
||||
let back = read_clean(&bytes);
|
||||
let clip = back.compositions[0].tracks[0]
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|i| match i {
|
||||
CItem::Clip(c) => Some(c),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(clip.start, craft_timeline::time::FrameRate::FPS_25.tick_of(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flattened_selectors_and_nested_scopes_are_reported() {
|
||||
for (class, property, message) in
|
||||
|
||||
@@ -360,7 +360,7 @@ pub(crate) fn write(doc: &Document, version: craft_cfb::Version, identity: &Iden
|
||||
|
||||
// ---- nested compositions: a clip refers to one as it does to a master mob, through the
|
||||
// composition's first track of the clip's kind (a broken-out channel: that channel's track)
|
||||
let mut refs = Refs { mobs: master_ref, rates: HashMap::new() };
|
||||
let mut refs = Refs { mobs: master_ref, rates: doc.sources.iter().enumerate().map(|(i, s)| (i, source_rate(s))).collect() };
|
||||
let nested_ids: Vec<[u8; 32]> = doc.nested.iter().map(|_| ids.next()).collect();
|
||||
for (si, s) in doc.sources.iter().enumerate() {
|
||||
let Some((comp, id)) = s.nested.and_then(|n| Some((doc.nested.get(n)?, nested_ids.get(n)?))) else { continue };
|
||||
|
||||
@@ -217,3 +217,27 @@ fn a_composition_nested_in_itself_is_a_gap() {
|
||||
assert_eq!(back.nested.len(), 1);
|
||||
assert!(matches!(back.nested[0].tracks[0].items[..], [CItem::Filler(_)]), "{:?}", back.nested[0].tracks[0].items);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn aaf_source_start_uses_referenced_slot_rate() {
|
||||
let doc = sound_only(None);
|
||||
let bytes = aaf_bytes(&doc, false);
|
||||
let back = read_clean(&bytes, true);
|
||||
let original = doc.compositions[0].tracks[0]
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| match item {
|
||||
CItem::Clip(c) => Some(c.start),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
let actual = back.compositions[0].tracks[0]
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| match item {
|
||||
CItem::Clip(c) => Some(c.start),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(actual, original);
|
||||
}
|
||||
Reference in new issue
Block a user