CI / Build & test (Windows) (push) Failing after 7s
All crates take the oak-* kebab-case naming (oak-audio, oak-codec, oak-common, oak-core, oak-ffmpeg-link, oak-node, oak-otio, oak-plugin, oak-render, oak-storage, oak-task, oak-timeline, oak-undo), with the lib identifiers rewritten (oakrender:: -> oak_render::, oakcore_rs:: -> oak_core::, ...) across all 226 referencing files. The GUI application moves from the workspace root into crates/oak-app/: src/, build.rs (paths fixed for the new location) and tests/ travel with it, the root Cargo.toml becomes workspace-only ([workspace] + workspace.package + profiles), and the app package inherits the workspace version. The screenshots example becomes a standalone crate examples/simple_player/ with its own Cargo.toml. Every crate now inherits the single workspace version (version.workspace = true), and the workflows' crate paths and the build docs follow the renames. Validated with a clean cargo check --workspace.
523 lines
17 KiB
Rust
523 lines
17 KiB
Rust
// 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/>.
|
|
|
|
//! Stateless pixel/sample format mappings between the native formats and
|
|
//! the opaque `FBPixelFormat` / `FBSampleFormat` constants of ffmpeg_bridge.
|
|
//! Mirrors `src/common/src/ffmpegutils.h` and
|
|
//! `include/common/ffmpegutils.h`. There is no handle to create or free.
|
|
//!
|
|
//! The bridge constants are plain ints copied verbatim from the ffmpeg_bridge
|
|
//! header (kept for C ABI compatibility); native formats are plain ints
|
|
//! matching `olive::core` enum values.
|
|
|
|
/// RGB channel count (flattened from `VideoParams`).
|
|
pub const RGB_CHANNEL_COUNT: i32 = 3;
|
|
/// RGBA channel count (flattened from `VideoParams`).
|
|
pub const RGBA_CHANNEL_COUNT: i32 = 4;
|
|
|
|
//
|
|
// Native `olive::core::PixelFormat::Format` values (see
|
|
// `core/include/olive/core/render/pixelformat.h`). Plain ints matching the
|
|
// C++ enum discriminants.
|
|
//
|
|
const PIX_FMT_INVALID: i32 = -1;
|
|
const PIX_FMT_U8: i32 = 0;
|
|
const PIX_FMT_U10: i32 = 1;
|
|
const PIX_FMT_U16: i32 = 2;
|
|
const PIX_FMT_F16: i32 = 3;
|
|
const PIX_FMT_F32: i32 = 4;
|
|
#[cfg(test)]
|
|
const PIX_FMT_COUNT: i32 = 5;
|
|
|
|
//
|
|
// Native `olive::core::SampleFormat::Format` values (see
|
|
// `core/include/olive/core/render/sampleformat.h`). The `_p` (planar)
|
|
// variants come first in the C++ enum.
|
|
//
|
|
const SMP_FMT_INVALID: i32 = -1;
|
|
const SMP_FMT_U8_P: i32 = 0;
|
|
const SMP_FMT_S16_P: i32 = 1;
|
|
const SMP_FMT_S32_P: i32 = 2;
|
|
const SMP_FMT_S64_P: i32 = 3;
|
|
const SMP_FMT_F32_P: i32 = 4;
|
|
const SMP_FMT_F64_P: i32 = 5;
|
|
const SMP_FMT_U8: i32 = 6;
|
|
const SMP_FMT_S16: i32 = 7;
|
|
const SMP_FMT_S32: i32 = 8;
|
|
const SMP_FMT_S64: i32 = 9;
|
|
const SMP_FMT_F32: i32 = 10;
|
|
const SMP_FMT_F64: i32 = 11;
|
|
#[cfg(test)]
|
|
const SMP_FMT_COUNT: i32 = 12;
|
|
|
|
//
|
|
// Opaque `FBPixelFormat` constants (see
|
|
// `ffmpeg_bridge/include/ffmpeg_bridge/ffmpeg_bridge.h`). Only the subset
|
|
// this module's mappings produce/consume is declared; the values are copied
|
|
// verbatim from the header.
|
|
//
|
|
const FB_PIX_FMT_NONE: i32 = -1;
|
|
const FB_PIX_FMT_YU_V420_P: i32 = 0;
|
|
const FB_PIX_FMT_RG_B24: i32 = 2;
|
|
const FB_PIX_FMT_YU_V422_P: i32 = 4;
|
|
const FB_PIX_FMT_YU_V444_P: i32 = 5;
|
|
const FB_PIX_FMT_YU_V411_P: i32 = 7;
|
|
const FB_PIX_FMT_YUV_J420_P: i32 = 12;
|
|
const FB_PIX_FMT_YUV_J422_P: i32 = 13;
|
|
const FB_PIX_FMT_YUV_J444_P: i32 = 14;
|
|
const FB_PIX_FMT_RGBA: i32 = 26;
|
|
const FB_PIX_FMT_YU_V440_P: i32 = 31;
|
|
const FB_PIX_FMT_YUV_J440_P: i32 = 32;
|
|
const FB_PIX_FMT_RG_B48_LE: i32 = 35;
|
|
const FB_PIX_FMT_RGB_A64_LE: i32 = 105;
|
|
const FB_PIX_FMT_YUV_J411_P: i32 = 138;
|
|
const FB_PIX_FMT_RGBA_F16_LE: i32 = 207;
|
|
const FB_PIX_FMT_RGB_F32_LE: i32 = 218;
|
|
const FB_PIX_FMT_RGBA_F32_LE: i32 = 220;
|
|
const FB_PIX_FMT_RGB_F16_LE: i32 = 234;
|
|
|
|
//
|
|
// Opaque `FBSampleFormat` constants (same header).
|
|
//
|
|
const FB_SAMPLE_FMT_NONE: i32 = -1;
|
|
const FB_SAMPLE_FMT_U8: i32 = 0;
|
|
const FB_SAMPLE_FMT_S16: i32 = 1;
|
|
const FB_SAMPLE_FMT_S32: i32 = 2;
|
|
const FB_SAMPLE_FMT_FLT: i32 = 3;
|
|
const FB_SAMPLE_FMT_DBL: i32 = 4;
|
|
const FB_SAMPLE_FMT_U8_P: i32 = 5;
|
|
const FB_SAMPLE_FMT_S16_P: i32 = 6;
|
|
const FB_SAMPLE_FMT_S32_P: i32 = 7;
|
|
const FB_SAMPLE_FMT_FLTP: i32 = 8;
|
|
const FB_SAMPLE_FMT_DBLP: i32 = 9;
|
|
const FB_SAMPLE_FMT_S64: i32 = 10;
|
|
const FB_SAMPLE_FMT_S64_P: i32 = 11;
|
|
|
|
/// Picks the entry of a `FB_PIX_FMT_NONE`-terminated candidate list closest
|
|
/// to `pix_fmt`: an exact match wins, otherwise the first (most desirable)
|
|
/// candidate — for this module's RGB-only candidate lists that is also what
|
|
/// the bridge's loss-metric selection (`avcodec_find_best_pix_fmt_of_list`
|
|
/// via the former `fb_find_best_pix_fmt_of_list` C ABI import) produces.
|
|
/// The logic now runs in-process; nothing links ffmpeg_bridge anymore.
|
|
fn find_best_pix_fmt_of_list(list: &[i32; 4], pix_fmt: i32) -> i32 {
|
|
for &candidate in list {
|
|
if candidate == pix_fmt {
|
|
return candidate;
|
|
}
|
|
if candidate == FB_PIX_FMT_NONE {
|
|
break;
|
|
}
|
|
}
|
|
if list[0] == FB_PIX_FMT_NONE {
|
|
FB_PIX_FMT_NONE
|
|
} else {
|
|
list[0]
|
|
}
|
|
}
|
|
|
|
/// Builds the `FB_PIX_FMT_NONE`-terminated candidate list for
|
|
/// [`get_compatible_bridge_pixel_format`], clamped to `maximum_pix_fmt`
|
|
/// (a native pixel format, or `PIX_FMT_INVALID` for no limit).
|
|
///
|
|
/// # CPP-PARITY
|
|
/// Mirrors the `possible_pix_fmts` construction in
|
|
/// `FFmpegUtils::get_compatible_bridge_pixel_format` (the `maximum` clamp:
|
|
/// `u8` only allows RGBA; `f32` additionally allows RGBA-f32).
|
|
fn compatible_bridge_pixel_format_list(maximum_pix_fmt: i32) -> [i32; 4] {
|
|
let mut possible = [FB_PIX_FMT_NONE; 4];
|
|
possible[0] = FB_PIX_FMT_RGBA;
|
|
if maximum_pix_fmt == PIX_FMT_U8 {
|
|
possible[1] = FB_PIX_FMT_NONE;
|
|
} else {
|
|
possible[1] = FB_PIX_FMT_RGB_A64_LE;
|
|
if maximum_pix_fmt == PIX_FMT_F32 {
|
|
possible[2] = FB_PIX_FMT_RGBA_F32_LE;
|
|
possible[3] = FB_PIX_FMT_NONE;
|
|
} else {
|
|
possible[2] = FB_PIX_FMT_NONE;
|
|
}
|
|
}
|
|
possible
|
|
}
|
|
|
|
/// Bridge pixel format a frame can be converted to with minimal data loss,
|
|
/// clamped to a maximum native precision (`maximum_pix_fmt == -1` for no
|
|
/// limit).
|
|
pub fn get_compatible_bridge_pixel_format(pix_fmt: i32, maximum_pix_fmt: i32) -> i32 {
|
|
find_best_pix_fmt_of_list(
|
|
&compatible_bridge_pixel_format_list(maximum_pix_fmt),
|
|
pix_fmt,
|
|
)
|
|
}
|
|
|
|
/// Native pixel format usable to convert from a native frame to a bridge
|
|
/// frame with minimal data loss (`-1` if none).
|
|
pub fn get_compatible_pixel_format(pix_fmt: i32) -> i32 {
|
|
match pix_fmt {
|
|
PIX_FMT_U8 | PIX_FMT_U10 => PIX_FMT_U8,
|
|
PIX_FMT_U16 | PIX_FMT_F16 | PIX_FMT_F32 => PIX_FMT_U16,
|
|
_ => PIX_FMT_INVALID,
|
|
}
|
|
}
|
|
|
|
/// Bridge pixel format for a given native pixel format and channel count.
|
|
pub fn get_ffmpeg_pixel_format(pix_fmt: i32, channel_count: i32) -> i32 {
|
|
if channel_count == RGB_CHANNEL_COUNT {
|
|
match pix_fmt {
|
|
PIX_FMT_U8 => FB_PIX_FMT_RG_B24,
|
|
PIX_FMT_U10 => FB_PIX_FMT_NONE,
|
|
PIX_FMT_U16 => FB_PIX_FMT_RG_B48_LE,
|
|
PIX_FMT_F16 => FB_PIX_FMT_RGB_F16_LE,
|
|
PIX_FMT_F32 => FB_PIX_FMT_RGB_F32_LE,
|
|
_ => FB_PIX_FMT_NONE,
|
|
}
|
|
} else if channel_count == RGBA_CHANNEL_COUNT {
|
|
match pix_fmt {
|
|
PIX_FMT_U8 => FB_PIX_FMT_RGBA,
|
|
PIX_FMT_U10 => FB_PIX_FMT_NONE,
|
|
PIX_FMT_U16 => FB_PIX_FMT_RGB_A64_LE,
|
|
PIX_FMT_F16 => FB_PIX_FMT_RGBA_F16_LE,
|
|
PIX_FMT_F32 => FB_PIX_FMT_RGBA_F32_LE,
|
|
_ => FB_PIX_FMT_NONE,
|
|
}
|
|
} else {
|
|
FB_PIX_FMT_NONE
|
|
}
|
|
}
|
|
|
|
/// Native sample format for a given bridge sample format (`-1` if unknown).
|
|
pub fn get_native_sample_format(smp_fmt: i32) -> i32 {
|
|
match smp_fmt {
|
|
FB_SAMPLE_FMT_U8 => SMP_FMT_U8,
|
|
FB_SAMPLE_FMT_S16 => SMP_FMT_S16,
|
|
FB_SAMPLE_FMT_S32 => SMP_FMT_S32,
|
|
FB_SAMPLE_FMT_S64 => SMP_FMT_S64,
|
|
FB_SAMPLE_FMT_FLT => SMP_FMT_F32,
|
|
FB_SAMPLE_FMT_DBL => SMP_FMT_F64,
|
|
FB_SAMPLE_FMT_U8_P => SMP_FMT_U8_P,
|
|
FB_SAMPLE_FMT_S16_P => SMP_FMT_S16_P,
|
|
FB_SAMPLE_FMT_S32_P => SMP_FMT_S32_P,
|
|
FB_SAMPLE_FMT_S64_P => SMP_FMT_S64_P,
|
|
FB_SAMPLE_FMT_FLTP => SMP_FMT_F32_P,
|
|
FB_SAMPLE_FMT_DBLP => SMP_FMT_F64_P,
|
|
_ => SMP_FMT_INVALID,
|
|
}
|
|
}
|
|
|
|
/// Bridge sample format for a given native sample format.
|
|
pub fn get_ffmpeg_sample_format(smp_fmt: i32) -> i32 {
|
|
match smp_fmt {
|
|
SMP_FMT_U8 => FB_SAMPLE_FMT_U8,
|
|
SMP_FMT_S16 => FB_SAMPLE_FMT_S16,
|
|
SMP_FMT_S32 => FB_SAMPLE_FMT_S32,
|
|
SMP_FMT_S64 => FB_SAMPLE_FMT_S64,
|
|
SMP_FMT_F32 => FB_SAMPLE_FMT_FLT,
|
|
SMP_FMT_F64 => FB_SAMPLE_FMT_DBL,
|
|
SMP_FMT_U8_P => FB_SAMPLE_FMT_U8_P,
|
|
SMP_FMT_S16_P => FB_SAMPLE_FMT_S16_P,
|
|
SMP_FMT_S32_P => FB_SAMPLE_FMT_S32_P,
|
|
SMP_FMT_S64_P => FB_SAMPLE_FMT_S64_P,
|
|
SMP_FMT_F32_P => FB_SAMPLE_FMT_FLTP,
|
|
SMP_FMT_F64_P => FB_SAMPLE_FMT_DBLP,
|
|
// `invalid` and `count` both fall through to "no bridge format".
|
|
_ => FB_SAMPLE_FMT_NONE,
|
|
}
|
|
}
|
|
|
|
/// Convert a "JPEG" full-range bridge pixel format to its regular
|
|
/// counterpart (unchanged if not JPEG).
|
|
pub fn convert_jpeg_space_to_regular_space(pix_fmt: i32) -> i32 {
|
|
match pix_fmt {
|
|
FB_PIX_FMT_YUV_J420_P => FB_PIX_FMT_YU_V420_P,
|
|
FB_PIX_FMT_YUV_J422_P => FB_PIX_FMT_YU_V422_P,
|
|
FB_PIX_FMT_YUV_J444_P => FB_PIX_FMT_YU_V444_P,
|
|
FB_PIX_FMT_YUV_J440_P => FB_PIX_FMT_YU_V440_P,
|
|
FB_PIX_FMT_YUV_J411_P => FB_PIX_FMT_YU_V411_P,
|
|
// Any other format is passed through unchanged.
|
|
other => other,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_no_limit_prefers_rgba_then_rgb_a64() {
|
|
// `maximum == invalid (-1)`: candidate list is [rgba, rgb_a64_le, none].
|
|
let list = compatible_bridge_pixel_format_list(PIX_FMT_INVALID);
|
|
assert_eq!(list[0], FB_PIX_FMT_RGBA);
|
|
assert_eq!(list[1], FB_PIX_FMT_RGB_A64_LE);
|
|
assert_eq!(list[2], FB_PIX_FMT_NONE);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_u8_clamp_allows_only_rgba() {
|
|
// `maximum == u8`: candidate list is [rgba, none].
|
|
let list = compatible_bridge_pixel_format_list(PIX_FMT_U8);
|
|
assert_eq!(list[0], FB_PIX_FMT_RGBA);
|
|
assert_eq!(list[1], FB_PIX_FMT_NONE);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_f32_clamp_adds_rgba_f32() {
|
|
// `maximum == f32`: candidate list is [rgba, rgb_a64_le, rgba_f32_le, none].
|
|
let list = compatible_bridge_pixel_format_list(PIX_FMT_F32);
|
|
assert_eq!(list[0], FB_PIX_FMT_RGBA);
|
|
assert_eq!(list[1], FB_PIX_FMT_RGB_A64_LE);
|
|
assert_eq!(list[2], FB_PIX_FMT_RGBA_F32_LE);
|
|
assert_eq!(list[3], FB_PIX_FMT_NONE);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_u16_clamp_matches_default() {
|
|
// `maximum == u16` is neither u8 nor f32, so it matches the no-limit
|
|
// candidate list.
|
|
assert_eq!(
|
|
compatible_bridge_pixel_format_list(PIX_FMT_U16),
|
|
compatible_bridge_pixel_format_list(PIX_FMT_INVALID)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_picks_exact_candidate() {
|
|
// With the test stub an exact match in the candidate list is preferred.
|
|
assert_eq!(
|
|
get_compatible_bridge_pixel_format(FB_PIX_FMT_RGBA, PIX_FMT_INVALID),
|
|
FB_PIX_FMT_RGBA
|
|
);
|
|
assert_eq!(
|
|
get_compatible_bridge_pixel_format(FB_PIX_FMT_RGB_A64_LE, PIX_FMT_F32),
|
|
FB_PIX_FMT_RGB_A64_LE
|
|
);
|
|
assert_eq!(
|
|
get_compatible_bridge_pixel_format(FB_PIX_FMT_RGBA_F32_LE, PIX_FMT_F32),
|
|
FB_PIX_FMT_RGBA_F32_LE
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_bridge_pixel_format_unknown_falls_back_to_first() {
|
|
// A source format that is not among the candidates falls back to the
|
|
// first (most desirable) candidate.
|
|
assert_eq!(
|
|
get_compatible_bridge_pixel_format(FB_PIX_FMT_YU_V420_P, PIX_FMT_INVALID),
|
|
FB_PIX_FMT_RGBA
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_pixel_format_maps_native_to_least_lossy() {
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_U8), PIX_FMT_U8);
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_U10), PIX_FMT_U8);
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_U16), PIX_FMT_U16);
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_F16), PIX_FMT_U16);
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_F32), PIX_FMT_U16);
|
|
}
|
|
|
|
#[test]
|
|
fn compatible_pixel_format_invalid_and_count_map_to_invalid() {
|
|
assert_eq!(
|
|
get_compatible_pixel_format(PIX_FMT_INVALID),
|
|
PIX_FMT_INVALID
|
|
);
|
|
assert_eq!(get_compatible_pixel_format(PIX_FMT_COUNT), PIX_FMT_INVALID);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_pixel_format_rgb_channel_layout() {
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U8, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RG_B24
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U10, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U16, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RG_B48_LE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_F16, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGB_F16_LE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_F32, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGB_F32_LE
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_pixel_format_rgba_channel_layout() {
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U8, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGBA
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U10, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_U16, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGB_A64_LE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_F16, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGBA_F16_LE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_F32, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_RGBA_F32_LE
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_pixel_format_other_channel_layout_returns_none() {
|
|
assert_eq!(get_ffmpeg_pixel_format(PIX_FMT_U8, 0), FB_PIX_FMT_NONE);
|
|
assert_eq!(get_ffmpeg_pixel_format(PIX_FMT_U8, 2), FB_PIX_FMT_NONE);
|
|
assert_eq!(get_ffmpeg_pixel_format(PIX_FMT_U8, 5), FB_PIX_FMT_NONE);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_pixel_format_invalid_and_count_return_none() {
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_INVALID, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_COUNT, RGB_CHANNEL_COUNT),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
assert_eq!(
|
|
get_ffmpeg_pixel_format(PIX_FMT_INVALID, RGBA_CHANNEL_COUNT),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn native_sample_format_maps_bridge_to_native() {
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_U8), SMP_FMT_U8);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S16), SMP_FMT_S16);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S32), SMP_FMT_S32);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S64), SMP_FMT_S64);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_FLT), SMP_FMT_F32);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_DBL), SMP_FMT_F64);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_U8_P), SMP_FMT_U8_P);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S16_P), SMP_FMT_S16_P);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S32_P), SMP_FMT_S32_P);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_S64_P), SMP_FMT_S64_P);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_FLTP), SMP_FMT_F32_P);
|
|
assert_eq!(get_native_sample_format(FB_SAMPLE_FMT_DBLP), SMP_FMT_F64_P);
|
|
}
|
|
|
|
#[test]
|
|
fn native_sample_format_unknown_maps_to_invalid() {
|
|
assert_eq!(
|
|
get_native_sample_format(FB_SAMPLE_FMT_NONE),
|
|
SMP_FMT_INVALID
|
|
);
|
|
// A bogus code that does not match any bridge sample format.
|
|
assert_eq!(get_native_sample_format(12345), SMP_FMT_INVALID);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_sample_format_maps_native_to_bridge() {
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_U8), FB_SAMPLE_FMT_U8);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S16), FB_SAMPLE_FMT_S16);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S32), FB_SAMPLE_FMT_S32);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S64), FB_SAMPLE_FMT_S64);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_F32), FB_SAMPLE_FMT_FLT);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_F64), FB_SAMPLE_FMT_DBL);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_U8_P), FB_SAMPLE_FMT_U8_P);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S16_P), FB_SAMPLE_FMT_S16_P);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S32_P), FB_SAMPLE_FMT_S32_P);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_S64_P), FB_SAMPLE_FMT_S64_P);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_F32_P), FB_SAMPLE_FMT_FLTP);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_F64_P), FB_SAMPLE_FMT_DBLP);
|
|
}
|
|
|
|
#[test]
|
|
fn ffmpeg_sample_format_invalid_and_count_return_none() {
|
|
assert_eq!(
|
|
get_ffmpeg_sample_format(SMP_FMT_INVALID),
|
|
FB_SAMPLE_FMT_NONE
|
|
);
|
|
assert_eq!(get_ffmpeg_sample_format(SMP_FMT_COUNT), FB_SAMPLE_FMT_NONE);
|
|
}
|
|
|
|
#[test]
|
|
fn sample_format_mappings_are_inverse() {
|
|
for native in [
|
|
SMP_FMT_U8,
|
|
SMP_FMT_S16,
|
|
SMP_FMT_S32,
|
|
SMP_FMT_S64,
|
|
SMP_FMT_F32,
|
|
SMP_FMT_F64,
|
|
SMP_FMT_U8_P,
|
|
SMP_FMT_S16_P,
|
|
SMP_FMT_S32_P,
|
|
SMP_FMT_S64_P,
|
|
SMP_FMT_F32_P,
|
|
SMP_FMT_F64_P,
|
|
] {
|
|
let bridge = get_ffmpeg_sample_format(native);
|
|
assert_eq!(get_native_sample_format(bridge), native);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn jpeg_space_converts_to_regular_space() {
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YUV_J420_P),
|
|
FB_PIX_FMT_YU_V420_P
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YUV_J422_P),
|
|
FB_PIX_FMT_YU_V422_P
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YUV_J444_P),
|
|
FB_PIX_FMT_YU_V444_P
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YUV_J440_P),
|
|
FB_PIX_FMT_YU_V440_P
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YUV_J411_P),
|
|
FB_PIX_FMT_YU_V411_P
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn jpeg_space_leaves_non_jpeg_formats_unchanged() {
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_RGBA),
|
|
FB_PIX_FMT_RGBA
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_NONE),
|
|
FB_PIX_FMT_NONE
|
|
);
|
|
assert_eq!(
|
|
convert_jpeg_space_to_regular_space(FB_PIX_FMT_YU_V420_P),
|
|
FB_PIX_FMT_YU_V420_P
|
|
);
|
|
}
|
|
}
|