Commit Graph
2006 Commits
Author SHA1 Message Date
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 03d4087124 refactor: cut engine-to-UI include violations ahead of the liboakengine split
- slider DisplayType enums sink to node/sliderdisplaytype.h (canonical
  engine home); FloatSlider/RationalSlider alias them for compatibility
- DropWithoutSequenceBehavior enum sinks to common/dropworkflowbehavior.h
- Config errors now go through a registered ErrorHandler hook instead of
  QMessageBox with a MainWindow parent; the style default no longer
  depends on the UI style manager
- MainWindowLayoutInfo moves to node/project/serializer/ and its panel
  dependency is reduced to a plain std::map alias (PanelLayoutInfo),
  breaking the engine -> PanelWidget -> KDDockWidgets chain
- ProjectImportErrorDialog moves from task/ to dialog/projectimport/
- remove confirmed-redundant UI includes and give project.h/import.h/
  project.cpp the direct includes they were borrowing transitively
- project.h includes folder/sequence headers directly (it used both
  types in its own API all along)
2026-07-20 00:52:12 +08:00
Mike-Solar 76f5c2a65b color: input colorspace auto-detection, HDR export tags, LGG/white balance nodes, more LUT formats, waveform parade
- media color primaries/transfer tags now flow from the FFmpeg probe
  through VideoParams into Footage::get_colorspace_to_use(); precedence
  is user override > media tags > project default
- export nclc tags derive from the output colorspace (PQ/HLG/BT.2020,
  P3, sRGB, Rec.601, Rec.709) instead of hardcoded BT.709
- new OCIO Color Grading (Log) node (lift/gamma/gain) and White Balance
  node (kelvin temperature + tint, HDR-safe)
- LUT whitelist extended to 9 OCIO-supported formats
- waveform scope gains an RGB parade mode (GPU and software paths)
- tests updated for the new colorspace precedence
2026-07-19 21:45:51 +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 004e942cf9 fix: remaining issues recorded during test coverage work
- RenderManager: GPU-side members (context_, decoder_cache_,
  shader_cache_, auto_cacher_, worker_pool_, decoder_clear_timer_) were
  left uninitialized when the configured graphics backend is unknown
  (e.g. dummy); ViewerWidget then dereferenced garbage and crashed.
  Initialize them at declaration
- CurveView::SelectKeyframesOfInput ignored its reference parameter and
  selected keyframes of every connected track; select only the
  requested track's keyframes
- SeekableWidget::SeekToScenePoint dereferenced GetViewerNode()
  unconditionally; skip the playhead update when no viewer is connected
- LoadOTIOTask: unknown root schema leaked the freshly allocated
  project_ (delete + reset; OTIO is not enabled in local builds so this
  file is compile-verified by inspection only)

Locked by new tests: RenderManagerDummyBackend,
TimeRuler.SeekToScenePointWithoutViewerIsNoOp,
CurveViewTest.SelectKeyframesOfInputSelectsOnlyRequestedTrack
2026-07-17 17:20:50 +08:00
Mike-Solar b4db6ebc88 fix: define TimeRuler::SetCenteredText (declared but never defined)
Any caller would hit a link error; there were none, so the bug was
latent until the new widget tests called it.
2026-07-17 15:48:03 +08:00
Mike-Solar ecc66e3e2a fix: widget bugs surfaced by new gtest coverage
- FrameRateComboBox: RepopulateList() left current index at -1 on first
  fill, so GetFrameRate() returned 0/1 instead of the displayed first
  entry until something called SetFrameRate()
- HandMovableView: default_drag_mode_ was never initialized; an early
  Core::ToolChanged signal would setDragMode() with it (UB)
2026-07-17 14:13:09 +08:00
Mike-Solar 4a4dcae580 lut: pick from the global LUT library in node params; i18n; doc
- File inputs marked with the 'lut_library' property (currently the
  OCIO LUT node) now show a combo box populated from the global LUT
  library above the path field: pick a library LUT directly, or use
  'Other (Custom File)...' with the regular path field; selections go
  through the standard undoable input-change path
- Refresh zh_CN translations with lupdate and translate all strings
  introduced by the proxy dialog, LUT library, LUT picker, waveform
  sync and footage start time work
