feat(app): proxy editing and audio sync, aligned with the C++ version

Proxy: preview-path proxy substitution (global UseProxyMedia AND
per-footage enabled AND on-disk ready; export always uses originals),
proxy generate/delete/reveal/enable actions, ProxyDialog with global
and per-footage custom params, Tools menu + context-menu Proxy
submenus, progress in the status bar, OVE serialization of proxy
metadata and source_start_time.

Sync: timeline context-menu Synchronize by Source Time / by Waveform /
by Waveform (Adjust Speed) with ctrl-shift-w, cache-envelope
extraction with validity masks, reference/anchor selection and
single multi-undo application (replace-with-gap, speed adjust,
re-place) mirroring timelinewidget.cpp semantics.
This commit is contained in:
2026-08-18 18:58:26 +08:00
parent 2db1615453
commit f2af92958a
17 changed files with 2696 additions and 82 deletions
+35
View File
@@ -41,6 +41,20 @@ pub enum ProxyState {
Failed = 3,
}
impl TryFrom<i32> for ProxyState {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(ProxyState::Missing),
1 => Ok(ProxyState::Generating),
2 => Ok(ProxyState::Ready),
3 => Ok(ProxyState::Failed),
_ => Err(()),
}
}
}
/// `olive::ProxyManager::ProxyParams` — mirror of `oakcodec_proxy_params`.
#[derive(Clone, Debug)]
#[repr(C)]
@@ -166,6 +180,27 @@ impl ProxyManager {
}
}
/// The proxy state a string name stands for (`Missing` for anything
/// unrecognized; also accepts the numeric form the Rust serializer used
/// before the string form landed).
pub fn proxy_state_from_string(name: &str) -> ProxyState {
match name.trim() {
"generating" | "1" => ProxyState::Generating,
"ready" | "2" => ProxyState::Ready,
"failed" | "3" => ProxyState::Failed,
_ => ProxyState::Missing,
}
}
/// Whether a proxy filename was generated with an audio track (the
/// generation tags audio-including proxies `.a1.`).
pub fn proxy_filename_has_audio(proxy_filename: &str) -> bool {
std::path::Path::new(proxy_filename)
.file_name()
.map(|n| n.to_string_lossy().contains(".a1."))
.unwrap_or(false)
}
/// Proxy directory for a project cache path.
pub fn get_proxy_directory(cache_path: &str) -> crate::error::Result<String> {
Ok(Path::new(cache_path)