1use std::ffi::CString;
2
3use libcamera_sys::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Primaries {
8 Raw,
9 Smpte170m,
10 Rec709,
11 Rec2020,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum TransferFunction {
17 Linear,
18 Srgb,
19 Rec709,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum YcbcrEncoding {
25 None,
26 Rec601,
27 Rec709,
28 Rec2020,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum Range {
34 Full,
35 Limited,
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct ColorSpace {
41 pub primaries: Primaries,
42 pub transfer_function: TransferFunction,
43 pub ycbcr_encoding: YcbcrEncoding,
44 pub range: Range,
45}
46
47impl ColorSpace {
48 pub const fn new(
49 primaries: Primaries,
50 transfer_function: TransferFunction,
51 ycbcr_encoding: YcbcrEncoding,
52 range: Range,
53 ) -> Self {
54 Self {
55 primaries,
56 transfer_function,
57 ycbcr_encoding,
58 range,
59 }
60 }
61
62 pub fn raw() -> Self {
64 unsafe { libcamera_color_space_raw() }.into()
65 }
66 pub fn srgb() -> Self {
67 unsafe { libcamera_color_space_srgb() }.into()
68 }
69 pub fn sycc() -> Self {
70 unsafe { libcamera_color_space_sycc() }.into()
71 }
72 pub fn smpte170m() -> Self {
73 unsafe { libcamera_color_space_smpte170m() }.into()
74 }
75 pub fn rec709() -> Self {
76 unsafe { libcamera_color_space_rec709() }.into()
77 }
78 pub fn rec2020() -> Self {
79 unsafe { libcamera_color_space_rec2020() }.into()
80 }
81
82 pub fn to_repr(&self) -> String {
84 unsafe {
85 let ptr = libcamera_color_space_to_string(&(*self).into());
86 if ptr.is_null() {
87 return String::new();
88 }
89 let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned();
90 libc::free(ptr.cast());
91 s
92 }
93 }
94
95 pub fn from_string(s: &str) -> Option<Self> {
97 let cstr = CString::new(s).ok()?;
98 let mut cs = libcamera_color_space_t {
99 primaries: libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW,
100 transfer_function: libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR,
101 ycbcr_encoding: libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE,
102 range: libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL,
103 };
104 let ok = unsafe { libcamera_color_space_from_string(cstr.as_ptr(), &mut cs) };
105 if ok {
106 Some(ColorSpace::from(cs))
107 } else {
108 None
109 }
110 }
111
112 pub fn adjust_for_format(&mut self, pixel_format: crate::pixel_format::PixelFormat) -> bool {
117 let mut cs = (*self).into();
118 let adjusted = unsafe { libcamera_color_space_adjust(&mut cs, &pixel_format.0) };
119 *self = cs.into();
120 adjusted
121 }
122
123 pub fn with_adjusted_for_format(&self, pixel_format: crate::pixel_format::PixelFormat) -> Option<Self> {
128 let mut clone = *self;
129 let _ = clone.adjust_for_format(pixel_format);
130 Some(clone)
131 }
132}
133
134impl core::fmt::Display for ColorSpace {
135 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
136 f.write_str(&self.to_repr())
137 }
138}
139
140impl From<ColorSpace> for libcamera_color_space_t {
141 fn from(cs: ColorSpace) -> Self {
142 unsafe {
143 libcamera_color_space_make(
144 match cs.primaries {
145 Primaries::Raw => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW,
146 Primaries::Smpte170m => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_SMPTE170M,
147 Primaries::Rec709 => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC709,
148 Primaries::Rec2020 => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC2020,
149 },
150 match cs.transfer_function {
151 TransferFunction::Linear => {
152 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR
153 }
154 TransferFunction::Srgb => {
155 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_SRGB
156 }
157 TransferFunction::Rec709 => {
158 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_REC709
159 }
160 },
161 match cs.ycbcr_encoding {
162 YcbcrEncoding::None => {
163 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE
164 }
165 YcbcrEncoding::Rec601 => {
166 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC601
167 }
168 YcbcrEncoding::Rec709 => {
169 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC709
170 }
171 YcbcrEncoding::Rec2020 => {
172 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC2020
173 }
174 },
175 match cs.range {
176 Range::Full => libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL,
177 Range::Limited => libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_LIMITED,
178 },
179 )
180 }
181 }
182}
183
184impl From<libcamera_color_space_t> for ColorSpace {
185 fn from(cs: libcamera_color_space_t) -> Self {
186 let primaries = match cs.primaries {
187 libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW => Primaries::Raw,
188 libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_SMPTE170M => Primaries::Smpte170m,
189 libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC709 => Primaries::Rec709,
190 libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC2020 => Primaries::Rec2020,
191 _ => Primaries::Raw,
192 };
193 let transfer_function = match cs.transfer_function {
194 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR => {
195 TransferFunction::Linear
196 }
197 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_SRGB => {
198 TransferFunction::Srgb
199 }
200 libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_REC709 => {
201 TransferFunction::Rec709
202 }
203 _ => TransferFunction::Linear,
204 };
205 let ycbcr_encoding = match cs.ycbcr_encoding {
206 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE => YcbcrEncoding::None,
207 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC601 => YcbcrEncoding::Rec601,
208 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC709 => YcbcrEncoding::Rec709,
209 libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC2020 => {
210 YcbcrEncoding::Rec2020
211 }
212 _ => YcbcrEncoding::None,
213 };
214 let range = match cs.range {
215 libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL => Range::Full,
216 libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_LIMITED => Range::Limited,
217 _ => Range::Full,
218 };
219
220 ColorSpace {
221 primaries,
222 transfer_function,
223 ycbcr_encoding,
224 range,
225 }
226 }
227}