core: turn olivecore into liboakcore.so with a pure C ABI
liboakcore is now a shared library that exposes only a C ABI: - every value class (Rational, TimeRange, Color, Bezier, AudioParams, SampleBuffer) and the free-function groups (StringUtils, fraction utils, Timecode) is wrapped in an opaque-handle C API under core/include/olive/core/oakcore/ (init/copy/free + self-first functions), implemented in core/src/capi/ - consumers keep the original C++ API unchanged through same-name wrapper classes that hold the handle and forward across the C boundary; original implementations moved to core/src/oliveimpl (namespace olive::core::internal) and are hidden from export - TimeRangeList/TimeRangeListFrameIterator are reimplemented inline over the wrapper (iterators/containers don't cross C ABI) - generic Value container stays internal (unused by consumers) and is no longer part of the public umbrella header - hidden visibility + OAKCORE_BUILD export macro; nm shows zero olive::* symbols exported - install into the platform's standard libdir (GNUInstallDirs); Windows DLLs next to the executables, macOS into the app bundle - TimelineWorkArea::in/out/length now return by value: the wrapped TimeRange getters return values, and forwarding them through const references dangled (found via RenderWorkerFootageTest crash) - tests: 9 new pure C ABI test executables (oakcore_*_test) covering every public C function; 4 stale legacy core tests removed (they targeted a long-renamed API and were never built due to a malformed option() that also kept OLIVECORE_BUILD_TESTS off) - CI/CD: oakcore.dll staged for NSIS, liboakcore.so added to the AppImage validation list, build-tree DLL copies on Windows
This commit is contained in:
@@ -0,0 +1,315 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/audioparams.h"
|
||||
|
||||
#include "render/audioparams.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::AudioParams *impl(OakAudioParams *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::AudioParams *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::AudioParams *impl(const OakAudioParams *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::AudioParams *>(h);
|
||||
}
|
||||
|
||||
OakAudioParams *wrap(olive::core::internal::AudioParams *p)
|
||||
{
|
||||
return reinterpret_cast<OakAudioParams *>(p);
|
||||
}
|
||||
|
||||
const olive::core::internal::Rational *impl(const OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
OakRational *wrap(olive::core::internal::Rational *r)
|
||||
{
|
||||
return reinterpret_cast<OakRational *>(r);
|
||||
}
|
||||
|
||||
olive::core::SampleFormat to_format(int f)
|
||||
{
|
||||
return olive::core::SampleFormat(
|
||||
static_cast<olive::core::SampleFormat::Format>(f));
|
||||
}
|
||||
|
||||
// The supported channel layouts / sample rates as constant data. These
|
||||
// mirror AudioParams::k_supported_channel_layouts /
|
||||
// k_supported_sample_rates (src/render/audioparams.cpp) and must be kept in
|
||||
// sync with them. The C API serves these instead of reading the
|
||||
// implementation's std::vector statics directly so that the functions are
|
||||
// safe to call during a consumer's static initialization even when
|
||||
// liboakcore is linked statically (cross-TU static init order is
|
||||
// unspecified; the implementation's vectors may not be constructed yet).
|
||||
constexpr uint64_t k_supported_channel_layouts[] = {
|
||||
olive::core::k_channel_layout_mono,
|
||||
olive::core::k_channel_layout_stereo,
|
||||
olive::core::k_channel_layout2_1,
|
||||
olive::core::k_channel_layout5_point1,
|
||||
olive::core::k_channel_layout7_point1,
|
||||
};
|
||||
|
||||
constexpr int k_supported_sample_rates[] = {
|
||||
8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 88200, 96000,
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
T at_or_zero(const T (&arr)[N], int index)
|
||||
{
|
||||
if (index < 0 || size_t(index) >= N) {
|
||||
return 0;
|
||||
}
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakAudioParams *oakcore_audioparams_create(int sample_rate,
|
||||
uint64_t channel_layout, int format)
|
||||
{
|
||||
return wrap(new olive::core::internal::AudioParams(
|
||||
sample_rate, channel_layout, to_format(format)));
|
||||
}
|
||||
|
||||
OakAudioParams *oakcore_audioparams_create_invalid(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::AudioParams());
|
||||
}
|
||||
|
||||
OakAudioParams *oakcore_audioparams_copy(const OakAudioParams *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::AudioParams(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_audioparams_free(OakAudioParams *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
int oakcore_audioparams_sample_rate(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->sample_rate();
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_sample_rate(OakAudioParams *self, int sample_rate)
|
||||
{
|
||||
impl(self)->set_sample_rate(sample_rate);
|
||||
}
|
||||
|
||||
uint64_t oakcore_audioparams_channel_layout(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->channel_layout();
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_channel_layout(OakAudioParams *self, uint64_t mask)
|
||||
{
|
||||
impl(self)->set_channel_layout(mask);
|
||||
}
|
||||
|
||||
OakRational *oakcore_audioparams_time_base(const OakAudioParams *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(impl(self)->time_base()));
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_time_base(OakAudioParams *self,
|
||||
const OakRational *timebase)
|
||||
{
|
||||
impl(self)->set_time_base(*impl(timebase));
|
||||
}
|
||||
|
||||
OakRational *oakcore_audioparams_sample_rate_as_time_base(
|
||||
const OakAudioParams *self)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::Rational(impl(self)->sample_rate_as_time_base()));
|
||||
}
|
||||
|
||||
int oakcore_audioparams_format(const OakAudioParams *self)
|
||||
{
|
||||
return int(impl(self)->format());
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_format(OakAudioParams *self, int format)
|
||||
{
|
||||
impl(self)->set_format(to_format(format));
|
||||
}
|
||||
|
||||
int oakcore_audioparams_enabled(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->enabled() ? 1 : 0;
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_enabled(OakAudioParams *self, int enabled)
|
||||
{
|
||||
impl(self)->set_enabled(enabled != 0);
|
||||
}
|
||||
|
||||
int oakcore_audioparams_stream_index(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->stream_index();
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_stream_index(OakAudioParams *self, int stream_index)
|
||||
{
|
||||
impl(self)->set_stream_index(stream_index);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_duration(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->duration();
|
||||
}
|
||||
|
||||
void oakcore_audioparams_set_duration(OakAudioParams *self, int64_t duration)
|
||||
{
|
||||
impl(self)->set_duration(duration);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_bytes(const OakAudioParams *self, double time)
|
||||
{
|
||||
return impl(self)->time_to_bytes(time);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_bytes_rational(const OakAudioParams *self,
|
||||
const OakRational *time)
|
||||
{
|
||||
return impl(self)->time_to_bytes(*impl(time));
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_bytes_per_channel(const OakAudioParams *self,
|
||||
double time)
|
||||
{
|
||||
return impl(self)->time_to_bytes_per_channel(time);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_bytes_per_channel_rational(
|
||||
const OakAudioParams *self, const OakRational *time)
|
||||
{
|
||||
return impl(self)->time_to_bytes_per_channel(*impl(time));
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_samples(const OakAudioParams *self,
|
||||
double time)
|
||||
{
|
||||
return impl(self)->time_to_samples(time);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_time_to_samples_rational(const OakAudioParams *self,
|
||||
const OakRational *time)
|
||||
{
|
||||
return impl(self)->time_to_samples(*impl(time));
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_samples_to_bytes(const OakAudioParams *self,
|
||||
int64_t samples)
|
||||
{
|
||||
return impl(self)->samples_to_bytes(samples);
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_samples_to_bytes_per_channel(
|
||||
const OakAudioParams *self, int64_t samples)
|
||||
{
|
||||
return impl(self)->samples_to_bytes_per_channel(samples);
|
||||
}
|
||||
|
||||
OakRational *oakcore_audioparams_samples_to_time(const OakAudioParams *self,
|
||||
int64_t samples)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::Rational(impl(self)->samples_to_time(samples)));
|
||||
}
|
||||
|
||||
int64_t oakcore_audioparams_bytes_to_samples(const OakAudioParams *self,
|
||||
int64_t bytes)
|
||||
{
|
||||
return impl(self)->bytes_to_samples(bytes);
|
||||
}
|
||||
|
||||
OakRational *oakcore_audioparams_bytes_to_time(const OakAudioParams *self,
|
||||
int64_t bytes)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::Rational(impl(self)->bytes_to_time(bytes)));
|
||||
}
|
||||
|
||||
OakRational *oakcore_audioparams_bytes_per_channel_to_time(
|
||||
const OakAudioParams *self, int64_t bytes)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(
|
||||
impl(self)->bytes_per_channel_to_time(bytes)));
|
||||
}
|
||||
|
||||
int oakcore_audioparams_channel_count(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->channel_count();
|
||||
}
|
||||
|
||||
int oakcore_audioparams_bytes_per_sample_per_channel(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->bytes_per_sample_per_channel();
|
||||
}
|
||||
|
||||
int oakcore_audioparams_bits_per_sample(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->bits_per_sample();
|
||||
}
|
||||
|
||||
int oakcore_audioparams_is_valid(const OakAudioParams *self)
|
||||
{
|
||||
return impl(self)->is_valid() ? 1 : 0;
|
||||
}
|
||||
|
||||
int oakcore_audioparams_equals(const OakAudioParams *self,
|
||||
const OakAudioParams *other)
|
||||
{
|
||||
return (*impl(self) == *impl(other)) ? 1 : 0;
|
||||
}
|
||||
|
||||
int oakcore_audioparams_supported_channel_layout_count(void)
|
||||
{
|
||||
return int(sizeof(k_supported_channel_layouts) /
|
||||
sizeof(k_supported_channel_layouts[0]));
|
||||
}
|
||||
|
||||
uint64_t oakcore_audioparams_supported_channel_layout_at(int index)
|
||||
{
|
||||
return at_or_zero(k_supported_channel_layouts, index);
|
||||
}
|
||||
|
||||
int oakcore_audioparams_supported_sample_rate_count(void)
|
||||
{
|
||||
return int(sizeof(k_supported_sample_rates) /
|
||||
sizeof(k_supported_sample_rates[0]));
|
||||
}
|
||||
|
||||
int oakcore_audioparams_supported_sample_rate_at(int index)
|
||||
{
|
||||
return at_or_zero(k_supported_sample_rates, index);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,157 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/bezier.h"
|
||||
|
||||
#include "util/bezier.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::Bezier *impl(OakBezier *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::Bezier *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::Bezier *impl(const OakBezier *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Bezier *>(h);
|
||||
}
|
||||
|
||||
OakBezier *wrap(olive::core::internal::Bezier *b)
|
||||
{
|
||||
return reinterpret_cast<OakBezier *>(b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakBezier *oakcore_bezier_create(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::Bezier());
|
||||
}
|
||||
|
||||
OakBezier *oakcore_bezier_create_xy(double x, double y)
|
||||
{
|
||||
return wrap(new olive::core::internal::Bezier(x, y));
|
||||
}
|
||||
|
||||
OakBezier *oakcore_bezier_create_full(double x, double y, double cp1_x,
|
||||
double cp1_y, double cp2_x, double cp2_y)
|
||||
{
|
||||
return wrap(new olive::core::internal::Bezier(x, y, cp1_x, cp1_y, cp2_x,
|
||||
cp2_y));
|
||||
}
|
||||
|
||||
OakBezier *oakcore_bezier_copy(const OakBezier *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::Bezier(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_bezier_free(OakBezier *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
double oakcore_bezier_x(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->x();
|
||||
}
|
||||
|
||||
double oakcore_bezier_y(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->y();
|
||||
}
|
||||
|
||||
double oakcore_bezier_cp1_x(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->cp1_x();
|
||||
}
|
||||
|
||||
double oakcore_bezier_cp1_y(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->cp1_y();
|
||||
}
|
||||
|
||||
double oakcore_bezier_cp2_x(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->cp2_x();
|
||||
}
|
||||
|
||||
double oakcore_bezier_cp2_y(const OakBezier *self)
|
||||
{
|
||||
return impl(self)->cp2_y();
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_x(OakBezier *self, double x)
|
||||
{
|
||||
impl(self)->set_x(x);
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_y(OakBezier *self, double y)
|
||||
{
|
||||
impl(self)->set_y(y);
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_cp1_x(OakBezier *self, double cp1_x)
|
||||
{
|
||||
impl(self)->set_cp1_x(cp1_x);
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_cp1_y(OakBezier *self, double cp1_y)
|
||||
{
|
||||
impl(self)->set_cp1_y(cp1_y);
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_cp2_x(OakBezier *self, double cp2_x)
|
||||
{
|
||||
impl(self)->set_cp2_x(cp2_x);
|
||||
}
|
||||
|
||||
void oakcore_bezier_set_cp2_y(OakBezier *self, double cp2_y)
|
||||
{
|
||||
impl(self)->set_cp2_y(cp2_y);
|
||||
}
|
||||
|
||||
double oakcore_bezier_quadratic_xto_t(double x, double a, double b, double c)
|
||||
{
|
||||
return olive::core::internal::Bezier::quadratic_xto_t(x, a, b, c);
|
||||
}
|
||||
|
||||
double oakcore_bezier_quadratic_tto_y(double a, double b, double c, double t)
|
||||
{
|
||||
return olive::core::internal::Bezier::quadratic_tto_y(a, b, c, t);
|
||||
}
|
||||
|
||||
double oakcore_bezier_cubic_xto_t(double x, double a, double b, double c,
|
||||
double d)
|
||||
{
|
||||
return olive::core::internal::Bezier::cubic_xto_t(x, a, b, c, d);
|
||||
}
|
||||
|
||||
double oakcore_bezier_cubic_tto_y(double a, double b, double c, double d,
|
||||
double t)
|
||||
{
|
||||
return olive::core::internal::Bezier::cubic_tto_y(a, b, c, d, t);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,220 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/color.h"
|
||||
|
||||
#include "util/color.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::Color *impl(OakColor *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::Color *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::Color *impl(const OakColor *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Color *>(h);
|
||||
}
|
||||
|
||||
OakColor *wrap(olive::core::internal::Color *c)
|
||||
{
|
||||
return reinterpret_cast<OakColor *>(c);
|
||||
}
|
||||
|
||||
olive::core::PixelFormat to_format(int f)
|
||||
{
|
||||
return olive::core::PixelFormat(
|
||||
static_cast<olive::core::PixelFormat::Format>(f));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakColor *oakcore_color_create(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::Color());
|
||||
}
|
||||
|
||||
OakColor *oakcore_color_create_rgba(float r, float g, float b, float a)
|
||||
{
|
||||
return wrap(new olive::core::internal::Color(r, g, b, a));
|
||||
}
|
||||
|
||||
OakColor *oakcore_color_copy(const OakColor *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::Color(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_color_free(OakColor *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
OakColor *oakcore_color_from_hsv(float h, float s, float v)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::Color(olive::core::internal::Color::from_hsv(h, s, v)));
|
||||
}
|
||||
|
||||
OakColor *oakcore_color_from_data(const char *data, int format, int nb_channels)
|
||||
{
|
||||
return wrap(new olive::core::internal::Color(
|
||||
olive::core::internal::Color::from_data(data, to_format(format),
|
||||
static_cast<unsigned int>(nb_channels))));
|
||||
}
|
||||
|
||||
float oakcore_color_red(const OakColor *self)
|
||||
{
|
||||
return impl(self)->red();
|
||||
}
|
||||
|
||||
float oakcore_color_green(const OakColor *self)
|
||||
{
|
||||
return impl(self)->green();
|
||||
}
|
||||
|
||||
float oakcore_color_blue(const OakColor *self)
|
||||
{
|
||||
return impl(self)->blue();
|
||||
}
|
||||
|
||||
float oakcore_color_alpha(const OakColor *self)
|
||||
{
|
||||
return impl(self)->alpha();
|
||||
}
|
||||
|
||||
void oakcore_color_set_red(OakColor *self, float red)
|
||||
{
|
||||
impl(self)->set_red(red);
|
||||
}
|
||||
|
||||
void oakcore_color_set_green(OakColor *self, float green)
|
||||
{
|
||||
impl(self)->set_green(green);
|
||||
}
|
||||
|
||||
void oakcore_color_set_blue(OakColor *self, float blue)
|
||||
{
|
||||
impl(self)->set_blue(blue);
|
||||
}
|
||||
|
||||
void oakcore_color_set_alpha(OakColor *self, float alpha)
|
||||
{
|
||||
impl(self)->set_alpha(alpha);
|
||||
}
|
||||
|
||||
void oakcore_color_to_hsv(const OakColor *self, float *hue, float *sat, float *val)
|
||||
{
|
||||
impl(self)->to_hsv(hue, sat, val);
|
||||
}
|
||||
|
||||
float oakcore_color_hsv_hue(const OakColor *self)
|
||||
{
|
||||
return impl(self)->hsv_hue();
|
||||
}
|
||||
|
||||
float oakcore_color_hsv_saturation(const OakColor *self)
|
||||
{
|
||||
return impl(self)->hsv_saturation();
|
||||
}
|
||||
|
||||
float oakcore_color_value(const OakColor *self)
|
||||
{
|
||||
return impl(self)->value();
|
||||
}
|
||||
|
||||
void oakcore_color_to_hsl(const OakColor *self, float *hue, float *sat,
|
||||
float *lightness)
|
||||
{
|
||||
impl(self)->to_hsl(hue, sat, lightness);
|
||||
}
|
||||
|
||||
float oakcore_color_hsl_hue(const OakColor *self)
|
||||
{
|
||||
return impl(self)->hsl_hue();
|
||||
}
|
||||
|
||||
float oakcore_color_hsl_saturation(const OakColor *self)
|
||||
{
|
||||
return impl(self)->hsl_saturation();
|
||||
}
|
||||
|
||||
float oakcore_color_lightness(const OakColor *self)
|
||||
{
|
||||
return impl(self)->lightness();
|
||||
}
|
||||
|
||||
float *oakcore_color_data(OakColor *self)
|
||||
{
|
||||
return impl(self)->data();
|
||||
}
|
||||
|
||||
const float *oakcore_color_const_data(const OakColor *self)
|
||||
{
|
||||
return impl(self)->data();
|
||||
}
|
||||
|
||||
void oakcore_color_to_data(const OakColor *self, char *out, int format,
|
||||
int nb_channels)
|
||||
{
|
||||
impl(self)->to_data(out, to_format(format),
|
||||
static_cast<unsigned int>(nb_channels));
|
||||
}
|
||||
|
||||
float oakcore_color_get_rough_luminance(const OakColor *self)
|
||||
{
|
||||
return impl(self)->get_rough_luminance();
|
||||
}
|
||||
|
||||
void oakcore_color_add_assign(OakColor *self, const OakColor *other)
|
||||
{
|
||||
*impl(self) += *impl(other);
|
||||
}
|
||||
|
||||
void oakcore_color_sub_assign(OakColor *self, const OakColor *other)
|
||||
{
|
||||
*impl(self) -= *impl(other);
|
||||
}
|
||||
|
||||
void oakcore_color_add_scalar_assign(OakColor *self, float value)
|
||||
{
|
||||
*impl(self) += value;
|
||||
}
|
||||
|
||||
void oakcore_color_sub_scalar_assign(OakColor *self, float value)
|
||||
{
|
||||
*impl(self) -= value;
|
||||
}
|
||||
|
||||
void oakcore_color_mul_scalar_assign(OakColor *self, float value)
|
||||
{
|
||||
*impl(self) *= value;
|
||||
}
|
||||
|
||||
void oakcore_color_div_scalar_assign(OakColor *self, float value)
|
||||
{
|
||||
*impl(self) /= value;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,53 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/fractionutils.h"
|
||||
|
||||
#include "util/fractionutils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::FractionRounding impl(OakFractionRounding rnd)
|
||||
{
|
||||
return static_cast<olive::core::internal::FractionRounding>(rnd);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
void oakcore_fractionutils_reduce_fraction(int64_t *num, int64_t *den, int64_t max)
|
||||
{
|
||||
olive::core::internal::reduce_fraction(*num, *den, max);
|
||||
}
|
||||
|
||||
int oakcore_fractionutils_compare_fractions(int an, int ad, int bn, int bd)
|
||||
{
|
||||
return olive::core::internal::compare_fractions(an, ad, bn, bd);
|
||||
}
|
||||
|
||||
int64_t oakcore_fractionutils_rescale_rnd(int64_t a, int64_t b, int64_t c, OakFractionRounding rnd)
|
||||
{
|
||||
return olive::core::internal::rescale_rnd(a, b, c, impl(rnd));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,172 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/rational.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/rational.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::Rational *impl(OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::Rational *impl(const OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
OakRational *wrap(olive::core::internal::Rational *r)
|
||||
{
|
||||
return reinterpret_cast<OakRational *>(r);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakRational *oakcore_rational_create(int numerator)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(numerator));
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_create_nd(int numerator, int denominator)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(numerator, denominator));
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_create_nan(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(olive::core::internal::Rational::na_n));
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_copy(const OakRational *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_rational_free(OakRational *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
int oakcore_rational_numerator(const OakRational *self)
|
||||
{
|
||||
return impl(self)->numerator();
|
||||
}
|
||||
|
||||
int oakcore_rational_denominator(const OakRational *self)
|
||||
{
|
||||
return impl(self)->denominator();
|
||||
}
|
||||
|
||||
double oakcore_rational_to_double(const OakRational *self)
|
||||
{
|
||||
return impl(self)->to_double();
|
||||
}
|
||||
|
||||
int oakcore_rational_to_string(const OakRational *self, char *buf, int buf_size)
|
||||
{
|
||||
const std::string s = impl(self)->to_string();
|
||||
if (buf && buf_size > 0) {
|
||||
snprintf(buf, size_t(buf_size), "%s", s.c_str());
|
||||
}
|
||||
return int(s.size());
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_from_double(double value, int *ok)
|
||||
{
|
||||
bool b = false;
|
||||
olive::core::internal::Rational *r =
|
||||
new olive::core::internal::Rational(olive::core::internal::Rational::from_double(value, &b));
|
||||
if (ok) {
|
||||
*ok = b ? 1 : 0;
|
||||
}
|
||||
return wrap(r);
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_from_string(const char *str, int *ok)
|
||||
{
|
||||
bool b = false;
|
||||
olive::core::internal::Rational *r = new olive::core::internal::Rational(
|
||||
olive::core::internal::Rational::from_string(str ? str : "", &b));
|
||||
if (ok) {
|
||||
*ok = b ? 1 : 0;
|
||||
}
|
||||
return wrap(r);
|
||||
}
|
||||
|
||||
int oakcore_rational_is_null(const OakRational *self)
|
||||
{
|
||||
return impl(self)->isNull() ? 1 : 0;
|
||||
}
|
||||
|
||||
int oakcore_rational_is_nan(const OakRational *self)
|
||||
{
|
||||
return impl(self)->isNaN() ? 1 : 0;
|
||||
}
|
||||
|
||||
OakRational *oakcore_rational_flipped(const OakRational *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(impl(self)->flipped()));
|
||||
}
|
||||
|
||||
void oakcore_rational_flip(OakRational *self)
|
||||
{
|
||||
impl(self)->flip();
|
||||
}
|
||||
|
||||
void oakcore_rational_add_assign(OakRational *self, const OakRational *other)
|
||||
{
|
||||
*impl(self) += *impl(other);
|
||||
}
|
||||
|
||||
void oakcore_rational_sub_assign(OakRational *self, const OakRational *other)
|
||||
{
|
||||
*impl(self) -= *impl(other);
|
||||
}
|
||||
|
||||
void oakcore_rational_mul_assign(OakRational *self, const OakRational *other)
|
||||
{
|
||||
*impl(self) *= *impl(other);
|
||||
}
|
||||
|
||||
void oakcore_rational_div_assign(OakRational *self, const OakRational *other)
|
||||
{
|
||||
*impl(self) /= *impl(other);
|
||||
}
|
||||
|
||||
int oakcore_rational_compare(const OakRational *self, const OakRational *other)
|
||||
{
|
||||
if (*impl(self) < *impl(other)) {
|
||||
return -1;
|
||||
}
|
||||
if (*impl(other) < *impl(self)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,272 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/samplebuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "render/audioparams.h"
|
||||
#include "render/samplebuffer.h"
|
||||
#include "util/rational.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::SampleBuffer *impl(OakSampleBuffer *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::SampleBuffer *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::SampleBuffer *impl(const OakSampleBuffer *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::SampleBuffer *>(h);
|
||||
}
|
||||
|
||||
OakSampleBuffer *wrap(olive::core::internal::SampleBuffer *b)
|
||||
{
|
||||
return reinterpret_cast<OakSampleBuffer *>(b);
|
||||
}
|
||||
|
||||
const olive::core::internal::AudioParams *apimpl(const OakAudioParams *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::AudioParams *>(h);
|
||||
}
|
||||
|
||||
OakAudioParams *apwrap(olive::core::internal::AudioParams *p)
|
||||
{
|
||||
return reinterpret_cast<OakAudioParams *>(p);
|
||||
}
|
||||
|
||||
const olive::core::internal::Rational *rimpl(const OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakSampleBuffer *oakcore_samplebuffer_create(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::SampleBuffer());
|
||||
}
|
||||
|
||||
OakSampleBuffer *oakcore_samplebuffer_create_length(
|
||||
const OakAudioParams *params, const OakRational *length)
|
||||
{
|
||||
return wrap(new olive::core::internal::SampleBuffer(*apimpl(params),
|
||||
*rimpl(length)));
|
||||
}
|
||||
|
||||
OakSampleBuffer *oakcore_samplebuffer_create_samples(
|
||||
const OakAudioParams *params, size_t samples_per_channel)
|
||||
{
|
||||
return wrap(new olive::core::internal::SampleBuffer(*apimpl(params),
|
||||
samples_per_channel));
|
||||
}
|
||||
|
||||
OakSampleBuffer *oakcore_samplebuffer_copy(const OakSampleBuffer *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::SampleBuffer(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_free(OakSampleBuffer *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
OakSampleBuffer *oakcore_samplebuffer_rip_channel(const OakSampleBuffer *self,
|
||||
int channel)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::SampleBuffer(impl(self)->rip_channel(channel)));
|
||||
}
|
||||
|
||||
int oakcore_samplebuffer_rip_channel_vector(const OakSampleBuffer *self,
|
||||
int channel, float *out,
|
||||
int out_size)
|
||||
{
|
||||
const std::vector<float> v = impl(self)->rip_channel_vector(channel);
|
||||
if (out && out_size > 0) {
|
||||
const size_t n = std::min(v.size(), size_t(out_size));
|
||||
std::copy(v.begin(), v.begin() + n, out);
|
||||
}
|
||||
return int(v.size());
|
||||
}
|
||||
|
||||
OakAudioParams *oakcore_samplebuffer_audio_params(const OakSampleBuffer *self)
|
||||
{
|
||||
return apwrap(
|
||||
new olive::core::internal::AudioParams(impl(self)->audio_params()));
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_set_audio_params(OakSampleBuffer *self,
|
||||
const OakAudioParams *params)
|
||||
{
|
||||
impl(self)->set_audio_params(*apimpl(params));
|
||||
}
|
||||
|
||||
size_t oakcore_samplebuffer_sample_count(const OakSampleBuffer *self)
|
||||
{
|
||||
return impl(self)->sample_count();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_set_sample_count(OakSampleBuffer *self,
|
||||
size_t sample_count)
|
||||
{
|
||||
impl(self)->set_sample_count(sample_count);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_set_sample_count_length(OakSampleBuffer *self,
|
||||
const OakRational *length)
|
||||
{
|
||||
impl(self)->set_sample_count(*rimpl(length));
|
||||
}
|
||||
|
||||
float *oakcore_samplebuffer_data(OakSampleBuffer *self, int channel)
|
||||
{
|
||||
if (!impl(self)->is_allocated() || channel < 0 ||
|
||||
channel >= impl(self)->channel_count()) {
|
||||
return nullptr;
|
||||
}
|
||||
return impl(self)->data(channel);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_to_raw_ptrs(OakSampleBuffer *self, float **out)
|
||||
{
|
||||
if (!out) {
|
||||
return;
|
||||
}
|
||||
const std::vector<float *> ptrs = impl(self)->to_raw_ptrs();
|
||||
std::copy(ptrs.begin(), ptrs.end(), out);
|
||||
}
|
||||
|
||||
int oakcore_samplebuffer_channel_count(const OakSampleBuffer *self)
|
||||
{
|
||||
return impl(self)->channel_count();
|
||||
}
|
||||
|
||||
int oakcore_samplebuffer_is_allocated(const OakSampleBuffer *self)
|
||||
{
|
||||
return impl(self)->is_allocated() ? 1 : 0;
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_allocate(OakSampleBuffer *self)
|
||||
{
|
||||
impl(self)->allocate();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_destroy(OakSampleBuffer *self)
|
||||
{
|
||||
impl(self)->destroy();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_reverse(OakSampleBuffer *self)
|
||||
{
|
||||
impl(self)->reverse();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_speed(OakSampleBuffer *self, double speed)
|
||||
{
|
||||
impl(self)->speed(speed);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume(OakSampleBuffer *self, float f)
|
||||
{
|
||||
impl(self)->transform_volume(f);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume_for_channel(OakSampleBuffer *self,
|
||||
int channel,
|
||||
float volume)
|
||||
{
|
||||
impl(self)->transform_volume_for_channel(channel, volume);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume_to(float f,
|
||||
const OakSampleBuffer *input,
|
||||
OakSampleBuffer *output)
|
||||
{
|
||||
olive::core::internal::SampleBuffer::transform_volume(f, impl(input),
|
||||
impl(output));
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume_for_channel_to(
|
||||
int channel, float volume, const OakSampleBuffer *input,
|
||||
OakSampleBuffer *output)
|
||||
{
|
||||
olive::core::internal::SampleBuffer::transform_volume_for_channel(
|
||||
channel, volume, impl(input), impl(output));
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume_for_sample(OakSampleBuffer *self,
|
||||
size_t sample_index,
|
||||
float volume)
|
||||
{
|
||||
impl(self)->transform_volume_for_sample(sample_index, volume);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_transform_volume_for_sample_on_channel(
|
||||
OakSampleBuffer *self, size_t sample_index, int channel, float volume)
|
||||
{
|
||||
impl(self)->transform_volume_for_sample_on_channel(sample_index, channel,
|
||||
volume);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_clamp(OakSampleBuffer *self)
|
||||
{
|
||||
impl(self)->clamp();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_silence(OakSampleBuffer *self)
|
||||
{
|
||||
impl(self)->silence();
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_silence_range(OakSampleBuffer *self,
|
||||
size_t start_sample,
|
||||
size_t end_sample)
|
||||
{
|
||||
impl(self)->silence(start_sample, end_sample);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_silence_bytes(OakSampleBuffer *self,
|
||||
size_t start_byte, size_t end_byte)
|
||||
{
|
||||
impl(self)->silence_bytes(start_byte, end_byte);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_set(OakSampleBuffer *self, int channel,
|
||||
const float *data, size_t sample_offset,
|
||||
size_t sample_length)
|
||||
{
|
||||
impl(self)->set(channel, data, sample_offset, sample_length);
|
||||
}
|
||||
|
||||
void oakcore_samplebuffer_fast_set(OakSampleBuffer *self,
|
||||
const OakSampleBuffer *other, int to,
|
||||
int from)
|
||||
{
|
||||
impl(self)->fast_set(*impl(other), to, from);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,123 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/stringutils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util/stringutils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
char **copy_string_vector(const std::vector<std::string> &v, int *count)
|
||||
{
|
||||
char **arr = static_cast<char **>(malloc(sizeof(char *) * v.size()));
|
||||
if (!arr) {
|
||||
*count = 0;
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < v.size(); i++) {
|
||||
arr[i] = static_cast<char *>(malloc(v[i].size() + 1));
|
||||
if (!arr[i]) {
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
free(arr[j]);
|
||||
}
|
||||
free(arr);
|
||||
*count = 0;
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(arr[i], v[i].c_str(), v[i].size() + 1);
|
||||
}
|
||||
*count = int(v.size());
|
||||
return arr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
char **oakcore_stringutils_split(const char *s, char separator, int *count)
|
||||
{
|
||||
const std::vector<std::string> v =
|
||||
olive::core::internal::StringUtils::split(s ? s : "", separator);
|
||||
return copy_string_vector(v, count);
|
||||
}
|
||||
|
||||
char **oakcore_stringutils_split_regex(const char *s, const char *pattern,
|
||||
int *count)
|
||||
{
|
||||
const std::vector<std::string> v =
|
||||
olive::core::internal::StringUtils::split_regex(
|
||||
s ? s : "", std::regex(pattern ? pattern : ""));
|
||||
return copy_string_vector(v, count);
|
||||
}
|
||||
|
||||
void oakcore_stringutils_free_string_array(char **arr, int count)
|
||||
{
|
||||
if (!arr) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; i++) {
|
||||
free(arr[i]);
|
||||
}
|
||||
free(arr);
|
||||
}
|
||||
|
||||
int oakcore_stringutils_to_int(const char *s, int base, int *ok)
|
||||
{
|
||||
bool b = false;
|
||||
const int x = olive::core::internal::StringUtils::to_int(s ? s : "", base, &b);
|
||||
if (ok) {
|
||||
*ok = b ? 1 : 0;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int oakcore_stringutils_format(char *buf, int buf_size, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
const int r = oakcore_stringutils_format_v(buf, buf_size, fmt, args);
|
||||
va_end(args);
|
||||
return r;
|
||||
}
|
||||
|
||||
int oakcore_stringutils_format_v(char *buf, int buf_size, const char *fmt,
|
||||
va_list args)
|
||||
{
|
||||
// The implementation class only exposes a variadic format(), so the
|
||||
// va_list form applies the same vsnprintf semantics directly here.
|
||||
va_list copy;
|
||||
va_copy(copy, args);
|
||||
const int needed =
|
||||
vsnprintf(buf, buf_size > 0 ? size_t(buf_size) : 0, fmt, copy);
|
||||
va_end(copy);
|
||||
return needed;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,157 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/timecodefunctions.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "util/rational.h"
|
||||
#include "util/timecodefunctions.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const olive::core::internal::Rational *impl(const OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
OakRational *wrap(olive::core::internal::Rational *r)
|
||||
{
|
||||
return reinterpret_cast<OakRational *>(r);
|
||||
}
|
||||
|
||||
olive::core::internal::Timecode::Display to_display(OakTimecodeDisplay d)
|
||||
{
|
||||
return static_cast<olive::core::internal::Timecode::Display>(d);
|
||||
}
|
||||
|
||||
olive::core::internal::Timecode::Rounding to_rounding(OakTimecodeRounding r)
|
||||
{
|
||||
return static_cast<olive::core::internal::Timecode::Rounding>(r);
|
||||
}
|
||||
|
||||
int write_string(const std::string &s, char *buf, int buf_size)
|
||||
{
|
||||
if (buf && buf_size > 0) {
|
||||
snprintf(buf, size_t(buf_size), "%s", s.c_str());
|
||||
}
|
||||
return int(s.size());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
int oakcore_timecode_time_to_timecode(const OakRational *time,
|
||||
const OakRational *timebase,
|
||||
OakTimecodeDisplay display,
|
||||
int show_plus_if_positive, char *buf,
|
||||
int buf_size)
|
||||
{
|
||||
const std::string s = olive::core::internal::Timecode::time_to_timecode(
|
||||
*impl(time), *impl(timebase), to_display(display),
|
||||
show_plus_if_positive != 0);
|
||||
return write_string(s, buf, buf_size);
|
||||
}
|
||||
|
||||
OakRational *oakcore_timecode_timecode_to_time(const char *timecode,
|
||||
const OakRational *timebase,
|
||||
OakTimecodeDisplay display,
|
||||
int *ok)
|
||||
{
|
||||
bool b = false;
|
||||
olive::core::internal::Rational *r = new olive::core::internal::Rational(
|
||||
olive::core::internal::Timecode::timecode_to_time(
|
||||
timecode ? timecode : "", *impl(timebase), to_display(display),
|
||||
&b));
|
||||
if (ok) {
|
||||
*ok = b ? 1 : 0;
|
||||
}
|
||||
return wrap(r);
|
||||
}
|
||||
|
||||
int oakcore_timecode_time_to_string(int64_t ms, char *buf, int buf_size)
|
||||
{
|
||||
return write_string(olive::core::internal::Timecode::time_to_string(ms),
|
||||
buf, buf_size);
|
||||
}
|
||||
|
||||
OakRational *oakcore_timecode_snap_time_to_timebase(const OakRational *time,
|
||||
const OakRational *timebase,
|
||||
OakTimecodeRounding rounding)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(
|
||||
olive::core::internal::Timecode::snap_time_to_timebase(
|
||||
*impl(time), *impl(timebase), to_rounding(rounding))));
|
||||
}
|
||||
|
||||
int64_t oakcore_timecode_time_to_timestamp(const OakRational *time,
|
||||
const OakRational *timebase,
|
||||
OakTimecodeRounding rounding)
|
||||
{
|
||||
return olive::core::internal::Timecode::time_to_timestamp(
|
||||
*impl(time), *impl(timebase), to_rounding(rounding));
|
||||
}
|
||||
|
||||
int64_t oakcore_timecode_time_to_timestamp_d(double time,
|
||||
const OakRational *timebase,
|
||||
OakTimecodeRounding rounding)
|
||||
{
|
||||
return olive::core::internal::Timecode::time_to_timestamp(
|
||||
time, *impl(timebase), to_rounding(rounding));
|
||||
}
|
||||
|
||||
int64_t oakcore_timecode_rescale_timestamp(int64_t ts,
|
||||
const OakRational *source,
|
||||
const OakRational *dest)
|
||||
{
|
||||
return olive::core::internal::Timecode::rescale_timestamp(
|
||||
ts, *impl(source), *impl(dest));
|
||||
}
|
||||
|
||||
int64_t oakcore_timecode_rescale_timestamp_ceil(int64_t ts,
|
||||
const OakRational *source,
|
||||
const OakRational *dest)
|
||||
{
|
||||
return olive::core::internal::Timecode::rescale_timestamp_ceil(
|
||||
ts, *impl(source), *impl(dest));
|
||||
}
|
||||
|
||||
OakRational *oakcore_timecode_timestamp_to_time(int64_t timestamp,
|
||||
const OakRational *timebase)
|
||||
{
|
||||
return wrap(new olive::core::internal::Rational(
|
||||
olive::core::internal::Timecode::timestamp_to_time(timestamp,
|
||||
*impl(timebase))));
|
||||
}
|
||||
|
||||
int oakcore_timecode_timebase_is_drop_frame(const OakRational *timebase)
|
||||
{
|
||||
return olive::core::internal::Timecode::timebase_is_drop_frame(
|
||||
*impl(timebase))
|
||||
? 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,221 @@
|
||||
/***
|
||||
|
||||
Oak - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#include "oakcore/timerange.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "util/rational.h"
|
||||
#include "util/timerange.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
olive::core::internal::TimeRange *impl(OakTimeRange *h)
|
||||
{
|
||||
return reinterpret_cast<olive::core::internal::TimeRange *>(h);
|
||||
}
|
||||
|
||||
const olive::core::internal::TimeRange *impl(const OakTimeRange *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::TimeRange *>(h);
|
||||
}
|
||||
|
||||
OakTimeRange *wrap(olive::core::internal::TimeRange *r)
|
||||
{
|
||||
return reinterpret_cast<OakTimeRange *>(r);
|
||||
}
|
||||
|
||||
const olive::core::internal::Rational *rimpl(const OakRational *h)
|
||||
{
|
||||
return reinterpret_cast<const olive::core::internal::Rational *>(h);
|
||||
}
|
||||
|
||||
OakRational *rwrap(olive::core::internal::Rational *r)
|
||||
{
|
||||
return reinterpret_cast<OakRational *>(r);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
OakTimeRange *oakcore_timerange_create(void)
|
||||
{
|
||||
return wrap(new olive::core::internal::TimeRange());
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_create_io(const OakRational *in,
|
||||
const OakRational *out)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::TimeRange(*rimpl(in), *rimpl(out)));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_copy(const OakTimeRange *self)
|
||||
{
|
||||
return wrap(new olive::core::internal::TimeRange(*impl(self)));
|
||||
}
|
||||
|
||||
void oakcore_timerange_free(OakTimeRange *self)
|
||||
{
|
||||
delete impl(self);
|
||||
}
|
||||
|
||||
OakRational *oakcore_timerange_in(const OakTimeRange *self)
|
||||
{
|
||||
return rwrap(new olive::core::internal::Rational(impl(self)->in()));
|
||||
}
|
||||
|
||||
OakRational *oakcore_timerange_out(const OakTimeRange *self)
|
||||
{
|
||||
return rwrap(new olive::core::internal::Rational(impl(self)->out()));
|
||||
}
|
||||
|
||||
OakRational *oakcore_timerange_length(const OakTimeRange *self)
|
||||
{
|
||||
return rwrap(new olive::core::internal::Rational(impl(self)->length()));
|
||||
}
|
||||
|
||||
void oakcore_timerange_set_in(OakTimeRange *self, const OakRational *in)
|
||||
{
|
||||
impl(self)->set_in(*rimpl(in));
|
||||
}
|
||||
|
||||
void oakcore_timerange_set_out(OakTimeRange *self, const OakRational *out)
|
||||
{
|
||||
impl(self)->set_out(*rimpl(out));
|
||||
}
|
||||
|
||||
void oakcore_timerange_set_range(OakTimeRange *self, const OakRational *in,
|
||||
const OakRational *out)
|
||||
{
|
||||
impl(self)->set_range(*rimpl(in), *rimpl(out));
|
||||
}
|
||||
|
||||
int oakcore_timerange_equal(const OakTimeRange *self,
|
||||
const OakTimeRange *other)
|
||||
{
|
||||
return *impl(self) == *impl(other) ? 1 : 0;
|
||||
}
|
||||
|
||||
int oakcore_timerange_overlaps_with(const OakTimeRange *self,
|
||||
const OakTimeRange *other,
|
||||
int in_inclusive, int out_inclusive)
|
||||
{
|
||||
return impl(self)
|
||||
->overlaps_with(*impl(other), in_inclusive != 0,
|
||||
out_inclusive != 0) ?
|
||||
1 :
|
||||
0;
|
||||
}
|
||||
|
||||
int oakcore_timerange_contains_range(const OakTimeRange *self,
|
||||
const OakTimeRange *other,
|
||||
int in_inclusive, int out_inclusive)
|
||||
{
|
||||
return impl(self)
|
||||
->contains(*impl(other), in_inclusive != 0,
|
||||
out_inclusive != 0) ?
|
||||
1 :
|
||||
0;
|
||||
}
|
||||
|
||||
int oakcore_timerange_contains_time(const OakTimeRange *self,
|
||||
const OakRational *time)
|
||||
{
|
||||
return impl(self)->contains(*rimpl(time)) ? 1 : 0;
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_combined(const OakTimeRange *self,
|
||||
const OakTimeRange *other)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::TimeRange(impl(self)->combined(*impl(other))));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_combine(const OakTimeRange *a,
|
||||
const OakTimeRange *b)
|
||||
{
|
||||
return wrap(new olive::core::internal::TimeRange(
|
||||
olive::core::internal::TimeRange::combine(*impl(a), *impl(b))));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_intersected(const OakTimeRange *self,
|
||||
const OakTimeRange *other)
|
||||
{
|
||||
return wrap(new olive::core::internal::TimeRange(
|
||||
impl(self)->intersected(*impl(other))));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_intersect(const OakTimeRange *a,
|
||||
const OakTimeRange *b)
|
||||
{
|
||||
return wrap(new olive::core::internal::TimeRange(
|
||||
olive::core::internal::TimeRange::intersect(*impl(a), *impl(b))));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_add(const OakTimeRange *self,
|
||||
const OakRational *rhs)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::TimeRange(*impl(self) + *rimpl(rhs)));
|
||||
}
|
||||
|
||||
OakTimeRange *oakcore_timerange_sub(const OakTimeRange *self,
|
||||
const OakRational *rhs)
|
||||
{
|
||||
return wrap(
|
||||
new olive::core::internal::TimeRange(*impl(self) - *rimpl(rhs)));
|
||||
}
|
||||
|
||||
void oakcore_timerange_add_assign(OakTimeRange *self, const OakRational *rhs)
|
||||
{
|
||||
*impl(self) += *rimpl(rhs);
|
||||
}
|
||||
|
||||
void oakcore_timerange_sub_assign(OakTimeRange *self, const OakRational *rhs)
|
||||
{
|
||||
*impl(self) -= *rimpl(rhs);
|
||||
}
|
||||
|
||||
int oakcore_timerange_split_count(const OakTimeRange *self, int chunk_size)
|
||||
{
|
||||
return int(impl(self)->split(chunk_size).size());
|
||||
}
|
||||
|
||||
int oakcore_timerange_split(const OakTimeRange *self, int chunk_size,
|
||||
OakTimeRange **out_ranges, int out_size)
|
||||
{
|
||||
const std::list<olive::core::internal::TimeRange> ranges =
|
||||
impl(self)->split(chunk_size);
|
||||
int n = 0;
|
||||
for (const olive::core::internal::TimeRange &r : ranges) {
|
||||
if (out_ranges && n < out_size) {
|
||||
out_ranges[n] =
|
||||
wrap(new olive::core::internal::TimeRange(r));
|
||||
}
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -0,0 +1,217 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_AUDIOPARAMS_H
|
||||
#define OAK_LIBOLIVECORE_AUDIOPARAMS_H
|
||||
#include <cstring>
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
#include "render/channellayout.h"
|
||||
#include "render/sampleformat.h"
|
||||
#include "../util/rational.h"
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Audio parameters class managing audio stream configuration
|
||||
*
|
||||
* Channel layouts are stored as plain 64-bit masks (see channellayout.h).
|
||||
* Because the mask is a simple value type, AudioParams has value semantics
|
||||
* and can be copied freely.
|
||||
*/
|
||||
class AudioParams {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor creates invalid AudioParams
|
||||
* sample_rate=0, channel_layout empty, format=INVALID
|
||||
*/
|
||||
AudioParams()
|
||||
: sample_rate_(0)
|
||||
, channel_layout_mask_(0)
|
||||
, channel_count_(0)
|
||||
, format_(SampleFormat::invalid)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor from channel layout mask
|
||||
* @param sample_rate Audio sample rate
|
||||
* @param channel_layout Channel layout mask (e.g., kChannelLayoutStereo)
|
||||
* @param format Sample format
|
||||
*/
|
||||
AudioParams(const int &sample_rate, uint64_t channel_layout,
|
||||
const SampleFormat &format)
|
||||
: sample_rate_(sample_rate)
|
||||
, channel_layout_mask_(channel_layout)
|
||||
, channel_count_(0)
|
||||
, format_(format)
|
||||
{
|
||||
set_default_footage_parameters();
|
||||
timebase_ = sample_rate_as_time_base();
|
||||
calculate_channel_count();
|
||||
}
|
||||
int sample_rate() const
|
||||
{
|
||||
return sample_rate_;
|
||||
}
|
||||
|
||||
void set_sample_rate(int sample_rate)
|
||||
{
|
||||
sample_rate_ = sample_rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Channel layout as a 64-bit mask (0 if unspecified)
|
||||
*/
|
||||
const uint64_t &channel_layout() const
|
||||
{
|
||||
return channel_layout_mask_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set channel layout from mask
|
||||
* @param mask Channel layout mask (e.g., kChannelLayoutStereo)
|
||||
*/
|
||||
void set_channel_layout(uint64_t mask)
|
||||
{
|
||||
channel_layout_mask_ = mask;
|
||||
calculate_channel_count();
|
||||
}
|
||||
Rational time_base() const
|
||||
{
|
||||
return timebase_;
|
||||
}
|
||||
|
||||
void set_time_base(const Rational &timebase)
|
||||
{
|
||||
timebase_ = timebase;
|
||||
}
|
||||
|
||||
Rational sample_rate_as_time_base() const
|
||||
{
|
||||
return Rational(1, sample_rate());
|
||||
}
|
||||
|
||||
SampleFormat format() const
|
||||
{
|
||||
return format_;
|
||||
}
|
||||
|
||||
void set_format(SampleFormat format)
|
||||
{
|
||||
format_ = format;
|
||||
}
|
||||
|
||||
bool enabled() const
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
void set_enabled(bool e)
|
||||
{
|
||||
enabled_ = e;
|
||||
}
|
||||
|
||||
int stream_index() const
|
||||
{
|
||||
return stream_index_;
|
||||
}
|
||||
|
||||
void set_stream_index(int s)
|
||||
{
|
||||
stream_index_ = s;
|
||||
}
|
||||
|
||||
int64_t duration() const
|
||||
{
|
||||
return duration_;
|
||||
}
|
||||
|
||||
void set_duration(int64_t duration)
|
||||
{
|
||||
duration_ = duration;
|
||||
}
|
||||
|
||||
int64_t time_to_bytes(const double &time) const;
|
||||
int64_t time_to_bytes(const Rational &time) const;
|
||||
int64_t time_to_bytes_per_channel(const double &time) const;
|
||||
int64_t time_to_bytes_per_channel(const Rational &time) const;
|
||||
int64_t time_to_samples(const double &time) const;
|
||||
int64_t time_to_samples(const Rational &time) const;
|
||||
int64_t samples_to_bytes(const int64_t &samples) const;
|
||||
int64_t samples_to_bytes_per_channel(const int64_t &samples) const;
|
||||
Rational samples_to_time(const int64_t &samples) const;
|
||||
int64_t bytes_to_samples(const int64_t &bytes) const;
|
||||
Rational bytes_to_time(const int64_t &bytes) const;
|
||||
Rational bytes_per_channel_to_time(const int64_t &bytes) const;
|
||||
int channel_count() const;
|
||||
int bytes_per_sample_per_channel() const;
|
||||
int bits_per_sample() const;
|
||||
bool is_valid() const;
|
||||
|
||||
bool operator==(const AudioParams &other) const;
|
||||
bool operator!=(const AudioParams &other) const;
|
||||
|
||||
static const std::vector<uint64_t> k_supported_channel_layouts;
|
||||
static const std::vector<int> k_supported_sample_rates;
|
||||
|
||||
private:
|
||||
void set_default_footage_parameters()
|
||||
{
|
||||
enabled_ = true;
|
||||
stream_index_ = 0;
|
||||
duration_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates channel_count_ from the current channel_layout_mask_
|
||||
* Called after any channel layout modification.
|
||||
*/
|
||||
void calculate_channel_count();
|
||||
|
||||
int sample_rate_; ///< Audio sample rate in Hz (e.g., 48000)
|
||||
|
||||
/**
|
||||
* @brief Channel layout mask (0 if unspecified)
|
||||
*
|
||||
* Plain value type mirroring FFmpeg's AV_CH_LAYOUT_* masks; no dynamic
|
||||
* memory is involved, so copies are trivially safe.
|
||||
*/
|
||||
uint64_t channel_layout_mask_;
|
||||
|
||||
int channel_count_; ///< Cached channel count from layout
|
||||
|
||||
SampleFormat format_; ///< Audio sample format
|
||||
|
||||
// Footage-specific parameters (serialized with footage metadata)
|
||||
int enabled_; // Using int instead of bool fixes GCC 11 stringop-overflow issue (byte alignment)
|
||||
int stream_index_; ///< Index in the source file's stream list
|
||||
int64_t duration_; ///< Stream duration in timebase units
|
||||
Rational timebase_; ///< Timebase for this audio stream
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_AUDIOPARAMS_H
|
||||
@@ -0,0 +1,137 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_SAMPLEBUFFER_H
|
||||
#define OAK_LIBOLIVECORE_SAMPLEBUFFER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "audioparams.h"
|
||||
#include "../util/rational.h"
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A buffer of audio samples
|
||||
*
|
||||
* Audio samples in this structure are always stored in PLANAR (separated by channel). This is done to simplify audio
|
||||
* rendering code. This replaces the old system of using QByteArrays (containing packed audio) and while SampleBuffer
|
||||
* replaces many of those in the rendering/processing side of things, QByteArrays are currently still in use for
|
||||
* playback, including reading to and from the cache.
|
||||
*/
|
||||
class SampleBuffer {
|
||||
public:
|
||||
SampleBuffer();
|
||||
SampleBuffer(const AudioParams &audio_params, const Rational &length);
|
||||
SampleBuffer(const AudioParams &audio_params, size_t samples_per_channel);
|
||||
|
||||
SampleBuffer rip_channel(int channel) const;
|
||||
std::vector<float> rip_channel_vector(int channel) const;
|
||||
|
||||
const AudioParams &audio_params() const;
|
||||
void set_audio_params(const AudioParams ¶ms);
|
||||
|
||||
const size_t &sample_count() const
|
||||
{
|
||||
return sample_count_per_channel_;
|
||||
}
|
||||
void set_sample_count(const size_t &sample_count);
|
||||
void set_sample_count(const Rational &length)
|
||||
{
|
||||
set_sample_count(audio_params_.time_to_samples(length));
|
||||
}
|
||||
|
||||
float *data(int channel)
|
||||
{
|
||||
return data_[channel].data();
|
||||
}
|
||||
|
||||
const float *data(int channel) const
|
||||
{
|
||||
return data_.at(channel).data();
|
||||
}
|
||||
|
||||
std::vector<float *> to_raw_ptrs()
|
||||
{
|
||||
std::vector<float *> r(data_.size());
|
||||
for (size_t i = 0; i < r.size(); i++) {
|
||||
r[i] = data_[i].data();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int channel_count() const
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
bool is_allocated() const
|
||||
{
|
||||
return !data_.empty();
|
||||
}
|
||||
void allocate();
|
||||
void destroy();
|
||||
|
||||
void reverse();
|
||||
void speed(double speed);
|
||||
|
||||
void transform_volume(float f);
|
||||
void transform_volume_for_channel(int channel, float volume);
|
||||
static void transform_volume(float f, const SampleBuffer *input,
|
||||
SampleBuffer *output);
|
||||
static void transform_volume_for_channel(int channel, float volume,
|
||||
const SampleBuffer *input,
|
||||
SampleBuffer *output);
|
||||
|
||||
void transform_volume_for_sample(size_t sample_index, float volume);
|
||||
void transform_volume_for_sample_on_channel(size_t sample_index,
|
||||
int channel, float volume);
|
||||
|
||||
void clamp();
|
||||
|
||||
void silence();
|
||||
void silence(size_t start_sample, size_t end_sample);
|
||||
void silence_bytes(size_t start_byte, size_t end_byte);
|
||||
|
||||
void set(int channel, const float *data, size_t sample_offset,
|
||||
size_t sample_length);
|
||||
void set(int channel, const float *data, size_t sample_length)
|
||||
{
|
||||
set(channel, data, 0, sample_length);
|
||||
}
|
||||
|
||||
void fast_set(const SampleBuffer &other, int to, int from = -1);
|
||||
|
||||
private:
|
||||
void clamp_channel(int channel);
|
||||
|
||||
AudioParams audio_params_;
|
||||
|
||||
size_t sample_count_per_channel_;
|
||||
|
||||
std::vector<std::vector<float>> data_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_SAMPLEBUFFER_H
|
||||
@@ -0,0 +1,138 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_BEZIER_H
|
||||
#define OAK_LIBOLIVECORE_BEZIER_H
|
||||
|
||||
#include <Imath/ImathVec.h>
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
class Bezier {
|
||||
public:
|
||||
Bezier();
|
||||
Bezier(double x, double y);
|
||||
Bezier(double x, double y, double cp1_x, double cp1_y, double cp2_x,
|
||||
double cp2_y);
|
||||
|
||||
const double &x() const
|
||||
{
|
||||
return x_;
|
||||
}
|
||||
const double &y() const
|
||||
{
|
||||
return y_;
|
||||
}
|
||||
const double &cp1_x() const
|
||||
{
|
||||
return cp1_x_;
|
||||
}
|
||||
const double &cp1_y() const
|
||||
{
|
||||
return cp1_y_;
|
||||
}
|
||||
const double &cp2_x() const
|
||||
{
|
||||
return cp2_x_;
|
||||
}
|
||||
const double &cp2_y() const
|
||||
{
|
||||
return cp2_y_;
|
||||
}
|
||||
|
||||
Imath::V2d to_vec() const
|
||||
{
|
||||
return Imath::V2d(x_, y_);
|
||||
}
|
||||
|
||||
Imath::V2d control_point_1_to_vec() const
|
||||
{
|
||||
return Imath::V2d(cp1_x_, cp1_y_);
|
||||
}
|
||||
|
||||
Imath::V2d control_point_2_to_vec() const
|
||||
{
|
||||
return Imath::V2d(cp2_x_, cp2_y_);
|
||||
}
|
||||
|
||||
void set_x(const double &x)
|
||||
{
|
||||
x_ = x;
|
||||
}
|
||||
void set_y(const double &y)
|
||||
{
|
||||
y_ = y;
|
||||
}
|
||||
void set_cp1_x(const double &cp1_x)
|
||||
{
|
||||
cp1_x_ = cp1_x;
|
||||
}
|
||||
void set_cp1_y(const double &cp1_y)
|
||||
{
|
||||
cp1_y_ = cp1_y;
|
||||
}
|
||||
void set_cp2_x(const double &cp2_x)
|
||||
{
|
||||
cp2_x_ = cp2_x;
|
||||
}
|
||||
void set_cp2_y(const double &cp2_y)
|
||||
{
|
||||
cp2_y_ = cp2_y;
|
||||
}
|
||||
|
||||
static double quadratic_xto_t(double x, double a, double b, double c);
|
||||
|
||||
static double quadratic_tto_y(double a, double b, double c, double t);
|
||||
|
||||
static double quadratic_xto_y(double x, const Imath::V2d &a,
|
||||
const Imath::V2d &b, const Imath::V2d &c)
|
||||
{
|
||||
return quadratic_tto_y(a.y, b.y, c.y, quadratic_xto_t(x, a.x, b.x, c.x));
|
||||
}
|
||||
|
||||
static double cubic_xto_t(double x, double a, double b, double c, double d);
|
||||
|
||||
static double cubic_tto_y(double a, double b, double c, double d, double t);
|
||||
|
||||
static double cubic_xto_y(double x, const Imath::V2d &a, const Imath::V2d &b,
|
||||
const Imath::V2d &c, const Imath::V2d &d)
|
||||
{
|
||||
return cubic_tto_y(a.y, b.y, c.y, d.y, cubic_xto_t(x, a.x, b.x, c.x, d.x));
|
||||
}
|
||||
|
||||
private:
|
||||
static double calculate_t_from_x(bool cubic, double x, double a, double b,
|
||||
double c, double d);
|
||||
|
||||
double x_;
|
||||
double y_;
|
||||
|
||||
double cp1_x_;
|
||||
double cp1_y_;
|
||||
|
||||
double cp2_x_;
|
||||
double cp2_y_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_BEZIER_H
|
||||
@@ -0,0 +1,184 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_COLOR_H
|
||||
#define OAK_LIBOLIVECORE_COLOR_H
|
||||
|
||||
#include "render/pixelformat.h"
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief High precision 32-bit DataType based RGBA color value
|
||||
*/
|
||||
class Color {
|
||||
public:
|
||||
using DataType = float;
|
||||
static constexpr unsigned int rgba = 4;
|
||||
|
||||
Color()
|
||||
{
|
||||
for (unsigned int i = 0; i < rgba; i++) {
|
||||
data_[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
Color(const DataType &r, const DataType &g, const DataType &b,
|
||||
const DataType &a = 1.0f)
|
||||
{
|
||||
data_[0] = r;
|
||||
data_[1] = g;
|
||||
data_[2] = b;
|
||||
data_[3] = a;
|
||||
}
|
||||
|
||||
Color(const char *data, const PixelFormat &format, int ch_layout);
|
||||
|
||||
/**
|
||||
* @brief Creates a Color struct from hue/saturation/value
|
||||
*
|
||||
* Hue expects a value between 0.0 and 360.0. Saturation and Value expect a value between 0.0 and 1.0.
|
||||
*/
|
||||
static Color from_hsv(const DataType &h, const DataType &s,
|
||||
const DataType &v);
|
||||
|
||||
const DataType &red() const
|
||||
{
|
||||
return data_[0];
|
||||
}
|
||||
const DataType &green() const
|
||||
{
|
||||
return data_[1];
|
||||
}
|
||||
const DataType &blue() const
|
||||
{
|
||||
return data_[2];
|
||||
}
|
||||
const DataType &alpha() const
|
||||
{
|
||||
return data_[3];
|
||||
}
|
||||
|
||||
void to_hsv(DataType *hue, DataType *sat, DataType *val) const;
|
||||
DataType hsv_hue() const;
|
||||
DataType hsv_saturation() const;
|
||||
DataType value() const;
|
||||
|
||||
void to_hsl(DataType *hue, DataType *sat, DataType *lightness) const;
|
||||
DataType hsl_hue() const;
|
||||
DataType hsl_saturation() const;
|
||||
DataType lightness() const;
|
||||
|
||||
void set_red(const DataType &red)
|
||||
{
|
||||
data_[0] = red;
|
||||
}
|
||||
void set_green(const DataType &green)
|
||||
{
|
||||
data_[1] = green;
|
||||
}
|
||||
void set_blue(const DataType &blue)
|
||||
{
|
||||
data_[2] = blue;
|
||||
}
|
||||
void set_alpha(const DataType &alpha)
|
||||
{
|
||||
data_[3] = alpha;
|
||||
}
|
||||
|
||||
DataType *data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
const DataType *data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
void to_data(char *out, const PixelFormat &format,
|
||||
unsigned int nb_channels) const;
|
||||
|
||||
static Color from_data(const char *in, const PixelFormat &format,
|
||||
unsigned int nb_channels);
|
||||
|
||||
// Suuuuper rough luminance value mostly used for UI (determining whether to overlay with black
|
||||
// or white text)
|
||||
DataType get_rough_luminance() const;
|
||||
|
||||
// Assignment math operators
|
||||
Color &operator+=(const Color &rhs);
|
||||
Color &operator-=(const Color &rhs);
|
||||
Color &operator+=(const DataType &rhs);
|
||||
Color &operator-=(const DataType &rhs);
|
||||
Color &operator*=(const DataType &rhs);
|
||||
Color &operator/=(const DataType &rhs);
|
||||
|
||||
// Binary math operators
|
||||
Color operator+(const Color &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c += rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color operator-(const Color &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c -= rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color operator+(const DataType &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c += rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color operator-(const DataType &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c -= rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color operator*(const DataType &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c *= rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
Color operator/(const DataType &rhs) const
|
||||
{
|
||||
Color c(*this);
|
||||
c /= rhs;
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
DataType data_[rgba];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_COLOR_H
|
||||
@@ -0,0 +1,80 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_FRACTIONUTILS_H
|
||||
#define OAK_LIBOLIVECORE_FRACTIONUTILS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Rounding modes for RescaleRnd()
|
||||
*
|
||||
* Mirrors the FFmpeg AVRounding modes that this codebase used before the
|
||||
* FFmpeg dependency was removed from core.
|
||||
*/
|
||||
enum class FractionRounding {
|
||||
/**
|
||||
* Round to the nearest value; halfway cases are rounded away from zero.
|
||||
* Equivalent to FFmpeg's AV_ROUND_NEAR_INF.
|
||||
*/
|
||||
k_near_inf,
|
||||
|
||||
/**
|
||||
* Round toward positive infinity. Equivalent to FFmpeg's AV_ROUND_UP.
|
||||
*/
|
||||
k_up
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Reduce a fraction so that numerator and denominator fit within `max`
|
||||
*
|
||||
* Native re-implementation of FFmpeg's av_reduce(): divides out the greatest
|
||||
* common divisor and, if the values still do not fit within `max`, finds the
|
||||
* closest approximation using continued fractions.
|
||||
*
|
||||
* A zero denominator is preserved (with the numerator set to zero).
|
||||
*/
|
||||
void reduce_fraction(int64_t &num, int64_t &den, int64_t max);
|
||||
|
||||
/**
|
||||
* @brief Compare two fractions
|
||||
*
|
||||
* Native re-implementation of FFmpeg's av_cmp_q(): returns -1 if a < b,
|
||||
* 0 if a == b, 1 if a > b, and INT_MIN when the comparison is meaningless
|
||||
* (degenerate zero-denominator fractions).
|
||||
*/
|
||||
int compare_fractions(int an, int ad, int bn, int bd);
|
||||
|
||||
/**
|
||||
* @brief Rescale `a` by the fraction b/c: returns a * b / c
|
||||
*
|
||||
* Native re-implementation of FFmpeg's av_rescale_rnd(). The intermediate
|
||||
* product is computed with 128-bit arithmetic where available so that no
|
||||
* precision is lost for large timestamps.
|
||||
*/
|
||||
int64_t rescale_rnd(int64_t a, int64_t b, int64_t c, FractionRounding rnd);
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_FRACTIONUTILS_H
|
||||
@@ -0,0 +1,157 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_RATIONAL_H
|
||||
#define OAK_LIBOLIVECORE_RATIONAL_H
|
||||
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef USE_OTIO
|
||||
#include <opentime/rationalTime.h>
|
||||
#endif
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
class Rational {
|
||||
public:
|
||||
Rational(const int &numerator = 0)
|
||||
{
|
||||
num_ = numerator;
|
||||
den_ = 1;
|
||||
}
|
||||
|
||||
Rational(const int &numerator, const int &denominator)
|
||||
{
|
||||
num_ = numerator;
|
||||
den_ = denominator;
|
||||
|
||||
fix_signs();
|
||||
reduce();
|
||||
}
|
||||
|
||||
Rational(const Rational &rhs) = default;
|
||||
|
||||
static Rational from_double(const double &flt, bool *ok = nullptr);
|
||||
static Rational from_string(const std::string &str, bool *ok = nullptr);
|
||||
|
||||
static const Rational na_n;
|
||||
|
||||
//Assignment Operators
|
||||
const Rational &operator=(const Rational &rhs);
|
||||
const Rational &operator+=(const Rational &rhs);
|
||||
const Rational &operator-=(const Rational &rhs);
|
||||
const Rational &operator/=(const Rational &rhs);
|
||||
const Rational &operator*=(const Rational &rhs);
|
||||
|
||||
//Binary math operators
|
||||
Rational operator+(const Rational &rhs) const;
|
||||
Rational operator-(const Rational &rhs) const;
|
||||
Rational operator/(const Rational &rhs) const;
|
||||
Rational operator*(const Rational &rhs) const;
|
||||
|
||||
//Relational and equality operators
|
||||
bool operator<(const Rational &rhs) const;
|
||||
bool operator<=(const Rational &rhs) const;
|
||||
bool operator>(const Rational &rhs) const;
|
||||
bool operator>=(const Rational &rhs) const;
|
||||
bool operator==(const Rational &rhs) const;
|
||||
bool operator!=(const Rational &rhs) const;
|
||||
|
||||
//Unary operators
|
||||
const Rational &operator+() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
Rational operator-() const
|
||||
{
|
||||
return Rational(num_, -den_);
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return !num_;
|
||||
}
|
||||
|
||||
//Function: convert to double
|
||||
double to_double() const;
|
||||
|
||||
#ifdef USE_OTIO
|
||||
static Rational fromRationalTime(const opentime::RationalTime &t)
|
||||
{
|
||||
// Is this the best way to do this?
|
||||
return fromDouble(t.to_seconds());
|
||||
}
|
||||
|
||||
// Convert Olive rationals to opentime rationals with the given framerate (defaults to 24)
|
||||
opentime::RationalTime toRationalTime(double framerate = 24) const;
|
||||
#endif
|
||||
|
||||
// Produce "flipped" version
|
||||
Rational flipped() const;
|
||||
void flip();
|
||||
|
||||
// Returns whether the Rational is valid but equal to zero or not
|
||||
//
|
||||
// A NaN is always a null, but a null is not always a NaN
|
||||
bool isNull() const
|
||||
{
|
||||
return num_ == 0;
|
||||
}
|
||||
|
||||
// Returns whether this Rational is not a valid number (denominator == 0)
|
||||
bool isNaN() const
|
||||
{
|
||||
return den_ == 0;
|
||||
}
|
||||
|
||||
const int &numerator() const
|
||||
{
|
||||
return num_;
|
||||
}
|
||||
const int &denominator() const
|
||||
{
|
||||
return den_;
|
||||
}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &out, const Rational &value)
|
||||
{
|
||||
out << value.num_ << '/' << value.den_;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
void fix_signs();
|
||||
void reduce();
|
||||
|
||||
int num_;
|
||||
int den_;
|
||||
};
|
||||
|
||||
#define RATIONAL_MIN Rational(INT_MIN)
|
||||
#define RATIONAL_MAX Rational(INT_MAX)
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_RATIONAL_H
|
||||
@@ -0,0 +1,211 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_STRINGUTILS_H
|
||||
#define OAK_LIBOLIVECORE_STRINGUTILS_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
class StringUtils {
|
||||
public:
|
||||
/**
|
||||
* @brief Split a string into a list of strings using a specific delimiter
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The string to split.
|
||||
*
|
||||
* @param separator
|
||||
*
|
||||
* The character to split the string on.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A vector of strings split by the specified delimiter.
|
||||
*/
|
||||
static std::vector<std::string> split(const std::string &s, char separator);
|
||||
|
||||
/**
|
||||
* @brief Splits a string into a list of strings using regular expressions.
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The string to split.
|
||||
*
|
||||
* @param regex
|
||||
*
|
||||
* The regular expression to split the string on.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A vector of strings split wherever the regular expression matched.
|
||||
*/
|
||||
static std::vector<std::string> split_regex(const std::string &s,
|
||||
const std::regex ®ex);
|
||||
|
||||
/**
|
||||
* @brief Convert a string to int using a bool pointer to determine success rather than an exception
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The string to parse an int from.
|
||||
*
|
||||
* @param base
|
||||
*
|
||||
* The base of the number in the string (usually 10, or 16 for hex).
|
||||
*
|
||||
* @param ok
|
||||
*
|
||||
* (Optional) a boolean output parameter specifying whether the conversion was successful or not.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Either the int parsed from the string, or 0 (with *ok set to false) on parser error.
|
||||
*/
|
||||
static int to_int(const std::string &s, int base, bool *ok = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Overloaded function
|
||||
*
|
||||
* @param s
|
||||
*
|
||||
* The string to parse an int from.
|
||||
*
|
||||
* @param ok
|
||||
*
|
||||
* (Optional) a boolean output parameter specifying whether the conversion was successful or not.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* Either the int parsed from the string, or 0 (with *ok set to false) on parser error.
|
||||
*/
|
||||
static int to_int(const std::string &s, bool *ok = nullptr)
|
||||
{
|
||||
return to_int(s, 10, ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a number to a string with left padding
|
||||
*
|
||||
* Usually used for converting a number to a string with leading zeroes.
|
||||
*
|
||||
* @param val
|
||||
*
|
||||
* The number to convert. This is a templated function and will accept any type, e.g.
|
||||
* int/long/float/double/etc.
|
||||
*
|
||||
* @param padding
|
||||
*
|
||||
* Total desired length of the string. For example, setting this to `2` will ensure the string
|
||||
* is at least 2 characters in size, using `c` to pad the left side where necessary.
|
||||
*
|
||||
* @param c
|
||||
*
|
||||
* The character to pad with. This defaults to `0` assuming you'll be using this function to
|
||||
* create leading zeroes.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* The padded string.
|
||||
*/
|
||||
template <typename T>
|
||||
static std::string to_string_leftpad(T val, size_t padding, char c = '0')
|
||||
{
|
||||
std::string s = std::to_string(val);
|
||||
|
||||
if (s.size() < padding) {
|
||||
s.insert(0, padding - s.size(), c);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Format a string
|
||||
*
|
||||
* A sprintf wrapper that returns a std::string.
|
||||
*
|
||||
* @param fmt
|
||||
*
|
||||
* The format to use.
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* A formatted string in std::string form.
|
||||
*/
|
||||
static std::string format(const char *fmt, ...);
|
||||
|
||||
// trim from start (in place)
|
||||
static inline void ltrim(std::string &s)
|
||||
{
|
||||
s.erase(s.begin(),
|
||||
std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
}
|
||||
|
||||
// trim from end (in place)
|
||||
static inline void rtrim(std::string &s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||
[](unsigned char ch) { return !std::isspace(ch); })
|
||||
.base(),
|
||||
s.end());
|
||||
}
|
||||
|
||||
// trim from both ends (in place)
|
||||
static inline void trim(std::string &s)
|
||||
{
|
||||
rtrim(s);
|
||||
ltrim(s);
|
||||
}
|
||||
|
||||
// trim from start (copying)
|
||||
static inline std::string ltrimmed(std::string s)
|
||||
{
|
||||
ltrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from end (copying)
|
||||
static inline std::string rtrimmed(std::string s)
|
||||
{
|
||||
rtrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from both ends (copying)
|
||||
static inline std::string trimmed(std::string s)
|
||||
{
|
||||
trim(s);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_STRINGUTILS_H
|
||||
@@ -0,0 +1,93 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_TIMECODEFUNCTIONS_H
|
||||
#define OAK_LIBOLIVECORE_TIMECODEFUNCTIONS_H
|
||||
|
||||
#include "rational.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Functions for converting times/timecodes/timestamps
|
||||
*
|
||||
* Olive uses the following terminology through its code:
|
||||
*
|
||||
* `time` - time in seconds presented in a Rational form
|
||||
* `timebase` - the base time unit of an audio/video stream in seconds
|
||||
* `timestamp` - an integer representation of a time in timebase units (in many cases is used like a frame number)
|
||||
* `timecode` a user-friendly string representation of a time according to Timecode::Display
|
||||
*/
|
||||
class Timecode {
|
||||
public:
|
||||
enum Display {
|
||||
k_timecode_drop_frame,
|
||||
k_timecode_non_drop_frame,
|
||||
k_timecode_seconds,
|
||||
k_frames,
|
||||
k_milliseconds
|
||||
};
|
||||
|
||||
enum Rounding { k_ceil, k_floor, k_round };
|
||||
|
||||
/**
|
||||
* @brief Convert a timestamp (according to a Rational timebase) to a user-friendly string representation
|
||||
*/
|
||||
static std::string time_to_timecode(const Rational &time,
|
||||
const Rational &timebase,
|
||||
const Display &display,
|
||||
bool show_plus_if_positive = false);
|
||||
static Rational timecode_to_time(std::string timecode,
|
||||
const Rational &timebase,
|
||||
const Display &display,
|
||||
bool *ok = nullptr);
|
||||
|
||||
static std::string time_to_string(int64_t ms);
|
||||
|
||||
static Rational snap_time_to_timebase(const Rational &time,
|
||||
const Rational &timebase,
|
||||
Rounding floor = k_round);
|
||||
|
||||
static int64_t time_to_timestamp(const Rational &time,
|
||||
const Rational &timebase,
|
||||
Rounding floor = k_round);
|
||||
static int64_t time_to_timestamp(const double &time,
|
||||
const Rational &timebase,
|
||||
Rounding floor = k_round);
|
||||
|
||||
static int64_t rescale_timestamp(const int64_t &ts, const Rational &source,
|
||||
const Rational &dest);
|
||||
static int64_t rescale_timestamp_ceil(const int64_t &ts,
|
||||
const Rational &source,
|
||||
const Rational &dest);
|
||||
|
||||
static Rational timestamp_to_time(const int64_t ×tamp,
|
||||
const Rational &timebase);
|
||||
|
||||
static bool timebase_is_drop_frame(const Rational &timebase);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_TIMECODEFUNCTIONS_H
|
||||
@@ -0,0 +1,315 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_TIMERANGE_H
|
||||
#define OAK_LIBOLIVECORE_TIMERANGE_H
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "rational.h"
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
class TimeRange {
|
||||
public:
|
||||
TimeRange() = default;
|
||||
TimeRange(const Rational &in, const Rational &out);
|
||||
TimeRange(const TimeRange &r)
|
||||
: TimeRange(r.in(), r.out())
|
||||
{
|
||||
}
|
||||
|
||||
TimeRange &operator=(const TimeRange &r)
|
||||
{
|
||||
set_range(r.in(), r.out());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Rational &in() const;
|
||||
const Rational &out() const;
|
||||
const Rational &length() const;
|
||||
|
||||
void set_in(const Rational &in);
|
||||
void set_out(const Rational &out);
|
||||
void set_range(const Rational &in, const Rational &out);
|
||||
|
||||
bool operator==(const TimeRange &r) const;
|
||||
bool operator!=(const TimeRange &r) const;
|
||||
|
||||
bool overlaps_with(const TimeRange &a, bool in_inclusive = true,
|
||||
bool out_inclusive = true) const;
|
||||
bool contains(const TimeRange &a, bool in_inclusive = true,
|
||||
bool out_inclusive = true) const;
|
||||
bool contains(const Rational &r) const;
|
||||
|
||||
TimeRange combined(const TimeRange &a) const;
|
||||
static TimeRange combine(const TimeRange &a, const TimeRange &b);
|
||||
TimeRange intersected(const TimeRange &a) const;
|
||||
static TimeRange intersect(const TimeRange &a, const TimeRange &b);
|
||||
|
||||
TimeRange operator+(const Rational &rhs) const;
|
||||
TimeRange operator-(const Rational &rhs) const;
|
||||
|
||||
const TimeRange &operator+=(const Rational &rhs);
|
||||
const TimeRange &operator-=(const Rational &rhs);
|
||||
|
||||
std::list<TimeRange> split(const int &chunk_size) const;
|
||||
|
||||
private:
|
||||
void normalize();
|
||||
|
||||
Rational in_;
|
||||
Rational out_;
|
||||
Rational length_;
|
||||
};
|
||||
|
||||
class TimeRangeList {
|
||||
public:
|
||||
TimeRangeList() = default;
|
||||
|
||||
TimeRangeList(std::initializer_list<TimeRange> r)
|
||||
: array_(r)
|
||||
{
|
||||
}
|
||||
|
||||
void insert(const TimeRangeList &list_to_add);
|
||||
void insert(TimeRange range_to_add);
|
||||
|
||||
void remove(const TimeRange &remove);
|
||||
void remove(const TimeRangeList &list);
|
||||
|
||||
template <typename T>
|
||||
static void util_remove(std::vector<T> *list, const TimeRange &remove)
|
||||
{
|
||||
std::vector<T> additions;
|
||||
|
||||
for (auto it = list->begin(); it != list->end();) {
|
||||
T &compare = *it;
|
||||
|
||||
if (remove.contains(compare)) {
|
||||
// This element is entirely encompassed in this range, remove it
|
||||
it = list->erase(it);
|
||||
} else {
|
||||
if (compare.contains(remove, false, false)) {
|
||||
// The remove range is within this element, only choice is to split the element into two
|
||||
T new_range = compare;
|
||||
new_range.set_in(remove.out());
|
||||
compare.set_out(remove.in());
|
||||
|
||||
additions.push_back(new_range);
|
||||
break;
|
||||
} else {
|
||||
if (compare.in() < remove.in() &&
|
||||
compare.out() > remove.in()) {
|
||||
// This element's out point overlaps the range's in, we'll trim it
|
||||
compare.set_out(remove.in());
|
||||
} else if (compare.in() < remove.out() &&
|
||||
compare.out() > remove.out()) {
|
||||
// This element's in point overlaps the range's out, we'll trim it
|
||||
compare.set_in(remove.out());
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list->insert(list->end(), additions.begin(), additions.end());
|
||||
}
|
||||
|
||||
bool contains(const TimeRange &range, bool in_inclusive = true,
|
||||
bool out_inclusive = true) const;
|
||||
|
||||
bool contains(const Rational &r) const
|
||||
{
|
||||
for (const TimeRange &range : array_) {
|
||||
if (range.contains(r)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool overlaps_with(const TimeRange &r, bool in_inclusive = true,
|
||||
bool out_inclusive = true) const
|
||||
{
|
||||
for (const TimeRange &range : array_) {
|
||||
if (range.overlaps_with(r, in_inclusive, out_inclusive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return array_.empty();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
array_.clear();
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return array_.size();
|
||||
}
|
||||
|
||||
void shift(const Rational &diff);
|
||||
|
||||
void trim_in(const Rational &diff);
|
||||
|
||||
void trim_out(const Rational &diff);
|
||||
|
||||
TimeRangeList intersects(const TimeRange &range) const;
|
||||
|
||||
using const_iterator = std::vector<TimeRange>::const_iterator;
|
||||
|
||||
const_iterator begin() const
|
||||
{
|
||||
return array_.cbegin();
|
||||
}
|
||||
|
||||
const_iterator end() const
|
||||
{
|
||||
return array_.cend();
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return begin();
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return end();
|
||||
}
|
||||
|
||||
const TimeRange &first() const
|
||||
{
|
||||
return array_.front();
|
||||
}
|
||||
|
||||
const TimeRange &last() const
|
||||
{
|
||||
return array_.back();
|
||||
}
|
||||
|
||||
const TimeRange &at(int index) const
|
||||
{
|
||||
return array_.at(index);
|
||||
}
|
||||
|
||||
const std::vector<TimeRange> &internal_array() const
|
||||
{
|
||||
return array_;
|
||||
}
|
||||
|
||||
bool operator==(const TimeRangeList &rhs) const
|
||||
{
|
||||
return array_ == rhs.array_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<TimeRange> array_;
|
||||
};
|
||||
|
||||
class TimeRangeListFrameIterator {
|
||||
public:
|
||||
TimeRangeListFrameIterator();
|
||||
TimeRangeListFrameIterator(const TimeRangeList &list,
|
||||
const Rational &timebase);
|
||||
|
||||
Rational snap(const Rational &r) const;
|
||||
|
||||
bool get_next(Rational *out);
|
||||
|
||||
bool has_next() const;
|
||||
|
||||
std::vector<Rational> to_vector() const
|
||||
{
|
||||
TimeRangeListFrameIterator copy(list_, timebase_);
|
||||
std::vector<Rational> times;
|
||||
Rational r;
|
||||
while (copy.get_next(&r)) {
|
||||
times.push_back(r);
|
||||
}
|
||||
return times;
|
||||
}
|
||||
|
||||
int size();
|
||||
|
||||
void reset()
|
||||
{
|
||||
*this = TimeRangeListFrameIterator();
|
||||
}
|
||||
|
||||
void insert(const TimeRange &range)
|
||||
{
|
||||
list_.insert(range);
|
||||
}
|
||||
|
||||
void insert(const TimeRangeList &list)
|
||||
{
|
||||
list_.insert(list);
|
||||
}
|
||||
|
||||
bool is_custom_range() const
|
||||
{
|
||||
return custom_range_;
|
||||
}
|
||||
|
||||
void set_custom_range(bool e)
|
||||
{
|
||||
custom_range_ = e;
|
||||
}
|
||||
|
||||
int frame_index() const
|
||||
{
|
||||
return frame_index_;
|
||||
}
|
||||
|
||||
private:
|
||||
void update_index_if_necessary();
|
||||
|
||||
TimeRangeList list_;
|
||||
|
||||
Rational timebase_;
|
||||
|
||||
Rational current_;
|
||||
|
||||
int range_index_;
|
||||
|
||||
int size_;
|
||||
|
||||
int frame_index_;
|
||||
|
||||
bool custom_range_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_TIMERANGE_H
|
||||
@@ -0,0 +1,96 @@
|
||||
/***
|
||||
|
||||
Olive - Non-Linear Video Editor
|
||||
Copyright (C) 2023 Olive Studios LLC
|
||||
Modifications Copyright (C) 2025 mikesolar
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_LIBOLIVECORE_VALUE_H
|
||||
#define OAK_LIBOLIVECORE_VALUE_H
|
||||
|
||||
#include <map>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Generic type container
|
||||
*/
|
||||
class Value {
|
||||
public:
|
||||
enum Type {
|
||||
/// Null/no data
|
||||
none,
|
||||
|
||||
/// Signed int64
|
||||
INT,
|
||||
|
||||
/// Double-precision float
|
||||
FLOAT,
|
||||
|
||||
/// UTF-8 string
|
||||
string
|
||||
};
|
||||
|
||||
Value()
|
||||
{
|
||||
type_ = none;
|
||||
}
|
||||
|
||||
Value(int64_t v)
|
||||
{
|
||||
data_.resize(sizeof(int64_t));
|
||||
memcpy(data_.data(), &v, sizeof(int64_t));
|
||||
type_ = INT;
|
||||
}
|
||||
|
||||
Value(double v)
|
||||
{
|
||||
data_.resize(sizeof(double));
|
||||
memcpy(data_.data(), &v, sizeof(int64_t));
|
||||
type_ = FLOAT;
|
||||
}
|
||||
|
||||
Value(const char *s)
|
||||
{
|
||||
size_t sz = strlen(s);
|
||||
data_.resize(sz);
|
||||
memcpy(data_.data(), s, sz);
|
||||
type_ = string;
|
||||
}
|
||||
|
||||
Value(const std::string &s)
|
||||
{
|
||||
data_.resize(s.size());
|
||||
memcpy(data_.data(), s.data(), data_.size());
|
||||
type_ = string;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
using ValueMap = std::map<std::string, Value>;
|
||||
|
||||
}
|
||||
|
||||
#endif // OAK_LIBOLIVECORE_VALUE_H
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
const std::vector<int> AudioParams::k_supported_sample_rates = {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "util/cpuoptimize.h"
|
||||
#include "util/log.h"
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
SampleBuffer::SampleBuffer()
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
Bezier::Bezier()
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
Color Color::from_hsv(const DataType &h, const DataType &s, const DataType &v)
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
namespace
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "util/fractionutils.h"
|
||||
#include "util/stringutils.h"
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
const Rational Rational::na_n = Rational(0, 0);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
std::vector<std::string> StringUtils::split(const std::string &s,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "util/fractionutils.h"
|
||||
#include "util/stringutils.h"
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
std::string Timecode::time_to_timecode(const Rational &time,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include "util/timecodefunctions.h"
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
TimeRange::TimeRange(const Rational &in, const Rational &out)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "util/value.h"
|
||||
|
||||
namespace olive::core
|
||||
namespace olive::core::internal
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user