feat(app): multicam panel with live angle grid, switching, timeline enable
- New MulticamPanel: rows/cols angle grid with the current angle highlighted, click-to-switch, 1-9 switch-and-split and cmd-1-9 switch-only shortcuts (focused-panel routed), deferred switch queue during playback. - src/oakui/multicam.rs: clip->connected-sequence resolution, multicam state detection (selection then playhead fallbacks), per-angle frame requests rendered through the process backend into an LRU cache. - Timeline clip context menu Multi-Cam checkable item wired to oaktimeline::multicam enable/disable with undo. - Engine trait extended (real + mock); mock drives the real command path with synthesized angle frames.
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_CONFORM_H
|
||||
#define OAK_EDITOR_CODEC_CONFORM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file conform.h
|
||||
* @brief C ABI for the oakcodec audio conform manager
|
||||
* (olive::ConformManager): pcm waveform cache files used for fast
|
||||
* audio scrubbing.
|
||||
*
|
||||
* Interim state (pre-M8): actual conform work is delegated to the global
|
||||
* task submit callback (see task.h). While no callback is registered,
|
||||
* state queries report OAKCODEC_CONFORM_UNAVAILABLE.
|
||||
*/
|
||||
|
||||
#define OAKCODEC_CONFORM_EXISTS 0
|
||||
#define OAKCODEC_CONFORM_GENERATING 1
|
||||
#define OAKCODEC_CONFORM_UNAVAILABLE 2
|
||||
|
||||
/**
|
||||
* @brief Create the ConformManager singleton (no-op when it exists).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_create_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ConformManager singleton (no-op when absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_destroy_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Query the conform state of one audio stream, starting the
|
||||
* conform when needed and possible.
|
||||
*
|
||||
* Addresses the source by filename/stream_index and the target audio
|
||||
* format by sample_rate/channel_layout/sample_format
|
||||
* (olive::core::SampleFormat::Format as int).
|
||||
*
|
||||
* When the conform files do not exist and a task submit callback is
|
||||
* registered (task.h), the conform is submitted synchronously and the
|
||||
* filesystem is re-checked; `wait` only controls whether a post-submit
|
||||
* miss is reported as OAKCODEC_CONFORM_UNAVAILABLE (wait != 0) or
|
||||
* OAKCODEC_CONFORM_GENERATING (wait == 0). Without a registrar the
|
||||
* result is always OAKCODEC_CONFORM_UNAVAILABLE.
|
||||
*
|
||||
* @return One of OAKCODEC_CONFORM_* (non-negative), or a negative
|
||||
* OAKCODEC_E_* code for invalid arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_get_state(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
int sample_rate, uint64_t channel_layout,
|
||||
int sample_format, int wait);
|
||||
|
||||
/**
|
||||
* @brief Number of conform (pcm) files for the given stream/params — one
|
||||
* per channel; 0 on invalid arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_filename_count(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
int sample_rate, uint64_t channel_layout,
|
||||
int sample_format);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th conform filename (buf/size getter).
|
||||
*
|
||||
* @return Required buffer size including NUL (non-negative), or a
|
||||
* negative OAKCODEC_E_* code (OAKCODEC_E_NOT_FOUND when index is
|
||||
* out of range).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_conform_filename_at(const char *cache_path,
|
||||
const char *source_filename,
|
||||
int stream_index, int sample_rate,
|
||||
uint64_t channel_layout, int sample_format,
|
||||
int index, char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_CONFORM_H
|
||||
@@ -0,0 +1,245 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_DECODER_H
|
||||
#define OAK_EDITOR_CODEC_DECODER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "frame.h"
|
||||
#include "render/cancelatom.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file decoder.h
|
||||
* @brief C ABI for oakcodec media decoders (olive::Decoder and its
|
||||
* FFmpeg/OIIO implementations): probing, stream enumeration and
|
||||
* CPU-frame decoding.
|
||||
*
|
||||
* Handles follow the neutral by-value convention documented in frame.h
|
||||
* (and oakcommon's common/handle.h). Two usage patterns share the
|
||||
* OakDecoder handle:
|
||||
*
|
||||
* - Probe: oakcodec_decoder_probe() inspects a file WITHOUT opening a
|
||||
* decode session; the stream getters describe what was found.
|
||||
* - Decode: oakcodec_decoder_init() + oakcodec_decoder_open() attach a
|
||||
* decoder instance to one (filename, stream) pair; the decode
|
||||
* functions then produce frames/audio.
|
||||
*/
|
||||
|
||||
typedef struct OakDecoder {
|
||||
void *ctx; /**< Opaque pointer to the reference-counted object. */
|
||||
void (*addref)(void *ctx); /**< Atomically increments the count. */
|
||||
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
|
||||
uint32_t abi_version; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakDecoder;
|
||||
|
||||
/**
|
||||
* @brief POD description of one probed video stream.
|
||||
*
|
||||
* duration_ts counts units of the stream's time base;
|
||||
* time_base_num/den is seconds per time-base unit. color_primaries and
|
||||
* color_trc carry the ISO/IEC 23001-8 code points the decoder reports
|
||||
* (0 = unknown). interlaced is 1 when the stream is interlaced.
|
||||
* format is an OakPixelFormat value (the decoder's native delivery
|
||||
* format), channel_count its plane channel count.
|
||||
*/
|
||||
typedef struct oakcodec_video_stream_info {
|
||||
int stream_index;
|
||||
int width;
|
||||
int height;
|
||||
int frame_rate_num;
|
||||
int frame_rate_den;
|
||||
int64_t duration_ts;
|
||||
int time_base_num;
|
||||
int time_base_den;
|
||||
int format;
|
||||
int channel_count;
|
||||
int color_primaries;
|
||||
int color_trc;
|
||||
int interlaced;
|
||||
} oakcodec_video_stream_info;
|
||||
|
||||
/**
|
||||
* @brief POD description of one probed audio stream.
|
||||
*
|
||||
* channel_layout is the ffmpeg-style channel mask (e.g. 0x3 = stereo).
|
||||
*/
|
||||
typedef struct oakcodec_audio_stream_info {
|
||||
int stream_index;
|
||||
int sample_rate;
|
||||
uint64_t channel_layout;
|
||||
int channel_count;
|
||||
int64_t duration_ts;
|
||||
int time_base_num;
|
||||
int time_base_den;
|
||||
} oakcodec_audio_stream_info;
|
||||
|
||||
/* ---- Probe (stateless inspection) ---------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Probe a media file: decoder name plus stream inventory.
|
||||
*
|
||||
* Tries each available decoder implementation (FFmpeg, then OIIO) and
|
||||
* wraps the first one that recognizes the file. The returned handle only
|
||||
* carries probe results; it cannot decode (use init + open for that).
|
||||
*
|
||||
* @return Handle with reference count 1, or an empty handle (ctx == NULL)
|
||||
* when no decoder recognizes the file (oakcodec_probe_last_error()
|
||||
* carries the reason).
|
||||
*/
|
||||
OAKCODEC_API OakDecoder oakcodec_decoder_probe(const char *filename);
|
||||
|
||||
/**
|
||||
* @brief Thread-local error detail of the last failed probe on this
|
||||
* thread (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_probe_last_error(char *buf, int buf_size);
|
||||
|
||||
/** @brief Probed decoder id ("ffmpeg"/"oiio", buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_decoder_probe_decoder_name(OakDecoder probe, char *buf,
|
||||
int buf_size);
|
||||
|
||||
OAKCODEC_API int oakcodec_decoder_probe_video_stream_count(OakDecoder probe);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_audio_stream_count(OakDecoder probe);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_subtitle_stream_count(OakDecoder probe);
|
||||
|
||||
/**
|
||||
* @brief Fill `out` with the video stream at `index` (0-based within the
|
||||
* video stream list).
|
||||
*
|
||||
* @return OAKCODEC_OK, OAKCODEC_E_INVALID, or OAKCODEC_E_NOT_FOUND when
|
||||
* index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_probe_get_video_stream(OakDecoder probe, int index,
|
||||
oakcodec_video_stream_info *out);
|
||||
OAKCODEC_API int oakcodec_decoder_probe_get_audio_stream(OakDecoder probe, int index,
|
||||
oakcodec_audio_stream_info *out);
|
||||
|
||||
/* ---- Decode session ------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Create a closed decoder handle (count 1).
|
||||
*/
|
||||
OAKCODEC_API OakDecoder oakcodec_decoder_init(void);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a decoder. No-op on NULL/empty.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_decoder_free(OakDecoder *decoder);
|
||||
|
||||
/**
|
||||
* @brief Open `filename`'s stream `stream_index` for decoding.
|
||||
*
|
||||
* The decoder implementation is chosen automatically from the probe
|
||||
* results. Opening an already-open decoder on the same stream is a
|
||||
* successful no-op.
|
||||
*
|
||||
* @return OAKCODEC_OK on success, OAKCODEC_E_NOT_FOUND when the file
|
||||
* does not exist, OAKCODEC_E_FAILED otherwise (see
|
||||
* oakcodec_decoder_last_error()).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_open(OakDecoder decoder, const char *filename,
|
||||
int stream_index);
|
||||
|
||||
/** @brief Close the current stream (safe when closed). */
|
||||
OAKCODEC_API int oakcodec_decoder_close(OakDecoder decoder);
|
||||
|
||||
/** @brief 1 when a stream is open, 0 otherwise. */
|
||||
OAKCODEC_API int oakcodec_decoder_is_open(OakDecoder decoder);
|
||||
|
||||
/**
|
||||
* @brief Decode the video frame at `numerator/denominator` seconds.
|
||||
*
|
||||
* Before the start of the footage the first frame is returned, after the
|
||||
* end the last frame.
|
||||
*
|
||||
* @return A frame handle with reference count 1 (caller releases), or an
|
||||
* empty handle (ctx == NULL) on error/EOF — check
|
||||
* oakcodec_decoder_last_error().
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_decoder_decode_video(OakDecoder decoder, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Decode audio into a float buffer.
|
||||
*
|
||||
* Decodes the interleaved audio covering [in, out) seconds (rational
|
||||
* pairs), resampled/laid out to `sample_rate`/`channel_layout`.
|
||||
* `buf` must hold at least `buf_frames` frames worth of interleaved
|
||||
* floats.
|
||||
*
|
||||
* @return The number of frames written (>= 0), or a negative
|
||||
* OAKCODEC_E_* code. Conform generation is NOT triggered by this
|
||||
* family in the current intermediate state (no task registrar);
|
||||
* media requiring a conform yields OAKCODEC_E_STATE.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_decode_audio(OakDecoder decoder, int in_num, int in_den,
|
||||
int out_num, int out_den, int sample_rate,
|
||||
uint64_t channel_layout, float *buf,
|
||||
int buf_frames);
|
||||
|
||||
/**
|
||||
* @brief Conform the open stream's audio into per-channel pcm cache files
|
||||
* (Decoder::conform_audio()).
|
||||
*
|
||||
* `output_filenames` is an array of `filename_count` final per-channel
|
||||
* paths. `sample_format` is olive::core::SampleFormat::Format as int.
|
||||
* `cancelled` may be an empty OakCancelAtom (ctx == NULL).
|
||||
*
|
||||
* @return OAKCODEC_OK on success, OAKCODEC_E_STATE when no stream is
|
||||
* open, OAKCODEC_E_CANCELLED when cancelled, OAKCODEC_E_FAILED
|
||||
* otherwise.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_conform_audio(OakDecoder decoder,
|
||||
const char *const *output_filenames, int filename_count,
|
||||
int sample_rate, uint64_t channel_layout, int sample_format,
|
||||
OakCancelAtom cancelled);
|
||||
|
||||
/**
|
||||
* @brief Image-sequence filename heuristics (Decoder::get_image_sequence_*).
|
||||
*
|
||||
* digit_count: number of trailing digits in the filename stem (0 = not an
|
||||
* image sequence filename). index: the numeric value of those digits (-1
|
||||
* when none). transform: substitute `number` into the digit field,
|
||||
* two-stage string getter.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_get_image_sequence_digit_count(
|
||||
const char *filename);
|
||||
OAKCODEC_API int64_t oakcodec_decoder_get_image_sequence_index(
|
||||
const char *filename);
|
||||
OAKCODEC_API int oakcodec_decoder_transform_image_sequence_file_name(
|
||||
const char *filename, int64_t number, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Human-readable detail of the last error on this decoder
|
||||
* (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_decoder_last_error(OakDecoder decoder, char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_DECODER_H
|
||||
@@ -0,0 +1,223 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_ENCODER_H
|
||||
#define OAK_EDITOR_CODEC_ENCODER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file encoder.h
|
||||
* @brief C ABI for oakcodec media encoders (olive::Encoder and its
|
||||
* FFmpeg/OIIO implementations).
|
||||
*
|
||||
* Handles follow the neutral by-value convention documented in frame.h.
|
||||
* The workflow is: fill an oakcodec_encoding_params POD (all fields,
|
||||
* zeroed = disabled) -> oakcodec_encoder_init() ->
|
||||
* oakcodec_encoder_open() -> oakcodec_encoder_write_*() ->
|
||||
* oakcodec_encoder_flush(). Encoder-specific options
|
||||
* (e.g. "crf" = "18") go through oakcodec_encoder_set_video_option()
|
||||
* between init and open.
|
||||
*
|
||||
* Enum int fields carry the engine's own enum values
|
||||
* (olive::ExportFormat::Format, olive::ExportCodec::Codec,
|
||||
* OakPixelFormat, olive::VideoParams::Interlacing,
|
||||
* olive::core::SampleFormat::Format) — the same values
|
||||
* oakengine/encoding.h documents.
|
||||
*/
|
||||
|
||||
typedef struct OakEncoder {
|
||||
void *ctx; /**< Opaque pointer to the reference-counted object. */
|
||||
void (*addref)(void *ctx); /**< Atomically increments the count. */
|
||||
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
|
||||
uint32_t abi_version; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakEncoder;
|
||||
|
||||
/** @brief olive::VideoParams::Interlacing values. */
|
||||
#define OAKCODEC_INTERLACE_NONE 0
|
||||
#define OAKCODEC_INTERLACE_TOP_FIRST 1
|
||||
#define OAKCODEC_INTERLACE_BOTTOM_FIRST 2
|
||||
|
||||
/** @brief EncodingParams::VideoScalingMethod values. */
|
||||
#define OAKCODEC_ENCODING_SCALING_FIT 0
|
||||
#define OAKCODEC_ENCODING_SCALING_STRETCH 1
|
||||
#define OAKCODEC_ENCODING_SCALING_CROP 2
|
||||
|
||||
/**
|
||||
* @brief Flattened encoding parameters (olive::EncodingParams).
|
||||
*
|
||||
* A zeroed struct describes an all-tracks-disabled configuration. The
|
||||
* filename (and image-sequence "[#####]" template when
|
||||
* video_is_image_sequence is set) lives in `filename`.
|
||||
* video_time_base_* is the frame duration (frame rate flipped), matching
|
||||
* oak_video_params' convention.
|
||||
*/
|
||||
typedef struct oakcodec_encoding_params {
|
||||
char filename[1024];
|
||||
int format; /**< olive::ExportFormat::Format. */
|
||||
|
||||
int video_enabled; /**< 1/0. */
|
||||
int video_codec; /**< olive::ExportCodec::Codec. */
|
||||
int video_width;
|
||||
int video_height;
|
||||
int video_time_base_num; /**< Frame duration numerator. */
|
||||
int video_time_base_den;
|
||||
int video_pixel_format; /**< OakPixelFormat (delivery format). */
|
||||
int video_interlacing; /**< OAKCODEC_INTERLACE_*. */
|
||||
int video_pixel_aspect_num;
|
||||
int video_pixel_aspect_den;
|
||||
int64_t video_bit_rate; /**< bit/s, 0 = codec default. */
|
||||
int64_t video_min_bit_rate;
|
||||
int64_t video_max_bit_rate;
|
||||
int64_t video_buffer_size; /**< bytes. */
|
||||
int video_threads; /**< 0 = auto. */
|
||||
char video_pix_fmt[64]; /**< Encoded pixel format name ("yuv420p"). */
|
||||
int video_is_image_sequence; /**< 1/0. */
|
||||
int video_scaling_method; /**< OAKCODEC_ENCODING_SCALING_*. */
|
||||
|
||||
int audio_enabled; /**< 1/0. */
|
||||
int audio_codec; /**< olive::ExportCodec::Codec. */
|
||||
int audio_sample_rate;
|
||||
uint64_t audio_channel_layout; /**< ffmpeg-style channel mask. */
|
||||
int audio_sample_format; /**< olive::core::SampleFormat::Format. */
|
||||
int64_t audio_bit_rate; /**< bit/s. */
|
||||
|
||||
int subtitles_enabled; /**< 1/0. */
|
||||
int subtitles_codec; /**< olive::ExportCodec::Codec. */
|
||||
int subtitles_are_sidecar; /**< 1/0. */
|
||||
int subtitles_sidecar_format; /**< olive::ExportFormat::Format. */
|
||||
|
||||
/** Output OCIO colorspace name; empty = reference space (no transform). */
|
||||
char color_transform_output[256];
|
||||
|
||||
int export_length_num; /**< Export length in seconds (rational). */
|
||||
int export_length_den;
|
||||
|
||||
/** Custom export range (seconds, rational pairs); used when
|
||||
* has_custom_range != 0. */
|
||||
int has_custom_range;
|
||||
int64_t custom_range_in_num;
|
||||
int64_t custom_range_in_den;
|
||||
int64_t custom_range_out_num;
|
||||
int64_t custom_range_out_den;
|
||||
} oakcodec_encoding_params;
|
||||
|
||||
/**
|
||||
* @brief Create an encoder for `params` (count 1).
|
||||
*
|
||||
* The implementation (FFmpeg/OIIO) is chosen from params.format and the
|
||||
* enabled tracks. The file is NOT opened yet. Returns an empty handle
|
||||
* (ctx == NULL) when the configuration is invalid.
|
||||
*/
|
||||
OAKCODEC_API OakEncoder oakcodec_encoder_init(const oakcodec_encoding_params *params);
|
||||
|
||||
/** @brief Release one reference to an encoder. No-op on NULL/empty. */
|
||||
OAKCODEC_API void oakcodec_encoder_free(OakEncoder *encoder);
|
||||
|
||||
/**
|
||||
* @brief Set an encoder-specific video option (e.g. "crf" = "18").
|
||||
*
|
||||
* Only valid between init and open.
|
||||
*
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_STATE when already open.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_set_video_option(OakEncoder encoder, const char *key,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* @brief Open the output file and write stream headers.
|
||||
*
|
||||
* @return OAKCODEC_OK, OAKCODEC_E_STATE (already open), or
|
||||
* OAKCODEC_E_FAILED (see oakcodec_encoder_last_error()).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_open(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief Encode one video frame.
|
||||
*
|
||||
* The frame's parameters must match the encoding parameters (the encoder
|
||||
* converts the delivery pixel format to the encoded one internally).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_video(OakEncoder encoder, OakFrame frame);
|
||||
|
||||
/**
|
||||
* @brief Encode interleaved float audio samples.
|
||||
*
|
||||
* @param samples frame_count * channel_count interleaved floats.
|
||||
* @return OAKCODEC_OK or a negative OAKCODEC_E_* code.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_audio(OakEncoder encoder, const float *samples,
|
||||
int frame_count);
|
||||
|
||||
/**
|
||||
* @brief Encode one subtitle entry (times in seconds).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_write_subtitle(OakEncoder encoder, const char *text,
|
||||
double in_seconds, double out_seconds);
|
||||
|
||||
/**
|
||||
* @brief Flush the encoders, write the trailer and close the file.
|
||||
*
|
||||
* Idempotent; after a successful flush the encoder cannot be written to
|
||||
* (write calls return OAKCODEC_E_STATE).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_flush(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief Human-readable detail of the last error on this encoder
|
||||
* (buf/size string getter convention).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_last_error(OakEncoder encoder, char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief The pixel format the encoder wants frames in
|
||||
* (Encoder::get_desired_pixel_format()), as int; -1 when
|
||||
* unknown/invalid encoder.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoder_get_desired_pixel_format(OakEncoder encoder);
|
||||
|
||||
/**
|
||||
* @brief File extension for an export format
|
||||
* (ExportFormat::get_extension()), two-stage string getter.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_export_format_get_extension(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Scaling matrix for a scaling method
|
||||
* (EncodingParams::generate_matrix()), row-major 4x4 into
|
||||
* out_matrix[16].
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_generate_matrix(int method, int src_width,
|
||||
int src_height, int dst_width,
|
||||
int dst_height, double *out_matrix);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_ENCODER_H
|
||||
@@ -0,0 +1,61 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_ERROR_H
|
||||
#define OAK_EDITOR_CODEC_ERROR_H
|
||||
|
||||
/**
|
||||
* @brief Status and error codes shared by all oakcodec C API families.
|
||||
*
|
||||
* Return-code convention (mirrors the other split modules):
|
||||
* 0 (OAKCODEC_OK) on success, a negative OAKCODEC_E_* error code on
|
||||
* failure. String getters return the required buffer size in bytes
|
||||
* (including the terminating NUL) as a non-negative value instead.
|
||||
*/
|
||||
#define OAKCODEC_OK 0 /**< Success. */
|
||||
#define OAKCODEC_E_INVALID (-50001) /**< NULL handle or invalid argument. */
|
||||
#define OAKCODEC_E_STATE (-50002) /**< Call not valid in the current state. */
|
||||
#define OAKCODEC_E_FAILED (-50003) /**< The underlying operation failed. */
|
||||
#define OAKCODEC_E_NOT_FOUND (-50004) /**< Index out of range / entry not found. */
|
||||
#define OAKCODEC_E_NOMEM (-50005) /**< Allocation failed. */
|
||||
#define OAKCODEC_E_CANCELLED (-50006) /**< The operation was cancelled. */
|
||||
|
||||
/**
|
||||
* @brief Current ABI version stamped into every oakcodec handle.
|
||||
*
|
||||
* Bump whenever the handle layout or the semantics of any exported
|
||||
* function change incompatibly. Consumers should compare a handle's
|
||||
* abi_version field against the value they were compiled with before
|
||||
* dereferencing ctx.
|
||||
*/
|
||||
#define OAKCODEC_ABI_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief Export macro for the oakcodec C ABI.
|
||||
*
|
||||
* oakcodec is built with -fvisibility=hidden (01 §1 rule 5): only the
|
||||
* oakcodec_* functions marked with this macro leave the shared library.
|
||||
* This also keeps codec-internal C++ classes (whose olive::* names may
|
||||
* collide with transition stubs inside other modules) from participating
|
||||
* in cross-library weak-symbol coalescing.
|
||||
*/
|
||||
#define OAKCODEC_API __attribute__((visibility("default")))
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_ERROR_H
|
||||
@@ -0,0 +1,217 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_FORMAT_H
|
||||
#define OAK_EDITOR_CODEC_FORMAT_H
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file format.h
|
||||
* @brief C ABI for the oakcodec container-format / codec metadata queries
|
||||
* (olive::ExportFormat / olive::ExportCodec / olive::Encoder statics).
|
||||
*
|
||||
* This family is the module-side mirror of the facade's
|
||||
* oakengine_encoding_format_* / codec_* surface (oakengine/encoding.h):
|
||||
* the export dialog queries it to populate its format/codec combo boxes and
|
||||
* to enable/disable the bit-rate controls. The functions are stateless —
|
||||
* no handles involved.
|
||||
*
|
||||
* Enum int fields carry the engine's own enum values
|
||||
* (olive::ExportFormat::Format, olive::ExportCodec::Codec,
|
||||
* olive::core::SampleFormat::Format) — the same values oakengine/encoding.h
|
||||
* documents. Return-code convention follows include/codec/error.h: 0
|
||||
* (OAKCODEC_OK) on success, a negative OAKCODEC_E_* code on failure, and
|
||||
* string getters return the required buffer size in bytes INCLUDING the
|
||||
* terminating NUL as a non-negative value (two-stage convention). Note this
|
||||
* differs from oakcodec_export_format_get_extension() (encoder.h), which
|
||||
* predates this family and reports unknown formats as the empty string.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Container formats (olive::ExportFormat::Format) referenced by name
|
||||
* in UI code. Only append; the values are serialized in project/preset
|
||||
* files. The complete list lives in src/codec/src/exportformat.h.
|
||||
*/
|
||||
#define OAKCODEC_ENCODING_FORMAT_MATROSKA 1
|
||||
#define OAKCODEC_ENCODING_FORMAT_MPEG4_VIDEO 2
|
||||
#define OAKCODEC_ENCODING_FORMAT_QUICKTIME 4
|
||||
#define OAKCODEC_ENCODING_FORMAT_PNG 5
|
||||
#define OAKCODEC_ENCODING_FORMAT_WAV 7
|
||||
#define OAKCODEC_ENCODING_FORMAT_SRT 13
|
||||
|
||||
/**
|
||||
* @brief Codecs (olive::ExportCodec::Codec) referenced by name in UI code.
|
||||
* Only append; the values are serialized. The complete list lives in
|
||||
* src/codec/src/exportcodec.h.
|
||||
*/
|
||||
#define OAKCODEC_ENCODING_CODEC_H264 1
|
||||
#define OAKCODEC_ENCODING_CODEC_H264RGB 2
|
||||
#define OAKCODEC_ENCODING_CODEC_H265 3
|
||||
#define OAKCODEC_ENCODING_CODEC_CINEFORM 7
|
||||
#define OAKCODEC_ENCODING_CODEC_AAC 12
|
||||
#define OAKCODEC_ENCODING_CODEC_PCM 13
|
||||
#define OAKCODEC_ENCODING_CODEC_SRT 17
|
||||
#define OAKCODEC_ENCODING_CODEC_AV1 18
|
||||
|
||||
/* ---- Container format / codec metadata ---------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Number of container formats (olive::ExportFormat::k_format_count).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_count(void);
|
||||
|
||||
/**
|
||||
* @brief Display name of a container format (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `format` is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_name(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief File extension (no dot) of a container format (buf/size,
|
||||
* two-stage); same return convention as
|
||||
* oakcodec_encoding_format_name().
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_extension(int format, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Number of video codecs a container format supports, or
|
||||
* OAKCODEC_E_INVALID when the format is invalid.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_video_codec_count(int format);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th video codec of `format` as an
|
||||
* olive::ExportCodec::Codec value.
|
||||
*
|
||||
* @return OAKCODEC_E_INVALID when the format is invalid, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_format_video_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/** @brief Audio-codec variant of the two functions above. */
|
||||
OAKCODEC_API int oakcodec_encoding_format_audio_codec_count(int format);
|
||||
OAKCODEC_API int oakcodec_encoding_format_audio_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/** @brief Subtitle-codec variant of the two functions above. */
|
||||
OAKCODEC_API int oakcodec_encoding_format_subtitle_codec_count(int format);
|
||||
OAKCODEC_API int oakcodec_encoding_format_subtitle_codec_at(int format,
|
||||
int index);
|
||||
|
||||
/**
|
||||
* @brief Display name of a codec (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `codec` is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_codec_name(int codec, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/** @brief 1 when `codec` encodes still images (PNG/TIFF/OpenEXR), else 0
|
||||
* (0 also for an invalid codec). */
|
||||
OAKCODEC_API int oakcodec_encoding_codec_is_still_image(int codec);
|
||||
|
||||
/** @brief 1 when `codec` is lossless (no bit-rate setting applies), else 0
|
||||
* (0 also for an invalid codec). */
|
||||
OAKCODEC_API int oakcodec_encoding_codec_is_lossless(int codec);
|
||||
|
||||
/**
|
||||
* @brief Number of encoded pixel formats (e.g. "yuv420p") usable with
|
||||
* `codec` inside `format`, or OAKCODEC_E_INVALID when either
|
||||
* argument is out of range. The list is queried from the format's
|
||||
* encoder (FFmpeg/OIIO), so codecs without an encoder report 0.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_count(int format, int codec);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th encoded pixel format name (buf/size, two-stage).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID for bad format/codec, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_at(int format, int codec,
|
||||
int index, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Index of `pix_fmt` (e.g. "yuv420p") in `codec`'s supported pixel
|
||||
* format list; 0 (the codec's preferred format) when absent or
|
||||
* `pix_fmt` is NULL/empty or `codec` is invalid.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_pix_fmt_index(int codec,
|
||||
const char *pix_fmt);
|
||||
|
||||
/**
|
||||
* @brief Number of sample formats usable with `codec` inside `format`, or
|
||||
* OAKCODEC_E_INVALID when either argument is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_sample_format_count(int format,
|
||||
int codec);
|
||||
|
||||
/**
|
||||
* @brief The `index`-th sample format as an olive::core::SampleFormat::Format
|
||||
* value.
|
||||
*
|
||||
* @return OAKCODEC_E_INVALID for bad format/codec, or
|
||||
* OAKCODEC_E_NOT_FOUND when the index is out of range.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_encoding_sample_format_at(int format, int codec,
|
||||
int index);
|
||||
|
||||
/* ---- Image-sequence filename helpers (olive::Encoder statics) ----------- */
|
||||
|
||||
/** @brief 1 when `filename` contains a "[#####]" digit placeholder, else 0
|
||||
* (0 for NULL). */
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_filename_contains_digit_placeholder(const char *filename);
|
||||
|
||||
/** @brief Digit count of the filename's "[#####]" placeholder; 0 when none
|
||||
* (0 for NULL). */
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_image_sequence_digit_count(const char *filename);
|
||||
|
||||
/**
|
||||
* @brief `filename` with the digit placeholder removed (buf/size, two-stage;
|
||||
* a leading separator like "_"/"-"/"."/" " before the placeholder is
|
||||
* removed along with it).
|
||||
*
|
||||
* @return The required buffer size (including the NUL), or
|
||||
* OAKCODEC_E_INVALID when `filename` is NULL.
|
||||
*/
|
||||
OAKCODEC_API int
|
||||
oakcodec_encoding_filename_remove_digit_placeholder(const char *filename,
|
||||
char *buf, int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_FORMAT_H
|
||||
@@ -0,0 +1,162 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_FRAME_H
|
||||
#define OAK_EDITOR_CODEC_FRAME_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/videoparams.h"
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file frame.h
|
||||
* @brief C ABI for the oakcodec frame object (olive::Frame), a CPU pixel
|
||||
* buffer plus an OakVideoParams parameter set.
|
||||
*
|
||||
* Handle convention (all oakcodec families): neutral by-value handles with
|
||||
* the same four fields as oakcommon (see oakcommon's common/handle.h):
|
||||
*
|
||||
* typedef struct OakFrame {
|
||||
* void *ctx; // opaque, points to the impl
|
||||
* void (*addref)(void *ctx); // atomic +1, owner-DLL code
|
||||
* void (*release)(void *ctx); // atomic -1, destroys at 0
|
||||
* uint32_t abi_version; // OAKCODEC_ABI_VERSION
|
||||
* } OakFrame;
|
||||
*
|
||||
* oakcodec_frame_init*() returns a handle whose underlying object has
|
||||
* reference count 1. Copying the struct copies the pointer, not the
|
||||
* count: call handle.addref(handle.ctx) for every additional long-lived
|
||||
* copy and handle.release(handle.ctx) (or oakcodec_frame_free()) when
|
||||
* done with each copy. Functions that only use a handle take it BY
|
||||
* VALUE; an empty handle (ctx == NULL) is reported as
|
||||
* OAKCODEC_E_INVALID. oakcodec_frame_free() takes a pointer so it can
|
||||
* null out the caller's ctx; NULL and ctx == NULL are no-ops.
|
||||
*/
|
||||
typedef struct OakFrame {
|
||||
void *ctx; /**< Opaque pointer to the reference-counted object. */
|
||||
void (*addref)(void *ctx); /**< Atomically increments the count. */
|
||||
void (*release)(void *ctx); /**< Decrements the count, destroys at 0. */
|
||||
uint32_t abi_version; /**< OAKCODEC_ABI_VERSION. */
|
||||
} OakFrame;
|
||||
|
||||
/**
|
||||
* @brief Create an empty frame with default (invalid) video parameters.
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on allocation
|
||||
* failure.
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_frame_init(void);
|
||||
|
||||
/**
|
||||
* @brief Create a frame with a copy of the given parameter set.
|
||||
*
|
||||
* The params handle is addref'd internally; the caller keeps its own
|
||||
* reference. The frame is not allocated; call oakcodec_frame_allocate().
|
||||
*
|
||||
* @return Handle with reference count 1; ctx is NULL on failure.
|
||||
*/
|
||||
OAKCODEC_API OakFrame oakcodec_frame_init_with_params(OakVideoParams params);
|
||||
|
||||
/**
|
||||
* @brief Release one reference to a frame.
|
||||
*
|
||||
* Convenience wrapper around handle.release(handle.ctx); nulls ctx
|
||||
* afterwards. No-op when frame is NULL or frame->ctx is NULL.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_frame_free(OakFrame *frame);
|
||||
|
||||
/**
|
||||
* @brief Get a copy of the frame's parameter set.
|
||||
*
|
||||
* @param out Receives an addref'd OakVideoParams; the caller must release
|
||||
* it with oakcommon_videoparams_free().
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_INVALID for bad arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_get_params(OakFrame frame, OakVideoParams *out);
|
||||
|
||||
/**
|
||||
* @brief Replace the frame's parameter set (the handle is addref'd
|
||||
* internally). Recomputes the line sizes; does not reallocate the
|
||||
* buffer.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_set_params(OakFrame frame, OakVideoParams params);
|
||||
|
||||
/**
|
||||
* @brief Allocate the pixel buffer from the current parameters.
|
||||
*
|
||||
* @return OAKCODEC_OK on success (including already-allocated),
|
||||
* OAKCODEC_E_STATE when the parameters are invalid,
|
||||
* OAKCODEC_E_INVALID for an empty handle.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_allocate(OakFrame frame);
|
||||
|
||||
/** @brief 1 when the pixel buffer is allocated, 0 otherwise. */
|
||||
OAKCODEC_API int oakcodec_frame_is_allocated(OakFrame frame);
|
||||
|
||||
/** @brief Writable pixel buffer, or NULL when unallocated/empty. */
|
||||
OAKCODEC_API void *oakcodec_frame_data(OakFrame frame);
|
||||
|
||||
/** @brief Const variant of oakcodec_frame_data(). */
|
||||
OAKCODEC_API const void *oakcodec_frame_const_data(OakFrame frame);
|
||||
|
||||
/** @brief Size of the pixel buffer in bytes (0 when unallocated). */
|
||||
OAKCODEC_API int oakcodec_frame_allocated_size(OakFrame frame);
|
||||
|
||||
/** @brief Distance between two rows in bytes (0 when params are unset). */
|
||||
OAKCODEC_API int oakcodec_frame_linesize_bytes(OakFrame frame);
|
||||
|
||||
/** @brief Distance between two rows in pixels. */
|
||||
OAKCODEC_API int oakcodec_frame_linesize_pixels(OakFrame frame);
|
||||
|
||||
/* Query helpers; all return 0 / OAKCOMMON_PIXEL_FORMAT_INVALID on an
|
||||
* empty handle. */
|
||||
OAKCODEC_API int oakcodec_frame_width(OakFrame frame);
|
||||
OAKCODEC_API int oakcodec_frame_height(OakFrame frame);
|
||||
OAKCODEC_API int oakcodec_frame_format(OakFrame frame); /**< OakPixelFormat value. */
|
||||
OAKCODEC_API int oakcodec_frame_channel_count(OakFrame frame);
|
||||
|
||||
/**
|
||||
* @brief Frame timestamp as a rational number of seconds.
|
||||
*
|
||||
* @return OAKCODEC_OK, or OAKCODEC_E_INVALID for bad arguments.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_frame_get_timestamp(OakFrame frame, int *numerator,
|
||||
int *denominator);
|
||||
OAKCODEC_API int oakcodec_frame_set_timestamp(OakFrame frame, int numerator,
|
||||
int denominator);
|
||||
|
||||
/**
|
||||
* @brief Number of live oakcodec handle objects (debug/leak checking).
|
||||
*
|
||||
* Counts every boxed object created by oakcodec_*_init*() that has not
|
||||
* been released yet, across all families (frame/decoder/encoder/...).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_debug_alive_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_FRAME_H
|
||||
@@ -0,0 +1,140 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_PROXY_H
|
||||
#define OAK_EDITOR_CODEC_PROXY_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file proxy.h
|
||||
* @brief C ABI for the oakcodec proxy generation singleton
|
||||
* (olive::ProxyManager).
|
||||
*
|
||||
* Interim state (pre-M8): actual transcodes are delegated to the global
|
||||
* task submit callback (see task.h). While no callback is registered,
|
||||
* oakcodec_proxy_get_or_start() reports the proxy as missing instead of
|
||||
* starting background work.
|
||||
*/
|
||||
|
||||
#define OAKCODEC_PROXY_STATE_MISSING 0
|
||||
#define OAKCODEC_PROXY_STATE_GENERATING 1
|
||||
#define OAKCODEC_PROXY_STATE_READY 2
|
||||
#define OAKCODEC_PROXY_STATE_FAILED 3
|
||||
|
||||
/**
|
||||
* @brief POD proxy generation parameters (olive::ProxyManager::ProxyParams).
|
||||
*
|
||||
* divider: source resolution divider (1 = use absolute width/height,
|
||||
* 2/4/8 = fraction of the source resolution). extension/preset are the
|
||||
* ffmpeg output container and encoder preset (e.g. "mp4"/"veryfast").
|
||||
*/
|
||||
typedef struct oakcodec_proxy_params {
|
||||
int width;
|
||||
int height;
|
||||
int divider;
|
||||
int version;
|
||||
int crf;
|
||||
int include_audio; /**< 1/0. */
|
||||
char extension[32];
|
||||
char preset[32];
|
||||
} oakcodec_proxy_params;
|
||||
|
||||
typedef struct oakcodec_proxy_result {
|
||||
int state; /**< OAKCODEC_PROXY_STATE_* */
|
||||
char filename[1024];
|
||||
} oakcodec_proxy_result;
|
||||
|
||||
/**
|
||||
* @brief Create the ProxyManager singleton (no-op when it exists).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_create_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Destroy the ProxyManager singleton (no-op when absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_destroy_instance(void);
|
||||
|
||||
/**
|
||||
* @brief Compiled-in default proxy parameters (1280x720, divider 1, mp4,
|
||||
* crf 23, "veryfast", audio included). Interim state: until the config
|
||||
* milestone wires a real store these do not reflect user settings.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_params_default(oakcodec_proxy_params *out);
|
||||
|
||||
/**
|
||||
* @brief State of a proxy file on disk (OAKCODEC_PROXY_STATE_*;
|
||||
* OAKCODEC_PROXY_STATE_MISSING for NULL/empty/absent).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_state(const char *proxy_filename);
|
||||
|
||||
/** @brief Human-readable string for a proxy state (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_state_to_string(int state, char *buf, int buf_size);
|
||||
|
||||
/** @brief Proxy directory for a project cache path (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_get_proxy_directory(const char *cache_path, char *buf,
|
||||
int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Deterministic proxy filename for a source stream (buf/size
|
||||
* getter).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_proxy_filename(const char *cache_path,
|
||||
const char *source_filename,
|
||||
int stream_index,
|
||||
const oakcodec_proxy_params *params,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/** @brief Working (in-progress) filename of a proxy (buf/size getter). */
|
||||
OAKCODEC_API int oakcodec_proxy_get_working_filename(const char *proxy_filename,
|
||||
char *buf, int buf_size);
|
||||
|
||||
/**
|
||||
* @brief Get or start generating a proxy for `source_filename`.
|
||||
*
|
||||
* `cache_path` is the project cache directory. On return `out->state`
|
||||
* and `out->filename` describe the proxy. When a task submit callback is
|
||||
* registered (task.h) and no proxy exists, generation is submitted
|
||||
* synchronously before the state is re-derived; without a registrar the
|
||||
* state stays OAKCODEC_PROXY_STATE_MISSING.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_get_or_start(const char *cache_path,
|
||||
const char *source_filename, int stream_index,
|
||||
const oakcodec_proxy_params *params,
|
||||
oakcodec_proxy_result *out);
|
||||
|
||||
/**
|
||||
* @brief Locate an ffmpeg executable for proxy generation (buf/size
|
||||
* getter; empty string when none is found).
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_proxy_find_ffmpeg(const char *configured_path, char *buf,
|
||||
int buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_PROXY_H
|
||||
@@ -0,0 +1,113 @@
|
||||
/***
|
||||
|
||||
Oak Video Editor - Non-Linear Video Editor
|
||||
Copyright (C) 2026 Oak Team
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
***/
|
||||
|
||||
#ifndef OAK_EDITOR_CODEC_TASK_H
|
||||
#define OAK_EDITOR_CODEC_TASK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Background task submission hook for oakcodec (interim state).
|
||||
*
|
||||
* The codec module occasionally needs background work (audio conforms,
|
||||
* proxy transcodes). The task system itself is split out at milestone M8;
|
||||
* until then oakcodec exposes a single global submit callback. A host
|
||||
* (M8: oaktask) registers a callback with oakcodec_set_task_submit_cb();
|
||||
* the conform/proxy managers call it whenever they need a task.
|
||||
*
|
||||
* While no callback is registered, managers report the work as
|
||||
* unavailable (they never crash and never block).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Kinds of background tasks oakcodec can request.
|
||||
*/
|
||||
enum OakCodecTaskKind {
|
||||
OAKCODEC_TASK_CONFORM = 0, /**< Audio conform to pcm cache files. */
|
||||
OAKCODEC_TASK_PROXY = 1 /**< Video proxy transcode. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Description of one background task request.
|
||||
*
|
||||
* All strings are borrowed and only valid for the duration of the
|
||||
* submit call; the callback must copy anything it retains.
|
||||
*
|
||||
* Field usage by kind:
|
||||
* - OAKCODEC_TASK_CONFORM: input_filename (source media), stream_index
|
||||
* (audio stream), output_filename (final path of the FIRST channel's
|
||||
* pcm file; the task derives the sibling per-channel paths and the
|
||||
* ".working" temporary names from the deterministic naming rule),
|
||||
* sample_rate / channel_layout / sample_format (target audio params,
|
||||
* sample_format is olive::core::SampleFormat::Format as int).
|
||||
* - OAKCODEC_TASK_PROXY: input_filename (source media), stream_index
|
||||
* (video stream), output_filename (final proxy path; the task owns
|
||||
* the ".working.mp4" temporary name and the rename on success),
|
||||
* proxy_width / proxy_height (absolute target size, both 0 when the
|
||||
* request is divider-based).
|
||||
*/
|
||||
typedef struct OakCodecTaskRequest {
|
||||
int kind; /**< OakCodecTaskKind. */
|
||||
const char *input_filename; /**< Source media filename. */
|
||||
const char *output_filename; /**< Final destination path (see above). */
|
||||
int stream_index; /**< Stream inside the source media. */
|
||||
int sample_rate; /**< conform: target sample rate. */
|
||||
uint64_t channel_layout; /**< conform: target channel layout mask. */
|
||||
int sample_format; /**< conform: target sample format (enum as int). */
|
||||
int proxy_width; /**< proxy: target width, 0 = unspecified/divider. */
|
||||
int proxy_height; /**< proxy: target height, 0 = unspecified/divider. */
|
||||
} OakCodecTaskRequest;
|
||||
|
||||
/**
|
||||
* @brief Task submit callback.
|
||||
*
|
||||
* @return 0 (OAKCODEC_OK) if the task was accepted - either completed
|
||||
* synchronously or queued; a negative OAKCODEC_E_* code if the request
|
||||
* was rejected.
|
||||
*/
|
||||
typedef int (*oakcodec_task_submit_fn)(const OakCodecTaskRequest *req,
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Registers (or replaces) the global task submit callback.
|
||||
*
|
||||
* Thread-safe. Pass cb == NULL to unregister. Interim state (pre-M8):
|
||||
* nobody registers and all task-dependent work reports unavailable.
|
||||
*/
|
||||
OAKCODEC_API void oakcodec_set_task_submit_cb(oakcodec_task_submit_fn cb, void *userdata);
|
||||
|
||||
/**
|
||||
* @brief Returns 1 if a submit callback is currently registered, else 0.
|
||||
*
|
||||
* Thread-safe.
|
||||
*/
|
||||
OAKCODEC_API int oakcodec_task_submit_is_registered(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //OAK_EDITOR_CODEC_TASK_H
|
||||
Reference in New Issue
Block a user