Commit Graph
22 Commits
Author SHA1 Message Date
Mike-Solar 012659bf57 export: fix render-ticket classification; export any sequence
Two export killers fixed and the feature surfaced properly:

- TicketArena::allocate() reaps finished fire-and-forget slots on every
  new submit, but RenderTask classified finished tickets by asking the
  arena for their kind/time afterwards - any ticket that completed
  before the next submit (all of them on the inline backend) failed
  with 'Render ticket reported an unexpected timestamp' and the export
  died after writing a header-only file. RenderTask now records each
  ticket's delivery key at submit time instead.
- File > Export becomes 导出序列 (all 8 locales): the dialog offers a
  sequence picker (any sequence in the project, the current one
  preselected) instead of silently exporting the current one, and the
  project bin's sequence context menu gains 导出序列 opening the same
  dialog. Engines expose sequence_entries / current_sequence_id /
  start_export_of.
- The export-project dialog drops its dead hand-typed path field (OK
  already asked the platform save dialog).
- New end-to-end test: a one-second sequence exports to a real
  H.264/AAC MP4 that probes and decodes back to the clip's content.
2026-09-10 16:54:15 +08:00
Mike-Solar 2c64317a58 export media: editable resolution / frame rate / bit rate spin boxes
CI / Build & test (Linux) (push) Canceled after 0s
CI / Build & test (Windows) (push) Canceled after 0s
The three values are SpinBoxes (typed input + stepping): width & height
(0 = use the sequence size), frame rate in fps (0 = sequence rate),
bit rate in bit/s (0 = the codec default). The engine already accepted
arbitrary values, so the dialog now exposes them instead of the closed
preset lists. i18n across the 8 packs.
2026-09-02 09:35:54 +08:00
Mike-Solar 92813707bc export media: dialog UI — container→codec gating, color space/bit depth, range
- ExportDialogContent: container format (existing), then the video and
  audio codec combos rebuilt per container from the compatibility tables
  (an unsupported codec is never offered — switching container
  re-selects the first compatible entry), a color-space combo (SDR
  Rec.709 8-bit / HDR BT.2020 10-bit), an export-range combo (whole
  timeline / in-out) and the output path
- ComboBox::set_options added for the container-driven list rebuild
- settings() gathers the ExportSettings the engine consumes
- begin_export routes through start_export_with
- i18n keys across the 8 packs (zh-CN uses distinct values so the
  en==zh equality test passes)
2026-09-02 09:31:49 +08:00
Mike-Solar 660a32a1b3 project file: new-project dialog (name + sequence format), open prompt lists formats
- 文件 → 新建项目 opens an in-app dialog: project name + the first
  sequence's format (preset / custom / interlaced, reusing
  SequenceFormatFields); OK creates the library project then seeds the
  first sequence from the chosen format
- 打开项目 prompt advertises the supported project formats
  (.ove / .otio / .fcpxml)
- manager.new.project_name across the 8 i18n packs
- action-search first-item test follows the new flow (New Project now
  opens its dialog)
2026-09-02 09:15:30 +08:00
Mike-Solar c900804941 project file: export dialog with OTIO/OVE/FCPXML format choice
文件 → 导出工程文件… now opens an in-app dialog (format dropdown:
OpenTimelineIO / Oak / FCPXML + output path) instead of the bare
platform save prompt; OK routes the chosen extension through the
engine's export_project_path. Adds project.export.format i18n across
the 8 packs.
2026-09-02 09:10:39 +08:00
Mike-Solar 1b0a15192e multicam: wizard + AFV + node-graph preview + performance
CI / Build & test (Linux) (push) Failing after 24s
CI / Build & test (Windows) (push) Failing after 3m38s
- wizard: angle multi-select, sync modes, auto-align, create sequence;
  keeps the host sequence current (host clip = the multicam clip)
- build_multicam_sequence: per-angle clip -> SOURCES_INPUT[element],
  array slot growth, audio angle tracks for AFV
- AFV: host linked audio clip follows the switched source (one undo),
  muted host audio track disables it
- node-graph preview: inline producer renders through the traverser
  (viewer/project-matched graph frames); sequence viewer uses the graph
- multicam node value(): element-tagged row keys (sources_in[i]),
  reads the current source; build_row keys array inputs by element
- angle grid: viewer=0 (single-track montage, not whole-graph)
- project explorer: rename (dialog) + delete (undoable) real items
- performance: decoded-frame LRU, per-process NVDEC quota (1 session,
  evict before open), GPU composite fail-once fallback, snapshot
  upload debounced on the engine tick, worker vram budget headroom
