refactor(codec): de-Qt oakcodec and wrap it in a pure C ABI; switch common handles to refcounted value structs
- oakcodec: de-Qt all 20 sources (QThread decode loop -> std::thread,
QObject/signals -> callbacks), pure C ABI in include/codec with
refcounted neutral handles (OakFrame/OakDecoder/OakEncoder),
framemanager moved in from render, frame_to_buffer/buffer_to_frame
moved in from oakcommon oiioutils, codec->task via submit callback
(M8 will register), all cross-module calls go through the other
side's C API, -fvisibility=hidden + OAKCODEC_API
- oakcommon: handles become refcounted value structs
{ctx, addref, release, abi_version} (FFmpeg-style), pass-by-value
signatures, free() as release wrapper; init_from_native/get_native
for copyable value objects; OakCommonXxx renamed to OakXxx
- oakcommon: add logging (log_debug/info/warning/critical with level
filtering and sink injection) + printf-style oakcommon_log C wrapper
- oakrender: add CancelAtom C API family; complete
oakrender_color_processor_convert_frame; fix get_processor() missing
definition and OCIO env var lookup
- tests: oakcommon 174, oaknode 96, oakrender 42, oakcodec 18, all
green in their standalone builds
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
target_sources(oakrender PRIVATE
|
||||
renderer.cpp
|
||||
cache.cpp
|
||||
cancelatom.cpp
|
||||
color.cpp
|
||||
manager.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "../../../include/render/cancelatom.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "alivecount.h"
|
||||
|
||||
#include "cancelatom.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Heap box behind every OakCancelAtom's ctx pointer.
|
||||
*
|
||||
* Holds the wrapped CancelAtom plus its atomic reference count. addref
|
||||
* and release are emitted in this translation unit so the function
|
||||
* pointers stored in a handle always run code from the DLL that created
|
||||
* the object.
|
||||
*/
|
||||
struct CancelAtomBox {
|
||||
olive::CancelAtom impl;
|
||||
std::atomic<uint32_t> refs;
|
||||
|
||||
CancelAtomBox()
|
||||
: refs(1)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
CancelAtomBox *box(OakCancelAtom atom)
|
||||
{
|
||||
return static_cast<CancelAtomBox *>(atom.ctx);
|
||||
}
|
||||
|
||||
olive::CancelAtom *impl(OakCancelAtom atom)
|
||||
{
|
||||
auto *b = box(atom);
|
||||
return b ? &b->impl : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle addref thunk: atomically increments the count.
|
||||
*/
|
||||
void cancel_atom_addref(void *ctx)
|
||||
{
|
||||
auto *b = static_cast<CancelAtomBox *>(ctx);
|
||||
if (b)
|
||||
b->refs.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle release thunk: decrements the count, destroys at zero.
|
||||
*/
|
||||
void cancel_atom_release(void *ctx)
|
||||
{
|
||||
auto *b = static_cast<CancelAtomBox *>(ctx);
|
||||
if (b && b->refs.fetch_sub(1, std::memory_order_acq_rel) == 1) {
|
||||
delete b;
|
||||
oakrender_c_api::alive_dec();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OakCancelAtom oakrender_cancelatom_init(void)
|
||||
{
|
||||
OakCancelAtom h = {};
|
||||
try {
|
||||
h.ctx = new CancelAtomBox();
|
||||
} catch (...) {
|
||||
h.ctx = nullptr;
|
||||
}
|
||||
h.addref = &cancel_atom_addref;
|
||||
h.release = &cancel_atom_release;
|
||||
h.abi_version = OAKRENDER_ABI_VERSION;
|
||||
if (h.ctx)
|
||||
oakrender_c_api::alive_inc();
|
||||
return h;
|
||||
}
|
||||
|
||||
void oakrender_cancelatom_free(OakCancelAtom *atom)
|
||||
{
|
||||
if (!atom || !atom->ctx || !atom->release)
|
||||
return;
|
||||
atom->release(atom->ctx);
|
||||
atom->ctx = nullptr;
|
||||
}
|
||||
|
||||
int oakrender_cancelatom_cancel(OakCancelAtom atom)
|
||||
{
|
||||
auto *c = impl(atom);
|
||||
if (!c)
|
||||
return OAKRENDER_E_INVALID;
|
||||
c->cancel();
|
||||
return OAKRENDER_OK;
|
||||
}
|
||||
|
||||
int oakrender_cancelatom_is_cancelled(OakCancelAtom atom, int *cancelled)
|
||||
{
|
||||
auto *c = impl(atom);
|
||||
if (!c || !cancelled)
|
||||
return OAKRENDER_E_INVALID;
|
||||
*cancelled = c->is_cancelled() ? 1 : 0;
|
||||
return OAKRENDER_OK;
|
||||
}
|
||||
|
||||
int oakrender_cancelatom_heard_cancel(OakCancelAtom atom, int *heard)
|
||||
{
|
||||
auto *c = impl(atom);
|
||||
if (!c || !heard)
|
||||
return OAKRENDER_E_INVALID;
|
||||
*heard = c->heard_cancel() ? 1 : 0;
|
||||
return OAKRENDER_OK;
|
||||
}
|
||||
+30
-10
@@ -30,6 +30,7 @@
|
||||
|
||||
#include "color/colormanager/colormanager.h"
|
||||
#include "filefunctions.h"
|
||||
#include <OpenColorIO/OpenColorIO.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -57,7 +58,7 @@ OakColorProcessor *oakrender_color_processor_create(const char *src_space,
|
||||
return nullptr;
|
||||
}
|
||||
try {
|
||||
ocio::ConstConfigRcPtr config = olive::ColorManager::get_default_config();
|
||||
OCIO_NAMESPACE::ConstConfigRcPtr config = olive::ColorManager::get_default_config();
|
||||
if (!config) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -69,17 +70,17 @@ OakColorProcessor *oakrender_color_processor_create(const char *src_space,
|
||||
src = config->getCanonicalName(src_space);
|
||||
}
|
||||
|
||||
// OCIO failures are non-fatal (matching the C++ behavior): the
|
||||
// OCIO_NAMESPACE failures are non-fatal (matching the C++ behavior): the
|
||||
// handle is still returned, but holds a null processor and
|
||||
// conversions pass through.
|
||||
ocio::ConstProcessorRcPtr processor;
|
||||
OCIO_NAMESPACE::ConstProcessorRcPtr processor;
|
||||
try {
|
||||
if (direction == OAKRENDER_COLOR_DIRECTION_NORMAL) {
|
||||
processor = config->getProcessor(src.c_str(), dst_transform);
|
||||
} else {
|
||||
processor = config->getProcessor(dst_transform, src.c_str());
|
||||
}
|
||||
} catch (ocio::Exception &) {
|
||||
} catch (OCIO_NAMESPACE::Exception &) {
|
||||
processor = nullptr;
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ int oakrender_color_manager_display_transform(const char *display,
|
||||
return OAKRENDER_E_INVALID;
|
||||
}
|
||||
try {
|
||||
ocio::ConstConfigRcPtr config = olive::ColorManager::get_default_config();
|
||||
OCIO_NAMESPACE::ConstConfigRcPtr config = olive::ColorManager::get_default_config();
|
||||
if (!config) {
|
||||
return OAKRENDER_E_STATE;
|
||||
}
|
||||
@@ -197,25 +198,44 @@ int oakrender_color_manager_display_transform(const char *display,
|
||||
}
|
||||
|
||||
// Source = the config's reference colorspace (role lookup).
|
||||
ocio::ConstColorSpaceRcPtr ref_cs =
|
||||
config->getColorSpace(ocio::ROLE_REFERENCE);
|
||||
OCIO_NAMESPACE::ConstColorSpaceRcPtr ref_cs =
|
||||
config->getColorSpace(OCIO_NAMESPACE::ROLE_REFERENCE);
|
||||
if (!ref_cs) {
|
||||
return OAKRENDER_E_STATE;
|
||||
}
|
||||
|
||||
auto dvt = ocio::DisplayViewTransform::Create();
|
||||
auto dvt = OCIO_NAMESPACE::DisplayViewTransform::Create();
|
||||
dvt->setSrc(ref_cs->getName());
|
||||
dvt->setDisplay(display);
|
||||
dvt->setView(view);
|
||||
|
||||
ocio::ConstProcessorRcPtr processor = config->getProcessor(dvt);
|
||||
OCIO_NAMESPACE::ConstProcessorRcPtr processor = config->getProcessor(dvt);
|
||||
if (!processor) {
|
||||
return OAKRENDER_E_NOT_FOUND;
|
||||
}
|
||||
return write_string(processor->getCacheID(), buf, n);
|
||||
} catch (ocio::Exception &) {
|
||||
} catch (OCIO_NAMESPACE::Exception &) {
|
||||
return OAKRENDER_E_NOT_FOUND;
|
||||
} catch (...) {
|
||||
return OAKRENDER_E_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
int oakrender_color_processor_convert_frame(OakColorProcessor *processor,
|
||||
OakCodecFrame *frame)
|
||||
{
|
||||
if (!processor || !processor->ptr || !frame || !frame->ptr) {
|
||||
return OAKRENDER_E_INVALID;
|
||||
}
|
||||
try {
|
||||
// In-place: ColorProcessor::convert_frame() applies the CPU
|
||||
// processor to the frame's pixel buffer through an
|
||||
// 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);
|
||||
return OAKRENDER_OK;
|
||||
} catch (...) {
|
||||
return OAKRENDER_E_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user