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
+48 -24
View File
@@ -38,10 +38,13 @@ extern "C" {
* @brief C ABI for the oakrender playback/frame-hash caches
* (olive::PlaybackCache / olive::FrameHashCache), M7 §2.2.
*
* An OakRenderCache IS a reinterpreted olive::FrameHashCache (created
* without a parent node), no wrapper allocation. Handles from
* oakrender_cache_create() are owned by the caller and must be released
* with oakrender_cache_free().
* An OakRenderCache is a by-value reference-counted handle (shared_ptr
* semantics, see oakcommon's common/handle.h) boxing an
* olive::FrameHashCache (created without a parent node). Handles from
* oakrender_cache_create() are owned by the caller (reference count 1)
* and must be released with oakrender_cache_free(); handles from
* oakrender_cache_wrap_borrowed() are borrowed (release only frees the
* box).
*
* All timestamps are int64 frame numbers in the cache's timebase (see
* oakrender_cache_set_timebase()); a cache without a valid timebase
@@ -51,27 +54,48 @@ extern "C" {
* invalidate/validate are triggered by and known to the caller; the
* facade re-emits notifications after the triggering command.
*/
typedef struct OakRenderCache OakRenderCache;
typedef struct OakRenderCache {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakRenderCache;
/**
* @brief Create a detached frame hash cache (no parent node, no
* timebase). Owned by the caller.
*
* @return Cache handle, or NULL on allocation failure.
* @return Cache handle with reference count 1; ctx is NULL on
* allocation failure.
*/
OakRenderCache *oakrender_cache_create(void);
OakRenderCache oakrender_cache_create(void);
/** @brief Destroy a cache created by oakrender_cache_create(). NULL-safe. */
/**
* @brief Release one reference to a cache created by
* oakrender_cache_create(). Convenience wrapper around
* cache->release(cache->ctx). NULL / empty-handle no-op; clears
* cache->ctx after releasing.
*/
void oakrender_cache_free(OakRenderCache *cache);
/**
* @brief Borrowed handle wrapping a native frame cache pointer obtained
* through oaknode (oaknode_node_get_video_frame_cache()).
*
* The cache itself stays owned by its node: release() on this handle
* only frees the box. Empty handle (ctx == NULL) for a NULL native
* pointer.
*/
OakRenderCache oakrender_cache_wrap_borrowed(void *native_cache);
/**
* @brief Set the frame timebase used to interpret all timestamps of this
* cache (FrameHashCache::set_timebase()).
*
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for NULL cache or
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for an empty cache or
* non-positive num/den.
*/
int oakrender_cache_set_timebase(OakRenderCache *cache, int num, int den);
int oakrender_cache_set_timebase(OakRenderCache cache, int num, int den);
/**
* @brief Set the cache UUID used in on-disk frame cache filenames
@@ -79,27 +103,27 @@ int oakrender_cache_set_timebase(OakRenderCache *cache, int num, int den);
*
* @return OAKRENDER_OK or OAKRENDER_E_INVALID.
*/
int oakrender_cache_set_uuid(OakRenderCache *cache, const char *uuid);
int oakrender_cache_set_uuid(OakRenderCache cache, const char *uuid);
/**
* @brief Mark the timestamp range [in_ts, out_ts) invalidated
* (PlaybackCache::invalidate()). NULL cache is a no-op.
* (PlaybackCache::invalidate()). Empty cache is a no-op.
*/
void oakrender_cache_invalidate(OakRenderCache *cache, int64_t in_ts,
void oakrender_cache_invalidate(OakRenderCache cache, int64_t in_ts,
int64_t out_ts);
/**
* @brief Mark the timestamp range [in_ts, out_ts) validated
* (PlaybackCache::validate()). NULL cache is a no-op.
* (PlaybackCache::validate()). Empty cache is a no-op.
*/
void oakrender_cache_validate(OakRenderCache *cache, int64_t in_ts,
void oakrender_cache_validate(OakRenderCache cache, int64_t in_ts,
int64_t out_ts);
/**
* @brief 1 when the cache holds any validated range
* (PlaybackCache::has_validated_ranges()), 0 otherwise / on NULL.
* (PlaybackCache::has_validated_ranges()), 0 otherwise / empty.
*/
int oakrender_cache_has_validated_ranges(const OakRenderCache *cache);
int oakrender_cache_has_validated_ranges(OakRenderCache cache);
/**
* @brief Timeline cache indicator height in pixels
@@ -117,7 +141,7 @@ int oakrender_cache_indicator_height(void);
*
* @return Range count (>= 0), or a negative OAKRENDER_E_* code.
*/
int oakrender_cache_get_invalidated_ranges(OakRenderCache *c,
int oakrender_cache_get_invalidated_ranges(OakRenderCache c,
int64_t in_num, int64_t in_den, int64_t out_num, int64_t out_den,
int64_t *ranges, int max_ranges);
@@ -130,20 +154,20 @@ int oakrender_cache_get_invalidated_ranges(OakRenderCache *c,
* @param out_frame Receives an owned frame handle (release with
* oakrender_codec_frame_free()).
*
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (NULL argument), or
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (empty/NULL argument), or
* OAKRENDER_E_NOT_FOUND (no cached frame at `ts` / undecodable).
*/
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);
/**
* @brief Save a frame to the disk cache under the cache's timebase and
* the frame's own timestamp (FrameHashCache::save_cache_frame()).
* NULL arguments are a no-op.
* Empty/NULL arguments are a no-op.
*/
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);
/* ---- Debug --------------------------------------------------------------- */
-10
View File
@@ -37,16 +37,6 @@ namespace olive { class CancelAtom; }
extern "C" {
#endif
/**
* @brief Current ABI version stamped into every oakrender handle.
*
* Bump whenever a handle layout or the semantics of any exported function
* change incompatibly. Consumers should compare a handle's abi_version
* field against the value they were compiled with before dereferencing
* ctx.
*/
#define OAKRENDER_ABI_VERSION 1
/**
* @file cancelatom.h
* @brief C ABI for the oakrender cancellation primitive
+29 -18
View File
@@ -34,10 +34,11 @@ extern "C" {
* the process-wide default OCIO config (olive::ColorManager
* statics), M7 §2.3.
*
* An OakColorProcessor IS a wrapper allocation holding a
* ColorProcessorPtr (ColorProcessor is shared_ptr-managed); release with
* oakrender_color_processor_free(). NULL is accepted by every function
* and yields a no-op / OAKRENDER_E_INVALID.
* An OakColorProcessor is a by-value reference-counted handle (shared_ptr
* semantics, see oakcommon's common/handle.h) boxing a ColorProcessorPtr
* (ColorProcessor is shared_ptr-managed); release with
* oakrender_color_processor_free(). Empty handles (ctx == NULL) are
* accepted by every function and yield a no-op / OAKRENDER_E_INVALID.
*
* Processors are built against the process-wide default OCIO config
* (olive::ColorManager::get_default_config()): the $OCIO config when the
@@ -52,7 +53,12 @@ enum {
OAKRENDER_COLOR_DIRECTION_INVERSE = 1
};
typedef struct OakColorProcessor OakColorProcessor;
typedef struct OakColorProcessor {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakColorProcessor;
/**
* @brief Create a colorspace-to-colorspace processor on the default
@@ -67,29 +73,34 @@ typedef struct OakColorProcessor OakColorProcessor;
* still returned but oakrender_color_processor_is_valid() reports 0 and
* conversions are pass-through.
*
* @return Processor handle, or NULL for NULL/empty strings, an unknown
* direction, no default config, or allocation failure.
* @return Processor handle with reference count 1; ctx is NULL for
* NULL/empty strings, an unknown direction, no default config,
* or allocation failure.
*/
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);
/** @brief Release a processor handle. NULL-safe no-op. */
/**
* @brief Release one reference to a processor handle. Convenience
* wrapper around processor->release(processor->ctx). NULL /
* empty-handle no-op; clears processor->ctx after releasing.
*/
void oakrender_color_processor_free(OakColorProcessor *processor);
/**
* @brief 1 when the processor holds a valid OCIO processor
* (ColorProcessor::get_processor() != null), 0 otherwise / on NULL.
* (ColorProcessor::get_processor() != null), 0 otherwise / empty.
*/
int oakrender_color_processor_is_valid(const OakColorProcessor *processor);
int oakrender_color_processor_is_valid(OakColorProcessor processor);
/**
* @brief Convert a single RGBA color (ColorProcessor::convert_color()).
* On an invalid processor the input is copied through.
*
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for NULL arguments.
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for empty/NULL arguments.
*/
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);
@@ -105,11 +116,11 @@ int oakrender_color_processor_convert(OakColorProcessor *processor,
* non-fatal) is a pass-through and returns OAKRENDER_OK, mirroring the
* C++ API.
*
* @return OAKRENDER_OK, OAKRENDER_E_INVALID for NULL/uninitialized
* @return OAKRENDER_OK, OAKRENDER_E_INVALID for empty/uninitialized
* arguments, or OAKRENDER_E_FAILED on an internal exception.
*/
int oakrender_color_processor_convert_frame(OakColorProcessor *processor,
OakCodecFrame *frame);
int oakrender_color_processor_convert_frame(OakColorProcessor processor,
OakCodecFrame frame);
/* ---- ColorManager statics ------------------------------------------------- */
+26 -9
View File
@@ -30,35 +30,52 @@ extern "C" {
#endif
/**
* @brief Opaque handle to a project copier (olive::ProjectCopier):
* deep-copies a project graph for background processing
* (export/precache).
* @brief Reference-counted handle to a project copier
* (olive::ProjectCopier): deep-copies a project graph for
* background processing (export/precache).
*
* By-value handle (shared_ptr semantics, see oakcommon's
* common/handle.h): oakrender_project_copier_create() returns a handle
* with reference count 1; release it with
* oakrender_project_copier_free().
*/
typedef struct OakRenderProjectCopier OakRenderProjectCopier;
typedef struct OakRenderProjectCopier {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakRenderProjectCopier;
/**
* @brief Create a copier. The copy is built by
* oakrender_project_copier_set_project().
*
* @return Copier handle with reference count 1; ctx is NULL on
* allocation failure.
*/
OakRenderProjectCopier *oakrender_project_copier_create(void);
OakRenderProjectCopier oakrender_project_copier_create(void);
/** @brief Free the copier AND its copied project. NULL-safe. */
/**
* @brief Release one reference to a copier; the final release frees the
* copier AND its copied project. NULL / empty-handle no-op; clears
* copier->ctx after releasing.
*/
void oakrender_project_copier_free(OakRenderProjectCopier *copier);
/** @brief (Re)build the copy from `project` (borrowed handle). */
int oakrender_project_copier_set_project(OakRenderProjectCopier *copier,
int oakrender_project_copier_set_project(OakRenderProjectCopier copier,
OakNodeProject project);
/** @brief The copied counterpart of an original node (borrowed handle;
* freeing it only releases the handle box), empty handle when the
* node is not in the copied project. */
OakNodeNode oakrender_project_copier_get_copy(
OakRenderProjectCopier *copier, OakNodeNode original);
OakRenderProjectCopier copier, OakNodeNode original);
/** @brief The copied project (borrowed handle; freeing it only releases
* the handle box). */
OakNodeProject oakrender_project_copier_get_copied_project(
OakRenderProjectCopier *copier);
OakRenderProjectCopier copier);
#ifdef __cplusplus
}
+10
View File
@@ -29,6 +29,16 @@
* failure. String getters return the required buffer size in bytes
* (including the terminating NUL) as a non-negative value instead.
*/
/**
* @brief Current ABI version stamped into every oakrender handle.
*
* Bump whenever a handle layout or the semantics of any exported function
* change incompatibly. Consumers should compare a handle's abi_version
* field against the value they were compiled with before dereferencing
* ctx.
*/
#define OAKRENDER_ABI_VERSION 1
#define OAKRENDER_OK 0 /**< Success. */
#define OAKRENDER_E_INVALID (-1) /**< NULL handle or invalid argument. */
#define OAKRENDER_E_STATE (-2) /**< Call not valid in the current state. */
+8 -8
View File
@@ -46,9 +46,9 @@ extern "C" {
* The frame request callback is the asynchronous command return channel
* (M7 §2.2 note): it fires on a render worker thread, possibly after
* cancellation. The delivered OakCodecFrame is owned by the callback
* recipient (release with oakrender_codec_frame_free()); a NULL frame
* signals "no result" (cancelled or failed). Beyond this callback there
* are no event subscription interfaces.
* recipient (release with oakrender_codec_frame_free()); an empty frame
* (ctx == NULL) signals "no result" (cancelled or failed). Beyond this
* callback there are no event subscription interfaces.
*/
/**
@@ -69,11 +69,11 @@ void oakrender_manager_shutdown(void);
/**
* @brief Completion callback of an asynchronous frame request.
*
* @param frame Owned frame handle, or NULL when the request finished
* without a result (cancelled/failed).
* @param frame Owned frame handle, or an empty handle (ctx == NULL)
* when the request finished without a result (cancelled/failed).
* @param ts The request's timestamp, passed back verbatim.
*/
typedef void (*oakrender_frame_ready_fn)(OakCodecFrame *frame, int64_t ts,
typedef void (*oakrender_frame_ready_fn)(OakCodecFrame frame, int64_t ts,
void *userdata);
/**
@@ -114,11 +114,11 @@ int oakrender_set_cacher_multicam(OakNodeNode multicam_or_NULL);
/**
* @brief Set the display color processor on the manager's auto-cacher
* (PreviewAutoCacher::set_display_color_processor()). Borrowed handle,
* NULL to clear.
* empty ctx to clear.
*
* @return OAKRENDER_OK or OAKRENDER_E_STATE.
*/
int oakrender_set_display_color_processor(OakColorProcessor *p_or_NULL);
int oakrender_set_display_color_processor(OakColorProcessor p_or_NULL);
/* ---- Disk cache (olive::DiskManager) -------------------------------------- */
+117 -66
View File
@@ -38,20 +38,25 @@ extern "C" {
* (docs/zh/plans/completed/r7-pure-abi-plan.md §A.2) with the
* oakrender_ prefix (M7 §2.1).
*
* Ownership protocol: textures and frames are opaque handles pointing to
* oakrender-heap control blocks (internally holding std::shared_ptr;
* invisible to the ABI). Ownership transfers via explicit retain/free.
* Every retain must be paired with exactly one free. NULL is accepted by
* every function and yields a no-op / zero result / OAKRENDER_E_INVALID.
* Ownership protocol: every public handle is a by-value
* reference-counted struct (see oakcommon's common/handle.h; shared_ptr
* semantics). init/create functions return a handle with reference
* count 1, handle.addref(handle.ctx) takes another reference, and
* handle.release(handle.ctx) (or the oakrender_*_free() convenience
* wrappers, which also null the caller's ctx) drops one; the object is
* destroyed in this library when the count reaches zero. Empty handles
* (ctx == NULL) are accepted by every function and yield a no-op / zero
* result / OAKRENDER_E_INVALID.
*
* Cross-thread handoff (§A.3): the producing side retains before
* publishing a handle into a shared slot; the consuming side frees the
* handle it replaced. The side holding the slot when it is torn down
* frees the remaining handle.
* Cross-thread handoff (§A.3): the producing side addrefs before
* publishing a handle into a shared slot; the consuming side releases
* the handle it replaced. The side holding the slot when it is torn
* down releases the remaining handle.
*
* Handles:
* - OakRenderRenderer IS a reinterpreted olive::Renderer (no wrapper).
* - OakRenderTexture / OakCodecFrame are refcounted control blocks.
* - OakRenderRenderer wraps a native olive::Renderer.
* - OakRenderTexture / OakCodecFrame box shared_ptr-managed engine
* objects.
* - `gl_context` is an opaque borrowed olive::OpenGLContext* (or NULL
* to let the backend create its own offscreen surface).
*/
@@ -81,17 +86,42 @@ typedef struct oakrender_video_params {
int premultiplied_alpha; /**< 0/1. */
} oakrender_video_params;
typedef struct OakRenderRenderer OakRenderRenderer;
typedef struct OakRenderTexture OakRenderTexture;
/**
* @brief Reference-counted handle to a display renderer
* (olive::Renderer). See the file-level ownership protocol.
*/
typedef struct OakRenderRenderer {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakRenderRenderer;
/**
* @brief Opaque CPU frame handle (refcounted control block around an
* olive::FramePtr). Declared here so the cache family (render/cache.h)
* can use the same type; the frame functions live in this header.
* @brief Reference-counted handle to a GPU texture (olive::Texture).
* See the file-level ownership protocol.
*/
typedef struct OakRenderTexture {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakRenderTexture;
/**
* @brief Reference-counted handle to a CPU frame (an olive::FramePtr
* boxed in a control block). Declared here so the cache family
* (render/cache.h) can use the same type; the frame functions live in
* this header.
* Named OakCodecFrame per the M7 §2.2 contract; the oakcodec wave (M5)
* adopts the same handle.
*/
typedef struct OakCodecFrame OakCodecFrame;
typedef struct OakCodecFrame {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakCodecFrame;
/**
* @brief Flattened POD of olive::ColorTransformJob for the display blit
@@ -99,8 +129,8 @@ typedef struct OakCodecFrame OakCodecFrame;
* means identity.
*/
typedef struct oakrender_color_transform_job {
const void *processor; /**< OakColorProcessor* (borrowed), may be NULL. */
void *input_texture; /**< OakRenderTexture* (borrowed, not retained). */
const void *processor; /**< OakColorProcessor ctx (borrowed), may be NULL. */
void *input_texture; /**< OakRenderTexture ctx (borrowed, not retained). */
int input_alpha_association; /**< 0=none, 1=associated. */
int clear_destination; /**< 0/1. */
int force_opaque; /**< 0/1. */
@@ -115,116 +145,137 @@ typedef struct oakrender_color_transform_job {
* "vulkan"; olive::DynamicRenderer). Loads the backend shared library;
* falls back per DynamicRenderer rules.
*
* @return Renderer handle, or NULL on NULL/empty backend id, load
* failure, or allocation failure.
* @return Renderer handle with reference count 1; ctx is NULL on
* NULL/empty backend id, load failure, or allocation failure.
*/
OakRenderRenderer *oakrender_display_renderer_create_dynamic(
OakRenderRenderer oakrender_display_renderer_create_dynamic(
const char *backend_id);
/**
* @brief Create an OpenGL renderer (olive::OpenGLRenderer). The renderer
* is not initialized; call oakrender_display_renderer_init() before use.
*
* @return Renderer handle, or NULL on allocation failure.
* @return Renderer handle with reference count 1; ctx is NULL on
* allocation failure.
*/
OakRenderRenderer *oakrender_display_renderer_create_opengl(void);
OakRenderRenderer oakrender_display_renderer_create_opengl(void);
/**
* @brief Initialize a renderer. `gl_context` is a borrowed opaque
* olive::OpenGLContext*, or NULL to use the backend's default
* device/context path (Renderer::init()).
*
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (NULL renderer), or
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (empty renderer), or
* OAKRENDER_E_FAILED (backend init failed).
*/
int oakrender_display_renderer_init(OakRenderRenderer *renderer,
int oakrender_display_renderer_init(OakRenderRenderer renderer,
void *gl_context);
/**
* @brief Destroy a renderer (Renderer::destroy() + delete). NULL-safe
* no-op.
* @brief Release one reference to a renderer (the final release runs
* Renderer::destroy() + delete). Convenience wrapper around
* renderer->release(renderer->ctx): NULL / empty-handle no-op; clears
* renderer->ctx after releasing.
*/
void oakrender_display_renderer_destroy(OakRenderRenderer *renderer);
/* ---- Renderer queries ---------------------------------------------------- */
/** @brief 1 when the renderer is OpenGL-based, 0 otherwise / on NULL. */
int oakrender_display_renderer_is_open_gl(const OakRenderRenderer *renderer);
/** @brief 1 when the renderer is OpenGL-based, 0 otherwise / empty. */
int oakrender_display_renderer_is_open_gl(OakRenderRenderer renderer);
/** @brief 1 when the renderer is Vulkan-based, 0 otherwise / on NULL. */
int oakrender_display_renderer_is_vulkan(const OakRenderRenderer *renderer);
/** @brief 1 when the renderer is Vulkan-based, 0 otherwise / empty. */
int oakrender_display_renderer_is_vulkan(OakRenderRenderer renderer);
/* ---- Texture handle (opaque, refcounted) --------------------------------- */
/* ---- Texture handle ------------------------------------------------------ */
/**
* @brief Create a GPU texture on `renderer`.
*
* @param pixels Initial pixel data, or NULL for an uninitialized texture.
* @param linesize Stride of `pixels` in bytes (0 when pixels is NULL).
* @return New texture handle (refcount=1), or NULL on invalid arguments /
* allocation failure.
* @return New texture handle (reference count 1); ctx is NULL on invalid
* arguments / allocation failure.
*/
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);
/** @brief Increment refcount, return the same handle. NULL-safe. */
OakRenderTexture *oakrender_display_texture_retain(OakRenderTexture *texture);
/**
* @brief Take another reference to a texture and return the same handle.
*
* Convenience wrapper around handle.addref(handle.ctx). An empty handle
* in yields an empty handle out. Every retain must be paired with
* exactly one free/release.
*/
OakRenderTexture oakrender_display_texture_retain(OakRenderTexture texture);
/** @brief Decrement refcount; frees at zero. NULL-safe. */
/**
* @brief Release one reference to a texture. Convenience wrapper around
* texture->release(texture->ctx): frees the texture when the count
* reaches zero. NULL / empty-handle no-op; clears texture->ctx after
* releasing.
*/
void oakrender_display_texture_free(OakRenderTexture *texture);
int oakrender_display_texture_upload(OakRenderTexture *texture,
int oakrender_display_texture_upload(OakRenderTexture texture,
const void *pixels, int linesize);
int oakrender_display_texture_download(OakRenderTexture *texture, void *pixels,
int oakrender_display_texture_download(OakRenderTexture texture, void *pixels,
int linesize);
/* ---- Texture queries ----------------------------------------------------- */
int oakrender_display_texture_get_params(const OakRenderTexture *texture,
int oakrender_display_texture_get_params(OakRenderTexture texture,
oakrender_video_params *out);
/** @brief Native texture id (0 on NULL or a dummy/id-less texture). */
int oakrender_display_texture_id(const OakRenderTexture *texture);
/** @brief Native texture id (0 on empty or a dummy/id-less texture). */
int oakrender_display_texture_id(OakRenderTexture texture);
/* ---- Frame handle (opaque, refcounted) ----------------------------------- */
/* ---- Frame handle -------------------------------------------------------- */
/** @brief Create an empty CPU frame. Returns handle (refcount=1). */
OakCodecFrame *oakrender_codec_frame_create(void);
/** @brief Create an empty CPU frame. Returns a handle with count 1. */
OakCodecFrame oakrender_codec_frame_create(void);
/** @brief Increment refcount, return the same handle. NULL-safe. */
OakCodecFrame *oakrender_codec_frame_retain(OakCodecFrame *frame);
/**
* @brief Take another reference to a frame and return the same handle.
* Empty in yields empty out (see oakrender_display_texture_retain()).
*/
OakCodecFrame oakrender_codec_frame_retain(OakCodecFrame frame);
/** @brief Decrement refcount; frees at zero. NULL-safe. */
/**
* @brief Release one reference to a frame. Convenience wrapper around
* frame->release(frame->ctx). NULL / empty-handle no-op; clears
* frame->ctx after releasing.
*/
void oakrender_codec_frame_free(OakCodecFrame *frame);
int oakrender_codec_frame_set_video_params(
OakCodecFrame *frame, const oakrender_video_params *params);
OakCodecFrame frame, const oakrender_video_params *params);
int oakrender_codec_frame_get_params(const OakCodecFrame *frame,
int oakrender_codec_frame_get_params(OakCodecFrame frame,
oakrender_video_params *out);
/**
* @brief Allocate the pixel buffer per the frame's video params
* (Frame::allocate()).
*
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (NULL frame), or
* @return OAKRENDER_OK, OAKRENDER_E_INVALID (empty frame), or
* OAKRENDER_E_FAILED (invalid params / allocation failed).
*/
int oakrender_codec_frame_allocate(OakCodecFrame *frame);
int oakrender_codec_frame_allocate(OakCodecFrame frame);
/** @brief Borrowed pixel data pointer (valid until free). */
void *oakrender_codec_frame_data(OakCodecFrame *frame);
/** @brief Borrowed pixel data pointer (valid until the final release). */
void *oakrender_codec_frame_data(OakCodecFrame frame);
/** @brief Borrowed const pixel data pointer. */
const void *oakrender_codec_frame_const_data(const OakCodecFrame *frame);
const void *oakrender_codec_frame_const_data(OakCodecFrame frame);
/** @brief Line stride in bytes. */
int oakrender_codec_frame_linesize_bytes(const OakCodecFrame *frame);
int oakrender_codec_frame_linesize_bytes(OakCodecFrame frame);
/** @brief 1 when the pixel buffer is allocated, 0 otherwise / on NULL. */
int oakrender_codec_frame_is_allocated(const OakCodecFrame *frame);
/** @brief 1 when the pixel buffer is allocated, 0 otherwise / empty. */
int oakrender_codec_frame_is_allocated(OakCodecFrame frame);
/* ---- Color-managed blit -------------------------------------------------- */
@@ -232,18 +283,18 @@ int oakrender_codec_frame_is_allocated(const OakCodecFrame *frame);
* @brief Blit a color-managed image through the OCIO pipeline
* (Renderer::blit_color_managed()).
*
* @param dst_texture Destination texture handle, or NULL for the current
* output target.
* @param dst_texture Destination texture handle, or an empty handle for
* the current output target.
* @param params Destination video params, or NULL to use dst_texture's.
*/
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);
/* ---- 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);
/* ---- Backend management (M7 §2.1) ---------------------------------------- */
+37 -23
View File
@@ -38,19 +38,29 @@ extern "C" {
#endif
/**
* @brief Opaque handle to a render ticket (olive::RenderTicketWatcher).
* @brief Reference-counted handle to a render ticket
* (olive::RenderTicketWatcher).
*
* Created by oakrender_ticket_render_frame() /
* oakrender_ticket_render_audio(); free with oakrender_ticket_free().
* By-value handle (shared_ptr semantics, see oakcommon's
* common/handle.h). Created by oakrender_ticket_render_frame() /
* oakrender_ticket_render_audio() with reference count 1; release with
* oakrender_ticket_free().
*/
typedef struct OakRenderTicket OakRenderTicket;
typedef struct OakRenderTicket {
void *ctx; /**< Opaque pointer to the reference-counted object. */
void (*addref)(void *ctx); /**< Atomically increments the count. */
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
uint32_t abi_version; /**< OAKRENDER_ABI_VERSION. */
} OakRenderTicket;
/**
* @brief Finished callback (async command return channel, 01 §4
* exception). Fires on the ticket's finishing thread, exactly
* once (cancelled tickets fire with a NULL result).
* once (cancelled tickets fire with a NULL result). The ticket
* handle is a borrowed copy of the submitter's handle; the
* submitter keeps ownership and releases it.
*/
typedef void (*oakrender_ticket_finished_fn)(OakRenderTicket *ticket,
typedef void (*oakrender_ticket_finished_fn)(OakRenderTicket ticket,
void *userdata);
/** @brief Ticket types (RenderManager::TicketType). */
@@ -77,7 +87,7 @@ typedef struct oakrender_video_ticket_params {
int has_force_matrix;
int force_format; /**< PixelFormat as int, -1 = off. */
int force_channel_count; /**< 0 = off. */
OakColorProcessor *force_color_output; /**< May be NULL. */
OakColorProcessor force_color_output; /**< Borrowed; empty ctx = none. */
OakColorTransform force_color_transform; /**< By value; empty ctx = default. */
OakNodeFrameCache *cache; /**< Borrowed frame cache, may be NULL. */
} oakrender_video_ticket_params;
@@ -85,11 +95,12 @@ typedef struct oakrender_video_ticket_params {
/**
* @brief Submit a video frame render ticket.
*
* @return Ticket handle (caller frees), or NULL on failure. The finished
* callback fires exactly once; NULL `cb` is allowed (poll with
* @return Ticket handle with reference count 1 (caller releases); ctx is
* NULL on failure. The finished callback fires exactly once;
* NULL `cb` is allowed (poll with
* oakrender_ticket_wait()/oakrender_ticket_is_finished()).
*/
OakRenderTicket *oakrender_ticket_render_frame(
OakRenderTicket oakrender_ticket_render_frame(
const oakrender_video_ticket_params *params,
oakrender_ticket_finished_fn cb, void *userdata);
@@ -99,48 +110,51 @@ OakRenderTicket *oakrender_ticket_render_frame(
* @param output_node Connected sample output node.
* @param params Audio params (borrowed oakcore handle).
*/
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);
int oakrender_ticket_is_finished(OakRenderTicket *ticket);
int oakrender_ticket_is_finished(OakRenderTicket ticket);
/** @brief Block until the ticket finishes. */
int oakrender_ticket_wait(OakRenderTicket *ticket);
int oakrender_ticket_wait(OakRenderTicket ticket);
int oakrender_ticket_cancel(OakRenderTicket *ticket);
int oakrender_ticket_cancel(OakRenderTicket ticket);
/** @brief OAKRENDER_TICKET_* or negative error. */
int oakrender_ticket_get_type(OakRenderTicket *ticket);
int oakrender_ticket_get_type(OakRenderTicket ticket);
/** @brief Ticket timestamp (video tickets). */
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);
/** @brief Ticket time range (audio tickets). */
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);
/**
* @brief The resulting frame (video tickets). *out receives a retained
* @brief The resulting frame (video tickets). *out receives an owned
* OakCodecFrame (release with oakrender_codec_frame_free()).
* OAKRENDER_E_STATE when unfinished, OAKRENDER_E_FAILED when the
* ticket has no frame result.
*/
int oakrender_ticket_get_frame(OakRenderTicket *ticket,
OakCodecFrame **out);
int oakrender_ticket_get_frame(OakRenderTicket ticket, OakCodecFrame *out);
/**
* @brief The resulting samples (audio tickets). *out receives a copy
* (release with oakcore_samplebuffer_free()).
*/
int oakrender_ticket_get_samples(OakRenderTicket *ticket,
int oakrender_ticket_get_samples(OakRenderTicket ticket,
OakSampleBuffer **out);
/** @brief Free the ticket handle (safe on finished tickets; cancels and
* waits on running ones). No-op on NULL. */
/**
* @brief Release one reference to a ticket (the final release is safe on
* finished tickets; cancels and waits on running ones). Convenience
* wrapper around ticket->release(ticket->ctx). NULL / empty-handle
* no-op; clears ticket->ctx after releasing.
*/
void oakrender_ticket_free(OakRenderTicket *ticket);
/**