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:
+44
-42
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user