1use crate::built_coefficients::{get_built_forward_transform, get_built_inverse_transform};
30use num_traits::AsPrimitive;
31use std::fmt::{Display, Formatter};
32
33#[derive(Debug, Copy, Clone)]
34pub struct CbCrInverseTransform<T> {
35 pub y_coef: T,
36 pub cr_coef: T,
37 pub cb_coef: T,
38 pub g_coeff_1: T,
39 pub g_coeff_2: T,
40}
41
42impl<T> CbCrInverseTransform<T> {
43 pub fn new(
44 y_coef: T,
45 cr_coef: T,
46 cb_coef: T,
47 g_coeff_1: T,
48 g_coeff_2: T,
49 ) -> CbCrInverseTransform<T> {
50 CbCrInverseTransform {
51 y_coef,
52 cr_coef,
53 cb_coef,
54 g_coeff_1,
55 g_coeff_2,
56 }
57 }
58}
59
60impl CbCrInverseTransform<f32> {
61 pub fn to_integers(self, precision: u32) -> CbCrInverseTransform<i32> {
63 let precision_scale: i32 = 1i32 << (precision as i32);
64 let cr_coef = (self.cr_coef * precision_scale as f32).round() as i32;
65 let cb_coef = (self.cb_coef * precision_scale as f32).round() as i32;
66 let y_coef = (self.y_coef * precision_scale as f32).round() as i32;
67 let g_coef_1 = (self.g_coeff_1 * precision_scale as f32).round() as i32;
68 let g_coef_2 = (self.g_coeff_2 * precision_scale as f32).round() as i32;
69 CbCrInverseTransform::<i32> {
70 y_coef,
71 cr_coef,
72 cb_coef,
73 g_coeff_1: g_coef_1,
74 g_coeff_2: g_coef_2,
75 }
76 }
77}
78
79impl<V> CbCrInverseTransform<V> {
80 #[inline]
81 pub(crate) fn cast<T: Copy + 'static>(&self) -> CbCrInverseTransform<T>
82 where
83 V: AsPrimitive<T>,
84 {
85 CbCrInverseTransform {
86 y_coef: self.y_coef.as_(),
87 cb_coef: self.cb_coef.as_(),
88 cr_coef: self.cr_coef.as_(),
89 g_coeff_1: self.g_coeff_1.as_(),
90 g_coeff_2: self.g_coeff_2.as_(),
91 }
92 }
93}
94
95pub fn get_inverse_transform(
97 range_bgra: u32,
98 range_y: u32,
99 range_uv: u32,
100 kr: f32,
101 kb: f32,
102) -> CbCrInverseTransform<f32> {
103 let range_uv = range_bgra as f32 / range_uv as f32;
104 let y_coef = range_bgra as f32 / range_y as f32;
105 let cr_coeff = (2f32 * (1f32 - kr)) * range_uv;
106 let cb_coeff = (2f32 * (1f32 - kb)) * range_uv;
107 let kg = 1.0f32 - kr - kb;
108 assert_ne!(kg, 0., "1.0f - kr - kg must not be 0");
109 let g_coeff_1 = (2f32 * ((1f32 - kr) * kr / kg)) * range_uv;
110 let g_coeff_2 = (2f32 * ((1f32 - kb) * kb / kg)) * range_uv;
111 CbCrInverseTransform::new(y_coef, cr_coeff, cb_coeff, g_coeff_1, g_coeff_2)
112}
113
114#[repr(C)]
115#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
116pub struct CbCrForwardTransform<T> {
117 pub yr: T,
118 pub yg: T,
119 pub yb: T,
120 pub cb_r: T,
121 pub cb_g: T,
122 pub cb_b: T,
123 pub cr_r: T,
124 pub cr_g: T,
125 pub cr_b: T,
126}
127
128impl CbCrForwardTransform<i32> {
129 #[inline]
130 pub(crate) const fn _interleaved_yr_yg(&self) -> i32 {
131 let w0_as_u16 = self.yg.to_ne_bytes();
132 let w1_as_u16 = self.yr.to_ne_bytes();
133 i32::from_ne_bytes([w1_as_u16[0], w1_as_u16[1], w0_as_u16[0], w0_as_u16[1]])
134 }
135
136 #[inline]
137 pub(crate) const fn _interleaved_cbr_cbg(&self) -> i32 {
138 let w0_as_u16 = self.cb_g.to_ne_bytes();
139 let w1_as_u16 = self.cb_r.to_ne_bytes();
140 i32::from_ne_bytes([w1_as_u16[0], w1_as_u16[1], w0_as_u16[0], w0_as_u16[1]])
141 }
142
143 #[inline]
144 pub(crate) const fn _interleaved_crr_crg(&self) -> i32 {
145 let w0_as_u16 = self.cr_g as u16;
146 let w1_as_u16 = self.cr_r as u16;
147 (((w0_as_u16 as u32) << 16) | (w1_as_u16 as u32)) as i32
148 }
149}
150
151pub trait ToIntegerTransform {
152 fn to_integers(&self, precision: u32) -> CbCrForwardTransform<i32>;
153}
154
155impl ToIntegerTransform for CbCrForwardTransform<f32> {
156 fn to_integers(&self, precision: u32) -> CbCrForwardTransform<i32> {
157 let scale = (1 << precision) as f32;
158 CbCrForwardTransform::<i32> {
159 yr: (self.yr * scale).round() as i32,
160 yg: (self.yg * scale).round() as i32,
161 yb: (self.yb * scale).round() as i32,
162 cb_r: (self.cb_r * scale).round() as i32,
163 cb_g: (self.cb_g * scale).round() as i32,
164 cb_b: (self.cb_b * scale).round() as i32,
165 cr_r: (self.cr_r * scale).round() as i32,
166 cr_g: (self.cr_g * scale).round() as i32,
167 cr_b: (self.cr_b * scale).round() as i32,
168 }
169 }
170}
171
172impl<V> CbCrForwardTransform<V> {
173 pub(crate) fn cast<T: Copy + 'static>(&self) -> CbCrForwardTransform<T>
174 where
175 V: AsPrimitive<T>,
176 {
177 CbCrForwardTransform {
178 yr: self.yr.as_(),
179 yg: self.yg.as_(),
180 yb: self.yb.as_(),
181 cb_r: self.cb_r.as_(),
182 cb_g: self.cb_g.as_(),
183 cb_b: self.cb_b.as_(),
184 cr_r: self.cr_r.as_(),
185 cr_g: self.cr_g.as_(),
186 cr_b: self.cr_b.as_(),
187 }
188 }
189}
190
191pub fn get_forward_transform(
193 range_rgba: u32,
194 range_y: u32,
195 range_uv: u32,
196 kr: f32,
197 kb: f32,
198) -> CbCrForwardTransform<f32> {
199 let kg = 1.0f32 - kr - kb;
200
201 let yr = kr * range_y as f32 / range_rgba as f32;
202 let yg = kg * range_y as f32 / range_rgba as f32;
203 let yb = kb * range_y as f32 / range_rgba as f32;
204
205 let cb_r = -0.5f32 * kr / (1f32 - kb) * range_uv as f32 / range_rgba as f32;
206 let cb_g = -0.5f32 * kg / (1f32 - kb) * range_uv as f32 / range_rgba as f32;
207 let cb_b = 0.5f32 * range_uv as f32 / range_rgba as f32;
208
209 let cr_r = 0.5f32 * range_uv as f32 / range_rgba as f32;
210 let cr_g = -0.5f32 * kg / (1f32 - kr) * range_uv as f32 / range_rgba as f32;
211 let cr_b = -0.5f32 * kb / (1f32 - kr) * range_uv as f32 / range_rgba as f32;
212 CbCrForwardTransform {
213 yr,
214 yg,
215 yb,
216 cb_r,
217 cb_g,
218 cb_b,
219 cr_r,
220 cr_g,
221 cr_b,
222 }
223}
224
225#[repr(C)]
226#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
227pub enum YuvRange {
229 Limited,
231 Full,
233}
234
235#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
237pub struct YuvChromaRange {
238 pub bias_y: u32,
239 pub bias_uv: u32,
240 pub range_y: u32,
241 pub range_uv: u32,
242 pub range: YuvRange,
243}
244
245pub const fn get_yuv_range(depth: u32, range: YuvRange) -> YuvChromaRange {
247 match range {
248 YuvRange::Limited => YuvChromaRange {
249 bias_y: 16 << (depth - 8),
250 bias_uv: 1 << (depth - 1),
251 range_y: 219 << (depth - 8),
252 range_uv: 224 << (depth - 8),
253 range,
254 },
255 YuvRange::Full => YuvChromaRange {
256 bias_y: 0,
257 bias_uv: 1 << (depth - 1),
258 range_uv: (1 << depth) - 1,
259 range_y: (1 << depth) - 1,
260 range,
261 },
262 }
263}
264
265#[repr(C)]
266#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
267pub enum YuvStandardMatrix {
270 Bt601,
272 Bt709,
273 Bt2020,
274 Smpte240,
275 Bt470_6,
276 Custom(f32, f32),
279}
280
281#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
282pub struct YuvBias {
283 pub kr: f32,
284 pub kb: f32,
285}
286
287impl YuvStandardMatrix {
288 pub const fn get_kr_kb(self) -> YuvBias {
289 match self {
290 YuvStandardMatrix::Bt601 => YuvBias {
291 kr: 0.299f32,
292 kb: 0.114f32,
293 },
294 YuvStandardMatrix::Bt709 => YuvBias {
295 kr: 0.2126f32,
296 kb: 0.0722f32,
297 },
298 YuvStandardMatrix::Bt2020 => YuvBias {
299 kr: 0.2627f32,
300 kb: 0.0593f32,
301 },
302 YuvStandardMatrix::Smpte240 => YuvBias {
303 kr: 0.087f32,
304 kb: 0.212f32,
305 },
306 YuvStandardMatrix::Bt470_6 => YuvBias {
307 kr: 0.2220f32,
308 kb: 0.0713f32,
309 },
310 YuvStandardMatrix::Custom(kr, kb) => YuvBias { kr, kb },
311 }
312 }
313}
314
315#[repr(u8)]
316#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
317pub enum YuvNVOrder {
318 UV = 0,
319 VU = 1,
320}
321
322impl YuvNVOrder {
323 #[inline]
324 pub const fn get_u_position(&self) -> usize {
325 match self {
326 YuvNVOrder::UV => 0,
327 YuvNVOrder::VU => 1,
328 }
329 }
330 #[inline]
331 pub const fn get_v_position(&self) -> usize {
332 match self {
333 YuvNVOrder::UV => 1,
334 YuvNVOrder::VU => 0,
335 }
336 }
337}
338
339impl From<u8> for YuvNVOrder {
340 #[inline(always)]
341 fn from(value: u8) -> Self {
342 match value {
343 0 => YuvNVOrder::UV,
344 1 => YuvNVOrder::VU,
345 _ => {
346 unimplemented!("Unknown value")
347 }
348 }
349 }
350}
351
352#[repr(u8)]
353#[derive(Debug, Copy, Clone, PartialEq, Eq)]
354pub enum YuvChromaSubsampling {
355 Yuv420 = 0,
356 Yuv422 = 1,
357 Yuv444 = 2,
358}
359
360impl From<u8> for YuvChromaSubsampling {
361 #[inline(always)]
362 fn from(value: u8) -> Self {
363 match value {
364 0 => YuvChromaSubsampling::Yuv420,
365 1 => YuvChromaSubsampling::Yuv422,
366 2 => YuvChromaSubsampling::Yuv444,
367 _ => {
368 unimplemented!("Unknown value")
369 }
370 }
371 }
372}
373
374#[repr(u8)]
375#[derive(Copy, Clone, PartialEq, Eq)]
376pub enum YuvEndianness {
378 #[cfg(feature = "big_endian")]
379 BigEndian = 0,
380 LittleEndian = 1,
381}
382
383impl From<u8> for YuvEndianness {
384 #[inline(always)]
385 fn from(value: u8) -> Self {
386 match value {
387 #[cfg(feature = "big_endian")]
388 0 => YuvEndianness::BigEndian,
389 1 => YuvEndianness::LittleEndian,
390 _ => {
391 unimplemented!("Unknown value")
392 }
393 }
394 }
395}
396
397#[repr(u8)]
398#[derive(Debug, Copy, Clone, PartialEq, Eq)]
399pub enum YuvBytesPacking {
411 MostSignificantBytes = 0,
412 LeastSignificantBytes = 1,
413}
414
415impl From<u8> for YuvBytesPacking {
416 #[inline(always)]
417 fn from(value: u8) -> Self {
418 match value {
419 0 => YuvBytesPacking::MostSignificantBytes,
420 1 => YuvBytesPacking::LeastSignificantBytes,
421 _ => {
422 unimplemented!("Unknown value")
423 }
424 }
425 }
426}
427
428#[repr(u8)]
429#[derive(Debug, Copy, Clone, PartialEq, Eq)]
430pub enum YuvSourceChannels {
431 Rgb = 0,
432 Rgba = 1,
433 Bgra = 2,
434 Bgr = 3,
435}
436
437impl Display for YuvSourceChannels {
438 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439 match self {
440 YuvSourceChannels::Rgb => f.write_str("YuvSourceChannels::Rgb"),
441 YuvSourceChannels::Rgba => f.write_str("YuvSourceChannels::Rgba"),
442 YuvSourceChannels::Bgra => f.write_str("YuvSourceChannels::Bgra"),
443 YuvSourceChannels::Bgr => f.write_str("YuvSourceChannels::Bgr"),
444 }
445 }
446}
447
448impl From<u8> for YuvSourceChannels {
449 #[inline(always)]
450 fn from(value: u8) -> Self {
451 match value {
452 0 => YuvSourceChannels::Rgb,
453 1 => YuvSourceChannels::Rgba,
454 2 => YuvSourceChannels::Bgra,
455 3 => YuvSourceChannels::Bgr,
456 _ => {
457 unimplemented!("Unknown value")
458 }
459 }
460 }
461}
462
463impl YuvSourceChannels {
464 #[inline(always)]
465 pub const fn get_channels_count(&self) -> usize {
466 match self {
467 YuvSourceChannels::Rgb | YuvSourceChannels::Bgr => 3,
468 YuvSourceChannels::Rgba | YuvSourceChannels::Bgra => 4,
469 }
470 }
471
472 #[inline(always)]
473 pub const fn has_alpha(&self) -> bool {
474 match self {
475 YuvSourceChannels::Rgb | YuvSourceChannels::Bgr => false,
476 YuvSourceChannels::Rgba | YuvSourceChannels::Bgra => true,
477 }
478 }
479}
480
481impl YuvSourceChannels {
482 #[inline(always)]
483 pub const fn get_r_channel_offset(&self) -> usize {
484 match self {
485 YuvSourceChannels::Rgb => 0,
486 YuvSourceChannels::Rgba => 0,
487 YuvSourceChannels::Bgra => 2,
488 YuvSourceChannels::Bgr => 2,
489 }
490 }
491
492 #[inline(always)]
493 pub const fn get_g_channel_offset(&self) -> usize {
494 match self {
495 YuvSourceChannels::Rgb | YuvSourceChannels::Bgr => 1,
496 YuvSourceChannels::Rgba | YuvSourceChannels::Bgra => 1,
497 }
498 }
499
500 #[inline(always)]
501 pub const fn get_b_channel_offset(&self) -> usize {
502 match self {
503 YuvSourceChannels::Rgb => 2,
504 YuvSourceChannels::Rgba => 2,
505 YuvSourceChannels::Bgra => 0,
506 YuvSourceChannels::Bgr => 0,
507 }
508 }
509 #[inline(always)]
510 pub const fn get_a_channel_offset(&self) -> usize {
511 match self {
512 YuvSourceChannels::Rgb | YuvSourceChannels::Bgr => 0,
513 YuvSourceChannels::Rgba | YuvSourceChannels::Bgra => 3,
514 }
515 }
516}
517
518#[repr(usize)]
519#[derive(Debug, Copy, Clone, PartialEq, Eq)]
520#[allow(clippy::upper_case_acronyms)]
521pub(crate) enum Yuy2Description {
522 YUYV = 0,
523 UYVY = 1,
524 YVYU = 2,
525 VYUY = 3,
526}
527
528impl From<usize> for Yuy2Description {
529 fn from(value: usize) -> Self {
530 match value {
531 0 => Yuy2Description::YUYV,
532 1 => Yuy2Description::UYVY,
533 2 => Yuy2Description::YVYU,
534 3 => Yuy2Description::VYUY,
535 _ => {
536 unimplemented!("YUY2 not supported value {}", value)
537 }
538 }
539 }
540}
541
542impl Yuy2Description {
543 #[inline]
544 pub(crate) const fn get_u_position(&self) -> usize {
545 match self {
546 Yuy2Description::YUYV => 1,
547 Yuy2Description::UYVY => 0,
548 Yuy2Description::YVYU => 3,
549 Yuy2Description::VYUY => 2,
550 }
551 }
552
553 #[inline]
554 pub(crate) const fn get_v_position(&self) -> usize {
555 match self {
556 Yuy2Description::YUYV => 3,
557 Yuy2Description::UYVY => 2,
558 Yuy2Description::YVYU => 1,
559 Yuy2Description::VYUY => 0,
560 }
561 }
562
563 #[inline(always)]
564 pub(crate) const fn get_first_y_position(&self) -> usize {
565 match self {
566 Yuy2Description::YUYV => 0,
567 Yuy2Description::UYVY => 1,
568 Yuy2Description::YVYU => 0,
569 Yuy2Description::VYUY => 1,
570 }
571 }
572
573 #[inline]
574 pub(crate) const fn get_second_y_position(&self) -> usize {
575 match self {
576 Yuy2Description::YUYV => 2,
577 Yuy2Description::UYVY => 3,
578 Yuy2Description::YVYU => 2,
579 Yuy2Description::VYUY => 3,
580 }
581 }
582}
583
584#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
585pub(crate) enum YuvPacked444Format {
586 Ayuv = 0,
587 Vuya = 1,
588}
589
590impl From<u8> for YuvPacked444Format {
591 fn from(value: u8) -> Self {
592 match value {
593 0 => YuvPacked444Format::Ayuv,
594 1 => YuvPacked444Format::Vuya,
595 _ => unimplemented!("{} is not implemented on PackedYuv444", value),
596 }
597 }
598}
599
600#[cfg(not(all(target_arch = "aarch64", target_feature = "neon")))]
601impl YuvPacked444Format {
602 pub(crate) const fn get_a_ps(&self) -> usize {
603 match self {
604 YuvPacked444Format::Ayuv => 0,
605 YuvPacked444Format::Vuya => 3,
606 }
607 }
608
609 pub(crate) const fn get_u_ps(&self) -> usize {
610 match self {
611 YuvPacked444Format::Ayuv => 2,
612 YuvPacked444Format::Vuya => 1,
613 }
614 }
615
616 pub(crate) const fn get_v_ps(&self) -> usize {
617 match self {
618 YuvPacked444Format::Ayuv => 3,
619 YuvPacked444Format::Vuya => 0,
620 }
621 }
622
623 pub(crate) const fn get_y_ps(&self) -> usize {
624 match self {
625 YuvPacked444Format::Ayuv => 1,
626 YuvPacked444Format::Vuya => 2,
627 }
628 }
629}
630
631#[derive(Debug, Copy, Clone, PartialEq, Eq)]
632pub(crate) enum Rgb30 {
633 Ar30 = 0,
634 Ab30 = 1,
635 Ra30 = 2,
636 Ba30 = 3,
637}
638
639impl From<usize> for Rgb30 {
640 fn from(value: usize) -> Self {
641 match value {
642 0 => Rgb30::Ar30,
643 1 => Rgb30::Ab30,
644 2 => Rgb30::Ra30,
645 3 => Rgb30::Ba30,
646 _ => {
647 unimplemented!("Rgb30 is not implemented for value {}", value)
648 }
649 }
650 }
651}
652
653#[inline]
655const fn htonl(hostlong: u32) -> u32 {
656 hostlong.to_be()
657}
658
659#[inline]
661const fn ntohl(netlong: u32) -> u32 {
662 u32::from_be(netlong)
663}
664
665impl Rgb30 {
666 #[inline(always)]
667 pub(crate) const fn pack<const STORE: usize>(self, r: i32, g: i32, b: i32) -> u32 {
668 let value: u32 = match self {
669 Rgb30::Ar30 => (((3 << 30) | (b << 20)) | ((g << 10) | r)) as u32,
670 Rgb30::Ab30 => (((3 << 30) | (r << 20)) | ((g << 10) | b)) as u32,
671 Rgb30::Ra30 => (((r << 22) | (g << 12)) | ((b << 2) | 3)) as u32,
672 Rgb30::Ba30 => (((b << 22) | (g << 12)) | ((r << 2) | 3)) as u32,
673 };
674 if STORE == 0 {
675 value
676 } else {
677 htonl(value)
678 }
679 }
680
681 pub(crate) const fn pack_w_a<const STORE: usize>(self, r: i32, g: i32, b: i32, a: i32) -> u32 {
682 let value: u32 = match self {
683 Rgb30::Ar30 => ((a << 30) | (b << 20) | (g << 10) | r) as u32,
684 Rgb30::Ab30 => ((a << 30) | (r << 20) | (g << 10) | b) as u32,
685 Rgb30::Ra30 => ((r << 22) | (g << 12) | (b << 2) | a) as u32,
686 Rgb30::Ba30 => ((b << 22) | (g << 12) | (r << 2) | a) as u32,
687 };
688 if STORE == 0 {
689 value
690 } else {
691 htonl(value)
692 }
693 }
694
695 #[inline(always)]
696 pub(crate) const fn unpack<const STORE: usize>(self, value: u32) -> (u32, u32, u32, u32) {
697 let pixel = if STORE == 0 { value } else { ntohl(value) };
698 match self {
699 Rgb30::Ar30 => {
700 let r10 = pixel & 0x3ff;
701 let g10 = (pixel >> 10) & 0x3ff;
702 let b10 = (pixel >> 20) & 0x3ff;
703 let a10 = pixel >> 30;
704 (r10, g10, b10, a10)
705 }
706 Rgb30::Ab30 => {
707 let b10 = pixel & 0x3ff;
708 let g10 = (pixel >> 10) & 0x3ff;
709 let r10 = (pixel >> 20) & 0x3ff;
710 let a10 = pixel >> 30;
711 (r10, g10, b10, a10)
712 }
713 Rgb30::Ra30 => {
714 let a2 = pixel & 0x3;
715 let r10 = (pixel >> 22) & 0x3ff;
716 let g10 = (pixel >> 12) & 0x3ff;
717 let b10 = (pixel >> 2) & 0x3ff;
718 (r10, g10, b10, a2)
719 }
720 Rgb30::Ba30 => {
721 let a2 = pixel & 0x3;
722 let b10 = (pixel >> 22) & 0x3ff;
723 let g10 = (pixel >> 12) & 0x3ff;
724 let r10 = (pixel >> 2) & 0x3ff;
725 (r10, g10, b10, a2)
726 }
727 }
728 }
729}
730
731#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
732pub enum Rgb30ByteOrder {
743 Host = 0,
744 Network = 1,
745}
746
747impl From<usize> for Rgb30ByteOrder {
748 fn from(value: usize) -> Self {
749 match value {
750 0 => Rgb30ByteOrder::Host,
751 1 => Rgb30ByteOrder::Network,
752 _ => {
753 unimplemented!("Rgb30ByteOrder is not implemented for value {}", value)
754 }
755 }
756 }
757}
758
759pub(crate) fn search_forward_transform(
761 precision: i32,
762 bit_depth: u32,
763 range: YuvRange,
764 matrix: YuvStandardMatrix,
765 chroma_range: YuvChromaRange,
766 kr_kb: YuvBias,
767) -> CbCrForwardTransform<i32> {
768 if let Some(stored_t) = get_built_forward_transform(precision as u32, bit_depth, range, matrix)
769 {
770 stored_t
771 } else {
772 let transform_precise = get_forward_transform(
773 (1 << bit_depth) - 1,
774 chroma_range.range_y,
775 chroma_range.range_uv,
776 kr_kb.kr,
777 kr_kb.kb,
778 );
779 transform_precise.to_integers(precision as u32)
780 }
781}
782
783pub(crate) fn search_inverse_transform(
785 precision: i32,
786 bit_depth: u32,
787 range: YuvRange,
788 matrix: YuvStandardMatrix,
789 chroma_range: YuvChromaRange,
790 kr_kb: YuvBias,
791) -> CbCrInverseTransform<i32> {
792 if let Some(stored) = get_built_inverse_transform(precision as u32, bit_depth, range, matrix) {
793 stored
794 } else {
795 let transform = get_inverse_transform(
796 (1 << bit_depth) - 1,
797 chroma_range.range_y,
798 chroma_range.range_uv,
799 kr_kb.kr,
800 kr_kb.kb,
801 );
802 if precision == 6 {
803 let mut transform = transform.to_integers(precision as u32);
805 transform.cr_coef = transform.cr_coef.min(127);
806 transform.cb_coef = transform.cb_coef.min(127);
807 transform.g_coeff_1 = transform.g_coeff_1.min(127);
808 transform.g_coeff_2 = transform.g_coeff_2.min(127);
809 transform
810 } else {
811 transform.to_integers(precision as u32)
812 }
813 }
814}
815
816#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Default)]
820pub enum YuvConversionMode {
821 #[cfg(feature = "fast_mode")]
831 #[cfg_attr(docsrs, doc(cfg(feature = "fast_mode")))]
832 Fast,
833 #[default]
838 Balanced,
839 #[cfg(feature = "professional_mode")]
841 #[cfg_attr(docsrs, doc(cfg(feature = "professional_mode")))]
842 Professional,
843}
844
845impl Display for YuvConversionMode {
846 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
847 match self {
848 #[cfg(feature = "fast_mode")]
849 YuvConversionMode::Fast => f.write_str("YuvAccuracy::Fast"),
850 YuvConversionMode::Balanced => f.write_str("YuvAccuracy::Balanced"),
851 #[cfg(feature = "professional_mode")]
852 YuvConversionMode::Professional => f.write_str("YuvAccuracy::Professional"),
853 }
854 }
855}