1
+ use std:: ffi:: CString ;
2
+
1
3
use crate :: ffi:: AVChromaLocation :: * ;
2
4
use crate :: ffi:: * ;
5
+ use crate :: utils;
6
+ use crate :: Error ;
3
7
#[ cfg( feature = "serialize" ) ]
4
8
use serde:: { Deserialize , Serialize } ;
5
9
@@ -15,6 +19,55 @@ pub enum Location {
15
19
Bottom ,
16
20
}
17
21
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
+
18
71
impl From < AVChromaLocation > for Location {
19
72
fn from ( value : AVChromaLocation ) -> Self {
20
73
match value {
@@ -46,3 +99,50 @@ impl From<Location> for AVChromaLocation {
46
99
}
47
100
}
48
101
}
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 ( ) + "\0 something 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