refactor: workspace layout — crates/, app at root, legacy C++ removed

Single mechanical restructure commit:
- root Cargo.toml = oakapp bin + workspace; one cargo build produces
  oakapp, oak-cli, oak-worker, liboakengine.dylib
- app/rust/src -> src/ (app at repo root, no rust/ nesting)
- src/<mod>/rust -> crates/oak<mod>; src/oakcore-rs -> crates/oakcore;
  src/bindings/oakotio -> crates/oakotio; src/engine/rust ->
  crates/oakengine (keeps cdylib+staticlib+rlib)
- public C headers include/<mod>/ -> crates/oakengine/include/<mod>/
- OFX SDK headers vendored into crates/oakplugin/ofx/ (HostSupport gone)
- legacy deleted: old src/ C++ modules, engine/, core/, ffmpeg_bridge/,
  app/ (Qt), cli/worker C++, root CMakeLists, third_party/KDDockWidgets
  submodule, otio-install, all build-* output (~40GB)
- oakstorage kept but excluded from the workspace (skeleton w/ todos);
  gpui excluded (own workspace)
- verified: cargo build green, cargo test --workspace 1845/0
  (with the documented OCIO_RS_* env override for the homebrew OCIO)
This commit is contained in:
2026-08-10 20:24:25 +08:00
parent f8540e3892
commit 013a175707
4212 changed files with 8331 additions and 2274987 deletions
+150
View File
@@ -0,0 +1,150 @@
// Oak Video Editor - Non-Linear Video Editor
// Copyright (C) 2026 Oak Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! Sequence: the C++ `ViewerOutput`/`Sequence` pair — a node that owns
//! tracks, markers, work area, and playback caches.
//! `// CPP-PARITY: src/node/src/output/viewer/viewer.{h,cpp}`,
//! `// CPP-PARITY: src/node/src/project/sequence/sequence.{h,cpp}`.
use crate::id::NodeId;
use crate::node::{Category, NodeBehavior, NodeCore};
use crate::value::{AudioParams, VideoParams};
/// Sequence texture/samples input ids (ViewerOutput::k_texture_input /
/// k_samples_input) and the track input id format (Sequence::
/// k_track_input_format).
pub const TEXTURE_INPUT: &str = "tex_in";
pub const SAMPLES_INPUT: &str = "samples_in";
pub const TRACK_INPUT_FORMAT: &str = "track_in_%1";
/// Sequence behavior (viewer node).
pub struct SequenceBehavior {
/// Track list node ids (video then audio, C++ order).
pub track_lists: Vec<NodeId>,
/// Timeline markers handle (oaktimeline, owned).
pub markers: crate::handle::CHandle,
/// Work area handle (oaktimeline, owned).
pub workarea: crate::handle::CHandle,
/// Length cache (C++ last_length_).
pub last_length: oakcore_rs::Rational,
/// Autocache toggles.
pub autocache_video: bool,
/// Audio autocache toggle.
pub autocache_audio: bool,
/// Playhead position (C++ ViewerOutput::playhead_).
pub playhead: oakcore_rs::Rational,
/// Video parameter streams.
pub video_params: Vec<VideoParams>,
/// Audio parameter streams.
pub audio_params: Vec<AudioParams>,
}
impl SequenceBehavior {
/// Empty sequence with zero tracks and no parameters.
pub fn new() -> Self {
SequenceBehavior {
track_lists: Vec::new(),
markers: crate::handle::CHandle::null(),
workarea: crate::handle::CHandle::null(),
last_length: oakcore_rs::Rational::new(0, 1),
autocache_video: false,
autocache_audio: false,
playhead: oakcore_rs::Rational::new(0, 1),
video_params: Vec::new(),
audio_params: Vec::new(),
}
}
/// Apply the default video/audio parameters (C++
/// `ViewerOutput::set_default_parameters()`; the config lookups use
/// oakcommon's defaults when the config module is absent).
pub fn set_default_parameters(&mut self) {
let width = crate::bridge::common::config_get_int("DefaultSequenceWidth", "", 1920)
.unwrap_or(1920);
let height = crate::bridge::common::config_get_int("DefaultSequenceHeight", "", 1080)
.unwrap_or(1080);
let sample_rate =
crate::bridge::common::config_get_int("DefaultSequenceAudioFrequency", "", 48000)
.unwrap_or(48000);
let fps_num = crate::bridge::common::config_get_int("DefaultSequenceFrameRateNum", "", 30)
.unwrap_or(30);
let fps_den = crate::bridge::common::config_get_int("DefaultSequenceFrameRateDen", "", 1)
.unwrap_or(1);
self.video_params = vec![VideoParams {
width,
height,
frame_rate: oakcore_rs::Rational::new(fps_num as i64, fps_den as i64),
pixel_format: 4, // f32
channels: 4,
}];
self.audio_params = vec![AudioParams {
sample_rate,
channel_layout: 0x3, // stereo
format: 4, // f32
}];
}
/// Recompute the cached lengths from the track lists (C++
/// `ViewerOutput::verify_length()`).
pub fn verify_length(&mut self, lengths: (oakcore_rs::Rational, oakcore_rs::Rational, oakcore_rs::Rational)) {
let (video, audio, overall) = lengths;
self.last_length = overall;
let _ = (video, audio);
}
/// Total stream counts.
pub fn video_stream_count(&self) -> usize {
self.video_params.len()
}
/// Audio stream count.
pub fn audio_stream_count(&self) -> usize {
self.audio_params.len()
}
}
impl NodeBehavior for SequenceBehavior {
fn name(&self) -> &str {
"Sequence"
}
fn type_id(&self) -> &str {
"org.olivevideoeditor.Olive.sequence"
}
fn categories(&self) -> &[Category] {
&[Category::Output]
}
fn duplicate(&self, _core: &NodeCore) -> Option<Box<dyn NodeBehavior>> {
Some(Box::new(SequenceBehavior::new()))
}
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
fn as_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
Some(self)
}
}
impl Default for SequenceBehavior {
fn default() -> Self {
SequenceBehavior::new()
}
}