refactor(node,render): route oaknode->oakrender calls through the C ABI

- oakrender cache C API: add create_for_node (four cache kinds),
  get_uuid, request, load/save_state, set_saving_enabled,
  set_passthrough, get_passthroughs, get_valid_cache_filename,
  get_timebase, lock/unlock, invalidate_range (rational variant),
  get_native (C++ only, for the in-module PreviewAutoCacher)
- Node's four caches become owned OakRenderCache value handles; all
  cache access in node.cpp/clip/viewer/traverser/serializers goes
  through the C ABI
- oaknode_node_get_video_frame_cache returns an addref'd
  OakRenderCache; drop OakNodeFrameCache; oaktask precache/export and
  oakrender_video_ticket_params take the value handle
- color: OCIOBaseNode/OCIOLutNode hold OakColorProcessor handles
  (dtors added); oakrender gains color_processor_create_transform/
  create_lut/create_grading_primary/get_native and LUT library
  queries, keeping all OCIO transform construction inside oakrender;
  oaknode gains colormanager_wrap_borrowed/get_native
- RenderManager::instance() check -> oakrender_manager_available();
  cancel_video_tasks and disk cache path go through manager C API
- remaining node->render C++ symbol: only olive::Texture::~Texture
  via Variant's shared_ptr payload (recorded exception, same class as
  the UndoCommand inheritance)

