feat(app): multicam panel with live angle grid, switching, timeline enable
- New MulticamPanel: rows/cols angle grid with the current angle highlighted, click-to-switch, 1-9 switch-and-split and cmd-1-9 switch-only shortcuts (focused-panel routed), deferred switch queue during playback. - src/oakui/multicam.rs: clip->connected-sequence resolution, multicam state detection (selection then playhead fallbacks), per-angle frame requests rendered through the process backend into an LRU cache. - Timeline clip context menu Multi-Cam checkable item wired to oaktimeline::multicam enable/disable with undo. - Engine trait extended (real + mock); mock drives the real command path with synthesized angle frames.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_ERROR_H
|
||||
#define OAK_EDITOR_AUDIO_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Current ABI version stamped into every oakaudio 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 OAKAUDIO_ABI_VERSION 1
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(OAKAUDIO_BUILD)
|
||||
#define OAKAUDIO_API __declspec(dllexport)
|
||||
#else
|
||||
#define OAKAUDIO_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define OAKAUDIO_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakaudio C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKAUDIO_OK) on success, a negative OAKAUDIO_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKAUDIO_OK 0 /**< Success. */
|
||||
#define OAKAUDIO_E_INVALID (-60001) /**< NULL handle or invalid argument. */
|
||||
#define OAKAUDIO_E_STATE (-60002) /**< Call not valid in the current state. */
|
||||
#define OAKAUDIO_E_FAILED (-60003) /**< The underlying operation failed. */
|
||||
#define OAKAUDIO_E_NOT_FOUND (-60004) /**< Index out of range / entry not found. */
|
||||
#define OAKAUDIO_E_NOMEM (-60005) /**< Allocation failed. */
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_ERROR_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_LEVELMETER_H
|
||||
#define OAK_EDITOR_AUDIO_LEVELMETER_H
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file levelmeter.h
|
||||
* @brief C ABI for the oakaudio level meter (olive::AudioLevelMeter):
|
||||
* stateless peak/RMS/VU/LUFS analysis of planar float audio.
|
||||
*/
|
||||
|
||||
/** Per-channel analysis results. dB fields floor at -200. */
|
||||
typedef struct oakaudio_channel_stats {
|
||||
double peak_linear;
|
||||
double peak_db;
|
||||
double rms_linear;
|
||||
double rms_db;
|
||||
double vu_db;
|
||||
} oakaudio_channel_stats;
|
||||
|
||||
/** Buffer-wide summary. */
|
||||
typedef struct oakaudio_meter_stats {
|
||||
double max_peak_linear;
|
||||
double integrated_lufs; /**< BS.1770-compatible unit (no K-weighting). */
|
||||
int silence; /**< 1 when the buffer is (near-)silent. */
|
||||
} oakaudio_meter_stats;
|
||||
|
||||
/**
|
||||
* @brief Analyze a planar float buffer.
|
||||
*
|
||||
* @param planar Per-channel float planes.
|
||||
* @param channel_count Number of channels (> 0).
|
||||
* @param frame_count Frames per channel (>= 0).
|
||||
* @param channels Receives per-channel stats; may be NULL.
|
||||
* @param channels_capacity Capacity of `channels` (must be >=
|
||||
* channel_count when channels is non-NULL).
|
||||
* @param summary Receives the buffer-wide summary; may be NULL.
|
||||
* @return OAKAUDIO_OK or OAKAUDIO_E_INVALID.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_levelmeter_analyze(const float *const *planar,
|
||||
int channel_count, int frame_count,
|
||||
oakaudio_channel_stats *channels, int channels_capacity,
|
||||
oakaudio_meter_stats *summary);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_LEVELMETER_H
|
||||
@@ -0,0 +1,176 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_MANAGER_H
|
||||
#define OAK_EDITOR_AUDIO_MANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "codec/encoder.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file manager.h
|
||||
* @brief C ABI for the oakaudio PortAudio output/input manager
|
||||
* (olive::AudioManager singleton).
|
||||
*
|
||||
* OakAudioManager uses the standard handle layout (see oakcommon's
|
||||
* common/handle.h) but with singleton semantics: ctx points to the
|
||||
* process-wide instance created by oakaudio_manager_create_instance(), so
|
||||
* addref() and release() are intentionally no-ops and never destroy
|
||||
* anything (mirrors oakcommon's OakCurrent). abi_version is always
|
||||
* OAKAUDIO_ABI_VERSION.
|
||||
*
|
||||
* Device indices are PortAudio PaDeviceIndex values (-1 = paNoDevice).
|
||||
* Sample formats are olive::core::SampleFormat::Format values.
|
||||
*/
|
||||
typedef struct OakAudioManager {
|
||||
void *ctx; /**< Opaque pointer to the singleton object. */
|
||||
void (*addref)(void *ctx); /**< No-op (singleton). */
|
||||
void (*release)(void *ctx); /**< No-op (singleton). */
|
||||
uint32_t abi_version; /**< OAKAUDIO_ABI_VERSION. */
|
||||
} OakAudioManager;
|
||||
|
||||
/**
|
||||
* @brief Create the process-wide AudioManager (no-op when it exists).
|
||||
*
|
||||
* Initializes PortAudio and picks the configured/default devices.
|
||||
*
|
||||
* @return OAKAUDIO_OK or OAKAUDIO_E_NOMEM.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_create_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the process-wide AudioManager (no-op when absent).
|
||||
*/
|
||||
OAKAUDIO_API void oakaudio_manager_destroy_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Return a handle to the process-wide AudioManager.
|
||||
*
|
||||
* The returned handle is borrowed; addref/release are no-ops. When no
|
||||
* instance exists the handle is empty (ctx == NULL) and all functions
|
||||
* report OAKAUDIO_E_STATE.
|
||||
*/
|
||||
OAKAUDIO_API OakAudioManager oakaudio_manager_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Release a manager handle. No-op (singleton), safe on NULL/empty.
|
||||
*/
|
||||
OAKAUDIO_API void oakaudio_manager_free(OakAudioManager *self);
|
||||
|
||||
/**
|
||||
* @brief Bytes between output-notify pulses (0 disables).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_set_output_notify_interval(
|
||||
OakAudioManager self, int64_t bytes);
|
||||
|
||||
/**
|
||||
* @brief Push a block of samples to the output device, opening/restarting
|
||||
* the stream when the params changed.
|
||||
*
|
||||
* @param rate/layout/format Stream params (ffmpeg-style layout mask,
|
||||
* SampleFormat::Format int).
|
||||
* @param samples Packed samples in the given format.
|
||||
* @param samples_size Byte count of `samples`.
|
||||
* @param error_buf/error_buf_size Optional human-readable failure detail.
|
||||
* @return OAKAUDIO_OK, OAKAUDIO_E_INVALID, OAKAUDIO_E_STATE (no output
|
||||
* device), or OAKAUDIO_E_FAILED (PortAudio error, see error_buf).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_push_to_output(OakAudioManager self,
|
||||
int rate, uint64_t layout, int format,
|
||||
const char *samples, int64_t samples_size,
|
||||
char *error_buf, int error_buf_size);
|
||||
|
||||
OAKAUDIO_API int oakaudio_manager_clear_buffered_output(OakAudioManager self);
|
||||
OAKAUDIO_API int oakaudio_manager_stop_output(OakAudioManager self);
|
||||
|
||||
/**
|
||||
* @brief Seconds of audio consumed by the output device since the last
|
||||
* reset, compensated for output latency; negative when no stream
|
||||
* is running.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_seconds(OakAudioManager self, double *out);
|
||||
|
||||
OAKAUDIO_API int oakaudio_manager_reset_output_clock(OakAudioManager self);
|
||||
|
||||
/**
|
||||
* @brief Current output device index, paNoDevice (-1), or a negative
|
||||
* OAKAUDIO_E_* code.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_get_output_device(OakAudioManager self);
|
||||
OAKAUDIO_API int oakaudio_manager_set_output_device(OakAudioManager self,
|
||||
int device);
|
||||
OAKAUDIO_API int oakaudio_manager_get_input_device(OakAudioManager self);
|
||||
OAKAUDIO_API int oakaudio_manager_set_input_device(OakAudioManager self,
|
||||
int device);
|
||||
|
||||
/**
|
||||
* @brief Close the output stream and re-initialize PortAudio.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_hard_reset(OakAudioManager self);
|
||||
|
||||
/**
|
||||
* @brief Start recording the input device to a file via the oakcodec
|
||||
* encoder C ABI.
|
||||
*
|
||||
* `params` must describe an audio-enabled encoding; the input stream is
|
||||
* always captured as interleaved 32-bit float (the only format the
|
||||
* oakcodec encoder write path accepts).
|
||||
*
|
||||
* @return OAKAUDIO_OK, OAKAUDIO_E_STATE (no input device), or
|
||||
* OAKAUDIO_E_FAILED (see error_buf).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_start_recording(OakAudioManager self,
|
||||
const oakcodec_encoding_params *params,
|
||||
char *error_buf, int error_buf_size);
|
||||
|
||||
OAKAUDIO_API int oakaudio_manager_stop_recording(OakAudioManager self);
|
||||
|
||||
/**
|
||||
* @brief Device index named by the configuration ("AudioOutput" /
|
||||
* "AudioInput"), or the default device when unset/unmatched.
|
||||
* Static: valid without an instance (PortAudio must be initialized
|
||||
* by an instance first; returns paNoDevice otherwise).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_find_config_device_by_name_s(
|
||||
int is_output_device);
|
||||
|
||||
/**
|
||||
* @brief Device index whose name matches `name` exactly (empty name
|
||||
* matches nothing, falls through to the default device).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_manager_find_device_by_name_s(const char *name,
|
||||
int is_output_device);
|
||||
|
||||
/**
|
||||
* @brief Number of live oakaudio reference-counted objects (leak check).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_debug_alive_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_MANAGER_H
|
||||
@@ -0,0 +1,131 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_PROCESSOR_H
|
||||
#define OAK_EDITOR_AUDIO_PROCESSOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file processor.h
|
||||
* @brief C ABI for the oakaudio real-time resampler/format converter
|
||||
* (olive::AudioProcessor).
|
||||
*
|
||||
* OakAudioProcessor follows the neutral by-value handle convention (see
|
||||
* oakcommon's common/handle.h): oakaudio_processor_init() returns a handle
|
||||
* whose underlying object has reference count 1, the addref and release
|
||||
* function pointers adjust that count atomically (release destroys the
|
||||
* object at zero), and abi_version is always OAKAUDIO_ABI_VERSION.
|
||||
* Functions that only use a handle take it BY VALUE; an empty handle
|
||||
* (ctx == NULL) is reported as OAKAUDIO_E_INVALID.
|
||||
*
|
||||
* Sample formats are passed as ints matching the
|
||||
* olive::core::SampleFormat::Format enum values (invalid = -1, u8_p = 0,
|
||||
* s16_p, s32_p, s64_p, f32_p, f64_p, u8, s16, s32, s64, f32, f64,
|
||||
* count). Channel layouts are ffmpeg-style channel masks.
|
||||
*/
|
||||
typedef struct OakAudioProcessor {
|
||||
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; /**< OAKAUDIO_ABI_VERSION. */
|
||||
} OakAudioProcessor;
|
||||
|
||||
/** oakaudio_processor_convert() delivers planar 32-bit float output. */
|
||||
#define OAKAUDIO_PROCESSOR_OUTPUT_FORMAT 4 /**< SampleFormat::f32_p. */
|
||||
|
||||
/**
|
||||
* @brief Create a closed audio processor (count 1).
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OAKAUDIO_API OakAudioProcessor oakaudio_processor_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a processor.
|
||||
*
|
||||
* Convenience wrapper around self->release(self->ctx); nulls self->ctx.
|
||||
* No-op when self is NULL or self->ctx is NULL.
|
||||
*/
|
||||
OAKAUDIO_API void oakaudio_processor_free(OakAudioProcessor *self);
|
||||
|
||||
/**
|
||||
* @brief Open the resampling/format-conversion graph.
|
||||
*
|
||||
* out_format is accepted for interface completeness but the conversion
|
||||
* output is always planar 32-bit float (see
|
||||
* OAKAUDIO_PROCESSOR_OUTPUT_FORMAT); passing any other format returns
|
||||
* OAKAUDIO_E_INVALID. A channel layout mask of 0 falls back to the
|
||||
* default layout for the channel count (stereo when unknown), matching
|
||||
* the C++ implementation.
|
||||
*
|
||||
* @param speed Tempo factor (1.0 = unchanged).
|
||||
* @return OAKAUDIO_OK, OAKAUDIO_E_STATE when already open,
|
||||
* OAKAUDIO_E_INVALID for bad arguments, or OAKAUDIO_E_FAILED when
|
||||
* the filter graph could not be created.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_processor_open(OakAudioProcessor self,
|
||||
int in_rate, uint64_t in_layout, int in_format,
|
||||
int out_rate, uint64_t out_layout, int out_format, double speed);
|
||||
|
||||
/**
|
||||
* @brief Close the graph (safe when closed; self must be non-empty).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_processor_close(OakAudioProcessor self);
|
||||
|
||||
/**
|
||||
* @brief 1 when open, 0 when closed, OAKAUDIO_E_INVALID for empty handle.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_processor_is_open(OakAudioProcessor self);
|
||||
|
||||
/**
|
||||
* @brief Push planar float input and pull converted output.
|
||||
*
|
||||
* @param in_planar Per-channel float input planes (in channel count);
|
||||
* NULL with in_frame_count == 0 only pulls pending output.
|
||||
* @param in_frame_count Frames per input channel.
|
||||
* @param out_planar Per-channel float output planes (out channel count);
|
||||
* NULL to discard/pull nothing (returns 0).
|
||||
* @param out_capacity_frames Capacity of each output plane in frames.
|
||||
* @return Number of output frames written (>= 0), or a negative
|
||||
* OAKAUDIO_E_* code. Output is clamped to out_capacity_frames;
|
||||
* remaining frames stay queued in the graph.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_processor_convert(OakAudioProcessor self,
|
||||
const float *const *in_planar, int in_frame_count,
|
||||
float *const *out_planar, int out_capacity_frames);
|
||||
|
||||
/**
|
||||
* @brief Signal end-of-input to the graph (flushes internal delay).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_processor_flush(OakAudioProcessor self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_PROCESSOR_H
|
||||
@@ -0,0 +1,132 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_SYNC_H
|
||||
#define OAK_EDITOR_AUDIO_SYNC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file sync.h
|
||||
* @brief C ABI for the oakaudio synchronization helpers
|
||||
* (olive::AudioSynchronizer and olive::AudioWaveformSync):
|
||||
* stateless source-time placement and envelope-correlation offset
|
||||
* estimation.
|
||||
*/
|
||||
|
||||
/** Result of an offset estimation. */
|
||||
typedef struct oakaudio_offset_result {
|
||||
int64_t offset_samples;
|
||||
double confidence; /**< 0..1 correlation score. */
|
||||
int valid; /**< 1 when an estimate was found. */
|
||||
} oakaudio_offset_result;
|
||||
|
||||
/** Result of a stretch-plus-offset estimation. */
|
||||
typedef struct oakaudio_stretch_offset_result {
|
||||
double rate; /**< Playback rate aligning the candidate (> 1 = speed up). */
|
||||
int64_t offset_samples;
|
||||
double confidence;
|
||||
int valid;
|
||||
} oakaudio_stretch_offset_result;
|
||||
|
||||
/**
|
||||
* @brief Per-window RMS envelope of a planar float buffer (static).
|
||||
*
|
||||
* @return Number of envelope windows (>= 0) or a negative OAKAUDIO_E_*
|
||||
* code. When out is NULL or too small, the required window count
|
||||
* is returned and nothing is written.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_sync_extract_rms_envelope(
|
||||
const float *const *planar, int channel_count, int frame_count,
|
||||
uint64_t window_samples, double *out, int capacity);
|
||||
|
||||
/**
|
||||
* @brief Estimate the candidate's offset against the reference by
|
||||
* normalized cross-correlation of RMS envelopes.
|
||||
*
|
||||
* @param reference_valid/candidate_valid Optional per-window validity
|
||||
* masks (NULL = all windows valid; when non-NULL the length must
|
||||
* match the corresponding envelope length).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_sync_estimate_envelope_offset(
|
||||
const double *reference, int reference_len,
|
||||
const double *candidate, int candidate_len,
|
||||
const uint8_t *reference_valid, const uint8_t *candidate_valid,
|
||||
uint64_t window_samples, int64_t max_offset_windows,
|
||||
oakaudio_offset_result *out);
|
||||
|
||||
/**
|
||||
* @brief Estimate a playback-rate change plus offset aligning the
|
||||
* candidate to the reference.
|
||||
*
|
||||
* The candidate envelope is resampled at each rate in
|
||||
* [min_rate, max_rate] (step rate_step) and correlated against the
|
||||
* reference. O(rates * lags * overlap); bound max_offset_windows.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_sync_estimate_stretch_and_offset(
|
||||
const double *reference, int reference_len,
|
||||
const double *candidate, int candidate_len,
|
||||
const uint8_t *reference_valid, const uint8_t *candidate_valid,
|
||||
uint64_t window_samples, int64_t max_offset_windows,
|
||||
double min_rate, double max_rate, double rate_step,
|
||||
oakaudio_stretch_offset_result *out);
|
||||
|
||||
/** One clip's source-time metadata (rational seconds). */
|
||||
typedef struct oakaudio_source_clip {
|
||||
int64_t source_start_time_num;
|
||||
int64_t source_start_time_den;
|
||||
int64_t media_in_num;
|
||||
int64_t media_in_den;
|
||||
int has_source_start_time;
|
||||
} oakaudio_source_clip;
|
||||
|
||||
/**
|
||||
* @brief Place the candidate on the timeline so its source time aligns
|
||||
* with the reference clip.
|
||||
*
|
||||
* @param reference_timeline_in_num/den Reference clip's timeline in point.
|
||||
* @param out_num/out_den Receive the candidate's timeline in point.
|
||||
* @param out_valid Receives 1 when placement succeeded.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_sync_place_by_source_time(
|
||||
const oakaudio_source_clip *reference,
|
||||
const oakaudio_source_clip *candidate,
|
||||
int64_t reference_timeline_in_num, int64_t reference_timeline_in_den,
|
||||
int64_t *out_num, int64_t *out_den, int *out_valid);
|
||||
|
||||
/**
|
||||
* @brief Timeline placement from a measured waveform offset.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_sync_place_by_waveform_offset(
|
||||
int64_t reference_timeline_in_num, int64_t reference_timeline_in_den,
|
||||
int64_t candidate_offset_samples, int sample_rate,
|
||||
int64_t *out_num, int64_t *out_den, int *out_valid);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_SYNC_H
|
||||
@@ -0,0 +1,179 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_AUDIO_WAVEFORM_H
|
||||
#define OAK_EDITOR_AUDIO_WAVEFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file waveform.h
|
||||
* @brief C ABI for the oakaudio visual waveform store
|
||||
* (olive::AudioVisualWaveform) and whole-file waveform extraction.
|
||||
*
|
||||
* OakAudioWaveform follows the neutral by-value handle convention (see
|
||||
* oakcommon's common/handle.h). Times are rationals as (num, den) pairs
|
||||
* of int64_t in seconds; den must be non-zero.
|
||||
*
|
||||
* Summaries are stored as channel-interleaved min/max pairs: point p of
|
||||
* channel c lives at pairs[p * channel_count + c]. This matches the
|
||||
* on-disk/cache layout of the engine's waveform data (min/max float
|
||||
* pairs), so the extraction output is drop-in compatible.
|
||||
*/
|
||||
|
||||
/** One summarized waveform point of one channel. */
|
||||
typedef struct oakaudio_min_max {
|
||||
float min;
|
||||
float max;
|
||||
} oakaudio_min_max;
|
||||
|
||||
typedef struct OakAudioWaveform {
|
||||
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; /**< OAKAUDIO_ABI_VERSION. */
|
||||
} OakAudioWaveform;
|
||||
|
||||
/**
|
||||
* @brief Create an empty waveform (count 1, channel count 0).
|
||||
*/
|
||||
OAKAUDIO_API OakAudioWaveform oakaudio_waveform_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference. No-op on NULL/empty handle.
|
||||
*/
|
||||
OAKAUDIO_API void oakaudio_waveform_free(OakAudioWaveform *self);
|
||||
|
||||
/**
|
||||
* @brief Channel count, or a negative OAKAUDIO_E_* code.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_get_channel_count(OakAudioWaveform self);
|
||||
OAKAUDIO_API int oakaudio_waveform_set_channel_count(OakAudioWaveform self,
|
||||
int channels);
|
||||
|
||||
/**
|
||||
* @brief Waveform length in seconds as a rational pair.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_length(OakAudioWaveform self,
|
||||
int64_t *num, int64_t *den);
|
||||
|
||||
/**
|
||||
* @brief Write planar float samples into the waveform at `start` seconds,
|
||||
* expanding it if necessary.
|
||||
*
|
||||
* @param planar Per-channel float planes; channel count is taken from the
|
||||
* waveform (set it first with oakaudio_waveform_set_channel_count).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_overwrite_samples(OakAudioWaveform self,
|
||||
const float *const *planar, int frame_count, int sample_rate,
|
||||
int64_t start_num, int64_t start_den);
|
||||
|
||||
/**
|
||||
* @brief Copy summarized data from another waveform over this one.
|
||||
*
|
||||
* @param dest_num/dest_den Where in `self` the sums start being written.
|
||||
* @param offset_num/offset_den Where in `src` reading starts.
|
||||
* @param length_num/length_den Maximum amount to copy; 0/1 = all of src.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_overwrite_sums(OakAudioWaveform self,
|
||||
OakAudioWaveform src,
|
||||
int64_t dest_num, int64_t dest_den,
|
||||
int64_t offset_num, int64_t offset_den,
|
||||
int64_t length_num, int64_t length_den);
|
||||
|
||||
OAKAUDIO_API int oakaudio_waveform_overwrite_silence(OakAudioWaveform self,
|
||||
int64_t start_num, int64_t start_den,
|
||||
int64_t length_num, int64_t length_den);
|
||||
|
||||
/**
|
||||
* @brief Drop `length` seconds from the front (negative prepends silence).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_trim_in(OakAudioWaveform self,
|
||||
int64_t length_num, int64_t length_den);
|
||||
|
||||
OAKAUDIO_API int oakaudio_waveform_resize(OakAudioWaveform self,
|
||||
int64_t length_num, int64_t length_den);
|
||||
|
||||
OAKAUDIO_API int oakaudio_waveform_trim_range(OakAudioWaveform self,
|
||||
int64_t in_num, int64_t in_den,
|
||||
int64_t length_num, int64_t length_den);
|
||||
|
||||
/**
|
||||
* @brief Summarized min/max pairs covering [start, start+length).
|
||||
*
|
||||
* @param out_pairs Receives points * channel_count channel-interleaved
|
||||
* pairs; may be NULL to query the point count.
|
||||
* @param capacity_points Capacity of out_pairs in points.
|
||||
* @return Number of points (>= 0), or a negative OAKAUDIO_E_* code.
|
||||
* When out_pairs is NULL or too small the required count is
|
||||
* returned and nothing is written.
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_get_summary(OakAudioWaveform self,
|
||||
int64_t start_num, int64_t start_den,
|
||||
int64_t length_num, int64_t length_den,
|
||||
oakaudio_min_max *out_pairs, int capacity_points);
|
||||
|
||||
/**
|
||||
* @brief Min/max of `length` samples starting at `start_index` for every
|
||||
* channel (static, no handle).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_sum_samples_s(const float *const *planar,
|
||||
int channel_count, int start_index, int length,
|
||||
oakaudio_min_max *out);
|
||||
|
||||
/**
|
||||
* @brief Re-summarize channel-interleaved pairs into one point per
|
||||
* channel (static, no handle).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_re_sum_s(const oakaudio_min_max *in,
|
||||
int nb_entries, int nb_channels, oakaudio_min_max *out);
|
||||
|
||||
/**
|
||||
* @brief Extract a whole-file waveform summary from a media file through
|
||||
* the oakcodec decoder C ABI.
|
||||
*
|
||||
* Decodes `filename`'s audio stream `stream_index` (index within the
|
||||
* file's audio stream list) and reduces it to channel-interleaved
|
||||
* min/max pairs, one point per `samples_per_point` source samples.
|
||||
*
|
||||
* @param out_pairs Receives the pairs; may be NULL to query the size.
|
||||
* @param capacity_points Capacity of out_pairs in points.
|
||||
* @param out_channel_count Receives the channel count (may be NULL).
|
||||
* @return Number of points (>= 0); when out_pairs is NULL or too small,
|
||||
* the required count is returned and nothing is written.
|
||||
* Negative OAKAUDIO_E_* code on failure
|
||||
* (OAKAUDIO_E_NOT_FOUND when the file/stream does not exist).
|
||||
*/
|
||||
OAKAUDIO_API int oakaudio_waveform_extract(const char *filename,
|
||||
int stream_index, int samples_per_point,
|
||||
oakaudio_min_max *out_pairs, int capacity_points,
|
||||
int *out_channel_count);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_AUDIO_WAVEFORM_H
|
||||
@@ -0,0 +1,106 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_CONFORM_H
|
||||
#define OAK_EDITOR_CODEC_CONFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file conform.h
|
||||
* @brief C ABI for the oakcodec audio conform manager
|
||||
* (olive::ConformManager): pcm waveform cache files used for fast
|
||||
* audio scrubbing.
|
||||
*
|
||||
* Interim state (pre-M8): actual conform work is delegated to the global
|
||||
* task submit callback (see task.h). While no callback is registered,
|
||||
* state queries report OAKCODEC_CONFORM_UNAVAILABLE.
|
||||
*/
|
||||
|
||||
#define OAKCODEC_CONFORM_EXISTS 0
|
||||
#define OAKCODEC_CONFORM_GENERATING 1
|
||||
#define OAKCODEC_CONFORM_UNAVAILABLE 2
|
||||
|
||||
/**
|
||||
* @brief Create the ConformManager singleton (no-op when it exists).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_create_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ConformManager singleton (no-op when absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_destroy_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Query the conform state of one audio stream, starting the
|
||||
* conform when needed and possible.
|
||||
*
|
||||
* Addresses the source by filename/stream_index and the target audio
|
||||
* format by sample_rate/channel_layout/sample_format
|
||||
* (olive::core::SampleFormat::Format as int).
|
||||
*
|
||||
* When the conform files do not exist and a task submit callback is
|
||||
* registered (task.h), the conform is submitted synchronously and the
|
||||
* filesystem is re-checked; `wait` only controls whether a post-submit
|
||||
* miss is reported as OAKCODEC_CONFORM_UNAVAILABLE (wait != 0) or
|
||||
* OAKCODEC_CONFORM_GENERATING (wait == 0). Without a registrar the
|
||||
* result is always OAKCODEC_CONFORM_UNAVAILABLE.
|
||||
*
|
||||
* @return One of OAKCODEC_CONFORM_* (non-negative), or a negative
|
||||
* OAKCODEC_E_* code for invalid arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_get_state(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
int sample_rate, uint64_t channel_layout,
|
||||
int sample_format, int wait);
|
||||
|
||||
/**
|
||||
* @brief Number of conform (pcm) files for the given stream/params — one
|
||||
* per channel; 0 on invalid arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_filename_count(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
int sample_rate, uint64_t channel_layout,
|
||||
int sample_format);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th conform filename (buf/size getter).
|
||||
*
|
||||
* @return Required buffer size including NUL (non-negative), or a
|
||||
* negative OAKCODEC_E_* code (OAKCODEC_E_NOT_FOUND when index is
|
||||
* out of range).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_filename_at(const char *cache_path,
|
||||
const char *source_filename,
|
||||
int stream_index, int sample_rate,
|
||||
uint64_t channel_layout, int sample_format,
|
||||
int index, char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_CONFORM_H
|
||||
@@ -0,0 +1,245 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_DECODER_H
|
||||
#define OAK_EDITOR_CODEC_DECODER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "frame.h"
|
||||
#include "render/cancelatom.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file decoder.h
|
||||
* @brief C ABI for oakcodec media decoders (olive::Decoder and its
|
||||
* FFmpeg/OIIO implementations): probing, stream enumeration and
|
||||
* CPU-frame decoding.
|
||||
*
|
||||
* Handles follow the neutral by-value convention documented in frame.h
|
||||
* (and oakcommon's common/handle.h). Two usage patterns share the
|
||||
* OakDecoder handle:
|
||||
*
|
||||
* - Probe: oakcodec_decoder_probe() inspects a file WITHOUT opening a
|
||||
* decode session; the stream getters describe what was found.
|
||||
* - Decode: oakcodec_decoder_init() + oakcodec_decoder_open() attach a
|
||||
* decoder instance to one (filename, stream) pair; the decode
|
||||
* functions then produce frames/audio.
|
||||
*/
|
||||
|
||||
typedef struct OakDecoder {
|
||||
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; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakDecoder;
|
||||
|
||||
/**
|
||||
* @brief POD description of one probed video stream.
|
||||
*
|
||||
* duration_ts counts units of the stream's time base;
|
||||
* time_base_num/den is seconds per time-base unit. color_primaries and
|
||||
* color_trc carry the ISO/IEC 23001-8 code points the decoder reports
|
||||
* (0 = unknown). interlaced is 1 when the stream is interlaced.
|
||||
* format is an OakPixelFormat value (the decoder's native delivery
|
||||
* format), channel_count its plane channel count.
|
||||
*/
|
||||
typedef struct oakcodec_video_stream_info {
|
||||
int stream_index;
|
||||
int width;
|
||||
int height;
|
||||
int frame_rate_num;
|
||||
int frame_rate_den;
|
||||
int64_t duration_ts;
|
||||
int time_base_num;
|
||||
int time_base_den;
|
||||
int format;
|
||||
int channel_count;
|
||||
int color_primaries;
|
||||
int color_trc;
|
||||
int interlaced;
|
||||
} oakcodec_video_stream_info;
|
||||
|
||||
/**
|
||||
* @brief POD description of one probed audio stream.
|
||||
*
|
||||
* channel_layout is the ffmpeg-style channel mask (e.g. 0x3 = stereo).
|
||||
*/
|
||||
typedef struct oakcodec_audio_stream_info {
|
||||
int stream_index;
|
||||
int sample_rate;
|
||||
uint64_t channel_layout;
|
||||
int channel_count;
|
||||
int64_t duration_ts;
|
||||
int time_base_num;
|
||||
int time_base_den;
|
||||
} oakcodec_audio_stream_info;
|
||||
|
||||
/* ---- Probe (stateless inspection) ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Probe a media file: decoder name plus stream inventory.
|
||||
*
|
||||
* Tries each available decoder implementation (FFmpeg, then OIIO) and
|
||||
* wraps the first one that recognizes the file. The returned handle only
|
||||
* carries probe results; it cannot decode (use init + open for that).
|
||||
*
|
||||
* @return Handle with reference count 1, or an empty handle (ctx == NULL)
|
||||
* when no decoder recognizes the file (oakcodec_probe_last_error()
|
||||
* carries the reason).
|
||||
*/
|
||||
OAKCODEC_API OakDecoder oakcodec_decoder_probe(const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Thread-local error detail of the last failed probe on this
|
||||
* thread (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_probe_last_error(char *buf, int buf_size);
|
||||
|
||||
/** @brief Probed decoder id ("ffmpeg"/"oiio", buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_decoder_probe_decoder_name(OakDecoder probe, char *buf,
|
||||
int buf_size);
|
||||
|
||||
OAKCODEC_API int oakcodec_decoder_probe_video_stream_count(OakDecoder probe);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_audio_stream_count(OakDecoder probe);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_subtitle_stream_count(OakDecoder probe);
|
||||
|
||||
/**
|
||||
* @brief Fill `out` with the video stream at `index` (0-based within the
|
||||
* video stream list).
|
||||
*
|
||||
* @return OAKCODEC_OK, OAKCODEC_E_INVALID, or OAKCODEC_E_NOT_FOUND when
|
||||
* index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_probe_get_video_stream(OakDecoder probe, int index,
|
||||
oakcodec_video_stream_info *out);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_get_audio_stream(OakDecoder probe, int index,
|
||||
oakcodec_audio_stream_info *out);
|
||||
|
||||
/* ---- Decode session ------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Create a closed decoder handle (count 1).
|
||||
*/
|
||||
OAKCODEC_API OakDecoder oakcodec_decoder_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a decoder. No-op on NULL/empty.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_decoder_free(OakDecoder *decoder);
|
||||
|
||||
/**
|
||||
* @brief Open `filename`'s stream `stream_index` for decoding.
|
||||
*
|
||||
* The decoder implementation is chosen automatically from the probe
|
||||
* results. Opening an already-open decoder on the same stream is a
|
||||
* successful no-op.
|
||||
*
|
||||
* @return OAKCODEC_OK on success, OAKCODEC_E_NOT_FOUND when the file
|
||||
* does not exist, OAKCODEC_E_FAILED otherwise (see
|
||||
* oakcodec_decoder_last_error()).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_open(OakDecoder decoder, const char *filename,
|
||||
int stream_index);
|
||||
|
||||
/** @brief Close the current stream (safe when closed). */
|
||||
OAKCODEC_API int oakcodec_decoder_close(OakDecoder decoder);
|
||||
|
||||
/** @brief 1 when a stream is open, 0 otherwise. */
|
||||
OAKCODEC_API int oakcodec_decoder_is_open(OakDecoder decoder);
|
||||
|
||||
/**
|
||||
* @brief Decode the video frame at `numerator/denominator` seconds.
|
||||
*
|
||||
* Before the start of the footage the first frame is returned, after the
|
||||
* end the last frame.
|
||||
*
|
||||
* @return A frame handle with reference count 1 (caller releases), or an
|
||||
* empty handle (ctx == NULL) on error/EOF — check
|
||||
* oakcodec_decoder_last_error().
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_decoder_decode_video(OakDecoder decoder, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Decode audio into a float buffer.
|
||||
*
|
||||
* Decodes the interleaved audio covering [in, out) seconds (rational
|
||||
* pairs), resampled/laid out to `sample_rate`/`channel_layout`.
|
||||
* `buf` must hold at least `buf_frames` frames worth of interleaved
|
||||
* floats.
|
||||
*
|
||||
* @return The number of frames written (>= 0), or a negative
|
||||
* OAKCODEC_E_* code. Conform generation is NOT triggered by this
|
||||
* family in the current intermediate state (no task registrar);
|
||||
* media requiring a conform yields OAKCODEC_E_STATE.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_decode_audio(OakDecoder decoder, int in_num, int in_den,
|
||||
int out_num, int out_den, int sample_rate,
|
||||
uint64_t channel_layout, float *buf,
|
||||
int buf_frames);
|
||||
|
||||
/**
|
||||
* @brief Conform the open stream's audio into per-channel pcm cache files
|
||||
* (Decoder::conform_audio()).
|
||||
*
|
||||
* `output_filenames` is an array of `filename_count` final per-channel
|
||||
* paths. `sample_format` is olive::core::SampleFormat::Format as int.
|
||||
* `cancelled` may be an empty OakCancelAtom (ctx == NULL).
|
||||
*
|
||||
* @return OAKCODEC_OK on success, OAKCODEC_E_STATE when no stream is
|
||||
* open, OAKCODEC_E_CANCELLED when cancelled, OAKCODEC_E_FAILED
|
||||
* otherwise.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_conform_audio(OakDecoder decoder,
|
||||
const char *const *output_filenames, int filename_count,
|
||||
int sample_rate, uint64_t channel_layout, int sample_format,
|
||||
OakCancelAtom cancelled);
|
||||
|
||||
/**
|
||||
* @brief Image-sequence filename heuristics (Decoder::get_image_sequence_*).
|
||||
*
|
||||
* digit_count: number of trailing digits in the filename stem (0 = not an
|
||||
* image sequence filename). index: the numeric value of those digits (-1
|
||||
* when none). transform: substitute `number` into the digit field,
|
||||
* two-stage string getter.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_get_image_sequence_digit_count(
|
||||
const char *filename);
|
||||
OAKCODEC_API int64_t oakcodec_decoder_get_image_sequence_index(
|
||||
const char *filename);
|
||||
OAKCODEC_API int oakcodec_decoder_transform_image_sequence_file_name(
|
||||
const char *filename, int64_t number, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Human-readable detail of the last error on this decoder
|
||||
* (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_last_error(OakDecoder decoder, char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_DECODER_H
|
||||
@@ -0,0 +1,223 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_ENCODER_H
|
||||
#define OAK_EDITOR_CODEC_ENCODER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file encoder.h
|
||||
* @brief C ABI for oakcodec media encoders (olive::Encoder and its
|
||||
* FFmpeg/OIIO implementations).
|
||||
*
|
||||
* Handles follow the neutral by-value convention documented in frame.h.
|
||||
* The workflow is: fill an oakcodec_encoding_params POD (all fields,
|
||||
* zeroed = disabled) -> oakcodec_encoder_init() ->
|
||||
* oakcodec_encoder_open() -> oakcodec_encoder_write_*() ->
|
||||
* oakcodec_encoder_flush(). Encoder-specific options
|
||||
* (e.g. "crf" = "18") go through oakcodec_encoder_set_video_option()
|
||||
* between init and open.
|
||||
*
|
||||
* Enum int fields carry the engine's own enum values
|
||||
* (olive::ExportFormat::Format, olive::ExportCodec::Codec,
|
||||
* OakPixelFormat, olive::VideoParams::Interlacing,
|
||||
* olive::core::SampleFormat::Format) — the same values
|
||||
* oakengine/encoding.h documents.
|
||||
*/
|
||||
|
||||
typedef struct OakEncoder {
|
||||
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; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakEncoder;
|
||||
|
||||
/** @brief olive::VideoParams::Interlacing values. */
|
||||
#define OAKCODEC_INTERLACE_NONE 0
|
||||
#define OAKCODEC_INTERLACE_TOP_FIRST 1
|
||||
#define OAKCODEC_INTERLACE_BOTTOM_FIRST 2
|
||||
|
||||
/** @brief EncodingParams::VideoScalingMethod values. */
|
||||
#define OAKCODEC_ENCODING_SCALING_FIT 0
|
||||
#define OAKCODEC_ENCODING_SCALING_STRETCH 1
|
||||
#define OAKCODEC_ENCODING_SCALING_CROP 2
|
||||
|
||||
/**
|
||||
* @brief Flattened encoding parameters (olive::EncodingParams).
|
||||
*
|
||||
* A zeroed struct describes an all-tracks-disabled configuration. The
|
||||
* filename (and image-sequence "[#####]" template when
|
||||
* video_is_image_sequence is set) lives in `filename`.
|
||||
* video_time_base_* is the frame duration (frame rate flipped), matching
|
||||
* oak_video_params' convention.
|
||||
*/
|
||||
typedef struct oakcodec_encoding_params {
|
||||
char filename[1024];
|
||||
int format; /**< olive::ExportFormat::Format. */
|
||||
|
||||
int video_enabled; /**< 1/0. */
|
||||
int video_codec; /**< olive::ExportCodec::Codec. */
|
||||
int video_width;
|
||||
int video_height;
|
||||
int video_time_base_num; /**< Frame duration numerator. */
|
||||
int video_time_base_den;
|
||||
int video_pixel_format; /**< OakPixelFormat (delivery format). */
|
||||
int video_interlacing; /**< OAKCODEC_INTERLACE_*. */
|
||||
int video_pixel_aspect_num;
|
||||
int video_pixel_aspect_den;
|
||||
int64_t video_bit_rate; /**< bit/s, 0 = codec default. */
|
||||
int64_t video_min_bit_rate;
|
||||
int64_t video_max_bit_rate;
|
||||
int64_t video_buffer_size; /**< bytes. */
|
||||
int video_threads; /**< 0 = auto. */
|
||||
char video_pix_fmt[64]; /**< Encoded pixel format name ("yuv420p"). */
|
||||
int video_is_image_sequence; /**< 1/0. */
|
||||
int video_scaling_method; /**< OAKCODEC_ENCODING_SCALING_*. */
|
||||
|
||||
int audio_enabled; /**< 1/0. */
|
||||
int audio_codec; /**< olive::ExportCodec::Codec. */
|
||||
int audio_sample_rate;
|
||||
uint64_t audio_channel_layout; /**< ffmpeg-style channel mask. */
|
||||
int audio_sample_format; /**< olive::core::SampleFormat::Format. */
|
||||
int64_t audio_bit_rate; /**< bit/s. */
|
||||
|
||||
int subtitles_enabled; /**< 1/0. */
|
||||
int subtitles_codec; /**< olive::ExportCodec::Codec. */
|
||||
int subtitles_are_sidecar; /**< 1/0. */
|
||||
int subtitles_sidecar_format; /**< olive::ExportFormat::Format. */
|
||||
|
||||
/** Output OCIO colorspace name; empty = reference space (no transform). */
|
||||
char color_transform_output[256];
|
||||
|
||||
int export_length_num; /**< Export length in seconds (rational). */
|
||||
int export_length_den;
|
||||
|
||||
/** Custom export range (seconds, rational pairs); used when
|
||||
* has_custom_range != 0. */
|
||||
int has_custom_range;
|
||||
int64_t custom_range_in_num;
|
||||
int64_t custom_range_in_den;
|
||||
int64_t custom_range_out_num;
|
||||
int64_t custom_range_out_den;
|
||||
} oakcodec_encoding_params;
|
||||
|
||||
/**
|
||||
* @brief Create an encoder for `params` (count 1).
|
||||
*
|
||||
* The implementation (FFmpeg/OIIO) is chosen from params.format and the
|
||||
* enabled tracks. The file is NOT opened yet. Returns an empty handle
|
||||
* (ctx == NULL) when the configuration is invalid.
|
||||
*/
|
||||
OAKCODEC_API OakEncoder oakcodec_encoder_init(const oakcodec_encoding_params *params);
|
||||
|
||||
/** @brief Release one reference to an encoder. No-op on NULL/empty. */
|
||||
OAKCODEC_API void oakcodec_encoder_free(OakEncoder *encoder);
|
||||
|
||||
/**
|
||||
* @brief Set an encoder-specific video option (e.g. "crf" = "18").
|
||||
*
|
||||
* Only valid between init and open.
|
||||
*
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_STATE when already open.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_set_video_option(OakEncoder encoder, const char *key,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Open the output file and write stream headers.
|
||||
*
|
||||
* @return OAKCODEC_OK, OAKCODEC_E_STATE (already open), or
|
||||
* OAKCODEC_E_FAILED (see oakcodec_encoder_last_error()).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_open(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief Encode one video frame.
|
||||
*
|
||||
* The frame's parameters must match the encoding parameters (the encoder
|
||||
* converts the delivery pixel format to the encoded one internally).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_video(OakEncoder encoder, OakFrame frame);
|
||||
|
||||
/**
|
||||
* @brief Encode interleaved float audio samples.
|
||||
*
|
||||
* @param samples frame_count * channel_count interleaved floats.
|
||||
* @return OAKCODEC_OK or a negative OAKCODEC_E_* code.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_audio(OakEncoder encoder, const float *samples,
|
||||
int frame_count);
|
||||
|
||||
/**
|
||||
* @brief Encode one subtitle entry (times in seconds).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_subtitle(OakEncoder encoder, const char *text,
|
||||
double in_seconds, double out_seconds);
|
||||
|
||||
/**
|
||||
* @brief Flush the encoders, write the trailer and close the file.
|
||||
*
|
||||
* Idempotent; after a successful flush the encoder cannot be written to
|
||||
* (write calls return OAKCODEC_E_STATE).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_flush(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief Human-readable detail of the last error on this encoder
|
||||
* (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_last_error(OakEncoder encoder, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The pixel format the encoder wants frames in
|
||||
* (Encoder::get_desired_pixel_format()), as int; -1 when
|
||||
* unknown/invalid encoder.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_get_desired_pixel_format(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief File extension for an export format
|
||||
* (ExportFormat::get_extension()), two-stage string getter.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_export_format_get_extension(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Scaling matrix for a scaling method
|
||||
* (EncodingParams::generate_matrix()), row-major 4x4 into
|
||||
* out_matrix[16].
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_generate_matrix(int method, int src_width,
|
||||
int src_height, int dst_width,
|
||||
int dst_height, double *out_matrix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_ENCODER_H
|
||||
@@ -0,0 +1,61 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_ERROR_H
|
||||
#define OAK_EDITOR_CODEC_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakcodec C API families.
|
||||
*
|
||||
* Return-code convention (mirrors the other split modules):
|
||||
* 0 (OAKCODEC_OK) on success, a negative OAKCODEC_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKCODEC_OK 0 /**< Success. */
|
||||
#define OAKCODEC_E_INVALID (-50001) /**< NULL handle or invalid argument. */
|
||||
#define OAKCODEC_E_STATE (-50002) /**< Call not valid in the current state. */
|
||||
#define OAKCODEC_E_FAILED (-50003) /**< The underlying operation failed. */
|
||||
#define OAKCODEC_E_NOT_FOUND (-50004) /**< Index out of range / entry not found. */
|
||||
#define OAKCODEC_E_NOMEM (-50005) /**< Allocation failed. */
|
||||
#define OAKCODEC_E_CANCELLED (-50006) /**< The operation was cancelled. */
|
||||
|
||||
/**
|
||||
* @brief Current ABI version stamped into every oakcodec handle.
|
||||
*
|
||||
* Bump whenever the 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 OAKCODEC_ABI_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief Export macro for the oakcodec C ABI.
|
||||
*
|
||||
* oakcodec is built with -fvisibility=hidden (01 §1 rule 5): only the
|
||||
* oakcodec_* functions marked with this macro leave the shared library.
|
||||
* This also keeps codec-internal C++ classes (whose olive::* names may
|
||||
* collide with transition stubs inside other modules) from participating
|
||||
* in cross-library weak-symbol coalescing.
|
||||
*/
|
||||
#define OAKCODEC_API __attribute__((visibility("default")))
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_ERROR_H
|
||||
@@ -0,0 +1,217 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_FORMAT_H
|
||||
#define OAK_EDITOR_CODEC_FORMAT_H
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file format.h
|
||||
* @brief C ABI for the oakcodec container-format / codec metadata queries
|
||||
* (olive::ExportFormat / olive::ExportCodec / olive::Encoder statics).
|
||||
*
|
||||
* This family is the module-side mirror of the facade's
|
||||
* oakengine_encoding_format_* / codec_* surface (oakengine/encoding.h):
|
||||
* the export dialog queries it to populate its format/codec combo boxes and
|
||||
* to enable/disable the bit-rate controls. The functions are stateless —
|
||||
* no handles involved.
|
||||
*
|
||||
* Enum int fields carry the engine's own enum values
|
||||
* (olive::ExportFormat::Format, olive::ExportCodec::Codec,
|
||||
* olive::core::SampleFormat::Format) — the same values oakengine/encoding.h
|
||||
* documents. Return-code convention follows include/codec/error.h: 0
|
||||
* (OAKCODEC_OK) on success, a negative OAKCODEC_E_* code on failure, and
|
||||
* string getters return the required buffer size in bytes INCLUDING the
|
||||
* terminating NUL as a non-negative value (two-stage convention). Note this
|
||||
* differs from oakcodec_export_format_get_extension() (encoder.h), which
|
||||
* predates this family and reports unknown formats as the empty string.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Container formats (olive::ExportFormat::Format) referenced by name
|
||||
* in UI code. Only append; the values are serialized in project/preset
|
||||
* files. The complete list lives in src/codec/src/exportformat.h.
|
||||
*/
|
||||
#define OAKCODEC_ENCODING_FORMAT_MATROSKA 1
|
||||
#define OAKCODEC_ENCODING_FORMAT_MPEG4_VIDEO 2
|
||||
#define OAKCODEC_ENCODING_FORMAT_QUICKTIME 4
|
||||
#define OAKCODEC_ENCODING_FORMAT_PNG 5
|
||||
#define OAKCODEC_ENCODING_FORMAT_WAV 7
|
||||
#define OAKCODEC_ENCODING_FORMAT_SRT 13
|
||||
|
||||
/**
|
||||
* @brief Codecs (olive::ExportCodec::Codec) referenced by name in UI code.
|
||||
* Only append; the values are serialized. The complete list lives in
|
||||
* src/codec/src/exportcodec.h.
|
||||
*/
|
||||
#define OAKCODEC_ENCODING_CODEC_H264 1
|
||||
#define OAKCODEC_ENCODING_CODEC_H264RGB 2
|
||||
#define OAKCODEC_ENCODING_CODEC_H265 3
|
||||
#define OAKCODEC_ENCODING_CODEC_CINEFORM 7
|
||||
#define OAKCODEC_ENCODING_CODEC_AAC 12
|
||||
#define OAKCODEC_ENCODING_CODEC_PCM 13
|
||||
#define OAKCODEC_ENCODING_CODEC_SRT 17
|
||||
#define OAKCODEC_ENCODING_CODEC_AV1 18
|
||||
|
||||
/* ---- Container format / codec metadata ---------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Number of container formats (olive::ExportFormat::k_format_count).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_count(void);
|
||||
|
||||
/**
|
||||
* @brief Display name of a container format (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `format` is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_name(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief File extension (no dot) of a container format (buf/size,
|
||||
* two-stage); same return convention as
|
||||
* oakcodec_encoding_format_name().
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_extension(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Number of video codecs a container format supports, or
|
||||
* OAKCODEC_E_INVALID when the format is invalid.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_video_codec_count(int format);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th video codec of `format` as an
|
||||
* olive::ExportCodec::Codec value.
|
||||
*
|
||||
* @return OAKCODEC_E_INVALID when the format is invalid, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_video_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/** @brief Audio-codec variant of the two functions above. */
|
||||
OAKCODEC_API int oakcodec_encoding_format_audio_codec_count(int format);
|
||||
OAKCODEC_API int oakcodec_encoding_format_audio_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/** @brief Subtitle-codec variant of the two functions above. */
|
||||
OAKCODEC_API int oakcodec_encoding_format_subtitle_codec_count(int format);
|
||||
OAKCODEC_API int oakcodec_encoding_format_subtitle_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/**
|
||||
* @brief Display name of a codec (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `codec` is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_codec_name(int codec, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/** @brief 1 when `codec` encodes still images (PNG/TIFF/OpenEXR), else 0
|
||||
* (0 also for an invalid codec). */
|
||||
OAKCODEC_API int oakcodec_encoding_codec_is_still_image(int codec);
|
||||
|
||||
/** @brief 1 when `codec` is lossless (no bit-rate setting applies), else 0
|
||||
* (0 also for an invalid codec). */
|
||||
OAKCODEC_API int oakcodec_encoding_codec_is_lossless(int codec);
|
||||
|
||||
/**
|
||||
* @brief Number of encoded pixel formats (e.g. "yuv420p") usable with
|
||||
* `codec` inside `format`, or OAKCODEC_E_INVALID when either
|
||||
* argument is out of range. The list is queried from the format's
|
||||
* encoder (FFmpeg/OIIO), so codecs without an encoder report 0.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_count(int format, int codec);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th encoded pixel format name (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID for bad format/codec, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_at(int format, int codec,
|
||||
int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Index of `pix_fmt` (e.g. "yuv420p") in `codec`'s supported pixel
|
||||
* format list; 0 (the codec's preferred format) when absent or
|
||||
* `pix_fmt` is NULL/empty or `codec` is invalid.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_index(int codec,
|
||||
const char *pix_fmt);
|
||||
|
||||
/**
|
||||
* @brief Number of sample formats usable with `codec` inside `format`, or
|
||||
* OAKCODEC_E_INVALID when either argument is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_sample_format_count(int format,
|
||||
int codec);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th sample format as an olive::core::SampleFormat::Format
|
||||
* value.
|
||||
*
|
||||
* @return OAKCODEC_E_INVALID for bad format/codec, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_sample_format_at(int format, int codec,
|
||||
int index);
|
||||
|
||||
/* ---- Image-sequence filename helpers (olive::Encoder statics) ----------- */
|
||||
|
||||
/** @brief 1 when `filename` contains a "[#####]" digit placeholder, else 0
|
||||
* (0 for NULL). */
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_filename_contains_digit_placeholder(const char *filename);
|
||||
|
||||
/** @brief Digit count of the filename's "[#####]" placeholder; 0 when none
|
||||
* (0 for NULL). */
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_image_sequence_digit_count(const char *filename);
|
||||
|
||||
/**
|
||||
* @brief `filename` with the digit placeholder removed (buf/size, two-stage;
|
||||
* a leading separator like "_"/"-"/"."/" " before the placeholder is
|
||||
* removed along with it).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `filename` is NULL.
|
||||
*/
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_filename_remove_digit_placeholder(const char *filename,
|
||||
char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_FORMAT_H
|
||||
@@ -0,0 +1,162 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_FRAME_H
|
||||
#define OAK_EDITOR_CODEC_FRAME_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/videoparams.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file frame.h
|
||||
* @brief C ABI for the oakcodec frame object (olive::Frame), a CPU pixel
|
||||
* buffer plus an OakVideoParams parameter set.
|
||||
*
|
||||
* Handle convention (all oakcodec families): neutral by-value handles with
|
||||
* the same four fields as oakcommon (see oakcommon's common/handle.h):
|
||||
*
|
||||
* typedef struct OakFrame {
|
||||
* void *ctx; // opaque, points to the impl
|
||||
* void (*addref)(void *ctx); // atomic +1, owner-DLL code
|
||||
* void (*release)(void *ctx); // atomic -1, destroys at 0
|
||||
* uint32_t abi_version; // OAKCODEC_ABI_VERSION
|
||||
* } OakFrame;
|
||||
*
|
||||
* oakcodec_frame_init*() returns a handle whose underlying object has
|
||||
* reference count 1. Copying the struct copies the pointer, not the
|
||||
* count: call handle.addref(handle.ctx) for every additional long-lived
|
||||
* copy and handle.release(handle.ctx) (or oakcodec_frame_free()) when
|
||||
* done with each copy. Functions that only use a handle take it BY
|
||||
* VALUE; an empty handle (ctx == NULL) is reported as
|
||||
* OAKCODEC_E_INVALID. oakcodec_frame_free() takes a pointer so it can
|
||||
* null out the caller's ctx; NULL and ctx == NULL are no-ops.
|
||||
*/
|
||||
typedef struct OakFrame {
|
||||
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; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakFrame;
|
||||
|
||||
/**
|
||||
* @brief Create an empty frame with default (invalid) video parameters.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_frame_init(void);
|
||||
|
||||
/**
|
||||
* @brief Create a frame with a copy of the given parameter set.
|
||||
*
|
||||
* The params handle is addref'd internally; the caller keeps its own
|
||||
* reference. The frame is not allocated; call oakcodec_frame_allocate().
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_frame_init_with_params(OakVideoParams params);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a frame.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx); nulls ctx
|
||||
* afterwards. No-op when frame is NULL or frame->ctx is NULL.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_frame_free(OakFrame *frame);
|
||||
|
||||
/**
|
||||
* @brief Get a copy of the frame's parameter set.
|
||||
*
|
||||
* @param out Receives an addref'd OakVideoParams; the caller must release
|
||||
* it with oakcommon_videoparams_free().
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_INVALID for bad arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_get_params(OakFrame frame, OakVideoParams *out);
|
||||
|
||||
/**
|
||||
* @brief Replace the frame's parameter set (the handle is addref'd
|
||||
* internally). Recomputes the line sizes; does not reallocate the
|
||||
* buffer.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_set_params(OakFrame frame, OakVideoParams params);
|
||||
|
||||
/**
|
||||
* @brief Allocate the pixel buffer from the current parameters.
|
||||
*
|
||||
* @return OAKCODEC_OK on success (including already-allocated),
|
||||
* OAKCODEC_E_STATE when the parameters are invalid,
|
||||
* OAKCODEC_E_INVALID for an empty handle.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_allocate(OakFrame frame);
|
||||
|
||||
/** @brief 1 when the pixel buffer is allocated, 0 otherwise. */
|
||||
OAKCODEC_API int oakcodec_frame_is_allocated(OakFrame frame);
|
||||
|
||||
/** @brief Writable pixel buffer, or NULL when unallocated/empty. */
|
||||
OAKCODEC_API void *oakcodec_frame_data(OakFrame frame);
|
||||
|
||||
/** @brief Const variant of oakcodec_frame_data(). */
|
||||
OAKCODEC_API const void *oakcodec_frame_const_data(OakFrame frame);
|
||||
|
||||
/** @brief Size of the pixel buffer in bytes (0 when unallocated). */
|
||||
OAKCODEC_API int oakcodec_frame_allocated_size(OakFrame frame);
|
||||
|
||||
/** @brief Distance between two rows in bytes (0 when params are unset). */
|
||||
OAKCODEC_API int oakcodec_frame_linesize_bytes(OakFrame frame);
|
||||
|
||||
/** @brief Distance between two rows in pixels. */
|
||||
OAKCODEC_API int oakcodec_frame_linesize_pixels(OakFrame frame);
|
||||
|
||||
/* Query helpers; all return 0 / OAKCOMMON_PIXEL_FORMAT_INVALID on an
|
||||
* empty handle. */
|
||||
OAKCODEC_API int oakcodec_frame_width(OakFrame frame);
|
||||
OAKCODEC_API int oakcodec_frame_height(OakFrame frame);
|
||||
OAKCODEC_API int oakcodec_frame_format(OakFrame frame); /**< OakPixelFormat value. */
|
||||
OAKCODEC_API int oakcodec_frame_channel_count(OakFrame frame);
|
||||
|
||||
/**
|
||||
* @brief Frame timestamp as a rational number of seconds.
|
||||
*
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_INVALID for bad arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_get_timestamp(OakFrame frame, int *numerator,
|
||||
int *denominator);
|
||||
OAKCODEC_API int oakcodec_frame_set_timestamp(OakFrame frame, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Number of live oakcodec handle objects (debug/leak checking).
|
||||
*
|
||||
* Counts every boxed object created by oakcodec_*_init*() that has not
|
||||
* been released yet, across all families (frame/decoder/encoder/...).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_debug_alive_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_FRAME_H
|
||||
@@ -0,0 +1,140 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_PROXY_H
|
||||
#define OAK_EDITOR_CODEC_PROXY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file proxy.h
|
||||
* @brief C ABI for the oakcodec proxy generation singleton
|
||||
* (olive::ProxyManager).
|
||||
*
|
||||
* Interim state (pre-M8): actual transcodes are delegated to the global
|
||||
* task submit callback (see task.h). While no callback is registered,
|
||||
* oakcodec_proxy_get_or_start() reports the proxy as missing instead of
|
||||
* starting background work.
|
||||
*/
|
||||
|
||||
#define OAKCODEC_PROXY_STATE_MISSING 0
|
||||
#define OAKCODEC_PROXY_STATE_GENERATING 1
|
||||
#define OAKCODEC_PROXY_STATE_READY 2
|
||||
#define OAKCODEC_PROXY_STATE_FAILED 3
|
||||
|
||||
/**
|
||||
* @brief POD proxy generation parameters (olive::ProxyManager::ProxyParams).
|
||||
*
|
||||
* divider: source resolution divider (1 = use absolute width/height,
|
||||
* 2/4/8 = fraction of the source resolution). extension/preset are the
|
||||
* ffmpeg output container and encoder preset (e.g. "mp4"/"veryfast").
|
||||
*/
|
||||
typedef struct oakcodec_proxy_params {
|
||||
int width;
|
||||
int height;
|
||||
int divider;
|
||||
int version;
|
||||
int crf;
|
||||
int include_audio; /**< 1/0. */
|
||||
char extension[32];
|
||||
char preset[32];
|
||||
} oakcodec_proxy_params;
|
||||
|
||||
typedef struct oakcodec_proxy_result {
|
||||
int state; /**< OAKCODEC_PROXY_STATE_* */
|
||||
char filename[1024];
|
||||
} oakcodec_proxy_result;
|
||||
|
||||
/**
|
||||
* @brief Create the ProxyManager singleton (no-op when it exists).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_create_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ProxyManager singleton (no-op when absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_destroy_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Compiled-in default proxy parameters (1280x720, divider 1, mp4,
|
||||
* crf 23, "veryfast", audio included). Interim state: until the config
|
||||
* milestone wires a real store these do not reflect user settings.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_params_default(oakcodec_proxy_params *out);
|
||||
|
||||
/**
|
||||
* @brief State of a proxy file on disk (OAKCODEC_PROXY_STATE_*;
|
||||
* OAKCODEC_PROXY_STATE_MISSING for NULL/empty/absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_state(const char *proxy_filename);
|
||||
|
||||
/** @brief Human-readable string for a proxy state (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_state_to_string(int state, char *buf, int buf_size);
|
||||
|
||||
/** @brief Proxy directory for a project cache path (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_get_proxy_directory(const char *cache_path, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Deterministic proxy filename for a source stream (buf/size
|
||||
* getter).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_proxy_filename(const char *cache_path,
|
||||
const char *source_filename,
|
||||
int stream_index,
|
||||
const oakcodec_proxy_params *params,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/** @brief Working (in-progress) filename of a proxy (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_get_working_filename(const char *proxy_filename,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get or start generating a proxy for `source_filename`.
|
||||
*
|
||||
* `cache_path` is the project cache directory. On return `out->state`
|
||||
* and `out->filename` describe the proxy. When a task submit callback is
|
||||
* registered (task.h) and no proxy exists, generation is submitted
|
||||
* synchronously before the state is re-derived; without a registrar the
|
||||
* state stays OAKCODEC_PROXY_STATE_MISSING.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_or_start(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
const oakcodec_proxy_params *params,
|
||||
oakcodec_proxy_result *out);
|
||||
|
||||
/**
|
||||
* @brief Locate an ffmpeg executable for proxy generation (buf/size
|
||||
* getter; empty string when none is found).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_find_ffmpeg(const char *configured_path, char *buf,
|
||||
int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_PROXY_H
|
||||
@@ -0,0 +1,113 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_TASK_H
|
||||
#define OAK_EDITOR_CODEC_TASK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Background task submission hook for oakcodec (interim state).
|
||||
*
|
||||
* The codec module occasionally needs background work (audio conforms,
|
||||
* proxy transcodes). The task system itself is split out at milestone M8;
|
||||
* until then oakcodec exposes a single global submit callback. A host
|
||||
* (M8: oaktask) registers a callback with oakcodec_set_task_submit_cb();
|
||||
* the conform/proxy managers call it whenever they need a task.
|
||||
*
|
||||
* While no callback is registered, managers report the work as
|
||||
* unavailable (they never crash and never block).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Kinds of background tasks oakcodec can request.
|
||||
*/
|
||||
enum OakCodecTaskKind {
|
||||
OAKCODEC_TASK_CONFORM = 0, /**< Audio conform to pcm cache files. */
|
||||
OAKCODEC_TASK_PROXY = 1 /**< Video proxy transcode. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Description of one background task request.
|
||||
*
|
||||
* All strings are borrowed and only valid for the duration of the
|
||||
* submit call; the callback must copy anything it retains.
|
||||
*
|
||||
* Field usage by kind:
|
||||
* - OAKCODEC_TASK_CONFORM: input_filename (source media), stream_index
|
||||
* (audio stream), output_filename (final path of the FIRST channel's
|
||||
* pcm file; the task derives the sibling per-channel paths and the
|
||||
* ".working" temporary names from the deterministic naming rule),
|
||||
* sample_rate / channel_layout / sample_format (target audio params,
|
||||
* sample_format is olive::core::SampleFormat::Format as int).
|
||||
* - OAKCODEC_TASK_PROXY: input_filename (source media), stream_index
|
||||
* (video stream), output_filename (final proxy path; the task owns
|
||||
* the ".working.mp4" temporary name and the rename on success),
|
||||
* proxy_width / proxy_height (absolute target size, both 0 when the
|
||||
* request is divider-based).
|
||||
*/
|
||||
typedef struct OakCodecTaskRequest {
|
||||
int kind; /**< OakCodecTaskKind. */
|
||||
const char *input_filename; /**< Source media filename. */
|
||||
const char *output_filename; /**< Final destination path (see above). */
|
||||
int stream_index; /**< Stream inside the source media. */
|
||||
int sample_rate; /**< conform: target sample rate. */
|
||||
uint64_t channel_layout; /**< conform: target channel layout mask. */
|
||||
int sample_format; /**< conform: target sample format (enum as int). */
|
||||
int proxy_width; /**< proxy: target width, 0 = unspecified/divider. */
|
||||
int proxy_height; /**< proxy: target height, 0 = unspecified/divider. */
|
||||
} OakCodecTaskRequest;
|
||||
|
||||
/**
|
||||
* @brief Task submit callback.
|
||||
*
|
||||
* @return 0 (OAKCODEC_OK) if the task was accepted - either completed
|
||||
* synchronously or queued; a negative OAKCODEC_E_* code if the request
|
||||
* was rejected.
|
||||
*/
|
||||
typedef int (*oakcodec_task_submit_fn)(const OakCodecTaskRequest *req,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Registers (or replaces) the global task submit callback.
|
||||
*
|
||||
* Thread-safe. Pass cb == NULL to unregister. Interim state (pre-M8):
|
||||
* nobody registers and all task-dependent work reports unavailable.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_set_task_submit_cb(oakcodec_task_submit_fn cb, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Returns 1 if a submit callback is currently registered, else 0.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_task_submit_is_registered(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_TASK_H
|
||||
@@ -0,0 +1,156 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_COLORTRANSFORM_H
|
||||
#define OAK_EDITOR_COLORTRANSFORM_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace olive
|
||||
{
|
||||
class ColorTransform;
|
||||
}
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a color transform description
|
||||
* (olive::ColorTransform).
|
||||
*
|
||||
* Ownership/count semantics follow the convention in common/handle.h:
|
||||
* init functions return a handle whose object has reference count 1,
|
||||
* addref(ctx)/release(ctx) adjust it atomically, and release destroys
|
||||
* the object at zero. abi_version is always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakColorTransform {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakColorTransform;
|
||||
|
||||
/**
|
||||
* @brief Create a plain output-colorspace transform.
|
||||
*
|
||||
* @param output Output colorspace name. Must not be NULL.
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakColorTransform oakcommon_colortransform_init_output(
|
||||
const char *output);
|
||||
|
||||
/**
|
||||
* @brief Create a display/view/look transform.
|
||||
*
|
||||
* All three strings must not be NULL.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakColorTransform oakcommon_colortransform_init_display(
|
||||
const char *display, const char *view, const char *look);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* @brief Copy a native olive::ColorTransform into a new handle.
|
||||
*
|
||||
* The source object is deep-copied; the handle does not keep any
|
||||
* reference to @p src, which may be destroyed immediately afterwards.
|
||||
* Only visible to C++ consumers.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL if src is NULL or
|
||||
* on allocation failure.
|
||||
*/
|
||||
OakColorTransform oakcommon_colortransform_init_from_native(
|
||||
const olive::ColorTransform *src);
|
||||
|
||||
/**
|
||||
* @brief Borrow the native object behind a handle.
|
||||
*
|
||||
* The returned pointer is borrowed: it stays valid while the caller
|
||||
* holds a reference to the handle (i.e. until the matching release).
|
||||
* Only visible to C++ consumers.
|
||||
*
|
||||
* @return Borrowed pointer, or NULL if transform is NULL or
|
||||
* transform->ctx is NULL.
|
||||
*/
|
||||
const olive::ColorTransform *oakcommon_colortransform_get_native(
|
||||
OakColorTransform transform);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a transform.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when transform is NULL or transform->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_colortransform_free(OakColorTransform *transform);
|
||||
|
||||
/**
|
||||
* @brief Query whether this is a display/view/look transform.
|
||||
*
|
||||
* @param is_display Receives the result. Must not be NULL.
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_colortransform_is_display(OakColorTransform transform,
|
||||
int *is_display);
|
||||
|
||||
/**
|
||||
* @brief Get the display name (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_colortransform_get_display(OakColorTransform transform,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get the output colorspace name (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_colortransform_get_output(OakColorTransform transform,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get the view name (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_colortransform_get_view(OakColorTransform transform,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get the look name (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_colortransform_get_look(OakColorTransform transform,
|
||||
char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_COLORTRANSFORM_H
|
||||
@@ -0,0 +1,225 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_COMMANDLINEPARSER_H
|
||||
#define OAK_EDITOR_COMMANDLINEPARSER_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a command-line parser instance.
|
||||
*
|
||||
* Ownership/count semantics follow the convention in common/handle.h:
|
||||
* init returns a handle whose object has reference count 1,
|
||||
* addref(ctx)/release(ctx) adjust it atomically, and release destroys
|
||||
* the object at zero. abi_version is always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakCommandLineParser {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakCommandLineParser;
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a registered command-line option.
|
||||
*
|
||||
* The handle is released with oakcommon_commandlineoption_free() (or
|
||||
* handle.release(handle.ctx)); the underlying option is owned by the
|
||||
* parser and stays valid until the parser is destroyed. abi_version is
|
||||
* always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakCommandLineOption {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakCommandLineOption;
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a registered positional argument.
|
||||
*
|
||||
* The handle is released with
|
||||
* oakcommon_commandlinepositionalargument_free() (or
|
||||
* handle.release(handle.ctx)); the underlying argument is owned by the
|
||||
* parser and stays valid until the parser is destroyed. abi_version is
|
||||
* always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakCommandLinePositionalArgument {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakCommandLinePositionalArgument;
|
||||
|
||||
/**
|
||||
* @brief Create a command-line parser.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakCommandLineParser oakcommon_commandlineparser_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a command-line parser.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the parser (invalidating all
|
||||
* option and positional-argument handles created from it) when the
|
||||
* count reaches zero. No-op when parser is NULL or parser->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_commandlineparser_free(OakCommandLineParser *parser);
|
||||
|
||||
/**
|
||||
* @brief Set the application name/version shown by print_help.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineparser_set_app_info(OakCommandLineParser parser,
|
||||
const char *name,
|
||||
const char *version);
|
||||
|
||||
/**
|
||||
* @brief Register an option with one or more name strings.
|
||||
*
|
||||
* @param names Array of option name strings (without leading dash).
|
||||
* @param name_count Number of entries in names. Must be > 0.
|
||||
* @param description Help text, may be NULL.
|
||||
* @param takes_arg Non-zero if the option consumes the following argument.
|
||||
* @param arg_placeholder Placeholder shown in help, may be NULL.
|
||||
* @param hidden Non-zero to omit from help output.
|
||||
* @param out_option Receives the option handle (reference count 1).
|
||||
* May be NULL if unused.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineparser_add_option(
|
||||
OakCommandLineParser parser, const char *const *names, int name_count,
|
||||
const char *description, int takes_arg, const char *arg_placeholder,
|
||||
int hidden, OakCommandLineOption *out_option);
|
||||
|
||||
/**
|
||||
* @brief Register a positional argument.
|
||||
*
|
||||
* @param out_argument Receives the argument handle (reference count 1).
|
||||
* May be NULL if unused.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineparser_add_positional_argument(
|
||||
OakCommandLineParser parser, const char *name,
|
||||
const char *description, int required,
|
||||
OakCommandLinePositionalArgument *out_argument);
|
||||
|
||||
/**
|
||||
* @brief Parse an argv-style argument list.
|
||||
*
|
||||
* argv[0] is skipped as the program name, matching C main() convention.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineparser_process(OakCommandLineParser parser,
|
||||
const char *const *argv, int argc);
|
||||
|
||||
/**
|
||||
* @brief Print usage/help text to stdout.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineparser_print_help(OakCommandLineParser parser,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Query whether an option was present on the command line.
|
||||
*
|
||||
* @param is_set Receives the result. Must not be NULL.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineoption_is_set(OakCommandLineOption option,
|
||||
bool *is_set);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to an option handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx). Does not
|
||||
* unregister the option from the parser. No-op when option is NULL or
|
||||
* option->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_commandlineoption_free(OakCommandLineOption *option);
|
||||
|
||||
/**
|
||||
* @brief Get an option's argument value (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineoption_get_setting(OakCommandLineOption option,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set an option's argument value.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlineoption_set_setting(OakCommandLineOption option,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Get a positional argument's value (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlinepositionalargument_get_setting(
|
||||
OakCommandLinePositionalArgument argument, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set a positional argument's value.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_commandlinepositionalargument_set_setting(
|
||||
OakCommandLinePositionalArgument argument, const char *value);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a positional argument handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx). Does not
|
||||
* unregister the argument from the parser. No-op when argument is NULL
|
||||
* or argument->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_commandlinepositionalargument_free(
|
||||
OakCommandLinePositionalArgument *argument);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_COMMANDLINEPARSER_H
|
||||
@@ -0,0 +1,189 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_COMMON_CONFIG_H
|
||||
#define OAK_EDITOR_COMMON_CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief De-Qt application configuration store, C ABI
|
||||
* (M1-oakcommon.md §2.1, extended for the real consumer surface)
|
||||
*
|
||||
* oakcommon_config is a process-wide singleton key/value store (the de-Qt
|
||||
* replacement for engine/config/config.h's QSettings/QVariant wrapper).
|
||||
* Per the config-wave ruling it is NOT wrapped in the refcounted-handle
|
||||
* convention of common/handle.h: there is exactly one store per process,
|
||||
* so the family is a plain set of functions over that singleton (same
|
||||
* singleton precedent as OakCurrent).
|
||||
*
|
||||
* Keys follow the frozen (group, key) convention of §2.1 and keep the
|
||||
* QSettings INI shape: pass group == NULL (or "") for a top-level key,
|
||||
* otherwise the entry is stored under an INI [group] section and
|
||||
* addressed as "group/key" internally.
|
||||
*
|
||||
* Values are typed (string / int64 / double / bool). Rational settings
|
||||
* are stored as strings in the "num/den" form used by
|
||||
* oakcore_rational_to_string(). Typed getters take a fallback which is
|
||||
* returned when the key is absent or has a different type (§2.1 special
|
||||
* convention: they return values, not error codes).
|
||||
*
|
||||
* Persistence is an INI file at
|
||||
* <FileFunctions::get_configuration_location()>/config.ini. The store
|
||||
* starts up with compiled-in defaults; oakcommon_config_load() re-reads
|
||||
* the file (a missing file is not an error) and oakcommon_config_save()
|
||||
* writes it. The OAK_CONFIG_DIR environment override honored by
|
||||
* get_configuration_location() also redirects this file (tests/tooling).
|
||||
*
|
||||
* NOTE (behavior change): the old Qt implementation persisted to
|
||||
* config.xml (engine XML) — and on macOS QSettings used a plist — so
|
||||
* previously saved settings do NOT carry over; the first run starts from
|
||||
* the compiled-in defaults.
|
||||
*/
|
||||
|
||||
typedef enum OakCommonConfigEntryType {
|
||||
OAKCOMMON_CONFIG_ENTRY_NONE = 0, /**< No entry / null type. */
|
||||
OAKCOMMON_CONFIG_ENTRY_STRING = 1,
|
||||
OAKCOMMON_CONFIG_ENTRY_INT = 2,
|
||||
OAKCOMMON_CONFIG_ENTRY_DOUBLE = 3,
|
||||
OAKCOMMON_CONFIG_ENTRY_BOOL = 4
|
||||
} OakCommonConfigEntryType;
|
||||
|
||||
/**
|
||||
* @brief Handler for configuration errors that should be shown to the user
|
||||
*
|
||||
* The engine layer cannot show dialogs itself. The UI registers a handler
|
||||
* (e.g. QMessageBox-based) at startup; without one, errors go to stderr.
|
||||
* Same injection pattern as the codec task-submit callback.
|
||||
*/
|
||||
typedef void (*OakCommonConfigErrorHandler)(const char *title,
|
||||
const char *message,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Resets the store to compiled-in defaults and loads config.ini
|
||||
*
|
||||
* A missing file leaves the defaults in place and returns OAKCOMMON_OK.
|
||||
* Malformed lines are skipped. An unreadable existing file is reported
|
||||
* through the error handler and returns OAKCOMMON_E_FAILED.
|
||||
*/
|
||||
int oakcommon_config_load(void);
|
||||
|
||||
/**
|
||||
* @brief Writes the current store to config.ini (via a temp file + rename)
|
||||
*
|
||||
* On failure the error handler is invoked and OAKCOMMON_E_FAILED is
|
||||
* returned.
|
||||
*/
|
||||
int oakcommon_config_save(void);
|
||||
|
||||
/**
|
||||
* @brief Resets the store to compiled-in defaults (drops custom keys)
|
||||
*/
|
||||
int oakcommon_config_reset_defaults(void);
|
||||
|
||||
/**
|
||||
* @brief Sets a string entry (§2.1)
|
||||
*
|
||||
* A new key is created as OAKCOMMON_CONFIG_ENTRY_STRING. Setting an
|
||||
* existing typed (INT/DOUBLE/BOOL) entry parses the string into its
|
||||
* declared type; an unparseable value returns OAKCOMMON_E_STATE and
|
||||
* leaves the entry unchanged.
|
||||
*/
|
||||
void oakcommon_config_set(const char *group, const char *key,
|
||||
const char *value_utf8);
|
||||
|
||||
/**
|
||||
* @brief Reads an entry as a string, two-stage buffer (§2.1)
|
||||
*
|
||||
* Numeric/bool entries are formatted (bools as "true"/"false", doubles
|
||||
* with %g).
|
||||
*
|
||||
* @return Required buffer size in bytes (including the terminating NUL),
|
||||
* or a negative OAKCOMMON_E_* error code (OAKCOMMON_E_NOT_FOUND when the
|
||||
* key is absent).
|
||||
*/
|
||||
int oakcommon_config_get(const char *group, const char *key, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Reads an INT entry as int (§2.1)
|
||||
*
|
||||
* @return The stored value, or `fallback` when the key is absent or has
|
||||
* a different type.
|
||||
*/
|
||||
int oakcommon_config_get_int(const char *group, const char *key,
|
||||
int fallback);
|
||||
|
||||
/**
|
||||
* @brief Reads a DOUBLE entry (§2.1), fallback semantics as get_int
|
||||
*/
|
||||
double oakcommon_config_get_double(const char *group, const char *key,
|
||||
double fallback);
|
||||
|
||||
/**
|
||||
* @brief Sets an INT entry (32-bit, §2.1)
|
||||
*/
|
||||
void oakcommon_config_set_int(const char *group, const char *key, int v);
|
||||
|
||||
/**
|
||||
* @brief INT entry as int64 (extension for channel-layout style values)
|
||||
*/
|
||||
int64_t oakcommon_config_get_int64(const char *group, const char *key,
|
||||
int64_t fallback);
|
||||
void oakcommon_config_set_int64(const char *group, const char *key,
|
||||
int64_t v);
|
||||
|
||||
/**
|
||||
* @brief BOOL entry as int 0/1 (extension), fallback semantics as get_int
|
||||
*/
|
||||
int oakcommon_config_get_bool(const char *group, const char *key,
|
||||
int fallback);
|
||||
void oakcommon_config_set_bool(const char *group, const char *key, int v);
|
||||
|
||||
/**
|
||||
* @brief Sets a DOUBLE entry (extension)
|
||||
*/
|
||||
void oakcommon_config_set_double(const char *group, const char *key,
|
||||
double v);
|
||||
|
||||
/**
|
||||
* @brief Returns the OakCommonConfigEntryType of a key, or a negative
|
||||
* OAKCOMMON_E_* error (OAKCOMMON_E_NOT_FOUND when the key is absent)
|
||||
*/
|
||||
int oakcommon_config_entry_type(const char *group, const char *key);
|
||||
|
||||
/**
|
||||
* @brief Registers (or clears, with NULL) the error handler
|
||||
*/
|
||||
int oakcommon_config_set_error_handler(OakCommonConfigErrorHandler handler,
|
||||
void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_COMMON_CONFIG_H
|
||||
@@ -0,0 +1,123 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CURRENT_H
|
||||
#define OAK_EDITOR_CURRENT_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to the process-wide Current singleton.
|
||||
*
|
||||
* Uses the standard handle layout (see common/handle.h) but with
|
||||
* singleton semantics: ctx points to a statically allocated object that
|
||||
* lives until process exit, so addref() and release() are intentionally
|
||||
* no-ops and never destroy anything. abi_version is always
|
||||
* OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakCurrent {
|
||||
void *ctx; /**< Opaque pointer to the singleton object. */
|
||||
void (*addref)(void *ctx); /**< No-op (singleton). */
|
||||
void (*release)(void *ctx); /**< No-op (singleton). */
|
||||
uint32_t abi_version; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakCurrent;
|
||||
|
||||
/**
|
||||
* @brief Destructor callback for objects handed to Current slots.
|
||||
*
|
||||
* Called when the slot is overwritten or cleared. May be NULL if the
|
||||
* caller keeps ownership of the object.
|
||||
*/
|
||||
typedef void (*OakDestroyFn)(void *obj);
|
||||
|
||||
/**
|
||||
* @brief Return a handle to the process-wide Current singleton.
|
||||
*
|
||||
* The returned handle is borrowed: its ctx is valid for the lifetime of
|
||||
* the process. addref/release on it are no-ops; calling
|
||||
* oakcommon_current_free() is allowed for symmetry and does nothing.
|
||||
*/
|
||||
OakCurrent oakcommon_current_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Release a Current handle.
|
||||
*
|
||||
* No-op: the underlying object is a singleton whose release() never
|
||||
* destroys anything. Safe to call with NULL or a ctx == NULL handle.
|
||||
*/
|
||||
void oakcommon_current_free(OakCurrent *self);
|
||||
|
||||
/**
|
||||
* @brief Store a pointer in a Current slot, taking over destruction.
|
||||
*
|
||||
* Passing NULL for obj clears the slot (destroy is ignored). If a
|
||||
* previous object with a destroy callback was stored, it is destroyed.
|
||||
*
|
||||
* @param self Handle from oakcommon_current_instance().
|
||||
* @param obj Opaque pointer to the external object (e.g. a
|
||||
* VideoParams), or NULL to clear.
|
||||
* @param destroy Optional destructor invoked when the slot is replaced.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if self.ctx is NULL.
|
||||
*/
|
||||
int oakcommon_current_set_video_params(OakCurrent self, void *obj,
|
||||
OakDestroyFn destroy);
|
||||
int oakcommon_current_set_audio_params(OakCurrent self, void *obj,
|
||||
OakDestroyFn destroy);
|
||||
int oakcommon_current_set_plugin_host(OakCurrent self, void *obj,
|
||||
OakDestroyFn destroy);
|
||||
int oakcommon_current_set_plugin_cache(OakCurrent self, void *obj,
|
||||
OakDestroyFn destroy);
|
||||
|
||||
/**
|
||||
* @brief Fetch the raw pointer currently stored in a slot.
|
||||
*
|
||||
* The returned pointer is borrowed and remains valid until the slot is
|
||||
* overwritten or cleared. *out is set to NULL when the slot is empty.
|
||||
*
|
||||
* @param self Handle from oakcommon_current_instance().
|
||||
* @param out Receives the stored pointer.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if self.ctx or
|
||||
* out is NULL.
|
||||
*/
|
||||
int oakcommon_current_get_video_params(OakCurrent self, void **out);
|
||||
int oakcommon_current_get_audio_params(OakCurrent self, void **out);
|
||||
int oakcommon_current_get_plugin_host(OakCurrent self, void **out);
|
||||
int oakcommon_current_get_plugin_cache(OakCurrent self, void **out);
|
||||
|
||||
/**
|
||||
* @brief Query whether the session is interactive.
|
||||
*
|
||||
* @param self Handle from oakcommon_current_instance().
|
||||
* @param out Receives 1 for interactive, 0 otherwise.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if self.ctx or
|
||||
* out is NULL.
|
||||
*/
|
||||
int oakcommon_current_is_interactive(OakCurrent self, int *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_CURRENT_H
|
||||
@@ -0,0 +1,113 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_DEBUG_H
|
||||
#define OAK_EDITOR_DEBUG_H
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Severity levels for oakcommon debug output.
|
||||
*
|
||||
* Mirrors olive::DebugLevel in src/common/src/debug.h.
|
||||
*/
|
||||
enum OakDebugLevel {
|
||||
OAKCOMMON_DEBUG_DEBUG = 0, /**< Verbose debug message. */
|
||||
OAKCOMMON_DEBUG_INFO = 1, /**< Informational message. */
|
||||
OAKCOMMON_DEBUG_WARNING = 2, /**< Warning message. */
|
||||
OAKCOMMON_DEBUG_ERROR = 3, /**< Error message. */
|
||||
OAKCOMMON_DEBUG_FATAL = 4 /**< Fatal error message. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Print a debug message to stderr, prefixed with its level.
|
||||
*
|
||||
* De-Qt replacement for the old Qt message handler. The line is
|
||||
* flushed immediately.
|
||||
*
|
||||
* @param level One of OakDebugLevel; out-of-range values print
|
||||
* as "UNKNOWN".
|
||||
* @param msg NUL-terminated message; NULL is treated as an empty
|
||||
* string.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if msg is NULL.
|
||||
*/
|
||||
int oakcommon_debug_log(int level, const char *msg);
|
||||
|
||||
/**
|
||||
* @brief Copy the printable name of a debug level into buf.
|
||||
*
|
||||
* Two-segment string getter: if buf is NULL or buf_size is too small,
|
||||
* nothing is written.
|
||||
*
|
||||
* @param level One of OakDebugLevel.
|
||||
* @param buf Destination buffer, may be NULL to query the size.
|
||||
* @param buf_size Size of buf in bytes.
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative).
|
||||
*/
|
||||
int oakcommon_debug_level_name(int level, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief printf-style filtered log, replacing qDebug()/qInfo()/
|
||||
* qWarning()/qCritical() call sites.
|
||||
*
|
||||
* The message is formatted with vsnprintf into a dynamically sized
|
||||
* buffer (arbitrary length, no truncation, no fixed stack buffer) and
|
||||
* emitted as "[LEVEL] message\n" unless @p level is below the current
|
||||
* filter level (see oakcommon_log_set_level()).
|
||||
*
|
||||
* @param level One of OakDebugLevel; out-of-range values print
|
||||
* as "UNKNOWN" and are never filtered out below FATAL.
|
||||
* @param fmt printf-style format string. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if fmt is NULL,
|
||||
* OAKCOMMON_E_FAILED if formatting failed.
|
||||
*/
|
||||
int oakcommon_log(int level, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Set the minimum level emitted by oakcommon_log().
|
||||
*
|
||||
* Messages with a lower level are dropped. The default is
|
||||
* OAKCOMMON_DEBUG_INFO.
|
||||
*
|
||||
* @param level One of OakDebugLevel.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if level is
|
||||
* outside the OakDebugLevel range.
|
||||
*/
|
||||
int oakcommon_log_set_level(int level);
|
||||
|
||||
/**
|
||||
* @brief Query the current minimum level emitted by oakcommon_log().
|
||||
*
|
||||
* @param out_level Receives one of OakDebugLevel. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_level is
|
||||
* NULL.
|
||||
*/
|
||||
int oakcommon_log_get_level(int *out_level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_DEBUG_H
|
||||
@@ -0,0 +1,73 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_DROPWORKFLOWBEHAVIOR_H
|
||||
#define OAK_EDITOR_DROPWORKFLOWBEHAVIOR_H
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Behavior when media is dropped onto a timeline without a
|
||||
* sequence.
|
||||
*
|
||||
* Mirrors olive::DropWithoutSequenceBehavior in
|
||||
* src/common/src/dropworkflowbehavior.h; enumerator order and values
|
||||
* must stay identical because the config layer persists them as ints.
|
||||
*/
|
||||
enum OakDropWorkflowBehavior {
|
||||
OAKCOMMON_DWS_ASK = 0, /**< Ask the user every time. */
|
||||
OAKCOMMON_DWS_AUTO = 1, /**< Automatically create a sequence. */
|
||||
OAKCOMMON_DWS_MANUAL = 2, /**< Never create; import manually. */
|
||||
OAKCOMMON_DWS_DISABLE = 3 /**< Disable dropping entirely. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Check whether value is a valid OakDropWorkflowBehavior.
|
||||
*
|
||||
* @param value Integer behavior value (e.g. read from config).
|
||||
* @return 1 if valid, 0 otherwise (this is a predicate, not a status
|
||||
* code).
|
||||
*/
|
||||
int oakcommon_drop_workflow_behavior_is_valid(int value);
|
||||
|
||||
/**
|
||||
* @brief Copy the printable name of a behavior into buf.
|
||||
*
|
||||
* Two-segment string getter: if buf is NULL or buf_size is too small,
|
||||
* nothing is written. Invalid values yield "UNKNOWN".
|
||||
*
|
||||
* @param value One of OakDropWorkflowBehavior.
|
||||
* @param buf Destination buffer, may be NULL to query the size.
|
||||
* @param buf_size Size of buf in bytes.
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative).
|
||||
*/
|
||||
int oakcommon_drop_workflow_behavior_name(int value, char *buf,
|
||||
int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_DROPWORKFLOWBEHAVIOR_H
|
||||
@@ -0,0 +1,66 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_ERROR_H
|
||||
#define OAK_EDITOR_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakcommon C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKCOMMON_OK) on success, a negative OAKCOMMON_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*
|
||||
* Project-wide error code scheme (-MMCCCC, 2026-08):
|
||||
* every module's error codes are negative integers of the form
|
||||
* -(MM * 10000 + CCCC), where MM is the module number from the registry
|
||||
* below and CCCC is a module-local code. The first module-local codes
|
||||
* are reserved and identical across modules: 0001 INVALID, 0002 STATE,
|
||||
* 0003 FAILED, 0004 NOT_FOUND, 0005 NOMEM, 0006 CANCELLED.
|
||||
*
|
||||
* An error code crossing a module boundary is passed through
|
||||
* UNTRANSLATED — the numeric module prefix preserves provenance
|
||||
* (e.g. -30004 is oaknode's NOT_FOUND no matter which module reports it
|
||||
* to the caller).
|
||||
*
|
||||
* Module number registry (only ever appended to; numbers are frozen):
|
||||
*/
|
||||
#define OAK_ERROR_MODULE_COMMON 1 /**< oakcommon */
|
||||
#define OAK_ERROR_MODULE_UNDO 2 /**< oakundo */
|
||||
#define OAK_ERROR_MODULE_NODE 3 /**< oaknode */
|
||||
#define OAK_ERROR_MODULE_TIMELINE 4 /**< oaktimeline */
|
||||
#define OAK_ERROR_MODULE_CODEC 5 /**< oakcodec */
|
||||
#define OAK_ERROR_MODULE_AUDIO 6 /**< oakaudio */
|
||||
#define OAK_ERROR_MODULE_RENDER 7 /**< oakrender */
|
||||
#define OAK_ERROR_MODULE_TASK 8 /**< oaktask */
|
||||
#define OAK_ERROR_MODULE_PLUGIN 9 /**< oakplugin */
|
||||
#define OAK_ERROR_MODULE_STORAGE 10 /**< oakstorage (reserved) */
|
||||
|
||||
#define OAKCOMMON_OK 0 /**< Success. */
|
||||
#define OAKCOMMON_E_INVALID (-10001) /**< Empty handle (ctx == NULL) or invalid argument. */
|
||||
#define OAKCOMMON_E_STATE (-10002) /**< Call not valid in the current state. */
|
||||
#define OAKCOMMON_E_FAILED (-10003) /**< The underlying operation failed. */
|
||||
#define OAKCOMMON_E_NOT_FOUND (-10004) /**< Index out of range / entry not found. */
|
||||
#define OAKCOMMON_E_NOMEM (-10005) /**< Allocation failed. */
|
||||
|
||||
#define SUCCESS OAKCOMMON_OK /**< @deprecated Use OAKCOMMON_OK. */
|
||||
|
||||
#endif //OAK_EDITOR_ERROR_H
|
||||
@@ -0,0 +1,116 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_FFMPEGUTILS_H
|
||||
#define OAK_EDITOR_FFMPEGUTILS_H
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Stateless mappings between native pixel/sample formats and the
|
||||
* opaque FBPixelFormat / FBSampleFormat constants of ffmpeg_bridge
|
||||
*
|
||||
* All functions are pure format conversions; there is no handle to create
|
||||
* or free. Native pixel/sample formats are passed as plain ints matching
|
||||
* the olive::core::PixelFormat::Format / SampleFormat::Format enum values
|
||||
* (invalid = -1). Bridge formats are the fb_pix_fmt_* / fb_sample_fmt_*
|
||||
* constants from ffmpeg_bridge/ffmpeg_bridge.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief RGB / RGBA channel counts (flattened from VideoParams)
|
||||
*/
|
||||
#define OAKCOMMON_RGB_CHANNEL_COUNT 3
|
||||
#define OAKCOMMON_RGBA_CHANNEL_COUNT 4
|
||||
|
||||
/**
|
||||
* @brief Returns a bridge pixel format that a frame can be converted to
|
||||
* with minimal data loss, clamped to a maximum native precision
|
||||
*
|
||||
* @param pix_fmt bridge pixel format to find a compatible conversion for
|
||||
* @param maximum_pix_fmt maximum native pixel format, or -1 for no limit
|
||||
* @param out receives the chosen bridge pixel format
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_get_compatible_bridge_pixel_format(
|
||||
int pix_fmt, int maximum_pix_fmt, int *out);
|
||||
|
||||
/**
|
||||
* @brief Returns a native pixel format usable to convert from a native
|
||||
* frame to a bridge frame with minimal data loss
|
||||
*
|
||||
* @param pix_fmt native pixel format
|
||||
* @param out receives the compatible native pixel format (-1 if none)
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_get_compatible_pixel_format(int pix_fmt,
|
||||
int *out);
|
||||
|
||||
/**
|
||||
* @brief Returns a bridge pixel format for a given native pixel format
|
||||
*
|
||||
* @param pix_fmt native pixel format
|
||||
* @param channel_count OAKCOMMON_RGB_CHANNEL_COUNT or
|
||||
* OAKCOMMON_RGBA_CHANNEL_COUNT
|
||||
* @param out receives the bridge pixel format (fb_pix_fmt_none if none)
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_get_ffmpeg_pixel_format(int pix_fmt,
|
||||
int channel_count,
|
||||
int *out);
|
||||
|
||||
/**
|
||||
* @brief Returns a native sample format for a given bridge sample format
|
||||
*
|
||||
* @param smp_fmt bridge sample format
|
||||
* @param out receives the native sample format (-1 if unknown)
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_get_native_sample_format(int smp_fmt, int *out);
|
||||
|
||||
/**
|
||||
* @brief Returns a bridge sample format for a given native sample format
|
||||
*
|
||||
* @param smp_fmt native sample format
|
||||
* @param out receives the bridge sample format (fb_sample_fmt_none if none)
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_get_ffmpeg_sample_format(int smp_fmt, int *out);
|
||||
|
||||
/**
|
||||
* @brief Converts a "JPEG" full-range bridge pixel format to its regular
|
||||
* counterpart
|
||||
*
|
||||
* @param pix_fmt bridge pixel format
|
||||
* @param out receives the regular-range format (unchanged if not JPEG)
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out is NULL
|
||||
*/
|
||||
int oakcommon_ffmpegutils_convert_jpeg_space_to_regular_space(int pix_fmt,
|
||||
int *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_FFMPEGUTILS_H
|
||||
@@ -0,0 +1,167 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_FILEFUNCTIONS_H
|
||||
#define OAK_EDITOR_FILEFUNCTIONS_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle for the filefunctions family
|
||||
*
|
||||
* File functions are stateless; the handle only exists to keep the C API
|
||||
* shape uniform across oakcommon families. Ownership/count semantics
|
||||
* follow the convention in common/handle.h: init returns a handle whose
|
||||
* (empty) object has reference count 1, addref(ctx)/release(ctx) adjust
|
||||
* it atomically, and release destroys it at zero. abi_version is always
|
||||
* OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakFileFunctions {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakFileFunctions;
|
||||
|
||||
/**
|
||||
* @brief Creates a filefunctions handle
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakFileFunctions oakcommon_filefunctions_init(void);
|
||||
|
||||
/**
|
||||
* @brief Releases one reference to a filefunctions handle
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when self is NULL or self->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_filefunctions_free(OakFileFunctions *self);
|
||||
|
||||
/**
|
||||
* @brief Returns a deterministic identifier string for a file
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code. Returns an empty string (required size 1) if
|
||||
* the file does not exist.
|
||||
*/
|
||||
int oakcommon_filefunctions_get_unique_file_identifier(
|
||||
OakFileFunctions self, const char *filename, char *buf,
|
||||
int buf_size);
|
||||
|
||||
int oakcommon_filefunctions_get_configuration_location(
|
||||
OakFileFunctions self, char *buf, int buf_size);
|
||||
|
||||
int oakcommon_filefunctions_get_application_path(
|
||||
OakFileFunctions self, char *buf, int buf_size);
|
||||
|
||||
int oakcommon_filefunctions_get_temp_file_path(
|
||||
OakFileFunctions self, char *buf, int buf_size);
|
||||
|
||||
int oakcommon_filefunctions_get_auto_recovery_root(
|
||||
OakFileFunctions self, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Checks whether `source` can be copied to `dest` without
|
||||
* overwriting anything
|
||||
*
|
||||
* @param out Receives 1 (safe) or 0 (would overwrite).
|
||||
*/
|
||||
int oakcommon_filefunctions_can_copy_directory_without_overwriting(
|
||||
OakFileFunctions self, const char *source, const char *dest,
|
||||
int *out);
|
||||
|
||||
/**
|
||||
* @brief Recursively copies a directory
|
||||
*/
|
||||
int oakcommon_filefunctions_copy_directory(OakFileFunctions self,
|
||||
const char *source,
|
||||
const char *dest, int overwrite);
|
||||
|
||||
/**
|
||||
* @brief Checks whether a directory exists, optionally creating it
|
||||
*
|
||||
* @param out Receives 1 (valid) or 0 (invalid).
|
||||
*/
|
||||
int oakcommon_filefunctions_directory_is_valid(
|
||||
OakFileFunctions self, const char *dir,
|
||||
int try_to_create_if_not_exists, int *out);
|
||||
|
||||
/**
|
||||
* @brief Ensures a filename ends with the given extension (no dot)
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_filefunctions_ensure_filename_extension(
|
||||
OakFileFunctions self, const char *filename,
|
||||
const char *extension, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Reads an entire file into a string
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code. Returns an empty string (required size 1) if
|
||||
* the file cannot be read.
|
||||
*/
|
||||
int oakcommon_filefunctions_read_file_as_string(
|
||||
OakFileFunctions self, const char *filename, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Returns a non-existing temporary variant of `original`
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_filefunctions_get_safe_temporary_filename(
|
||||
OakFileFunctions self, const char *original, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Renames `from` to `to`, deleting `to` first if it exists
|
||||
*
|
||||
* @param out Receives 1 (renamed) or 0 (failed).
|
||||
*/
|
||||
int oakcommon_filefunctions_rename_file_allow_overwrite(
|
||||
OakFileFunctions self, const char *from, const char *to,
|
||||
int *out);
|
||||
|
||||
/**
|
||||
* @brief Appends the platform executable suffix (".exe" on Windows)
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_filefunctions_get_formatted_executable_for_platform(
|
||||
OakFileFunctions self, const char *unformatted, char *buf,
|
||||
int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_FILEFUNCTIONS_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_HANDLE_H
|
||||
#define OAK_EDITOR_HANDLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Current ABI version stamped into every oakcommon handle.
|
||||
*
|
||||
* Bump whenever the 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 OAKCOMMON_ABI_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief Neutral handle convention shared by all oakcommon wrappers.
|
||||
*
|
||||
* Every wrapper type is a by-value struct with the same four fields:
|
||||
*
|
||||
* typedef struct OakXxx {
|
||||
* void *ctx; // opaque, points to the impl
|
||||
* void (*addref)(void *ctx); // atomic +1, owner-DLL code
|
||||
* void (*release)(void *ctx); // atomic -1, destroys at 0
|
||||
* uint32_t abi_version; // OAKCOMMON_ABI_VERSION
|
||||
* } OakXxx;
|
||||
*
|
||||
* Rules:
|
||||
* - oakcommon_<name>_init*() returns a handle whose underlying object
|
||||
* has reference count 1.
|
||||
* - Copying the struct copies the pointer, not the count: call
|
||||
* handle.addref(handle.ctx) for every additional long-lived copy and
|
||||
* handle.release(handle.ctx) (or the oakcommon_<name>_free()
|
||||
* convenience wrapper) when done with each copy.
|
||||
* - release() decrements the atomic count and destroys the underlying
|
||||
* object when it reaches zero; the destructor runs in the DLL that
|
||||
* created the object, so cross-DLL handing is safe.
|
||||
* - The struct itself carries no ownership: it is never heap-allocated
|
||||
* by the API, so it needs no destruction of its own.
|
||||
* - Functions that only read a handle take it BY VALUE (OakXxx self);
|
||||
* an empty handle (ctx == NULL) is reported as OAKCOMMON_E_INVALID.
|
||||
* oakcommon_<name>_free() deliberately stays a pointer API
|
||||
* (OakXxx *h, like av_frame_unref()/av_buffer_unref()) so it can
|
||||
* null out the caller's ctx after the final release; NULL and
|
||||
* ctx == NULL are no-ops. Out parameters that produce a handle
|
||||
* (e.g. option/positional-argument registration) also stay pointers.
|
||||
*/
|
||||
|
||||
#endif //OAK_EDITOR_HANDLE_H
|
||||
@@ -0,0 +1,44 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_LOOPMODE_H
|
||||
#define OAK_EDITOR_LOOPMODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Playback loop mode, mirroring olive::LoopMode.
|
||||
*
|
||||
* The numeric values must stay in sync with src/common/src/loopmode.h.
|
||||
* Pure enum: no functions are needed.
|
||||
*/
|
||||
enum OakLoopMode {
|
||||
OAKCOMMON_LOOP_MODE_OFF = 0, /**< Looping disabled. */
|
||||
OAKCOMMON_LOOP_MODE_LOOP = 1, /**< Loop playback. */
|
||||
OAKCOMMON_LOOP_MODE_CLAMP = 2 /**< Clamp at the end. */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_LOOPMODE_H
|
||||
@@ -0,0 +1,117 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_MISCUTILS_H
|
||||
#define OAK_EDITOR_MISCUTILS_H
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Minimum decibel value used by the editor (-200.0 dB).
|
||||
*
|
||||
* In basically all circumstances, this calculates to 0.0 linear.
|
||||
*/
|
||||
#define OAKCOMMON_DECIBEL_MINIMUM (-200.0)
|
||||
|
||||
/**
|
||||
* @brief Convert a linear amplitude to decibels.
|
||||
*
|
||||
* A linear value of 0.0 (or anything yielding an infinite result) returns
|
||||
* OAKCOMMON_DECIBEL_MINIMUM.
|
||||
*
|
||||
* @param linear Linear amplitude.
|
||||
* @param out_db Receives the decibel value. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_db is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_from_linear(double linear, double *out_db);
|
||||
|
||||
/**
|
||||
* @brief Convert decibels to a linear amplitude.
|
||||
*
|
||||
* Results below 1e-6 are clamped to 0.0.
|
||||
*
|
||||
* @param db Decibel value.
|
||||
* @param out_linear Receives the linear amplitude. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_linear is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_to_linear(double db, double *out_linear);
|
||||
|
||||
/**
|
||||
* @brief Convert a logarithmic slider position (0..1) to decibels.
|
||||
*
|
||||
* @param logarithmic Logarithmic position.
|
||||
* @param out_db Receives the decibel value. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_db is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_from_logarithmic(double logarithmic, double *out_db);
|
||||
|
||||
/**
|
||||
* @brief Convert decibels to a logarithmic slider position (0..1).
|
||||
*
|
||||
* @param db Decibel value.
|
||||
* @param out_logarithmic Receives the logarithmic position. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_logarithmic
|
||||
* is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_to_logarithmic(double db, double *out_logarithmic);
|
||||
|
||||
/**
|
||||
* @brief Convert a linear amplitude directly to a logarithmic position.
|
||||
*
|
||||
* @param linear Linear amplitude.
|
||||
* @param out_logarithmic Receives the logarithmic position. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_logarithmic
|
||||
* is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_linear_to_logarithmic(double linear,
|
||||
double *out_logarithmic);
|
||||
|
||||
/**
|
||||
* @brief Convert a logarithmic position directly to a linear amplitude.
|
||||
*
|
||||
* @param logarithmic Logarithmic position.
|
||||
* @param out_linear Receives the linear amplitude. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_linear is NULL.
|
||||
*/
|
||||
int oakcommon_decibel_logarithmic_to_linear(double logarithmic,
|
||||
double *out_linear);
|
||||
|
||||
/**
|
||||
* @brief Linearly interpolate between a and b using t.
|
||||
*
|
||||
* t should be between 0.0 and 1.0: 0.0 returns a, 1.0 returns b.
|
||||
*
|
||||
* @param a Start value.
|
||||
* @param b End value.
|
||||
* @param t Interpolation factor.
|
||||
* @param out_value Receives the interpolated value. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_value is NULL.
|
||||
*/
|
||||
int oakcommon_lerp(double a, double b, double t, double *out_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_MISCUTILS_H
|
||||
@@ -0,0 +1,105 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_OCIOUTILS_H
|
||||
#define OAK_EDITOR_OCIOUTILS_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Native pixel format codes, mirroring olive::core::PixelFormat
|
||||
*
|
||||
* The numeric values must stay in sync with
|
||||
* olive/core/render/pixelformat.h (Format enum).
|
||||
*/
|
||||
enum OakPixelFormat {
|
||||
OAKCOMMON_PIXEL_FORMAT_INVALID = -1, /**< Invalid/unknown format. */
|
||||
OAKCOMMON_PIXEL_FORMAT_U8 = 0, /**< 8-bit unsigned integer. */
|
||||
OAKCOMMON_PIXEL_FORMAT_U10 = 1, /**< 10-bit unsigned integer. */
|
||||
OAKCOMMON_PIXEL_FORMAT_U16 = 2, /**< 16-bit unsigned integer. */
|
||||
OAKCOMMON_PIXEL_FORMAT_F16 = 3, /**< 16-bit float (half). */
|
||||
OAKCOMMON_PIXEL_FORMAT_F32 = 4, /**< 32-bit float. */
|
||||
OAKCOMMON_PIXEL_FORMAT_COUNT = 5 /**< Sentinel, not a valid format. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief OpenColorIO bit depth codes, matching OCIO::BitDepth
|
||||
*
|
||||
* Returned through the out parameter of
|
||||
* oakcommon_ocioutils_get_ocio_bit_depth_from_pixel_format() as a plain
|
||||
* int so that callers never see OCIO types. Values match the OCIO
|
||||
* BitDepth enum: 0 = unknown, 1 = uint8, 2 = uint10, 3 = uint12,
|
||||
* 4 = uint14, 5 = uint16, 6 = uint32, 7 = f16, 8 = f32 (OCIO v2).
|
||||
*/
|
||||
/**
|
||||
* @brief Neutral by-value handle for the OCIO utils family
|
||||
*
|
||||
* The object is stateless; the handle exists only to satisfy the C API
|
||||
* lifetime contract. Ownership/count semantics follow common/handle.h:
|
||||
* init returns a handle whose (empty) object has reference count 1 and
|
||||
* release destroys it at zero. abi_version is always
|
||||
* OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakOCIOUtils {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakOCIOUtils;
|
||||
|
||||
/**
|
||||
* @brief Creates an OCIOUtils handle
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakOCIOUtils oakcommon_ocioutils_init(void);
|
||||
|
||||
/**
|
||||
* @brief Releases one reference to an OCIOUtils handle
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx); no-op when
|
||||
* self is NULL or self->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_ocioutils_free(OakOCIOUtils *self);
|
||||
|
||||
/**
|
||||
* @brief Maps a native pixel format to an OCIO bit depth
|
||||
*
|
||||
* @param self handle from oakcommon_ocioutils_init()
|
||||
* @param pixel_format one of the OakPixelFormat values
|
||||
* @param out_bit_depth receives the OCIO bit depth as an int (see the
|
||||
* OakOCIOUtils typedef documentation); set to 0
|
||||
* (BIT_DEPTH_UNKNOWN) for invalid formats
|
||||
* @return OAKCOMMON_OK, or OAKCOMMON_E_INVALID if self.ctx or
|
||||
* out_bit_depth is NULL or pixel_format is not a known code
|
||||
*/
|
||||
int oakcommon_ocioutils_get_ocio_bit_depth_from_pixel_format(
|
||||
OakOCIOUtils self, int pixel_format, int *out_bit_depth);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_OCIOUTILS_H
|
||||
@@ -0,0 +1,125 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_OIIOUTILS_H
|
||||
#define OAK_EDITOR_OIIOUTILS_H
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
/* Reuses the OakPixelFormat enum (mirroring
|
||||
* olive::core::PixelFormat) rather than redefining it here. */
|
||||
#include "common/ocioutils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief OIIO base type codes, matching OIIO::TypeDesc::BASETYPE
|
||||
*
|
||||
* Passed through the C API as plain ints so callers never see OIIO
|
||||
* types. Values match the OIIO TypeDesc::BASETYPE enum: 0 = UNKNOWN,
|
||||
* 1 = NONE, 2 = UINT8, 3 = INT8, 4 = UINT16, 5 = INT16, 6 = UINT32,
|
||||
* 7 = INT32, 8 = UINT64, 9 = INT64, 10 = HALF, 11 = FLOAT, 12 = DOUBLE,
|
||||
* 13 = STRING, 14 = PTR. OIIO >= 2.5 adds 15 = USTRINGHASH and shifts
|
||||
* LASTBASE, so the exact LASTBASE value is version-dependent.
|
||||
*/
|
||||
/**
|
||||
* @brief Neutral by-value handle for the OIIO utils family
|
||||
*
|
||||
* The object is stateless; the handle exists only to satisfy the C API
|
||||
* lifetime contract. Ownership/count semantics follow common/handle.h:
|
||||
* init returns a handle whose (empty) object has reference count 1 and
|
||||
* release destroys it at zero. abi_version is always
|
||||
* OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakOIIOUtils {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakOIIOUtils;
|
||||
|
||||
/**
|
||||
* @brief Creates an OIIOUtils handle
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakOIIOUtils oakcommon_oiioutils_init(void);
|
||||
|
||||
/**
|
||||
* @brief Releases one reference to an OIIOUtils handle
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx); no-op when
|
||||
* self is NULL or self->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_oiioutils_free(OakOIIOUtils *self);
|
||||
|
||||
/**
|
||||
* @brief Maps a native pixel format to an OIIO base type
|
||||
*
|
||||
* @param self handle from oakcommon_oiioutils_init()
|
||||
* @param pixel_format one of the OakPixelFormat values
|
||||
* @param out_base_type receives the OIIO base type as an int (see the
|
||||
* OakOIIOUtils typedef documentation); set to 0
|
||||
* (TypeDesc::UNKNOWN) for invalid or unmappable formats
|
||||
* @return OAKCOMMON_OK, or OAKCOMMON_E_INVALID if self.ctx or
|
||||
* out_base_type is NULL or pixel_format is not a known code
|
||||
*/
|
||||
int oakcommon_oiioutils_get_oiio_base_type_from_format(
|
||||
OakOIIOUtils self, int pixel_format, int *out_base_type);
|
||||
|
||||
/**
|
||||
* @brief Maps an OIIO base type to a native pixel format
|
||||
*
|
||||
* @param self handle from oakcommon_oiioutils_init()
|
||||
* @param base_type an OIIO TypeDesc::BASETYPE value as an int
|
||||
* @param out_pixel_format receives one of the OakPixelFormat
|
||||
* values; set to OAKCOMMON_PIXEL_FORMAT_INVALID for unknown or
|
||||
* unmappable base types
|
||||
* @return OAKCOMMON_OK, or OAKCOMMON_E_INVALID if self.ctx or
|
||||
* out_pixel_format is NULL or base_type is negative
|
||||
*/
|
||||
int oakcommon_oiioutils_get_format_from_oiio_basetype(
|
||||
OakOIIOUtils self, int base_type, int *out_pixel_format);
|
||||
|
||||
/**
|
||||
* @brief Converts a PixelAspectRatio attribute value to a rational
|
||||
*
|
||||
* Flattened form of the former ImageSpec-based helper: the caller reads
|
||||
* the "PixelAspectRatio" float attribute from the OIIO::ImageSpec
|
||||
* (defaulting to 1.0 when absent) and passes it here.
|
||||
*
|
||||
* @param self handle from oakcommon_oiioutils_init()
|
||||
* @param pixel_aspect_ratio the PixelAspectRatio attribute value
|
||||
* @param out_numerator receives the rational numerator
|
||||
* @param out_denominator receives the rational denominator
|
||||
* @return OAKCOMMON_OK, or OAKCOMMON_E_INVALID if self.ctx,
|
||||
* out_numerator or out_denominator is NULL
|
||||
*/
|
||||
int oakcommon_oiioutils_get_pixel_aspect_ratio(
|
||||
OakOIIOUtils self, double pixel_aspect_ratio, int *out_numerator,
|
||||
int *out_denominator);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_OIIOUTILS_H
|
||||
@@ -0,0 +1,58 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_POWER_H
|
||||
#define OAK_EDITOR_POWER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Round `value` up to the next power of two
|
||||
*
|
||||
* Stateless pure function, no handle required. Writes the result to `out`.
|
||||
*
|
||||
* @param value Input value.
|
||||
* @param out Receives the rounded value. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if `out` is NULL.
|
||||
*/
|
||||
int oakcommon_power_ceil_to_power_of_2(uint32_t value, uint32_t *out);
|
||||
|
||||
/**
|
||||
* @brief Round `value` down to the nearest power of two
|
||||
*
|
||||
* Stateless pure function, no handle required. Writes the result to `out`.
|
||||
*
|
||||
* @param value Input value.
|
||||
* @param out Receives the rounded value. Must not be NULL.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if `out` is NULL.
|
||||
*/
|
||||
int oakcommon_power_floor_to_power_of_2(uint32_t value, uint32_t *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_POWER_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_COMMON_QTUTILS_H
|
||||
#define OAK_COMMON_QTUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Convert a pointer to an integer value
|
||||
*
|
||||
* @param ptr Pointer to convert (may be NULL, yielding 0).
|
||||
* @param out_value Receives the integer representation of ptr.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_value is NULL.
|
||||
*/
|
||||
int oakcommon_qtutils_ptr_to_value(void *ptr, uint64_t *out_value);
|
||||
|
||||
/**
|
||||
* @brief Convert an integer produced by oakcommon_qtutils_ptr_to_value() back to a pointer
|
||||
*
|
||||
* @param value Integer representation of a pointer.
|
||||
* @param out_ptr Receives the decoded pointer.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID if out_ptr is NULL.
|
||||
*/
|
||||
int oakcommon_qtutils_value_to_ptr(uint64_t value, void **out_ptr);
|
||||
|
||||
/**
|
||||
* @brief Get the creation (birth) time of a file as seconds since the Unix epoch
|
||||
*
|
||||
* Falls back to the last metadata change time when the filesystem does not
|
||||
* record birth times.
|
||||
*
|
||||
* @param path NUL-terminated filesystem path.
|
||||
* @param out_secs Receives the creation time in seconds since the epoch.
|
||||
* @return OAKCOMMON_OK on success, OAKCOMMON_E_INVALID for NULL arguments,
|
||||
* OAKCOMMON_E_NOT_FOUND if the file does not exist or cannot be stat'ed.
|
||||
*/
|
||||
int oakcommon_qtutils_get_creation_date(const char *path, int64_t *out_secs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_COMMON_QTUTILS_H
|
||||
@@ -0,0 +1,176 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_SUBTITLEPARAMS_H
|
||||
#define OAK_EDITOR_SUBTITLEPARAMS_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace olive
|
||||
{
|
||||
class SubtitleParams;
|
||||
}
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a subtitle parameter set
|
||||
* (olive::SubtitleParams).
|
||||
*
|
||||
* Ownership/count semantics follow the convention in common/handle.h:
|
||||
* init functions return a handle whose object has reference count 1,
|
||||
* addref(ctx)/release(ctx) adjust it atomically, and release destroys
|
||||
* the object at zero. abi_version is always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakSubtitleParams {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakSubtitleParams;
|
||||
|
||||
/**
|
||||
* @brief Create an empty subtitle parameter set.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakSubtitleParams oakcommon_subtitleparams_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* @brief Copy a native olive::SubtitleParams into a new handle.
|
||||
*
|
||||
* The source object is deep-copied; the handle does not keep any
|
||||
* reference to @p src, which may be destroyed immediately afterwards.
|
||||
* Only visible to C++ consumers.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL if src is NULL or
|
||||
* on allocation failure.
|
||||
*/
|
||||
OakSubtitleParams oakcommon_subtitleparams_init_from_native(
|
||||
const olive::SubtitleParams *src);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a subtitle parameter set.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when params is NULL or params->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_subtitleparams_free(OakSubtitleParams *params);
|
||||
|
||||
int oakcommon_subtitleparams_get_stream_index(
|
||||
OakSubtitleParams params, int *index);
|
||||
int oakcommon_subtitleparams_set_stream_index(
|
||||
OakSubtitleParams params, int index);
|
||||
int oakcommon_subtitleparams_get_enabled(OakSubtitleParams params,
|
||||
int *enabled);
|
||||
int oakcommon_subtitleparams_set_enabled(OakSubtitleParams params,
|
||||
int enabled);
|
||||
|
||||
/**
|
||||
* @brief Query whether the set contains at least one subtitle.
|
||||
*/
|
||||
int oakcommon_subtitleparams_is_valid(OakSubtitleParams params,
|
||||
int *is_valid);
|
||||
|
||||
/**
|
||||
* @brief Number of subtitle entries.
|
||||
*/
|
||||
int oakcommon_subtitleparams_count(OakSubtitleParams params,
|
||||
int *count);
|
||||
|
||||
/**
|
||||
* @brief Out time of the last subtitle (0/1 when empty).
|
||||
*/
|
||||
int oakcommon_subtitleparams_duration(OakSubtitleParams params,
|
||||
int *numerator, int *denominator);
|
||||
|
||||
/**
|
||||
* @brief Append a subtitle entry.
|
||||
*
|
||||
* @param text Subtitle text. Must not be NULL.
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_add_subtitle(OakSubtitleParams params,
|
||||
int in_num, int in_den, int out_num,
|
||||
int out_den, const char *text);
|
||||
|
||||
/**
|
||||
* @brief Remove all subtitle entries.
|
||||
*/
|
||||
int oakcommon_subtitleparams_clear(OakSubtitleParams params);
|
||||
|
||||
/**
|
||||
* @brief Get the time range of the subtitle at @p index.
|
||||
*
|
||||
* @return OAKCOMMON_OK, OAKCOMMON_E_NOT_FOUND if @p index is out of range,
|
||||
* or another negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_get_subtitle(OakSubtitleParams params,
|
||||
int index, int *in_num, int *in_den,
|
||||
int *out_num, int *out_den);
|
||||
|
||||
/**
|
||||
* @brief Get the text of the subtitle at @p index (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), OAKCOMMON_E_NOT_FOUND if @p index is out of
|
||||
* range, or another negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_get_subtitle_text(OakSubtitleParams params,
|
||||
int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Generate a default ASS header (static, no handle required).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_generate_ass_header(char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Load subtitles from an XML fragment.
|
||||
*
|
||||
* @param xml NUL-terminated XML text. Must not be NULL.
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_load_xml(OakSubtitleParams params,
|
||||
const char *xml);
|
||||
|
||||
/**
|
||||
* @brief Save subtitles to an XML fragment (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_subtitleparams_save_xml(OakSubtitleParams params,
|
||||
char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_SUBTITLEPARAMS_H
|
||||
@@ -0,0 +1,367 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_VIDEOPARAMS_H
|
||||
#define OAK_EDITOR_VIDEOPARAMS_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
#include "common/ocioutils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace olive
|
||||
{
|
||||
class VideoParams;
|
||||
}
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a video parameter set
|
||||
* (olive::VideoParams).
|
||||
*
|
||||
* Ownership/count semantics follow the convention in common/handle.h:
|
||||
* init functions return a handle whose object has reference count 1,
|
||||
* addref(ctx)/release(ctx) adjust it atomically, and release destroys
|
||||
* the object at zero. abi_version is always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakVideoParams {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakVideoParams;
|
||||
|
||||
/**
|
||||
* @brief Interlacing modes, mirroring olive::VideoParams::Interlacing.
|
||||
*/
|
||||
enum OakVideoInterlacing {
|
||||
OAKCOMMON_VIDEO_INTERLACE_NONE = 0,
|
||||
OAKCOMMON_VIDEO_INTERLACED_TOP_FIRST = 1,
|
||||
OAKCOMMON_VIDEO_INTERLACED_BOTTOM_FIRST = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Video stream types, mirroring olive::VideoParams::Type.
|
||||
*/
|
||||
enum OakVideoType {
|
||||
OAKCOMMON_VIDEO_TYPE_VIDEO = 0,
|
||||
OAKCOMMON_VIDEO_TYPE_STILL = 1,
|
||||
OAKCOMMON_VIDEO_TYPE_IMAGE_SEQUENCE = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Color range codes, mirroring olive::VideoParams::ColorRange.
|
||||
*/
|
||||
enum OakVideoColorRange {
|
||||
OAKCOMMON_COLOR_RANGE_LIMITED = 0, /**< 16-235 */
|
||||
OAKCOMMON_COLOR_RANGE_FULL = 1 /**< 0-255 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a default (invalid) video parameter set.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakVideoParams oakcommon_videoparams_init(void);
|
||||
|
||||
/**
|
||||
* @brief Create a video parameter set without a time base.
|
||||
*
|
||||
* @param pixel_format One of the OakPixelFormat values.
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakVideoParams oakcommon_videoparams_init_basic(
|
||||
int width, int height, int pixel_format, int nb_channels,
|
||||
int pixel_aspect_num, int pixel_aspect_den, int interlacing, int divider);
|
||||
|
||||
/**
|
||||
* @brief Create a video parameter set with a time base.
|
||||
*
|
||||
* The frame rate is derived as the flipped time base.
|
||||
*
|
||||
* @param pixel_format One of the OakPixelFormat values.
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakVideoParams oakcommon_videoparams_init_with_time_base(
|
||||
int width, int height, int time_base_num, int time_base_den,
|
||||
int pixel_format, int nb_channels, int pixel_aspect_num,
|
||||
int pixel_aspect_den, int interlacing, int divider);
|
||||
|
||||
#ifdef __cplusplus
|
||||
/**
|
||||
* @brief Copy a native olive::VideoParams into a new handle.
|
||||
*
|
||||
* The source object is deep-copied; the handle does not keep any
|
||||
* reference to @p src, which may be destroyed immediately afterwards.
|
||||
* Only visible to C++ consumers.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL if src is NULL or
|
||||
* on allocation failure.
|
||||
*/
|
||||
OakVideoParams oakcommon_videoparams_init_from_native(
|
||||
const olive::VideoParams *src);
|
||||
|
||||
/**
|
||||
* @brief Borrow the native object behind a handle.
|
||||
*
|
||||
* The returned pointer is borrowed: it stays valid while the caller
|
||||
* holds a reference to the handle (i.e. until the matching release).
|
||||
* Only visible to C++ consumers.
|
||||
*
|
||||
* @return Borrowed pointer, or NULL if params is NULL or params->ctx is
|
||||
* NULL.
|
||||
*/
|
||||
const olive::VideoParams *oakcommon_videoparams_get_native(
|
||||
OakVideoParams params);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a video parameter set.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when params is NULL or params->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_videoparams_free(OakVideoParams *params);
|
||||
|
||||
int oakcommon_videoparams_get_width(OakVideoParams params, int *width);
|
||||
int oakcommon_videoparams_set_width(OakVideoParams params, int width);
|
||||
int oakcommon_videoparams_get_height(OakVideoParams params, int *height);
|
||||
int oakcommon_videoparams_set_height(OakVideoParams params, int height);
|
||||
int oakcommon_videoparams_get_depth(OakVideoParams params, int *depth);
|
||||
int oakcommon_videoparams_set_depth(OakVideoParams params, int depth);
|
||||
int oakcommon_videoparams_get_is_3d(OakVideoParams params, int *is_3d);
|
||||
|
||||
/**
|
||||
* @brief Rational getters return the value as a numerator/denominator pair.
|
||||
*/
|
||||
int oakcommon_videoparams_get_time_base(OakVideoParams params,
|
||||
int *numerator, int *denominator);
|
||||
int oakcommon_videoparams_set_time_base(OakVideoParams params,
|
||||
int numerator, int denominator);
|
||||
int oakcommon_videoparams_get_frame_rate(OakVideoParams params,
|
||||
int *numerator, int *denominator);
|
||||
int oakcommon_videoparams_set_frame_rate(OakVideoParams params,
|
||||
int numerator, int denominator);
|
||||
int oakcommon_videoparams_frame_rate_as_time_base(OakVideoParams params,
|
||||
int *numerator,
|
||||
int *denominator);
|
||||
int oakcommon_videoparams_get_pixel_aspect_ratio(OakVideoParams params,
|
||||
int *numerator,
|
||||
int *denominator);
|
||||
int oakcommon_videoparams_set_pixel_aspect_ratio(OakVideoParams params,
|
||||
int numerator, int denominator);
|
||||
|
||||
/**
|
||||
* @brief Format getters/setters use the OakPixelFormat codes.
|
||||
*/
|
||||
int oakcommon_videoparams_get_format(OakVideoParams params, int *format);
|
||||
int oakcommon_videoparams_set_format(OakVideoParams params, int format);
|
||||
int oakcommon_videoparams_get_channel_count(OakVideoParams params,
|
||||
int *count);
|
||||
int oakcommon_videoparams_set_channel_count(OakVideoParams params,
|
||||
int count);
|
||||
int oakcommon_videoparams_get_interlacing(OakVideoParams params,
|
||||
int *interlacing);
|
||||
int oakcommon_videoparams_set_interlacing(OakVideoParams params,
|
||||
int interlacing);
|
||||
int oakcommon_videoparams_get_divider(OakVideoParams params,
|
||||
int *divider);
|
||||
int oakcommon_videoparams_set_divider(OakVideoParams params,
|
||||
int divider);
|
||||
int oakcommon_videoparams_get_enabled(OakVideoParams params,
|
||||
int *enabled);
|
||||
int oakcommon_videoparams_set_enabled(OakVideoParams params,
|
||||
int enabled);
|
||||
int oakcommon_videoparams_get_x(OakVideoParams params, float *x);
|
||||
int oakcommon_videoparams_set_x(OakVideoParams params, float x);
|
||||
int oakcommon_videoparams_get_y(OakVideoParams params, float *y);
|
||||
int oakcommon_videoparams_set_y(OakVideoParams params, float y);
|
||||
int oakcommon_videoparams_get_stream_index(OakVideoParams params,
|
||||
int *index);
|
||||
int oakcommon_videoparams_set_stream_index(OakVideoParams params,
|
||||
int index);
|
||||
int oakcommon_videoparams_get_video_type(OakVideoParams params,
|
||||
int *type);
|
||||
int oakcommon_videoparams_set_video_type(OakVideoParams params,
|
||||
int type);
|
||||
int oakcommon_videoparams_get_start_time(OakVideoParams params,
|
||||
int64_t *start_time);
|
||||
int oakcommon_videoparams_set_start_time(OakVideoParams params,
|
||||
int64_t start_time);
|
||||
int oakcommon_videoparams_get_duration(OakVideoParams params,
|
||||
int64_t *duration);
|
||||
int oakcommon_videoparams_set_duration(OakVideoParams params,
|
||||
int64_t duration);
|
||||
int oakcommon_videoparams_get_premultiplied_alpha(OakVideoParams params,
|
||||
int *premultiplied);
|
||||
int oakcommon_videoparams_set_premultiplied_alpha(OakVideoParams params,
|
||||
int premultiplied);
|
||||
int oakcommon_videoparams_get_color_range(OakVideoParams params,
|
||||
int *color_range);
|
||||
int oakcommon_videoparams_set_color_range(OakVideoParams params,
|
||||
int color_range);
|
||||
int oakcommon_videoparams_get_color_primaries(OakVideoParams params,
|
||||
int *primaries);
|
||||
int oakcommon_videoparams_set_color_primaries(OakVideoParams params,
|
||||
int primaries);
|
||||
int oakcommon_videoparams_get_color_transfer(OakVideoParams params,
|
||||
int *transfer);
|
||||
int oakcommon_videoparams_set_color_transfer(OakVideoParams params,
|
||||
int transfer);
|
||||
|
||||
/**
|
||||
* @brief Get the colorspace name (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_get_colorspace(OakVideoParams params,
|
||||
char *buf, int buf_size);
|
||||
int oakcommon_videoparams_set_colorspace(OakVideoParams params,
|
||||
const char *colorspace);
|
||||
|
||||
/**
|
||||
* @brief Width multiplied by the pixel aspect ratio.
|
||||
*/
|
||||
int oakcommon_videoparams_get_square_pixel_width(OakVideoParams params,
|
||||
int *width);
|
||||
int oakcommon_videoparams_get_effective_width(OakVideoParams params,
|
||||
int *width);
|
||||
int oakcommon_videoparams_get_effective_height(OakVideoParams params,
|
||||
int *height);
|
||||
int oakcommon_videoparams_get_effective_depth(OakVideoParams params,
|
||||
int *depth);
|
||||
int oakcommon_videoparams_get_is_valid(OakVideoParams params,
|
||||
int *is_valid);
|
||||
int oakcommon_videoparams_get_bytes_per_channel(OakVideoParams params,
|
||||
int *bytes);
|
||||
int oakcommon_videoparams_get_bytes_per_pixel(OakVideoParams params,
|
||||
int *bytes);
|
||||
int oakcommon_videoparams_get_buffer_size(OakVideoParams params,
|
||||
int *size);
|
||||
|
||||
/**
|
||||
* @brief Convert a time (in seconds, as a rational) to time base units.
|
||||
*
|
||||
* Returns INT64_MIN (AV_NOPTS_VALUE) in @p timestamp when no time base is
|
||||
* set.
|
||||
*/
|
||||
int oakcommon_videoparams_get_time_in_timebase_units(
|
||||
OakVideoParams params, int time_num, int time_den,
|
||||
int64_t *timestamp);
|
||||
|
||||
/**
|
||||
* @brief Compare two parameter sets for equality.
|
||||
*/
|
||||
int oakcommon_videoparams_equals(OakVideoParams params,
|
||||
OakVideoParams other, int *equal);
|
||||
|
||||
/**
|
||||
* @brief Load parameters from an XML fragment.
|
||||
*
|
||||
* @param xml NUL-terminated XML text. Must not be NULL.
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_load_xml(OakVideoParams params,
|
||||
const char *xml);
|
||||
|
||||
/**
|
||||
* @brief Save parameters to an XML fragment (two-stage string getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_save_xml(OakVideoParams params, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/* Static helpers (no handle required). */
|
||||
|
||||
int oakcommon_videoparams_get_bytes_per_channel_for_format(int pixel_format);
|
||||
int oakcommon_videoparams_get_bytes_per_pixel_for_format(int pixel_format,
|
||||
int channels);
|
||||
int oakcommon_videoparams_calculate_buffer_size(int width, int height,
|
||||
int pixel_format,
|
||||
int channels);
|
||||
int oakcommon_videoparams_format_is_float(int pixel_format);
|
||||
int oakcommon_videoparams_generate_auto_divider(int64_t width, int64_t height);
|
||||
int oakcommon_videoparams_get_scaled_dimension(int dimension, int divider);
|
||||
int oakcommon_videoparams_get_divider_for_target_resolution(int src_width,
|
||||
int src_height,
|
||||
int dst_width,
|
||||
int dst_height);
|
||||
|
||||
/**
|
||||
* @brief Human-readable name for a divider ("Full", "1/2", ...).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_get_name_for_divider(int divider, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Human-readable name for a pixel format.
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_get_format_name(int pixel_format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Human-readable frame rate string ("23.976 FPS").
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_videoparams_frame_rate_to_string(int numerator, int denominator,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get bytes per channel.
|
||||
*
|
||||
* @return Bytes per channel.
|
||||
*/
|
||||
int oakcommon_videoparams_static_get_bytes_per_channel(OakPixelFormat format);
|
||||
|
||||
/**
|
||||
* @brief Get bytes per pixel.
|
||||
*
|
||||
* @return Bytes per pixel.
|
||||
*/
|
||||
int oakcommon_videoparams_static_get_bytes_per_pixel(OakPixelFormat format,
|
||||
int channels);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_VIDEOPARAMS_H
|
||||
@@ -0,0 +1,215 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_XMLUTILS_H
|
||||
#define OAK_EDITOR_XMLUTILS_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/handle.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a streaming XML reader.
|
||||
*
|
||||
* Ownership/count semantics follow the convention in common/handle.h:
|
||||
* init returns a handle whose object has reference count 1,
|
||||
* addref(ctx)/release(ctx) adjust it atomically, and release destroys
|
||||
* the object at zero. abi_version is always OAKCOMMON_ABI_VERSION.
|
||||
*/
|
||||
typedef struct OakXmlReader {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakXmlReader;
|
||||
|
||||
/**
|
||||
* @brief Neutral by-value handle to a streaming XML writer.
|
||||
*
|
||||
* Same ownership/count semantics as OakXmlReader.
|
||||
*/
|
||||
typedef struct OakXmlWriter {
|
||||
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; /**< OAKCOMMON_ABI_VERSION. */
|
||||
} OakXmlWriter;
|
||||
|
||||
/**
|
||||
* @brief Create a streaming XML reader over a complete document.
|
||||
*
|
||||
* @param data NUL-terminated XML text. Must not be NULL.
|
||||
* @return Handle with reference count 1; ctx is NULL on failure
|
||||
* (NULL data, out of memory).
|
||||
*/
|
||||
OakXmlReader oakcommon_xml_reader_init(const char *data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
namespace olive { class XmlStreamReader; class XmlStreamWriter; }
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Borrowed access to the underlying C++ reader/writer (C++ only,
|
||||
* for adapter layers). Valid while the handle is held. NULL-safe.
|
||||
*/
|
||||
olive::XmlStreamReader *oakcommon_xml_reader_get_native(OakXmlReader reader);
|
||||
olive::XmlStreamWriter *oakcommon_xml_writer_get_native(OakXmlWriter writer);
|
||||
|
||||
/**
|
||||
* @brief Wrap an existing C++ reader/writer in a borrowed handle (C++
|
||||
* only, for adapter layers). The box never owns the object; the caller
|
||||
* must keep it alive and release the box with
|
||||
* oakcommon_xml_reader_free()/oakcommon_xml_writer_free(). Empty handle
|
||||
* for a NULL object or on allocation failure.
|
||||
*/
|
||||
OakXmlReader oakcommon_xml_reader_wrap_native(olive::XmlStreamReader *reader);
|
||||
OakXmlWriter oakcommon_xml_writer_wrap_native(olive::XmlStreamWriter *writer);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a reader.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when reader is NULL or reader->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_xml_reader_free(OakXmlReader *reader);
|
||||
|
||||
/**
|
||||
* @brief Advance until the next start element, an end element, or the end
|
||||
* of the document.
|
||||
*
|
||||
* @param reader Reader handle.
|
||||
* @param found Out: 1 if positioned on a start element, 0 otherwise.
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_read_next_start_element(OakXmlReader reader,
|
||||
int *found);
|
||||
|
||||
/**
|
||||
* @brief Name of the current element token.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_name(OakXmlReader reader, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Read the concatenated character data of the current element.
|
||||
*
|
||||
* Must be called on a start element; consumes up to the matching end
|
||||
* element.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_read_element_text(OakXmlReader reader,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Skip the current element and all of its children.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_skip_current_element(OakXmlReader reader);
|
||||
|
||||
/**
|
||||
* @brief Number of attributes on the current start element.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_attribute_count(OakXmlReader reader,
|
||||
int *count);
|
||||
|
||||
/**
|
||||
* @brief Name of the attribute at @p index on the current start element.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), OAKCOMMON_E_NOT_FOUND
|
||||
* if @p index is out of range, or another negative OAKCOMMON_E_* code.
|
||||
*/
|
||||
int oakcommon_xml_reader_attribute_name(OakXmlReader reader, int index,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Value of the attribute at @p index on the current start element.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), OAKCOMMON_E_NOT_FOUND
|
||||
* if @p index is out of range, or another negative OAKCOMMON_E_* code.
|
||||
*/
|
||||
int oakcommon_xml_reader_attribute_value(OakXmlReader reader,
|
||||
int index, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Whether the document failed to parse.
|
||||
*
|
||||
* @return OAKCOMMON_OK or a negative OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_reader_has_error(OakXmlReader reader,
|
||||
int *has_error);
|
||||
|
||||
/**
|
||||
* @brief Create a streaming XML writer.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OakXmlWriter oakcommon_xml_writer_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a writer.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero.
|
||||
* No-op when writer is NULL or writer->ctx is NULL.
|
||||
*/
|
||||
void oakcommon_xml_writer_free(OakXmlWriter *writer);
|
||||
|
||||
int oakcommon_xml_writer_write_start_element(OakXmlWriter writer,
|
||||
const char *name);
|
||||
int oakcommon_xml_writer_write_attribute(OakXmlWriter writer,
|
||||
const char *name, const char *value);
|
||||
int oakcommon_xml_writer_write_characters(OakXmlWriter writer,
|
||||
const char *text);
|
||||
int oakcommon_xml_writer_write_text_element(OakXmlWriter writer,
|
||||
const char *name,
|
||||
const char *text);
|
||||
int oakcommon_xml_writer_write_end_element(OakXmlWriter writer);
|
||||
int oakcommon_xml_writer_write_end_document(OakXmlWriter writer);
|
||||
|
||||
/**
|
||||
* @brief The document written so far.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKCOMMON_E_* error code.
|
||||
*/
|
||||
int oakcommon_xml_writer_output(OakXmlWriter writer, char *buf,
|
||||
int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_XMLUTILS_H
|
||||
@@ -0,0 +1,313 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_BLOCK_H
|
||||
#define OAK_EDITOR_NODE_BLOCK_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a timeline block (olive::Block).
|
||||
*
|
||||
* Covers the whole Block family: ClipBlock, GapBlock and the concrete
|
||||
* TransitionBlock subclasses. The object never leaves the library that
|
||||
* created it; every external reference is one of these handles.
|
||||
* Semantics are shared_ptr-like: the oaknode_block_*_create() factories
|
||||
* below return a handle with count 1, addref(ctx) takes another
|
||||
* reference, release(ctx) drops one and the library destroys the object
|
||||
* when the count reaches zero. Callers never touch C++ subclasses
|
||||
* directly.
|
||||
*
|
||||
* Placing a block on a track (the oaknode_track_*_block() primitives)
|
||||
* transfers ownership to the track; handles obtained from accessors
|
||||
* (neighbours, lookups) are borrowed and never destroy the underlying
|
||||
* object.
|
||||
*/
|
||||
typedef struct OakNodeBlock {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeBlock;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a track (olive::Track), see
|
||||
* node/track.h.
|
||||
*
|
||||
* Re-declared here so block.h is self-contained; the typedef is identical.
|
||||
*/
|
||||
typedef struct OakNodeTrack OakNodeTrack;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a node (olive::Node), see
|
||||
* node/node.h.
|
||||
*
|
||||
* Re-declared here so block.h is self-contained; the typedef is identical.
|
||||
*/
|
||||
typedef struct OakNodeNode OakNodeNode;
|
||||
|
||||
/**
|
||||
* @brief Concrete transition kinds for oaknode_block_transition_create().
|
||||
*/
|
||||
enum OakNodeTransitionKind {
|
||||
OAKNODE_TRANSITION_CROSS_DISSOLVE = 0, /**< CrossDissolveTransition. */
|
||||
OAKNODE_TRANSITION_DIP_TO_COLOR = 1 /**< DipToColorTransition. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Input ids of a TransitionBlock's block connections
|
||||
* (TransitionBlock::k_out_block_input / k_in_block_input). Pinned by
|
||||
* test; pass to oaknode_node_connect()/oaknode_node_disconnect().
|
||||
*/
|
||||
#define OAKNODE_TRANSITION_OUT_BLOCK_INPUT "out_block_in"
|
||||
#define OAKNODE_TRANSITION_IN_BLOCK_INPUT "in_block_in"
|
||||
|
||||
/**
|
||||
* @brief Create a ClipBlock.
|
||||
*
|
||||
* The caller owns the block until it is placed on a track that belongs to
|
||||
* a project; a block that was never placed must be released with
|
||||
* oaknode_block_free().
|
||||
*
|
||||
* @return Block handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakNodeBlock oaknode_block_clip_create(void);
|
||||
|
||||
/**
|
||||
* @brief Create a GapBlock. Ownership as oaknode_block_clip_create().
|
||||
*
|
||||
* @return Block handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakNodeBlock oaknode_block_gap_create(void);
|
||||
|
||||
/**
|
||||
* @brief Create a concrete TransitionBlock.
|
||||
*
|
||||
* @param kind One of the OakNodeTransitionKind values.
|
||||
* @return Block handle with reference count 1; ctx is NULL on invalid
|
||||
* kind / allocation failure.
|
||||
*/
|
||||
OakNodeBlock oaknode_block_transition_create(int kind);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a block handle.
|
||||
*
|
||||
* Destroys the block when the reference count reaches zero. NULL handle
|
||||
* or NULL ctx is a no-op; clears `block->ctx` after releasing.
|
||||
*
|
||||
* The block must not be placed on a track or linked to other nodes; the
|
||||
* caller is responsible for detaching it first.
|
||||
*/
|
||||
void oaknode_block_free(OakNodeBlock *block);
|
||||
|
||||
enum OakNodeBlockKind {
|
||||
OAKNODE_BLOCK_OTHER = 0,
|
||||
OAKNODE_BLOCK_CLIP = 1,
|
||||
OAKNODE_BLOCK_GAP = 2,
|
||||
OAKNODE_BLOCK_TRANSITION = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concrete kind of a block (dynamic_cast query).
|
||||
*/
|
||||
int oaknode_block_get_kind(OakNodeBlock block, int *out_kind);
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a block handle to its node handle.
|
||||
*
|
||||
* Every Block is a Node; releasing the result never destroys the block.
|
||||
* Empty handle for an empty handle.
|
||||
*/
|
||||
OakNodeNode oaknode_block_as_node(OakNodeBlock block);
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a node handle to a block handle.
|
||||
*
|
||||
* Returns an empty handle if the node is not a Block (or is empty).
|
||||
*/
|
||||
OakNodeBlock oaknode_block_from_node(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Rational getters/setters use numerator/denominator out pairs.
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_block_get_in(OakNodeBlock block, int *numerator, int *denominator);
|
||||
int oaknode_block_set_in(OakNodeBlock block, int numerator, int denominator);
|
||||
int oaknode_block_get_out(OakNodeBlock block, int *numerator, int *denominator);
|
||||
int oaknode_block_set_out(OakNodeBlock block, int numerator, int denominator);
|
||||
int oaknode_block_get_length(OakNodeBlock block, int *numerator,
|
||||
int *denominator);
|
||||
|
||||
/**
|
||||
* @brief Set the block length, keeping the media out/in point anchored
|
||||
* (olive::Block::set_length_and_media_out / _media_in).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_block_set_length_and_media_out(OakNodeBlock block, int numerator,
|
||||
int denominator);
|
||||
int oaknode_block_set_length_and_media_in(OakNodeBlock block, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Enabled flag (olive::Block::is_enabled/set_enabled).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_block_get_enabled(OakNodeBlock block, int *enabled);
|
||||
int oaknode_block_set_enabled(OakNodeBlock block, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Adjacency accessors. `out` receives a borrowed handle (empty when
|
||||
* there is no neighbour / the block is not on a track).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_block_get_previous(OakNodeBlock block, OakNodeBlock *out);
|
||||
int oaknode_block_get_next(OakNodeBlock block, OakNodeBlock *out);
|
||||
int oaknode_block_get_track(OakNodeBlock block, OakNodeTrack *out);
|
||||
|
||||
/**
|
||||
* @brief Link two blocks (olive::Node::link/unlink/are_linked).
|
||||
*
|
||||
* Linked blocks move together in timeline edits.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_FAILED (already
|
||||
* linked / not linked).
|
||||
*/
|
||||
int oaknode_block_link(OakNodeBlock a, OakNodeBlock b);
|
||||
int oaknode_block_unlink(OakNodeBlock a, OakNodeBlock b);
|
||||
int oaknode_block_are_linked(OakNodeBlock a, OakNodeBlock b, int *linked);
|
||||
|
||||
/**
|
||||
* @brief Number of blocks linked to `block` (olive::Node::links()).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_block_get_link_count(OakNodeBlock block, int *count);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle to the linked block at `index`.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_block_get_link_at(OakNodeBlock block, int index,
|
||||
OakNodeBlock *out);
|
||||
|
||||
/* ---------------------------------------------------------------- Clip */
|
||||
|
||||
/**
|
||||
* @brief Media in/out accessors (olive::ClipBlock). Non-clip blocks return
|
||||
* OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_clip_get_media_in(OakNodeBlock clip, int *numerator,
|
||||
int *denominator);
|
||||
int oaknode_clip_set_media_in(OakNodeBlock clip, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Playback speed factor, 1.0 = normal (olive::ClipBlock speed input).
|
||||
*/
|
||||
int oaknode_clip_get_speed(OakNodeBlock clip, double *speed);
|
||||
int oaknode_clip_set_speed(OakNodeBlock clip, double speed);
|
||||
|
||||
/**
|
||||
* @brief Reverse playback flag.
|
||||
*/
|
||||
int oaknode_clip_get_reverse(OakNodeBlock clip, int *reverse);
|
||||
int oaknode_clip_set_reverse(OakNodeBlock clip, int reverse);
|
||||
|
||||
/**
|
||||
* @brief Maintain-audio-pitch flag.
|
||||
*/
|
||||
int oaknode_clip_get_maintain_audio_pitch(OakNodeBlock clip, int *maintain);
|
||||
int oaknode_clip_set_maintain_audio_pitch(OakNodeBlock clip, int maintain);
|
||||
|
||||
/**
|
||||
* @brief Loop mode, one of the OakLoopMode values
|
||||
* (olive::ClipBlock::loop_mode/set_loop_mode).
|
||||
*/
|
||||
int oaknode_clip_get_loop_mode(OakNodeBlock clip, int *loop_mode);
|
||||
int oaknode_clip_set_loop_mode(OakNodeBlock clip, int loop_mode);
|
||||
|
||||
/**
|
||||
* @brief Type of the track the clip sits on (OakNodeTrackType values,
|
||||
* OAKNODE_TRACK_TYPE_NONE when trackless).
|
||||
*/
|
||||
int oaknode_clip_get_track_type(OakNodeBlock clip, int *type);
|
||||
|
||||
/* ----------------------------------------------------------- Transition */
|
||||
|
||||
/**
|
||||
* @brief Transition offsets (olive::TransitionBlock). Non-transition blocks
|
||||
* return OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_transition_get_in_offset(OakNodeBlock transition, int *numerator,
|
||||
int *denominator);
|
||||
int oaknode_transition_get_out_offset(OakNodeBlock transition, int *numerator,
|
||||
int *denominator);
|
||||
int oaknode_transition_get_offset_center(OakNodeBlock transition,
|
||||
int *numerator, int *denominator);
|
||||
int oaknode_transition_set_offset_center(OakNodeBlock transition,
|
||||
int numerator, int denominator);
|
||||
int oaknode_transition_set_offsets_and_length(OakNodeBlock transition,
|
||||
int in_num, int in_den,
|
||||
int out_num, int out_den);
|
||||
|
||||
/**
|
||||
* @brief Whether both sides of the transition are connected to clips.
|
||||
*/
|
||||
int oaknode_transition_is_dual(OakNodeBlock transition, int *dual);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handles to the connected out/in side blocks (empty when
|
||||
* unconnected).
|
||||
*/
|
||||
int oaknode_transition_get_connected_out_block(OakNodeBlock transition,
|
||||
OakNodeBlock *out);
|
||||
int oaknode_transition_get_connected_in_block(OakNodeBlock transition,
|
||||
OakNodeBlock *out);
|
||||
|
||||
/**
|
||||
* @brief Forward cache passthroughs from another clip
|
||||
* (ClipBlock::add_cache_passthrough_from()). Used after splitting a
|
||||
* clip so the new part shares the render caches.
|
||||
*/
|
||||
int oaknode_clip_add_cache_passthrough_from(OakNodeBlock clip,
|
||||
OakNodeBlock other);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_BLOCK_H
|
||||
@@ -0,0 +1,221 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_COLORMANAGER_H
|
||||
#define OAK_EDITOR_NODE_COLORMANAGER_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/colortransform.h"
|
||||
#include "node/error.h"
|
||||
#include "node/project.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a color manager
|
||||
* (olive::ColorManager).
|
||||
*
|
||||
* Semantics are shared_ptr-like: oaknode_colormanager_init() returns a
|
||||
* handle whose object has reference count 1, addref(ctx) takes another
|
||||
* reference, and release(ctx) (or oaknode_colormanager_free()) drops
|
||||
* one; the library destroys the object when the count reaches zero.
|
||||
*/
|
||||
typedef struct OakNodeColorManager {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeColorManager;
|
||||
|
||||
/**
|
||||
* @brief Create a color manager bound to `project` (borrowed).
|
||||
*
|
||||
* The manager is created without a config; call
|
||||
* oaknode_colormanager_initialize() (or set a config filename and
|
||||
* oaknode_colormanager_update_config_from_filename()) before using the
|
||||
* config-dependent queries.
|
||||
*
|
||||
* @return Manager handle with reference count 1 (release with
|
||||
* oaknode_colormanager_free()); ctx is NULL on an empty project
|
||||
* handle or allocation failure.
|
||||
*/
|
||||
OakNodeColorManager oaknode_colormanager_init(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Release the caller's reference to the color manager and null
|
||||
* out the handle. No-op on NULL or an empty handle; the object is
|
||||
* destroyed when its reference count reaches zero.
|
||||
*/
|
||||
void oaknode_colormanager_free(OakNodeColorManager *manager);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle wrapping a native manager pointer held by a
|
||||
* node (olive::OCIOBaseNode::manager()).
|
||||
*
|
||||
* The manager stays owned by its project: release() on this handle
|
||||
* only frees the box. Empty handle (ctx == NULL) for a NULL native
|
||||
* pointer.
|
||||
*/
|
||||
OakNodeColorManager oaknode_colormanager_wrap_borrowed(void *native_manager);
|
||||
|
||||
/**
|
||||
* @brief Load the built-in default OCIO config and set the default input
|
||||
* colorspace (olive::ColorManager::init()).
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_FAILED (the OCIO
|
||||
* config could not be created).
|
||||
*/
|
||||
int oaknode_colormanager_initialize(OakNodeColorManager manager);
|
||||
|
||||
/**
|
||||
* @brief (Re)build the process-wide default OCIO config
|
||||
* (olive::ColorManager::set_up_default_config()).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_FAILED.
|
||||
*/
|
||||
int oaknode_colormanager_set_up_default_config(void);
|
||||
|
||||
/**
|
||||
* @brief Config filename stored on the project. Two-stage string getter:
|
||||
* returns the required buffer size in bytes including NUL; pass
|
||||
* buf == NULL or a too-small buffer to query the size.
|
||||
*/
|
||||
int oaknode_colormanager_get_config_filename(OakNodeColorManager manager,
|
||||
char *buf, int buf_size);
|
||||
int oaknode_colormanager_set_config_filename(OakNodeColorManager manager,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Reload the OCIO config from the stored filename. Missing/invalid
|
||||
* files are tolerated (the previous config is kept), matching
|
||||
* olive::ColorManager::update_config_from_filename().
|
||||
*/
|
||||
int oaknode_colormanager_update_config_from_filename(
|
||||
OakNodeColorManager manager);
|
||||
|
||||
/**
|
||||
* @brief Default input colorspace. Two-stage string accessor.
|
||||
*/
|
||||
int oaknode_colormanager_get_default_input_color_space(
|
||||
OakNodeColorManager manager, char *buf, int buf_size);
|
||||
int oaknode_colormanager_set_default_input_color_space(
|
||||
OakNodeColorManager manager, const char *colorspace);
|
||||
|
||||
/**
|
||||
* @brief Reference (working) colorspace. Two-stage string getter.
|
||||
*/
|
||||
int oaknode_colormanager_get_reference_color_space(
|
||||
OakNodeColorManager manager, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Return `colorspace` when the active config lists it, otherwise the
|
||||
* default input colorspace. Two-stage string getter. Requires a config
|
||||
* (OAKNODE_E_STATE when none is loaded).
|
||||
*/
|
||||
int oaknode_colormanager_get_compliant_color_space(
|
||||
OakNodeColorManager manager, const char *colorspace, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Map FFmpeg color primaries/transfer codes to a colorspace of the
|
||||
* active config. Two-stage string getter; an empty result (required size
|
||||
* 1) means "unknown tags, use the default". Requires a config
|
||||
* (OAKNODE_E_STATE when none is loaded).
|
||||
*/
|
||||
int oaknode_colormanager_get_colorspace_for_ffmpeg_tags(
|
||||
OakNodeColorManager manager, int primaries, int trc, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Config listings. Count + per-index two-stage string getters.
|
||||
* All require a loaded config (OAKNODE_E_STATE otherwise); index out of
|
||||
* range yields OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_colormanager_get_display_count(OakNodeColorManager manager,
|
||||
int *count);
|
||||
int oaknode_colormanager_get_display_at(OakNodeColorManager manager,
|
||||
int index, char *buf, int buf_size);
|
||||
int oaknode_colormanager_get_default_display(OakNodeColorManager manager,
|
||||
char *buf, int buf_size);
|
||||
int oaknode_colormanager_get_view_count(OakNodeColorManager manager,
|
||||
const char *display, int *count);
|
||||
int oaknode_colormanager_get_view_at(OakNodeColorManager manager,
|
||||
const char *display, int index, char *buf,
|
||||
int buf_size);
|
||||
int oaknode_colormanager_get_default_view(OakNodeColorManager manager,
|
||||
const char *display, char *buf,
|
||||
int buf_size);
|
||||
int oaknode_colormanager_get_look_count(OakNodeColorManager manager,
|
||||
int *count);
|
||||
int oaknode_colormanager_get_look_at(OakNodeColorManager manager, int index,
|
||||
char *buf, int buf_size);
|
||||
int oaknode_colormanager_get_colorspace_count(OakNodeColorManager manager,
|
||||
int *count);
|
||||
int oaknode_colormanager_get_colorspace_at(OakNodeColorManager manager,
|
||||
int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Default luma coefficients of the active config into rgb[3].
|
||||
* Requires a loaded config (OAKNODE_E_STATE otherwise).
|
||||
*/
|
||||
int oaknode_colormanager_get_default_luma_coefs(OakNodeColorManager manager,
|
||||
double rgb[3]);
|
||||
|
||||
/**
|
||||
* @brief Return a copy of `transform` whose display/view/look (or output
|
||||
* colorspace) is clamped to what the active config offers
|
||||
* (olive::ColorManager::get_compliant_color_space(ColorTransform, bool)).
|
||||
*
|
||||
* `out` receives a NEW by-value handle owned by the caller (reference
|
||||
* count 1, release with oakcommon_colortransform_free()). Requires a
|
||||
* loaded config (OAKNODE_E_STATE otherwise).
|
||||
*/
|
||||
int oaknode_colormanager_get_compliant_color_transform(
|
||||
OakNodeColorManager manager, OakColorTransform transform,
|
||||
int force_display, OakColorTransform *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
namespace olive { class ColorManager; }
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Borrowed access to the underlying C++ manager (C++ only, for
|
||||
* adapter layers). Valid while the handle is held. NULL-safe.
|
||||
*/
|
||||
olive::ColorManager *oaknode_colormanager_get_native(
|
||||
OakNodeColorManager manager);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_COLORMANAGER_H
|
||||
@@ -0,0 +1,137 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_DRAGGER_H
|
||||
#define OAK_EDITOR_NODE_DRAGGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file dragger.h
|
||||
* @brief C ABI for olive::NodeInputDragger (src/node/src/inputdragger.h):
|
||||
* live drag of an input's value with a single commit command.
|
||||
*
|
||||
* A dragger wraps the engine's NodeInputDragger state machine
|
||||
* (start -> drag* -> end). start() records the drag anchor and, when the
|
||||
* input is keyframing, creates one keyframe at the drag time (on every
|
||||
* track when requested); drag() live-sets the dragged component (clamped
|
||||
* by the input's min/max properties when present); end() returns ONE
|
||||
* undoable command that commits the whole drag -- undo removes the
|
||||
* created keyframe(s) (restoring the pre-drag keyframe count), redo
|
||||
* re-creates them with the final value.
|
||||
*
|
||||
* A dragger must be ended before it is freed; freeing a started dragger
|
||||
* leaks the created keyframe(s) (the same ownership rule as the C++
|
||||
* class).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to an input dragger
|
||||
* (olive::NodeInputDragger).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* oaknode_dragger_create() returns a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero.
|
||||
*/
|
||||
typedef struct OakNodeDragger {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeDragger;
|
||||
|
||||
/**
|
||||
* @brief Create an input dragger for live-drag of an input's value.
|
||||
*
|
||||
* `input_id` must name an existing input of `node`; `element` addresses
|
||||
* an array input's element (-1 for non-array inputs). `track` is the
|
||||
* create-time default; the track passed to oaknode_dragger_start()
|
||||
* establishes the actual drag track.
|
||||
*
|
||||
* @return Dragger handle with count 1; ctx is NULL on invalid arguments
|
||||
* or allocation failure.
|
||||
*/
|
||||
OakNodeDragger oaknode_dragger_create(OakNodeNode node, const char *input_id,
|
||||
int element, int track);
|
||||
|
||||
/**
|
||||
* @brief Start the drag at the given rational time (creates a keyframe
|
||||
* when the input is keyframing).
|
||||
*
|
||||
* `insert_on_all_tracks` != 0 also creates sibling keyframes on every
|
||||
* other track of the input. OAKNODE_E_STATE when the dragger was already
|
||||
* started.
|
||||
*/
|
||||
int oaknode_dragger_start(OakNodeDragger dragger, int64_t time_num,
|
||||
int64_t time_den, int track,
|
||||
int insert_on_all_tracks);
|
||||
|
||||
/**
|
||||
* @brief Drag to a new per-track component value (live; no undo).
|
||||
*
|
||||
* `value` carries the dragged component of the input's declared type:
|
||||
* scalar types in f[0]/num; for split-track types (VEC2/3/4/COLOR) the
|
||||
* POD type must match the input's declared type and the dragged
|
||||
* component sits in f[0] (the facade's dragger convention). The value is
|
||||
* clamped to the input's min/max properties when present.
|
||||
* OAKNODE_E_STATE when the dragger was not started.
|
||||
*/
|
||||
int oaknode_dragger_drag(OakNodeDragger dragger, const oaknode_value *value);
|
||||
|
||||
/**
|
||||
* @brief End the drag, returning ONE undoable command for the whole drag.
|
||||
*
|
||||
* `*out_command` receives an owned command handle (execute it with
|
||||
* oakundo_command_redo_now(), push it onto an OakUndoStack, or release
|
||||
* it with oakundo_command_free()). OAKNODE_E_STATE when the dragger was
|
||||
* not started.
|
||||
*/
|
||||
int oaknode_dragger_end(OakNodeDragger dragger, OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief 1 if the dragger has been started and not yet ended.
|
||||
*/
|
||||
int oaknode_dragger_is_started(OakNodeDragger dragger, int *out_started);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a dragger handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* dragger when the count reaches zero. NULL handle or NULL ctx is a
|
||||
* no-op; clears `dragger->ctx` after releasing. The dragger must have
|
||||
* been ended (see the file comment).
|
||||
*/
|
||||
void oaknode_dragger_free(OakNodeDragger *dragger);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_DRAGGER_H
|
||||
@@ -0,0 +1,49 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_ERROR_H
|
||||
#define OAK_EDITOR_NODE_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oaknode C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKNODE_OK) on success, a negative OAKNODE_E_* error code on
|
||||
* 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 oaknode 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 OAKNODE_ABI_VERSION 1
|
||||
|
||||
#define OAKNODE_OK 0 /**< Success. */
|
||||
#define OAKNODE_E_INVALID (-30001) /**< NULL handle or invalid argument. */
|
||||
#define OAKNODE_E_STATE (-30002) /**< Call not valid in the current state. */
|
||||
#define OAKNODE_E_FAILED (-30003) /**< The underlying operation failed. */
|
||||
#define OAKNODE_E_NOT_FOUND (-30004) /**< Index out of range / entry not found. */
|
||||
#define OAKNODE_E_NOMEM (-30005) /**< Allocation failed. */
|
||||
|
||||
#endif //OAK_EDITOR_NODE_ERROR_H
|
||||
@@ -0,0 +1,100 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_FACTORY_H
|
||||
#define OAK_EDITOR_NODE_FACTORY_H
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file factory.h
|
||||
* @brief C ABI for olive::NodeFactory (src/node/src/factory.h): the
|
||||
* internal node-type library.
|
||||
*
|
||||
* The library must be populated with oaknode_factory_initialize() before
|
||||
* any other call; oaknode_factory_destroy() releases it. The factory is
|
||||
* a process-wide singleton (static olive::NodeFactory), so there is no
|
||||
* OakNodeFactory handle type. Prototype nodes from
|
||||
* oaknode_factory_node_at() are owned by the library: read-only metadata
|
||||
* queries only, never add them to a graph.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Populate the internal node library (NodeFactory::initialize()).
|
||||
* Idempotent: calling twice is a no-op.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_factory_initialize(void);
|
||||
|
||||
/**
|
||||
* @brief Release the internal node library (NodeFactory::destroy()).
|
||||
* Safe when not initialized.
|
||||
*/
|
||||
void oaknode_factory_destroy(void);
|
||||
|
||||
/**
|
||||
* @brief Number of registered node types (the library size).
|
||||
* OAKNODE_E_STATE when not initialized.
|
||||
*/
|
||||
int oaknode_factory_id_count(int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The type id of the registered node at `index`. Two-stage
|
||||
* getter; OAKNODE_E_NOT_FOUND for an out-of-range index,
|
||||
* OAKNODE_E_STATE when not initialized.
|
||||
*/
|
||||
int oaknode_factory_id_at(int index, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The display name of the node type `type_id`
|
||||
* (NodeFactory::get_name_from_id()). Two-stage getter; an unknown id
|
||||
* yields an empty string (required size 1).
|
||||
*/
|
||||
int oaknode_factory_name_from_id(const char *type_id, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Create a node of `type_id` WITHOUT adding it to any graph
|
||||
* (NodeFactory::create_from_id()). The caller owns the returned node
|
||||
* (reference count 1) and must release it with oaknode_node_free() while
|
||||
* it is still orphaned. ctx is NULL when the id is unknown or not
|
||||
* initialized.
|
||||
*/
|
||||
OakNodeNode oaknode_factory_create_from_id(const char *type_id);
|
||||
|
||||
/**
|
||||
* @brief Borrow the prototype node at `index` in the library (non-owning
|
||||
* handle written to `out_node`; release it with oaknode_node_free()).
|
||||
* OAKNODE_E_NOT_FOUND for an out-of-range index, OAKNODE_E_STATE when
|
||||
* not initialized.
|
||||
*/
|
||||
int oaknode_factory_node_at(int index, OakNodeNode *out_node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_FACTORY_H
|
||||
@@ -0,0 +1,170 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_FOLDER_H
|
||||
#define OAK_EDITOR_NODE_FOLDER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
#include "node/project.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file folder.h
|
||||
* @brief C ABI for olive::Folder (oaknode)
|
||||
*
|
||||
* A folder is a project node that organizes item children (footage,
|
||||
* sequences, subfolders). Folder handles are borrowed from the owning
|
||||
* project; they become invalid when the project is freed or cleared.
|
||||
*
|
||||
* Child add/remove/move operations execute the underlying undo commands
|
||||
* live (redo_now); wiring them onto an undo stack is the oakundo /
|
||||
* facade layer's job, not this layer's.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a folder node (olive::Folder).
|
||||
*
|
||||
* Semantics are shared_ptr-like (see OakNodeProject): addref(ctx) takes a
|
||||
* reference, release(ctx) drops one. Folder handles handed out by this API
|
||||
* are borrowed views into the owning project's graph: releasing them only
|
||||
* releases the handle itself, never the folder.
|
||||
*/
|
||||
typedef struct OakNodeFolder {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeFolder;
|
||||
|
||||
/**
|
||||
* @brief Create a folder node owned by `project`.
|
||||
*
|
||||
* The folder is added to the project's graph (Project::add_node()) but is
|
||||
* NOT attached under any parent folder; use oaknode_folder_add_child() to
|
||||
* place it. The returned handle is borrowed: the project owns the folder,
|
||||
* so releasing the handle only releases the handle itself.
|
||||
*
|
||||
* @return Folder handle; ctx is NULL on failure.
|
||||
*/
|
||||
OakNodeFolder oaknode_folder_create(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Number of direct item children (Folder::item_child_count()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_folder_child_count(OakNodeFolder folder);
|
||||
|
||||
/**
|
||||
* @brief Borrowed node handle of the item child at `index`
|
||||
* (Folder::item_child()).
|
||||
*
|
||||
* The returned handle only releases the handle itself. Empty handle
|
||||
* (ctx == NULL) when out of range.
|
||||
*/
|
||||
OakNodeNode oaknode_folder_child_at(OakNodeFolder folder, int index);
|
||||
|
||||
/**
|
||||
* @brief Add `child` as a direct item child of `folder` (live, non-undoable;
|
||||
* executes FolderAddChild::redo()).
|
||||
*
|
||||
* After a successful call the graph owns `child`: releasing the child
|
||||
* handle only releases the handle itself.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_STATE if `child` already belongs to a
|
||||
* folder, or another negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_folder_add_child(OakNodeFolder folder, OakNodeNode child);
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a folder handle to its node handle.
|
||||
*
|
||||
* The returned handle only releases the handle itself. Empty handle for an
|
||||
* empty handle.
|
||||
*/
|
||||
OakNodeNode oaknode_folder_as_node(OakNodeFolder folder);
|
||||
|
||||
/**
|
||||
* @brief Create an undoable FolderAddChild command.
|
||||
*
|
||||
* @return Command handle with reference count 1 (release with
|
||||
* oakundo_command_free()); ctx is NULL on failure.
|
||||
*/
|
||||
OakUndoCommand oaknode_command_create_folder_add_child(
|
||||
OakNodeFolder folder, OakNodeNode child);
|
||||
|
||||
/**
|
||||
* @brief Remove `child` from `folder` without deleting it (live,
|
||||
* non-undoable; executes Folder::RemoveElementCommand::redo()).
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_NOT_FOUND if `child` is not a direct child,
|
||||
* or another negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_folder_remove_child(OakNodeFolder folder, OakNodeNode child);
|
||||
|
||||
/**
|
||||
* @brief Move several nodes into `dest_folder` (live, non-undoable).
|
||||
*
|
||||
* Each node is removed from its current folder (if any) and appended to
|
||||
* `dest_folder`; the graph assumes the lifetime of every moved node. Nodes
|
||||
* already directly inside `dest_folder` are skipped.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_folder_move_children(const OakNodeNode *nodes, int count,
|
||||
OakNodeFolder dest_folder);
|
||||
|
||||
/**
|
||||
* @brief 1 if `folder` recursively contains `child`, 0 otherwise
|
||||
* (Folder::has_child_recursive()). Negative OAKNODE_E_* code on empty
|
||||
* handles.
|
||||
*/
|
||||
int oaknode_folder_has_child_recursive(OakNodeFolder folder,
|
||||
OakNodeNode child);
|
||||
|
||||
/**
|
||||
* @brief Index of `child` in `folder`'s direct children
|
||||
* (Folder::index_of_child()).
|
||||
*
|
||||
* @return The index, OAKNODE_E_NOT_FOUND if not a direct child, or
|
||||
* OAKNODE_E_INVALID on empty handles.
|
||||
*/
|
||||
int oaknode_folder_index_of_child(OakNodeFolder folder,
|
||||
OakNodeNode child);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle of the folder a node currently belongs to
|
||||
* (Node::folder()).
|
||||
*
|
||||
* The returned handle only releases the handle itself. Empty handle
|
||||
* (ctx == NULL) if the node is not in any folder.
|
||||
*/
|
||||
OakNodeFolder oaknode_folder_parent_of(OakNodeNode node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_FOLDER_H
|
||||
@@ -0,0 +1,256 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_FOOTAGE_H
|
||||
#define OAK_EDITOR_NODE_FOOTAGE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/videoparams.h"
|
||||
#include "node/error.h"
|
||||
// NOTE: quoted-relative to bypass the "render/cancelatom.h" transition
|
||||
// bridge (oakrender's C++ olive::CancelAtom) that shadows the C ABI
|
||||
// header on oaknode's include path.
|
||||
#include "../../include/render/cancelatom.h"
|
||||
#include "node/project.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file footage.h
|
||||
* @brief C ABI for olive::Footage (oaknode)
|
||||
*
|
||||
* A footage node references an external media file and caches its stream
|
||||
* metadata. Footage handles are borrowed from the owning project; they
|
||||
* become invalid when the project is freed or cleared.
|
||||
*
|
||||
* NOTE: setting a filename whose file exists on disk triggers a probe,
|
||||
* which requires the codec/render modules (outside oaknode). Tests and
|
||||
* pure-graph consumers should use nonexistent paths; probing is the
|
||||
* facade layer's job.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a footage node (olive::Footage).
|
||||
*
|
||||
* Semantics are shared_ptr-like (see OakNodeProject): addref(ctx) takes a
|
||||
* reference, release(ctx) drops one. Footage handles handed out by this
|
||||
* API are borrowed views into the owning project's graph: releasing them
|
||||
* only releases the handle itself, never the footage.
|
||||
*/
|
||||
typedef struct OakNodeFootage {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeFootage;
|
||||
|
||||
/**
|
||||
* @brief Create a footage node owned by `project` (added to the project's
|
||||
* graph, not attached to any folder).
|
||||
*
|
||||
* The returned handle is borrowed: the project owns the footage, so
|
||||
* releasing the handle only releases the handle itself.
|
||||
*
|
||||
* @param filename Initial media path, may be NULL/empty.
|
||||
*
|
||||
* @return Footage handle; ctx is NULL on failure.
|
||||
*/
|
||||
OakNodeFootage oaknode_footage_create(OakNodeProject project,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a footage handle to its node handle.
|
||||
*
|
||||
* The returned handle only releases the handle itself. Empty handle for an
|
||||
* empty handle.
|
||||
*/
|
||||
OakNodeNode oaknode_footage_as_node(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Current media path (Footage::filename()). Two-stage string getter.
|
||||
*
|
||||
* @return Required buffer size in bytes including the NUL, or a negative
|
||||
* OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_filename(OakNodeFootage footage, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set the media path (Footage::set_filename()). Does not re-probe
|
||||
* unless the file exists (see the file comment above).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_set_filename(OakNodeFootage footage, const char *filename);
|
||||
|
||||
/**
|
||||
* @brief 1 if the footage was successfully probed and is ready for use
|
||||
* (Footage::is_valid()), 0 otherwise. Negative OAKNODE_E_* code on an
|
||||
* empty handle.
|
||||
*/
|
||||
int oaknode_footage_is_valid(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Last-modified timestamp of the media file in milliseconds since the
|
||||
* epoch (Footage::timestamp()).
|
||||
*
|
||||
* @param out_timestamp Receives the timestamp. Must not be NULL.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_timestamp(OakNodeFootage footage,
|
||||
int64_t *out_timestamp);
|
||||
|
||||
/**
|
||||
* @brief Set the last-modified timestamp (Footage::set_timestamp()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_set_timestamp(OakNodeFootage footage, int64_t timestamp);
|
||||
|
||||
/**
|
||||
* @brief Decoder ID recorded when the footage was probed
|
||||
* (Footage::decoder()). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_footage_decoder(OakNodeFootage footage, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Total number of streams (Footage::get_total_stream_count()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_total_stream_count(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Number of video streams (ViewerOutput::get_video_stream_count()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_video_stream_count(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Number of audio streams (ViewerOutput::get_audio_stream_count()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_audio_stream_count(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Number of subtitle streams (ViewerOutput::get_subtitle_stream_count()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_subtitle_stream_count(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Footage duration as a rational number of seconds
|
||||
* (ViewerOutput::get_length()).
|
||||
*
|
||||
* @param out_numerator Receives the numerator. Must not be NULL.
|
||||
* @param out_denominator Receives the denominator. Must not be NULL.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_duration(OakNodeFootage footage, int *out_numerator,
|
||||
int *out_denominator);
|
||||
|
||||
/**
|
||||
* @brief 1 if proxy playback is enabled (Footage::proxy_enabled()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_proxy_enabled(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable proxy playback (Footage::set_proxy_enabled()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_set_proxy_enabled(OakNodeFootage footage, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Proxy file path, or "" when none (Footage::proxy_path()).
|
||||
* Two-stage string getter.
|
||||
*/
|
||||
int oaknode_footage_proxy_path(OakNodeFootage footage, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Proxy state enum value (Footage::proxy_state():
|
||||
* ProxyManager::ProxyState). Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_footage_proxy_state(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Set all proxy fields at once (Footage::set_proxy()).
|
||||
*
|
||||
* @param path Proxy file path, may be NULL/empty.
|
||||
* @param state ProxyManager::ProxyState enum value.
|
||||
* @param video_stream_index Proxy's video stream index (-1 when none).
|
||||
* @param preset_version Proxy preset version.
|
||||
* @param enabled Non-zero to enable proxy playback.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_set_proxy(OakNodeFootage footage, const char *path,
|
||||
int state, int video_stream_index,
|
||||
int preset_version, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Clear all proxy fields (Footage::clear_proxy()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_footage_clear_proxy(OakNodeFootage footage);
|
||||
|
||||
/**
|
||||
* @brief Video stream parameters as an oakcommon video-params handle
|
||||
* (ViewerOutput::get_video_params()). `out` receives a handle with
|
||||
* reference count 1 (release with oakcommon_videoparams_free()).
|
||||
* OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_footage_get_video_params(OakNodeFootage footage, int index,
|
||||
OakVideoParams *out);
|
||||
|
||||
/**
|
||||
* @brief Set a video stream's parameters from an oakcommon handle
|
||||
* (ViewerOutput::set_video_params()).
|
||||
*/
|
||||
int oaknode_footage_set_video_params(OakNodeFootage footage, int index,
|
||||
const OakVideoParams *params);
|
||||
|
||||
/**
|
||||
* @brief Video length as a rational pair (ViewerOutput::get_video_length()).
|
||||
*/
|
||||
int oaknode_footage_get_video_length(OakNodeFootage footage,
|
||||
int64_t *out_num, int64_t *out_den);
|
||||
|
||||
/**
|
||||
* @brief Set the footage's cancellation atom used during probing
|
||||
* (Footage::set_cancel_pointer()). `atom` may be an empty OakCancelAtom
|
||||
* (ctx == NULL) to clear.
|
||||
*/
|
||||
int oaknode_footage_set_cancel_atom(OakNodeFootage footage,
|
||||
OakCancelAtom atom);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_FOOTAGE_H
|
||||
@@ -0,0 +1,186 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_GROUP_H
|
||||
#define OAK_EDITOR_NODE_GROUP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file group.h
|
||||
* @brief C ABI for olive::NodeGroup (src/node/src/group/group.h):
|
||||
* input passthrough management and input resolution.
|
||||
*
|
||||
* An OakNodeGroup wraps an olive::NodeGroup (a Node subclass); group
|
||||
* handles share the reference-counted lifetime rules of OakNodeNode.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a node group (olive::NodeGroup).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* oaknode_group_create() returns a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero. Handles returned by
|
||||
* oaknode_group_cast() are borrowed views of a node: releasing them
|
||||
* never destroys the underlying group.
|
||||
*/
|
||||
typedef struct OakNodeGroup {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeGroup;
|
||||
|
||||
/**
|
||||
* @brief Create a standalone NodeGroup (owned; release with
|
||||
* oaknode_group_free() while still orphaned).
|
||||
*
|
||||
* @return Group handle with count 1; ctx is NULL on allocation failure.
|
||||
*/
|
||||
OakNodeGroup oaknode_group_create(void);
|
||||
|
||||
/**
|
||||
* @brief Borrow a group view of a node (dynamic_cast). The returned
|
||||
* handle is non-owning; release it with oaknode_group_free().
|
||||
*
|
||||
* @return Borrowed group handle; ctx is NULL when the node is not a
|
||||
* NodeGroup.
|
||||
*/
|
||||
OakNodeGroup oaknode_group_cast(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a group handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* group when the count reaches zero and the handle owns it. NULL handle
|
||||
* or NULL ctx is a no-op; clears `group->ctx` after releasing.
|
||||
*/
|
||||
void oaknode_group_free(OakNodeGroup *group);
|
||||
|
||||
/**
|
||||
* @brief Add an input passthrough for (`node`, `input_id`, `element`)
|
||||
* (live, NodeGroup::add_input_passthrough()). The generated passthrough
|
||||
* id is returned through the two-stage string convention.
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_group_add_input_passthrough(OakNodeGroup group,
|
||||
OakNodeNode node,
|
||||
const char *input_id, int element,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Create an add-passthrough command
|
||||
* (olive::NodeGroupAddInputPassthrough). The generated id is NOT
|
||||
* retrievable through this call (the command computes it on redo).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_group_add_input_passthrough_undoable(OakNodeGroup group,
|
||||
OakNodeNode node,
|
||||
const char *input_id,
|
||||
int element,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Remove the passthrough for (`node`, `input_id`, `element`)
|
||||
* (live). OAKNODE_E_NOT_FOUND when no such passthrough exists.
|
||||
*/
|
||||
int oaknode_group_remove_input_passthrough(OakNodeGroup group,
|
||||
OakNodeNode node,
|
||||
const char *input_id, int element);
|
||||
|
||||
/**
|
||||
* @brief Number of registered input passthroughs.
|
||||
*/
|
||||
int oaknode_group_passthrough_count(OakNodeGroup group, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The passthrough id at `index`. Two-stage getter;
|
||||
* OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_group_passthrough_id_at(OakNodeGroup group, int index,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The inner input behind passthrough `index`: node (borrowed
|
||||
* handle written to `out_node` when non-NULL; release it with
|
||||
* oaknode_node_free()), input id (two-stage string) and element.
|
||||
* OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_group_passthrough_input_at(OakNodeGroup group, int index,
|
||||
OakNodeNode *out_node, char *buf,
|
||||
int buf_size, int *out_element);
|
||||
|
||||
/**
|
||||
* @brief The output passthrough node (borrowed handle written to
|
||||
* `out_node`; release it with oaknode_node_free()), an empty handle when
|
||||
* unset. OAKNODE_OK is returned either way.
|
||||
*/
|
||||
int oaknode_group_get_output_passthrough(OakNodeGroup group,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/**
|
||||
* @brief Set the output passthrough node directly (live). `node` may be
|
||||
* an empty handle to clear the passthrough.
|
||||
*/
|
||||
int oaknode_group_set_output_passthrough(OakNodeGroup group,
|
||||
OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Create a set-output-passthrough command
|
||||
* (olive::NodeGroupSetOutputPassthrough).
|
||||
*/
|
||||
int oaknode_group_set_output_passthrough_undoable(
|
||||
OakNodeGroup group, OakNodeNode node, OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Resolve an input through group passthroughs
|
||||
* (NodeGroup::resolve_input()): follows a group's passthrough id to the
|
||||
* inner node input. Non-group inputs resolve to themselves.
|
||||
*
|
||||
* `out_node` (may be NULL) receives a borrowed handle (release it with
|
||||
* oaknode_node_free()); the resolved input id uses the two-stage string
|
||||
* convention; `out_element` (may be NULL) receives the element.
|
||||
* OAKNODE_E_NOT_FOUND when the input does not resolve to a valid target.
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_group_resolve_input(OakNodeNode node, const char *input_id,
|
||||
int element, OakNodeNode *out_node,
|
||||
char *buf, int buf_size, int *out_element);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_GROUP_H
|
||||
@@ -0,0 +1,295 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_KEYFRAME_H
|
||||
#define OAK_EDITOR_NODE_KEYFRAME_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file keyframe.h
|
||||
* @brief C ABI for olive::NodeKeyframe (src/node/src/keyframe.h).
|
||||
*
|
||||
* An OakNodeKeyframe wraps an olive::NodeKeyframe. Handles created by
|
||||
* oaknode_keyframe_create() are owned and must be released with
|
||||
* oaknode_keyframe_free(); keyframes attached to a node input's track
|
||||
* are owned by the node.
|
||||
*
|
||||
* Every setter comes in a live variant and an undoable variant (suffix
|
||||
* _undoable) returning an owned, un-executed OakUndoCommand.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Interpolation type of a keyframe (olive::NodeKeyframe::Type).
|
||||
*/
|
||||
typedef enum oaknode_keyframe_type {
|
||||
OAKNODE_KEYFRAME_INVALID = -1,
|
||||
OAKNODE_KEYFRAME_LINEAR = 0,
|
||||
OAKNODE_KEYFRAME_HOLD = 1,
|
||||
OAKNODE_KEYFRAME_BEZIER = 2
|
||||
} oaknode_keyframe_type;
|
||||
|
||||
/**
|
||||
* @brief Bezier handle selector (olive::NodeKeyframe::BezierType).
|
||||
*/
|
||||
typedef enum oaknode_keyframe_bezier {
|
||||
OAKNODE_KEYFRAME_IN_HANDLE = 0,
|
||||
OAKNODE_KEYFRAME_OUT_HANDLE = 1
|
||||
} oaknode_keyframe_bezier;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a keyframe (olive::NodeKeyframe).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* oaknode_keyframe_create() returns a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero.
|
||||
*/
|
||||
typedef struct OakNodeKeyframe {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeKeyframe;
|
||||
|
||||
/**
|
||||
* @brief Create a standalone keyframe (owned; release with
|
||||
* oaknode_keyframe_free()).
|
||||
*
|
||||
* `value` may be NULL (null variant); OAKNODE_VALUE_STRING is rejected
|
||||
* (use oaknode_keyframe_set_value_string() after creation). `type` is an
|
||||
* oaknode_keyframe_type. `parent_or_null` may be an empty handle.
|
||||
*
|
||||
* @return Keyframe handle with count 1; ctx is NULL on invalid argument
|
||||
* or allocation failure.
|
||||
*/
|
||||
OakNodeKeyframe oaknode_keyframe_create(int64_t time_num, int64_t time_den,
|
||||
const oaknode_value *value, int type,
|
||||
int track, int element,
|
||||
const char *input_id,
|
||||
OakNodeNode parent_or_null);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a keyframe handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* keyframe when the count reaches zero and the handle owns it. NULL
|
||||
* handle or NULL ctx is a no-op; clears `keyframe->ctx` after releasing.
|
||||
* Never free a keyframe that is attached to a node's track.
|
||||
*/
|
||||
void oaknode_keyframe_free(OakNodeKeyframe *keyframe);
|
||||
|
||||
/**
|
||||
* @brief The keyframe's time as a rational (numerator/denominator).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_keyframe_get_time(OakNodeKeyframe keyframe,
|
||||
int64_t *out_num, int64_t *out_den);
|
||||
|
||||
/**
|
||||
* @brief Set the keyframe's time directly (live).
|
||||
*/
|
||||
int oaknode_keyframe_set_time(OakNodeKeyframe keyframe, int64_t time_num,
|
||||
int64_t time_den);
|
||||
|
||||
/**
|
||||
* @brief Create a set-time command (olive::NodeParamSetKeyframeTimeCommand).
|
||||
*/
|
||||
int oaknode_keyframe_set_time_undoable(OakNodeKeyframe keyframe,
|
||||
int64_t time_num, int64_t time_den,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Read the keyframe's value mapped into `out`. Values without a
|
||||
* POD representation fail with OAKNODE_E_FAILED.
|
||||
*/
|
||||
int oaknode_keyframe_get_value(OakNodeKeyframe keyframe,
|
||||
oaknode_value *out);
|
||||
|
||||
/**
|
||||
* @brief Set the keyframe's value directly (live).
|
||||
* OAKNODE_VALUE_STRING is rejected (use
|
||||
* oaknode_keyframe_set_value_string()).
|
||||
*/
|
||||
int oaknode_keyframe_set_value(OakNodeKeyframe keyframe,
|
||||
const oaknode_value *v);
|
||||
|
||||
/**
|
||||
* @brief Create a set-value command
|
||||
* (olive::NodeParamSetKeyframeValueCommand).
|
||||
*/
|
||||
int oaknode_keyframe_set_value_undoable(OakNodeKeyframe keyframe,
|
||||
const oaknode_value *v,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Read a string value. Two-stage getter.
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_keyframe_get_value_string(OakNodeKeyframe keyframe,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set a string value directly (live).
|
||||
*/
|
||||
int oaknode_keyframe_set_value_string(OakNodeKeyframe keyframe,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Create a set-string-value command.
|
||||
*/
|
||||
int oaknode_keyframe_set_value_string_undoable(OakNodeKeyframe keyframe,
|
||||
const char *value,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief The keyframe's interpolation type (oaknode_keyframe_type).
|
||||
*/
|
||||
int oaknode_keyframe_get_type(OakNodeKeyframe keyframe, int *out_type);
|
||||
|
||||
/**
|
||||
* @brief Set the interpolation type directly (live,
|
||||
* NodeKeyframe::set_type(), which adjusts neighbouring bezier handles).
|
||||
*/
|
||||
int oaknode_keyframe_set_type(OakNodeKeyframe keyframe, int type);
|
||||
|
||||
/**
|
||||
* @brief Create a set-type command (same semantics as the live variant).
|
||||
*/
|
||||
int oaknode_keyframe_set_type_undoable(OakNodeKeyframe keyframe, int type,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief A bezier control point (`handle` is an
|
||||
* oaknode_keyframe_bezier).
|
||||
*/
|
||||
int oaknode_keyframe_get_bezier_control(OakNodeKeyframe keyframe,
|
||||
int handle, double *out_x,
|
||||
double *out_y);
|
||||
|
||||
/**
|
||||
* @brief Set a bezier control point directly (live).
|
||||
*/
|
||||
int oaknode_keyframe_set_bezier_control(OakNodeKeyframe keyframe, int handle,
|
||||
double x, double y);
|
||||
|
||||
/**
|
||||
* @brief Create a set-bezier-control command.
|
||||
*/
|
||||
int oaknode_keyframe_set_bezier_control_undoable(OakNodeKeyframe keyframe,
|
||||
int handle, double x, double y,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief The keyframe's track index.
|
||||
*/
|
||||
int oaknode_keyframe_get_track(OakNodeKeyframe keyframe,
|
||||
int *out_track);
|
||||
|
||||
/**
|
||||
* @brief The keyframe's element index.
|
||||
*/
|
||||
int oaknode_keyframe_get_element(OakNodeKeyframe keyframe,
|
||||
int *out_element);
|
||||
|
||||
/**
|
||||
* @brief The id of the input this keyframe belongs to. Two-stage getter.
|
||||
*/
|
||||
int oaknode_keyframe_get_input(OakNodeKeyframe keyframe, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The node this keyframe belongs to (borrowed handle written to
|
||||
* `out_node`; release it with oaknode_node_free()), an empty handle when
|
||||
* orphaned. OAKNODE_OK either way.
|
||||
*/
|
||||
int oaknode_keyframe_get_parent(OakNodeKeyframe keyframe,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/**
|
||||
* @brief A bezier control point guaranteed valid for animation
|
||||
* (NodeKeyframe::valid_bezier_control_in()/out()).
|
||||
*
|
||||
* Unlike oaknode_keyframe_get_bezier_control(), the returned point is
|
||||
* clamped so the curve never overlaps: the in-handle's x cannot pass the
|
||||
* previous keyframe's time and the out-handle's x cannot pass the next
|
||||
* keyframe's time. `handle` is an oaknode_keyframe_bezier.
|
||||
*/
|
||||
int oaknode_keyframe_get_valid_bezier_control(OakNodeKeyframe keyframe,
|
||||
int handle, double *out_x,
|
||||
double *out_y);
|
||||
|
||||
/**
|
||||
* @brief The opposing bezier handle type
|
||||
* (NodeKeyframe::get_opposing_bezier_type): OAKNODE_KEYFRAME_IN_HANDLE
|
||||
* (0) <-> OAKNODE_KEYFRAME_OUT_HANDLE (1).
|
||||
*
|
||||
* @return The opposing handle type, or OAKNODE_E_INVALID for a type
|
||||
* outside the two handle values.
|
||||
*/
|
||||
int oaknode_keyframe_opposing_bezier_type(int type);
|
||||
|
||||
/**
|
||||
* @brief Compute the combined node value to use when inserting
|
||||
* `keyframe` onto `target_node` (the keyframe paste path).
|
||||
*
|
||||
* Takes the target node's split value at the keyframe's time, replaces
|
||||
* the keyframe's own track with the keyframe's value, and combines the
|
||||
* per-track components into a single normal value (mirrors the facade's
|
||||
* oakengine_keyframe_compute_paste_value). OAKNODE_E_NOT_FOUND when the
|
||||
* keyframe's input id does not exist on `target_node`; OAKNODE_E_FAILED
|
||||
* for input types without a POD representation.
|
||||
*/
|
||||
int oaknode_keyframe_compute_paste_value(OakNodeNode target_node,
|
||||
OakNodeKeyframe keyframe,
|
||||
oaknode_value *out);
|
||||
|
||||
/**
|
||||
* @brief 1 if a sibling keyframe exists at the given rational time on
|
||||
* this keyframe's own track (NodeKeyframe::has_sibling_at_time(): the
|
||||
* track's key at `time` that is not this keyframe — the move-collision
|
||||
* check). Unlike the facade, the time is an exact rational rather than a
|
||||
* whole-second frame timestamp, and no track argument is needed (the
|
||||
* lookup is relative to this keyframe's track).
|
||||
*
|
||||
* An orphaned keyframe (no parent node) has no siblings: `*out_value`
|
||||
* is set to 0 and OAKNODE_OK is returned.
|
||||
*/
|
||||
int oaknode_keyframe_has_sibling_at_time(OakNodeKeyframe keyframe,
|
||||
int64_t time_num, int64_t time_den,
|
||||
int *out_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_KEYFRAME_H
|
||||
@@ -0,0 +1,119 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_MULTICAM_H
|
||||
#define OAK_EDITOR_NODE_MULTICAM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file multicam.h
|
||||
* @brief C ABI for olive::MultiCamNode (src/node/src/input/multicam/
|
||||
* multicamnode.h): multi-camera source switching and the source-grid
|
||||
* math used by the multicam viewer.
|
||||
*
|
||||
* The input-id getters return static strings (never freed) naming the
|
||||
* multicam node's inputs: current source (combo), sources (array),
|
||||
* sequence and sequence type. A node that is not a MultiCamNode (or a
|
||||
* NULL handle) fails the per-node queries with OAKNODE_E_INVALID.
|
||||
*
|
||||
* The grid helpers are static and pure: they only depend on their
|
||||
* arguments, not on a node.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief The input id string for the current camera ("current_in").
|
||||
*/
|
||||
const char *oaknode_multicam_input_current(void);
|
||||
|
||||
/**
|
||||
* @brief The input id string for the sources array ("sources_in").
|
||||
*/
|
||||
const char *oaknode_multicam_input_sources(void);
|
||||
|
||||
/**
|
||||
* @brief The input id string for the sequence ("sequence_in").
|
||||
*/
|
||||
const char *oaknode_multicam_input_sequence(void);
|
||||
|
||||
/**
|
||||
* @brief The input id string for the sequence type ("sequence_type_in").
|
||||
*/
|
||||
const char *oaknode_multicam_input_sequence_type(void);
|
||||
|
||||
/**
|
||||
* @brief Number of connected source cameras (MultiCamNode::
|
||||
* get_source_count(); the connected sequence's track count, or the
|
||||
* sources array size when no sequence is connected).
|
||||
*
|
||||
* OAKNODE_E_INVALID when `node` is not a multicam.
|
||||
*/
|
||||
int oaknode_multicam_get_source_count(OakNodeNode node, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief Compute the grid (rows, cols) that holds `source_count` cells.
|
||||
*
|
||||
* Mirrors MultiCamNode::get_rows_and_columns(): the grid grows from
|
||||
* 1x1, widening the smaller dimension, until rows * cols >= source_count
|
||||
* (0 sources yields 1x1). OAKNODE_E_INVALID for a negative count or
|
||||
* NULL out pointers.
|
||||
*/
|
||||
int oaknode_multicam_get_rows_and_columns(int source_count, int *rows,
|
||||
int *cols);
|
||||
|
||||
/**
|
||||
* @brief Convert a flat source index to (row, col) in a rows x cols grid
|
||||
* (row-major: col = index % cols, row = index / cols).
|
||||
*
|
||||
* OAKNODE_E_INVALID for a negative index, degenerate grid or NULL out
|
||||
* pointers.
|
||||
*/
|
||||
int oaknode_multicam_index_to_row_cols(int index, int rows, int cols,
|
||||
int *out_row, int *out_col);
|
||||
|
||||
/**
|
||||
* @brief Convert (row, col) to a flat source index (col + row * cols).
|
||||
*
|
||||
* @return The flat index (>= 0), or OAKNODE_E_INVALID when the cell is
|
||||
* out of range or the grid is degenerate.
|
||||
*/
|
||||
int oaknode_multicam_rows_cols_to_index(int row, int col, int rows,
|
||||
int cols);
|
||||
|
||||
/**
|
||||
* @brief The current source index (MultiCamNode::get_current_source(),
|
||||
* the "current_in" combo value).
|
||||
*
|
||||
* OAKNODE_E_INVALID when `node` is not a multicam.
|
||||
*/
|
||||
int oaknode_multicam_get_current_source(OakNodeNode node, int *out_source);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_MULTICAM_H
|
||||
@@ -0,0 +1,679 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_NODE_H
|
||||
#define OAK_EDITOR_NODE_NODE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/videoparams.h"
|
||||
#include "node/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file node.h
|
||||
* @brief C ABI for olive::Node (src/node/src/node.h).
|
||||
*
|
||||
* Handles are by-value reference-counted structs (see
|
||||
* include/common/handle.h): every OakNodeNode carries ctx/addref/release/
|
||||
* abi_version and behaves like a shared_ptr at the ABI level. Factory
|
||||
* functions return a handle with reference count 1; release it with
|
||||
* oaknode_node_free(). Handles borrowed from a graph only release the
|
||||
* handle itself when freed; once a node lives in a project graph its
|
||||
* lifetime belongs to the graph (the implementation flips ownership
|
||||
* internally), and borrowed handles become invalid when the owning project
|
||||
* or node is destroyed.
|
||||
*
|
||||
* Parameter values cross the boundary as the POD oaknode_value; the
|
||||
* meaningful fields depend on its type (oaknode_value_type). String-typed
|
||||
* inputs (NodeValue::k_file/k_text/k_font/k_str_combo) do not fit the POD
|
||||
* and use the dedicated *_input_string() pair (two-stage buf/size getters
|
||||
* return the required size including the terminating NUL).
|
||||
*
|
||||
* Every mutating function comes in a live variant (applies immediately)
|
||||
* and an undoable variant (suffix _undoable) that creates an
|
||||
* olive::UndoCommand without executing it and returns it as an owned
|
||||
* OakUndoCommand handle. Execute it with oakundo_command_redo_now(),
|
||||
* push it onto an OakUndoStack, or release it with
|
||||
* oakundo_command_free().
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Value type of an oaknode_value / a node input.
|
||||
*
|
||||
* Pinned mapping to olive::NodeValue::Type (src/node/src/value.h):
|
||||
* NONE -> k_none, INT -> k_int, FLOAT -> k_float, BOOL -> k_boolean,
|
||||
* RATIONAL -> k_rational, COLOR -> k_color, VEC2 -> k_vec2,
|
||||
* VEC3 -> k_vec3, VEC4 -> k_vec4, COMBO -> k_combo,
|
||||
* STRING -> k_file (string-family inputs: k_file/k_text/k_font/
|
||||
* k_str_combo, handled by the dedicated string functions). Types without
|
||||
* a POD representation (texture, samples, matrix, params, bezier, binary,
|
||||
* ...) report as OAKNODE_VALUE_NONE.
|
||||
*/
|
||||
typedef enum oaknode_value_type {
|
||||
OAKNODE_VALUE_NONE = 0,
|
||||
OAKNODE_VALUE_INT, /**< num (olive k_int, int64_t) */
|
||||
OAKNODE_VALUE_FLOAT, /**< f[0] (olive k_float, double) */
|
||||
OAKNODE_VALUE_BOOL, /**< num 0/1 (olive k_boolean) */
|
||||
OAKNODE_VALUE_RATIONAL, /**< num/den (olive k_rational) */
|
||||
OAKNODE_VALUE_COLOR, /**< f[0..3] = r,g,b,a (olive k_color) */
|
||||
OAKNODE_VALUE_VEC2, /**< f[0..1] (olive k_vec2) */
|
||||
OAKNODE_VALUE_VEC3, /**< f[0..2] (olive k_vec3) */
|
||||
OAKNODE_VALUE_VEC4, /**< f[0..3] (olive k_vec4) */
|
||||
OAKNODE_VALUE_COMBO, /**< num = selected index (olive k_combo) */
|
||||
OAKNODE_VALUE_STRING, /**< k_file string family; string APIs only */
|
||||
OAKNODE_VALUE_COUNT
|
||||
} oaknode_value_type;
|
||||
|
||||
/**
|
||||
* @brief POD parameter value. Only the fields documented for the value's
|
||||
* `type` are meaningful.
|
||||
*/
|
||||
typedef struct oaknode_value {
|
||||
int type; /**< oaknode_value_type. */
|
||||
int64_t num; /**< INT/COMBO value, BOOL 0/1, RATIONAL numerator. */
|
||||
int64_t den; /**< RATIONAL denominator. */
|
||||
double f[4]; /**< FLOAT f[0]; VEC2/3/4 f[0..n-1]; COLOR r,g,b,a. */
|
||||
} oaknode_value;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a node (olive::Node).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* init/factory functions return a handle with reference count 1,
|
||||
* addref(ctx) takes another reference, release(ctx) drops one; release a
|
||||
* handle with oaknode_node_free(). Borrowed handles into graph-owned
|
||||
* objects only release the handle itself.
|
||||
*/
|
||||
typedef struct OakNodeNode {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeNode;
|
||||
|
||||
/* Re-declared here so node.h is self-contained; see node/project.h. */
|
||||
typedef struct OakNodeProject OakNodeProject;
|
||||
|
||||
/* Re-declared here so node.h is self-contained; see node/footage.h. */
|
||||
typedef struct OakNodeFootage OakNodeFootage;
|
||||
|
||||
/**
|
||||
* @brief Timeline data owned by viewer nodes (TimelineMarkerList /
|
||||
* TimelineWorkArea in oaktimeline) cross the boundary as oaktimeline
|
||||
* value handles. Forward-declared here so node.h stays self-contained;
|
||||
* include timeline/marker.h / timeline/workarea.h for the definitions.
|
||||
*/
|
||||
struct OakTimelineMarkerList;
|
||||
struct OakTimelineWorkArea;
|
||||
|
||||
/**
|
||||
* @brief Opaque borrowed handle to a node's video frame cache
|
||||
* (olive::FrameHashCache in oakrender). oakrender reinterprets this into
|
||||
* its own handle types.
|
||||
*/
|
||||
struct OakRenderCache;
|
||||
|
||||
/* oakcore handles used by the viewer setters. */
|
||||
typedef struct OakAudioParams OakAudioParams;
|
||||
|
||||
/**
|
||||
* @brief Number of live owned objects created through this API
|
||||
* (nodes from oaknode_factory_create_from_id()/oaknode_node_create_copy(),
|
||||
* keyframes, groups, traversers, traverser databases). Debug aid for
|
||||
* leak checking; thread-unsafe, test/diagnostic use only.
|
||||
*/
|
||||
int oaknode_debug_alive_count(void);
|
||||
|
||||
/* ---- Metadata --------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief The node's unique type id (Node::id(), e.g.
|
||||
* "org.olivevideoeditor.Olive.solidgenerator"). Two-stage getter.
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_get_id(OakNodeNode node, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The node's display name (Node::name()). Two-stage getter,
|
||||
* same return convention as oaknode_node_get_id().
|
||||
*/
|
||||
int oaknode_node_get_name(OakNodeNode node, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The node's user label (Node::get_label()). Two-stage getter,
|
||||
* same return convention as oaknode_node_get_id().
|
||||
*/
|
||||
int oaknode_node_get_label(OakNodeNode node, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set the node's user label directly (Node::set_label(), live).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_label(OakNodeNode node, const char *label);
|
||||
|
||||
/**
|
||||
* @brief Create a label-change command (olive::NodeRenameCommand).
|
||||
*
|
||||
* The command is NOT executed; `out_command` receives an owned command
|
||||
* handle.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_label_undoable(OakNodeNode node, const char *label,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief The node's override color index (Node::get_override_color();
|
||||
* -1 = none).
|
||||
*
|
||||
* @param out_value Receives the result. Must not be NULL.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_get_override_color(OakNodeNode node, int *out_value);
|
||||
|
||||
/**
|
||||
* @brief Set the override color index directly (-1 = none; live).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_override_color(OakNodeNode node, int index);
|
||||
|
||||
/**
|
||||
* @brief Create an override-color command (olive::NodeOverrideColorCommand).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_override_color_undoable(OakNodeNode node, int index,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief 1 if the node is enabled (the boolean "enabled_in" input's
|
||||
* standard value).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_is_enabled(OakNodeNode node, int *out_value);
|
||||
|
||||
/**
|
||||
* @brief Set the node's enabled state directly (live).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_enabled(OakNodeNode node, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Create an enabled-state command
|
||||
* (olive::NodeParamSetStandardValueCommand on "enabled_in").
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_set_enabled_undoable(OakNodeNode node, int enabled,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/* ---- Input introspection ------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Number of declared inputs (Node::inputs(); array elements are not
|
||||
* counted separately).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_node_input_count(OakNodeNode node, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The input id at `index` (Node::inputs()). Two-stage getter;
|
||||
* returns OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_node_input_id(OakNodeNode node, int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The input's value type mapped to oaknode_value_type (see the
|
||||
* pinned mapping on oaknode_value_type). OAKNODE_E_NOT_FOUND for an
|
||||
* unknown input id.
|
||||
*/
|
||||
int oaknode_node_input_get_type(OakNodeNode node, const char *input_id,
|
||||
int *out_type);
|
||||
|
||||
/**
|
||||
* @brief 1 if the input currently has a connected edge
|
||||
* (Node::is_input_connected()). OAKNODE_E_NOT_FOUND for an unknown id.
|
||||
*/
|
||||
int oaknode_node_input_is_connected(OakNodeNode node, const char *input_id,
|
||||
int *out_value);
|
||||
|
||||
/**
|
||||
* @brief 1 if the input accepts connections (Node::is_input_connectable()).
|
||||
* OAKNODE_E_NOT_FOUND for an unknown id.
|
||||
*/
|
||||
int oaknode_node_input_is_connectable(OakNodeNode node, const char *input_id,
|
||||
int *out_value);
|
||||
|
||||
/**
|
||||
* @brief The human-readable name of the input (Node::get_input_name()).
|
||||
* Two-stage getter; OAKNODE_E_NOT_FOUND for an unknown id.
|
||||
*/
|
||||
int oaknode_node_get_input_name(OakNodeNode node, const char *input_id,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The node feeding this input (Node::get_connected_output(),
|
||||
* element -1). `out_node` receives a borrowed handle (empty, ctx == NULL,
|
||||
* when not connected; releasing it only releases the handle).
|
||||
* OAKNODE_E_NOT_FOUND for an unknown input id.
|
||||
*/
|
||||
int oaknode_node_input_get_connected_node(OakNodeNode node,
|
||||
const char *input_id,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/* ---- Parameter access ----------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Read an input's standard value (Node::get_standard_value())
|
||||
* mapped into `out`.
|
||||
*
|
||||
* String-family inputs fail with OAKNODE_E_INVALID (use
|
||||
* oaknode_node_get_input_string()); types without a POD representation
|
||||
* fail with OAKNODE_E_FAILED; an unknown input id fails with
|
||||
* OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_node_get_input(OakNodeNode node, const char *input_id,
|
||||
oaknode_value *out);
|
||||
|
||||
/**
|
||||
* @brief Write an input's standard value directly (live,
|
||||
* Node::set_standard_value()).
|
||||
*
|
||||
* `v->type` must match the input's declared type; OAKNODE_VALUE_STRING is
|
||||
* rejected (use oaknode_node_set_input_string()).
|
||||
*/
|
||||
int oaknode_node_set_input(OakNodeNode node, const char *input_id,
|
||||
const oaknode_value *v);
|
||||
|
||||
/**
|
||||
* @brief Create a set-standard-value command
|
||||
* (olive::NodeParamSetStandardValueCommand, track -1 semantics via the
|
||||
* whole-value reference on track 0).
|
||||
*
|
||||
* Same type rules as oaknode_node_set_input().
|
||||
*/
|
||||
int oaknode_node_set_input_undoable(OakNodeNode node, const char *input_id,
|
||||
const oaknode_value *v,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Read a string-family input's standard value. Two-stage getter.
|
||||
*/
|
||||
int oaknode_node_get_input_string(OakNodeNode node, const char *input_id,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Write a string-family input's standard value directly (live).
|
||||
*/
|
||||
int oaknode_node_set_input_string(OakNodeNode node, const char *input_id,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Create a set-standard-value command for a string-family input.
|
||||
*/
|
||||
int oaknode_node_set_input_string_undoable(OakNodeNode node,
|
||||
const char *input_id,
|
||||
const char *value,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/* ---- Graph editing -------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Connect `output_node`'s output into `input_node`'s `input_id`
|
||||
* directly (live, Node::connect_edge(), element -1).
|
||||
*
|
||||
* Fails with OAKNODE_E_NOT_FOUND for an unknown input id,
|
||||
* OAKNODE_E_INVALID when the input is not connectable, and
|
||||
* OAKNODE_E_STATE when the input is already connected or the nodes belong
|
||||
* to different graphs.
|
||||
*/
|
||||
int oaknode_node_connect(OakNodeNode output_node, OakNodeNode input_node,
|
||||
const char *input_id);
|
||||
|
||||
/**
|
||||
* @brief Create an edge-add command (olive::NodeEdgeAddCommand,
|
||||
* element -1). Same validation as oaknode_node_connect() except the
|
||||
* different-graph check (the command may legitimately be redone after
|
||||
* graph changes).
|
||||
*/
|
||||
int oaknode_node_connect_undoable(OakNodeNode output_node,
|
||||
OakNodeNode input_node,
|
||||
const char *input_id,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Remove the edge feeding `input_node`'s `input_id` directly
|
||||
* (live, Node::disconnect_edge(), element -1). OAKNODE_E_NOT_FOUND when
|
||||
* the input is unknown or not connected.
|
||||
*/
|
||||
int oaknode_node_disconnect(OakNodeNode input_node, const char *input_id);
|
||||
|
||||
/**
|
||||
* @brief Create an edge-remove command (olive::NodeEdgeRemoveCommand,
|
||||
* element -1). OAKNODE_E_NOT_FOUND when not connected.
|
||||
*/
|
||||
int oaknode_node_disconnect_undoable(OakNodeNode input_node,
|
||||
const char *input_id,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Number of outgoing edges (Node::output_connections()).
|
||||
*/
|
||||
int oaknode_node_output_connection_count(OakNodeNode node, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The node at the input end of outgoing edge `index` (borrowed
|
||||
* handle; releasing it only releases the handle). OAKNODE_E_NOT_FOUND for
|
||||
* an out-of-range index.
|
||||
*/
|
||||
int oaknode_node_output_connection_node_at(OakNodeNode node, int index,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/**
|
||||
* @brief The input id at the input end of outgoing edge `index`.
|
||||
* Two-stage getter; OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_node_output_connection_input_id_at(OakNodeNode node, int index,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The input element at the input end of outgoing edge `index`
|
||||
* (-1 for non-array inputs). OAKNODE_E_NOT_FOUND for an out-of-range
|
||||
* index.
|
||||
*/
|
||||
int oaknode_node_output_connection_element_at(OakNodeNode node, int index,
|
||||
int *out_element);
|
||||
|
||||
/* ---- Links --------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Link two nodes directly (live, Node::link()). `out_linked`
|
||||
* receives 1 on success, 0 when the link was rejected (e.g. either node
|
||||
* rejects links). `out_linked` may be NULL.
|
||||
*/
|
||||
int oaknode_node_link(OakNodeNode a, OakNodeNode b, int *out_linked);
|
||||
|
||||
/**
|
||||
* @brief Unlink two nodes directly (live, Node::unlink()).
|
||||
* `out_unlinked` receives 1 on success, 0 otherwise; may be NULL.
|
||||
*/
|
||||
int oaknode_node_unlink(OakNodeNode a, OakNodeNode b, int *out_unlinked);
|
||||
|
||||
/**
|
||||
* @brief Create a link/unlink command (olive::NodeLinkCommand;
|
||||
* `link` != 0 links, 0 unlinks).
|
||||
*/
|
||||
int oaknode_node_link_undoable(OakNodeNode a, OakNodeNode b, int link,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief 1 if the two nodes are linked (Node::are_linked()).
|
||||
*/
|
||||
int oaknode_node_are_linked(OakNodeNode a, OakNodeNode b, int *out_value);
|
||||
|
||||
/**
|
||||
* @brief Number of linked nodes (Node::links()).
|
||||
*/
|
||||
int oaknode_node_link_count(OakNodeNode node, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The linked node at `index` (borrowed handle; releasing it only
|
||||
* releases the handle). OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_node_link_at(OakNodeNode node, int index,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/* ---- Context positions ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Number of context entries (Node::get_context_positions()).
|
||||
*/
|
||||
int oaknode_node_context_count(OakNodeNode node, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The context node at `index` (borrowed handle; releasing it only
|
||||
* releases the handle). OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_node_context_node_at(OakNodeNode node, int index,
|
||||
OakNodeNode *out_node);
|
||||
|
||||
/**
|
||||
* @brief The node's position in `context` (any out pointer may be NULL).
|
||||
* OAKNODE_E_NOT_FOUND when the context does not contain this node.
|
||||
*/
|
||||
int oaknode_node_get_context_position(OakNodeNode node, OakNodeNode context,
|
||||
double *out_x, double *out_y,
|
||||
int *out_expanded);
|
||||
|
||||
/**
|
||||
* @brief Set the node's position in `context` directly (live,
|
||||
* Node::set_node_position_in_context() + set_node_expanded_in_context()).
|
||||
*/
|
||||
int oaknode_node_set_context_position(OakNodeNode node, OakNodeNode context,
|
||||
double x, double y, int expanded);
|
||||
|
||||
/**
|
||||
* @brief Create a set-position command (olive::NodeSetPositionCommand).
|
||||
*/
|
||||
int oaknode_node_set_context_position_undoable(OakNodeNode node,
|
||||
OakNodeNode context, double x,
|
||||
double y, int expanded,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Remove the node from `context` directly (live).
|
||||
* OAKNODE_E_NOT_FOUND when not contained.
|
||||
*/
|
||||
int oaknode_node_remove_from_context(OakNodeNode node, OakNodeNode context);
|
||||
|
||||
/* ---- Lifetime --------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Create a standalone copy of the node (Node::copy()). The copy is
|
||||
* NOT added to any graph; the returned handle has reference count 1 and
|
||||
* must be released with oaknode_node_free() while it is still orphaned.
|
||||
* Returns an empty handle (ctx == NULL) for an empty handle or on failure.
|
||||
*/
|
||||
OakNodeNode oaknode_node_create_copy(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Copy a node inside its graph (Node::copy_node_in_graph()),
|
||||
* recording the reconnect operations in a new MultiUndoCommand.
|
||||
*
|
||||
* `*out_command` receives an owned undo command handle (free with
|
||||
* oakundo_command_free()). The copy is inserted into the graph only when
|
||||
* the returned command is redone; treat it as owned (oaknode_node_free())
|
||||
* until then. Returns an empty handle (ctx == NULL) on failure.
|
||||
*/
|
||||
OakNodeNode oaknode_node_copy_in_graph(OakNodeNode node,
|
||||
OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Get the project this node belongs to. `out` receives a borrowed
|
||||
* handle (empty, ctx == NULL, if the node is orphaned; releasing it only
|
||||
* releases the handle).
|
||||
*/
|
||||
int oaknode_node_get_project(OakNodeNode node, OakNodeProject *out);
|
||||
|
||||
/**
|
||||
* @brief Insert/remove an element in an input array (live,
|
||||
* Node::input_array_insert/remove()). OAKNODE_E_NOT_FOUND for an
|
||||
* unknown input id.
|
||||
*/
|
||||
int oaknode_node_input_array_insert(OakNodeNode node, const char *input_id,
|
||||
int index);
|
||||
int oaknode_node_input_array_remove(OakNodeNode node, const char *input_id,
|
||||
int index);
|
||||
|
||||
/**
|
||||
* @brief Element-aware variants of oaknode_node_connect()/disconnect()
|
||||
* (NodeInput element != -1, e.g. Sequence's track_in_N array inputs).
|
||||
*/
|
||||
int oaknode_node_connect_element(OakNodeNode output_node,
|
||||
OakNodeNode input_node,
|
||||
const char *input_id, int element);
|
||||
int oaknode_node_disconnect_element(OakNodeNode input_node,
|
||||
const char *input_id, int element);
|
||||
|
||||
/**
|
||||
* @brief Create a command that adds a node to a project's graph
|
||||
* (olive::NodeAddCommand). Owned; free with oakundo_command_free().
|
||||
*/
|
||||
OakUndoCommand oaknode_command_create_add_node(OakNodeProject graph,
|
||||
OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Create a command that sets a node's position in a context and
|
||||
* repositions its dependencies recursively
|
||||
* (olive::NodeSetPositionAndDependenciesRecursivelyCommand). Owned.
|
||||
*/
|
||||
OakUndoCommand oaknode_command_create_set_position_recursive(
|
||||
OakNodeNode node, OakNodeNode context, double x, double y);
|
||||
|
||||
/**
|
||||
* @brief Marker list / work area of a viewer node, as addref'd
|
||||
* oaktimeline value handles (release with
|
||||
* oaktimeline_marker_list_free()/oaktimeline_workarea_free()). *out is
|
||||
* an empty handle (ctx == NULL) when the node is not a viewer or for
|
||||
* an empty node handle.
|
||||
*/
|
||||
int oaknode_node_get_markers(OakNodeNode node,
|
||||
struct OakTimelineMarkerList *out);
|
||||
int oaknode_node_get_work_area(OakNodeNode node,
|
||||
struct OakTimelineWorkArea *out);
|
||||
|
||||
/**
|
||||
* @brief Video frame cache of a node as an addref'd oakrender value
|
||||
* handle (release with oakrender_cache_free()). *out is an
|
||||
* empty handle (ctx == NULL) when the node has none or for an
|
||||
* empty node handle. struct OakRenderCache is forward-declared
|
||||
* here; include render/cache.h for the definition.
|
||||
*/
|
||||
int oaknode_node_get_video_frame_cache(OakNodeNode node,
|
||||
struct OakRenderCache *out);
|
||||
|
||||
/**
|
||||
* @brief Copy input values/connections from one node to another
|
||||
* (Node::copy_inputs()). include_connections != 0 also copies
|
||||
* input connections.
|
||||
*/
|
||||
int oaknode_node_copy_inputs(OakNodeNode dst, OakNodeNode src,
|
||||
int include_connections);
|
||||
|
||||
/**
|
||||
* @brief Set a track-routing value hint on an input
|
||||
* (Node::set_value_hint_for_input() with a single texture type
|
||||
* and a Track::Reference string).
|
||||
*/
|
||||
int oaknode_node_set_value_hint_track(OakNodeNode node, const char *input_id,
|
||||
int track_type, int track_index);
|
||||
|
||||
/**
|
||||
* @brief Set a viewer node's video/audio params (ViewerOutput::
|
||||
* set_video_params/set_audio_params, stream index 0). `params` is an
|
||||
* oakcommon handle (video) or borrowed oakcore handle (audio).
|
||||
*/
|
||||
int oaknode_viewer_set_video_params(OakNodeNode viewer,
|
||||
const OakVideoParams *params);
|
||||
int oaknode_viewer_set_audio_params(OakNodeNode viewer,
|
||||
const OakAudioParams *params);
|
||||
|
||||
/**
|
||||
* @brief Find a footage node upstream of this node's inputs
|
||||
* (Node::find_input_nodes<Footage>(), first match). `out` receives
|
||||
* a borrowed handle (empty, ctx == NULL, when none; releasing it
|
||||
* only releases the handle).
|
||||
*/
|
||||
int oaknode_node_find_input_footage(OakNodeNode node, OakNodeFootage *out);
|
||||
|
||||
/**
|
||||
* @brief Value of an input at a specific time (Node::get_value_at_time(),
|
||||
* element -1). Same POD rules as oaknode_node_get_input().
|
||||
*/
|
||||
int oaknode_node_get_input_at_time(OakNodeNode node,
|
||||
const char *input_id, int64_t time_num,
|
||||
int64_t time_den, oaknode_value *out);
|
||||
|
||||
/**
|
||||
* @brief Set an input's value at a specific time with keyframe logic
|
||||
* (Node::set_value_at_time(), element -1, track 0,
|
||||
* insert_on_all_tracks_if_no_key = true). `*out_command` receives
|
||||
* an owned undo command handle.
|
||||
*/
|
||||
int oaknode_node_set_input_at_time_undoable(OakNodeNode node,
|
||||
const char *input_id, int64_t time_num, int64_t time_den,
|
||||
const oaknode_value *v, int track, OakUndoCommand *out_command);
|
||||
|
||||
/**
|
||||
* @brief Identity of the underlying node object as an opaque integer
|
||||
* (address-cast; for registry keys only, never dereference).
|
||||
*/
|
||||
uintptr_t oaknode_node_identity(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Append a value-at-time set into an existing multi command
|
||||
* (same semantics as oaknode_node_set_input_at_time_undoable but
|
||||
* batches into `multi_command` from oakundo_command_init_multi()).
|
||||
*/
|
||||
int oaknode_node_set_input_at_time_into(OakNodeNode node,
|
||||
const char *input_id, int64_t time_num, int64_t time_den,
|
||||
const oaknode_value *v, int track, OakUndoCommand multi_command);
|
||||
|
||||
/**
|
||||
* @brief Create a command that removes a node from its graph together
|
||||
* with its exclusive dependencies and disconnects its edges
|
||||
* (NodeRemoveWithExclusiveDependenciesAndDisconnect).
|
||||
*
|
||||
* Owned command handle; free with oakundo_command_free(). Returns an
|
||||
* empty handle (ctx == NULL) on failure.
|
||||
*/
|
||||
OakUndoCommand oaknode_command_create_remove_node(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a node handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): the underlying
|
||||
* node is destroyed only when the last reference of an OWNED handle is
|
||||
* released; releasing a borrowed handle into a graph-owned object only
|
||||
* destroys the handle itself. NULL handle or NULL ctx is a no-op; clears
|
||||
* `node->ctx` after releasing.
|
||||
*/
|
||||
void oaknode_node_free(OakNodeNode *node);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_NODE_H
|
||||
@@ -0,0 +1,267 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_PROJECT_H
|
||||
#define OAK_EDITOR_NODE_PROJECT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file project.h
|
||||
* @brief C ABI for olive::Project (oaknode)
|
||||
*
|
||||
* An OakNodeProject owns its whole node graph: nodes added with
|
||||
* oaknode_project_add_node() (directly, or indirectly through the folder and
|
||||
* footage families) are deleted when the project's last reference is
|
||||
* released. Handles to nodes, folders and footage obtained from a project
|
||||
* are borrowed views: releasing them only releases the handle itself.
|
||||
*
|
||||
* Conventions (shared by all oaknode C API families):
|
||||
* - Return codes: 0 (OAKNODE_OK) on success, a negative OAKNODE_E_* code on
|
||||
* failure.
|
||||
* - String getters are two-stage: pass buf == NULL (or a short buffer) to
|
||||
* query the required size; the return value is the required buffer size in
|
||||
* bytes INCLUDING the terminating NUL. The output is NUL-terminated
|
||||
* whenever buf_size > 0.
|
||||
* - Empty handles (ctx == NULL) yield OAKNODE_E_INVALID (or a no-op for
|
||||
* free()).
|
||||
* - Disk save/load of project files is NOT part of this layer; it belongs to
|
||||
* oakstorage (milestone M10).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a project (olive::Project).
|
||||
*
|
||||
* Semantics are shared_ptr-like: oaknode_project_init() returns a handle
|
||||
* whose underlying object has reference count 1, addref(ctx) takes another
|
||||
* reference, and release(ctx) (or oaknode_project_free()) drops one; the
|
||||
* project and every node it owns are destroyed when the count reaches zero.
|
||||
*/
|
||||
typedef struct OakNodeProject {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeProject;
|
||||
|
||||
/**
|
||||
* @brief Node handle (defined by the node family; forward-declared
|
||||
* here so the headers can be included in any order).
|
||||
*/
|
||||
typedef struct OakNodeNode OakNodeNode;
|
||||
|
||||
/**
|
||||
* @brief Folder handle (defined in node/folder.h; forward-declared
|
||||
* here so the headers can be included in any order). Handles obtained from
|
||||
* a project are borrowed from it.
|
||||
*/
|
||||
typedef struct OakNodeFolder OakNodeFolder;
|
||||
|
||||
/**
|
||||
* @brief Create an empty project shell.
|
||||
*
|
||||
* The project has no root folder until oaknode_project_initialize() is
|
||||
* called (mirrors Project::initialize()).
|
||||
*
|
||||
* @return Project handle with reference count 1 (release with
|
||||
* oaknode_project_free()); ctx is NULL on allocation failure.
|
||||
*/
|
||||
OakNodeProject oaknode_project_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a project handle.
|
||||
*
|
||||
* Destroys the project and every node it owns when the count reaches zero.
|
||||
* NULL handle or NULL ctx is a no-op; clears `project->ctx` after releasing.
|
||||
*/
|
||||
void oaknode_project_free(OakNodeProject *project);
|
||||
|
||||
/**
|
||||
* @brief Initialize the project: create the root folder (Project::initialize()).
|
||||
*
|
||||
* @return OAKNODE_OK, or OAKNODE_E_STATE if already initialized.
|
||||
*/
|
||||
int oaknode_project_initialize(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Destructively destroy all nodes in the graph (Project::clear()).
|
||||
*
|
||||
* The project shell stays usable; oaknode_project_initialize() may be called
|
||||
* again afterwards.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_clear(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle of the project's root folder (Project::root()).
|
||||
*
|
||||
* The returned handle only releases the handle itself; the project owns the
|
||||
* folder. Empty handle (ctx == NULL) if the project has not been
|
||||
* initialized.
|
||||
*/
|
||||
OakNodeFolder oaknode_project_root(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Project display name (Project::name(): the filename's base name, or
|
||||
* "(untitled)"). Two-stage string getter.
|
||||
*
|
||||
* @return Required buffer size in bytes including the NUL, or a negative
|
||||
* OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_name(OakNodeProject project, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Full path the project was saved as, or "" if untitled
|
||||
* (Project::filename()). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_project_filename(OakNodeProject project, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Display name safe for window titles (Project::pretty_filename()).
|
||||
* Two-stage string getter.
|
||||
*/
|
||||
int oaknode_project_pretty_filename(OakNodeProject project, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set the project's filename (Project::set_filename()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_set_filename(OakNodeProject project, const char *filename);
|
||||
|
||||
/**
|
||||
* @brief 1 if the project has unsaved changes, 0 otherwise
|
||||
* (Project::is_modified()). Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_project_is_modified(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Set the modified flag (Project::set_modified()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_set_modified(OakNodeProject project, int modified);
|
||||
|
||||
/**
|
||||
* @brief 1 if the project is new (untitled and unmodified, Project::is_new()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_project_is_new(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Effective cache directory (Project::cache_path(), honoring the cache
|
||||
* location setting). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_project_cache_path(OakNodeProject project, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Copy all project settings (Project::copy_settings()).
|
||||
*/
|
||||
int oaknode_project_copy_settings(OakNodeProject dst,
|
||||
OakNodeProject src);
|
||||
|
||||
/**
|
||||
* @brief Cache location setting enum value
|
||||
* (Project::get_cache_location_setting(): 0 = default location,
|
||||
* 1 = alongside project, 2 = custom path). Negative OAKNODE_E_* code on an
|
||||
* empty handle.
|
||||
*/
|
||||
int oaknode_project_get_cache_location_setting(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Set the cache location setting (0/1/2, see
|
||||
* oaknode_project_get_cache_location_setting()).
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_set_cache_location_setting(OakNodeProject project,
|
||||
int setting);
|
||||
|
||||
/**
|
||||
* @brief Custom cache directory, or "" when none is set
|
||||
* (Project::get_custom_cache_path()). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_project_get_custom_cache_path(OakNodeProject project,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Set a custom cache directory (Project::set_custom_cache_path()).
|
||||
* NULL clears it.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_set_custom_cache_path(OakNodeProject project,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* @brief Project UUID string (Project::get_uuid()). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_project_get_uuid(OakNodeProject project, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Add a node to the graph; the graph assumes the node's lifetime
|
||||
* (Project::add_node()).
|
||||
*
|
||||
* After a successful call the graph owns the node: releasing `node` only
|
||||
* releases the handle itself.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_add_node(OakNodeProject project, OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Detach a node from the graph without deleting it
|
||||
* (Project::remove_node()).
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_NOT_FOUND if the node is not in the graph, or
|
||||
* another negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_project_remove_node(OakNodeProject project, OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Number of nodes belonging to the graph (Project::nodes().size()).
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_project_node_count(OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle of the graph node at `index`.
|
||||
*
|
||||
* The returned handle only releases the handle itself. Empty handle
|
||||
* (ctx == NULL) when out of range.
|
||||
*/
|
||||
OakNodeNode oaknode_project_node_at(OakNodeProject project, int index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_PROJECT_H
|
||||
@@ -0,0 +1,219 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_SEQUENCE_H
|
||||
#define OAK_EDITOR_NODE_SEQUENCE_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/videoparams.h"
|
||||
#include "node/error.h"
|
||||
#include "olive/core/oakcore/audioparams.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sequence texture/samples input ids (ViewerOutput::k_texture_input
|
||||
* / k_samples_input) and the track input id format
|
||||
* (Sequence::k_track_input_format). Pinned by test.
|
||||
*/
|
||||
#define OAKNODE_SEQUENCE_TEXTURE_INPUT "tex_in"
|
||||
#define OAKNODE_SEQUENCE_SAMPLES_INPUT "samples_in"
|
||||
#define OAKNODE_SEQUENCE_TRACK_INPUT_FORMAT "track_in_%1"
|
||||
|
||||
/* Re-declared here so sequence.h is self-contained; see node/node.h. */
|
||||
typedef struct OakNodeNode OakNodeNode;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a sequence (olive::Sequence).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* oaknode_sequence_create() returns a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero.
|
||||
*
|
||||
* Handles obtained from accessors (track lists, tracks) are borrowed:
|
||||
* releasing them does not destroy the underlying object, which stays
|
||||
* owned by the sequence graph.
|
||||
*/
|
||||
typedef struct OakNodeSequence {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeSequence;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a track list (olive::TrackList),
|
||||
* see node/track.h.
|
||||
*/
|
||||
typedef struct OakNodeTrackList OakNodeTrackList;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a track (olive::Track), see
|
||||
* node/track.h.
|
||||
*/
|
||||
typedef struct OakNodeTrack OakNodeTrack;
|
||||
|
||||
/**
|
||||
* @brief Create an empty sequence with zero tracks.
|
||||
*
|
||||
* @return Sequence handle with reference count 1 (release with
|
||||
* oaknode_sequence_free()); ctx is NULL on allocation failure.
|
||||
*/
|
||||
OakNodeSequence oaknode_sequence_create(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a sequence handle.
|
||||
*
|
||||
* Destroys the sequence (and its owned track lists) when the reference
|
||||
* count reaches zero. NULL handle or NULL ctx is a no-op; clears
|
||||
* `sequence->ctx` after releasing.
|
||||
*
|
||||
* Tracks and blocks connected to the sequence are owned by the graph and
|
||||
* are not deleted here; the caller must have torn them down first.
|
||||
*/
|
||||
void oaknode_sequence_free(OakNodeSequence *sequence);
|
||||
|
||||
/**
|
||||
* @brief Apply the default video/audio parameters
|
||||
* (ViewerOutput::set_default_parameters()).
|
||||
*/
|
||||
int oaknode_sequence_set_default_parameters(OakNodeSequence sequence);
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a sequence handle to its node handle.
|
||||
* Empty handle for an empty handle.
|
||||
*/
|
||||
OakNodeNode oaknode_sequence_as_node(OakNodeSequence sequence);
|
||||
|
||||
/**
|
||||
* @brief Non-owning cast from a node handle to a sequence handle (empty
|
||||
* ctx when the node is not a Sequence).
|
||||
*/
|
||||
OakNodeSequence oaknode_sequence_from_node(OakNodeNode node);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle to the per-type track list.
|
||||
*
|
||||
* @param type One of OAKNODE_TRACK_TYPE_VIDEO / _AUDIO / _SUBTITLE.
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_NOT_FOUND (bad type).
|
||||
*/
|
||||
int oaknode_sequence_get_track_list(OakNodeSequence sequence, int type,
|
||||
OakNodeTrackList *out);
|
||||
|
||||
/**
|
||||
* @brief Number of connected tracks of the given type.
|
||||
*/
|
||||
int oaknode_sequence_get_track_count(OakNodeSequence sequence, int type,
|
||||
int *count);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle to the track of `type` at `index`.
|
||||
*/
|
||||
int oaknode_sequence_get_track_at(OakNodeSequence sequence, int type,
|
||||
int index, OakNodeTrack *out);
|
||||
|
||||
/**
|
||||
* @brief Flat track cache across all types (olive::Sequence::get_tracks()).
|
||||
*/
|
||||
int oaknode_sequence_get_all_track_count(OakNodeSequence sequence, int *count);
|
||||
int oaknode_sequence_get_all_track_at(OakNodeSequence sequence, int index,
|
||||
OakNodeTrack *out);
|
||||
|
||||
/**
|
||||
* @brief Playhead position in sequence time.
|
||||
*/
|
||||
int oaknode_sequence_get_playhead(OakNodeSequence sequence, int *numerator,
|
||||
int *denominator);
|
||||
int oaknode_sequence_set_playhead(OakNodeSequence sequence, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Cached overall/video/audio lengths (olive::ViewerOutput).
|
||||
*/
|
||||
int oaknode_sequence_get_length(OakNodeSequence sequence, int *numerator,
|
||||
int *denominator);
|
||||
int oaknode_sequence_get_video_length(OakNodeSequence sequence,
|
||||
int *numerator, int *denominator);
|
||||
int oaknode_sequence_get_audio_length(OakNodeSequence sequence,
|
||||
int *numerator, int *denominator);
|
||||
|
||||
/**
|
||||
* @brief Recompute the cached lengths from the track lists
|
||||
* (olive::ViewerOutput::verify_length()).
|
||||
*/
|
||||
int oaknode_sequence_verify_length(OakNodeSequence sequence);
|
||||
|
||||
/* --------------------------------------------------- Video/audio params */
|
||||
|
||||
/**
|
||||
* @brief Number of video/audio parameter slots.
|
||||
*/
|
||||
int oaknode_sequence_get_video_stream_count(OakNodeSequence sequence,
|
||||
int *count);
|
||||
int oaknode_sequence_get_audio_stream_count(OakNodeSequence sequence,
|
||||
int *count);
|
||||
|
||||
/**
|
||||
* @brief Video parameters at `index` as a NEW by-value handle owned by
|
||||
* the caller (reference count 1, release with
|
||||
* oakcommon_videoparams_free()).
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID, OAKNODE_E_NOT_FOUND or
|
||||
* OAKNODE_E_NOMEM.
|
||||
*/
|
||||
int oaknode_sequence_get_video_params(OakNodeSequence sequence, int index,
|
||||
OakVideoParams *out);
|
||||
|
||||
/**
|
||||
* @brief Replace the video parameters at `index` with a copy of `params`.
|
||||
*
|
||||
* @return OAKNODE_E_INVALID if the sequence handle is empty, params.ctx is
|
||||
* NULL, or index is negative.
|
||||
*/
|
||||
int oaknode_sequence_set_video_params(OakNodeSequence sequence, int index,
|
||||
OakVideoParams params);
|
||||
|
||||
/**
|
||||
* @brief Audio parameters at `index` as a NEW handle owned by the caller
|
||||
* (release with oakcore_audioparams_free()).
|
||||
*/
|
||||
int oaknode_sequence_get_audio_params(OakNodeSequence sequence, int index,
|
||||
OakAudioParams **out);
|
||||
|
||||
/**
|
||||
* @brief Replace the audio parameters at `index` with a copy of `params`.
|
||||
*/
|
||||
int oaknode_sequence_set_audio_params(OakNodeSequence sequence, int index,
|
||||
const OakAudioParams *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_SEQUENCE_H
|
||||
@@ -0,0 +1,310 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_SERIALIZER_H
|
||||
#define OAK_EDITOR_NODE_SERIALIZER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
#include "node/project.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file serializer.h
|
||||
* @brief C ABI for olive::ProjectSerializer (oaknode), in-memory form
|
||||
*
|
||||
* Clipboard copy/paste and node-graph XML round trips without touching the
|
||||
* filesystem: "copy" is oaknode_serializer_save_to_xml() (serialize a
|
||||
* SaveData to an XML string), "paste" is oaknode_serializer_load_from_xml()
|
||||
* (parse an XML string into a project, exposing the resulting LoadData).
|
||||
* System-clipboard integration and on-disk .ove save/load live in the
|
||||
* facade / oakstorage layers (M9/M10), not here.
|
||||
*
|
||||
* oaknode_serializer_initialize() must be called before any save/load; it
|
||||
* registers the versioned serializers and the node factory the loaders use
|
||||
* to instantiate nodes by id.
|
||||
*/
|
||||
|
||||
/** @brief Load type: a whole project. */
|
||||
#define OAKNODE_SERIALIZER_LOAD_PROJECT 0
|
||||
/** @brief Load type: only nodes (clipboard node-graph paste). */
|
||||
#define OAKNODE_SERIALIZER_LOAD_ONLY_NODES 1
|
||||
/** @brief Load type: only clips (timeline family). */
|
||||
#define OAKNODE_SERIALIZER_LOAD_ONLY_CLIPS 2
|
||||
/** @brief Load type: only markers (timeline family). */
|
||||
#define OAKNODE_SERIALIZER_LOAD_ONLY_MARKERS 3
|
||||
/** @brief Load type: only keyframes (keyframe family). */
|
||||
#define OAKNODE_SERIALIZER_LOAD_ONLY_KEYFRAMES 4
|
||||
|
||||
/** @brief Serializer result code: success. */
|
||||
#define OAKNODE_SERIALIZER_OK 0
|
||||
/** @brief Serializer result code: data written by a too-old format. */
|
||||
#define OAKNODE_SERIALIZER_TOO_OLD 1
|
||||
/** @brief Serializer result code: data written by a too-new format. */
|
||||
#define OAKNODE_SERIALIZER_TOO_NEW 2
|
||||
/** @brief Serializer result code: unrecognizable format version. */
|
||||
#define OAKNODE_SERIALIZER_UNKNOWN_VERSION 3
|
||||
/** @brief Serializer result code: file I/O error (unused in-memory). */
|
||||
#define OAKNODE_SERIALIZER_FILE_ERROR 4
|
||||
/** @brief Serializer result code: XML parse error. */
|
||||
#define OAKNODE_SERIALIZER_XML_ERROR 5
|
||||
/** @brief Serializer result code: overwrite error (unused in-memory). */
|
||||
#define OAKNODE_SERIALIZER_OVERWRITE_ERROR 6
|
||||
/** @brief Serializer result code: no data to load. */
|
||||
#define OAKNODE_SERIALIZER_NO_DATA 7
|
||||
|
||||
/**
|
||||
* @brief Reference-counted save descriptor (wraps
|
||||
* olive::ProjectSerializer::SaveData).
|
||||
*
|
||||
* oaknode_serializer_savedata_create() returns a handle whose object has
|
||||
* reference count 1; release it with oaknode_serializer_savedata_free().
|
||||
*/
|
||||
typedef struct OakNodeSerializerSaveData {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeSerializerSaveData;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted load result (wraps
|
||||
* olive::ProjectSerializer::LoadData).
|
||||
*
|
||||
* The handle returned through oaknode_serializer_load_from_xml() has
|
||||
* reference count 1; release it with oaknode_serializer_loaddata_free().
|
||||
* Node handles obtained from it are borrowed from the target project.
|
||||
*/
|
||||
typedef struct OakNodeSerializerLoadData {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeSerializerLoadData;
|
||||
|
||||
/**
|
||||
* @brief Register the versioned serializers and initialize the node factory.
|
||||
* Idempotent. Must be called before any save/load.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_initialize(void);
|
||||
|
||||
/**
|
||||
* @brief Tear down the serializers and the node factory registered by
|
||||
* oaknode_serializer_initialize(). Safe to call when not initialized.
|
||||
*/
|
||||
void oaknode_serializer_shutdown(void);
|
||||
|
||||
/**
|
||||
* @brief Create a save descriptor.
|
||||
*
|
||||
* @param load_type One of OAKNODE_SERIALIZER_LOAD_*; use
|
||||
* OAKNODE_SERIALIZER_LOAD_ONLY_NODES for clipboard-style node copies.
|
||||
* @param project Context project (borrowed), may be an empty handle for
|
||||
* load types that do not require it.
|
||||
*
|
||||
* @return Save-data handle with reference count 1 (release with
|
||||
* oaknode_serializer_savedata_free()); ctx is NULL on failure.
|
||||
*/
|
||||
OakNodeSerializerSaveData oaknode_serializer_savedata_create(
|
||||
int load_type, OakNodeProject project);
|
||||
|
||||
/**
|
||||
* @brief Release the caller's reference to the save descriptor and null
|
||||
* out the handle. NULL and empty handles are a no-op; the object is
|
||||
* destroyed when its reference count reaches zero.
|
||||
*/
|
||||
void oaknode_serializer_savedata_free(OakNodeSerializerSaveData *save_data);
|
||||
|
||||
/**
|
||||
* @brief Restrict serialization to the given nodes
|
||||
* (SaveData::set_only_serialize_nodes()). `nodes` is an array of `count`
|
||||
* borrowed node handles.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_savedata_set_nodes(
|
||||
OakNodeSerializerSaveData save_data, const OakNodeNode *nodes, int count);
|
||||
|
||||
/**
|
||||
* @brief Attach a free-form (key, value) property to a node in the
|
||||
* serialized output (SaveData::set_properties()); used for graph positions
|
||||
* and clip metadata. Replaces the value if the (node, key) pair exists.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_savedata_set_property(
|
||||
OakNodeSerializerSaveData save_data, OakNodeNode node, const char *key,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Serialize to an in-memory XML document ("copy"). Two-stage string
|
||||
* getter: pass buf == NULL to query the size.
|
||||
*
|
||||
* @return Required buffer size in bytes including the NUL, or a negative
|
||||
* OAKNODE_E_* error code (OAKNODE_E_STATE if the serializers have
|
||||
* not been initialized).
|
||||
*/
|
||||
int oaknode_serializer_save_to_xml(OakNodeSerializerSaveData save_data,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Parse an in-memory XML document into `project` ("paste").
|
||||
*
|
||||
* @param project Target project (borrowed), may be an empty handle for
|
||||
* load types that do not attach nodes to a project.
|
||||
* @param xml Complete XML document text. Must not be NULL.
|
||||
* @param load_type One of OAKNODE_SERIALIZER_LOAD_*.
|
||||
* @param out_result Receives one of the OAKNODE_SERIALIZER_* result codes.
|
||||
* Must not be NULL.
|
||||
* @param out_load_data Receives the load result on OAKNODE_SERIALIZER_OK
|
||||
* (reference count 1, release with oaknode_serializer_loaddata_free();
|
||||
* may be NULL if the caller does not need it; receives an empty
|
||||
* handle on failure).
|
||||
* @param details_buf Optional human-readable error detail buffer
|
||||
* (two-stage convention is NOT used; truncation is silent). May be
|
||||
* NULL.
|
||||
* @param details_buf_size Size of details_buf.
|
||||
*
|
||||
* @return OAKNODE_OK if the call itself succeeded (inspect *out_result for
|
||||
* the serializer outcome), or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_load_from_xml(OakNodeProject project, const char *xml,
|
||||
int load_type, int *out_result,
|
||||
OakNodeSerializerLoadData *out_load_data,
|
||||
char *details_buf, int details_buf_size);
|
||||
|
||||
/**
|
||||
* @brief Release the caller's reference to the load result and null out
|
||||
* the handle. NULL and empty handles are a no-op.
|
||||
*
|
||||
* Does not delete the loaded nodes: they are newly created objects owned by
|
||||
* the CALLER until adopted into a project with oaknode_project_add_node()
|
||||
* (or attached under a folder); otherwise they leak.
|
||||
*/
|
||||
void oaknode_serializer_loaddata_free(OakNodeSerializerLoadData *load_data);
|
||||
|
||||
/**
|
||||
* @brief Number of nodes created by the load. Negative OAKNODE_E_* code on
|
||||
* an empty handle.
|
||||
*/
|
||||
int oaknode_serializer_loaddata_node_count(
|
||||
OakNodeSerializerLoadData load_data);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle of the loaded node at `index`, or an empty handle
|
||||
* when out of range.
|
||||
*/
|
||||
OakNodeNode oaknode_serializer_loaddata_node_at(
|
||||
OakNodeSerializerLoadData load_data, int index);
|
||||
|
||||
/**
|
||||
* @brief Look up a serialized property attached to a loaded node.
|
||||
* Two-stage string getter.
|
||||
*
|
||||
* @return Required buffer size in bytes including the NUL,
|
||||
* OAKNODE_E_NOT_FOUND if the (node, key) pair is absent, or another
|
||||
* negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_loaddata_get_property(
|
||||
OakNodeSerializerLoadData load_data, OakNodeNode node, const char *key,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Number of promised (deferred) connections in the load result.
|
||||
* Negative OAKNODE_E_* code on an empty handle.
|
||||
*/
|
||||
int oaknode_serializer_loaddata_connection_count(
|
||||
OakNodeSerializerLoadData load_data);
|
||||
|
||||
/**
|
||||
* @brief Read the promised connection at `index`.
|
||||
*
|
||||
* All output parameters except the input-id buffer are required;
|
||||
* `input_id_buf` follows the two-stage string convention inside a
|
||||
* fixed call: pass NULL/0 to skip copying the id.
|
||||
*
|
||||
* @param out_output_node Receives the output (source) node (borrowed).
|
||||
* @param out_input_node Receives the input (destination) node (borrowed).
|
||||
* @param input_id_buf Receives the input id string, may be NULL.
|
||||
* @param input_id_buf_size Size of input_id_buf.
|
||||
* @param out_element Receives the input element index.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_NOT_FOUND when out of range, or another
|
||||
* negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_serializer_loaddata_connection_at(
|
||||
OakNodeSerializerLoadData load_data, int index,
|
||||
OakNodeNode *out_output_node, OakNodeNode *out_input_node,
|
||||
char *input_id_buf, int input_id_buf_size, int *out_element);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_SERIALIZER_H
|
||||
|
||||
/**
|
||||
* @brief Result codes for file-level save/load (mirror
|
||||
* ProjectSerializer::ResultCode; pinned by test).
|
||||
*/
|
||||
enum OakNodeSerializerResultCode {
|
||||
OAKNODE_SERIALIZER_RESULT_SUCCESS = 0,
|
||||
OAKNODE_SERIALIZER_RESULT_PROJECT_TOO_OLD = 1,
|
||||
OAKNODE_SERIALIZER_RESULT_PROJECT_TOO_NEW = 2,
|
||||
OAKNODE_SERIALIZER_RESULT_UNKNOWN_VERSION = 3,
|
||||
OAKNODE_SERIALIZER_RESULT_FILE_ERROR = 4,
|
||||
OAKNODE_SERIALIZER_RESULT_XML_ERROR = 5,
|
||||
OAKNODE_SERIALIZER_RESULT_OVERWRITE_ERROR = 6,
|
||||
OAKNODE_SERIALIZER_RESULT_NO_DATA = 7
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Save a project to a file (ProjectSerializer::save(), project
|
||||
* type, optional OVEC compression). Layout data is not serialized
|
||||
* through this API (app-layer concern, see oakstorage/M10).
|
||||
*
|
||||
* @param out_code Receives an OakNodeSerializerResultCode (may be NULL).
|
||||
* @param details Optional two-stage buffer for the result details
|
||||
* string (e.g. the fallback filename on overwrite errors).
|
||||
* @return OAKNODE_OK when the result code is
|
||||
* OAKNODE_SERIALIZER_RESULT_SUCCESS, OAKNODE_E_FAILED otherwise
|
||||
* (details in out_code/details), OAKNODE_E_INVALID for empty
|
||||
* handles/NULL args.
|
||||
*/
|
||||
int oaknode_serializer_save_to_file(OakNodeProject project,
|
||||
const char *filename, int use_compression, int *out_code,
|
||||
char *details, int details_size);
|
||||
|
||||
/**
|
||||
* @brief Load a project from a file into `project`
|
||||
* (ProjectSerializer::load(), project type).
|
||||
*
|
||||
* Same return/out-param convention as oaknode_serializer_save_to_file().
|
||||
*/
|
||||
int oaknode_serializer_load_from_file(OakNodeProject project,
|
||||
const char *filename, int *out_code, char *details,
|
||||
int details_size);
|
||||
@@ -0,0 +1,355 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_TRACK_H
|
||||
#define OAK_EDITOR_NODE_TRACK_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a track (olive::Track).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* oaknode_track_create() returns a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero.
|
||||
*
|
||||
* Adding a track to a track list (oaknode_tracklist_add_track())
|
||||
* transfers ownership to the graph; handles obtained from accessors
|
||||
* (sequence/track-list lookups) are borrowed and never destroy the
|
||||
* underlying object.
|
||||
*/
|
||||
typedef struct OakNodeTrack {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeTrack;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a per-type track container
|
||||
* (olive::TrackList).
|
||||
*
|
||||
* Always borrowed from oaknode_sequence_get_track_list(); releasing the
|
||||
* handle never destroys the list, which stays owned by its sequence.
|
||||
*/
|
||||
typedef struct OakNodeTrackList {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeTrackList;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a block (olive::Block), see
|
||||
* node/block.h.
|
||||
*/
|
||||
typedef struct OakNodeBlock OakNodeBlock;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a sequence (olive::Sequence), see
|
||||
* node/sequence.h.
|
||||
*/
|
||||
typedef struct OakNodeSequence OakNodeSequence;
|
||||
|
||||
/**
|
||||
* @brief Track types, matching olive::Track::Type.
|
||||
*/
|
||||
enum OakNodeTrackType {
|
||||
OAKNODE_TRACK_TYPE_NONE = -1,
|
||||
OAKNODE_TRACK_TYPE_VIDEO = 0,
|
||||
OAKNODE_TRACK_TYPE_AUDIO = 1,
|
||||
OAKNODE_TRACK_TYPE_SUBTITLE = 2,
|
||||
OAKNODE_TRACK_TYPE_COUNT = 3
|
||||
};
|
||||
|
||||
/* Re-declared here so track.h is self-contained; see node/node.h. */
|
||||
typedef struct OakNodeNode OakNodeNode;
|
||||
|
||||
/**
|
||||
* @brief Borrowed cast from a track handle to its node handle.
|
||||
* Empty handle for an empty handle.
|
||||
*/
|
||||
OakNodeNode oaknode_track_as_node(OakNodeTrack track);
|
||||
|
||||
/* ---------------------------------------------------------------- Track */
|
||||
|
||||
/**
|
||||
* @brief Create a track of the given type (OakNodeTrackType value).
|
||||
*
|
||||
* The caller owns the track until it is added to a track list; a track
|
||||
* that was never added must be released with oaknode_track_free().
|
||||
*
|
||||
* @return Track handle with reference count 1; ctx is NULL on invalid
|
||||
* type / allocation failure.
|
||||
*/
|
||||
OakNodeTrack oaknode_track_create(int type);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a track handle.
|
||||
*
|
||||
* Destroys the track when the reference count reaches zero. NULL handle
|
||||
* or NULL ctx is a no-op; clears `track->ctx` after releasing.
|
||||
*
|
||||
* The track must have been removed from its track list first.
|
||||
*/
|
||||
void oaknode_track_free(OakNodeTrack *track);
|
||||
|
||||
/**
|
||||
* @brief Track type (OakNodeTrackType values).
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_track_get_type(OakNodeTrack track, int *type);
|
||||
int oaknode_track_set_type(OakNodeTrack track, int type);
|
||||
|
||||
/**
|
||||
* @brief Track height in internal units (olive::Track::get/set_track_height).
|
||||
*/
|
||||
int oaknode_track_get_height(OakNodeTrack track, double *height);
|
||||
int oaknode_track_set_height(OakNodeTrack track, double height);
|
||||
|
||||
/**
|
||||
* @brief Track height in pixels (converted through the default font height).
|
||||
*/
|
||||
int oaknode_track_get_height_in_pixels(OakNodeTrack track, int *height);
|
||||
int oaknode_track_set_height_in_pixels(OakNodeTrack track, int height);
|
||||
|
||||
/**
|
||||
* @brief Default / minimum track heights in pixels (static).
|
||||
*/
|
||||
int oaknode_track_get_default_height_in_pixels(void);
|
||||
int oaknode_track_get_minimum_height_in_pixels(void);
|
||||
|
||||
/**
|
||||
* @brief Index of the track inside its track list.
|
||||
*/
|
||||
int oaknode_track_get_index(OakNodeTrack track, int *index);
|
||||
int oaknode_track_set_index(OakNodeTrack track, int index);
|
||||
|
||||
/**
|
||||
* @brief Mute / lock flags.
|
||||
*/
|
||||
int oaknode_track_get_muted(OakNodeTrack track, int *muted);
|
||||
int oaknode_track_set_muted(OakNodeTrack track, int muted);
|
||||
int oaknode_track_get_locked(OakNodeTrack track, int *locked);
|
||||
int oaknode_track_set_locked(OakNodeTrack track, int locked);
|
||||
|
||||
/**
|
||||
* @brief Track reference as a (type, index) pair (olive::Track::Reference).
|
||||
*/
|
||||
int oaknode_track_get_reference(OakNodeTrack track, int *type, int *index);
|
||||
|
||||
/**
|
||||
* @brief Total length of the track (end of the last block).
|
||||
*/
|
||||
int oaknode_track_get_length(OakNodeTrack track, int *numerator,
|
||||
int *denominator);
|
||||
|
||||
/**
|
||||
* @brief Owning sequence as a borrowed handle (empty when trackless).
|
||||
*/
|
||||
int oaknode_track_get_sequence(OakNodeTrack track, OakNodeSequence *out);
|
||||
|
||||
/* ------------------------------------------------------- Track blocks */
|
||||
|
||||
/**
|
||||
* @brief Number of blocks on the track.
|
||||
*/
|
||||
int oaknode_track_get_block_count(OakNodeTrack track, int *count);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle to the block at `index`.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_track_get_block_at(OakNodeTrack track, int index,
|
||||
OakNodeBlock *out);
|
||||
|
||||
/**
|
||||
* @brief Append/prepend/insert primitives (olive::Track::*_block).
|
||||
*
|
||||
* The track takes over graph membership of the block; the block must have
|
||||
* a valid length before insertion.
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_track_append_block(OakNodeTrack track, OakNodeBlock block);
|
||||
int oaknode_track_prepend_block(OakNodeTrack track, OakNodeBlock block);
|
||||
int oaknode_track_insert_block_at_index(OakNodeTrack track,
|
||||
OakNodeBlock block, int index);
|
||||
int oaknode_track_insert_block_after(OakNodeTrack track, OakNodeBlock block,
|
||||
OakNodeBlock before);
|
||||
int oaknode_track_insert_block_before(OakNodeTrack track, OakNodeBlock block,
|
||||
OakNodeBlock after);
|
||||
|
||||
/**
|
||||
* @brief Remove `block` and shift all subsequent blocks earlier
|
||||
* (olive::Track::ripple_remove_block). The block is NOT deleted; ownership
|
||||
* returns to the caller.
|
||||
*/
|
||||
int oaknode_track_ripple_remove_block(OakNodeTrack track, OakNodeBlock block);
|
||||
|
||||
/**
|
||||
* @brief Replace `old_block` with `new_block`; both must have equal lengths.
|
||||
*/
|
||||
int oaknode_track_replace_block(OakNodeTrack track, OakNodeBlock old_block,
|
||||
OakNodeBlock new_block);
|
||||
|
||||
/**
|
||||
* @brief Index of `block` in the track's block array, or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_track_get_block_index(OakNodeTrack track, OakNodeBlock block,
|
||||
int *index);
|
||||
|
||||
/**
|
||||
* @brief Block strictly containing `time` (in < time < out), or
|
||||
* OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_track_get_block_containing_time(OakNodeTrack track, int numerator,
|
||||
int denominator,
|
||||
OakNodeBlock *out);
|
||||
|
||||
/**
|
||||
* @brief Block visible at `time` (in <= time < out), or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_track_get_visible_block_at_time(OakNodeTrack track, int numerator,
|
||||
int denominator,
|
||||
OakNodeBlock *out);
|
||||
|
||||
/**
|
||||
* @brief Whether the [in, out) range holds no block or only a gap
|
||||
* (olive::Track::is_range_free). `is_free` receives 1/0.
|
||||
*/
|
||||
int oaknode_track_is_range_free(OakNodeTrack track, int in_num, int in_den,
|
||||
int out_num, int out_den, int *is_free);
|
||||
|
||||
/* ------------------------------------------------------------ TrackList */
|
||||
|
||||
/**
|
||||
* @brief Track list type (OakNodeTrackType values).
|
||||
*/
|
||||
/**
|
||||
* @brief Nearest block lookups (Track::nearest_block_before_or_at /
|
||||
* nearest_block_after_or_at). *out is a borrowed handle (empty when none).
|
||||
*/
|
||||
int oaknode_track_get_nearest_block_before_or_at(OakNodeTrack track,
|
||||
int numerator, int denominator, OakNodeBlock *out);
|
||||
int oaknode_track_get_nearest_block_after_or_at(OakNodeTrack track,
|
||||
int numerator, int denominator, OakNodeBlock *out);
|
||||
|
||||
/**
|
||||
* @brief Borrowed sequence owning this track list.
|
||||
*/
|
||||
int oaknode_tracklist_get_sequence(OakNodeTrackList list,
|
||||
OakNodeSequence *out);
|
||||
|
||||
/**
|
||||
* @brief The list's track input id on the parent sequence
|
||||
* (e.g. "track_in_0"). Two-stage string getter.
|
||||
*/
|
||||
int oaknode_tracklist_get_track_input_id(OakNodeTrackList list,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Live input-array append/remove on the parent sequence for this
|
||||
* list's track input (TrackList::array_append/array_remove_last()).
|
||||
*/
|
||||
int oaknode_tracklist_array_append(OakNodeTrackList list);
|
||||
int oaknode_tracklist_array_remove_last(OakNodeTrackList list);
|
||||
|
||||
/**
|
||||
* @brief Map a cached track index to the input-array element index
|
||||
* (TrackList::get_array_index_from_cache_index()).
|
||||
*/
|
||||
int oaknode_tracklist_get_array_index_from_cache_index(
|
||||
OakNodeTrackList list, int cache_index, int *out_index);
|
||||
|
||||
int oaknode_tracklist_get_type(OakNodeTrackList list, int *type);
|
||||
|
||||
/**
|
||||
* @brief Number of connected tracks.
|
||||
*/
|
||||
int oaknode_tracklist_get_track_count(OakNodeTrackList list, int *count);
|
||||
|
||||
/**
|
||||
* @brief Borrowed handle to the track at `index`.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_tracklist_get_track_at(OakNodeTrackList list, int index,
|
||||
OakNodeTrack *out);
|
||||
|
||||
/**
|
||||
* @brief Combined length of the longest track in the list.
|
||||
*/
|
||||
int oaknode_tracklist_get_total_length(OakNodeTrackList list, int *numerator,
|
||||
int *denominator);
|
||||
|
||||
/**
|
||||
* @brief Size of the underlying input array (>= track count; may contain
|
||||
* disconnected slots).
|
||||
*/
|
||||
int oaknode_tracklist_get_array_size(OakNodeTrackList list, int *size);
|
||||
|
||||
/**
|
||||
* @brief Add `track` to the list (non-undoable primitive).
|
||||
*
|
||||
* Mirrors the graph steps of TimelineAddTrackCommand::redo() minus the
|
||||
* auto-merge: the track is parented to the list's graph (when any),
|
||||
* inherits the previous track's height, a new array slot is appended and
|
||||
* the track is connected to it. The sequence's flat track cache and
|
||||
* lengths are refreshed before returning.
|
||||
*
|
||||
* The list takes ownership of the track on success; the caller's handle
|
||||
* becomes a non-owning reference.
|
||||
*
|
||||
* @return OAKNODE_OK or OAKNODE_E_INVALID.
|
||||
*/
|
||||
int oaknode_tracklist_add_track(OakNodeTrackList list, OakNodeTrack track);
|
||||
|
||||
/**
|
||||
* @brief Remove `track` from the list (non-undoable primitive).
|
||||
*
|
||||
* Disconnects the track from its array slot and removes the slot
|
||||
* (Node::input_array_remove). The track is NOT deleted; ownership returns
|
||||
* to the caller.
|
||||
*
|
||||
* @return OAKNODE_OK, OAKNODE_E_INVALID or OAKNODE_E_NOT_FOUND.
|
||||
*/
|
||||
int oaknode_tracklist_remove_track(OakNodeTrackList list,
|
||||
OakNodeTrack track);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_TRACK_H
|
||||
@@ -0,0 +1,154 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_NODE_TRAVERSER_H
|
||||
#define OAK_EDITOR_NODE_TRAVERSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/error.h"
|
||||
#include "node/node.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file traverser.h
|
||||
* @brief C ABI for olive::NodeTraverser (src/node/src/traverser.h),
|
||||
* limited to database generation: generating the value database of a node
|
||||
* over a time range and enumerating its rows.
|
||||
*
|
||||
* The base NodeTraverser resolves no render jobs (textures/samples stay
|
||||
* dummy); only value-producing nodes are meaningful here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a traverser (olive::NodeTraverser).
|
||||
*
|
||||
* Semantics are shared_ptr-like: oaknode_traverser_init() returns a
|
||||
* handle with count 1, addref(ctx) takes another reference, release(ctx)
|
||||
* drops one and the library destroys the object when the count reaches
|
||||
* zero.
|
||||
*/
|
||||
typedef struct OakNodeTraverser {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeTraverser;
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to an owned copy of an
|
||||
* olive::NodeValueDatabase. Same reference-counting rules as
|
||||
* OakNodeTraverser; release with oaknode_traverser_database_free().
|
||||
*/
|
||||
typedef struct OakNodeValueDatabase {
|
||||
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; /**< OAKNODE_ABI_VERSION. */
|
||||
} OakNodeValueDatabase;
|
||||
|
||||
/**
|
||||
* @brief Create a traverser.
|
||||
*
|
||||
* @return Traverser handle with count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakNodeTraverser oaknode_traverser_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a traverser handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* traverser when the count reaches zero. NULL handle or NULL ctx is a
|
||||
* no-op; clears `traverser->ctx` after releasing.
|
||||
*/
|
||||
void oaknode_traverser_free(OakNodeTraverser *traverser);
|
||||
|
||||
/**
|
||||
* @brief Generate the value database of `node` over the time range
|
||||
* [`in_num`/`in_den`, `out_num`/`out_den`) seconds
|
||||
* (NodeTraverser::generate_database()).
|
||||
*
|
||||
* `out_db` receives an owned database handle with count 1.
|
||||
*
|
||||
* @return OAKNODE_OK or a negative OAKNODE_E_* error code.
|
||||
*/
|
||||
int oaknode_traverser_generate_database(OakNodeTraverser traverser,
|
||||
OakNodeNode node, int64_t in_num,
|
||||
int64_t in_den, int64_t out_num,
|
||||
int64_t out_den,
|
||||
OakNodeValueDatabase *out_db);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a database handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* database when the count reaches zero. NULL handle or NULL ctx is a
|
||||
* no-op; clears `db->ctx` after releasing.
|
||||
*/
|
||||
void oaknode_traverser_database_free(OakNodeValueDatabase *db);
|
||||
|
||||
/**
|
||||
* @brief Number of rows (input tables) in the database.
|
||||
*/
|
||||
int oaknode_traverser_database_row_count(OakNodeValueDatabase db,
|
||||
int *out_count);
|
||||
|
||||
/**
|
||||
* @brief The input id (key) of the row at `index`. Two-stage getter;
|
||||
* OAKNODE_E_NOT_FOUND for an out-of-range index.
|
||||
*/
|
||||
int oaknode_traverser_database_row_key_at(OakNodeValueDatabase db,
|
||||
int index, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Number of values in the row named `key`.
|
||||
* OAKNODE_E_NOT_FOUND for an unknown key.
|
||||
*/
|
||||
int oaknode_traverser_database_row_value_count(OakNodeValueDatabase db,
|
||||
const char *key,
|
||||
int *out_count);
|
||||
|
||||
/**
|
||||
* @brief Read the value at `index` of row `key` mapped into `out`.
|
||||
* Values without a POD representation fail with OAKNODE_E_FAILED;
|
||||
* OAKNODE_E_NOT_FOUND for an unknown key or out-of-range index.
|
||||
*/
|
||||
int oaknode_traverser_database_value_at(OakNodeValueDatabase db,
|
||||
const char *key, int index,
|
||||
oaknode_value *out);
|
||||
|
||||
/**
|
||||
* @brief Read the value at `index` of row `key` as a string
|
||||
* (NodeValue::value_to_string()). Two-stage getter;
|
||||
* OAKNODE_E_NOT_FOUND for an unknown key or out-of-range index.
|
||||
*/
|
||||
int oaknode_traverser_database_value_string_at(OakNodeValueDatabase db,
|
||||
const char *key, int index,
|
||||
char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_NODE_TRAVERSER_H
|
||||
@@ -0,0 +1,40 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_PLUGIN_ERROR_H
|
||||
#define OAK_EDITOR_PLUGIN_ERROR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakplugin C API families.
|
||||
*/
|
||||
#define OAKPLUGIN_OK 0 /**< Success. */
|
||||
#define OAKPLUGIN_E_INVALID (-90001) /**< NULL handle or invalid argument. */
|
||||
#define OAKPLUGIN_E_STATE (-90002) /**< Call not valid in the current state. */
|
||||
#define OAKPLUGIN_E_FAILED (-90003) /**< The underlying operation failed. */
|
||||
#define OAKPLUGIN_E_NOT_FOUND (-90004) /**< Entry not found. */
|
||||
#define OAKPLUGIN_E_NOMEM (-90005) /**< Allocation failed. */
|
||||
#define OAKPLUGIN_E_CANCELLED (-90006) /**< The operation was cancelled. */
|
||||
|
||||
/** @brief ABI version stamped into every oakplugin handle. */
|
||||
#define OAKPLUGIN_ABI_VERSION 1
|
||||
|
||||
#endif //OAK_EDITOR_PLUGIN_ERROR_H
|
||||
@@ -0,0 +1,69 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_PLUGIN_HOST_H
|
||||
#define OAK_EDITOR_PLUGIN_HOST_H
|
||||
|
||||
#include "plugin/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialize the OFX host (olive::plugin::load_plugins() with the
|
||||
* default search paths). Idempotent.
|
||||
*/
|
||||
int oakplugin_host_init(void);
|
||||
|
||||
/** @brief Shut the host down (persistent messages cleared). */
|
||||
void oakplugin_host_shutdown(void);
|
||||
|
||||
/** @brief Scan additional bundle directories. */
|
||||
int oakplugin_host_scan(const char *const *bundle_dirs, int dir_count);
|
||||
|
||||
/** @brief Number of discovered plugins (>= 0), or a negative error. */
|
||||
int oakplugin_host_plugin_count(void);
|
||||
|
||||
/** @brief Plugin identifier at index (two-stage string getter). */
|
||||
int oakplugin_host_plugin_id_at(int index, char *buf, int buf_size);
|
||||
|
||||
/** @brief Plugin label for an identifier (two-stage; currently the
|
||||
* identifier itself). OAKPLUGIN_E_NOT_FOUND for unknown ids. */
|
||||
int oakplugin_host_plugin_label(const char *plugin_id, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief UI message handler for OFX host messages (question replies use
|
||||
* OAKPLUGIN_MESSAGE_ANSWER_YES/NO). Without a handler, messages
|
||||
* are logged and questions get "no".
|
||||
*/
|
||||
#define OAKPLUGIN_MESSAGE_ANSWER_NO 0
|
||||
#define OAKPLUGIN_MESSAGE_ANSWER_YES 1
|
||||
typedef int (*oakplugin_message_fn)(const char *type, const char *message,
|
||||
void *userdata);
|
||||
void oakplugin_host_set_message_handler(oakplugin_message_fn fn,
|
||||
void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_PLUGIN_HOST_H
|
||||
@@ -0,0 +1,171 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_PLUGIN_INSTANCE_H
|
||||
#define OAK_EDITOR_PLUGIN_INSTANCE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "node/node.h"
|
||||
#include "plugin/error.h"
|
||||
#include "render/renderer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to an OFX plugin instance
|
||||
* (olive::plugin::OlivePluginInstance).
|
||||
*
|
||||
* Ownership/count semantics follow include/common/handle.h: create
|
||||
* returns count 1, addref/release adjust it, release destroys at zero.
|
||||
*/
|
||||
typedef struct OakPluginInstance {
|
||||
void *ctx;
|
||||
void (*addref)(void *ctx);
|
||||
void (*release)(void *ctx);
|
||||
uint32_t abi_version; /**< OAKPLUGIN_ABI_VERSION. */
|
||||
} OakPluginInstance;
|
||||
|
||||
/**
|
||||
* @brief Create an instance of a discovered plugin (filter context).
|
||||
* Returns an empty handle (ctx == NULL) for unknown ids/failure.
|
||||
*/
|
||||
OakPluginInstance oakplugin_instance_create(const char *plugin_id);
|
||||
|
||||
/** @brief Release one reference. NULL/empty no-op; clears ctx. */
|
||||
void oakplugin_instance_free(OakPluginInstance *instance);
|
||||
|
||||
/**
|
||||
* @brief Set/get a parameter as an oaknode_value POD (type rules from
|
||||
* node/node.h). String-typed params use
|
||||
* oakplugin_instance_set_param_string()/get_param_string().
|
||||
*/
|
||||
int oakplugin_instance_set_param(OakPluginInstance instance,
|
||||
const char *param_id,
|
||||
const oaknode_value *value);
|
||||
int oakplugin_instance_get_param(OakPluginInstance instance,
|
||||
const char *param_id, oaknode_value *out);
|
||||
int oakplugin_instance_set_param_string(OakPluginInstance instance,
|
||||
const char *param_id,
|
||||
const char *value);
|
||||
int oakplugin_instance_get_param_string(OakPluginInstance instance,
|
||||
const char *param_id, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Render one frame through the instance (renderAction).
|
||||
*
|
||||
* `src` may be an empty handle for generator plugins. Textures stay
|
||||
* owned by the caller (borrowed for the call).
|
||||
*/
|
||||
int oakplugin_instance_render(OakPluginInstance instance,
|
||||
OakRenderTexture dst, OakRenderTexture src,
|
||||
double time_seconds);
|
||||
|
||||
/**
|
||||
* @brief Progress callback for long renders (async return channel,
|
||||
* 01 §4 exception). Return non-zero to abort processing.
|
||||
*/
|
||||
typedef int (*oakplugin_progress_fn)(double progress, void *userdata);
|
||||
int oakplugin_instance_set_progress_cb(OakPluginInstance instance,
|
||||
oakplugin_progress_fn fn,
|
||||
void *userdata);
|
||||
|
||||
/** @brief Cancel any in-progress render/progress reporting. */
|
||||
int oakplugin_instance_cancel(OakPluginInstance instance);
|
||||
|
||||
/** @brief Alive-count for leak assertions in tests. */
|
||||
int oakplugin_debug_alive_count(void);
|
||||
|
||||
/*
|
||||
* M11 §4(GL 路径 + render 驱动收编)新增声明。既有签名不变。
|
||||
*
|
||||
* oakrender 的 PluginJob 经本组入口把整帧渲染流程(RoI/RoD、
|
||||
* 多输入收集、isIdentity 短路、参数覆盖、CPU/GL 渲染与输出装配)
|
||||
* 委托给 oakplugin 的 render 驱动(Rust 侧 render_driver 模块,
|
||||
* 语义对照 src/render/src/plugin/pluginrenderer.cpp)。
|
||||
*/
|
||||
|
||||
/** @brief 一帧渲染任务的参数覆盖条目(参数名 → oaknode_value POD;
|
||||
* 字符串参数走 oakplugin_instance_set_param_string)。 */
|
||||
typedef struct oakplugin_job_value {
|
||||
const char *key;
|
||||
oaknode_value value;
|
||||
} oakplugin_job_value;
|
||||
|
||||
/** @brief 一帧渲染任务的输入 clip 纹理条目。纹理为借用句柄
|
||||
* (job 内有效)。 */
|
||||
typedef struct oakplugin_job_texture {
|
||||
const char *clip;
|
||||
OakRenderTexture texture;
|
||||
} oakplugin_job_texture;
|
||||
|
||||
/**
|
||||
* @brief beginSequenceRender 括号。oakrender 对同一实例的一批帧先
|
||||
* begin 后 end,中间逐帧 oakplugin_instance_render_job
|
||||
* (OFX:render action 由 begin/end sequence render 括号包围)。
|
||||
* `interactive` 为信息性标记(Phase 2 不传入 action)。
|
||||
*/
|
||||
int oakplugin_instance_render_begin_sequence(OakPluginInstance instance,
|
||||
double start_time,
|
||||
double end_time,
|
||||
int interactive);
|
||||
|
||||
/** @brief endSequenceRender 括号(与 render_begin_sequence 配对)。 */
|
||||
int oakplugin_instance_render_end_sequence(OakPluginInstance instance,
|
||||
double start_time,
|
||||
double end_time,
|
||||
int interactive);
|
||||
|
||||
/**
|
||||
* @brief 一帧渲染的单一 C ABI 调用(PluginJob 的载体)。
|
||||
*
|
||||
* @param dst 目标纹理(oakrender 创建)。GL 模式下调用方须先把
|
||||
* dst 附着为渲染器输出目标并保持 GL 上下文 current
|
||||
* (OFX "OpenGL Current Context" 规则;等价 C++
|
||||
* PluginRenderer::attach_output_texture)。
|
||||
* @param src 主输入纹理(effect_input_id / SimpleSource;可空句柄)。
|
||||
* @param effect_input_id job.src 落点的 clip 名(可 NULL)。
|
||||
* @param inputs / input_count 其余输入 clip 的纹理表。
|
||||
* @param values / value_count 参数覆盖表。
|
||||
* @param renderer GL 渲染器(空句柄 → CPU 路径)。
|
||||
* @param clear_destination / interactive 信息性标记(Phase 2,
|
||||
* render 驱动暂不处理;上层渲染器负责目标清空)。
|
||||
*/
|
||||
int oakplugin_instance_render_job(OakPluginInstance instance,
|
||||
OakRenderTexture dst,
|
||||
double time_seconds,
|
||||
int clear_destination,
|
||||
int interactive,
|
||||
const char *effect_input_id,
|
||||
OakRenderTexture src,
|
||||
const oakplugin_job_texture *inputs,
|
||||
int input_count,
|
||||
const oakplugin_job_value *values,
|
||||
int value_count,
|
||||
OakRenderRenderer renderer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_PLUGIN_INSTANCE_H
|
||||
@@ -0,0 +1,315 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_CACHE_H
|
||||
#define OAK_EDITOR_RENDER_CACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Same-dir quoted includes: inside this build the engine-style spelling
|
||||
// "render/renderer.h" resolves to the transition bridge headers, so the
|
||||
// public headers reference each other relative to their own directory.
|
||||
#include "error.h"
|
||||
#include "renderer.h" /* OakCodecFrame */
|
||||
#include "node/node.h" /* OakNodeNode */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file cache.h
|
||||
* @brief C ABI for the oakrender playback/frame-hash caches
|
||||
* (olive::PlaybackCache / olive::FrameHashCache), M7 §2.2.
|
||||
*
|
||||
* 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
|
||||
* treats timestamps as whole seconds.
|
||||
*
|
||||
* No cache events cross the boundary (M7 §2.2, 2026-08 revision):
|
||||
* invalidate/validate are triggered by and known to the caller; the
|
||||
* facade re-emits notifications after the triggering command.
|
||||
*/
|
||||
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 with reference count 1; ctx is NULL on
|
||||
* allocation failure.
|
||||
*/
|
||||
OakRenderCache oakrender_cache_create(void);
|
||||
|
||||
/**
|
||||
* @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 Cache flavours owned by a node
|
||||
* (olive::Node's video/thumbnail/audio/waveform caches).
|
||||
*/
|
||||
enum OakRenderCacheKind {
|
||||
OAKRENDER_CACHE_VIDEO_FRAME = 0, /**< olive::FrameHashCache */
|
||||
OAKRENDER_CACHE_THUMBNAIL = 1, /**< olive::ThumbnailCache */
|
||||
OAKRENDER_CACHE_AUDIO_PLAYBACK = 2, /**< olive::AudioPlaybackCache */
|
||||
OAKRENDER_CACHE_AUDIO_WAVEFORM = 3 /**< olive::AudioWaveformCache */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a cache of the given kind with a parent node (the
|
||||
* native back-pointer stays inside oakrender; it is used for
|
||||
* project cache-path resolution and job bookkeeping only).
|
||||
*
|
||||
* Owned by the caller (reference count 1); release with
|
||||
* oakrender_cache_free(). Empty handle for an empty parent handle, an
|
||||
* unknown kind, or on allocation failure.
|
||||
*/
|
||||
OakRenderCache oakrender_cache_create_for_node(OakNodeNode parent,
|
||||
int kind);
|
||||
|
||||
/**
|
||||
* @brief Cache UUID as canonical text, two-stage
|
||||
* (PlaybackCache::get_uuid()).
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKRENDER_E_* code for an empty cache.
|
||||
*/
|
||||
int oakrender_cache_get_uuid(OakRenderCache cache, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Request caching of a time range on behalf of a viewer
|
||||
* (PlaybackCache::request()).
|
||||
*
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for an empty cache /
|
||||
* context handle or a context that is not a viewer.
|
||||
*/
|
||||
int oakrender_cache_request(OakRenderCache cache, OakNodeNode context,
|
||||
int64_t in_num, int64_t in_den,
|
||||
int64_t out_num, int64_t out_den);
|
||||
|
||||
/**
|
||||
* @brief Load/save the cache's on-disk state (PlaybackCache::load_state()
|
||||
* / save_state()). OAKRENDER_E_INVALID for an empty cache.
|
||||
*/
|
||||
int oakrender_cache_load_state(OakRenderCache cache);
|
||||
int oakrender_cache_save_state(OakRenderCache cache);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable persisting this cache
|
||||
* (PlaybackCache::set_saving_enabled()).
|
||||
*/
|
||||
int oakrender_cache_set_saving_enabled(OakRenderCache cache, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Pass this cache's ranges through to another cache
|
||||
* (PlaybackCache::set_passthrough()). OAKRENDER_E_INVALID for an
|
||||
* empty cache or an empty `other`.
|
||||
*/
|
||||
int oakrender_cache_set_passthrough(OakRenderCache cache,
|
||||
OakRenderCache other);
|
||||
|
||||
/**
|
||||
* @brief The on-disk filename for the frame at a time
|
||||
* (FrameHashCache::get_valid_cache_filename()), two-stage.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKRENDER_E_* code (OAKRENDER_E_INVALID when the cache is not
|
||||
* a frame hash cache).
|
||||
*/
|
||||
int oakrender_cache_get_valid_cache_filename(OakRenderCache cache,
|
||||
int64_t time_num,
|
||||
int64_t time_den, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The passthrough ranges as flat {in_n, in_d, out_n, out_d}
|
||||
* quadruples (PlaybackCache::get_passthroughs(); only the ranges
|
||||
* cross the boundary, the per-range cache UUID text stays
|
||||
* internal).
|
||||
*
|
||||
* Two-stage: call with ranges == NULL (or max_ranges == 0) to get the
|
||||
* count; then call with a buffer of max_ranges * 4 int64_t values.
|
||||
*
|
||||
* @return Range count (>= 0), or a negative OAKRENDER_E_* code.
|
||||
*/
|
||||
int oakrender_cache_get_passthroughs(OakRenderCache cache, int64_t *ranges,
|
||||
int max_ranges);
|
||||
|
||||
/**
|
||||
* @brief The cache's frame timebase (FrameHashCache::get_timebase()).
|
||||
* Out params may individually be NULL. OAKRENDER_E_INVALID for
|
||||
* an empty cache or a non-frame-hash cache.
|
||||
*/
|
||||
int oakrender_cache_get_timebase(OakRenderCache cache, int *num,
|
||||
int *den);
|
||||
|
||||
/**
|
||||
* @brief Lock/unlock the cache's internal mutex (PlaybackCache::mutex()).
|
||||
* Empty cache is a no-op. Always pair the calls.
|
||||
*/
|
||||
void oakrender_cache_lock(OakRenderCache cache);
|
||||
void oakrender_cache_unlock(OakRenderCache cache);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
namespace olive { class PlaybackCache; }
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Borrowed access to the underlying C++ cache (C++ only, for
|
||||
* oakrender-internal adapters such as PreviewAutoCacher). Valid
|
||||
* while the handle is held. NULL-safe.
|
||||
*/
|
||||
olive::PlaybackCache *oakrender_cache_get_native(OakRenderCache 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 an empty cache or
|
||||
* non-positive num/den.
|
||||
*/
|
||||
int oakrender_cache_set_timebase(OakRenderCache cache, int num, int den);
|
||||
|
||||
/**
|
||||
* @brief Set the cache UUID used in on-disk frame cache filenames
|
||||
* (PlaybackCache::set_uuid()).
|
||||
*
|
||||
* @return OAKRENDER_OK or OAKRENDER_E_INVALID.
|
||||
*/
|
||||
int oakrender_cache_set_uuid(OakRenderCache cache, const char *uuid);
|
||||
|
||||
/**
|
||||
* @brief Mark the timestamp range [in_ts, out_ts) invalidated
|
||||
* (PlaybackCache::invalidate()). Empty cache is a no-op.
|
||||
*/
|
||||
void oakrender_cache_invalidate(OakRenderCache cache, int64_t in_ts,
|
||||
int64_t out_ts);
|
||||
|
||||
/**
|
||||
* @brief Mark a rational time range invalidated
|
||||
* (PlaybackCache::invalidate(TimeRange)). Empty cache is a no-op.
|
||||
*/
|
||||
void oakrender_cache_invalidate_range(OakRenderCache cache,
|
||||
int64_t in_num, int64_t in_den,
|
||||
int64_t out_num, int64_t out_den);
|
||||
|
||||
/**
|
||||
* @brief Mark the timestamp range [in_ts, out_ts) validated
|
||||
* (PlaybackCache::validate()). Empty cache is a no-op.
|
||||
*/
|
||||
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 / empty.
|
||||
*/
|
||||
int oakrender_cache_has_validated_ranges(OakRenderCache cache);
|
||||
|
||||
/**
|
||||
* @brief Timeline cache indicator height in pixels
|
||||
* (PlaybackCache::get_cache_indicator_height()). Constant query.
|
||||
*/
|
||||
int oakrender_cache_indicator_height(void);
|
||||
|
||||
/**
|
||||
* @brief The invalidated sub-ranges of [in, out) as flat
|
||||
* {in_n, in_d, out_n, out_d} quadruples
|
||||
* (PlaybackCache::get_invalidated_ranges()).
|
||||
*
|
||||
* Two-stage: call with ranges == NULL (or max_ranges == 0) to get the
|
||||
* count; then call with a buffer of max_ranges * 4 int64_t values.
|
||||
*
|
||||
* @return Range count (>= 0), or a negative OAKRENDER_E_* code.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Load a cached frame from disk
|
||||
* (FrameHashCache::load_cache_frame(cache_path, uuid, ts)).
|
||||
*
|
||||
* @param path Cache directory (e.g. oakrender_disk_cache_path()).
|
||||
* @param uuid Cache UUID of the producing node.
|
||||
* @param out_frame Receives an owned frame handle (release with
|
||||
* oakrender_codec_frame_free()).
|
||||
*
|
||||
* @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,
|
||||
const char *uuid, int64_t ts,
|
||||
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()).
|
||||
* Empty/NULL arguments are a no-op.
|
||||
*/
|
||||
void oakrender_frame_cache_save(OakRenderCache cache, const char *path,
|
||||
const char *uuid, OakCodecFrame frame);
|
||||
|
||||
/* ---- Debug --------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Number of live oakrender-owned objects (caches, textures,
|
||||
* frames, color processors) for leak assertions in tests.
|
||||
*/
|
||||
int oakrender_debug_alive_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_CACHE_H
|
||||
@@ -0,0 +1,120 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_CANCELATOM_H
|
||||
#define OAK_EDITOR_RENDER_CANCELATOM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
namespace olive { class CancelAtom; }
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file cancelatom.h
|
||||
* @brief C ABI for the oakrender cancellation primitive
|
||||
* (olive::CancelAtom), a thread-safe cancel flag shared between a
|
||||
* render/encode caller and its worker.
|
||||
*
|
||||
* OakCancelAtom follows the neutral by-value handle convention (see
|
||||
* oakcommon's common/handle.h): oakrender_cancelatom_init() returns a
|
||||
* handle whose underlying object has reference count 1, the addref and
|
||||
* release function pointers adjust that count atomically (release
|
||||
* destroys the object at zero), and abi_version is always
|
||||
* OAKRENDER_ABI_VERSION. Copying the struct copies the pointer, not the
|
||||
* count: call addref for every additional long-lived copy and release (or
|
||||
* oakrender_cancelatom_free()) when done with each copy. Functions that
|
||||
* only use a handle take it BY VALUE; an empty handle (ctx == NULL) is
|
||||
* reported as OAKRENDER_E_INVALID.
|
||||
*/
|
||||
typedef struct OakCancelAtom {
|
||||
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. */
|
||||
} OakCancelAtom;
|
||||
|
||||
/**
|
||||
* @brief Create a cancellation atom in the not-cancelled state.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakCancelAtom oakrender_cancelatom_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a cancellation atom.
|
||||
*
|
||||
* Convenience wrapper around atom->release(atom->ctx): decrements the
|
||||
* atomic reference count and destroys the object when it reaches zero,
|
||||
* then nulls atom->ctx. No-op when atom is NULL or atom->ctx is NULL.
|
||||
*/
|
||||
void oakrender_cancelatom_free(OakCancelAtom *atom);
|
||||
|
||||
/**
|
||||
* @brief Set the cancel flag (CancelAtom::cancel()). Thread-safe.
|
||||
*
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for an empty handle.
|
||||
*/
|
||||
int oakrender_cancelatom_cancel(OakCancelAtom atom);
|
||||
|
||||
/**
|
||||
* @brief Read the cancel flag (CancelAtom::is_cancelled()).
|
||||
*
|
||||
* Reading a set flag also records that a consumer heard the
|
||||
* cancellation; see oakrender_cancelatom_heard_cancel().
|
||||
*
|
||||
* @param cancelled Receives 1 when cancelled, 0 otherwise.
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for an empty handle or a
|
||||
* NULL out parameter.
|
||||
*/
|
||||
int oakrender_cancelatom_is_cancelled(OakCancelAtom atom, int *cancelled);
|
||||
|
||||
/**
|
||||
* @brief Whether any consumer has observed the cancel flag through
|
||||
* oakrender_cancelatom_is_cancelled() (CancelAtom::heard_cancel()).
|
||||
*
|
||||
* @param heard Receives 1 when the cancellation was heard, 0 otherwise.
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for an empty handle or a
|
||||
* NULL out parameter.
|
||||
*/
|
||||
int oakrender_cancelatom_heard_cancel(OakCancelAtom atom, int *heard);
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* @brief Borrowed access to the underlying C++ atom (C++ only, for
|
||||
* adapter layers). Valid while the handle is held. NULL-safe.
|
||||
*/
|
||||
olive::CancelAtom *oakrender_cancelatom_get_native(OakCancelAtom atom);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_CANCELATOM_H
|
||||
@@ -0,0 +1,255 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_COLOR_H
|
||||
#define OAK_EDITOR_RENDER_COLOR_H
|
||||
|
||||
#include "error.h"
|
||||
#include "renderer.h"
|
||||
#include "common/colortransform.h" /* OakColorTransform */
|
||||
#include "node/colormanager.h" /* OakNodeColorManager */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file color.h
|
||||
* @brief C ABI for oakrender color processing (olive::ColorProcessor) and
|
||||
* the process-wide default OCIO config (olive::ColorManager
|
||||
* statics), M7 §2.3.
|
||||
*
|
||||
* 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
|
||||
* environment variable is set, otherwise the config extracted to the
|
||||
* user configuration location. oakrender_color_manager_set_up_default_config()
|
||||
* (re)builds it.
|
||||
*/
|
||||
|
||||
/** Direction values for oakrender_color_processor_create(). */
|
||||
enum {
|
||||
OAKRENDER_COLOR_DIRECTION_NORMAL = 0,
|
||||
OAKRENDER_COLOR_DIRECTION_INVERSE = 1
|
||||
};
|
||||
|
||||
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
|
||||
* OCIO config.
|
||||
*
|
||||
* @param src_space Source colorspace name (role names are resolved).
|
||||
* @param dst_transform Destination colorspace / output transform name.
|
||||
* @param direction OAKRENDER_COLOR_DIRECTION_NORMAL (src -> dst) or
|
||||
* OAKRENDER_COLOR_DIRECTION_INVERSE (dst -> src).
|
||||
*
|
||||
* OCIO failures are non-fatal (matching the C++ behavior): the handle is
|
||||
* still returned but oakrender_color_processor_is_valid() reports 0 and
|
||||
* conversions are pass-through.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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 / empty.
|
||||
*/
|
||||
int oakrender_color_processor_is_valid(OakColorProcessor processor);
|
||||
|
||||
/**
|
||||
* @brief Create a processor from an input colorspace and a destination
|
||||
* transform on a node's color manager
|
||||
* (ColorProcessor::create(ColorManager*, input, dest, dir)).
|
||||
*
|
||||
* @param manager Borrowed manager handle (e.g.
|
||||
* oaknode_colormanager_wrap_borrowed()).
|
||||
* @param direction OAKRENDER_COLOR_DIRECTION_NORMAL / _INVERSE.
|
||||
* @return Processor handle with reference count 1; ctx is NULL for
|
||||
* empty/invalid arguments or allocation failure.
|
||||
*/
|
||||
OakColorProcessor oakrender_color_processor_create_transform(
|
||||
OakNodeColorManager manager, const char *input,
|
||||
OakColorTransform dest, int direction);
|
||||
|
||||
/**
|
||||
* @brief Create a processor from a LUT file on a node's color manager
|
||||
* (OCIO FileTransform with linear interpolation; direction
|
||||
* selects forward/inverse).
|
||||
*
|
||||
* @return Processor handle with reference count 1; ctx is NULL for
|
||||
* empty/invalid arguments, an unreadable LUT, or allocation
|
||||
* failure.
|
||||
*/
|
||||
OakColorProcessor oakrender_color_processor_create_lut(
|
||||
OakNodeColorManager manager, const char *path, int direction);
|
||||
|
||||
/**
|
||||
* @brief Grading-primary transform styles for
|
||||
* oakrender_color_processor_create_grading_primary().
|
||||
*/
|
||||
enum OakRenderGradingPrimaryStyle {
|
||||
OAKRENDER_GRADING_PRIMARY_LIN = 0, /**< OCIO GRADING_LIN */
|
||||
OAKRENDER_GRADING_PRIMARY_LOG = 1 /**< OCIO GRADING_LOG */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create a dynamic grading-primary processor on a node's color
|
||||
* manager (OCIO GradingPrimaryTransform, forward direction).
|
||||
*
|
||||
* @return Processor handle with reference count 1; ctx is NULL for
|
||||
* invalid arguments or allocation failure.
|
||||
*/
|
||||
OakColorProcessor oakrender_color_processor_create_grading_primary(
|
||||
OakNodeColorManager manager, int style);
|
||||
|
||||
/* ---- LUT library ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief 1 when `extension` (without dot, case-insensitive) is a
|
||||
* supported LUT extension (LUTLibrary::is_supported_extension()).
|
||||
*/
|
||||
int oakrender_lut_is_supported_extension(const char *extension);
|
||||
|
||||
/**
|
||||
* @brief Number of supported LUT extensions
|
||||
* (LUTLibrary::supported_extensions()).
|
||||
*/
|
||||
int oakrender_lut_supported_extensions_count(void);
|
||||
|
||||
/**
|
||||
* @brief Supported LUT extension at `index`, two-stage string.
|
||||
*
|
||||
* @return Required buffer size in bytes (including NUL), or a negative
|
||||
* OAKRENDER_E_* code for an out-of-range index.
|
||||
*/
|
||||
int oakrender_lut_supported_extension_at(int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @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 empty/NULL arguments.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Convert a CPU frame's pixels through the processor, in place
|
||||
* (olive::ColorProcessor::convert_frame()).
|
||||
*
|
||||
* The frame's data buffer is rewritten through an OCIO PackedImageDesc
|
||||
* view; nothing is allocated and the frame handle stays owned by the
|
||||
* caller. A processor whose underlying OCIO processor is null
|
||||
* (oakrender_color_processor_create() treats lookup failure as
|
||||
* non-fatal) is a pass-through and returns OAKRENDER_OK, mirroring the
|
||||
* C++ API.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/* ---- ColorManager statics ------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief (Re)build the process-wide default OCIO config
|
||||
* (ColorManager::set_up_default_config()).
|
||||
*
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_FAILED when no config could be
|
||||
* created.
|
||||
*/
|
||||
int oakrender_color_manager_set_up_default_config(void);
|
||||
|
||||
/**
|
||||
* @brief Describe the active default config: the $OCIO path when set,
|
||||
* otherwise the extracted default config's path. Two-stage string
|
||||
* getter: returns the required buffer size including NUL; pass
|
||||
* buf == NULL or too small a buffer to query the size.
|
||||
*
|
||||
* @return Required size (non-negative), or OAKRENDER_E_STATE when no
|
||||
* default config exists.
|
||||
*/
|
||||
int oakrender_color_manager_get_config(char *buf, int n);
|
||||
|
||||
/**
|
||||
* @brief OCIO cache id of the display/view transform of the active
|
||||
* default config, computed from the config's reference colorspace
|
||||
* (a stable identifier usable as a conversion cache key).
|
||||
*
|
||||
* Two-stage string getter (same convention as
|
||||
* oakrender_color_manager_get_config()).
|
||||
*
|
||||
* @return Required size (non-negative), OAKRENDER_E_INVALID (NULL/empty
|
||||
* display or view), OAKRENDER_E_STATE (no default config), or
|
||||
* OAKRENDER_E_NOT_FOUND (unknown display/view).
|
||||
*/
|
||||
int oakrender_color_manager_display_transform(const char *display,
|
||||
const char *view, char *buf,
|
||||
int n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
#include <memory>
|
||||
namespace olive { class ColorProcessor; }
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Borrowed access to the underlying C++ processor (C++ only, for
|
||||
* adapter layers; a shared_ptr copy keeps the object alive).
|
||||
* Empty shared_ptr for an empty handle.
|
||||
*/
|
||||
std::shared_ptr<olive::ColorProcessor> oakrender_color_processor_get_native(
|
||||
OakColorProcessor processor);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_COLOR_H
|
||||
@@ -0,0 +1,84 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_COPIER_H
|
||||
#define OAK_EDITOR_RENDER_COPIER_H
|
||||
|
||||
#include "node/node.h"
|
||||
#include "node/project.h"
|
||||
#include "render/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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,
|
||||
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);
|
||||
|
||||
/** @brief The copied project (borrowed handle; freeing it only releases
|
||||
* the handle box). */
|
||||
OakNodeProject oakrender_project_copier_get_copied_project(
|
||||
OakRenderProjectCopier copier);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_COPIER_H
|
||||
@@ -0,0 +1,49 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_ERROR_H
|
||||
#define OAK_EDITOR_RENDER_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakrender C API families.
|
||||
*
|
||||
* Return-code convention (mirrors include/node/error.h):
|
||||
* 0 (OAKRENDER_OK) on success, a negative OAKRENDER_E_* error code on
|
||||
* 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 (-70001) /**< NULL handle or invalid argument. */
|
||||
#define OAKRENDER_E_STATE (-70002) /**< Call not valid in the current state. */
|
||||
#define OAKRENDER_E_FAILED (-70003) /**< The underlying operation failed. */
|
||||
#define OAKRENDER_E_NOT_FOUND (-70004) /**< Index out of range / entry not found. */
|
||||
#define OAKRENDER_E_NOMEM (-70005) /**< Allocation failed. */
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_ERROR_H
|
||||
@@ -0,0 +1,167 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_MANAGER_H
|
||||
#define OAK_EDITOR_RENDER_MANAGER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// See cache.h for why these are same-dir relative includes.
|
||||
#include "node/node.h" /* OakNodeNode (by-value handle) */
|
||||
#include "cache.h" /* OakCodecFrame */
|
||||
#include "color.h" /* OakColorProcessor */
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file manager.h
|
||||
* @brief C ABI for the oakrender render manager / preview auto-cacher /
|
||||
* disk cache singletons (olive::RenderManager,
|
||||
* olive::PreviewAutoCacher, olive::DiskManager), M7 §2.4.
|
||||
*
|
||||
* The render manager is a process-wide singleton gated by
|
||||
* oakrender_manager_init() / oakrender_manager_shutdown(). Functions
|
||||
* that need it return OAKRENDER_E_STATE when it is not up.
|
||||
*
|
||||
* 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()); an empty frame
|
||||
* (ctx == NULL) signals "no result" (cancelled or failed). Beyond this
|
||||
* callback there are no event subscription interfaces.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Create the RenderManager singleton (spawns render/audio
|
||||
* threads, loads the configured backend).
|
||||
*
|
||||
* @return OAKRENDER_OK, OAKRENDER_E_STATE (already initialized), or
|
||||
* OAKRENDER_E_FAILED.
|
||||
*/
|
||||
int oakrender_manager_init(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the RenderManager singleton. No-op when not
|
||||
* initialized.
|
||||
*/
|
||||
void oakrender_manager_shutdown(void);
|
||||
|
||||
/**
|
||||
* @brief Completion callback of an asynchronous frame request.
|
||||
*
|
||||
* @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,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Asynchronously render one frame of `viewer` at `ts`
|
||||
* (PreviewAutoCacher::get_single_frame()).
|
||||
*
|
||||
* `ts` is a frame number in the viewer node's video timebase (a whole
|
||||
* second count when the viewer carries no valid timebase). The
|
||||
* completion is delivered through `cb`; until then the request can be
|
||||
* cancelled with oakrender_cancel_request().
|
||||
*
|
||||
* @return A positive request id, or a negative OAKRENDER_E_* code
|
||||
* (OAKRENDER_E_INVALID for an empty viewer handle or NULL
|
||||
* callback, OAKRENDER_E_STATE when the manager is not
|
||||
* initialized, OAKRENDER_E_FAILED when no ticket could be
|
||||
* created).
|
||||
*/
|
||||
int64_t oakrender_request_frame(OakNodeNode viewer, int64_t ts,
|
||||
oakrender_frame_ready_fn cb, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Cancel a pending frame request. The callback still fires with a
|
||||
* NULL frame.
|
||||
*
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_NOT_FOUND for an unknown id.
|
||||
*/
|
||||
int oakrender_cancel_request(int64_t request_id);
|
||||
|
||||
/**
|
||||
* @brief Set the multicam node on the manager's auto-cacher
|
||||
* (PreviewAutoCacher::set_multicam_node()). `multicam_or_NULL` is a
|
||||
* borrowed oaknode handle to a MultiCamNode (empty handle to clear).
|
||||
*
|
||||
* @return OAKRENDER_OK or OAKRENDER_E_STATE.
|
||||
*/
|
||||
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,
|
||||
* empty ctx to clear.
|
||||
*
|
||||
* @return OAKRENDER_OK or OAKRENDER_E_STATE.
|
||||
*/
|
||||
int oakrender_set_display_color_processor(OakColorProcessor p_or_NULL);
|
||||
|
||||
/**
|
||||
* @brief 1 when the process-wide RenderManager singleton exists
|
||||
* (RenderManager::instance() != nullptr; only the main GUI
|
||||
* process creates one), 0 otherwise.
|
||||
*/
|
||||
int oakrender_manager_available(void);
|
||||
|
||||
/**
|
||||
* @brief Cancel in-flight video cache tasks on the manager's
|
||||
* auto-cacher (PreviewAutoCacher::cancel_video_tasks()). No-op
|
||||
* when no manager/auto-cacher exists (e.g. a worker process).
|
||||
*/
|
||||
void oakrender_cancel_video_tasks(int wait_for_done);
|
||||
|
||||
/* ---- Disk cache (olive::DiskManager) -------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief The default disk cache directory
|
||||
* (DiskManager::get_default_disk_cache_path()). Two-stage string getter:
|
||||
* returns the required buffer size including NUL; pass buf == NULL or
|
||||
* too small a buffer to query the size. Does not require the manager.
|
||||
*/
|
||||
int oakrender_disk_cache_path(char *buf, int n);
|
||||
|
||||
/**
|
||||
* @brief Bytes currently consumed by the default disk cache folder.
|
||||
* Lazily creates the DiskManager singleton on first use.
|
||||
*
|
||||
* @return Consumption in bytes (>= 0), or OAKRENDER_E_FAILED.
|
||||
*/
|
||||
int64_t oakrender_disk_cache_size(void);
|
||||
|
||||
/**
|
||||
* @brief Clear the default disk cache folder
|
||||
* (DiskManager::clear_disk_cache()).
|
||||
*
|
||||
* @return OAKRENDER_OK or OAKRENDER_E_FAILED.
|
||||
*/
|
||||
int oakrender_disk_cache_clear(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_MANAGER_H
|
||||
@@ -0,0 +1,374 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_RENDERER_H
|
||||
#define OAK_EDITOR_RENDER_RENDERER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file renderer.h
|
||||
* @brief C ABI for the oakrender display renderer (olive::Renderer) —
|
||||
* renderer/texture/frame/blit families plus backend management.
|
||||
*
|
||||
* Signatures follow the R7-A display.h rewrite
|
||||
* (docs/zh/plans/completed/r7-pure-abi-plan.md §A.2) with the
|
||||
* oakrender_ prefix (M7 §2.1).
|
||||
*
|
||||
* 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 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 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).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief POD mirror of olive::VideoParams' user-facing fields.
|
||||
*
|
||||
* Same layout and field semantics as oak_video_params
|
||||
* (engine/include/oakengine/videoparams.h): `time_base_*` is the frame
|
||||
* duration (frame rate flipped), `format` an olive::PixelFormat::Format
|
||||
* value, `interlacing` an olive::VideoParams::Interlacing value,
|
||||
* `color_range` an olive::VideoParams::ColorRange value. The video
|
||||
* channel count is an engine-internal constant and not exposed.
|
||||
*/
|
||||
typedef struct oakrender_video_params {
|
||||
int width;
|
||||
int height;
|
||||
int time_base_num; /**< Frame duration numerator (e.g. 1001/30000 s). */
|
||||
int time_base_den;
|
||||
int format; /**< olive::PixelFormat::Format. */
|
||||
int pixel_aspect_num;
|
||||
int pixel_aspect_den;
|
||||
int interlacing; /**< olive::VideoParams::Interlacing. */
|
||||
int color_range; /**< olive::VideoParams::ColorRange. */
|
||||
int divider; /**< Preview resolution divider (1 = full). */
|
||||
int video_type; /**< olive::VideoParams::Type (0 = video). */
|
||||
int premultiplied_alpha; /**< 0/1. */
|
||||
} oakrender_video_params;
|
||||
|
||||
/**
|
||||
* @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 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 {
|
||||
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
|
||||
* path. `matrix`/`crop_matrix` are column-major 4x4; an all-zero matrix
|
||||
* means identity.
|
||||
*/
|
||||
typedef struct oakrender_color_transform_job {
|
||||
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. */
|
||||
float matrix[16];
|
||||
float crop_matrix[16];
|
||||
} oakrender_color_transform_job;
|
||||
|
||||
/* ---- Renderer lifecycle -------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Create a renderer on the named dynamic backend ("opengl",
|
||||
* "vulkan"; olive::DynamicRenderer). Loads the backend shared library;
|
||||
* falls back per DynamicRenderer rules.
|
||||
*
|
||||
* @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(
|
||||
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 with reference count 1; ctx is NULL on
|
||||
* allocation failure.
|
||||
*/
|
||||
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 (empty renderer), or
|
||||
* OAKRENDER_E_FAILED (backend init failed).
|
||||
*/
|
||||
int oakrender_display_renderer_init(OakRenderRenderer renderer,
|
||||
void *gl_context);
|
||||
|
||||
/**
|
||||
* @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 / empty. */
|
||||
int oakrender_display_renderer_is_open_gl(OakRenderRenderer renderer);
|
||||
|
||||
/** @brief 1 when the renderer is Vulkan-based, 0 otherwise / empty. */
|
||||
int oakrender_display_renderer_is_vulkan(OakRenderRenderer renderer);
|
||||
|
||||
/* ---- 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 (reference count 1); ctx is NULL on invalid
|
||||
* arguments / allocation failure.
|
||||
*/
|
||||
OakRenderTexture oakrender_display_texture_create(
|
||||
OakRenderRenderer renderer, const oakrender_video_params *params,
|
||||
const void *pixels, int linesize);
|
||||
|
||||
/**
|
||||
* @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 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,
|
||||
const void *pixels, int linesize);
|
||||
|
||||
int oakrender_display_texture_download(OakRenderTexture texture, void *pixels,
|
||||
int linesize);
|
||||
|
||||
/* ---- Texture queries ----------------------------------------------------- */
|
||||
|
||||
int oakrender_display_texture_get_params(OakRenderTexture texture,
|
||||
oakrender_video_params *out);
|
||||
|
||||
/** @brief Frame width/height in pixels (0 on empty). */
|
||||
int oakrender_codec_frame_width(OakCodecFrame frame);
|
||||
int oakrender_codec_frame_height(OakCodecFrame frame);
|
||||
|
||||
/** @brief ffmpeg_bridge pixel format when the frame wraps a texture's
|
||||
* CPU copy (an AVFramePtr); -1 otherwise. */
|
||||
int oakrender_codec_frame_fb_format(OakCodecFrame frame);
|
||||
|
||||
/** @brief Native texture id (0 on empty or a dummy/id-less texture). */
|
||||
int oakrender_display_texture_id(OakRenderTexture texture);
|
||||
|
||||
/** @brief 1 when the texture is a placeholder dummy (Texture::is_dummy()). */
|
||||
int oakrender_display_texture_is_dummy(OakRenderTexture texture);
|
||||
|
||||
/**
|
||||
* @brief The CPU frame stored in the texture, if any (Texture::frame()).
|
||||
* *out receives a retained frame handle (empty when none).
|
||||
*/
|
||||
int oakrender_display_texture_get_frame(OakRenderTexture texture,
|
||||
OakCodecFrame *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
||||
namespace olive { class Texture; using TexturePtr = std::shared_ptr<Texture>; }
|
||||
|
||||
/**
|
||||
* @brief Wrap a native TexturePtr in a retained handle (C++ only; used
|
||||
* by oakrender internals when handing textures across the C ABI).
|
||||
*/
|
||||
OakRenderTexture oakrender_display_texture_wrap_native(
|
||||
const olive::TexturePtr &texture);
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ---- Frame handle -------------------------------------------------------- */
|
||||
|
||||
/** @brief Create an empty CPU frame. Returns a handle with count 1. */
|
||||
OakCodecFrame oakrender_codec_frame_create(void);
|
||||
|
||||
/**
|
||||
* @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 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);
|
||||
|
||||
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 (empty frame), or
|
||||
* OAKRENDER_E_FAILED (invalid params / allocation failed).
|
||||
*/
|
||||
int oakrender_codec_frame_allocate(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(OakCodecFrame frame);
|
||||
|
||||
/** @brief Line stride in bytes. */
|
||||
int oakrender_codec_frame_linesize_bytes(OakCodecFrame frame);
|
||||
|
||||
/** @brief 1 when the pixel buffer is allocated, 0 otherwise / empty. */
|
||||
int oakrender_codec_frame_is_allocated(OakCodecFrame frame);
|
||||
|
||||
/* ---- Color-managed blit -------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Blit a color-managed image through the OCIO pipeline
|
||||
* (Renderer::blit_color_managed()).
|
||||
*
|
||||
* @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);
|
||||
|
||||
/* ---- Cross-backend texture download -------------------------------------- */
|
||||
|
||||
int oakrender_display_renderer_download_from_texture(
|
||||
OakRenderRenderer renderer, int texture_id,
|
||||
const oakrender_video_params *params, void *dst_pixels, int linesize);
|
||||
|
||||
/* ---- Backend management (M7 §2.1) ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Number of known render backends (olive::RenderManager::Backend:
|
||||
* opengl, vulkan, multiprocess, dummy).
|
||||
*/
|
||||
int oakrender_backend_count(void);
|
||||
|
||||
/**
|
||||
* @brief Id string of the `i`-th backend ("opengl", ...). Two-stage
|
||||
* string getter: returns the required buffer size including NUL; pass
|
||||
* buf == NULL or too small a buffer to query the size.
|
||||
*
|
||||
* @return Required size (non-negative), or OAKRENDER_E_NOT_FOUND when
|
||||
* `i` is out of range.
|
||||
*/
|
||||
int oakrender_backend_id_at(int i, char *buf, int n);
|
||||
|
||||
/**
|
||||
* @brief Record the requested backend id (applied to the RenderManager
|
||||
* instance when one exists).
|
||||
*
|
||||
* @return OAKRENDER_OK, or OAKRENDER_E_INVALID for a NULL/unknown id.
|
||||
*/
|
||||
int oakrender_set_backend(const char *backend_id);
|
||||
|
||||
/**
|
||||
* @brief The effective backend: the RenderManager instance's backend when
|
||||
* an instance exists, otherwise the requested backend. Two-stage string
|
||||
* getter (same convention as oakrender_backend_id_at()).
|
||||
*/
|
||||
int oakrender_current_backend(char *buf, int n);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_RENDERER_H
|
||||
@@ -0,0 +1,171 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_RENDER_TICKET_H
|
||||
#define OAK_EDITOR_RENDER_TICKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/colortransform.h"
|
||||
#include "common/videoparams.h"
|
||||
#include "node/colormanager.h"
|
||||
#include "node/node.h"
|
||||
#include "olive/core/oakcore/audioparams.h"
|
||||
#include "olive/core/oakcore/samplebuffer.h"
|
||||
#include "render/error.h"
|
||||
#include "render/cache.h"
|
||||
#include "render/color.h"
|
||||
#include "render/renderer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a render ticket
|
||||
* (olive::RenderTicketWatcher).
|
||||
*
|
||||
* 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 {
|
||||
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). 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,
|
||||
void *userdata);
|
||||
|
||||
/** @brief Ticket types (RenderManager::TicketType). */
|
||||
enum OakRenderTicketType {
|
||||
OAKRENDER_TICKET_VIDEO = 0,
|
||||
OAKRENDER_TICKET_AUDIO = 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parameters for a video frame ticket
|
||||
* (RenderManager::RenderVideoParams).
|
||||
*/
|
||||
typedef struct oakrender_video_ticket_params {
|
||||
OakNodeNode output_node; /**< Connected texture output node (borrowed). */
|
||||
OakVideoParams video_params; /**< By value (oakcommon handle). */
|
||||
OakAudioParams *audio_params; /**< Borrowed oakcore handle, may be NULL. */
|
||||
int64_t time_num; /**< Frame timestamp as rational. */
|
||||
int64_t time_den;
|
||||
OakNodeColorManager color_manager; /**< Borrowed, empty ctx = NULL. */
|
||||
int mode; /**< olive::RenderMode::Mode as int. */
|
||||
int force_width; /**< 0/0 = off. */
|
||||
int force_height;
|
||||
double force_matrix[16]; /**< Used when has_force_matrix != 0. */
|
||||
int has_force_matrix;
|
||||
int force_format; /**< PixelFormat as int, -1 = off. */
|
||||
int force_channel_count; /**< 0 = off. */
|
||||
OakColorProcessor force_color_output; /**< Borrowed; empty ctx = none. */
|
||||
OakColorTransform force_color_transform; /**< By value; empty ctx = default. */
|
||||
OakRenderCache cache; /**< Borrowed frame cache; empty ctx = none. */
|
||||
} oakrender_video_ticket_params;
|
||||
|
||||
/**
|
||||
* @brief Submit a video frame render ticket.
|
||||
*
|
||||
* @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(
|
||||
const oakrender_video_ticket_params *params,
|
||||
oakrender_ticket_finished_fn cb, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Submit an audio render ticket (RenderManager::render_audio()).
|
||||
*
|
||||
* @param output_node Connected sample output node.
|
||||
* @param params Audio params (borrowed oakcore handle).
|
||||
*/
|
||||
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);
|
||||
|
||||
/** @brief Block until the ticket finishes. */
|
||||
int oakrender_ticket_wait(OakRenderTicket ticket);
|
||||
|
||||
int oakrender_ticket_cancel(OakRenderTicket ticket);
|
||||
|
||||
/** @brief OAKRENDER_TICKET_* or negative error. */
|
||||
int oakrender_ticket_get_type(OakRenderTicket ticket);
|
||||
|
||||
/** @brief Ticket timestamp (video tickets). */
|
||||
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,
|
||||
int64_t *in_den, int64_t *out_num,
|
||||
int64_t *out_den);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief The resulting samples (audio tickets). *out receives a copy
|
||||
* (release with oakcore_samplebuffer_free()).
|
||||
*/
|
||||
int oakrender_ticket_get_samples(OakRenderTicket ticket,
|
||||
OakSampleBuffer **out);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Toggle aggressive garbage collection on the render manager
|
||||
* (RenderManager::set_aggressive_garbage_collection()).
|
||||
*/
|
||||
int oakrender_manager_set_aggressive_gc(int enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_RENDER_TICKET_H
|
||||
@@ -0,0 +1,42 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TASK_ERROR_H
|
||||
#define OAK_EDITOR_TASK_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oaktask C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKTASK_OK) on success, a negative OAKTASK_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKTASK_ABI_VERSION 1
|
||||
|
||||
#define OAKTASK_OK 0 /**< Success. */
|
||||
#define OAKTASK_E_INVALID (-80001) /**< NULL handle or invalid argument. */
|
||||
#define OAKTASK_E_STATE (-80002) /**< Call not valid in the current state. */
|
||||
#define OAKTASK_E_FAILED (-80003) /**< The underlying operation failed. */
|
||||
#define OAKTASK_E_NOT_FOUND (-80004) /**< Index out of range / entry not found. */
|
||||
#define OAKTASK_E_NOMEM (-80005) /**< Allocation failed. */
|
||||
#define OAKTASK_E_CANCELLED (-80006) /**< The operation was cancelled. */
|
||||
|
||||
#endif //OAK_EDITOR_TASK_ERROR_H
|
||||
@@ -0,0 +1,55 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TASK_MANAGER_H
|
||||
#define OAK_EDITOR_TASK_MANAGER_H
|
||||
|
||||
#include "task/task.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Task manager singleton lifecycle.
|
||||
*/
|
||||
int oaktask_manager_init(void);
|
||||
void oaktask_manager_shutdown(void);
|
||||
|
||||
/**
|
||||
* @brief Register oaktask as oakcodec's background task submitter
|
||||
* (olive::register_codec_task_submitter()). Called by
|
||||
* oaktask_manager_init(); exposed for manual control.
|
||||
*/
|
||||
int oaktask_register_codec_submitter(void);
|
||||
|
||||
int oaktask_manager_count(void);
|
||||
|
||||
/** @brief Borrowed task at index (release only frees the box), empty
|
||||
* handle when out of range or no manager. */
|
||||
OakTaskTask oaktask_manager_at(int i);
|
||||
|
||||
void oaktask_manager_delete_finished(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TASK_MANAGER_H
|
||||
@@ -0,0 +1,126 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TASK_PROJECT_H
|
||||
#define OAK_EDITOR_TASK_PROJECT_H
|
||||
|
||||
#include "codec/encoder.h"
|
||||
#include "node/colormanager.h"
|
||||
#include "node/footage.h"
|
||||
#include "node/node.h"
|
||||
#include "node/project.h"
|
||||
#include "node/sequence.h"
|
||||
#include "task/task.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Project task factories and result accessors (M8 §2.2).
|
||||
*/
|
||||
|
||||
/** @brief olive::ProjectLoadTask. Empty handle (ctx == NULL) on
|
||||
* failure. */
|
||||
OakTaskTask oaktask_create_project_load(const char *filename);
|
||||
|
||||
/** @brief Take the loaded project (ownership transfer). Empty handle
|
||||
* (ctx == NULL) when the task has not succeeded or the project was
|
||||
* already taken. */
|
||||
OakNodeProject oaktask_load_take_project(OakTaskTask t);
|
||||
|
||||
/** @brief olive::ProjectSaveTask. `filename_or_NULL` overrides the
|
||||
* project's own filename. `project` is borrowed by the task. */
|
||||
OakTaskTask oaktask_create_project_save(OakNodeProject project,
|
||||
const char *filename_or_NULL,
|
||||
int use_compression);
|
||||
|
||||
/** @brief olive::ProjectImportTask. `folder`/`project` are borrowed by
|
||||
* the task. */
|
||||
OakTaskTask oaktask_create_project_import(OakNodeFolder folder,
|
||||
OakNodeProject project,
|
||||
const char *const *urls,
|
||||
int url_count);
|
||||
|
||||
/** @brief Take the import's undo command (ownership transfer). */
|
||||
OakUndoCommand oaktask_import_take_command(OakTaskTask t);
|
||||
|
||||
int oaktask_import_footage_count(OakTaskTask t);
|
||||
|
||||
/** @brief Footage handle at index (addref'd; release with
|
||||
* handle.release(handle.ctx) - box only, the project owns the
|
||||
* footage). Empty handle when out of range. */
|
||||
OakNodeFootage oaktask_import_footage_at(OakTaskTask t, int index);
|
||||
|
||||
int oaktask_import_invalid_count(OakTaskTask t);
|
||||
|
||||
/** @brief Invalid filename at index (two-stage). */
|
||||
int oaktask_import_invalid_at(OakTaskTask t, int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/** @brief olive::LoadOTIOTask. Empty handle (ctx == NULL) on failure. */
|
||||
OakTaskTask oaktask_create_project_load_otio(const char *filename);
|
||||
|
||||
/** @brief Take the loaded project (ownership transfer). Empty handle
|
||||
* (ctx == NULL) when the task has not succeeded or the project was
|
||||
* already taken. */
|
||||
OakNodeProject oaktask_load_otio_take_project(OakTaskTask t);
|
||||
|
||||
/** @brief olive::SaveOTIOTask. `project` is borrowed by the task. */
|
||||
OakTaskTask oaktask_create_project_save_otio(OakNodeProject project,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* @brief OTIO import confirmation callback (facade concern; default
|
||||
* accepts everything). Return non-zero to accept.
|
||||
*/
|
||||
typedef int (*oaktask_otio_import_confirm_fn)(
|
||||
const char *const *sequence_names, int count, void *userdata);
|
||||
void oaktask_load_otio_set_confirm_cb(oaktask_otio_import_confirm_fn fn,
|
||||
void *userdata);
|
||||
|
||||
/** @brief olive::PreCacheTask. `footage`/`sequence` are borrowed by the
|
||||
* task. */
|
||||
OakTaskTask oaktask_create_precache(OakNodeFootage footage, int index,
|
||||
OakNodeSequence sequence);
|
||||
|
||||
/** @brief olive::ExportTask (params POD from codec/encoder.h).
|
||||
* `viewer`/`color_manager` are borrowed by the task. */
|
||||
OakTaskTask oaktask_create_export(OakNodeNode viewer,
|
||||
OakNodeColorManager color_manager,
|
||||
const oakcodec_encoding_params *params);
|
||||
|
||||
/**
|
||||
* @brief Image-sequence confirmation callback (facade/UI concern;
|
||||
* olive::ProjectImportTask::set_image_sequence_confirm_callback).
|
||||
* Return non-zero to treat numbered stills as a sequence.
|
||||
* Default (no callback): not a sequence.
|
||||
*/
|
||||
typedef int (*oaktask_image_sequence_confirm_fn)(const char *filename,
|
||||
void *userdata);
|
||||
void oaktask_import_set_image_sequence_confirm_cb(
|
||||
oaktask_image_sequence_confirm_fn fn, void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TASK_PROJECT_H
|
||||
@@ -0,0 +1,108 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TASK_TASK_H
|
||||
#define OAK_EDITOR_TASK_TASK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "task/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to a background task (olive::Task).
|
||||
*
|
||||
* By-value handle (shared_ptr semantics, see oakcommon's
|
||||
* common/handle.h). Tasks are created through the factories in
|
||||
* task/project.h (and future family headers) with reference count 1 and
|
||||
* must be released with oaktask_task_free(). oaktask_task_start()
|
||||
* transfers the task's lifetime to the task manager: releasing the
|
||||
* handle afterwards only frees the box.
|
||||
*/
|
||||
typedef struct OakTaskTask {
|
||||
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; /**< OAKTASK_ABI_VERSION. */
|
||||
} OakTaskTask;
|
||||
|
||||
/** @brief Lifecycle event ids for oaktask_task_subscribe(). */
|
||||
enum OakTaskEvent {
|
||||
OAKTASK_EVENT_STARTED = 0,
|
||||
OAKTASK_EVENT_PROGRESS = 1,
|
||||
OAKTASK_EVENT_FINISHED = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Event callback (async command return channel, 01 §4 exception).
|
||||
*
|
||||
* For OAKTASK_EVENT_FINISHED, `value` is 1.0 on success / 0.0 on failure;
|
||||
* for OAKTASK_EVENT_PROGRESS it is 0..1; for OAKTASK_EVENT_STARTED it is
|
||||
* the start time in milliseconds.
|
||||
*/
|
||||
typedef void (*oaktask_event_fn)(int event_id, double value,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a task. Convenience wrapper around
|
||||
* t->release(t->ctx): NULL / empty-handle no-op; clears t->ctx
|
||||
* after releasing. The task must not be running on the manager
|
||||
* (oaktask_task_cancel + wait first if it is).
|
||||
*/
|
||||
void oaktask_task_free(OakTaskTask *t);
|
||||
|
||||
/** @brief Run synchronously in the calling thread. 1 = succeeded. */
|
||||
int oaktask_task_start_sync(OakTaskTask t);
|
||||
|
||||
/** @brief Run asynchronously on the task manager. */
|
||||
int oaktask_task_start(OakTaskTask t);
|
||||
|
||||
int oaktask_task_cancel(OakTaskTask t);
|
||||
|
||||
/** @brief Wait for an asynchronously started task. */
|
||||
int oaktask_task_wait(OakTaskTask t);
|
||||
|
||||
int oaktask_task_is_finished(OakTaskTask t);
|
||||
|
||||
int oaktask_task_succeeded(OakTaskTask t);
|
||||
|
||||
/** @brief Two-stage string getters. */
|
||||
int oaktask_task_title(OakTaskTask t, char *buf, int buf_size);
|
||||
int oaktask_task_error(OakTaskTask t, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Subscribe to lifecycle events (returns a subscription id >= 0,
|
||||
* or a negative error code). One-shot per event stream: the
|
||||
* subscription is dropped after OAKTASK_EVENT_FINISHED.
|
||||
*/
|
||||
int64_t oaktask_task_subscribe(OakTaskTask t, oaktask_event_fn fn,
|
||||
void *userdata);
|
||||
|
||||
/** @brief Alive-count for leak assertions in tests. */
|
||||
int oaktask_debug_alive_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TASK_TASK_H
|
||||
@@ -0,0 +1,51 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TIMELINE_DISPLAYMODE_H
|
||||
#define OAK_EDITOR_TIMELINE_DISPLAYMODE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Shared timeline display-mode constants.
|
||||
*
|
||||
* Neutral home for the enum values behind the TimelineThumbnailMode /
|
||||
* TimelineWaveformMode config keys; mirrors olive::Timeline::ThumbnailMode
|
||||
* / WaveformMode (src/timeline/src/timelinecommon.h) and must stay
|
||||
* value-compatible with them.
|
||||
*/
|
||||
enum OakTimelineThumbnailMode {
|
||||
OAK_TIMELINE_THUMBNAIL_OFF = 0,
|
||||
OAK_TIMELINE_THUMBNAIL_IN_OUT = 1,
|
||||
OAK_TIMELINE_THUMBNAIL_ON = 2
|
||||
};
|
||||
|
||||
enum OakTimelineWaveformMode {
|
||||
OAK_TIMELINE_WAVEFORMS_DISABLED = 0,
|
||||
OAK_TIMELINE_WAVEFORMS_ENABLED = 1
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OAK_EDITOR_TIMELINE_DISPLAYMODE_H
|
||||
@@ -0,0 +1,131 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TIMELINE_EDIT_H
|
||||
#define OAK_EDITOR_TIMELINE_EDIT_H
|
||||
|
||||
#include "node/block.h"
|
||||
#include "node/sequence.h"
|
||||
#include "node/track.h"
|
||||
#include "timeline/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Timeline edit primitives (M4 §2.3).
|
||||
*
|
||||
* The timeline undo command classes stay inside oaktimeline (01 §5);
|
||||
* consumers create commands through these factories, receiving base
|
||||
* OakUndoCommand handles (owned; free with oakundo_command_free()).
|
||||
* Redo a command directly or push it on an undo stack.
|
||||
*
|
||||
* OakNode* handles are passed by value per the oaknode handle
|
||||
* convention; an empty handle (ctx == NULL) yields an empty
|
||||
* OakUndoCommand result.
|
||||
*/
|
||||
|
||||
/** @brief olive::TimelineAddTrackCommand. */
|
||||
OakUndoCommand oaktimeline_add_track_command(OakNodeTrackList list);
|
||||
|
||||
/** @brief olive::TimelineRemoveTrackCommand. */
|
||||
OakUndoCommand oaktimeline_remove_track_command(OakNodeTrack track);
|
||||
|
||||
/** @brief olive::TrackPlaceBlockCommand. */
|
||||
OakUndoCommand oaktimeline_place_block_command(OakNodeTrackList list,
|
||||
int track_index,
|
||||
OakNodeBlock block,
|
||||
int64_t in_num,
|
||||
int64_t in_den);
|
||||
|
||||
/** @brief olive::TrackReplaceBlockWithGapCommand. */
|
||||
OakUndoCommand oaktimeline_replace_block_with_gap_command(
|
||||
OakNodeTrack track, OakNodeBlock block);
|
||||
|
||||
/**
|
||||
* @brief The capi's move-clip assembly: gap the block's old spot and place
|
||||
* it at `in` on `track_index` of `list` as ONE undoable entry
|
||||
* (olive::TrackReplaceBlockWithGapCommand + olive::TrackPlaceBlockCommand
|
||||
* inside a MultiUndoCommand).
|
||||
*/
|
||||
OakUndoCommand oaktimeline_move_block_command(OakNodeTrackList list,
|
||||
int track_index,
|
||||
OakNodeBlock block,
|
||||
int64_t in_num,
|
||||
int64_t in_den);
|
||||
|
||||
/**
|
||||
* @brief olive::BlockTrimCommand. `mode` is an OakTimelineMovementMode
|
||||
* value (k_trim_in / k_trim_out).
|
||||
*/
|
||||
OakUndoCommand oaktimeline_trim_command(OakNodeTrack track,
|
||||
OakNodeBlock block,
|
||||
int64_t new_length_num,
|
||||
int64_t new_length_den, int mode);
|
||||
|
||||
/** @brief olive::BlockSplitCommand on a set of blocks at one point. */
|
||||
OakUndoCommand oaktimeline_split_command(const OakNodeBlock *blocks,
|
||||
int count, int64_t point_num,
|
||||
int64_t point_den);
|
||||
|
||||
/** @brief olive::BlockSplitPreservingLinksCommand. */
|
||||
OakUndoCommand oaktimeline_split_preserving_links_command(
|
||||
const OakNodeBlock *blocks, int count, const int64_t *point_nums,
|
||||
const int64_t *point_dens, int time_count);
|
||||
|
||||
/** @brief olive::TimelineRippleDeleteGapsAtRegionsCommand. */
|
||||
OakUndoCommand oaktimeline_ripple_delete_gaps_command(
|
||||
OakNodeSequence sequence, const int64_t *in_nums,
|
||||
const int64_t *in_dens, const int64_t *out_nums,
|
||||
const int64_t *out_dens, const OakNodeTrack *tracks, int range_count);
|
||||
|
||||
/** @brief olive::TrackSlideCommand. */
|
||||
OakUndoCommand oaktimeline_slide_command(
|
||||
OakNodeTrack track, const OakNodeBlock *blocks, int block_count,
|
||||
OakNodeBlock in_adjacent, OakNodeBlock out_adjacent,
|
||||
int64_t movement_num, int64_t movement_den);
|
||||
|
||||
/** @brief olive::TrackRippleRemoveAreaCommand. */
|
||||
OakUndoCommand oaktimeline_ripple_remove_area_command(
|
||||
OakNodeTrack track, int64_t in_num, int64_t in_den, int64_t out_num,
|
||||
int64_t out_den);
|
||||
|
||||
/** @brief olive::TrackListInsertGaps. */
|
||||
OakUndoCommand oaktimeline_insert_gaps_command(OakNodeTrackList list,
|
||||
int64_t point_num,
|
||||
int64_t point_den,
|
||||
int64_t length_num,
|
||||
int64_t length_den);
|
||||
|
||||
/** @brief Movement modes (olive::Timeline::MovementMode). */
|
||||
enum OakTimelineMovementMode {
|
||||
OAKTIMELINE_MOVEMENT_NONE = 0,
|
||||
OAKTIMELINE_MOVEMENT_MOVE = 1,
|
||||
OAKTIMELINE_MOVEMENT_TRIM_IN = 2,
|
||||
OAKTIMELINE_MOVEMENT_TRIM_OUT = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TIMELINE_EDIT_H
|
||||
@@ -0,0 +1,41 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TIMELINE_ERROR_H
|
||||
#define OAK_EDITOR_TIMELINE_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oaktimeline C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKTIMELINE_OK) on success, a negative OAKTIMELINE_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKTIMELINE_ABI_VERSION 1
|
||||
|
||||
#define OAKTIMELINE_OK 0 /**< Success. */
|
||||
#define OAKTIMELINE_E_INVALID (-40001) /**< NULL handle or invalid argument. */
|
||||
#define OAKTIMELINE_E_STATE (-40002) /**< Call not valid in the current state. */
|
||||
#define OAKTIMELINE_E_FAILED (-40003) /**< The underlying operation failed. */
|
||||
#define OAKTIMELINE_E_NOT_FOUND (-40004) /**< Index out of range / entry not found. */
|
||||
#define OAKTIMELINE_E_NOMEM (-40005) /**< Allocation failed. */
|
||||
|
||||
#endif //OAK_EDITOR_TIMELINE_ERROR_H
|
||||
@@ -0,0 +1,138 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TIMELINE_MARKER_H
|
||||
#define OAK_EDITOR_TIMELINE_MARKER_H
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/node.h"
|
||||
#include "timeline/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief By-value handle to a timeline marker list
|
||||
* (olive::TimelineMarkerList).
|
||||
*
|
||||
* Borrowed handles are obtained via oaktimeline_marker_list_of() and box
|
||||
* a reference into the owning node; owning handles are created by
|
||||
* oaktimeline_marker_list_create(). Either way, release with
|
||||
* oaktimeline_marker_list_free() (or handle.release(handle.ctx)) when
|
||||
* done — release destroys the list only for owning handles.
|
||||
*/
|
||||
typedef struct OakTimelineMarkerList {
|
||||
void *ctx; /**< Opaque pointer to the object's box. */
|
||||
void (*addref)(void *ctx); /**< Atomically increments the box count. */
|
||||
void (*release)(void *ctx); /**< Decrements the count, frees the box. */
|
||||
uint32_t abi_version; /**< OAKTIMELINE_ABI_VERSION. */
|
||||
} OakTimelineMarkerList;
|
||||
|
||||
/**
|
||||
* @brief Create an owning handle to a new, empty marker list. Empty
|
||||
* handle (ctx == NULL) on allocation failure.
|
||||
*/
|
||||
OakTimelineMarkerList oaktimeline_marker_list_create(void);
|
||||
|
||||
/**
|
||||
* @brief Borrowed marker list of a viewer node (sequence). Empty handle
|
||||
* (ctx == NULL) for an empty node handle or when the node is not a
|
||||
* viewer.
|
||||
*/
|
||||
OakTimelineMarkerList oaktimeline_marker_list_of(OakNodeNode owner);
|
||||
|
||||
/**
|
||||
* @brief Release a marker list handle (destroys the list itself only
|
||||
* for owning handles). NULL / empty-handle no-op; clears
|
||||
* list->ctx after releasing.
|
||||
*/
|
||||
void oaktimeline_marker_list_free(OakTimelineMarkerList *list);
|
||||
|
||||
/**
|
||||
* @brief Append a marker directly (no undo command). name may be NULL
|
||||
* for an empty name.
|
||||
*/
|
||||
int oaktimeline_marker_add(OakTimelineMarkerList list, int in_num,
|
||||
int in_den, int out_num, int out_den,
|
||||
const char *name, int color);
|
||||
|
||||
/**
|
||||
* @brief Number of markers. Out-param convention; OAKTIMELINE_E_INVALID
|
||||
* for empty/NULL arguments.
|
||||
*/
|
||||
int oaktimeline_marker_count(OakTimelineMarkerList list, int *out_count);
|
||||
|
||||
/**
|
||||
* @brief Marker at index: time as num/den pairs, color and name
|
||||
* (two-stage string). OAKTIMELINE_E_NOT_FOUND when out of range.
|
||||
*/
|
||||
int oaktimeline_marker_at(OakTimelineMarkerList list, int index,
|
||||
int *in_num, int *in_den, int *out_num, int *out_den,
|
||||
int *color, char *name_buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Create a command that adds a marker (olive::MarkerAddCommand).
|
||||
*
|
||||
* Owned command; free with oakundo_command_free(). Redo it directly or
|
||||
* push it on an undo stack. Empty handle on failure.
|
||||
*/
|
||||
OakUndoCommand oaktimeline_marker_add_command(
|
||||
OakTimelineMarkerList list, int in_num, int in_den, int out_num,
|
||||
int out_den, const char *name, int color);
|
||||
|
||||
/**
|
||||
* @brief Create a command that removes the marker at `index`.
|
||||
* OAKTIMELINE_E_NOT_FOUND (as an empty result documented by error) is
|
||||
* reported by returning an empty handle.
|
||||
*/
|
||||
OakUndoCommand oaktimeline_marker_remove_at_command(
|
||||
OakTimelineMarkerList list, int index);
|
||||
|
||||
/**
|
||||
* @brief Create a command that sets a marker's time range.
|
||||
*/
|
||||
OakUndoCommand oaktimeline_marker_set_time_command(
|
||||
OakTimelineMarkerList list, int index, int in_num, int in_den,
|
||||
int out_num, int out_den);
|
||||
|
||||
/**
|
||||
* @brief Create a command that sets a marker's color and/or name.
|
||||
* `name` may be NULL to leave the name unchanged (color still applies
|
||||
* when >= 0; both NULL-name and color < 0 is a no-op error).
|
||||
*/
|
||||
OakUndoCommand oaktimeline_marker_set_props_command(
|
||||
OakTimelineMarkerList list, int index, int color, const char *name);
|
||||
|
||||
/**
|
||||
* @brief Load/save the list through oakcommon XML handles. The reader
|
||||
* must be positioned on the wrapping element (e.g. "markers").
|
||||
*/
|
||||
int oaktimeline_marker_list_load(OakTimelineMarkerList list,
|
||||
OakXmlReader reader);
|
||||
int oaktimeline_marker_list_save(OakTimelineMarkerList list,
|
||||
OakXmlWriter writer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TIMELINE_MARKER_H
|
||||
@@ -0,0 +1,122 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_TIMELINE_WORKAREA_H
|
||||
#define OAK_EDITOR_TIMELINE_WORKAREA_H
|
||||
|
||||
#include "common/xmlutils.h"
|
||||
#include "node/node.h"
|
||||
#include "timeline/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief By-value handle to a timeline work area
|
||||
* (olive::TimelineWorkArea).
|
||||
*
|
||||
* Borrowed handles are obtained via oaktimeline_workarea_of() and box a
|
||||
* reference into the owning node; owning handles are created by
|
||||
* oaktimeline_workarea_create(). Either way, release with
|
||||
* oaktimeline_workarea_free() (or handle.release(handle.ctx)) when
|
||||
* done — release destroys the work area only for owning handles.
|
||||
*/
|
||||
typedef struct OakTimelineWorkArea {
|
||||
void *ctx; /**< Opaque pointer to the object's box. */
|
||||
void (*addref)(void *ctx); /**< Atomically increments the box count. */
|
||||
void (*release)(void *ctx); /**< Decrements the count, frees the box. */
|
||||
uint32_t abi_version; /**< OAKTIMELINE_ABI_VERSION. */
|
||||
} OakTimelineWorkArea;
|
||||
|
||||
/**
|
||||
* @brief Create an owning handle to a new, default-constructed work
|
||||
* area. Empty handle (ctx == NULL) on allocation failure.
|
||||
*/
|
||||
OakTimelineWorkArea oaktimeline_workarea_create(void);
|
||||
|
||||
/**
|
||||
* @brief Borrowed work area of a viewer node (sequence). Empty handle
|
||||
* (ctx == NULL) for an empty node handle or when the node is not a
|
||||
* viewer.
|
||||
*/
|
||||
OakTimelineWorkArea oaktimeline_workarea_of(OakNodeNode owner);
|
||||
|
||||
/**
|
||||
* @brief Release a work area handle (destroys the work area itself only
|
||||
* for owning handles). NULL / empty-handle no-op; clears w->ctx
|
||||
* after releasing.
|
||||
*/
|
||||
void oaktimeline_workarea_free(OakTimelineWorkArea *w);
|
||||
|
||||
/**
|
||||
* @brief Set enabled directly (live).
|
||||
*/
|
||||
int oaktimeline_workarea_set_enabled(OakTimelineWorkArea w, int enabled);
|
||||
|
||||
/**
|
||||
* @brief Read the work area state. Out params may individually be NULL.
|
||||
*/
|
||||
int oaktimeline_workarea_get(OakTimelineWorkArea w, int *in_num,
|
||||
int *in_den, int *out_num, int *out_den,
|
||||
int *enabled);
|
||||
|
||||
/**
|
||||
* @brief Set the range directly (live).
|
||||
*/
|
||||
int oaktimeline_workarea_set_range(OakTimelineWorkArea w, int in_num,
|
||||
int in_den, int out_num, int out_den);
|
||||
|
||||
/**
|
||||
* @brief Create a set-range command (olive::WorkareaSetRangeCommand).
|
||||
* The old range must be supplied by the caller (facade knows what it
|
||||
* changed from). Owned; free with oakundo_command_free().
|
||||
*/
|
||||
OakUndoCommand oaktimeline_workarea_set_range_command(
|
||||
OakTimelineWorkArea w, int in_num, int in_den, int out_num,
|
||||
int out_den, int old_in_num, int old_in_den, int old_out_num,
|
||||
int old_out_den);
|
||||
|
||||
/**
|
||||
* @brief Create a set-enabled command (olive::WorkareaSetEnabledCommand).
|
||||
*/
|
||||
OakUndoCommand oaktimeline_workarea_set_enabled_command(
|
||||
OakTimelineWorkArea w, int enabled);
|
||||
|
||||
/**
|
||||
* @brief The reset sentinel range (TimelineWorkArea::k_reset_in/out).
|
||||
*/
|
||||
int oaktimeline_workarea_reset(int *in_num, int *in_den, int *out_num,
|
||||
int *out_den);
|
||||
|
||||
/**
|
||||
* @brief Load/save through oakcommon XML handles. The reader must be
|
||||
* positioned on the "workarea" element.
|
||||
*/
|
||||
int oaktimeline_workarea_load(OakTimelineWorkArea w, OakXmlReader reader);
|
||||
int oaktimeline_workarea_save(OakTimelineWorkArea w,
|
||||
OakXmlWriter writer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_TIMELINE_WORKAREA_H
|
||||
@@ -0,0 +1,39 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_UNDO_ERROR_H
|
||||
#define OAK_EDITOR_UNDO_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakundo C API families.
|
||||
*
|
||||
* Return-code convention (mirrors engine/include/oakengine/init.h):
|
||||
* 0 (OAKUNDO_OK) on success, a negative OAKUNDO_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKUNDO_OK 0 /**< Success. */
|
||||
#define OAKUNDO_E_INVALID (-20001) /**< NULL handle or invalid argument. */
|
||||
#define OAKUNDO_E_STATE (-20002) /**< Call not valid in the current state. */
|
||||
#define OAKUNDO_E_FAILED (-20003) /**< The underlying operation failed. */
|
||||
#define OAKUNDO_E_NOT_FOUND (-20004) /**< Index out of range / entry not found. */
|
||||
#define OAKUNDO_E_NOMEM (-20005) /**< Allocation failed. */
|
||||
|
||||
#endif //OAK_EDITOR_UNDO_ERROR_H
|
||||
@@ -0,0 +1,149 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_UNDO_UNDOCOMMAND_H
|
||||
#define OAK_EDITOR_UNDO_UNDOCOMMAND_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "undo/error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OAKUNDO_ABI_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to an undo command
|
||||
* (olive::UndoCommand).
|
||||
*
|
||||
* The object never leaves the library that created it; every external
|
||||
* reference is one of these handles. Semantics are shared_ptr-like:
|
||||
* init/factory functions return a handle with count 1, addref(ctx)
|
||||
* takes another reference, release(ctx) drops one and the library
|
||||
* destroys the object when the count reaches zero.
|
||||
*
|
||||
* Pushing a command onto an OakUndoStack transfers one reference to the
|
||||
* stack (the stack releases it when the command is discarded); callers
|
||||
* may keep their own reference or release it right after the push.
|
||||
*/
|
||||
typedef struct OakUndoCommand {
|
||||
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; /**< OAKUNDO_ABI_VERSION. */
|
||||
} OakUndoCommand;
|
||||
|
||||
/**
|
||||
* @brief Callback table backing a caller-defined undo command.
|
||||
*
|
||||
* Any callback may be NULL; a NULL redo/undo makes that direction a
|
||||
* no-op. free_fn is invoked when the command is destroyed (whether held
|
||||
* by a stack or released directly) and releases userdata.
|
||||
*/
|
||||
typedef struct OakUndoCommandVtable {
|
||||
void (*redo)(void *userdata);
|
||||
void (*undo)(void *userdata);
|
||||
void (*free_fn)(void *userdata);
|
||||
} OakUndoCommandVtable;
|
||||
|
||||
/**
|
||||
* @brief Create an undo command backed by C callbacks.
|
||||
*
|
||||
* The command takes ownership of `userdata`; `vtable` is copied.
|
||||
*
|
||||
* @return Command handle with count 1; ctx is NULL on invalid argument
|
||||
* or allocation failure.
|
||||
*/
|
||||
OakUndoCommand oakundo_command_init(const OakUndoCommandVtable *vtable,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Create an empty multi command (olive::MultiUndoCommand).
|
||||
*
|
||||
* @return Command handle with count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OakUndoCommand oakundo_command_init_multi(void);
|
||||
|
||||
/**
|
||||
* @brief Add `child` to the multi command `multi`.
|
||||
*
|
||||
* The multi command takes one reference to the child; the caller keeps
|
||||
* its own reference and may release it after the call.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_command_multi_add_child(OakUndoCommand multi,
|
||||
OakUndoCommand child);
|
||||
|
||||
/**
|
||||
* @brief Query the number of children in a multi command.
|
||||
*
|
||||
* @param out_count Receives the result. Must not be NULL.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_command_multi_child_count(OakUndoCommand multi,
|
||||
int *out_count);
|
||||
|
||||
/**
|
||||
* @brief Reference to the child at `index` of a multi command.
|
||||
*
|
||||
* The returned handle carries its own reference; release it with
|
||||
* oakundo_command_free().
|
||||
*
|
||||
* @return OAKUNDO_OK, OAKUNDO_E_NOT_FOUND for an out-of-range index, or
|
||||
* another negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_command_multi_child(OakUndoCommand multi, int index,
|
||||
OakUndoCommand *out_child);
|
||||
|
||||
/**
|
||||
* @brief Execute the command's redo without a stack
|
||||
* (olive::UndoCommand::redo_now semantics; a no-op if already done).
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_command_redo_now(OakUndoCommand command);
|
||||
|
||||
/**
|
||||
* @brief Execute the command's undo without a stack
|
||||
* (olive::UndoCommand::undo_now semantics; a no-op if not done).
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_command_undo_now(OakUndoCommand command);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a command handle.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx): destroys the
|
||||
* command when the count reaches zero. NULL handle or NULL ctx is a
|
||||
* no-op; clears `command->ctx` after releasing.
|
||||
*/
|
||||
void oakundo_command_free(OakUndoCommand *command);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_UNDO_UNDOCOMMAND_H
|
||||
@@ -0,0 +1,173 @@
|
||||
/***
|
||||
|
||||
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/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_UNDO_UNDOSTACK_H
|
||||
#define OAK_EDITOR_UNDO_UNDOSTACK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "undo/error.h"
|
||||
#include "undo/undocommand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Reference-counted handle to an undo stack (olive::UndoStack).
|
||||
*
|
||||
* Same ownership/count semantics as OakUndoCommand (see
|
||||
* undo/undocommand.h).
|
||||
*/
|
||||
typedef struct OakUndoStack {
|
||||
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; /**< OAKUNDO_ABI_VERSION. */
|
||||
} OakUndoStack;
|
||||
|
||||
/**
|
||||
* @brief Create an undo stack (count 1).
|
||||
*
|
||||
* A fresh stack contains a single "New/Open Project" empty command,
|
||||
* matching olive::UndoStack::clear().
|
||||
*
|
||||
* @return Stack handle; ctx is NULL on allocation failure.
|
||||
*/
|
||||
OakUndoStack oakundo_undostack_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to an undo stack.
|
||||
*
|
||||
* NULL handle or NULL ctx is a no-op; clears `stack->ctx` after
|
||||
* releasing.
|
||||
*/
|
||||
void oakundo_undostack_free(OakUndoStack *stack);
|
||||
|
||||
/**
|
||||
* @brief Push `command` onto the stack and execute its redo.
|
||||
*
|
||||
* The stack takes one reference to the command; the caller keeps its
|
||||
* own reference and may release it after the call. An empty multi
|
||||
* command is deleted immediately (not pushed), matching
|
||||
* olive::UndoStack::push. `name` is the user-visible label (NULL
|
||||
* behaves like an empty label).
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_push(OakUndoStack stack, OakUndoCommand command,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* @brief Push a command that has already been executed (redo skipped).
|
||||
*
|
||||
* Reference rules match oakundo_undostack_push().
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_push_pre_executed(OakUndoStack stack,
|
||||
OakUndoCommand command,
|
||||
const char *name);
|
||||
|
||||
/**
|
||||
* @brief Undo the most recently done command, if any.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_undo(OakUndoStack stack);
|
||||
|
||||
/**
|
||||
* @brief Redo the most recently undone command, if any.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_redo(OakUndoStack stack);
|
||||
|
||||
/**
|
||||
* @brief Undo/redo until the done-command count equals `index`
|
||||
* (olive::UndoStack::jump semantics). Negative values are clamped to 0.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_jump(OakUndoStack stack, int64_t index);
|
||||
|
||||
/**
|
||||
* @brief Delete all commands and push the fresh "New/Open Project" empty
|
||||
* command (olive::UndoStack::clear).
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_clear(OakUndoStack stack);
|
||||
|
||||
/**
|
||||
* @brief Query whether undo (redo) is currently possible.
|
||||
*
|
||||
* @param out_value Receives 1/0. Must not be NULL.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_can_undo(OakUndoStack stack, int *out_value);
|
||||
int oakundo_undostack_can_redo(OakUndoStack stack, int *out_value);
|
||||
|
||||
/**
|
||||
* @brief Total number of history rows (done + undone commands).
|
||||
*
|
||||
* @param out_count Receives the result. Must not be NULL.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_count(OakUndoStack stack, int64_t *out_count);
|
||||
|
||||
/**
|
||||
* @brief Current position in the history: the number of done commands
|
||||
* (rows at or above this index are undone).
|
||||
*
|
||||
* @param out_index Receives the result. Must not be NULL.
|
||||
*
|
||||
* @return OAKUNDO_OK or a negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_index(OakUndoStack stack, int64_t *out_index);
|
||||
|
||||
/**
|
||||
* @brief Label of the history row at `row` (0-based, two-stage getter).
|
||||
*
|
||||
* @return Required buffer size in bytes including the terminating NUL
|
||||
* (non-negative), OAKUNDO_E_NOT_FOUND for an invalid row, or
|
||||
* another negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_command_text(OakUndoStack stack, int64_t row,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Query whether the row at `row` is currently done (not undone).
|
||||
*
|
||||
* @param out_value Receives 1 (done) / 0 (undone). Must not be NULL.
|
||||
*
|
||||
* @return OAKUNDO_OK, OAKUNDO_E_NOT_FOUND for an invalid row, or another
|
||||
* negative OAKUNDO_E_* error code.
|
||||
*/
|
||||
int oakundo_undostack_command_is_done(OakUndoStack stack, int64_t row,
|
||||
int *out_value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_UNDO_UNDOSTACK_H
|
||||
Reference in New Issue
Block a user