Files
oak-editor/docs/zh/investigation-edge-display-and-playback.md
Mike-Solar a59c33715f fix: node graph edge display, teardown crashes, and event/audio lifetime bugs
- capi: oakengine_node_output_connection_at/_at_ex returned the source
  node as the connection destination; the actual destination is
  conn.second.node(). Out-edge enumeration was useless, so the node
  view could only draw in-edges and randomly lost whichever edges
  needed the out-edge path (random per context build order).
  Regression test in oakengine_node_test
- project teardown: Project::clear() pre-notifies node removal while
  nodes are fully constructed (observers used to crash on
  half-destroyed nodes); childEvent suppresses the removal dance while
  clearing; Node::disconnect_all/disconnect_edge get a silent mode for
  teardown so no invalidation/events touch dying members
  (is_being_cleared); ClipBlock marker disconnect guarded against
  dead viewer/markers; ProjectCopier and PreviewAutoCacher drop
  project references on Project::destroyed instead of disconnecting
  dead objects at shutdown
- preview: add oakengine_preview_request_get_audio_sample_count; the
  viewer queried sample count by passing nullptr to get_audio_samples
  which rejects it, so all playback audio was silently dropped
- app: fix unterminated input-id memcpy in ResolveGroupInput
  (nodeparamviewitem, widgetbridge) that corrupted every parameter id
- app: unsubscribe raw C-API event subscriptions in destructors of
  NodeParamViewKeyframeControl, NodeParamViewConnectedLabel and
  ExportDialog; playhead events used to fire into dead widgets
  (crash when dragging the playhead)
- tests: preview request roundtrip (video frame + audio range) and
  free-while-active teardown coverage; env-gated OAK_DEBUG_EDGES /
  OAK_DEBUG_INVALID_INPUT diagnostics
- docs: investigation notes in docs/zh/
2026-08-02 14:29:49 +08:00

6.9 KiB
Raw Permalink Blame History

节点图边显示异常 & 播放问题排查进展(2026-08-02)

本文记录当前排查状态,供手工继续排查。随调查更新。

当前未解决的两个现象

A. 节点图边显示随机缺失

  • 每次显示都不一样:有时全部显示,有时缺几条,缺的边每次不同,无规律。
  • 手工重连能连上;切换选中素材(时间线点选)再切回来,又随机缺。
  • 已确认不是只有 footage 相关边受影响,缺的边类型随机。

B. 播放冻结(部分修复后仍有残留报告)

  • 历史症状:播放头不动、无声音、画面不动。
  • 已修复两个确定的根因(见"已修复"清单 8、9),复测中。

已验证的事实(不要再重复验证)

  1. 引擎图是稳定的。用 C ABI 直接加载 ~/Movies/bbb.ove12 条边在 activate project + 多轮 frame request 后全部存活(/tmp/edge2_repro 验证)。 边不显示 ≠ 边被引擎删除。
  2. 项目文件内容正常。bbb.ove 的 12 条连接(见下"图结构")序列化无误, clip 节点只声明了 9 个输入(无 pos_in/tex_in/volume_in——那些警告见第 6 条)。
  3. NodeViewContext 的边创建没有走跳过分支OAK_DEBUG_EDGES=1 运行时, "no item for" 跳过日志一条都没有 → 每条边都调用了 add_edge_internal, 边对象是创建了的。问题在创建之后:被事件删掉、或绘制/几何异常。
  4. 删边路径只有两条child_input_disconnectedNODE_INPUT_DISCONNECTED 事件驱动,nodeviewcontext.cpp:251)和 remove_child(节点移除时递归删边)。
  5. XML/context 解析已排除。C ABI 实测:引擎解析出的 context 成员与 bbb.ove 完全一致(sequence=[sequence,track,track] clip1=[transform,clip1,footage]clip2=[footage,volume,clip2]), 12 条边全部存在。图在引擎里 100% 正确,问题只在 app 的 NodeViewContext 的 item_map_ 里缺节点 item。
  6. 根因已修复(边显示随机缺失)oakengine_node_output_connection_at_exoakengine_node_output_connection_atoutput_connections()conn.first(其实是 source 自身)当成目标节点返回,正确目标是 conn.second.node()。后果:NodeViewContext 的 out-edge 枚举拿到的 "对端"永远是节点自己,item_map_ 查到自己 → from==to 静默丢弃 → out-edge 一条都画不出,只能靠 in-edge 补;哪些边缺取决于节点进入 context 的顺序(成员顺序+时序)→ 表现为随机缺边。已加回归测试 oakengine_node_test.cpp test_edgesat_ex 的目标必须是 LUT 而非 solid)。 同路径受益者:timelinewidget multicam、nodeparamview 的删边逻辑。
  7. 日志里的 Failed to retrieve array size of parameter "pos_in"... in Olive.clip"muted_in" ... in Olive.sequence显示层的错查,调用栈: NodeParamView::update_element_yapp/widget/nodeparamview/nodeparamview.cpp:1174 把每个 item 的输入都拿去对 contexts_.first() 做 group resolve——硬编码 第一个 context,解析错了节点。此 bug 未修,与边显示的关系未确定。
  8. bbb.ove 图结构(12 条边):
    • folder.child_in → footage(33755451136), sequence(33848831232)
    • sequence.tex_in ← track(33796807680)sequence.samples_in ← track(33796810368)
    • sequence.track_in_0/1 ← 两个 track
    • track_v.block_in ← clip(33755511232)track_a.block_in ← clip(33755497792)
    • clip1.buffer_in ← transform(33764063616)transform.tex_in ← footage
    • clip2.buffer_in ← volume(33795740032)volume.samples_in ← footage