- timeline clip: multicam overlay via ClipDecorator
- wizard menu item moved to Sequence menu
2026-09-01 20:27:59 +08:00
Mike-Solar 5937e557a7 app: project-explorer new-sequence button, 4K presets, keying node fix, color-picker canvases
- Project explorer header gains a 新建序列 button (opens the existing
  new-sequence dialog, seeded like the menu action).
- Sequence presets gain 4K UHD (3840x2160@25) and 4K DCI (4096x2160@24);
  the sequence-properties dialog re-selects them on reopen. Format fields
  are also seedable from a probed footage format (the drop flow).
- Chroma Key (and Color Difference Key) value() now box a ShaderJobPayload
  like Despill: the old OCIO-processor gate pushed nothing (the processor
  is never populated without the render bridge), so the traverser handed
  the clip NodeValue::None and the rendered frame lost the clip. The
  renderer resolves the OCIO stub at compile time from OCIO_SHADER_STUBS.
  End-to-end graph test: green key on a green frame keys out, red key
  keeps it.
- The OFX color picker's SV palette / hue bar / preview / swatch canvases
  get size_full(): the bare canvases collapsed to zero height in the
  block layout, so the palette painted nothing (the reported 色板没显示).
  Regression test clicks the palette center and expects mid s/v.
2026-08-30 21:58:26 +08:00
Mike-Solar fdb5caabd5 color: non-sRGB preview, per-monitor display ICC, pipeline hardening
Preview now follows the project output colorspace end to end: the
display chain derives its content space from the project's OutputColorSpec
instead of a hardcoded sRGB name, self-managed ICC transforms go through
an XYZ D65 interchange stage (OCIO cie_xyz_d65_interchange) for non-sRGB
targets, and the platform layer declares the content colorspace (gpui
submodule bump). macOS defaults to OS-managed (fixes wide-gamut UI
oversaturation); Windows ACM warns once on non-sRGB targets.

Multi-monitor: the display ICC is looked up per the window's current
screen (macOS display id, Windows per-monitor DC, X11 RandR output
profile) with a throttled poll that invalidates frame caches on moves.

Pipeline precision: 10-bit+ sources fall back to YUV444P16LE + a Rust
matrix conversion when swscale lacks F32 output (no more 8-bit
truncation); BT.709/2020 SDR decodes with BT.1886 gamma 2.4 instead of
the sRGB EOTF; working-space compositing no longer clamps RGB to [0,1]
(alpha still clamped); the output node clamps to the target gamut;
frames without colorimetry metadata convert with BT.709 defaults
(warned once) instead of passing through; scopes read the
output-colorspace signal on both F32 paths.

Also: only emit rerun-if-changed for .env when it exists (a missing file
made every build fully dirty).
2026-08-29 00:24:15 +08:00
Mike-Solar 879ff8da5b app: PS-style colour picker and an eyedropper that keeps the popup open
CI / Build & test (Linux) (push) Failing after 9s
CI / Build & test (Windows) (push) Failing after 22s
- the popup now offers a large SV palette with a hue bar plus RGB/HSV
  mode tabs (shared slider model swap, hsv<->rgb pure functions)
- while the eyedropper is armed, clicks outside the popup pick a colour
  instead of dismissing it, so the picked draft can still be confirmed
- regression test pinning the OFX plugin colour set/read/undo chain
- i18n: ofx.color.mode_rgb/mode_hsv in all eight packs
2026-08-27 20:43:27 +08:00
Mike-Solar 5d21f83e1e render/app: display bit depth option (10-bit default, 8-bit optional)
Preferences gains a display-bit-depth combo stored in the config store;
at startup the app forwards it to gpui_wgpu via OAK_DISPLAY_BIT_DEPTH,
which prefers Rgb10a2Unorm for 10-bit presentation. Takes effect after
restart (noted in the dialog); i18n in all eight packs.
2026-08-27 19:08:55 +08:00
Mike-Solar 7422ccd7e9 app: rename the razor tool to Blade with an I-beam cursor
Display name only (identifiers unchanged), in all eight language packs.
2026-08-27 19:08:41 +08:00
Mike-Solar 54945e39af app: pick colors from the program viewer frame (PS-style eyedropper)
Replaces the project-thumbnail picker: the color popup's eyedropper
button arms the program viewer, the next click on the picture samples
that pixel (contain-fit mapped, BGRA from the current CPU frame) into
the picker's draft; Esc or the button cancels. Coordinated through a
global eyedropper mailbox on the engine.
2026-08-27 18:32:34 +08:00
Mike-Solar bad2f9552e app: sequence management -- new-sequence dialog, folders, sequences in the project bin
- File > New > Sequence opens a real dialog (name, PAL/NTSC/HD presets,
  width/height/frame rate, progressive/interlaced); VideoParams gains an
  interlaced flag