- Document the new per-footage custom <proxy> attributes and the
  'manual' source-start-time origin in the project file reference
- Add LutFileField UI tests
2026-07-16 23:49:59 +08:00
Mike-Solar caafac4203 sync: masked waveform correlation, stretch sync, manual start time
- Waveform sync no longer treats uncached waveform regions as silence:
  the envelope extraction now reports a per-window validity mask and the
  correlation skips invalid windows on either side, improving accuracy
  for partially cached clips
- Add stretch/speed sync: AudioWaveformSync::EstimateStretchAndOffset
  searches a playback-rate range plus offset, and a new timeline
  context action 'Synchronize by Waveform (Adjust Speed)' applies the
  estimated rate as a clip speed change (with undo) when plain offset
  alignment is inconclusive
- Footage properties dialog gains a Source Start Time field so the
  value used by source-time sync can be viewed and edited manually
  instead of relying solely on auto-detected metadata; applied via an
  undo command, with Footage::ClearSourceStartTime() for removal
- Regression tests for masked correlation, stretch estimation, the
  envelope validity mask, and source-start-time set/clear
2026-07-16 23:09:12 +08:00
Mike-Solar 547c2480e0 color: global LUT library, LUT error reporting, clamp + display fixes
- Add a global LUT library: user-configurable directories (new
  Preferences > LUT tab) scanned recursively for .cube/.3dl files; LUT
  node file pickers offer the library dirs as sidebar shortcuts via a
  'lut_library' input property handled by the param view bridge
- OCIOLutNode no longer fails silently: missing files, unsupported
  extensions and OCIO load errors are recorded in last_error() and
  surfaced in the status bar (input still passes through for rendering
  safety)
- ColorDialog: re-enable the display -> reference conversion using
  ColorProcessor::kInverse with a validity guard, and re-enable the
  Display tab in ColorValuesWidget; covered by a round-trip regression
  test proving the old OCIO inverse crash no longer occurs
- OCIOGradingTransformLinearNode: enforce the OCIO clampWhite >
  clampBlack invariant per frame in Value() so keyframed/connected
  values cannot produce invalid grading transforms, and constrain the
  white clamp UI minimum whenever the black clamp is static
- Regression tests for LUT extension checks, direction switching, node
  error reporting, LUT library scanning, display inverse round-trip and
  clamp enforcement
2026-07-16 22:53:33 +08:00
Mike-Solar ddca6a5e01 proxy: add dedicated Proxy dialog and preferences fields
- New ProxyDialog (Tools > Proxy Settings..., plus 'Proxy Settings...'
  in the project panel and timeline Proxy submenus) unifying global
  proxy settings, per-footage custom presets, generation and deletion
  in one place instead of three scattered entry points; this also fixes
  the Tools menu action opening the wrong preferences tab
- Preferences Disk tab gains an 'include audio in proxies' checkbox and
  an ffmpeg executable path field (blank = auto-detect)
- Add ProxyDialog smoke tests
2026-07-16 22:53:13 +08:00
Mike-Solar 6aaf37e2e5 proxy: per-footage presets, audio in proxies, configurable ffmpeg path
- Footage can store custom proxy parameters (width/height/crf/preset/
  extension/audio) that override the global settings; they are
  serialized with the project and used by every generation entry point
  via Footage::GetEffectiveProxyParams()
- Proxies now include the source audio streams (AAC) unless disabled;
  the proxy filename records the audio flag and offline audio rendering
  decodes from the proxy when present
- ProxyTask resolves ffmpeg from the new FFmpegPath config key first,
  then PATH, then common install locations (e.g. Homebrew on macOS),
  instead of relying on PATH only; the error message points at the
  preferences when no executable is found
- ProxyTask::BuildArguments() is extracted for testability
- Add ProxyIncludeAudio and FFmpegPath config defaults
- Add regression tests for the filename audio marker, config-backed
  params, ffmpeg resolution, argument building, and custom-param
  persistence
2026-07-16 22:31:37 +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 b4b52abbd4 Remove noisy graph-snapshot logs and add waveform-sync diagnostics
- Strip the dense RenderWorkerPool debug messages about cached/stale graph
  snapshots and cleanup to reduce log spam.