已修复的问题(本批,工作区内未全部提交)

# 问题 位置 状态
1 get_distance_between_nodes 无递归出口栈溢出 app/widget/nodeparamview/nodeparamview.cpp 已提交 a4dfc62f0
2 viewerdisplay texture_ 悬垂指针(GL 崩溃) viewerdisplay.{h,cpp} assign_texture 已提交 a4dfc62f0
3 resignal_requests 遍历中改容器 engine/render/playbackcache.h 已提交 a4dfc62f0
4 preview request 释放后 ticket 回调 UAF engine/src/capi/preview.cpp 已提交 a4dfc62f0
5 播放队列帧时间戳全为 0 → 画面不动 preview.h/.cpp + viewer.cpp 已提交 a4dfc62f0
6 浮动"查看器"绑定到序列节点 mainwindow.cpp open_node_in_viewer 已提交 a4dfc62f0
7 Track 析构 UAF + undo remove_track 丢片段 engine/node/output/track/track.{h,cpp} 已提交 30853cbcf
8 音频 sample_count API 缺失(无声音根因之一) preview.h/.cpp 新增 get_audio_sample_count 未提交
9 teardown 系列:~Node 中断边事件打到半死对象 node.cpp silent disconnectproject.cpp is_being_cleared_clip.cpp marker disconnect 空指针;projectcopier/previewautocacher 项目死后野指针 未提交
10 输入 id memcpy 未 NUL 终止(参数名腐坏) nodeparamviewitem.cpp:40、nodeparamviewwidgetbridge.cpp:145 未提交
11 裸事件订阅析构不退订(拖播放头崩溃) nodeparamviewkeyframecontrol、nodeparamviewconnectedlabel、export dialog 各加析构退订 未提交

测试:cd cmake-build-debug && ctest -j4 目前 122/122 通过 (含新增 preview request 端到端回归:单帧+音频请求、teardown 不崩)。

仍在工作区里的调试代码(提交前需清理)

  • OAK_DEBUG_EDGES=1nodeundo.cppAdd/RemoveCommand redo/undo)、 node.cpp disconnect_edge、nodeviewcontext.cppedge added/removed/跳过)。
  • OAK_DEBUG_INVALID_INPUT=1node.cpp report_invalid_input 打调用栈。
  • /tmp 下的复现程序(编译产物在 cmake-build-debug/app/ 下):
    • preview_repro:C ABI 播放请求全流程(单帧+音频+teardown)
    • edge_repro:工厂建节点连边 + autocache churn
    • edge2_repro:加载 bbb.ove 验证 12 条边存活

下一步排查方向(按优先级)

  1. 用最新构建(含 edge added/removed 日志)跑 OAK_DEBUG_EDGES=1, 对照 12 条边在视图里的 add/remove 次数,找幽灵 remove。
  2. 若证实是 load 线程事件与 GUI 建图交错:检查 EngineEventBridge 的 事件入队时序 vs NodeView::set_contexts 的建图时机(重复边/乱序删边)。
  3. update_element_ycontexts_.first() 硬编码(应按 item 所属 context resolve)。
  4. clip 缺少 transform 输入(pos_in 等)导致的参数面板/关键帧视图查询失败 (bbb.ove 里没有这些输入声明,但 app 代码在查)——需确认 Olive 原版 ClipBlock 是否有这些输入,是被 R8 弄丢的还是本来就不该查。
  5. 音频残留:Tried to allocate sample buffer with invalid audio parameters 仍在日志出现(audio processor 输出参数 channels=0 → fix_channel_layout 修正为 2,但上游某处仍用 0 声道创建 buffer)。