pub const RGB_CHANNEL_COUNT: i32 = 3;
pub const RGBA_CHANNEL_COUNT: i32 = 4;
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;
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;
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;
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;
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]
}
}
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
}
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,
)
}
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,
}
}
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
}
}
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,
}
}
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,
_ => FB_SAMPLE_FMT_NONE,
}
}
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,
other => other,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compatible_bridge_pixel_format_no_limit_prefers_rgba_then_rgb_a64() {
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() {
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() {
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() {
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() {
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() {
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
);
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
);
}
}