- Add qDebug logging and status-bar feedback to
  TimelineWidget::SynchronizeSelectedClipsByWaveform() so we can see why the
  sync action does nothing (e.g. not enough cached clips or no usable offset).
2026-07-13 18:05:02 +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 e484af9a1b Merge remote-tracking branch 'origin/main' 2026-07-13 17:05:22 +08:00
Mike-Solar e5eeaddf2f format: reformatting files 2026-07-13 15:30:43 +08:00
Mike-Solar 4f23051b2b Fix waveform sync using stale selection and add Ctrl+Shift+W shortcut 2026-07-13 11:09:32 +08:00
Mike-Solar f3389fe6ba Allow waveform sync with partially cached audio and add regression tests 2026-07-13 10:54:12 +08:00
Mike-Solar b47887e127 Defer parameter editor panel raise/focus to queued invocation
KDDockWidgets may need an event-loop iteration to finish opening or
tabifying a dock widget before raise() can switch to it. Defer raise(),
activateWindow(), and setFocus() via QMetaObject::invokeMethod with
Qt::QueuedConnection after show().
2026-07-13 10:19:30 +08:00
Mike-Solar 21ae1125f5 Activate parameter editor panel when jumping from node view
Call setAsCurrentTab() and activateWindow() on the ParamPanel dock widget
in ShowSelectedNodeInParamEditor so the parameter editor becomes the active
tab/window when invoked from the node view context menu or Shift+P shortcut.
2026-07-13 10:19:30 +08:00
Mike-Solar dba76ea9f2 Switch to the correct dock/tab when jumping to parameter editor
In NodeParamView::SetSelectedNodes, after locating the target node item,
expand and raise its containing NodeParamViewContext dock widget so the
active tab/folded section switches to the one that actually holds the node.
2026-07-13 10:19:30 +08:00
Mike-Solar a7fdab607d Fix node context-menu jump to parameter editor and drag-release crash
- Ensure right-clicking a node that isn't currently selected makes it the
  sole selection before showing the context menu, so 'Show in Parameter Editor'
  operates on the clicked node.
- Emit all selected node/context pairs when jumping to the parameter editor.
- Guard dragging_items_ iteration in mouseReleaseEvent against deleted items
  by snapshotting keys as QPointer and skipping null entries.
2026-07-13 10:19:30 +08:00
Mike-Solar 5c8f80480d UI: flatten preferences behavior tabs and add node parameter editor shortcut
- Move Behavior-General options (hover focus, slider ladder, scroll zooms)
  into the General preferences tab.
- Move Behavior-Audio option (audio scrubbing) into the Audio preferences tab.
- Promote remaining Behavior categories (Timeline, Playback, Project, Nodes,
  Rendering) to top-level sidebar entries without the 'Behavior - ' prefix.
- Update Chinese translations for the new sidebar titles and fill unfinished
  Behavior tab strings.

NodeView:
- Remove double-click jump-to-parameter-editor behavior; keep expand/collapse.
- Add right-click context menu item 'Show in Parameter Editor'.
- Add Shift+P shortcut bound to the same action.

Render:
- Fix crash in PreviewAutoCacher::ClearSingleFrameRenders when proxy playback
  causes a render ticket to finish synchronously before the watcher pointer is
  returned. Defer the watcher Finished signal via queued connection so the
  caller can safely register the watcher before it is deleted.
2026-07-13 10:19:30 +08:00
Mike-Solar f57ffa482f Flatten Behavior preferences into sidebar categories and scroll to node on double-click
Behavior preferences used a nested QTreeWidget with groups like General,
Audio, Timeline, etc. Replace it with one tab per group in the left sidebar
so users can jump directly to a category without expanding a secondary menu.

Also wire double-clicking a node in the node graph to emit a selection
signal with its context, causing the parameter panel to scroll to that
node's parameters (in addition to showing/raising the panel as before).
2026-07-13 10:19:30 +08:00
Mike-Solar b3c124fe7a Default viewer display transform to config display/view instead of input colorspace
When no explicit color transform was set, ManagedDisplayWidget fell back to
the project's default input colorspace. For scene-referred reference spaces
like ACEScg / Linear this produced a raw, greenish image on the viewer
instead of a monitor-ready picture. Default to the OCIO config's default
display and view so the viewer looks correct out of the box, while still
honoring any Color Space / Display / View choice the user makes from the
context menu.
2026-07-13 10:19:30 +08:00
Mike-Solar 43599dba9e Add batch proxy menu to Project Explorer and persist Use Proxy state
The Project Explorer previously only had an old Pre-Cache submenu that
required choosing a sequence. Replace it with the same Proxy menu that
the timeline uses:

