refactor(render): de-Qt oakrender and wrap it in a pure C ABI
- copy engine/render to src/render/src (sunk param types excluded), de-Qt in five parallel groups: core machinery (tickets/worker pool/ jobs), caches, color/texture, preview/IPC, GPU backends - replace Qt GL/Vulkan wrappers with native context abstractions (CGL/EGL/WGL, raw vulkan.h), QProcess with POSIX WorkerProcess, QJsonObject with a minimal NDJSON-compatible workerjson (wire protocol unchanged), QDataStream disk state with a byte-compatible BinaryStream - signals become single std::function callbacks or facade-triggered calls per the documented signal/slot strategy - pure C ABI in include/render + src/render/c_api (renderer/cache/ color/manager families, OAKRENDER_E_* codes), 37 gtest cases - bridge src/node/transition/render/* stubs to the real oakrender headers, closing the node<->render cycle: liboaknode links liboakrender, zero dangling symbols - docs: M7 implementation status + oakrender semantic-change notes
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
// Transitional: engine/audio/audiovisualwaveform.h de-Qt target form
|
||||
// (oakaudio contract, M6). Data-only surface used by oakrender: the Sample
|
||||
// reduction types plus the writers renderprocessor/audiowaveformcache call.
|
||||
// QPainter-based draw_sample() stays in the app layer.
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "olive/core/render/samplebuffer.h"
|
||||
#include "olive/core/util/rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using core::Rational;
|
||||
using core::SampleBuffer;
|
||||
|
||||
class AudioVisualWaveform {
|
||||
public:
|
||||
struct SamplePerChannel {
|
||||
float min;
|
||||
float max;
|
||||
};
|
||||
|
||||
using Sample = std::vector<SamplePerChannel>;
|
||||
|
||||
// Same value as the engine original (audiovisualwaveform.cpp)
|
||||
inline static const Rational k_minimum_sample_rate = Rational(1, 8);
|
||||
|
||||
int channel_count() const { return int(channels_.size()); }
|
||||
|
||||
void set_channel_count(int channels) { channels_.resize(size_t(channels)); }
|
||||
|
||||
void overwrite_samples(const SampleBuffer &samples, int sample_rate,
|
||||
bool /*from_maximum*/ = false)
|
||||
{
|
||||
(void) samples;
|
||||
(void) sample_rate;
|
||||
}
|
||||
|
||||
Sample get_summary_from_time(const Rational &, const Rational &) const
|
||||
{
|
||||
return Sample();
|
||||
}
|
||||
|
||||
static Sample sum_samples(const SampleBuffer &, size_t, size_t)
|
||||
{
|
||||
return Sample();
|
||||
}
|
||||
|
||||
static Sample re_sum_samples(const SamplePerChannel *, int, int)
|
||||
{
|
||||
return Sample();
|
||||
}
|
||||
|
||||
const Rational &length() const { return length_; }
|
||||
|
||||
// Simplified stub-model version of the engine writer: the real
|
||||
// implementation walks mipmapped rates; here sums are merged 1:1 per
|
||||
// channel at sample granularity (dest/offset in the same time base).
|
||||
void overwrite_sums(const AudioVisualWaveform &sums, const Rational &dest,
|
||||
const Rational &offset = 0, const Rational &length = 0)
|
||||
{
|
||||
size_t our_start = size_t(dest.to_double());
|
||||
size_t their_start = size_t(offset.to_double());
|
||||
size_t count = length.to_double() > 0
|
||||
? size_t(length.to_double())
|
||||
: SIZE_MAX;
|
||||
for (size_t ch = 0; ch < channels_.size() &&
|
||||
ch < sums.channels_.size();
|
||||
ch++) {
|
||||
Sample &our_arr = channels_[ch];
|
||||
const Sample &their_arr = sums.channels_[ch];
|
||||
if (our_start + count > our_arr.size()) {
|
||||
our_arr.resize(our_start + (count == SIZE_MAX ? their_arr.size() - their_start : count));
|
||||
}
|
||||
for (size_t i = 0; i < count &&
|
||||
their_start + i < their_arr.size() &&
|
||||
our_start + i < our_arr.size();
|
||||
i++) {
|
||||
our_arr[our_start + i] = their_arr[their_start + i];
|
||||
}
|
||||
}
|
||||
Rational end = dest + (length.to_double() > 0 ? length : Rational());
|
||||
if (end > length_) {
|
||||
length_ = end;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Sample> channels_;
|
||||
Rational length_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
#pragma once
|
||||
// Transitional: QDataStream replacement for the render disk-cache state and
|
||||
// index files. Mirrors QDataStream's default (big-endian) wire format for the
|
||||
// subset of types those files use, so existing cache files stay readable:
|
||||
// quint32/qint32/qint64 -> big-endian bytes
|
||||
// bool -> quint8
|
||||
// QString -> quint32 byte length + UTF-16BE code units
|
||||
// QUuid -> 16 raw bytes in RFC 4122 order
|
||||
// Reads past EOF yield zeroed values (QDataStream::ReadPastEnd semantics).
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
namespace binarystream_detail
|
||||
{
|
||||
|
||||
inline void append_utf16be(std::string &out, uint32_t cp)
|
||||
{
|
||||
if (cp >= 0x10000) {
|
||||
cp -= 0x10000;
|
||||
uint16_t hi = 0xD800 + (cp >> 10);
|
||||
uint16_t lo = 0xDC00 + (cp & 0x3FF);
|
||||
out += char(hi >> 8);
|
||||
out += char(hi & 0xFF);
|
||||
out += char(lo >> 8);
|
||||
out += char(lo & 0xFF);
|
||||
} else {
|
||||
out += char(cp >> 8);
|
||||
out += char(cp & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string utf8_to_utf16be(const std::string &s)
|
||||
{
|
||||
std::string out;
|
||||
size_t i = 0;
|
||||
while (i < s.size()) {
|
||||
unsigned char c = s[i];
|
||||
uint32_t cp;
|
||||
size_t extra;
|
||||
if (c < 0x80) {
|
||||
cp = c;
|
||||
extra = 0;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
cp = c & 0x1F;
|
||||
extra = 1;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
cp = c & 0x0F;
|
||||
extra = 2;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
cp = c & 0x07;
|
||||
extra = 3;
|
||||
} else {
|
||||
// Invalid byte, emit U+FFFD like Qt's UTF-8 handling
|
||||
cp = 0xFFFD;
|
||||
extra = 0;
|
||||
}
|
||||
for (size_t j = 0; j < extra; j++) {
|
||||
if (i + 1 < s.size()) {
|
||||
cp = (cp << 6) | (uint8_t(s[i + 1]) & 0x3F);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
append_utf16be(out, cp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
inline void append_utf8(std::string &out, uint32_t cp)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
out += char(cp);
|
||||
} else if (cp < 0x800) {
|
||||
out += char(0xC0 | (cp >> 6));
|
||||
out += char(0x80 | (cp & 0x3F));
|
||||
} else if (cp < 0x10000) {
|
||||
out += char(0xE0 | (cp >> 12));
|
||||
out += char(0x80 | ((cp >> 6) & 0x3F));
|
||||
out += char(0x80 | (cp & 0x3F));
|
||||
} else {
|
||||
out += char(0xF0 | (cp >> 18));
|
||||
out += char(0x80 | ((cp >> 12) & 0x3F));
|
||||
out += char(0x80 | ((cp >> 6) & 0x3F));
|
||||
out += char(0x80 | (cp & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string utf16be_to_utf8(const std::string &be)
|
||||
{
|
||||
std::string out;
|
||||
size_t units = be.size() / 2;
|
||||
for (size_t i = 0; i < units; i++) {
|
||||
uint16_t u = (uint8_t(be[i * 2]) << 8) | uint8_t(be[i * 2 + 1]);
|
||||
uint32_t cp = u;
|
||||
if (u >= 0xD800 && u < 0xDC00 && i + 1 < units) {
|
||||
uint16_t lo = (uint8_t(be[i * 2 + 2]) << 8) |
|
||||
uint8_t(be[i * 2 + 3]);
|
||||
if (lo >= 0xDC00 && lo < 0xE000) {
|
||||
cp = 0x10000 + ((uint32_t(u) - 0xD800) << 10) + (lo - 0xDC00);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
append_utf8(out, cp);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
inline int hex_digit(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace binarystream_detail
|
||||
|
||||
class BinaryStreamWriter {
|
||||
public:
|
||||
explicit BinaryStreamWriter(std::FILE *f)
|
||||
: f_(f)
|
||||
{
|
||||
}
|
||||
|
||||
BinaryStreamWriter &operator<<(uint32_t v)
|
||||
{
|
||||
write_be(v, 4);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamWriter &operator<<(int32_t v)
|
||||
{
|
||||
write_be(uint32_t(v), 4);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamWriter &operator<<(int64_t v)
|
||||
{
|
||||
write_be(uint64_t(v), 8);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamWriter &operator<<(bool v)
|
||||
{
|
||||
write_be(v ? 1 : 0, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// QString: quint32 byte length + UTF-16BE data
|
||||
BinaryStreamWriter &operator<<(const std::string &v)
|
||||
{
|
||||
std::string be = binarystream_detail::utf8_to_utf16be(v);
|
||||
write_be(uint32_t(be.size()), 4);
|
||||
if (!be.empty()) {
|
||||
std::fwrite(be.data(), 1, be.size(), f_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// QUuid: 16 raw bytes in RFC 4122 order. Accepts the canonical text form
|
||||
// "{8-4-4-4-12}" (braces optional), which is what cache uuids are stored as.
|
||||
void write_uuid_text(const std::string &uuid_text)
|
||||
{
|
||||
uint8_t bytes[16] = { 0 };
|
||||
int nibble = 0;
|
||||
for (char c : uuid_text) {
|
||||
if (c == '{' || c == '}' || c == '-') {
|
||||
continue;
|
||||
}
|
||||
if (nibble >= 32) {
|
||||
break;
|
||||
}
|
||||
int d = binarystream_detail::hex_digit(c);
|
||||
if (nibble % 2 == 0) {
|
||||
bytes[nibble / 2] = uint8_t(d << 4);
|
||||
} else {
|
||||
bytes[nibble / 2] |= uint8_t(d);
|
||||
}
|
||||
nibble++;
|
||||
}
|
||||
std::fwrite(bytes, 1, 16, f_);
|
||||
}
|
||||
|
||||
private:
|
||||
void write_be(uint64_t v, int bytes)
|
||||
{
|
||||
uint8_t b[8];
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
b[i] = uint8_t(v >> ((bytes - 1 - i) * 8));
|
||||
}
|
||||
std::fwrite(b, 1, bytes, f_);
|
||||
}
|
||||
|
||||
std::FILE *f_;
|
||||
};
|
||||
|
||||
class BinaryStreamReader {
|
||||
public:
|
||||
explicit BinaryStreamReader(std::FILE *f)
|
||||
: f_(f)
|
||||
{
|
||||
}
|
||||
|
||||
BinaryStreamReader &operator>>(uint32_t &v)
|
||||
{
|
||||
v = uint32_t(read_be(4));
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamReader &operator>>(int32_t &v)
|
||||
{
|
||||
v = int32_t(read_be(4));
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamReader &operator>>(int64_t &v)
|
||||
{
|
||||
v = int64_t(read_be(8));
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamReader &operator>>(bool &v)
|
||||
{
|
||||
v = read_be(1) != 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
BinaryStreamReader &operator>>(std::string &v)
|
||||
{
|
||||
uint32_t len = uint32_t(read_be(4));
|
||||
v.clear();
|
||||
if (len == 0xFFFFFFFF || len == 0) {
|
||||
return *this;
|
||||
}
|
||||
std::string be(len, '\0');
|
||||
size_t got = std::fread(&be[0], 1, len, f_);
|
||||
be.resize(got);
|
||||
v = binarystream_detail::utf16be_to_utf8(be);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// QUuid: 16 raw bytes -> canonical "{8-4-4-4-12}" lowercase text
|
||||
std::string read_uuid_text()
|
||||
{
|
||||
uint8_t bytes[16] = { 0 };
|
||||
std::fread(bytes, 1, 16, f_);
|
||||
|
||||
static const char k_hex[] = "0123456789abcdef";
|
||||
std::string out;
|
||||
out.reserve(38);
|
||||
out += '{';
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (i == 4 || i == 6 || i == 8 || i == 10) {
|
||||
out += '-';
|
||||
}
|
||||
out += k_hex[bytes[i] >> 4];
|
||||
out += k_hex[bytes[i] & 0xF];
|
||||
}
|
||||
out += '}';
|
||||
return out;
|
||||
}
|
||||
|
||||
bool at_end() const
|
||||
{
|
||||
int c = std::fgetc(f_);
|
||||
if (c == EOF) {
|
||||
return true;
|
||||
}
|
||||
std::ungetc(c, f_);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t read_be(int bytes)
|
||||
{
|
||||
uint8_t b[8] = { 0 };
|
||||
std::fread(b, 1, bytes, f_);
|
||||
uint64_t v = 0;
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
v = (v << 8) | b[i];
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::FILE *f_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
// Transitional: engine/codec/decoder.h de-Qt target form (oakcodec contract,
|
||||
// M5). Covers the Decoder/DecoderCache-facing surface the render core uses:
|
||||
// stream identification, open/close, video/audio retrieval and access-time
|
||||
// bookkeeping. CodecStream gains operator< because de-Qt RenderCache is
|
||||
// std::map-based (QHash used qHash before).
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "loopmode.h"
|
||||
#include "rendermodes.h"
|
||||
#include "cancelatom.h"
|
||||
#include "codec/frame.h"
|
||||
#include "project/footage/footagedescription.h"
|
||||
#include "olive/core/render/audioparams.h"
|
||||
#include "olive/core/render/samplebuffer.h"
|
||||
#include "olive/core/util/rational.h"
|
||||
#include "olive/core/util/timerange.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using core::AudioParams;
|
||||
using core::Rational;
|
||||
using core::SampleBuffer;
|
||||
using core::TimeRange;
|
||||
|
||||
class Block;
|
||||
class Renderer;
|
||||
class Texture;
|
||||
using TexturePtr = std::shared_ptr<Texture>;
|
||||
|
||||
class Decoder;
|
||||
using DecoderPtr = std::shared_ptr<Decoder>;
|
||||
|
||||
class Decoder {
|
||||
public:
|
||||
virtual ~Decoder() = default;
|
||||
|
||||
class CodecStream {
|
||||
public:
|
||||
CodecStream()
|
||||
: stream_(-1)
|
||||
, block_(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CodecStream(const std::string &filename, int stream, Block *block)
|
||||
: filename_(filename)
|
||||
, stream_(stream)
|
||||
, block_(block)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_valid() const { return !filename_.empty() && stream_ >= 0; }
|
||||
|
||||
void reset() { *this = CodecStream(); }
|
||||
|
||||
bool operator==(const CodecStream &rhs) const
|
||||
{
|
||||
return filename_ == rhs.filename_ && stream_ == rhs.stream_;
|
||||
}
|
||||
|
||||
bool operator<(const CodecStream &rhs) const
|
||||
{
|
||||
if (filename_ != rhs.filename_) {
|
||||
return filename_ < rhs.filename_;
|
||||
}
|
||||
return stream_ < rhs.stream_;
|
||||
}
|
||||
|
||||
const std::string &filename() const { return filename_; }
|
||||
int stream() const { return stream_; }
|
||||
Block *block() const { return block_; }
|
||||
|
||||
private:
|
||||
std::string filename_;
|
||||
int stream_;
|
||||
Block *block_;
|
||||
};
|
||||
|
||||
bool open(const CodecStream &) { return false; }
|
||||
void close() {}
|
||||
|
||||
// Same value as the engine original (decoder.cpp): RATIONAL_MIN.
|
||||
// inline because this stub is header-only.
|
||||
inline static const Rational k_any_timecode = RATIONAL_MIN;
|
||||
|
||||
struct RetrieveVideoParams {
|
||||
Renderer *renderer = nullptr;
|
||||
Rational time;
|
||||
int divider = 1;
|
||||
PixelFormat maximum_format = PixelFormat::invalid;
|
||||
CancelAtom *cancelled = nullptr;
|
||||
VideoParams::ColorRange force_range = VideoParams::k_color_range_default;
|
||||
VideoParams::Interlacing src_interlacing = VideoParams::k_interlace_none;
|
||||
};
|
||||
|
||||
TexturePtr retrieve_video(const RetrieveVideoParams &) { return nullptr; }
|
||||
FramePtr retrieve_video_frame(const RetrieveVideoParams &) { return nullptr; }
|
||||
|
||||
enum RetrieveAudioStatus {
|
||||
k_invalid = -1,
|
||||
k_ok,
|
||||
k_waiting_for_conform,
|
||||
k_unknown_error
|
||||
};
|
||||
|
||||
RetrieveAudioStatus retrieve_audio(SampleBuffer &, const TimeRange &,
|
||||
const AudioParams &,
|
||||
const std::string &, LoopMode,
|
||||
RenderMode::Mode)
|
||||
{
|
||||
return k_invalid;
|
||||
}
|
||||
|
||||
int64_t get_last_accessed_time() { return 0; }
|
||||
void increment_access_time(int64_t) {}
|
||||
|
||||
static DecoderPtr create_from_id(const std::string &) { return nullptr; }
|
||||
|
||||
// oaknode 侧契约(footage.cpp 探针路径)
|
||||
static std::vector<DecoderPtr> receive_list_of_all_decoders() { return {}; }
|
||||
|
||||
FootageDescription probe(const std::string &, CancelAtom *)
|
||||
{
|
||||
return FootageDescription();
|
||||
}
|
||||
|
||||
static std::string
|
||||
transform_image_sequence_file_name(const std::string &filename,
|
||||
int64_t frame_number)
|
||||
{
|
||||
(void) frame_number;
|
||||
return filename;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
// Transitional: engine/codec/frame.h de-Qt target form (oakcodec contract,
|
||||
// M5). Covers the surface the render core uses. Based on
|
||||
// src/node/transition/codec/frame.h, extended with the frame-allocation and
|
||||
// linesize API renderprocessor/renderworkerpool call.
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "videoparams.h"
|
||||
#include "olive/core/util/color.h"
|
||||
#include "olive/core/util/rational.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
using core::Color;
|
||||
using core::Rational;
|
||||
|
||||
class Frame;
|
||||
using FramePtr = std::shared_ptr<Frame>;
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
static FramePtr create() { return std::make_shared<Frame>(); }
|
||||
|
||||
static int generate_linesize_bytes(int width, PixelFormat format,
|
||||
int channel_count)
|
||||
{
|
||||
(void) width; (void) format; (void) channel_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_allocated() const { return false; }
|
||||
bool allocate() { return false; }
|
||||
char *data() { return nullptr; }
|
||||
const char *const_data() const { return nullptr; }
|
||||
int64_t allocated_size() const { return 0; }
|
||||
int width() const { return 0; }
|
||||
int height() const { return 0; }
|
||||
PixelFormat format() const { return PixelFormat::invalid; }
|
||||
int channel_count() const { return 0; }
|
||||
int linesize_bytes() const { return 0; }
|
||||
int linesize_pixels() const { return 0; }
|
||||
void set_pixel(int, int, const Color &) {}
|
||||
|
||||
const Rational ×tamp() const
|
||||
{
|
||||
static const Rational r;
|
||||
return r;
|
||||
}
|
||||
void set_timestamp(const Rational &) {}
|
||||
|
||||
const VideoParams &video_params() const
|
||||
{
|
||||
static VideoParams p;
|
||||
return p;
|
||||
}
|
||||
void set_video_params(const VideoParams &) {}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
// Transitional copy of engine/common/avframeptr.h(本身已无 Qt,待下沉 oakcommon)。只增不删。
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2022 Olive Team
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_AVFRAMEPTR_H
|
||||
#define OAK_AVFRAMEPTR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <ffmpeg_bridge/ffmpeg_bridge.h>
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief C++ adapter around the ffmpeg_bridge frame handle
|
||||
*
|
||||
* Mirrors the AVFrame field access the codebase used to perform directly,
|
||||
* but every operation goes through the pure C bridge API so the editor
|
||||
* never touches FFmpeg itself. The underlying frame object always lives
|
||||
* inside the bridge library.
|
||||
*/
|
||||
class AVFrame {
|
||||
public:
|
||||
AVFrame() :
|
||||
handle_(fb_frame_alloc())
|
||||
{
|
||||
}
|
||||
|
||||
explicit AVFrame(FBFrame *handle) :
|
||||
handle_(handle)
|
||||
{
|
||||
}
|
||||
|
||||
~AVFrame()
|
||||
{
|
||||
if (handle_) {
|
||||
fb_frame_free(&handle_);
|
||||
}
|
||||
}
|
||||
|
||||
AVFrame(const AVFrame &) = delete;
|
||||
AVFrame &operator=(const AVFrame &) = delete;
|
||||
|
||||
FBFrame *handle() const { return handle_; }
|
||||
|
||||
int width() const { return fb_frame_get_width(handle_); }
|
||||
void set_width(int w) { fb_frame_set_width(handle_, w); }
|
||||
int height() const { return fb_frame_get_height(handle_); }
|
||||
void set_height(int h) { fb_frame_set_height(handle_, h); }
|
||||
int format() const { return fb_frame_get_format(handle_); }
|
||||
void set_format(int f) { fb_frame_set_format(handle_, f); }
|
||||
int64_t pts() const { return fb_frame_get_pts(handle_); }
|
||||
void set_pts(int64_t p) { fb_frame_set_pts(handle_, p); }
|
||||
int64_t best_effort_timestamp() const
|
||||
{
|
||||
return fb_frame_get_best_effort_timestamp(handle_);
|
||||
}
|
||||
int nb_samples() const { return fb_frame_get_nb_samples(handle_); }
|
||||
void set_nb_samples(int n) { fb_frame_set_nb_samples(handle_, n); }
|
||||
int sample_rate() const { return fb_frame_get_sample_rate(handle_); }
|
||||
void set_sample_rate(int r) { fb_frame_set_sample_rate(handle_, r); }
|
||||
int color_range() const { return fb_frame_get_color_range(handle_); }
|
||||
void set_color_range(int r) { fb_frame_set_color_range(handle_, r); }
|
||||
int colorspace() const { return fb_frame_get_colorspace(handle_); }
|
||||
void set_colorspace(int cs) { fb_frame_set_colorspace(handle_, cs); }
|
||||
uint64_t channel_layout_mask() const
|
||||
{
|
||||
return fb_frame_get_channel_layout_mask(handle_);
|
||||
}
|
||||
void set_channel_layout_mask(uint64_t m)
|
||||
{
|
||||
fb_frame_set_channel_layout_mask(handle_, m);
|
||||
}
|
||||
|
||||
bool is_hw() const { return fb_frame_is_hw(handle_) != 0; }
|
||||
int hw_transfer_data(const AVFrame *src)
|
||||
{
|
||||
return fb_frame_hw_transfer_data(handle_, src->handle_);
|
||||
}
|
||||
int get_buffer(int align) { return fb_frame_get_buffer(handle_, align); }
|
||||
int make_writable() { return fb_frame_make_writable(handle_); }
|
||||
|
||||
uint8_t *data(int plane) { return fb_frame_get_data(handle_, plane); }
|
||||
const uint8_t *data(int plane) const
|
||||
{
|
||||
return fb_frame_get_data_const(handle_, plane);
|
||||
}
|
||||
void set_data(int plane, uint8_t *d)
|
||||
{
|
||||
fb_frame_set_data(handle_, plane, d);
|
||||
}
|
||||
int linesize(int plane) const
|
||||
{
|
||||
return fb_frame_get_linesize(handle_, plane);
|
||||
}
|
||||
void set_linesize(int plane, int l)
|
||||
{
|
||||
fb_frame_set_linesize(handle_, plane, l);
|
||||
}
|
||||
|
||||
private:
|
||||
FBFrame *handle_;
|
||||
};
|
||||
|
||||
using AVFramePtr = std::shared_ptr<AVFrame>;
|
||||
|
||||
inline AVFramePtr create_av_frame_ptr(FBFrame *f)
|
||||
{
|
||||
return std::make_shared<AVFrame>(f);
|
||||
}
|
||||
|
||||
inline AVFramePtr create_av_frame_ptr()
|
||||
{
|
||||
return std::make_shared<AVFrame>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_AVFRAMEPTR_H
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
// Transitional: engine/common/cancelableobject.h de-Qt target form. Header-only
|
||||
// in the original; the only Qt dependency was the transitively included
|
||||
// render/cancelatom.h, which oakrender provides for real. M-common folds this
|
||||
// into oakcommon; until then this contract matches the original 1:1.
|
||||
#include "cancelatom.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class CancelableObject {
|
||||
public:
|
||||
CancelableObject() {}
|
||||
|
||||
virtual ~CancelableObject() = default;
|
||||
|
||||
void cancel()
|
||||
{
|
||||
cancel_.cancel();
|
||||
CancelEvent();
|
||||
}
|
||||
|
||||
CancelAtom *get_cancel_atom() { return &cancel_; }
|
||||
|
||||
bool is_cancelled() { return cancel_.is_cancelled(); }
|
||||
|
||||
protected:
|
||||
virtual void CancelEvent() {}
|
||||
|
||||
private:
|
||||
CancelAtom cancel_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
// Transitional: engine/common/jobtime.h de-Qt target form. Original kept a
|
||||
// process-global mutex-protected counter; the atomic below preserves the same
|
||||
// monotonic-unique semantics. oakcommon has no jobtime.h yet (M-common folds
|
||||
// it in); renderjobtracker.h includes "common/jobtime.h".
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace olive {
|
||||
|
||||
class JobTime {
|
||||
public:
|
||||
JobTime() { acquire(); }
|
||||
|
||||
void acquire()
|
||||
{
|
||||
static std::atomic<uint64_t> index{ 0 };
|
||||
value_ = index.fetch_add(1, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
uint64_t value() const { return value_; }
|
||||
|
||||
bool operator==(const JobTime &rhs) const { return value_ == rhs.value_; }
|
||||
bool operator!=(const JobTime &rhs) const { return value_ != rhs.value_; }
|
||||
bool operator<(const JobTime &rhs) const { return value_ < rhs.value_; }
|
||||
bool operator>(const JobTime &rhs) const { return value_ > rhs.value_; }
|
||||
bool operator<=(const JobTime &rhs) const { return value_ <= rhs.value_; }
|
||||
bool operator>=(const JobTime &rhs) const { return value_ >= rhs.value_; }
|
||||
|
||||
private:
|
||||
uint64_t value_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
// Transitional stub for engine/config/config.h (still Qt-based, config 未拆分).
|
||||
// Union of the src/node/transition stub and the render-facing surface:
|
||||
// keeps the OAK_CONFIG* call shape; values are inert defaults until the
|
||||
// config milestone wires the real store. operator[] returns a stored
|
||||
// reference so writes (lutlibrary) compile; nothing is persisted. 只增不删。
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "variant.h"
|
||||
#ifndef QStringLiteral
|
||||
#define QStringLiteral(x) x
|
||||
#endif
|
||||
namespace olive {
|
||||
class ConfigValue : public olive::Variant {
|
||||
public:
|
||||
ConfigValue() = default;
|
||||
ConfigValue(const std::string &s) : olive::Variant(s) {}
|
||||
ConfigValue &operator=(const std::string &s)
|
||||
{
|
||||
olive::Variant::operator=(olive::Variant(s));
|
||||
return *this;
|
||||
}
|
||||
bool toBool() const { return to_bool(); }
|
||||
int toInt() const { return to_int(); }
|
||||
uint64_t toULongLong() const { return to_u_long_long(); }
|
||||
// rendermanager reads the graphics backend name through this
|
||||
std::string toString() const { return to_string(); }
|
||||
std::vector<std::string> toStringList() const { return to_string_list(); }
|
||||
};
|
||||
class Config {
|
||||
public:
|
||||
static Config ¤t() { static Config c; return c; }
|
||||
ConfigValue &operator[](const std::string &key) { return values_[key]; }
|
||||
private:
|
||||
std::map<std::string, ConfigValue> values_;
|
||||
};
|
||||
}
|
||||
#ifndef OAK_CONFIG
|
||||
#define OAK_CONFIG(x) Config::current()[x]
|
||||
#endif
|
||||
#ifndef OAK_CONFIG_STR
|
||||
#define OAK_CONFIG_STR(x) Config::current()[x]
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
// Transitional: engine/coreengine.h belongs to the facade layer and is not
|
||||
// available to the de-Qt render/node libraries. Union of the surfaces
|
||||
// oakrender (warn_cache_full, diskmanager.cpp) and oaknode (undo_stack,
|
||||
// timecode display, clipboard) use; the real implementation lives on the
|
||||
// facade side. Superset of the former src/node/transition stub.
|
||||
#include <string>
|
||||
|
||||
#include "olive/core/util/timecodefunctions.h"
|
||||
#include "undostack.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
|
||||
class EngineCore {
|
||||
public:
|
||||
static EngineCore *instance()
|
||||
{
|
||||
static EngineCore e;
|
||||
return &e;
|
||||
}
|
||||
|
||||
void warn_cache_full()
|
||||
{
|
||||
}
|
||||
|
||||
core::Timecode::Display get_timecode_display() const
|
||||
{
|
||||
return core::Timecode::k_timecode_seconds;
|
||||
}
|
||||
|
||||
UndoStack *undo_stack()
|
||||
{
|
||||
return &undo_stack_;
|
||||
}
|
||||
|
||||
static void copy_string_to_clipboard(const std::string &) {}
|
||||
static std::string paste_string_from_clipboard() { return std::string(); }
|
||||
|
||||
private:
|
||||
UndoStack undo_stack_;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
// Transitional stub for engine/pluginSupport/oliveclip.h (real header still
|
||||
// Qt-based, M9 处理). Only the surface render/plugin uses, with de-Qt'd
|
||||
// boundary types (std::string / olive::VideoParams / TexturePtr). OFX
|
||||
// HostSupport 交互签名一行不改。只增不删。
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "ofxhImageEffect.h"
|
||||
#include "ofxImageEffect.h"
|
||||
|
||||
#include "videoparams.h"
|
||||
#include "render/texture.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
namespace plugin
|
||||
{
|
||||
|
||||
class OliveClipInstance : public OFX::Host::ImageEffect::ClipInstance {
|
||||
public:
|
||||
OFX::Host::ImageEffect::Image *getOutputImage(OfxTime time)
|
||||
{
|
||||
(void) time;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string &getUnmappedComponents() const override
|
||||
{
|
||||
static const std::string s;
|
||||
return s;
|
||||
}
|
||||
|
||||
OFX::Host::ImageEffect::Image *
|
||||
getImage(OfxTime time, const OfxRectD *optional_bounds) override
|
||||
{
|
||||
(void) time;
|
||||
(void) optional_bounds;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setRegionOfDefinition(OfxRectD region_of_definition, OfxTime time)
|
||||
{
|
||||
(void) region_of_definition;
|
||||
(void) time;
|
||||
}
|
||||
|
||||
void setParams(const VideoParams ¶ms)
|
||||
{
|
||||
(void) params;
|
||||
}
|
||||
|
||||
void setInputTexture(TexturePtr texture, OfxTime time,
|
||||
bool readback = true)
|
||||
{
|
||||
(void) texture;
|
||||
(void) time;
|
||||
(void) readback;
|
||||
}
|
||||
|
||||
void setOutputTexture(TexturePtr texture, OfxTime time)
|
||||
{
|
||||
(void) texture;
|
||||
(void) time;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
// Transitional stub for engine/pluginSupport/oliveplugininstance.h (real
|
||||
// header still Qt-based, M9 处理). Only the surface render/plugin uses, with
|
||||
// de-Qt'd boundary types. OFX HostSupport 交互签名一行不改。只增不删。
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "ofxhImageEffect.h"
|
||||
|
||||
#include "videoparams.h"
|
||||
|
||||
namespace olive
|
||||
{
|
||||
namespace plugin
|
||||
{
|
||||
|
||||
class PluginNode;
|
||||
|
||||
class OlivePluginInstance : public OFX::Host::ImageEffect::Instance {
|
||||
public:
|
||||
void setVideoParam(VideoParams params)
|
||||
{
|
||||
(void) params;
|
||||
}
|
||||
|
||||
// oaknode 侧契约(plugin.cpp)
|
||||
void setNode(std::shared_ptr<PluginNode> node)
|
||||
{
|
||||
node_ = node;
|
||||
}
|
||||
|
||||
std::shared_ptr<PluginNode> node() const
|
||||
{
|
||||
return node_;
|
||||
}
|
||||
|
||||
void setOpenGLEnabled(bool enabled)
|
||||
{
|
||||
(void) enabled;
|
||||
}
|
||||
|
||||
bool isCreated() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int getNClips() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OFX::Host::ImageEffect::ClipInstance *getNthClip(int i)
|
||||
{
|
||||
(void) i;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::mutex &mutex()
|
||||
{
|
||||
return mutex_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::shared_ptr<PluginNode> node_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/backend/renderbackend_c.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/backend/renderbackend_c.h).
|
||||
#include "../../../src/backend/renderbackend_c.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
// Bridge: oaknode still includes "render/colorprocessor.h". Route it to the
|
||||
// real de-Qt oakrender header (src/render/src/colorprocessor.h) so both sides
|
||||
// see the same class definition.
|
||||
#include "../../src/colorprocessor.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
// Bridge: oaknode still includes "render/job/colortransformjob.h". Route it
|
||||
// to the real de-Qt oakrender header (src/render/src/job/colortransformjob.h)
|
||||
// so both sides see the same class definition.
|
||||
#include "../../../src/job/colortransformjob.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/job/pluginjob.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/job/pluginjob.h).
|
||||
#include "../../../src/job/pluginjob.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/job/shaderjob.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/job/shaderjob.h).
|
||||
#include "../../../src/job/shaderjob.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/opengl/openglcontext.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/opengl/openglcontext.h).
|
||||
#include "../../../src/opengl/openglcontext.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/opengl/openglcontextprovider.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/opengl/openglcontextprovider.h).
|
||||
#include "../../../src/opengl/openglcontextprovider.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/opengl/openglfunctions.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/opengl/openglfunctions.h).
|
||||
#include "../../../src/opengl/openglfunctions.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/opengl/openglrenderer.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/opengl/openglrenderer.h).
|
||||
#include "../../../src/opengl/openglrenderer.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/renderer.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/renderer.h).
|
||||
#include "../../src/renderer.h"
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
// Bridge: oaknode still includes "render/shadercode.h". Route it to the
|
||||
// real de-Qt oakrender header (src/render/src/shadercode.h) so both sides
|
||||
// see the same class definition.
|
||||
#include "../../src/shadercode.h"
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
// Bridge: oaknode still includes "render/texture.h". Route it to the real
|
||||
// de-Qt oakrender header (src/render/src/texture.h) so both sides see the
|
||||
// same class definition. samplebuffer.h is included first because oaknode's
|
||||
// value.h relied on the old transition texture.h pulling it in transitively.
|
||||
#include "render/samplebuffer.h"
|
||||
#include "../../src/texture.h"
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// Bridge: route the engine-style "render/vulkan/vulkanrenderer.h" include to the real de-Qt
|
||||
// oakrender header (src/render/src/vulkan/vulkanrenderer.h).
|
||||
#include "../../../src/vulkan/vulkanrenderer.h"
|
||||
Reference in New Issue
Block a user