refactor(task,render): RenderTask family over a new oakrender ticket C ABI

- oakrender: new ticket family (render_frame/render_audio with finished
  callback, result frame/samples access, cancel/wait), project copier
  C API, cache get_invalidated_ranges, manager set_aggressive_gc
- oaknode: node_copy_inputs, set_value_hint_track, viewer params
  setters, video frame cache borrowed outlet, project copy_settings
- oakcodec: encoder desired pixel format, export format extension,
  encoding generate_matrix, custom range in encoding params POD
- oaktask: RenderTask orchestrates oakrender tickets (no Qt threads/
  watchers), PreCacheTask and ExportTask rewritten over the oaknode/
  oakrender/oakcodec C ABIs; frames cross from oakrender to oakcodec
  handles by pixel copy (different control blocks)
- the two-step texture/download render path collapses into single-step
  (tickets always yield frames); subtitle sidecar kept
- tests: 105 in build-oaktask (export/precache factory paths,
  construction, conform end-to-end); regressions all green
This commit is contained in:
2026-08-07 14:40:12 +08:00
parent 6ded1d2d63
commit 40a336276f
29 changed files with 2548 additions and 726 deletions
+102
View File
@@ -20,6 +20,9 @@
#include "node/node.h"
#include "common/videoparams.h"
#include "olive/core/oakcore/audioparams.h"
#include <atomic>
#include <string>
@@ -1230,3 +1233,102 @@ int oaknode_node_get_work_area(const OakNodeNode *node,
}
return OAKNODE_OK;
}
int oaknode_node_get_video_frame_cache(const OakNodeNode *node,
OakNodeFrameCache **out)
{
if (!node || !out) {
return OAKNODE_E_INVALID;
}
*out = reinterpret_cast<OakNodeFrameCache *>(
to_node(node)->video_frame_cache());
return OAKNODE_OK;
}
int oaknode_node_copy_inputs(OakNodeNode *dst, const OakNodeNode *src,
int include_connections)
{
if (!dst || !src) {
return OAKNODE_E_INVALID;
}
try {
olive::Node::copy_inputs(to_node(src), to_node(dst),
include_connections != 0);
return OAKNODE_OK;
} catch (...) {
return OAKNODE_E_FAILED;
}
}
int oaknode_node_set_value_hint_track(OakNodeNode *node,
const char *input_id,
int track_type, int track_index)
{
if (!node || !input_id) {
return OAKNODE_E_INVALID;
}
try {
to_node(node)->set_value_hint_for_input(
input_id,
olive::Node::ValueHint({ olive::NodeValue::k_texture },
olive::Track::Reference(
static_cast<olive::Track::Type>(
track_type),
track_index)
.to_string()));
return OAKNODE_OK;
} catch (...) {
return OAKNODE_E_FAILED;
}
}
int oaknode_viewer_set_video_params(OakNodeNode *viewer,
const OakVideoParams *params)
{
if (!viewer || !params || !params->ctx) {
return OAKNODE_E_INVALID;
}
const olive::VideoParams *native =
oakcommon_videoparams_get_native(*params);
if (!native) {
return OAKNODE_E_INVALID;
}
olive::ViewerOutput *v =
dynamic_cast<olive::ViewerOutput *>(to_node(viewer));
if (!v) {
return OAKNODE_E_INVALID;
}
try {
v->set_video_params(*native);
return OAKNODE_OK;
} catch (...) {
return OAKNODE_E_FAILED;
}
}
int oaknode_viewer_set_audio_params(OakNodeNode *viewer,
const OakAudioParams *params)
{
if (!viewer || !params) {
return OAKNODE_E_INVALID;
}
olive::ViewerOutput *v =
dynamic_cast<olive::ViewerOutput *>(to_node(viewer));
if (!v) {
return OAKNODE_E_INVALID;
}
try {
v->set_audio_params(olive::AudioParams::from_handle(
oakcore_audioparams_copy(params)));
return OAKNODE_OK;
} catch (...) {
return OAKNODE_E_FAILED;
}
}
+15
View File
@@ -371,3 +371,18 @@ OakNodeNode *oaknode_project_node_at(const OakNodeProject *project, int index)
return NULL;
}
}
int oaknode_project_copy_settings(OakNodeProject *dst,
const OakNodeProject *src)
{
if (!dst || !src) {
return OAKNODE_E_INVALID;
}
try {
olive::Project::copy_settings(const_cast<olive::Project *>(to_cpp(src)), to_cpp(dst));
return OAKNODE_OK;
} catch (...) {
return OAKNODE_E_FAILED;
}
}