Commit Graph
627 Commits
Author SHA1 Message Date
Mike-Solar 66d761b4b7 R8: finish app/ pure C ABI migration (P3-P9) and make OTIO required
- app/ no longer includes engine C++ headers nor holds engine C++ types:
  engine access goes through the oakengine C ABI plus C++ wrappers
  (oakutil/oaknode.h, oakutil/oakvideo.h) and app-local mirror types
  (tooltypes, trackreferencehandle, timelinecommonapp, keyframetypes,
  subtitleapp, serializedlayoutinfoapp, nodevaluehandle, sliderdisplaytypeapp)
- engine: new C ABI functions for block/track/clip/transition navigation
  and predicates, links, caches, waveform/playback, disk folder,
  sequence_track_list, node_free, footage_is_valid, block_get_track,
  get_brush; loadotio/saveotio ported to the current engine API
- OTIO is now a required dependency: CI and CD build it on every
  platform, FindOpenTimelineIO fixed for OTIO 0.16/0.19 (the old deps
  include requirement silently disabled OTIO everywhere), runtime
  libraries are bundled into packages and copied next to macOS binaries
  (oak_copy_otio_runtime)
- fix ProjectViewModel drag&drop mime read/write size mismatch (segfault)
- unify color label naming (k_olive -> "Oak") in the app-side mirror
- docs: OTIO required, FFmpeg minimum corrected to 6.0 (en/zh)
- gtest suite: 1925 passed, 0 failed
2026-07-31 22:46:52 +08:00
Mike-Solar c0dcd33de0 R8 phase 1: extract app/engine shared utilities into shared/include/oakutil
Move the pure-header utilities shared by app/ and engine/ out of
engine/common/ into a new shared/include/oakutil/ layer (define, lerp,
decibel, digit, range, crashpadutils, autoscroll, qtutils, filefunctions
declarations, and a trimmed xmlutils exposing a CancelAtom-free void*
overload). engine/common/ keeps forwarding headers so internal include
paths are unchanged; app/ now includes oakutil/* directly.

engine/node/project.h gains an explicit NodeGroup forward declaration
previously obtained transitively through the old xmlutils.h.
2026-07-27 17:14:56 +08:00
Mike-Solar 17888a2dc1 change: remove UB in core.h 2026-07-27 08:26:13 +08:00
Mike-Solar a84e75ef47 change: UI and migrate to gtest 2026-07-27 05:27:32 +08:00
Mike-Solar eb634b53ef R7: pure C ABI display boundary + engine visibility closure
R7-A (Qwen 3.8 Max): oakengine/display.h rewritten to the POD contract
from r7-pure-abi-plan.md - oak_video_params everywhere, opaque
texture/frame handles with retain/free protocol (engine-heap control
blocks), OakSharedBuffer refcounted wrapper for the QVariant playback
path. All TexturePtr/FramePtr gone from app (47 sites).

R7-B (Qwen 3.8 Max): liboakengine.so exports 3486 -> 19 C++ symbols
(version script oakengine.ver: oakengine_* plus the documented
oakgl/oakvulkan dlopen plugin ABI). oakengine-obj OBJECT library feeds
both the shared lib and the test binaries (-rdynamic so dlopen'd
backends resolve engine objects).

Fix (Kimi K3): producer/consumer type mismatch - viewerdisplay
unpacks OakSharedBufferPtr but viewer.cpp pushed raw void* handles,
so no frame ever reached the display widget (all 5 vulkan viewer
tests timed out with 'never received a texture'). Producers now wrap
with oak_make_shared_frame / oak_make_shared_texture(retain).

Verified: build 0 errors, ctest 45/45, nm U _ZN5olive = 0 in
oak-editor/oak-render-worker/oak-cli, 19 exported C++ symbols in
liboakengine.so (all documented plugin ABI).
2026-07-27 00:54:46 +08:00
Mike-Solar 0aa5879f35 app: migrate all engine access to the C ABI facade (nm U _ZN5olive = 0)
Every app module now reaches liboakengine exclusively through
oakengine_* C calls, EngineEventBridge subscriptions and app-side
handle headers (cliphandle/keyframehandle/nodevaluehandle/oakvaluehelper).
Direct C++ command construction, engine signal connect()s, and engine
type usage in MOC-visible signatures are gone: 557 -> 0 undefined
olive:: symbols in oak-editor.
2026-07-26 22:43:21 +08:00
Mike-Solar 1384ad1e95 app: migrate the viewer panel to the facade playback engine 2026-07-20 18:55:04 +08:00
Mike-Solar 5109dd2995 refactor: move the ratio input dialog out of engine common/ into dialog/
get_float_ratio_from_user() is pure UI (QInputDialog/QMessageBox);
common/ stays dialog-free.
2026-07-20 01:04:57 +08:00
Mike-Solar a7ddc0f114 audio: master-clock playback timing, output clock compensation, buffer config, interpolated speed
- playback timer uses the audio output device as its master clock: the
  PortAudio callback counts consumed frames (including underrun
  zero-fill) so video cannot drift away from what is heard; wall clock
  remains as fallback when no clocked output is running
- output clock compensates for device output latency; new Preferences >
  Audio buffer size setting (0 = auto)
- SampleBuffer::speed() now uses linear interpolation instead of
  nearest-neighbor sampling
- regression tests: audio-clock driven timer (fwd/rev/speed), wall
  clock fallback, interpolation correctness
2026-07-19 21:44:34 +08:00
Mike-Solar bb40b4923e style: unify identifier naming per updated conventions
Automated with clang-tidy readability-identifier-naming (config added to
.clang-tidy) plus scripted passes, per the updated rules now documented
in CONTRIBUTING.md:

- types (class/struct/enum/alias/template params): PascalCase
- functions, variables, members: snake_case (incl. rational -> Rational)
- private/protected members: trailing underscore; static member
  variables likewise (instance_, available_themes_)
- constants and enum values: snake_case (kLinear -> k_linear,
  F32P -> f32p); ALL_CAPS reserved for macros
- macros: OAK_ prefix (OLIVE_ADD_TEST/OLIVE_ASSERT/OLIVE_CONFIG ->
  OAK_ADD_TEST/OAK_ASSERT/OAK_CONFIG, GL_PREAMBLE -> OAK_GL_PREAMBLE,
  include guards -> OAK_*)
- file names: all lowercase (Current/Plugin/OliveHost/OliveClip/
  OlivePluginInstance -> current/plugin/olivehost/oliveclip/
  oliveplugininstance)
- getters share the member name sans underscore, setters set_foo()
- Qt and third-party (OpenFX) virtual overrides and framework callbacks
  keep their original names (exempt in .clang-tidy)

Manual follow-ups required where automation could not reach:
- string-based QMetaObject/SIGNAL/SLOT references updated to renamed
  methods (AddTask, CreatedFile, DeleteSpecificFile, moveSelectionUp, ...)
- macro bodies referencing renamed methods (OLIVE_CONFIG,
  NODE_DEFAULT_DESTRUCTOR, MANAGEDDISPLAYWIDGET_*)
- self-shadowing locals renamed where signals/methods became same-named
  (size_changed, worker_count, selected_items, import param, filters)
- third_party OFX member/namespace usages restored (OFX::Host::*,
  _created, _clipPrefsDirty, createInstance, clearPersistentMessage)
- STL protocol aliases restored (const_iterator) with .clang-tidy
  ignore rules; qHash overloads restored

Full build and test suite pass: ctest 4/4, ~1960 gtest cases green.
2026-07-19 16:10:54 +08:00
Mike-Solar 6229381426 version: derive from git tag/commit hash; drop audio playback debug logs
Version is no longer hardcoded: at configure time CMake uses the tag
name when HEAD is exactly on a tag (leading "v" stripped), otherwise
the first 8 hex digits of the commit hash. When git is unavailable
(e.g. source tarball) it falls back to the contents of version.txt,
which is now the single place to bump the release version.

Also remove the temporary qDebug() flood in the audio playback path
(ViewerWidget::QueueNextAudioBuffer / ReceivedAudioBufferForPlayback,
AudioManager::PushToOutput).
2026-07-17 21:10:13 +08:00
Mike-Solar 3a3ead6fc0 app: route all FFmpeg access through the ffmpeg_bridge C API
Replace every direct FFmpeg call in the editor and the render worker
with the pure C ffmpeg_bridge API, wrapped in thin C++ adapters that
preserve the original interfaces:

- avframeptr.h: olive::AVFrame adapter around FBFrame handles
- ffmpegutils: format conversion helpers on FB_* constants; the int
  overload is renamed GetCompatibleBridgePixelFormat to avoid a silent
  overload-resolution trap with the PixelFormat enum
- ffmpegdecoder/ffmpegencoder: rewritten as handle-based adapters over
  FBDecoder/FBProbe/FBEncoder/FBScaler/FBResampler
- audioprocessor: FBAudioGraph push/pull adapter
- pluginrenderer/OliveClip: sws/pixdesc usage converted to FBScaler and
  fb_pix_fmt_* queries
- AudioParams/channel layouts are plain uint64_t masks everywhere

Build integration: the root project no longer links FFMPEG directly;
only ffmpeg_bridge does. Binaries resolve the bridge library at runtime
via @loader_path inside the macOS app bundle (copied there post-build)
and via $ORIGIN/../ffmpeg_bridge/bin on Linux; on Windows the DLL is
installed next to the executables, so packages on all three platforms
ship the bridge library.

ffmpeg_bridge gains the extra API the adapters need:
fb_frame_make_writable, fb_decoder_get_format_duration,
fb_resampler_convert_frame, FB_PIX_FMT_YUV440P, SRT validation in
fb_probe_read_subtitle_stream, packed/planar fixes in
fb_encoder_write_audio, and a component-size fix in
fb_pix_fmt_component_size.
2026-07-15 23:00:06 +08:00
Mike-Solar 7cde0b0f1a Fix invalid channel layout (0x0) in audio processor and add playback diagnostics
- Add FixChannelLayout() helper to AudioProcessor::Open() to fall back to a
  default native channel layout when the input/output layout is unspecified,
  custom, or has a zero mask. This prevents FFmpeg's abuffer/aformat filters
  from rejecting 'channel_layouts=0x0' on Linux.
- Log audio processor open parameters, viewer audio queue state, and
  AudioManager::PushToOutput device/stream status to help diagnose silent
  playback on Linux.
2026-07-13 17:46:15 +08:00
Mike-Solar e5eeaddf2f format: reformatting files 2026-07-13 15:30:43 +08:00
Mike-Solar 468b6f1d1b Fix playback backup timer interval and waveform-only prequeue
- The playback backup timer was using timebase_dbl() in seconds as its
  QTimer interval, which truncated to 0 ms for normal frame rates. This
  caused the timer to fire continuously and starve the event loop when
  the video display was hidden, e.g. in Show Waveform Only mode, freezing
  the UI and stopping the playhead. Multiply by 1000 to use milliseconds.
- If PlayInternal has neither video nor audio to prequeue, call
  FinishPlayPreprocess immediately so the backup timer starts and the
  playhead advances even in waveform-only mode with no audio.
2026-07-13 10:19:30 +08:00
Mike-Solar 094f4a8e44 Fix audio waveform view scene rect and timebase refresh
- AudioWaveformView now uses the video frame rate as its timebase
  (falling back to the default sequence frame rate), preventing the
  enormous scene rect that froze the UI when it previously used the
  audio sample rate.
- Call UpdateSceneRect() after changing the waveform timebase so the
  QGraphicsScene bounds are recomputed immediately.
- Refresh the waveform view's viewer/timebase whenever the waveform
  visibility mode changes, ensuring the correct timebase is applied
  even if the node was connected earlier with a different setting.
2026-07-13 10:19:30 +08:00
Mike-Solar 282a06b777 Default to full-resolution preview and fix audio-waveform freeze
- Use a divider of 1 (full resolution) for new sequences and for
  footage-derived viewer parameters instead of the auto-downscaling
  heuristic, so the viewer defaults to full-res preview.
- In AudioWaveformView, base the view timebase on the video frame rate
  when video is present; fall back to the audio sample rate only for
  audio-only sources. Using the audio sample rate as the view timebase
  created an enormous scene rect (time * sample_rate * scale), which
  froze the waveform view and stalled playback updates when showing
  the audio waveform.
2026-07-13 10:19:30 +08:00
Mike-Solar f6211f97a5 Fix render worker reuse and stabilize out-of-process video rendering 2026-07-13 10:19:30 +08:00
Mike-Solar e77de49406 add Comments 2026-07-13 10:19:30 +08:00
Mike-Solar 3c9592da45 完成Vulkan渲染后端 2026-07-13 10:19:30 +08:00
Mike-Solar 225f8505c2 feat(render): dynamic OpenGL/Vulkan backend split and backend-neutral viewer
- Extract libolive-rendercore static library to minimize backend link boundary.
- Add DynamicRenderer adapter with C ABI (oakgl/oakvulkan shared libs).
- Make OAK_ENABLE_DYNAMIC_RENDER_BACKEND default ON with OpenGL fallback.
- Implement VulkanRenderer prototype (textures, shaders, UBO blit, readback).
- Add backend-neutral viewer readback path (offscreen -> QImage -> QPainter).
- Refactor PluginRenderer to be renderer-agnostic; OFX plugins fall back to CPU
  path on non-OpenGL backends while preserving OpenGL render path.
- Add Renderer::AttachOutputTexture/DetachOutputTexture and C ABI forwards.
- Update docs/zh/render-backend-dynamic-plan.md for Phase 3/4/5.
2026-07-13 10:19:29 +08:00
Mike-Solar f731470c0f fix macOS timer bug 2026-06-03 17:49:21 +08:00
孙羽 00f57533e6 Add null checks for color processing functions 2026-05-28 18:21:42 +08:00
Mike-Solar a0abf9cfb0 Fixed: fixed black screen when pulling playhead back. 2026-05-21 16:29:39 +08:00
Mike-Solar 2a84027ff9 fix(renderer): macOS TBDR cross-context sync and OFX instance thread-safety
This commit fixes crashes (SIGSEGV in CImg blur_bilateral) and black-frame
corruption artifacts during playback and scrubbing on macOS Apple Silicon.

Root cause analysis:
1. macOS uses Tile-Based Deferred Rendering (TBDR). glFlush() does not
   guarantee tile memory writeback, causing glReadPixels to read incomplete
   tiles (black/corrupted frames) and cache them to disk.
2. Olive uses multiple shared OpenGL contexts (RenderProcessor contexts vs.
   thread-local PluginRenderer context). glFinish() only waits for the
   current context, not the shared context that produced the texture. CPU
   readback in PluginRenderer could read partially-rendered tiles.
3. OlivePluginInstance and OliveClipInstance are not thread-safe. Concurrent
   RenderProcessors could corrupt internal QMap/images_ and params_ via
   setInputTexture/renderAction races.

Fixes:
- OpenGLRenderer::Flush() on macOS now uses glFinish() unconditionally.
- OpenGLRenderer::DownloadFromTexture() and OpenGLRenderer::Blit() insert
  glFinish() before readback/detach to ensure tile writeback completes.
- PluginRenderer::RenderPlugin() now acquires a per-instance mutex to
  serialize concurrent OFX render calls.
- Before CPU readback in PluginRenderer, flush the renderer that originally
  produced each input texture, ensuring cross-context synchronization.
- RenderProcessor::ProcessVideoFootage() flushes after BlitColorManaged.
- Add black-frame detection in ProcessVideoCacheJob() to auto-purge TBDR-
   corrupted cache files.
- Add diagnostic qDebug() logging in viewer, decoder, renderer, and plugin
  paths to aid future debugging.
2026-05-17 14:54:49 +08:00
Mike-Solar 3845c31b37 perf(plugin): eliminate GPU↔CPU ping-pong in OFX render path
This commit removes redundant readbacks and uploads in the OpenFX
  plugin pipeline, achieving zero-copy rendering for GL-capable
  plugins and reducing CPU path overhead.

  PluginRenderer (OpenGL path):
  - Skip ReadbackTextureToFrame + ConvertFrameIfNeeded + Upload after
    plugin render. The destination texture is already valid on GPU.
  - Pass readback_cpu=false to setInputTexture() so input textures are
    provided via loadTexture() (GL texture IDs) instead of being
    downloaded to CPU Image buffers.
  - Remove duplicate ReadbackTextureToFrame block between
    getClipPreferences and the second setInputTexture call.

  OliveClipInstance:
  - Add optional bool readback_cpu=true to setInputTexture(). When
    false, only params and input_textures_ are updated; CPU readback
    and memcpy into Image are skipped.
  - Add pruneImagesCache() to prevent unbounded growth of images_.
    Input clips are limited to 8 cached frames; output clips are
    left untouched.

  Micro-optimizations:
  - Replace per-row memcpy loops with single block memcpy when
    src/dst strides are contiguous (common case in Olive pipeline).
  - Remove dead GL_PREAMBLE macro definition.

  fix(viewer): resolve playback head lag, frozen frames, and pause delay

  Three playback pipeline behavioral issues are fixed:

  1. Prequeue blocked playhead start:
     Reduce kVideoPlaybackInterval from 0.5s to 0.1s. This lowers
     prequeue length from 15–30 frames to 3–6 frames, so the
     playback timer starts much sooner after pressing Play.

  2. Frozen display during playback:
     Relax the hard frame-drop logic in RendererGeneratedFrameForQueue.
     When the queue has fewer than 2 frames, keep late frames instead
     of dropping them, preventing the viewer from freezing entirely
     when rendering cannot keep up with playback speed.

  3. Delayed frame update after pause:
     Cancel in-flight render tickets in PauseInternal() before
     deleting queue watchers. Previously the render thread continued
     processing stale playback frames, blocking the single-frame
     render requested by UpdateTextureFromNode().
2026-05-16 16:45:13 +08:00
Mike-Solar e85c6cf60a fix: OFX param instance lifecycle and thread-safety fixes
- Fix SIGSEGV in PluginMisc.Keyer by linking Param::SetInstance to instances.
    Olive's custom param instances (IntegerInstance, DoubleInstance, etc.) were
    not passing the SetInstance pointer to the OpenFX HostSupport base class,
    leaving _paramSetInstance as nullptr. When Keyer called paramSetValue during
    createInstanceAction, the suite function dereferenced the null pointer in
    paramChangedByPlugin(). Now newParam() passes 'this' to every constructor.

  - Fix render-thread crash when OFX plugins set params during rendering.
    MinOFX calls paramSetValue inside createInstanceAction from the render
    thread. SubmitUndoCommand() used to push undo commands directly to
    UndoStack, which modifies QAction state (GUI-only). Added IsGuiThread()
    check: non-GUI threads execute redo_now() and discard the command without
    touching the undo stack.

  - Enable PluginMisc.MergeOver and PluginMisc.Keyer integration tests.
    MergeOver now supplies both Source and Bg textures; Keyer uses U16 format.
    Both pass in the full test suite.

  - Make ViewerQueue thread-safe with QMutex around AppendTimewise/PurgeBefore.
    Adds copy ctor and assignment to support mutex-per-instance semantics.
2026-05-14 22:32:34 +08:00
Mike-Solar 43ba1c4642 fix ofx plugin bug 2026-05-14 20:26:17 +08:00
Mike-Solar eb79be87a4 add smoke test 2026-04-12 01:26:41 +08:00
Mike-Solar bfb1b2fce4 update copyright back 2026-01-16 21:22:05 +08:00
Mike-Solar e851653fa3 尝试修复粉紫屏未果 2026-01-16 21:11:24 +08:00
Mike-Solar 8ed5660faf solve some bugs 2026-01-05 18:01:13 +08:00
Mike-Solar b8669f6a11 Change project name; 2026-01-05 16:22:26 +08:00
Mike Solar 22fd521951 Merge branch 'refs/heads/dev' into plugin
# Conflicts:
#	.gitmodules
#	CMakeLists.txt
#	ext/core
2025-12-13 21:45:46 +08:00
Mike-Solar f317e0e173 Add null checks for timebase in TimeScaledObject and fix background color assignment in ViewerDisplayWidget 2025-11-24 10:33:38 +08:00
Mike-Solar 1e33a31b73 Update FFmpeg handling and focus management
Refactor FFmpeg frame processing and improve focus management in panels. Add memory sanitization for debug builds and update KDDockWidgets integration.
2025-11-23 16:35:09 +08:00
Mike Solar 6fdfd03ffd update: update copyright 2025-08-05 17:12:49 +08:00
Mike Solar 74f73ab3be change: change code style to Linux style except indent. 2025-08-03 03:09:40 +08:00
Mike Solar 65ab76edc8 fix: fix exceptions when import video 2025-08-03 02:06:45 +08:00
itsmattkc 4d953adc4b fixed viewer on wayland 2023-05-29 12:31:57 -07:00
itsmattkc 537908c605 footageviewer: auto switch waveform mode when clicking video/audio buttons 2023-03-20 16:51:39 -07:00
itsmattkc e9c97407aa viewer: improve visual appearance of scrubbing 2023-03-20 10:41:47 -07:00
itsmattkc 2c2df99963 name every undo command 2023-03-12 00:49:03 -08:00
itsmattkc 019f095ee4 implement history panel 2023-03-11 22:26:21 -08:00
itsmattkc 82454c09c9 viewer: force valid sample type
Fixes #2183
2023-02-27 18:12:13 -08:00
itsmattkc 8e2db520a7 nodeparamview/viewerdisplay: improve opening text gizmo from NPV 2023-02-22 12:18:43 -08:00
itsmattkc c8908587bb viewertexteditor: ensure page size is synced with transparent clone 2023-02-22 11:39:14 -08:00
itsmattkc fbcc4be4ad viewerdisplay: force update on keyboard and mouse events
For some reason, QTextEdit can be put into states where it no longer emits paint events, which is what we relied on. Now we force repaints for events we expect to change the visuals, e.g. keyboard/mouse events.
2023-02-22 11:33:12 -08:00
itsmattkc feb7d5762d viewer: allow resizing while text gizmo is active 2023-02-22 11:14:40 -08:00
itsmattkc 060c3b0883 viewersizer: use float for all calculations, center manual zoom 2023-02-22 10:41:17 -08:00