Implement most of the chroma location API

This commit is contained in:
FreezyLemon 2024-10-23 12:50:58 +02:00 committed by Josh Holmer
parent 251c09e732
commit 9ecb233d50
2 changed files with 121 additions and 1 deletions

View File

@ -1,6 +1,26 @@
use crate::AVPixelFormat;
use libc::c_int;
use crate::{AVChromaLocation, AVPixelFormat};
use crate::AVPixelFormat::*;
impl AVChromaLocation {
pub fn from_c_int(n: c_int) -> Option<Self> {
use AVChromaLocation as AVCL;
Some(match n {
n if n == AVCL::AVCHROMA_LOC_UNSPECIFIED as c_int => AVCL::AVCHROMA_LOC_UNSPECIFIED,
n if n == AVCL::AVCHROMA_LOC_LEFT as c_int => AVCL::AVCHROMA_LOC_LEFT,
n if n == AVCL::AVCHROMA_LOC_CENTER as c_int => AVCL::AVCHROMA_LOC_CENTER,
n if n == AVCL::AVCHROMA_LOC_TOPLEFT as c_int => AVCL::AVCHROMA_LOC_TOPLEFT,
n if n == AVCL::AVCHROMA_LOC_TOP as c_int => AVCL::AVCHROMA_LOC_TOP,
n if n == AVCL::AVCHROMA_LOC_BOTTOMLEFT as c_int => AVCL::AVCHROMA_LOC_BOTTOMLEFT,
n if n == AVCL::AVCHROMA_LOC_BOTTOM as c_int => AVCL::AVCHROMA_LOC_BOTTOM,
_ => return None,
})
}
}
#[cfg(target_endian = "little")]
pub const AV_PIX_FMT_RGB32: AVPixelFormat = AV_PIX_FMT_BGRA;
#[cfg(target_endian = "little")]

View File

@ -1,5 +1,9 @@
use std::ffi::CString;
use crate::ffi::AVChromaLocation::*;
use crate::ffi::*;
use crate::utils;
use crate::Error;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
@ -15,6 +19,55 @@ pub enum Location {
Bottom,
}
impl Location {
/// Returns the name of this location. Should usually return Some(name).
pub fn name(self) -> Option<&'static str> {
unsafe { utils::optional_str_from_c_ptr(av_chroma_location_name(self.into())) }
}
/// Returns a chroma location for the given name or an error if the `name` is invalid
/// or no location was found.
pub fn from_name<S: AsRef<str>>(name: S) -> Result<Self, Error> {
let Ok(cstr) = CString::new(name.as_ref()) else {
// invalid argument (contains a nul byte)
return Err(Error::from(AVERROR(libc::EINVAL)));
};
let ret = unsafe { av_chroma_location_from_name(cstr.as_ptr()) };
if ret < 0 {
Err(Error::from(ret))
} else {
AVChromaLocation::from_c_int(ret)
.map(Location::from)
.ok_or(Error::from(AVERROR(libc::EINVAL)))
}
}
/// Returns the swscale (x, y) chroma positions for this chroma location.
/// Will panic if `self` is [`Unspecified`][Location::Unspecified].
#[cfg(feature = "ffmpeg_6_0")]
pub fn pos(self) -> (i32, i32) {
let mut xpos = 0;
let mut ypos = 0;
let ret = unsafe { av_chroma_location_enum_to_pos(&mut xpos, &mut ypos, self.into()) };
assert_eq!(ret, 0, "av_chroma_location_enum_to_pos returned an error");
(xpos as i32, ypos as i32)
}
/// Returns a chroma location for the given swscale chroma position.
#[cfg(feature = "ffmpeg_6_0")]
pub fn from_pos(x: i32, y: i32) -> Self {
unsafe {
Self::from(av_chroma_location_pos_to_enum(
x as libc::c_int,
y as libc::c_int,
))
}
}
}
impl From<AVChromaLocation> for Location {
fn from(value: AVChromaLocation) -> Self {
match value {
@ -46,3 +99,50 @@ impl From<Location> for AVChromaLocation {
}
}
}
#[cfg(test)]
mod test {
use libc::EINVAL;
use super::*;
#[test]
fn name() {
assert_eq!(Location::BottomLeft.name(), Some("bottomleft"));
assert_eq!(Location::Center.name(), Some("center"));
assert_eq!(Location::Unspecified.name(), Some("unspecified"));
}
#[test]
fn from_name() {
assert_eq!(Location::from_name("topleft"), Ok(Location::TopLeft));
assert_eq!(
Location::from_name("asdf"),
Err(Error::Other { errno: EINVAL })
);
let name = "test".to_string() + "\0something else";
// important: no panic or segfault!
assert_eq!(
Location::from_name(name),
Err(Error::Other { errno: EINVAL })
);
}
#[test]
#[cfg(feature = "ffmpeg_6_0")]
fn pos() {
assert_eq!(Location::BottomLeft.pos(), (0, 256));
assert_eq!(Location::Left.pos(), (0, 128));
assert_eq!(Location::Center.pos(), (128, 128));
}
#[test]
#[cfg(feature = "ffmpeg_6_0")]
fn from_pos() {
assert_eq!(Location::from_pos(0, 128), Location::Left);
assert_eq!(Location::from_pos(128, 0), Location::Top);
assert_eq!(Location::from_pos(10, 20), Location::Unspecified);
}
}