Files
oak-editor/include/codec/decoder.h
T
Mike-Solar 3d004c081b refactor(codec): de-Qt oakcodec and wrap it in a pure C ABI; switch common handles to refcounted value structs
- oakcodec: de-Qt all 20 sources (QThread decode loop -> std::thread,
  QObject/signals -> callbacks), pure C ABI in include/codec with
  refcounted neutral handles (OakFrame/OakDecoder/OakEncoder),
  framemanager moved in from render, frame_to_buffer/buffer_to_frame
  moved in from oakcommon oiioutils, codec->task via submit callback
  (M8 will register), all cross-module calls go through the other
  side's C API, -fvisibility=hidden + OAKCODEC_API
- oakcommon: handles become refcounted value structs
  {ctx, addref, release, abi_version} (FFmpeg-style), pass-by-value
  signatures, free() as release wrapper; init_from_native/get_native
  for copyable value objects; OakCommonXxx renamed to OakXxx
- oakcommon: add logging (log_debug/info/warning/critical with level
  filtering and sink injection) + printf-style oakcommon_log C wrapper
- oakrender: add CancelAtom C API family; complete
  oakrender_color_processor_convert_frame; fix get_processor() missing
  definition and OCIO env var lookup
- tests: oakcommon 174, oaknode 96, oakrender 42, oakcodec 18, all
  green in their standalone builds
2026-08-06 18:50:07 +08:00

213 lines
7.2 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_DECODER_H
#define OAK_EDITOR_CODEC_DECODER_H
#include <stdint.h>
#include "error.h"
#include "frame.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 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