Single mechanical restructure commit: - root Cargo.toml = oakapp bin + workspace; one cargo build produces oakapp, oak-cli, oak-worker, liboakengine.dylib - app/rust/src -> src/ (app at repo root, no rust/ nesting) - src/<mod>/rust -> crates/oak<mod>; src/oakcore-rs -> crates/oakcore; src/bindings/oakotio -> crates/oakotio; src/engine/rust -> crates/oakengine (keeps cdylib+staticlib+rlib) - public C headers include/<mod>/ -> crates/oakengine/include/<mod>/ - OFX SDK headers vendored into crates/oakplugin/ofx/ (HostSupport gone) - legacy deleted: old src/ C++ modules, engine/, core/, ffmpeg_bridge/, app/ (Qt), cli/worker C++, root CMakeLists, third_party/KDDockWidgets submodule, otio-install, all build-* output (~40GB) - oakstorage kept but excluded from the workspace (skeleton w/ todos); gpui excluded (own workspace) - verified: cargo build green, cargo test --workspace 1845/0 (with the documented OCIO_RS_* env override for the homebrew OCIO)
224 lines
7.5 KiB
C
224 lines
7.5 KiB
C
/***
|
|
|
|
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
|