refactor(render,timeline,task): switch remaining handles to refcounted value structs

- oakrender: renderer/texture/frame/cache/colorprocessor/ticket/copier
  all become by-value {ctx, addref, release, abi_version} handles over a
  generic box; retain() folds into addref; new
  oakrender_cache_wrap_borrowed for native caches from oaknode
- oaktimeline: marker list/workarea borrowed handles become value
  handles (non-owning boxes) with explicit free
- oaktask: OakTaskTask becomes a value handle; ownership still moves
  to the manager on start (owns flag flips)
- consumers (timeline/task/codec sources) migrated; tests everywhere
  updated; suites green: render 45, timeline 117, task 106, node 96,
  common 193, codec 18, audio 36
This commit is contained in:
2026-08-07 18:05:34 +08:00
parent 67176281d9
commit 0462842f8c
48 changed files with 1462 additions and 919 deletions
+44 -42
View File
@@ -49,14 +49,9 @@ public:
using olive::PlaybackCache::validate;
};
OakRenderCacheImpl *impl(OakRenderCache *c)
OakRenderCacheImpl *impl(OakRenderCache c)
{
return reinterpret_cast<OakRenderCacheImpl *>(c);
}
const OakRenderCacheImpl *impl(const OakRenderCache *c)
{
return reinterpret_cast<const OakRenderCacheImpl *>(c);
return oakrender_c_api::to_native<OakRenderCacheImpl>(c);
}
/**
@@ -95,48 +90,52 @@ int oakrender_debug_alive_count(void)
return g_alive_count.load(std::memory_order_relaxed);
}
OakRenderCache *oakrender_cache_create(void)
OakRenderCache oakrender_cache_create(void)
{
try {
auto *c = new OakRenderCacheImpl();
oakrender_c_api::alive_inc();
return reinterpret_cast<OakRenderCache *>(c);
return oakrender_c_api::make_handle<OakRenderCache>(
new OakRenderCacheImpl(), true,
&oakrender_c_api::delete_as<OakRenderCacheImpl>);
} catch (...) {
return nullptr;
return OakRenderCache{};
}
}
void oakrender_cache_free(OakRenderCache *cache)
{
if (!cache) {
return;
}
delete impl(cache);
oakrender_c_api::alive_dec();
oakrender_c_api::free_handle(cache);
}
int oakrender_cache_set_timebase(OakRenderCache *cache, int num, int den)
OakRenderCache oakrender_cache_wrap_borrowed(void *native_cache)
{
if (!cache || num <= 0 || den <= 0) {
// Borrowed: the cache is owned by its node; releasing this handle
// only frees the box.
return oakrender_c_api::make_handle<OakRenderCache>(
native_cache, false, nullptr);
}
int oakrender_cache_set_timebase(OakRenderCache cache, int num, int den)
{
if (!cache.ctx || num <= 0 || den <= 0) {
return OAKRENDER_E_INVALID;
}
impl(cache)->set_timebase(olive::Rational(num, den));
return OAKRENDER_OK;
}
int oakrender_cache_set_uuid(OakRenderCache *cache, const char *uuid)
int oakrender_cache_set_uuid(OakRenderCache cache, const char *uuid)
{
if (!cache || !uuid) {
if (!cache.ctx || !uuid) {
return OAKRENDER_E_INVALID;
}
impl(cache)->set_uuid(uuid);
return OAKRENDER_OK;
}
void oakrender_cache_invalidate(OakRenderCache *cache, int64_t in_ts,
void oakrender_cache_invalidate(OakRenderCache cache, int64_t in_ts,
int64_t out_ts)
{
if (!cache) {
if (!cache.ctx) {
return;
}
OakRenderCacheImpl *c = impl(cache);
@@ -144,10 +143,10 @@ void oakrender_cache_invalidate(OakRenderCache *cache, int64_t in_ts,
olive::core::TimeRange(ts_to_time(c, in_ts), ts_to_time(c, out_ts)));
}
void oakrender_cache_validate(OakRenderCache *cache, int64_t in_ts,
void oakrender_cache_validate(OakRenderCache cache, int64_t in_ts,
int64_t out_ts)
{
if (!cache) {
if (!cache.ctx) {
return;
}
OakRenderCacheImpl *c = impl(cache);
@@ -155,9 +154,9 @@ void oakrender_cache_validate(OakRenderCache *cache, int64_t in_ts,
olive::core::TimeRange(ts_to_time(c, in_ts), ts_to_time(c, out_ts)));
}
int oakrender_cache_has_validated_ranges(const OakRenderCache *cache)
int oakrender_cache_has_validated_ranges(OakRenderCache cache)
{
return cache && impl(cache)->has_validated_ranges() ? 1 : 0;
return cache.ctx && impl(cache)->has_validated_ranges() ? 1 : 0;
}
int oakrender_cache_indicator_height(void)
@@ -165,11 +164,11 @@ int oakrender_cache_indicator_height(void)
return olive::PlaybackCache::get_cache_indicator_height();
}
int oakrender_frame_cache_load(OakRenderCache *cache, const char *path,
int oakrender_frame_cache_load(OakRenderCache cache, const char *path,
const char *uuid, int64_t ts,
OakCodecFrame **out_frame)
OakCodecFrame *out_frame)
{
if (!cache || !path || !uuid || !out_frame) {
if (!cache.ctx || !path || !uuid || !out_frame) {
return OAKRENDER_E_INVALID;
}
try {
@@ -178,20 +177,23 @@ int oakrender_frame_cache_load(OakRenderCache *cache, const char *path,
if (!f) {
return OAKRENDER_E_NOT_FOUND;
}
auto *block = new OakCodecFrame;
block->ptr = std::move(f);
oakrender_c_api::alive_inc();
*out_frame = block;
return OAKRENDER_OK;
auto *frame_impl = new OakCodecFrameImpl;
frame_impl->ptr = std::move(f);
*out_frame = oakrender_c_api::make_handle<OakCodecFrame>(
frame_impl, true,
&oakrender_c_api::delete_as<OakCodecFrameImpl>);
return out_frame->ctx ? OAKRENDER_OK : OAKRENDER_E_NOMEM;
} catch (...) {
return OAKRENDER_E_FAILED;
}
}
void oakrender_frame_cache_save(OakRenderCache *cache, const char *path,
const char *uuid, const OakCodecFrame *frame)
void oakrender_frame_cache_save(OakRenderCache cache, const char *path,
const char *uuid, OakCodecFrame frame)
{
if (!cache || !path || !uuid || !frame || !frame->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!cache.ctx || !path || !uuid || !f || !f->ptr) {
return;
}
try {
@@ -201,17 +203,17 @@ void oakrender_frame_cache_save(OakRenderCache *cache, const char *path,
tb = olive::Rational(1, 1);
}
olive::FrameHashCache::save_cache_frame(path, uuid,
frame->ptr->timestamp(), tb,
frame->ptr);
f->ptr->timestamp(), tb,
f->ptr);
} catch (...) {
}
}
int oakrender_cache_get_invalidated_ranges(OakRenderCache *cache,
int oakrender_cache_get_invalidated_ranges(OakRenderCache cache,
int64_t in_num, int64_t in_den, int64_t out_num, int64_t out_den,
int64_t *ranges, int max_ranges)
{
if (!cache || max_ranges < 0) {
if (!cache.ctx || max_ranges < 0) {
return OAKRENDER_E_INVALID;
}
+29 -26
View File
@@ -46,21 +46,21 @@ int write_string(const std::string &s, char *buf, int n)
} // namespace
OakColorProcessor *oakrender_color_processor_create(const char *src_space,
const char *dst_transform,
int direction)
OakColorProcessor oakrender_color_processor_create(const char *src_space,
const char *dst_transform,
int direction)
{
if (!src_space || !*src_space || !dst_transform || !*dst_transform) {
return nullptr;
return OakColorProcessor{};
}
if (direction != OAKRENDER_COLOR_DIRECTION_NORMAL &&
direction != OAKRENDER_COLOR_DIRECTION_INVERSE) {
return nullptr;
return OakColorProcessor{};
}
try {
OCIO_NAMESPACE::ConstConfigRcPtr config = olive::ColorManager::get_default_config();
if (!config) {
return nullptr;
return OakColorProcessor{};
}
// Resolve role names (e.g. "scene_linear") to canonical colorspace
@@ -84,41 +84,40 @@ OakColorProcessor *oakrender_color_processor_create(const char *src_space,
processor = nullptr;
}
auto *block = new OakColorProcessor;
block->ptr = olive::ColorProcessor::create(processor);
oakrender_c_api::alive_inc();
return block;
auto *impl = new OakColorProcessorImpl;
impl->ptr = olive::ColorProcessor::create(processor);
return oakrender_c_api::make_handle<OakColorProcessor>(
impl, true, &oakrender_c_api::delete_as<OakColorProcessorImpl>);
} catch (...) {
return nullptr;
return OakColorProcessor{};
}
}
void oakrender_color_processor_free(OakColorProcessor *processor)
{
if (!processor) {
return;
}
delete processor;
oakrender_c_api::alive_dec();
oakrender_c_api::free_handle(processor);
}
int oakrender_color_processor_is_valid(const OakColorProcessor *processor)
int oakrender_color_processor_is_valid(OakColorProcessor processor)
{
return processor && processor->ptr && processor->ptr->get_processor() ? 1 :
0;
OakColorProcessorImpl *p =
oakrender_c_api::to_native<OakColorProcessorImpl>(processor);
return p && p->ptr && p->ptr->get_processor() ? 1 : 0;
}
int oakrender_color_processor_convert(OakColorProcessor *processor,
int oakrender_color_processor_convert(OakColorProcessor processor,
double ir, double ig, double ib,
double ia, double *out_r, double *out_g,
double *out_b, double *out_a)
{
if (!processor || !processor->ptr || !out_r || !out_g || !out_b || !out_a) {
OakColorProcessorImpl *p =
oakrender_c_api::to_native<OakColorProcessorImpl>(processor);
if (!p || !p->ptr || !out_r || !out_g || !out_b || !out_a) {
return OAKRENDER_E_INVALID;
}
try {
olive::Color out =
processor->ptr->convert_color(olive::Color(ir, ig, ib, ia));
p->ptr->convert_color(olive::Color(ir, ig, ib, ia));
*out_r = out.red();
*out_g = out.green();
*out_b = out.blue();
@@ -221,10 +220,14 @@ int oakrender_color_manager_display_transform(const char *display,
}
}
int oakrender_color_processor_convert_frame(OakColorProcessor *processor,
OakCodecFrame *frame)
int oakrender_color_processor_convert_frame(OakColorProcessor processor,
OakCodecFrame frame)
{
if (!processor || !processor->ptr || !frame || !frame->ptr) {
OakColorProcessorImpl *p =
oakrender_c_api::to_native<OakColorProcessorImpl>(processor);
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!p || !p->ptr || !f || !f->ptr) {
return OAKRENDER_E_INVALID;
}
try {
@@ -233,7 +236,7 @@ int oakrender_color_processor_convert_frame(OakColorProcessor *processor,
// OCIO::PackedImageDesc view. A processor whose underlying OCIO
// processor is null (creation failure was non-fatal) is a
// pass-through and still reports success, mirroring the C++ API.
processor->ptr->convert_frame(frame->ptr);
p->ptr->convert_frame(f->ptr);
return OAKRENDER_OK;
} catch (...) {
return OAKRENDER_E_FAILED;
+15 -13
View File
@@ -24,36 +24,38 @@
#include "../../node/c_api/nodehandle.h"
#include "../src/projectcopier.h"
#include "internalhandles.h"
namespace
{
olive::ProjectCopier *impl(OakRenderProjectCopier *h)
olive::ProjectCopier *impl(OakRenderProjectCopier h)
{
return reinterpret_cast<olive::ProjectCopier *>(h);
return oakrender_c_api::to_native<olive::ProjectCopier>(h);
}
} // namespace
OakRenderProjectCopier *oakrender_project_copier_create(void)
OakRenderProjectCopier oakrender_project_copier_create(void)
{
try {
return reinterpret_cast<OakRenderProjectCopier *>(
new olive::ProjectCopier());
return oakrender_c_api::make_handle<OakRenderProjectCopier>(
new olive::ProjectCopier(), true,
&oakrender_c_api::delete_as<olive::ProjectCopier>);
} catch (...) {
return NULL;
return OakRenderProjectCopier{};
}
}
void oakrender_project_copier_free(OakRenderProjectCopier *copier)
{
delete impl(copier);
oakrender_c_api::free_handle(copier);
}
int oakrender_project_copier_set_project(OakRenderProjectCopier *copier,
int oakrender_project_copier_set_project(OakRenderProjectCopier copier,
OakNodeProject project)
{
if (!copier || !project.ctx) {
if (!copier.ctx || !project.ctx) {
return OAKRENDER_E_INVALID;
}
try {
@@ -66,9 +68,9 @@ int oakrender_project_copier_set_project(OakRenderProjectCopier *copier,
}
OakNodeNode oakrender_project_copier_get_copy(
OakRenderProjectCopier *copier, OakNodeNode original)
OakRenderProjectCopier copier, OakNodeNode original)
{
if (!copier || !original.ctx) {
if (!copier.ctx || !original.ctx) {
return OakNodeNode{};
}
// Borrowed handle: releasing it only destroys the handle box, never
@@ -79,9 +81,9 @@ OakNodeNode oakrender_project_copier_get_copy(
}
OakNodeProject oakrender_project_copier_get_copied_project(
OakRenderProjectCopier *copier)
OakRenderProjectCopier copier)
{
if (!copier) {
if (!copier.ctx) {
return OakNodeProject{};
}
// Borrowed handle: the copied project is owned by the copier.
+167 -12
View File
@@ -22,34 +22,189 @@
#define OAK_EDITOR_RENDER_INTERNALHANDLES_H
/**
* @brief Control-block definitions behind the public opaque handles
* (internal, not installed).
* @brief Internal control block behind every oakrender value handle,
* shared between the c_api translation units (internal, not
* installed).
*
* Textures, frames and color processors wrap shared_ptr-managed engine
* objects, so their handles are heap control blocks (the R7-A §A.2
* ownership protocol). The refcount on textures/frames implements the
* retain/free pairing rule; every alive control block participates in
* oakrender_debug_alive_count().
* All oakrender public handle structs have the identical layout
* (ctx/addref/release/abi_version), so a single generic box and
* addref/release pair serves every family; `deleter` knows the concrete
* C++ type to destroy. Textures, frames and color processors box the
* *Impl structs below (shared_ptr-managed engine objects); renderers,
* tickets, caches and copiers box their native pointers with custom
* deleters.
*
* `owns` is true for objects created through create/factory functions
* (releasing the last reference destroys the object through `deleter`)
* and false for borrowed wrappers (oakrender_cache_wrap_borrowed()):
* releasing those only destroys the box.
*
* Live-object accounting: make_handle() counts every owned handle it
* creates (alive_inc) and handle_release() un-counts an owned object
* right after destroying it (alive_dec), keeping
* oakrender_debug_alive_count() meaningful for leak checking.
*/
#include <atomic>
#include <new>
#include "render/error.h"
#include "alivecount.h"
#include "codec/frame.h"
#include "colorprocessor.h"
#include "texture.h"
struct OakRenderTexture {
/**
* @brief Boxed object behind OakRenderTexture: a shared_ptr-managed
* GPU texture.
*/
struct OakRenderTextureImpl {
olive::TexturePtr ptr;
std::atomic<int> refcount{ 1 };
};
struct OakCodecFrame {
/**
* @brief Boxed object behind OakCodecFrame: a shared_ptr-managed CPU
* frame.
*/
struct OakCodecFrameImpl {
olive::FramePtr ptr;
std::atomic<int> refcount{ 1 };
};
struct OakColorProcessor {
/**
* @brief Boxed object behind OakColorProcessor: a shared_ptr-managed
* color processor.
*/
struct OakColorProcessorImpl {
olive::ColorProcessorPtr ptr;
};
struct OakRenderBox {
void *object;
bool owns;
std::atomic<uint32_t> refs;
void (*deleter)(void *object);
OakRenderBox(void *o, bool own, void (*del)(void *))
: object(o)
, owns(own)
, refs(1)
, deleter(del)
{
}
};
namespace oakrender_c_api
{
inline void handle_addref(void *ctx)
{
if (ctx) {
static_cast<OakRenderBox *>(ctx)->refs.fetch_add(1);
}
}
inline void handle_release(void *ctx)
{
if (!ctx) {
return;
}
OakRenderBox *box = static_cast<OakRenderBox *>(ctx);
if (box->refs.fetch_sub(1) == 1) {
if (box->owns) {
box->deleter(box->object);
alive_dec();
}
delete box;
}
}
/**
* @brief Wrap `object` in a value handle with reference count 1.
*
* `owns` selects whether the final release destroys the object through
* `deleter`. Returns an empty handle (ctx == nullptr) for a null object
* or on allocation failure (an owned object is destroyed via `deleter`
* in the latter case).
*/
template <typename Handle>
inline Handle make_handle(void *object, bool owns, void (*deleter)(void *))
{
Handle handle = {};
if (!object) {
return handle;
}
OakRenderBox *box = new (std::nothrow) OakRenderBox(object, owns,
deleter);
if (!box) {
if (owns && deleter) {
deleter(object);
}
return handle;
}
if (owns) {
alive_inc();
}
handle.ctx = box;
handle.addref = handle_addref;
handle.release = handle_release;
handle.abi_version = OAKRENDER_ABI_VERSION;
return handle;
}
/**
* @brief Unwrap a value handle to the boxed object (nullptr for an
* empty handle).
*/
template <typename T, typename Handle>
inline T *to_native(Handle h)
{
if (!h.ctx) {
return nullptr;
}
return static_cast<T *>(static_cast<OakRenderBox *>(h.ctx)->object);
}
/**
* @brief Raw boxed object behind a handle ctx (NULL-safe). Used by the
* blit path, whose job struct carries borrowed ctx pointers.
*/
inline void *box_object(const void *ctx)
{
if (!ctx) {
return nullptr;
}
return static_cast<const OakRenderBox *>(ctx)->object;
}
/**
* @brief Deleter callback stamping the concrete C++ type.
*/
template <typename T>
inline void delete_as(void *object)
{
delete static_cast<T *>(object);
}
/**
* @brief Generic free() implementation for every oakrender family:
* release the caller's reference and null out the handle. NULL and
* ctx == NULL are no-ops.
*/
template <typename Handle>
inline void free_handle(Handle *h)
{
if (!h || !h->ctx) {
return;
}
h->release(h->ctx);
h->ctx = nullptr;
}
} // namespace oakrender_c_api
#endif //OAK_EDITOR_RENDER_INTERNALHANDLES_H
+11 -8
View File
@@ -111,14 +111,16 @@ int64_t oakrender_request_frame(OakNodeNode viewer, int64_t ts,
olive::RenderTicket *raw_ticket = ticket.get();
ticket->set_finished_callback([ticket, cb, ts, userdata, id]() {
OakCodecFrame *handle = nullptr;
OakCodecFrame handle = {};
if (ticket->has_result()) {
olive::FramePtr f = ticket->get().value<olive::FramePtr>();
if (f) {
handle = new (std::nothrow) OakCodecFrame;
if (handle) {
handle->ptr = std::move(f);
oakrender_c_api::alive_inc();
auto *impl = new (std::nothrow) OakCodecFrameImpl;
if (impl) {
impl->ptr = std::move(f);
handle = oakrender_c_api::make_handle<OakCodecFrame>(
impl, true,
&oakrender_c_api::delete_as<OakCodecFrameImpl>);
}
}
}
@@ -172,14 +174,15 @@ int oakrender_set_cacher_multicam(OakNodeNode multicam_or_NULL)
return OAKRENDER_OK;
}
int oakrender_set_display_color_processor(OakColorProcessor *p_or_NULL)
int oakrender_set_display_color_processor(OakColorProcessor p_or_NULL)
{
olive::RenderManager *manager = olive::RenderManager::instance();
if (!manager) {
return OAKRENDER_E_STATE;
}
manager->get_cacher()->set_display_color_processor(
p_or_NULL ? p_or_NULL->ptr : nullptr);
OakColorProcessorImpl *p =
oakrender_c_api::to_native<OakColorProcessorImpl>(p_or_NULL);
manager->get_cacher()->set_display_color_processor(p ? p->ptr : nullptr);
return OAKRENDER_OK;
}
+117 -113
View File
@@ -71,24 +71,19 @@ oakrender_video_params cpp_to_pod(const olive::VideoParams &vp)
return p;
}
OakRenderTexture *tex(OakRenderTexture *h)
olive::Renderer *ren(OakRenderRenderer h)
{
return h;
return oakrender_c_api::to_native<olive::Renderer>(h);
}
OakCodecFrame *frm(OakCodecFrame *h)
void renderer_delete(void *object)
{
return h;
}
olive::Renderer *ren(OakRenderRenderer *h)
{
return reinterpret_cast<olive::Renderer *>(h);
}
const olive::Renderer *ren(const OakRenderRenderer *h)
{
return reinterpret_cast<const olive::Renderer *>(h);
auto *r = static_cast<olive::Renderer *>(object);
try {
r->destroy();
delete r;
} catch (...) {
}
}
olive::Matrix4x4 mat_from_float(const float *f)
@@ -134,34 +129,36 @@ std::string g_requested_backend = "opengl";
/* ---- Renderer lifecycle -------------------------------------------------- */
OakRenderRenderer *oakrender_display_renderer_create_dynamic(
OakRenderRenderer oakrender_display_renderer_create_dynamic(
const char *backend_id)
{
if (!backend_id || !*backend_id) {
return nullptr;
return OakRenderRenderer{};
}
try {
auto *r = new olive::DynamicRenderer(backend_id);
if (!r->load()) {
delete r;
return nullptr;
return OakRenderRenderer{};
}
return reinterpret_cast<OakRenderRenderer *>(r);
return oakrender_c_api::make_handle<OakRenderRenderer>(
r, true, &renderer_delete);
} catch (...) {
return nullptr;
return OakRenderRenderer{};
}
}
OakRenderRenderer *oakrender_display_renderer_create_opengl(void)
OakRenderRenderer oakrender_display_renderer_create_opengl(void)
{
try {
return reinterpret_cast<OakRenderRenderer *>(new olive::OpenGLRenderer());
return oakrender_c_api::make_handle<OakRenderRenderer>(
new olive::OpenGLRenderer(), true, &renderer_delete);
} catch (...) {
return nullptr;
return OakRenderRenderer{};
}
}
int oakrender_display_renderer_init(OakRenderRenderer *renderer,
int oakrender_display_renderer_init(OakRenderRenderer renderer,
void *gl_context)
{
olive::Renderer *r = ren(renderer);
@@ -189,220 +186,221 @@ int oakrender_display_renderer_init(OakRenderRenderer *renderer,
void oakrender_display_renderer_destroy(OakRenderRenderer *renderer)
{
olive::Renderer *r = ren(renderer);
if (!r) {
return;
}
try {
r->destroy();
delete r;
} catch (...) {
}
oakrender_c_api::free_handle(renderer);
}
/* ---- Renderer queries ---------------------------------------------------- */
int oakrender_display_renderer_is_open_gl(const OakRenderRenderer *renderer)
int oakrender_display_renderer_is_open_gl(OakRenderRenderer renderer)
{
return renderer && ren(renderer)->is_open_gl() ? 1 : 0;
olive::Renderer *r = ren(renderer);
return r && r->is_open_gl() ? 1 : 0;
}
int oakrender_display_renderer_is_vulkan(const OakRenderRenderer *renderer)
int oakrender_display_renderer_is_vulkan(OakRenderRenderer renderer)
{
return renderer && ren(renderer)->is_vulkan() ? 1 : 0;
olive::Renderer *r = ren(renderer);
return r && r->is_vulkan() ? 1 : 0;
}
/* ---- Texture handle ------------------------------------------------------ */
OakRenderTexture *oakrender_display_texture_create(
OakRenderRenderer *renderer, const oakrender_video_params *params,
OakRenderTexture oakrender_display_texture_create(
OakRenderRenderer renderer, const oakrender_video_params *params,
const void *pixels, int linesize)
{
olive::Renderer *r = ren(renderer);
if (!r || !params) {
return nullptr;
return OakRenderTexture{};
}
try {
olive::TexturePtr t = r->create_texture(pod_to_cpp(*params), pixels,
linesize);
if (!t) {
return nullptr;
return OakRenderTexture{};
}
auto *block = new OakRenderTexture;
block->ptr = std::move(t);
oakrender_c_api::alive_inc();
return block;
auto *impl = new OakRenderTextureImpl;
impl->ptr = std::move(t);
return oakrender_c_api::make_handle<OakRenderTexture>(
impl, true, &oakrender_c_api::delete_as<OakRenderTextureImpl>);
} catch (...) {
return nullptr;
return OakRenderTexture{};
}
}
OakRenderTexture *oakrender_display_texture_retain(OakRenderTexture *texture)
OakRenderTexture oakrender_display_texture_retain(OakRenderTexture texture)
{
if (!texture) {
return nullptr;
if (texture.ctx) {
texture.addref(texture.ctx);
}
tex(texture)->refcount.fetch_add(1, std::memory_order_relaxed);
return texture;
}
void oakrender_display_texture_free(OakRenderTexture *texture)
{
if (!texture) {
return;
}
if (tex(texture)->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
delete tex(texture);
oakrender_c_api::alive_dec();
}
oakrender_c_api::free_handle(texture);
}
int oakrender_display_texture_upload(OakRenderTexture *texture,
int oakrender_display_texture_upload(OakRenderTexture texture,
const void *pixels, int linesize)
{
if (!texture || !pixels || !tex(texture)->ptr) {
OakRenderTextureImpl *t =
oakrender_c_api::to_native<OakRenderTextureImpl>(texture);
if (!t || !pixels || !t->ptr) {
return OAKRENDER_E_INVALID;
}
try {
tex(texture)->ptr->upload(const_cast<void *>(pixels), linesize);
t->ptr->upload(const_cast<void *>(pixels), linesize);
return OAKRENDER_OK;
} catch (...) {
return OAKRENDER_E_FAILED;
}
}
int oakrender_display_texture_download(OakRenderTexture *texture, void *pixels,
int oakrender_display_texture_download(OakRenderTexture texture, void *pixels,
int linesize)
{
if (!texture || !pixels || !tex(texture)->ptr) {
OakRenderTextureImpl *t =
oakrender_c_api::to_native<OakRenderTextureImpl>(texture);
if (!t || !pixels || !t->ptr) {
return OAKRENDER_E_INVALID;
}
try {
tex(texture)->ptr->download(pixels, linesize);
t->ptr->download(pixels, linesize);
return OAKRENDER_OK;
} catch (...) {
return OAKRENDER_E_FAILED;
}
}
int oakrender_display_texture_get_params(const OakRenderTexture *texture,
int oakrender_display_texture_get_params(OakRenderTexture texture,
oakrender_video_params *out)
{
if (!texture || !out || !tex(const_cast<OakRenderTexture *>(texture))->ptr) {
OakRenderTextureImpl *t =
oakrender_c_api::to_native<OakRenderTextureImpl>(texture);
if (!t || !out || !t->ptr) {
return OAKRENDER_E_INVALID;
}
*out = cpp_to_pod(tex(const_cast<OakRenderTexture *>(texture))->ptr->params());
*out = cpp_to_pod(t->ptr->params());
return OAKRENDER_OK;
}
int oakrender_display_texture_id(const OakRenderTexture *texture)
int oakrender_display_texture_id(OakRenderTexture texture)
{
if (!texture || !tex(const_cast<OakRenderTexture *>(texture))->ptr) {
OakRenderTextureImpl *t =
oakrender_c_api::to_native<OakRenderTextureImpl>(texture);
if (!t || !t->ptr) {
return 0;
}
return tex(const_cast<OakRenderTexture *>(texture))->ptr->id().to_int();
return t->ptr->id().to_int();
}
/* ---- Frame handle -------------------------------------------------------- */
OakCodecFrame *oakrender_codec_frame_create(void)
OakCodecFrame oakrender_codec_frame_create(void)
{
try {
auto *block = new OakCodecFrame;
block->ptr = olive::Frame::create();
oakrender_c_api::alive_inc();
return block;
auto *impl = new OakCodecFrameImpl;
impl->ptr = olive::Frame::create();
return oakrender_c_api::make_handle<OakCodecFrame>(
impl, true, &oakrender_c_api::delete_as<OakCodecFrameImpl>);
} catch (...) {
return nullptr;
return OakCodecFrame{};
}
}
OakCodecFrame *oakrender_codec_frame_retain(OakCodecFrame *frame)
OakCodecFrame oakrender_codec_frame_retain(OakCodecFrame frame)
{
if (!frame) {
return nullptr;
if (frame.ctx) {
frame.addref(frame.ctx);
}
frm(frame)->refcount.fetch_add(1, std::memory_order_relaxed);
return frame;
}
void oakrender_codec_frame_free(OakCodecFrame *frame)
{
if (!frame) {
return;
}
if (frm(frame)->refcount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
delete frm(frame);
oakrender_c_api::alive_dec();
}
oakrender_c_api::free_handle(frame);
}
int oakrender_codec_frame_set_video_params(
OakCodecFrame *frame, const oakrender_video_params *params)
OakCodecFrame frame, const oakrender_video_params *params)
{
if (!frame || !params || !frm(frame)->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !params || !f->ptr) {
return OAKRENDER_E_INVALID;
}
frm(frame)->ptr->set_video_params(pod_to_cpp(*params));
f->ptr->set_video_params(pod_to_cpp(*params));
return OAKRENDER_OK;
}
int oakrender_codec_frame_get_params(const OakCodecFrame *frame,
int oakrender_codec_frame_get_params(OakCodecFrame frame,
oakrender_video_params *out)
{
if (!frame || !out || !frm(const_cast<OakCodecFrame *>(frame))->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !out || !f->ptr) {
return OAKRENDER_E_INVALID;
}
*out = cpp_to_pod(
frm(const_cast<OakCodecFrame *>(frame))->ptr->video_params());
*out = cpp_to_pod(f->ptr->video_params());
return OAKRENDER_OK;
}
int oakrender_codec_frame_allocate(OakCodecFrame *frame)
int oakrender_codec_frame_allocate(OakCodecFrame frame)
{
if (!frame || !frm(frame)->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !f->ptr) {
return OAKRENDER_E_INVALID;
}
return frm(frame)->ptr->allocate() ? OAKRENDER_OK : OAKRENDER_E_FAILED;
return f->ptr->allocate() ? OAKRENDER_OK : OAKRENDER_E_FAILED;
}
void *oakrender_codec_frame_data(OakCodecFrame *frame)
void *oakrender_codec_frame_data(OakCodecFrame frame)
{
if (!frame || !frm(frame)->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !f->ptr) {
return nullptr;
}
return frm(frame)->ptr->data();
return f->ptr->data();
}
const void *oakrender_codec_frame_const_data(const OakCodecFrame *frame)
const void *oakrender_codec_frame_const_data(OakCodecFrame frame)
{
if (!frame || !frm(const_cast<OakCodecFrame *>(frame))->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !f->ptr) {
return nullptr;
}
return frm(const_cast<OakCodecFrame *>(frame))->ptr->const_data();
return f->ptr->const_data();
}
int oakrender_codec_frame_linesize_bytes(const OakCodecFrame *frame)
int oakrender_codec_frame_linesize_bytes(OakCodecFrame frame)
{
if (!frame || !frm(const_cast<OakCodecFrame *>(frame))->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !f->ptr) {
return 0;
}
return frm(const_cast<OakCodecFrame *>(frame))->ptr->linesize_bytes();
return f->ptr->linesize_bytes();
}
int oakrender_codec_frame_is_allocated(const OakCodecFrame *frame)
int oakrender_codec_frame_is_allocated(OakCodecFrame frame)
{
if (!frame || !frm(const_cast<OakCodecFrame *>(frame))->ptr) {
OakCodecFrameImpl *f =
oakrender_c_api::to_native<OakCodecFrameImpl>(frame);
if (!f || !f->ptr) {
return 0;
}
return frm(const_cast<OakCodecFrame *>(frame))->ptr->is_allocated() ? 1 : 0;
return f->ptr->is_allocated() ? 1 : 0;
}
/* ---- Color-managed blit -------------------------------------------------- */
int oakrender_display_renderer_blit_color_managed(
OakRenderRenderer *renderer, const oakrender_color_transform_job *job,
OakRenderTexture *dst_texture, const oakrender_video_params *params)
OakRenderRenderer renderer, const oakrender_color_transform_job *job,
OakRenderTexture dst_texture, const oakrender_video_params *params)
{
olive::Renderer *r = ren(renderer);
if (!r || !job) {
@@ -412,11 +410,15 @@ int oakrender_display_renderer_blit_color_managed(
olive::ColorTransformJob ctj;
if (job->processor) {
ctj.set_color_processor(
static_cast<const OakColorProcessor *>(job->processor)->ptr);
static_cast<OakColorProcessorImpl *>(
oakrender_c_api::box_object(job->processor))
->ptr);
}
if (job->input_texture) {
ctj.set_input_texture(
static_cast<OakRenderTexture *>(job->input_texture)->ptr);
static_cast<OakRenderTextureImpl *>(
oakrender_c_api::box_object(job->input_texture))
->ptr);
}
ctj.set_input_alpha_association(
static_cast<olive::AlphaAssociated>(job->input_alpha_association));
@@ -425,7 +427,9 @@ int oakrender_display_renderer_blit_color_managed(
ctj.set_transform_matrix(mat_from_float(job->matrix));
ctj.set_crop_matrix(mat_from_float(job->crop_matrix));
olive::Texture *dst = dst_texture ? tex(dst_texture)->ptr.get() : nullptr;
OakRenderTextureImpl *dst_impl =
oakrender_c_api::to_native<OakRenderTextureImpl>(dst_texture);
olive::Texture *dst = dst_impl ? dst_impl->ptr.get() : nullptr;
if (params) {
r->blit_color_managed(ctj, dst, pod_to_cpp(*params));
} else if (dst) {
@@ -442,7 +446,7 @@ int oakrender_display_renderer_blit_color_managed(
/* ---- Cross-backend texture download -------------------------------------- */
int oakrender_display_renderer_download_from_texture(
OakRenderRenderer *renderer, int texture_id,
OakRenderRenderer renderer, int texture_id,
const oakrender_video_params *params, void *dst_pixels, int linesize)
{
olive::Renderer *r = ren(renderer);
+67 -57
View File
@@ -39,25 +39,41 @@ struct TicketHandle {
olive::core::TimeRange range;
};
TicketHandle *impl(OakRenderTicket *t)
TicketHandle *impl(OakRenderTicket t)
{
return reinterpret_cast<TicketHandle *>(t);
return oakrender_c_api::to_native<TicketHandle>(t);
}
OakRenderTicket *wrap(olive::RenderTicketWatcher *w,
olive::RenderManager::TicketType type)
/**
* @brief Box deleter for tickets: cancels and waits on a running ticket,
* then destroys the watcher and the wrapper.
*/
void ticket_delete(void *object)
{
auto *h = static_cast<TicketHandle *>(object);
if (h->watcher->is_running()) {
h->watcher->cancel();
h->watcher->wait_for_finished();
}
delete h->watcher;
delete h;
}
OakRenderTicket wrap(olive::RenderTicketWatcher *w,
olive::RenderManager::TicketType type)
{
if (!w) {
return NULL;
return OakRenderTicket{};
}
TicketHandle *h = new (std::nothrow) TicketHandle{
w, type, olive::core::Rational(), olive::core::TimeRange()
};
if (!h) {
delete w;
return NULL;
return OakRenderTicket{};
}
return reinterpret_cast<OakRenderTicket *>(h);
return oakrender_c_api::make_handle<OakRenderTicket>(h, true,
&ticket_delete);
}
olive::Node *to_node(OakNodeNode n)
@@ -67,17 +83,17 @@ olive::Node *to_node(OakNodeNode n)
} // namespace
OakRenderTicket *oakrender_ticket_render_frame(
OakRenderTicket oakrender_ticket_render_frame(
const oakrender_video_ticket_params *params,
oakrender_ticket_finished_fn cb, void *userdata)
{
if (!params || !params->output_node.ctx) {
return NULL;
return OakRenderTicket{};
}
olive::RenderManager *manager = olive::RenderManager::instance();
if (!manager) {
return NULL;
return OakRenderTicket{};
}
try {
@@ -86,7 +102,7 @@ OakRenderTicket *oakrender_ticket_render_frame(
? oakcommon_videoparams_get_native(params->video_params)
: nullptr;
if (!vp) {
return NULL;
return OakRenderTicket{};
}
olive::RenderManager::RenderVideoParams rvp(
@@ -119,8 +135,11 @@ OakRenderTicket *oakrender_ticket_render_frame(
params->force_format);
rvp.force_channel_count = params->force_channel_count;
rvp.force_color_output =
params->force_color_output ? params->force_color_output->ptr
: nullptr;
params->force_color_output.ctx
? oakrender_c_api::to_native<OakColorProcessorImpl>(
params->force_color_output)
->ptr
: nullptr;
if (params->force_color_transform.ctx) {
const olive::ColorTransform *ct =
oakcommon_colortransform_get_native(
@@ -142,10 +161,10 @@ OakRenderTicket *oakrender_ticket_render_frame(
"time", olive::Variant::from_value(olive::core::Rational(
int(params->time_num), int(params->time_den))));
OakRenderTicket *handle =
OakRenderTicket handle =
wrap(watcher, olive::RenderManager::k_type_video);
if (!handle) {
return NULL;
if (!handle.ctx) {
return OakRenderTicket{};
}
impl(handle)->time = olive::core::Rational(
int(params->time_num), int(params->time_den));
@@ -160,22 +179,22 @@ OakRenderTicket *oakrender_ticket_render_frame(
watcher->set_ticket(manager->render_frame(rvp));
return handle;
} catch (...) {
return NULL;
return OakRenderTicket{};
}
}
OakRenderTicket *oakrender_ticket_render_audio(
OakRenderTicket oakrender_ticket_render_audio(
OakNodeNode output_node, int64_t in_num, int64_t in_den,
int64_t out_num, int64_t out_den, const OakAudioParams *params,
int mode, oakrender_ticket_finished_fn cb, void *userdata)
{
if (!output_node.ctx || !params) {
return NULL;
return OakRenderTicket{};
}
olive::RenderManager *manager = olive::RenderManager::instance();
if (!manager) {
return NULL;
return OakRenderTicket{};
}
try {
@@ -194,10 +213,10 @@ OakRenderTicket *oakrender_ticket_render_audio(
int(olive::RenderManager::k_type_audio)));
watcher->set_property("range", olive::Variant::from_value(range));
OakRenderTicket *handle =
OakRenderTicket handle =
wrap(watcher, olive::RenderManager::k_type_audio);
if (!handle) {
return NULL;
if (!handle.ctx) {
return OakRenderTicket{};
}
impl(handle)->range = range;
@@ -211,48 +230,48 @@ OakRenderTicket *oakrender_ticket_render_audio(
watcher->set_ticket(manager->render_audio(rap));
return handle;
} catch (...) {
return NULL;
return OakRenderTicket{};
}
}
int oakrender_ticket_is_finished(OakRenderTicket *ticket)
int oakrender_ticket_is_finished(OakRenderTicket ticket)
{
if (!ticket) {
if (!ticket.ctx) {
return OAKRENDER_E_INVALID;
}
return impl(ticket)->watcher->is_running() ? 0 : 1;
}
int oakrender_ticket_wait(OakRenderTicket *ticket)
int oakrender_ticket_wait(OakRenderTicket ticket)
{
if (!ticket) {
if (!ticket.ctx) {
return OAKRENDER_E_INVALID;
}
impl(ticket)->watcher->wait_for_finished();
return OAKRENDER_OK;
}
int oakrender_ticket_cancel(OakRenderTicket *ticket)
int oakrender_ticket_cancel(OakRenderTicket ticket)
{
if (!ticket) {
if (!ticket.ctx) {
return OAKRENDER_E_INVALID;
}
impl(ticket)->watcher->cancel();
return OAKRENDER_OK;
}
int oakrender_ticket_get_type(OakRenderTicket *ticket)
int oakrender_ticket_get_type(OakRenderTicket ticket)
{
if (!ticket) {
if (!ticket.ctx) {
return OAKRENDER_E_INVALID;
}
return int(impl(ticket)->type);
}
int oakrender_ticket_get_time(OakRenderTicket *ticket, int64_t *out_num,
int oakrender_ticket_get_time(OakRenderTicket ticket, int64_t *out_num,
int64_t *out_den)
{
if (!ticket || !out_num || !out_den) {
if (!ticket.ctx || !out_num || !out_den) {
return OAKRENDER_E_INVALID;
}
*out_num = impl(ticket)->time.numerator();
@@ -260,11 +279,11 @@ int oakrender_ticket_get_time(OakRenderTicket *ticket, int64_t *out_num,
return OAKRENDER_OK;
}
int oakrender_ticket_get_range(OakRenderTicket *ticket, int64_t *in_num,
int oakrender_ticket_get_range(OakRenderTicket ticket, int64_t *in_num,
int64_t *in_den, int64_t *out_num,
int64_t *out_den)
{
if (!ticket || !in_num || !in_den || !out_num || !out_den) {
if (!ticket.ctx || !in_num || !in_den || !out_num || !out_den) {
return OAKRENDER_E_INVALID;
}
*in_num = impl(ticket)->range.in().numerator();
@@ -274,12 +293,12 @@ int oakrender_ticket_get_range(OakRenderTicket *ticket, int64_t *in_num,
return OAKRENDER_OK;
}
int oakrender_ticket_get_frame(OakRenderTicket *ticket, OakCodecFrame **out)
int oakrender_ticket_get_frame(OakRenderTicket ticket, OakCodecFrame *out)
{
if (!ticket || !out) {
if (!ticket.ctx || !out) {
return OAKRENDER_E_INVALID;
}
*out = NULL;
*out = OakCodecFrame{};
TicketHandle *h = impl(ticket);
if (h->watcher->is_running()) {
@@ -296,19 +315,20 @@ int oakrender_ticket_get_frame(OakRenderTicket *ticket, OakCodecFrame **out)
return OAKRENDER_E_FAILED;
}
OakCodecFrame *handle = new (std::nothrow) OakCodecFrame;
if (!handle) {
auto *frame_impl = new (std::nothrow) OakCodecFrameImpl;
if (!frame_impl) {
return OAKRENDER_E_NOMEM;
}
handle->ptr = frame;
*out = handle;
return OAKRENDER_OK;
frame_impl->ptr = frame;
*out = oakrender_c_api::make_handle<OakCodecFrame>(
frame_impl, true, &oakrender_c_api::delete_as<OakCodecFrameImpl>);
return out->ctx ? OAKRENDER_OK : OAKRENDER_E_NOMEM;
}
int oakrender_ticket_get_samples(OakRenderTicket *ticket,
int oakrender_ticket_get_samples(OakRenderTicket ticket,
OakSampleBuffer **out)
{
if (!ticket || !out) {
if (!ticket.ctx || !out) {
return OAKRENDER_E_INVALID;
}
*out = NULL;
@@ -330,17 +350,7 @@ int oakrender_ticket_get_samples(OakRenderTicket *ticket,
void oakrender_ticket_free(OakRenderTicket *ticket)
{
if (!ticket) {
return;
}
TicketHandle *h = impl(ticket);
if (h->watcher->is_running()) {
h->watcher->cancel();
h->watcher->wait_for_finished();
}
delete h->watcher;
delete h;
oakrender_c_api::free_handle(ticket);
}
int oakrender_manager_set_aggressive_gc(int enabled)