- Generate Proxy: batch-generates proxies for all selected footage items
  that have an enabled video stream, using ProxyManager and the current
  proxy settings.
- Use Proxy: checkable toggle that enables/disables proxy playback for the
  selected footage.
- Reveal Proxy / Delete Proxy: consistent with the timeline context menu.

Also make Footage::SaveCustom() write the <proxy> element whenever
proxy_enabled_ is true, even if proxy_path_ is empty, and load it back
in LoadCustom(). This preserves the user's Use Proxy preference across
project saves so it is restored on the next open.

Translation files updated with lupdate; zh_CN and zh_TW translations for
the new Project Explorer strings (and the matching timeline strings) are
filled in.
2026-07-13 10:19:30 +08:00
Mike-Solar 8d3bde5a50 Implement software scope rendering for backend-neutral display paths
The Waveform, Vectorscope and Histogram panels were black when running on
the Vulkan / backend-neutral render path because ScopeBase::OnPaint()
returned early with a TODO. The viewer emits GPU textures that live in the
viewer's own renderer; on Vulkan each ManagedDisplayWidget has a separate
device, so those textures cannot be sampled directly.

Fix by:

- Adding a backend-neutral branch in ScopeBase::OnPaint() that downloads the
  reference texture (cross-renderer if needed), color-manages it into a U8
  offscreen texture, downloads it to a QImage, and draws via QPainter.
- Adding a pure virtual DrawScopeSoftware() to ScopeBase and implementing it
  for WaveformScope, VectorscopeScope and HistogramScope.
- Fixing the managed_tex_up_to_date_ flag that was never set to true in the
  OpenGL path, which caused the color-managed scope texture to be recreated
  on every paint.

All gtest suites pass.
2026-07-13 10:19:30 +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 0969e2adc5 Add diagnostics for proxy toggle synchronization
Add temporary qDebug logging to Footage, ProjectCopier,
RenderWorkerPool, and TimelineWidget to trace why Use Proxy cannot be
 toggled and why proxy footage may still be used after disabling.
2026-07-13 10:19:30 +08:00
Mike-Solar cf32fcfee1 Add configurable proxy settings and a menu entry
- Extend ProxyManager::ProxyParams with crf and preset, and update
  ProxyTask/ProxyParamsEqual to use them.
- Add global config keys ProxyWidth, ProxyHeight, ProxyCRF, ProxyPreset.
- Add a Proxy Settings group to Preferences -> Disk with width/height/CRF/preset
  controls.
- Read proxy settings from config when generating proxies from the timeline.
- Add Tools -> Proxy Settings... menu entry that opens Preferences on the Disk tab.
- Add ConfigDialogBase::SetCurrentTab() so PreferencesDialog can start on a
  specific tab.
2026-07-13 10:19:30 +08:00
Mike-Solar 94250a7690 Fix proxy decoding path and add proxy generation diagnostics
- RenderWorkerPool::DecodeInputFrame now uses the proxy filename/decoder/stream
  from FootageJob when a proxy is attached, so generated proxies are actually
  used during render.
- Add qDebug/qWarning logging to TimelineWidget::GenerateProxiesForSelectedClips
  and ProxyTask::Run to diagnose why Generate Proxy appears to do nothing.
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 76a98e5a93 Route viewer through dynamic backend in experimental builds 2026-07-13 10:19:29 +08:00
Mike-Solar 8ae8e3a159 Implement proxy media workflow 2026-07-13 10:19:29 +08:00
Mike-Solar 9c1fba4932 Add timeline audio sync actions 2026-07-13 10:19:29 +08:00
Mike-Solar 08b1c6d562 Implement audio sync foundations 2026-07-13 10:19:29 +08:00
Mike-Solar cac5a40b58 Implement color LUT v0.4 features 2026-06-07 00:24:08 +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