- File > New > Folder creates a folder in the project root
- sequences are mounted under the root folder so they appear in the
  project explorer (including the auto-created Sequence 1 and orphans
  from older projects); right-click > Sequence Properties edits the
  parameters afterwards
- dropping footage onto an empty, sequence-less timeline auto-creates a
  sequence from the footage's first video stream
2026-08-27 17:38:30 +08:00
Mike-Solar d65b84a6ca app: live color swatch and a project-media eyedropper in the color picker
- the swatch now follows the draft color while the popup is open
  (cancel still reverts) and set_effect_param failures are logged
  instead of silently reverting the swatch
- the popup lists project footage thumbnails; clicking a pixel picks
  its color into the draft (contain-fit coordinate mapping, no new
  dependencies)
- i18n: ofx.color.pick_project in all eight packs
2026-08-27 17:34:28 +08:00
Mike-Solar 4f6c44a0d0 proxy: hardware-accelerated transcode with configurable, resource-aware concurrency
CI / Build & test (Linux) (push) Successful in 19m14s
CI / Build & test (Windows) (push) Successful in 32m5s
Proxy generation no longer pegs the machine:

- the transcode probes for a hardware H.264 encoder once per process
  and uses it when present (macOS h264_videotoolbox; Windows/Linux
  h264_nvenc -> h264_qsv -> h264_amf; libx264 remains the universal
  fallback and the untouched C++ parity path), with decode-side
  -hwaccel auto (HEVC 4:2:2 10-bit decodes in hardware on Apple
  Silicon / RTX 50+ / Intel GPUs and falls back to software cleanly);
  quality/preset map from the proxy CRF/preset per encoder
- the concurrency limit is configurable (ProxyMaxConcurrent, default
  1) in the Proxy Settings dialog; auto-generated jobs queue and the
  next starts when a slot frees. The invariant
  concurrency x per-job threads <= logical cores / 2 holds by
  construction (thread budget = half the cores / concurrency, clamped
  to [1,8], covered by a unit test), and on Unix ffmpeg runs nice -n 10
  so the background task never starves the foreground
- deleting a footage's proxy also removes it from the auto-generation
  queue
2026-08-26 06:40:06 +08:00
Mike-Solar 186c41b894 app: about dialog, modal close affordances, more preferences
CI / Build & test (Windows) (push) Failing after 16m35s
CI / Build & test (Linux) (push) Successful in 18m59s
- Help > About Oak… opens a real dialog (was a placeholder print): name
  + version, the GPL-3.0 line, the Olive fork notice and the thanks to
  Enzo GD (Community Promoter).
- Modal (gpui_widgets, submodule bump): a title-row close button on
  every dialog and opt-in backdrop dismissal (dismiss_on_mask) — Help >
  Search Actions and About use it, so they close on an outside click
  (previously a buttonless modal could only be closed with Escape).
- Preferences general tab grows two live settings: the cache-ahead
  pre-render window (PlaybackPreRenderFrames, consumed by the preview
  scheduler every playback tick) and the library storage backend
  (Storage/Backend sqlite/pg + Storage/PgUrl connection string, read by
  oak-storage's write-through when a project binds; the pg URL field
  shows only for PostgreSQL and commits on dialog close). The C++
  auto-recovery toggle is skipped on purpose: the Rust snapshot loop
  has no disable semantic, so the switch would be dead.

i18n keys for all eight packs; new tests cover the about modal and the
preferences writes.
2026-08-25 01:55:08 +08:00
Mike-Solar 476114cec0 app: project properties dialog (File > Project Properties…)
The menu item was a placeholder print; it now opens a real dialog (the
C++ ProjectPropertiesDialog):

- Per-project OCIO config override with a 浏览… picker: validated on OK
  (an invalid config keeps the dialog open with the error shown, like
  the C++ accept()), persisted in the project settings, applied to the
  display color pipeline on accept and on project open, and reverted to
  the app default when the project closes. oak-render gains
  set_up_default_config_from for the explicit-path load.
- Disk-cache location (default / alongside the project / custom path):
  persisted through the OVE serializer (cachesetting/customcachepath
  round-trip the settings map, clamped on load) and honored by the
  thumbnail writer — the first live consumer of Project::cache_path.
- PathField gains an enabled state (the custom path field follows the
  combo selection).

The C++ color tab's Default Input Color Space and Reference Space
combos are intentionally absent: the Rust render pipeline has no
consumer for them today (decode performs no input transfer conversion),
so showing them would be dead settings.

