otio: write importable OTIO/FCPXML (DaVinci Resolve rejects both)
CI / Build & test (Linux) (push) Successful in 23m59s
CI / Build & test (Windows) (push) Successful in 31m18s

- available_range declared a zero duration for every clip (the media
  was 'unusable', so Resolve invalidated all of them): it now covers
  the whole media - video clips in the probed frame rate, audio clips
  in the probed sample rate (no more hardcoded 48000/0).
- Gap ranges mixed time bases (a 24 fps block start, a 1.0 trailing
  duration): gaps now stay in the sequence's time base, the trailing
  pad in whole frames.
- Empty sequences (no clips) are skipped, so a lone edited sequence
  exports as a bare Timeline root instead of a SerializableCollection
  Resolve cannot read.
- FCPXML: an asset used on both video and audio tracks now declares
  hasVideo AND hasAudio (the first registration's track kind used to
  hide the other stream); asset durations recover with available_range.
This commit is contained in:
2026-09-10 16:55:12 +08:00
parent 71e41d2d82
commit 280118a342
4 changed files with 387 additions and 22 deletions
+13
View File
@@ -472,6 +472,19 @@ pub fn footage_video_params(
f.video_params(index).map(common_from_node_video)
}
/// The footage's first audio stream's sample rate (`oaknode_footage_get_
/// audio_params`), `None` when unprobed or the file has no audio stream.
pub fn footage_audio_sample_rate(project: &ProjectRef, footage: NodeId) -> Option<i32> {
let guard = lock_project(project);
let f = guard
.graph
.get(footage)?
.behavior
.as_any()?
.downcast_ref::<FootageBehavior>()?;
f.audio_params(0).map(|a| a.sample_rate)
}
/// Overwrite (or create) the footage's `index`th video stream parameters
/// (`oaknode_footage_set_video_params`).
pub fn footage_set_video_params(