Skip to content

Commit 9ecb233

Browse files
FreezyLemonshssoichiro
authored andcommitted
Implement most of the chroma location API
1 parent 251c09e commit 9ecb233

File tree

2 files changed

+121
-1
lines changed

2 files changed

+121
-1
lines changed

ffmpeg-sys-the-third/src/avutil/pixfmt.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
1-
use crate::AVPixelFormat;
1+
use libc::c_int;
2+
3+
use crate::{AVChromaLocation, AVPixelFormat};
24
use crate::AVPixelFormat::*;
35

6+
impl AVChromaLocation {
7+
pub fn from_c_int(n: c_int) -> Option<Self> {
8+
use AVChromaLocation as AVCL;
9+
10+
Some(match n {
11+
n if n == AVCL::AVCHROMA_LOC_UNSPECIFIED as c_int => AVCL::AVCHROMA_LOC_UNSPECIFIED,
12+
n if n == AVCL::AVCHROMA_LOC_LEFT as c_int => AVCL::AVCHROMA_LOC_LEFT,
13+
n if n == AVCL::AVCHROMA_LOC_CENTER as c_int => AVCL::AVCHROMA_LOC_CENTER,
14+
n if n == AVCL::AVCHROMA_LOC_TOPLEFT as c_int => AVCL::AVCHROMA_LOC_TOPLEFT,
15+
n if n == AVCL::AVCHROMA_LOC_TOP as c_int => AVCL::AVCHROMA_LOC_TOP,
16+
n if n == AVCL::AVCHROMA_LOC_BOTTOMLEFT as c_int => AVCL::AVCHROMA_LOC_BOTTOMLEFT,
17+
n if n == AVCL::AVCHROMA_LOC_BOTTOM as c_int => AVCL::AVCHROMA_LOC_BOTTOM,
18+
19+
_ => return None,
20+
})
21+
}
22+
}
23+
424
#[cfg(target_endian = "little")]
525
pub const AV_PIX_FMT_RGB32: AVPixelFormat = AV_PIX_FMT_BGRA;
626
#[cfg(target_endian = "little")]

src/util/chroma/location.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use std::ffi::CString;
2+
13
use crate::ffi::AVChromaLocation::*;
24
use crate::ffi::*;
5+
use crate::utils;
6+
use crate::Error;
37
#[cfg(feature = "serialize")]
48
use serde::{Deserialize, Serialize};
59

@@ -15,6 +19,55 @@ pub enum Location {
1519
Bottom,
1620
}
1721

22+
impl Location {
23+
/// Returns the name of this location. Should usually return Some(name).
24+
pub fn name(self) -> Option<&'static str> {
25+
unsafe { utils::optional_str_from_c_ptr(av_chroma_location_name(self.into())) }
26+
}
27+
28+
/// Returns a chroma location for the given name or an error if the `name` is invalid
29+
/// or no location was found.
30+
pub fn from_name<S: AsRef<str>>(name: S) -> Result<Self, Error> {
31+
let Ok(cstr) = CString::new(name.as_ref()) else {
32+
// invalid argument (contains a nul byte)
33+
return Err(Error::from(AVERROR(libc::EINVAL)));
34+
};
35+
36+
let ret = unsafe { av_chroma_location_from_name(cstr.as_ptr()) };
37+
38+
if ret < 0 {
39+
Err(Error::from(ret))
40+
} else {
41+
AVChromaLocation::from_c_int(ret)
42+
.map(Location::from)
43+
.ok_or(Error::from(AVERROR(libc::EINVAL)))
44+
}
45+
}
46+
47+
/// Returns the swscale (x, y) chroma positions for this chroma location.
48+
/// Will panic if `self` is [`Unspecified`][Location::Unspecified].
49+
#[cfg(feature = "ffmpeg_6_0")]
50+
pub fn pos(self) -> (i32, i32) {
51+
let mut xpos = 0;
52+
let mut ypos = 0;
53+
let ret = unsafe { av_chroma_location_enum_to_pos(&mut xpos, &mut ypos, self.into()) };
54+
assert_eq!(ret, 0, "av_chroma_location_enum_to_pos returned an error");
55+
56+
(xpos as i32, ypos as i32)
57+
}
58+
59+
/// Returns a chroma location for the given swscale chroma position.
60+
#[cfg(feature = "ffmpeg_6_0")]
61+
pub fn from_pos(x: i32, y: i32) -> Self {
62+
unsafe {
63+
Self::from(av_chroma_location_pos_to_enum(
64+
x as libc::c_int,
65+
y as libc::c_int,
66+
))
67+
}
68+
}
69+
}
70+
1871
impl From<AVChromaLocation> for Location {
1972
fn from(value: AVChromaLocation) -> Self {
2073
match value {
@@ -46,3 +99,50 @@ impl From<Location> for AVChromaLocation {
4699
}
47100
}
48101
}
102+
103+
#[cfg(test)]
104+
mod test {
105+
use libc::EINVAL;
106+
107+
use super::*;
108+
109+
#[test]
110+
fn name() {
111+
assert_eq!(Location::BottomLeft.name(), Some("bottomleft"));
112+
assert_eq!(Location::Center.name(), Some("center"));
113+
assert_eq!(Location::Unspecified.name(), Some("unspecified"));
114+
}
115+
116+
#[test]
117+
fn from_name() {
118+
assert_eq!(Location::from_name("topleft"), Ok(Location::TopLeft));
119+
assert_eq!(
120+
Location::from_name("asdf"),
121+
Err(Error::Other { errno: EINVAL })
122+
);
123+
124+
let name = "test".to_string() + "\0something else";
125+
126+
// important: no panic or segfault!
127+
assert_eq!(
128+
Location::from_name(name),
129+
Err(Error::Other { errno: EINVAL })
130+
);
131+
}
132+
133+
#[test]
134+
#[cfg(feature = "ffmpeg_6_0")]
135+
fn pos() {
136+
assert_eq!(Location::BottomLeft.pos(), (0, 256));
137+
assert_eq!(Location::Left.pos(), (0, 128));
138+
assert_eq!(Location::Center.pos(), (128, 128));
139+
}
140+
141+
#[test]
142+
#[cfg(feature = "ffmpeg_6_0")]
143+
fn from_pos() {
144+
assert_eq!(Location::from_pos(0, 128), Location::Left);
145+
assert_eq!(Location::from_pos(128, 0), Location::Top);
146+
assert_eq!(Location::from_pos(10, 20), Location::Unspecified);
147+
}
148+
}

0 commit comments

Comments
 (0)