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
This commit is contained in:
2026-07-31 22:46:52 +08:00
parent 18aed979a2
commit 66d761b4b7
285 changed files with 13261 additions and 5895 deletions
+45 -38
View File
@@ -21,53 +21,57 @@
#ifndef OAKVALUEHELPER_H
#define OAKVALUEHELPER_H
#include <cstring>
#include <QVariant>
#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
#include "node/keyframe.h"
#include "node/value.h"
#include "nodevaluehandle.h"
#include "oakengine/node.h"
#include "olive/core/util/color.h"
#include "olive/core/util/rational.h"
namespace olive {
/**
* @brief Convert a per-track component QVariant into the C ABI oak_node_value POD.
*
* `type` is the declared input data type (e.g. k_float/k_color). For split-track
* types the component is the track-0 scalar (float for k_color's red channel, etc.).
* Returns false for types that have no POD representation.
* `type` uses engine NodeValue::Type ordinals (see the NodeValueType mirror
* in nodevaluehandle.h; an engine NodeValue::Type converts implicitly) and
* is the declared input data type (e.g. k_float/k_color). For split-track
* types the component is the track-0 scalar (float for k_color's red
* channel, etc.). Returns false for types that have no POD representation.
*/
static inline bool QVariantToOakNodeValue(NodeValue::Type type, const QVariant &v,
static inline bool QVariantToOakNodeValue(int type, const QVariant &v,
oak_node_value *out)
{
memset(out, 0, sizeof(*out));
switch (type) {
case NodeValue::k_int:
case NodeValue::k_combo:
out->type = (type == NodeValue::k_combo) ? OAK_NODE_VALUE_COMBO
: OAK_NODE_VALUE_INT;
case NodeValueType::k_int:
case NodeValueType::k_combo:
out->type = (type == NodeValueType::k_combo) ? OAK_NODE_VALUE_COMBO
: OAK_NODE_VALUE_INT;
out->num = v.toLongLong();
return true;
case NodeValue::k_float:
case NodeValueType::k_float:
out->type = OAK_NODE_VALUE_FLOAT;
out->f[0] = v.toDouble();
return true;
case NodeValue::k_boolean:
case NodeValueType::k_boolean:
out->type = OAK_NODE_VALUE_BOOL;
out->num = v.toBool() ? 1 : 0;
return true;
case NodeValue::k_rational:
case NodeValueType::k_rational:
out->type = OAK_NODE_VALUE_RATIONAL;
{
const Rational r = v.value<Rational>();
const core::Rational r = v.value<core::Rational>();
out->num = r.numerator();
out->den = r.denominator();
}
return true;
case NodeValue::k_color:
case NodeValueType::k_color:
out->type = OAK_NODE_VALUE_COLOR;
{
const core::Color c = v.value<core::Color>();
@@ -77,7 +81,7 @@ static inline bool QVariantToOakNodeValue(NodeValue::Type type, const QVariant &
out->f[3] = c.alpha();
}
return true;
case NodeValue::k_vec2:
case NodeValueType::k_vec2:
out->type = OAK_NODE_VALUE_VEC2;
{
const QVector2D vec = v.value<QVector2D>();
@@ -85,7 +89,7 @@ static inline bool QVariantToOakNodeValue(NodeValue::Type type, const QVariant &
out->f[1] = vec.y();
}
return true;
case NodeValue::k_vec3:
case NodeValueType::k_vec3:
out->type = OAK_NODE_VALUE_VEC3;
{
const QVector3D vec = v.value<QVector3D>();
@@ -94,7 +98,7 @@ static inline bool QVariantToOakNodeValue(NodeValue::Type type, const QVariant &
out->f[2] = vec.z();
}
return true;
case NodeValue::k_vec4:
case NodeValueType::k_vec4:
out->type = OAK_NODE_VALUE_VEC4;
{
const QVector4D vec = v.value<QVector4D>();
@@ -116,49 +120,51 @@ static inline bool QVariantToOakNodeValue(NodeValue::Type type, const QVariant &
* single track's component (e.g. one float for a k_color channel). The resulting
* POD has the input's declared type with the component in f[0]/num, exactly what
* the per-track facade commands expect.
*
* `type` uses engine NodeValue::Type ordinals (NodeValueType mirror).
*/
static inline bool NodeTrackComponentToOakNodeValue(NodeValue::Type type,
static inline bool NodeTrackComponentToOakNodeValue(int type,
const QVariant &v,
oak_node_value *out)
{
memset(out, 0, sizeof(*out));
switch (type) {
case NodeValue::k_int:
case NodeValue::k_combo:
out->type = (type == NodeValue::k_combo) ? OAK_NODE_VALUE_COMBO
: OAK_NODE_VALUE_INT;
case NodeValueType::k_int:
case NodeValueType::k_combo:
out->type = (type == NodeValueType::k_combo) ? OAK_NODE_VALUE_COMBO
: OAK_NODE_VALUE_INT;
out->num = v.toLongLong();
return true;
case NodeValue::k_float:
case NodeValue::k_bezier:
case NodeValueType::k_float:
case NodeValueType::k_bezier:
out->type = OAK_NODE_VALUE_FLOAT;
out->f[0] = v.toDouble();
return true;
case NodeValue::k_boolean:
case NodeValueType::k_boolean:
out->type = OAK_NODE_VALUE_BOOL;
out->num = v.toBool() ? 1 : 0;
return true;
case NodeValue::k_rational:
case NodeValueType::k_rational:
out->type = OAK_NODE_VALUE_RATIONAL;
{
const Rational r = v.value<Rational>();
const core::Rational r = v.value<core::Rational>();
out->num = r.numerator();
out->den = r.denominator();
}
return true;
case NodeValue::k_color:
case NodeValueType::k_color:
out->type = OAK_NODE_VALUE_COLOR;
out->f[0] = v.toFloat();
return true;
case NodeValue::k_vec2:
case NodeValueType::k_vec2:
out->type = OAK_NODE_VALUE_VEC2;
out->f[0] = v.toFloat();
return true;
case NodeValue::k_vec3:
case NodeValueType::k_vec3:
out->type = OAK_NODE_VALUE_VEC3;
out->f[0] = v.toFloat();
return true;
case NodeValue::k_vec4:
case NodeValueType::k_vec4:
out->type = OAK_NODE_VALUE_VEC4;
out->f[0] = v.toFloat();
return true;
@@ -185,7 +191,7 @@ static inline QVariant OakNodeValueToQVariant(const oak_node_value &v)
return QVariant::fromValue(v.num != 0);
case OAK_NODE_VALUE_RATIONAL:
return QVariant::fromValue(
Rational(int(v.num), int(v.den)));
core::Rational(int(v.num), int(v.den)));
case OAK_NODE_VALUE_COLOR:
return QVariant::fromValue(core::Color(
float(v.f[0]), float(v.f[1]), float(v.f[2]), float(v.f[3])));
@@ -206,16 +212,17 @@ static inline QVariant OakNodeValueToQVariant(const oak_node_value &v)
}
/**
* @brief Map an engine NodeKeyframe::Type to the facade easing type.
* @brief Map engine NodeKeyframe::Type ordinals (NodeKeyframeType mirror)
* to the facade easing type (0=linear, 1=bezier, 2=hold).
*/
static inline int NodeKeyframeTypeToFacade(NodeKeyframe::Type type)
static inline int NodeKeyframeTypeToFacade(int type)
{
switch (type) {
case NodeKeyframe::k_bezier:
case NodeKeyframeType::k_bezier:
return 1;
case NodeKeyframe::k_hold:
case NodeKeyframeType::k_hold:
return 2;
case NodeKeyframe::k_linear:
case NodeKeyframeType::k_linear:
default:
return 0;
}