refactor(node): switch oaknode to refcounted value handles, migrate consumers

- all 15 OakNode* handle types become neutral by-value structs
  {ctx, addref, release, abi_version}; shared box in
  src/node/c_api/nodehandle.h with owns flag (borrowed accessors
  return non-owning boxes; graph insertion flips owns off)
- oaktimeline/oaktask/oakrender call sites and their own public
  headers migrated to value handles; identity comparisons in
  timeline/task now compare native pointers
- regressions green: oaknode 96, oaktimeline 117, oaktask 106,
  oakrender 44, oakcommon 193, oakcodec 18, oakaudio 36
This commit is contained in:
2026-08-07 17:20:42 +08:00
parent 295ea1bfe5
commit 67176281d9
87 changed files with 4499 additions and 3431 deletions
+54 -38
View File
@@ -35,10 +35,10 @@ extern "C" {
* @file keyframe.h
* @brief C ABI for olive::NodeKeyframe (src/node/src/keyframe.h).
*
* An OakNodeKeyframe is a reinterpreted olive::NodeKeyframe. Handles
* created by oaknode_keyframe_create() are owned and must be released
* with oaknode_keyframe_free(); keyframes attached to a node input's
* track are owned by the node.
* An OakNodeKeyframe wraps an olive::NodeKeyframe. Handles created by
* oaknode_keyframe_create() are owned and must be released with
* oaknode_keyframe_free(); keyframes attached to a node input's track
* are owned by the node.
*
* Every setter comes in a live variant and an undoable variant (suffix
* _undoable) returning an owned, un-executed OakUndoCommand.
@@ -63,9 +63,20 @@ typedef enum oaknode_keyframe_bezier {
} oaknode_keyframe_bezier;
/**
* @brief Opaque keyframe handle (olive::NodeKeyframe).
* @brief Reference-counted handle to a keyframe (olive::NodeKeyframe).
*
* The object never leaves the library that created it; every external
* reference is one of these handles. Semantics are shared_ptr-like:
* oaknode_keyframe_create() returns a handle with count 1, addref(ctx)
* takes another reference, release(ctx) drops one and the library
* destroys the object when the count reaches zero.
*/
typedef struct OakNodeKeyframe OakNodeKeyframe;
typedef struct OakNodeKeyframe {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKNODE_ABI_VERSION. */
} OakNodeKeyframe;
/**
* @brief Create a standalone keyframe (owned; release with
@@ -73,20 +84,24 @@ typedef struct OakNodeKeyframe OakNodeKeyframe;
*
* `value` may be NULL (null variant); OAKNODE_VALUE_STRING is rejected
* (use oaknode_keyframe_set_value_string() after creation). `type` is an
* oaknode_keyframe_type. `parent_or_null` may be NULL.
* oaknode_keyframe_type. `parent_or_null` may be an empty handle.
*
* @return Keyframe handle, or NULL on invalid argument or allocation
* failure.
* @return Keyframe handle with count 1; ctx is NULL on invalid argument
* or allocation failure.
*/
OakNodeKeyframe *oaknode_keyframe_create(int64_t time_num, int64_t time_den,
const oaknode_value *value, int type,
int track, int element,
const char *input_id,
OakNodeNode *parent_or_null);
OakNodeKeyframe oaknode_keyframe_create(int64_t time_num, int64_t time_den,
const oaknode_value *value, int type,
int track, int element,
const char *input_id,
OakNodeNode parent_or_null);
/**
* @brief Destroy an OWNED keyframe. NULL is a no-op. Never free a
* keyframe that is attached to a node's track.
* @brief Release one reference to a keyframe handle.
*
* Convenience wrapper around handle.release(handle.ctx): destroys the
* keyframe when the count reaches zero and the handle owns it. NULL
* handle or NULL ctx is a no-op; clears `keyframe->ctx` after releasing.
* Never free a keyframe that is attached to a node's track.
*/
void oaknode_keyframe_free(OakNodeKeyframe *keyframe);
@@ -95,19 +110,19 @@ void oaknode_keyframe_free(OakNodeKeyframe *keyframe);
*
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
*/
int oaknode_keyframe_get_time(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_time(OakNodeKeyframe keyframe,
int64_t *out_num, int64_t *out_den);
/**
* @brief Set the keyframe's time directly (live).
*/
int oaknode_keyframe_set_time(OakNodeKeyframe *keyframe, int64_t time_num,
int oaknode_keyframe_set_time(OakNodeKeyframe keyframe, int64_t time_num,
int64_t time_den);
/**
* @brief Create a set-time command (olive::NodeParamSetKeyframeTimeCommand).
*/
int oaknode_keyframe_set_time_undoable(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_time_undoable(OakNodeKeyframe keyframe,
int64_t time_num, int64_t time_den,
OakUndoCommand *out_command);
@@ -115,7 +130,7 @@ int oaknode_keyframe_set_time_undoable(OakNodeKeyframe *keyframe,
* @brief Read the keyframe's value mapped into `out`. Values without a
* POD representation fail with OAKNODE_E_FAILED.
*/
int oaknode_keyframe_get_value(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_value(OakNodeKeyframe keyframe,
oaknode_value *out);
/**
@@ -123,14 +138,14 @@ int oaknode_keyframe_get_value(const OakNodeKeyframe *keyframe,
* OAKNODE_VALUE_STRING is rejected (use
* oaknode_keyframe_set_value_string()).
*/
int oaknode_keyframe_set_value(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value(OakNodeKeyframe keyframe,
const oaknode_value *v);
/**
* @brief Create a set-value command
* (olive::NodeParamSetKeyframeValueCommand).
*/
int oaknode_keyframe_set_value_undoable(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value_undoable(OakNodeKeyframe keyframe,
const oaknode_value *v,
OakUndoCommand *out_command);
@@ -140,84 +155,85 @@ int oaknode_keyframe_set_value_undoable(OakNodeKeyframe *keyframe,
* @return Required buffer size in bytes including the terminating NUL
* (non-negative), or a negative OAKNODE_E_* error code.
*/
int oaknode_keyframe_get_value_string(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_value_string(OakNodeKeyframe keyframe,
char *buf, int buf_size);
/**
* @brief Set a string value directly (live).
*/
int oaknode_keyframe_set_value_string(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value_string(OakNodeKeyframe keyframe,
const char *value);
/**
* @brief Create a set-string-value command.
*/
int oaknode_keyframe_set_value_string_undoable(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_value_string_undoable(OakNodeKeyframe keyframe,
const char *value,
OakUndoCommand *out_command);
/**
* @brief The keyframe's interpolation type (oaknode_keyframe_type).
*/
int oaknode_keyframe_get_type(const OakNodeKeyframe *keyframe, int *out_type);
int oaknode_keyframe_get_type(OakNodeKeyframe keyframe, int *out_type);
/**
* @brief Set the interpolation type directly (live,
* NodeKeyframe::set_type(), which adjusts neighbouring bezier handles).
*/
int oaknode_keyframe_set_type(OakNodeKeyframe *keyframe, int type);
int oaknode_keyframe_set_type(OakNodeKeyframe keyframe, int type);
/**
* @brief Create a set-type command (same semantics as the live variant).
*/
int oaknode_keyframe_set_type_undoable(OakNodeKeyframe *keyframe, int type,
int oaknode_keyframe_set_type_undoable(OakNodeKeyframe keyframe, int type,
OakUndoCommand *out_command);
/**
* @brief A bezier control point (`handle` is an
* oaknode_keyframe_bezier).
*/
int oaknode_keyframe_get_bezier_control(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_bezier_control(OakNodeKeyframe keyframe,
int handle, double *out_x,
double *out_y);
/**
* @brief Set a bezier control point directly (live).
*/
int oaknode_keyframe_set_bezier_control(OakNodeKeyframe *keyframe, int handle,
int oaknode_keyframe_set_bezier_control(OakNodeKeyframe keyframe, int handle,
double x, double y);
/**
* @brief Create a set-bezier-control command.
*/
int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe *keyframe,
int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe keyframe,
int handle, double x, double y,
OakUndoCommand *out_command);
/**
* @brief The keyframe's track index.
*/
int oaknode_keyframe_get_track(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_track(OakNodeKeyframe keyframe,
int *out_track);
/**
* @brief The keyframe's element index.
*/
int oaknode_keyframe_get_element(const OakNodeKeyframe *keyframe,
int oaknode_keyframe_get_element(OakNodeKeyframe keyframe,
int *out_element);
/**
* @brief The id of the input this keyframe belongs to. Two-stage getter.
*/
int oaknode_keyframe_get_input(const OakNodeKeyframe *keyframe, char *buf,
int oaknode_keyframe_get_input(OakNodeKeyframe keyframe, char *buf,
int buf_size);
/**
* @brief The node this keyframe belongs to (borrowed handle), or NULL
* when orphaned. OAKNODE_OK either way.
* @brief The node this keyframe belongs to (borrowed handle written to
* `out_node`; release it with oaknode_node_free()), an empty handle when
* orphaned. OAKNODE_OK either way.
*/
int oaknode_keyframe_get_parent(const OakNodeKeyframe *keyframe,
OakNodeNode **out_node);
int oaknode_keyframe_get_parent(OakNodeKeyframe keyframe,
OakNodeNode *out_node);
#ifdef __cplusplus
}