Tests: new cache/color/manager/colormanager cases; all standalone
trees green (common 196, codec 22, audio 40, task 112, render 63,
timeline 125, node 98, plugin 102).
This commit is contained in:
2026-08-08 03:56:17 +08:00
parent 81431d180d
commit 5a564f30ca
40 changed files with 1553 additions and 237 deletions
+230
View File
@@ -21,13 +21,18 @@
#include "../../../include/render/cache.h"
#include <atomic>
#include <cstring>
#include <new>
#include "alivecount.h"
#include "internalhandles.h"
#include "audioplaybackcache.h"
#include "audiowaveformcache.h"
#include "framehashcache.h"
#include "playbackcache.h"
#include "output/viewer/viewer.h"
#include "../../node/c_api/nodehandle.h"
namespace
{
@@ -114,6 +119,231 @@ OakRenderCache oakrender_cache_wrap_borrowed(void *native_cache)
native_cache, false, nullptr);
}
namespace
{
/**
* @brief Recover the boxed cache as its PlaybackCache base (NULL-safe).
*/
olive::PlaybackCache *base(OakRenderCache c)
{
if (!c.ctx) {
return nullptr;
}
return static_cast<olive::PlaybackCache *>(
oakrender_c_api::box_object(c.ctx));
}
/**
* @brief Copy @p value into the two-stage string buffer.
*
* @return Required buffer size in bytes (including NUL). The buffer is
* only written to when it is large enough.
*/
int copy_string(const std::string &value, char *buf, int buf_size)
{
int needed = static_cast<int>(value.size()) + 1;
if (buf && buf_size >= needed) {
memcpy(buf, value.c_str(), needed);
}
return needed;
}
} // namespace
OakRenderCache oakrender_cache_create_for_node(OakNodeNode parent, int kind)
{
olive::Node *native_parent =
oaknode_c_api::to_native<olive::Node>(parent);
if (!native_parent) {
return OakRenderCache{};
}
olive::PlaybackCache *cache = nullptr;
switch (kind) {
case OAKRENDER_CACHE_VIDEO_FRAME:
cache = new (std::nothrow) olive::FrameHashCache(native_parent);
break;
case OAKRENDER_CACHE_THUMBNAIL:
cache = new (std::nothrow) olive::ThumbnailCache(native_parent);
break;
case OAKRENDER_CACHE_AUDIO_PLAYBACK:
cache = new (std::nothrow) olive::AudioPlaybackCache(native_parent);
break;
case OAKRENDER_CACHE_AUDIO_WAVEFORM:
cache = new (std::nothrow) olive::AudioWaveformCache(native_parent);
break;
default:
return OakRenderCache{};
}
if (!cache) {
return OakRenderCache{};
}
return oakrender_c_api::make_handle<OakRenderCache>(
cache, true, &oakrender_c_api::delete_as<olive::PlaybackCache>);
}
int oakrender_cache_get_uuid(OakRenderCache cache, char *buf, int buf_size)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return OAKRENDER_E_INVALID;
}
return copy_string(c->get_uuid(), buf, buf_size);
}
void oakrender_cache_invalidate_range(OakRenderCache cache,
int64_t in_num, int64_t in_den,
int64_t out_num, int64_t out_den)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return;
}
c->invalidate(
olive::core::TimeRange(olive::Rational(in_num, in_den),
olive::Rational(out_num, out_den)));
}
int oakrender_cache_request(OakRenderCache cache, OakNodeNode context,
int64_t in_num, int64_t in_den,
int64_t out_num, int64_t out_den)
{
olive::PlaybackCache *c = base(cache);
olive::Node *native_context =
oaknode_c_api::to_native<olive::Node>(context);
auto *viewer = dynamic_cast<olive::ViewerOutput *>(native_context);
if (!c || !viewer) {
return OAKRENDER_E_INVALID;
}
c->request(viewer,
olive::core::TimeRange(olive::Rational(in_num, in_den),
olive::Rational(out_num, out_den)));
return OAKRENDER_OK;
}
int oakrender_cache_load_state(OakRenderCache cache)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return OAKRENDER_E_INVALID;
}
try {
c->load_state();
return OAKRENDER_OK;
} catch (...) {
return OAKRENDER_E_FAILED;
}
}
int oakrender_cache_save_state(OakRenderCache cache)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return OAKRENDER_E_INVALID;
}
try {
c->save_state();
return OAKRENDER_OK;
} catch (...) {
return OAKRENDER_E_FAILED;
}
}
int oakrender_cache_set_saving_enabled(OakRenderCache cache, int enabled)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return OAKRENDER_E_INVALID;
}
c->set_saving_enabled(enabled != 0);
return OAKRENDER_OK;
}
int oakrender_cache_set_passthrough(OakRenderCache cache,
OakRenderCache other)
{
olive::PlaybackCache *c = base(cache);
olive::PlaybackCache *o = base(other);
if (!c || !o) {
return OAKRENDER_E_INVALID;
}
c->set_passthrough(o);
return OAKRENDER_OK;
}
int oakrender_cache_get_valid_cache_filename(OakRenderCache cache,
int64_t time_num,
int64_t time_den, char *buf,
int buf_size)
{
auto *c = dynamic_cast<olive::FrameHashCache *>(base(cache));
if (!c) {
return OAKRENDER_E_INVALID;
}
return copy_string(
c->get_valid_cache_filename(olive::Rational(time_num, time_den)),
buf, buf_size);
}
int oakrender_cache_get_passthroughs(OakRenderCache cache, int64_t *ranges,
int max_ranges)
{
olive::PlaybackCache *c = base(cache);
if (!c) {
return OAKRENDER_E_INVALID;
}
const std::vector<olive::PlaybackCache::Passthrough> &all =
c->get_passthroughs();
int count = static_cast<int>(all.size());
if (ranges && max_ranges > 0) {
int n = count < max_ranges ? count : max_ranges;
for (int i = 0; i < n; i++) {
ranges[i * 4] = all[i].in().numerator();
ranges[i * 4 + 1] = all[i].in().denominator();
ranges[i * 4 + 2] = all[i].out().numerator();
ranges[i * 4 + 3] = all[i].out().denominator();
}
}
return count;
}
int oakrender_cache_get_timebase(OakRenderCache cache, int *num, int *den)
{
auto *c = dynamic_cast<olive::FrameHashCache *>(base(cache));
if (!c) {
return OAKRENDER_E_INVALID;
}
if (num) {
*num = c->get_timebase().numerator();
}
if (den) {
*den = c->get_timebase().denominator();
}
return OAKRENDER_OK;
}
void oakrender_cache_lock(OakRenderCache cache)
{
if (olive::PlaybackCache *c = base(cache)) {
c->mutex().lock();
}
}
void oakrender_cache_unlock(OakRenderCache cache)
{
if (olive::PlaybackCache *c = base(cache)) {
c->mutex().unlock();
}
}
olive::PlaybackCache *oakrender_cache_get_native(OakRenderCache cache)
{
return base(cache);
}
int oakrender_cache_set_timebase(OakRenderCache cache, int num, int den)
{
if (!cache.ctx || num <= 0 || den <= 0) {
+124
View File
@@ -30,6 +30,7 @@
#include "color/colormanager/colormanager.h"
#include "filefunctions.h"
#include "lutlibrary.h"
#include <OpenColorIO/OpenColorIO.h>
namespace
@@ -105,6 +106,129 @@ int oakrender_color_processor_is_valid(OakColorProcessor processor)
return p && p->ptr && p->ptr->get_processor() ? 1 : 0;
}
OakColorProcessor oakrender_color_processor_create_transform(
OakNodeColorManager manager, const char *input,
OakColorTransform dest, int direction)
{
olive::ColorManager *native_manager =
oaknode_colormanager_get_native(manager);
const olive::ColorTransform *native_dest =
oakcommon_colortransform_get_native(dest);
if (!native_manager || !input || !*input || !native_dest) {
return OakColorProcessor{};
}
if (direction != OAKRENDER_COLOR_DIRECTION_NORMAL &&
direction != OAKRENDER_COLOR_DIRECTION_INVERSE) {
return OakColorProcessor{};
}
try {
auto *impl = new OakColorProcessorImpl;
impl->ptr = olive::ColorProcessor::create(
native_manager, input, *native_dest,
direction == OAKRENDER_COLOR_DIRECTION_NORMAL ?
olive::ColorProcessor::k_normal :
olive::ColorProcessor::k_inverse);
return oakrender_c_api::make_handle<OakColorProcessor>(
impl, true, &oakrender_c_api::delete_as<OakColorProcessorImpl>);
} catch (...) {
return OakColorProcessor{};
}
}
OakColorProcessor oakrender_color_processor_create_lut(
OakNodeColorManager manager, const char *path, int direction)
{
olive::ColorManager *native_manager =
oaknode_colormanager_get_native(manager);
if (!native_manager || !path || !*path) {
return OakColorProcessor{};
}
if (direction != OAKRENDER_COLOR_DIRECTION_NORMAL &&
direction != OAKRENDER_COLOR_DIRECTION_INVERSE) {
return OakColorProcessor{};
}
try {
OCIO_NAMESPACE::FileTransformRcPtr transform =
OCIO_NAMESPACE::FileTransform::Create();
transform->setSrc(path);
transform->setInterpolation(OCIO_NAMESPACE::INTERP_LINEAR);
transform->setDirection(
direction == OAKRENDER_COLOR_DIRECTION_NORMAL ?
OCIO_NAMESPACE::TRANSFORM_DIR_FORWARD :
OCIO_NAMESPACE::TRANSFORM_DIR_INVERSE);
auto *impl = new OakColorProcessorImpl;
impl->ptr = olive::ColorProcessor::create(
native_manager->get_config()->getProcessor(transform));
return oakrender_c_api::make_handle<OakColorProcessor>(
impl, true, &oakrender_c_api::delete_as<OakColorProcessorImpl>);
} catch (...) {
return OakColorProcessor{};
}
}
OakColorProcessor oakrender_color_processor_create_grading_primary(
OakNodeColorManager manager, int style)
{
olive::ColorManager *native_manager =
oaknode_colormanager_get_native(manager);
if (!native_manager || (style != OAKRENDER_GRADING_PRIMARY_LIN &&
style != OAKRENDER_GRADING_PRIMARY_LOG)) {
return OakColorProcessor{};
}
try {
OCIO_NAMESPACE::GradingPrimaryTransformRcPtr gp =
OCIO_NAMESPACE::GradingPrimaryTransform::Create(
style == OAKRENDER_GRADING_PRIMARY_LIN ?
OCIO_NAMESPACE::GRADING_LIN :
OCIO_NAMESPACE::GRADING_LOG);
gp->makeDynamic();
gp->setDirection(
OCIO_NAMESPACE::TransformDirection::TRANSFORM_DIR_FORWARD);
auto *impl = new OakColorProcessorImpl;
impl->ptr = olive::ColorProcessor::create(
native_manager->get_config()->getProcessor(gp));
return oakrender_c_api::make_handle<OakColorProcessor>(
impl, true, &oakrender_c_api::delete_as<OakColorProcessorImpl>);
} catch (...) {
return OakColorProcessor{};
}
}
std::shared_ptr<olive::ColorProcessor> oakrender_color_processor_get_native(
OakColorProcessor processor)
{
OakColorProcessorImpl *p =
oakrender_c_api::to_native<OakColorProcessorImpl>(processor);
return p ? p->ptr : nullptr;
}
int oakrender_lut_is_supported_extension(const char *extension)
{
if (!extension) {
return 0;
}
return olive::LUTLibrary::is_supported_extension(extension) ? 1 : 0;
}
int oakrender_lut_supported_extensions_count(void)
{
return static_cast<int>(
olive::LUTLibrary::supported_extensions().size());
}
int oakrender_lut_supported_extension_at(int index, char *buf,
int buf_size)
{
const std::vector<std::string> &all =
olive::LUTLibrary::supported_extensions();
if (index < 0 || index >= static_cast<int>(all.size())) {
return OAKRENDER_E_NOT_FOUND;
}
return write_string(all[size_t(index)], buf, buf_size);
}
int oakrender_color_processor_convert(OakColorProcessor processor,
double ir, double ig, double ib,
double ia, double *out_r, double *out_g,
+16
View File
@@ -161,6 +161,22 @@ int oakrender_cancel_request(int64_t request_id)
return OAKRENDER_OK;
}
int oakrender_manager_available(void)
{
return olive::RenderManager::instance() != nullptr ? 1 : 0;
}
void oakrender_cancel_video_tasks(int wait_for_done)
{
olive::RenderManager *manager = olive::RenderManager::instance();
if (!manager) {
return;
}
if (olive::PreviewAutoCacher *cacher = manager->get_cacher()) {
cacher->cancel_video_tasks(wait_for_done != 0);
}
}
int oakrender_set_cacher_multicam(OakNodeNode multicam_or_NULL)
{
olive::RenderManager *manager = olive::RenderManager::instance();
+5 -3
View File
@@ -149,9 +149,11 @@ OakRenderTicket oakrender_ticket_render_frame(
}
}
if (params->cache) {
rvp.add_cache(reinterpret_cast<olive::FrameHashCache *>(
params->cache));
if (params->cache.ctx) {
if (auto *fc = dynamic_cast<olive::FrameHashCache *>(
oakrender_cache_get_native(params->cache))) {
rvp.add_cache(fc);
}
}
auto *watcher = new olive::RenderTicketWatcher();