Tests: dialog opens, OK applies the cache location, an invalid OCIO
config keeps the dialog open with the error row. i18n keys for all
eight packs.
2026-08-25 00:45:04 +08:00
Mike-Solar a5208b6cae test: replace wall-clock loop deadlines with progress criteria
CI / Build & test (Windows) (push) Failing after 30s
CI / Build & test (Linux) (push) Canceled after 8m31s
Three real-engine throughput loops (thumbnail pipeline, full-res fill
behind the proxy, playback window supply) failed on machine slowness:
their pass/fail was a wall-clock Instant deadline, so a loaded machine
broke them for speed, not for a broken pipeline. Each loop now counts
engine pumps — machine-speed independent — and asserts the condition
within a bounded number of pumps. The two single-frame worker channel
receives keep a generous 60 s recv_timeout (a one-shot bounded
operation, not a throughput loop).

oak-cli: the integration fixtures moved with the app crate during the
workspace restructure; point the fixture helpers at
../oak-app/tests instead of the (now empty) repo-root tests/.
2026-08-22 20:11:43 +08:00
Mike-Solar 4622a1af1e i18n: six new languages; packs become fully data-driven
New complete language packs (431 keys each, key-aligned with en-US):
French, German, Russian, Japanese, Spanish, Portuguese — contributed
via the translation subagent, reviewed for key parity and genuine
translations.

Runtime discovery replaces compiled-in packs: include_str! and the
Language enum are gone; every <code>.yaml found in the searched
directories registers a language, so adding one needs neither a
rebuild nor a code change. Each pack names itself via its
"language.name" key (the endonym), which the pickers display. The
menu bar language submenu is built from the discovered packs (menu ids
in the new LANG_ITEM_BASE range, dispatched before the registry), the
preferences combo enumerates them the same way, and switching goes
through set_language_code. The C++-style LangZh/LangEn registry
actions are removed (menu ids 303/304 stay reserved). pack_dirs gains
the system-install layout <exe>/../share/oak/i18n, and en.yaml is
renamed en-US.yaml so the discovered code matches the fallback code.

Test hardening (a Windows/Linux CI flake chain exposed by this work):
the two language-test mutexes are one shared poison-tolerant mutex;
every test that flips the process language restores en-US before
releasing it; tests that match menus by localized labels take the lock
and pin en-US first.
2026-08-21 15:35:10 +08:00
Mike-Solar eff845a5cd ci: linux xkbcommon-x11, yaml-cpp cstdint patch, hwaccel test skips on VT-less hosts
- Linux: libxkbcommon-x11-dev for the gpui X11 client link
- Windows: patch <cstdint> into the vendored yaml-cpp (a cached cmake
  configure ignores CXXFLAGS; the patch is idempotent and runs after
  cargo fetch)
- macOS: the hw-decode test skips its VideoToolbox engagement
  assertions on hosts where VT cannot initialize (headless/virtualized
  runners) instead of failing
- display color management: the display ICC (system or custom) is
  applied to viewer frames at present time (F32 in place, or in place
  on the BGRA staging copy with the R/B swizzle baked into the OCIO
  chain); preferences get a Color section (mode + custom ICC file); on
  macOS the Metal layer is tagged with the display colorspace when
  self-managing so ColorSync passes pixels through (no double
  correction); frame caches track the transform generation so a mode
  or profile change drops stale pixels
2026-08-21 02:16:39 +08:00
Mike-Solar bf0416c50b feat(i18n): externalize UI strings to YAML language packs
- string tables live in assets/i18n/<lang>.yaml, loaded at runtime
  (user pack dir ~/.oak/i18n, app bundle Resources/i18n, dev checkout)
  with the compiled-in English/Chinese tables as fallback
- new status.proxy.on/off keys; inspector.params copy no longer says
  "placeholder"; effect_library.group.builtin key
- bundle the packs as cargo-bundle resources; dev profile dep opt-level
  dropped to 1 for faster iteration builds
2026-08-20 22:27:57 +08:00
Mike-Solar 063837446d feat(app): link liboakengine.dylib via frozen C ABI; UI fixes
- App no longer depends on the oakengine rlib: build.rs links the
  built liboakengine.dylib (+rpath, -export_dynamic, IOSurface) and
  src/oakui/ffi.rs declares the pure-C surface; RealEngine calls only
  the frozen oakengine_* C ABI
- host_syms.rs provides the oakcore_*/fb_* host symbols the dylib
  imports via dynamic lookup
- Fix Preferences dialog crash (spawn_modal reentrancy) with a
  regression test
- Timeline toolbar and viewer transport render C++-era icons (16px
  grid, dark/light themes) with localized tooltips
- i18n: complete en-US table, add untranslated-key detection test
- New dialogs module (preferences, export, progress)
2026-08-11 00:25:20 +08:00