1use std::{
2 cmp,
3 fmt::{Display, Formatter},
4 iter,
5 num::NonZeroU32,
6};
7
8use bitflags::bitflags;
9use num_enum::TryFromPrimitive;
10
11use crate::{
12 base::utils::align_to,
13 ceil_rshift,
14 media_frame::{MemoryPlanes, PlaneInformation},
15};
16
17#[derive(Clone, Copy, Debug, PartialEq)]
18pub struct Resolution {
19 pub width: u32,
20 pub height: u32,
21}
22
23pub const RESOLUTION_SQCIF: Resolution = Resolution {
24 width: 128,
25 height: 96,
26};
27pub const RESOLUTION_QCIF: Resolution = Resolution {
28 width: 176,
29 height: 144,
30};
31
32pub const RESOLUTION_CIF: Resolution = Resolution {
33 width: 352,
34 height: 288,
35};
36pub const RESOLUTION_QQVGA: Resolution = Resolution {
37 width: 160,
38 height: 120,
39};
40pub const RESOLUTION_QVGA: Resolution = Resolution {
41 width: 320,
42 height: 240,
43};
44pub const RESOLUTION_VGA: Resolution = Resolution {
45 width: 640,
46 height: 480,
47};
48pub const RESOLUTION_SVGA: Resolution = Resolution {
49 width: 800,
50 height: 600,
51};
52pub const RESOLUTION_XGA: Resolution = Resolution {
53 width: 1024,
54 height: 768,
55};
56pub const RESOLUTION_SXGA: Resolution = Resolution {
57 width: 1280,
58 height: 1024,
59};
60pub const RESOLUTION_UXGA: Resolution = Resolution {
61 width: 1600,
62 height: 1200,
63};
64pub const RESOLUTION_QXGA: Resolution = Resolution {
65 width: 2048,
66 height: 1536,
67};
68pub const RESOLUTION_SD: Resolution = Resolution {
69 width: 720,
70 height: 480,
71};
72pub const RESOLUTION_HD: Resolution = Resolution {
73 width: 1280,
74 height: 720,
75};
76pub const RESOLUTION_FHD: Resolution = Resolution {
77 width: 1920,
78 height: 1080,
79};
80pub const RESOLUTION_QHD: Resolution = Resolution {
81 width: 2560,
82 height: 1440,
83};
84pub const RESOLUTION_UHD_4K: Resolution = Resolution {
85 width: 3840,
86 height: 2160,
87};
88pub const RESOLUTION_UHD_8K: Resolution = Resolution {
89 width: 7680,
90 height: 4320,
91};
92
93#[derive(Clone, Copy, Debug, Default, PartialEq)]
94#[repr(u8)]
95pub enum ColorRange {
96 #[default]
97 Unspecified,
98 Video,
99 Full,
100 MAX,
101}
102
103#[derive(Clone, Copy, Debug, Default, PartialEq)]
104#[repr(u8)]
105pub enum ColorMatrix {
106 #[default]
107 Identity = 0, BT709, Unspecified, FCC = 4, BT470BG, SMPTE170M, SMPTE240M, YCgCo, BT2020NCL, BT2020CL, SMPTE2085, ChromaDerivedNCL, ChromaDerivedCL, ICtCp, SMPTE2128, }
123
124#[derive(Clone, Copy, Debug, Default, PartialEq)]
125#[repr(u8)]
126pub enum ColorPrimaries {
127 #[default]
128 Reserved = 0, BT709, Unspecified, BT470M = 4, BT470BG, SMPTE170M, SMPTE240M, Film, BT2020, SMPTE428, SMPTE431, SMPTE432, JEDEC_P22 = 22, }
142
143#[allow(non_camel_case_types)]
144#[repr(u8)]
145#[derive(Clone, Copy, Debug, Default, PartialEq)]
146pub enum ColorTransferCharacteristics {
147 #[default]
148 Reserved = 0, BT709, Unspecified, BT470M = 4, BT470BG, SMPTE170M, SMPTE240M, Linear, Log, LogSqrt, IEC61966_2_4, BT1361E, IEC61966_2_1, BT2020_10, BT2020_12, SMPTE2084, SMPTE428, ARIB_STD_B67, }
167
168#[repr(u8)]
169#[derive(Clone, Copy, Debug, Default, PartialEq, TryFromPrimitive)]
170pub enum PixelFormat {
171 #[default]
172 ARGB32 = 0, BGRA32, ABGR32, RGBA32, RGB24, BGR24, I420, I422, I444, NV12, NV21, NV16, NV61, NV24, NV42, YV12, YV16, YV24, YUYV, YVYU, UYVY, VYUY, AYUV, Y8, YA8, RGB30, BGR30, ARGB64, ABGR64, I010, I210, I410, P010, P210, P410, I012, I212, I412, P012, P212, P412, I016, I216, I416, P016, P216, P416, MAX,
220}
221
222#[repr(u8)]
223#[derive(Clone, Copy, Debug, Default, PartialEq, TryFromPrimitive)]
224pub enum CompressionFormat {
225 #[default]
226 MJPEG,
227}
228
229#[derive(Clone, Copy, Debug, PartialEq)]
230pub enum VideoFormat {
231 Pixel(PixelFormat),
232 Compression(CompressionFormat),
233}
234
235#[derive(Clone, Copy, Debug, PartialEq)]
236pub enum ChromaSubsampling {
237 YUV420,
238 YUV422,
239 YUV444,
240}
241
242#[derive(Clone, Copy, Debug, Default, PartialEq)]
243pub enum Rotation {
244 #[default]
245 None,
246 Rotation90,
247 Rotation180,
248 Rotation270,
249}
250
251#[derive(Clone, Copy, Debug, Default, PartialEq)]
252pub enum Origin {
253 #[default]
254 TopDown,
255 BottomUp,
256}
257
258#[derive(Clone, Debug, PartialEq)]
259pub struct VideoFrameDescription {
260 pub format: PixelFormat,
261 pub color_range: ColorRange,
262 pub color_matrix: ColorMatrix,
263 pub color_primaries: ColorPrimaries,
264 pub color_transfer_characteristics: ColorTransferCharacteristics,
265 pub width: NonZeroU32,
266 pub height: NonZeroU32,
267 pub rotation: Rotation,
268 pub origin: Origin,
269 pub transparent: bool,
270 pub extra_alpha: bool,
271 pub crop_left: u32,
272 pub crop_top: u32,
273 pub crop_right: u32,
274 pub crop_bottom: u32,
275}
276
277impl VideoFrameDescription {
278 pub fn new(format: PixelFormat, width: NonZeroU32, height: NonZeroU32) -> Self {
279 Self {
280 format,
281 color_range: ColorRange::default(),
282 color_matrix: ColorMatrix::default(),
283 color_primaries: ColorPrimaries::default(),
284 color_transfer_characteristics: ColorTransferCharacteristics::default(),
285 width,
286 height,
287 rotation: Rotation::default(),
288 origin: Origin::default(),
289 transparent: false,
290 extra_alpha: false,
291 crop_left: 0,
292 crop_top: 0,
293 crop_right: 0,
294 crop_bottom: 0,
295 }
296 }
297}
298
299bitflags! {
300 struct ColorInfo: u32 {
301 const Alpha = 1 << 0;
302 const RGB = 1 << 1;
303 const YUV = 1 << 2;
304 const Planar = 1 << 3;
305 const Packed = 1 << 4;
306 const BiPlanar = 1 << 5;
307 }
308}
309
310struct PixelDescription {
311 pub components: u8,
312 pub chroma_shift_x: u8,
313 pub chroma_shift_y: u8,
314 pub depth: u8,
315 pub color_info: u32,
316 pub component_bytes: [u8; 4],
317}
318
319static PIXEL_DESC: [PixelDescription; PixelFormat::MAX as usize] = [
320 PixelDescription {
322 components: 1,
323 chroma_shift_x: 0,
324 chroma_shift_y: 0,
325 depth: 8,
326 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
327 component_bytes: [4, 0, 0, 0],
328 },
329 PixelDescription {
331 components: 1,
332 chroma_shift_x: 0,
333 chroma_shift_y: 0,
334 depth: 8,
335 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
336 component_bytes: [4, 0, 0, 0],
337 },
338 PixelDescription {
340 components: 1,
341 chroma_shift_x: 0,
342 chroma_shift_y: 0,
343 depth: 8,
344 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
345 component_bytes: [4, 0, 0, 0],
346 },
347 PixelDescription {
349 components: 1,
350 chroma_shift_x: 0,
351 chroma_shift_y: 0,
352 depth: 8,
353 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
354 component_bytes: [4, 0, 0, 0],
355 },
356 PixelDescription {
358 components: 1,
359 chroma_shift_x: 0,
360 chroma_shift_y: 0,
361 depth: 8,
362 color_info: ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
363 component_bytes: [3, 0, 0, 0],
364 },
365 PixelDescription {
367 components: 1,
368 chroma_shift_x: 0,
369 chroma_shift_y: 0,
370 depth: 8,
371 color_info: ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
372 component_bytes: [3, 0, 0, 0],
373 },
374 PixelDescription {
376 components: 3,
377 chroma_shift_x: 1,
378 chroma_shift_y: 1,
379 depth: 8,
380 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
381 component_bytes: [1, 1, 1, 0],
382 },
383 PixelDescription {
385 components: 3,
386 chroma_shift_x: 1,
387 chroma_shift_y: 0,
388 depth: 8,
389 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
390 component_bytes: [1, 1, 1, 0],
391 },
392 PixelDescription {
394 components: 3,
395 chroma_shift_x: 0,
396 chroma_shift_y: 0,
397 depth: 8,
398 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
399 component_bytes: [1, 1, 1, 0],
400 },
401 PixelDescription {
403 components: 2,
404 chroma_shift_x: 1,
405 chroma_shift_y: 1,
406 depth: 8,
407 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
408 component_bytes: [1, 2, 0, 0],
409 },
410 PixelDescription {
412 components: 2,
413 chroma_shift_x: 1,
414 chroma_shift_y: 1,
415 depth: 8,
416 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
417 component_bytes: [1, 2, 0, 0],
418 },
419 PixelDescription {
421 components: 2,
422 chroma_shift_x: 1,
423 chroma_shift_y: 0,
424 depth: 8,
425 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
426 component_bytes: [1, 2, 0, 0],
427 },
428 PixelDescription {
430 components: 2,
431 chroma_shift_x: 1,
432 chroma_shift_y: 0,
433 depth: 8,
434 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
435 component_bytes: [1, 2, 0, 0],
436 },
437 PixelDescription {
439 components: 2,
440 chroma_shift_x: 0,
441 chroma_shift_y: 0,
442 depth: 8,
443 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
444 component_bytes: [1, 2, 0, 0],
445 },
446 PixelDescription {
448 components: 2,
449 chroma_shift_x: 0,
450 chroma_shift_y: 0,
451 depth: 8,
452 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
453 component_bytes: [1, 2, 0, 0],
454 },
455 PixelDescription {
457 components: 3,
458 chroma_shift_x: 1,
459 chroma_shift_y: 1,
460 depth: 8,
461 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
462 component_bytes: [1, 1, 1, 0],
463 },
464 PixelDescription {
466 components: 3,
467 chroma_shift_x: 1,
468 chroma_shift_y: 0,
469 depth: 8,
470 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
471 component_bytes: [1, 1, 1, 0],
472 },
473 PixelDescription {
475 components: 3,
476 chroma_shift_x: 0,
477 chroma_shift_y: 0,
478 depth: 8,
479 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
480 component_bytes: [1, 1, 1, 0],
481 },
482 PixelDescription {
484 components: 1,
485 chroma_shift_x: 1,
486 chroma_shift_y: 0,
487 depth: 8,
488 color_info: ColorInfo::YUV.bits() | ColorInfo::Packed.bits(),
489 component_bytes: [4, 0, 0, 0],
490 },
491 PixelDescription {
493 components: 1,
494 chroma_shift_x: 1,
495 chroma_shift_y: 0,
496 depth: 8,
497 color_info: ColorInfo::YUV.bits() | ColorInfo::Packed.bits(),
498 component_bytes: [4, 0, 0, 0],
499 },
500 PixelDescription {
502 components: 1,
503 chroma_shift_x: 1,
504 chroma_shift_y: 0,
505 depth: 8,
506 color_info: ColorInfo::YUV.bits() | ColorInfo::Packed.bits(),
507 component_bytes: [4, 0, 0, 0],
508 },
509 PixelDescription {
511 components: 1,
512 chroma_shift_x: 1,
513 chroma_shift_y: 0,
514 depth: 8,
515 color_info: ColorInfo::YUV.bits() | ColorInfo::Packed.bits(),
516 component_bytes: [4, 0, 0, 0],
517 },
518 PixelDescription {
520 components: 1,
521 chroma_shift_x: 0,
522 chroma_shift_y: 0,
523 depth: 8,
524 color_info: ColorInfo::Alpha.bits() | ColorInfo::YUV.bits() | ColorInfo::Packed.bits(),
525 component_bytes: [4, 0, 0, 0],
526 },
527 PixelDescription {
529 components: 1,
530 chroma_shift_x: 0,
531 chroma_shift_y: 0,
532 depth: 8,
533 color_info: ColorInfo::Planar.bits(),
534 component_bytes: [1, 0, 0, 0],
535 },
536 PixelDescription {
538 components: 2,
539 chroma_shift_x: 0,
540 chroma_shift_y: 0,
541 depth: 8,
542 color_info: ColorInfo::Alpha.bits() | ColorInfo::Planar.bits(),
543 component_bytes: [1, 1, 0, 0],
544 },
545 PixelDescription {
547 components: 1,
548 chroma_shift_x: 0,
549 chroma_shift_y: 0,
550 depth: 10,
551 color_info: ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
552 component_bytes: [4, 0, 0, 0],
553 },
554 PixelDescription {
556 components: 1,
557 chroma_shift_x: 0,
558 chroma_shift_y: 0,
559 depth: 10,
560 color_info: ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
561 component_bytes: [4, 0, 0, 0],
562 },
563 PixelDescription {
565 components: 1,
566 chroma_shift_x: 0,
567 chroma_shift_y: 0,
568 depth: 16,
569 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
570 component_bytes: [8, 0, 0, 0],
571 },
572 PixelDescription {
574 components: 1,
575 chroma_shift_x: 0,
576 chroma_shift_y: 0,
577 depth: 16,
578 color_info: ColorInfo::Alpha.bits() | ColorInfo::RGB.bits() | ColorInfo::Packed.bits(),
579 component_bytes: [8, 0, 0, 0],
580 },
581 PixelDescription {
583 components: 3,
584 chroma_shift_x: 1,
585 chroma_shift_y: 1,
586 depth: 10,
587 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
588 component_bytes: [2, 2, 2, 0],
589 },
590 PixelDescription {
592 components: 3,
593 chroma_shift_x: 1,
594 chroma_shift_y: 0,
595 depth: 10,
596 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
597 component_bytes: [2, 2, 2, 0],
598 },
599 PixelDescription {
601 components: 3,
602 chroma_shift_x: 0,
603 chroma_shift_y: 0,
604 depth: 10,
605 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
606 component_bytes: [2, 2, 2, 0],
607 },
608 PixelDescription {
610 components: 2,
611 chroma_shift_x: 1,
612 chroma_shift_y: 1,
613 depth: 10,
614 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
615 component_bytes: [2, 4, 0, 0],
616 },
617 PixelDescription {
619 components: 2,
620 chroma_shift_x: 1,
621 chroma_shift_y: 0,
622 depth: 10,
623 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
624 component_bytes: [2, 4, 0, 0],
625 },
626 PixelDescription {
628 components: 2,
629 chroma_shift_x: 0,
630 chroma_shift_y: 0,
631 depth: 10,
632 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
633 component_bytes: [2, 4, 0, 0],
634 },
635 PixelDescription {
637 components: 3,
638 chroma_shift_x: 1,
639 chroma_shift_y: 1,
640 depth: 12,
641 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
642 component_bytes: [2, 2, 2, 0],
643 },
644 PixelDescription {
646 components: 3,
647 chroma_shift_x: 1,
648 chroma_shift_y: 0,
649 depth: 12,
650 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
651 component_bytes: [2, 2, 2, 0],
652 },
653 PixelDescription {
655 components: 3,
656 chroma_shift_x: 0,
657 chroma_shift_y: 0,
658 depth: 12,
659 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
660 component_bytes: [2, 2, 2, 0],
661 },
662 PixelDescription {
664 components: 2,
665 chroma_shift_x: 1,
666 chroma_shift_y: 1,
667 depth: 12,
668 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
669 component_bytes: [2, 4, 0, 0],
670 },
671 PixelDescription {
673 components: 2,
674 chroma_shift_x: 1,
675 chroma_shift_y: 0,
676 depth: 12,
677 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
678 component_bytes: [2, 4, 0, 0],
679 },
680 PixelDescription {
682 components: 2,
683 chroma_shift_x: 0,
684 chroma_shift_y: 0,
685 depth: 12,
686 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
687 component_bytes: [2, 4, 0, 0],
688 },
689 PixelDescription {
691 components: 3,
692 chroma_shift_x: 1,
693 chroma_shift_y: 1,
694 depth: 16,
695 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
696 component_bytes: [2, 2, 2, 0],
697 },
698 PixelDescription {
700 components: 3,
701 chroma_shift_x: 1,
702 chroma_shift_y: 0,
703 depth: 16,
704 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
705 component_bytes: [2, 2, 2, 0],
706 },
707 PixelDescription {
709 components: 3,
710 chroma_shift_x: 0,
711 chroma_shift_y: 0,
712 depth: 16,
713 color_info: ColorInfo::YUV.bits() | ColorInfo::Planar.bits(),
714 component_bytes: [2, 2, 2, 0],
715 },
716 PixelDescription {
718 components: 2,
719 chroma_shift_x: 1,
720 chroma_shift_y: 1,
721 depth: 16,
722 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
723 component_bytes: [2, 4, 0, 0],
724 },
725 PixelDescription {
727 components: 2,
728 chroma_shift_x: 1,
729 chroma_shift_y: 0,
730 depth: 16,
731 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
732 component_bytes: [2, 4, 0, 0],
733 },
734 PixelDescription {
736 components: 2,
737 chroma_shift_x: 0,
738 chroma_shift_y: 0,
739 depth: 16,
740 color_info: ColorInfo::YUV.bits() | ColorInfo::BiPlanar.bits(),
741 component_bytes: [2, 4, 0, 0],
742 },
743];
744
745impl PixelFormat {
746 pub fn components(&self) -> u8 {
747 PIXEL_DESC[*self as usize].components
748 }
749
750 pub fn component_bytes(&self, component: u8) -> u8 {
751 PIXEL_DESC[*self as usize].component_bytes[component as usize]
752 }
753
754 pub fn chroma_subsampling(&self) -> Option<ChromaSubsampling> {
755 if !self.is_yuv() {
756 return None;
757 }
758
759 let desc = &PIXEL_DESC[*self as usize];
760
761 match (desc.chroma_shift_x, desc.chroma_shift_y) {
762 (1, 1) => Some(ChromaSubsampling::YUV420),
763 (1, 0) => Some(ChromaSubsampling::YUV422),
764 (0, 0) => Some(ChromaSubsampling::YUV444),
765 _ => None,
766 }
767 }
768
769 pub fn calc_data(&self, width: u32, height: u32, alignment: u32) -> (u32, MemoryPlanes) {
770 let desc = &PIXEL_DESC[*self as usize];
771 let mut size;
772 let mut planes = MemoryPlanes::with_capacity(desc.components as usize);
773
774 match self {
775 PixelFormat::RGB24 | PixelFormat::BGR24 | PixelFormat::Y8 => {
776 let stride = align_to(width * desc.component_bytes[0] as u32, cmp::max(alignment, 4));
777 planes.push(PlaneInformation::Video(stride, height));
778 size = stride * height;
779 }
780 PixelFormat::YA8 => {
781 let stride = align_to(width * desc.component_bytes[0] as u32, cmp::max(alignment, 4));
782 planes.extend(iter::repeat(PlaneInformation::Video(stride, height)).take(2));
783 size = stride * height * 2;
784 }
785 PixelFormat::YUYV | PixelFormat::YVYU | PixelFormat::UYVY | PixelFormat::VYUY | PixelFormat::AYUV => {
786 let stride = align_to(ceil_rshift(width, desc.chroma_shift_x as u32) * 4, alignment);
787 planes.push(PlaneInformation::Video(stride, height));
788 size = stride * height;
789 }
790 _ => {
791 let stride = align_to(width * desc.component_bytes[0] as u32, alignment);
792 planes.push(PlaneInformation::Video(stride, height));
793 size = stride * height;
794 for i in 1..desc.components as usize {
795 let stride = align_to(ceil_rshift(width, desc.chroma_shift_x as u32) * desc.component_bytes[i as usize] as u32, alignment);
796 let height = ceil_rshift(height, desc.chroma_shift_y as u32);
797 planes.push(PlaneInformation::Video(stride, height));
798 size += stride * height;
799 }
800 }
801 }
802
803 (size, planes)
804 }
805
806 pub fn calc_data_with_stride(&self, height: u32, stride: u32) -> (u32, MemoryPlanes) {
807 let desc = &PIXEL_DESC[*self as usize];
808 let mut size;
809 let mut planes = MemoryPlanes::with_capacity(desc.components as usize);
810
811 planes.push(PlaneInformation::Video(stride, height));
812 size = stride * height;
813 for i in 1..desc.components as usize {
814 let plane_stride = ceil_rshift(stride, desc.chroma_shift_x as u32) * desc.component_bytes[i as usize] as u32;
815 let plane_height = ceil_rshift(height, desc.chroma_shift_y as u32);
816 planes.push(PlaneInformation::Video(plane_stride, plane_height));
817 size = size + plane_stride * plane_height;
818 }
819
820 (size, planes)
821 }
822
823 pub fn depth(&self) -> u8 {
824 PIXEL_DESC[*self as usize].depth
825 }
826
827 pub fn is_rgb(&self) -> bool {
828 PIXEL_DESC[*self as usize].color_info & ColorInfo::RGB.bits() != 0
829 }
830
831 pub fn is_yuv(&self) -> bool {
832 PIXEL_DESC[*self as usize].color_info & ColorInfo::YUV.bits() != 0
833 }
834
835 pub fn is_planar(&self) -> bool {
836 PIXEL_DESC[*self as usize].color_info & ColorInfo::Planar.bits() != 0
837 }
838
839 pub fn is_packed(&self) -> bool {
840 PIXEL_DESC[*self as usize].color_info & ColorInfo::Packed.bits() != 0
841 }
842
843 pub fn is_biplanar(&self) -> bool {
844 PIXEL_DESC[*self as usize].color_info & ColorInfo::BiPlanar.bits() != 0
845 }
846}
847
848impl TryFrom<usize> for PixelFormat {
849 type Error = ();
850
851 fn try_from(value: usize) -> Result<Self, Self::Error> {
852 if value <= PixelFormat::MAX as usize {
853 Ok(unsafe { std::mem::transmute(value as u8) })
854 } else {
855 Err(())
856 }
857 }
858}
859
860impl From<usize> for ColorRange {
861 fn from(value: usize) -> Self {
862 match value {
863 0 => ColorRange::Unspecified,
864 1 => ColorRange::Video,
865 2 => ColorRange::Full,
866 _ => ColorRange::Unspecified,
867 }
868 }
869}
870
871impl TryFrom<usize> for ColorMatrix {
872 type Error = ();
873
874 fn try_from(value: usize) -> Result<Self, Self::Error> {
875 match value {
876 0 => Ok(ColorMatrix::Identity),
877 1 => Ok(ColorMatrix::BT709),
878 2 => Ok(ColorMatrix::Unspecified),
879 4 => Ok(ColorMatrix::FCC),
880 5 => Ok(ColorMatrix::BT470BG),
881 6 => Ok(ColorMatrix::SMPTE170M),
882 7 => Ok(ColorMatrix::SMPTE240M),
883 8 => Ok(ColorMatrix::YCgCo),
884 9 => Ok(ColorMatrix::BT2020NCL),
885 10 => Ok(ColorMatrix::BT2020CL),
886 11 => Ok(ColorMatrix::SMPTE2085),
887 12 => Ok(ColorMatrix::ChromaDerivedNCL),
888 13 => Ok(ColorMatrix::ChromaDerivedCL),
889 14 => Ok(ColorMatrix::ICtCp),
890 _ => Err(()),
891 }
892 }
893}
894
895impl TryFrom<usize> for ColorPrimaries {
896 type Error = ();
897
898 fn try_from(value: usize) -> Result<Self, Self::Error> {
899 match value {
900 0 => Ok(ColorPrimaries::Reserved),
901 1 => Ok(ColorPrimaries::BT709),
902 2 => Ok(ColorPrimaries::Unspecified),
903 4 => Ok(ColorPrimaries::BT470M),
904 5 => Ok(ColorPrimaries::BT470BG),
905 6 => Ok(ColorPrimaries::SMPTE170M),
906 7 => Ok(ColorPrimaries::SMPTE240M),
907 8 => Ok(ColorPrimaries::Film),
908 9 => Ok(ColorPrimaries::BT2020),
909 10 => Ok(ColorPrimaries::SMPTE428),
910 11 => Ok(ColorPrimaries::SMPTE431),
911 12 => Ok(ColorPrimaries::SMPTE432),
912 _ => Err(()),
913 }
914 }
915}
916
917impl TryFrom<usize> for ColorTransferCharacteristics {
918 type Error = ();
919
920 fn try_from(value: usize) -> Result<Self, Self::Error> {
921 match value {
922 0 => Ok(ColorTransferCharacteristics::Reserved),
923 1 => Ok(ColorTransferCharacteristics::BT709),
924 2 => Ok(ColorTransferCharacteristics::Unspecified),
925 4 => Ok(ColorTransferCharacteristics::BT470M),
926 5 => Ok(ColorTransferCharacteristics::BT470BG),
927 6 => Ok(ColorTransferCharacteristics::SMPTE170M),
928 7 => Ok(ColorTransferCharacteristics::SMPTE240M),
929 8 => Ok(ColorTransferCharacteristics::Linear),
930 9 => Ok(ColorTransferCharacteristics::Log),
931 10 => Ok(ColorTransferCharacteristics::LogSqrt),
932 11 => Ok(ColorTransferCharacteristics::IEC61966_2_4),
933 12 => Ok(ColorTransferCharacteristics::BT1361E),
934 13 => Ok(ColorTransferCharacteristics::IEC61966_2_1),
935 14 => Ok(ColorTransferCharacteristics::BT2020_10),
936 15 => Ok(ColorTransferCharacteristics::BT2020_12),
937 16 => Ok(ColorTransferCharacteristics::SMPTE2084),
938 17 => Ok(ColorTransferCharacteristics::SMPTE428),
939 18 => Ok(ColorTransferCharacteristics::ARIB_STD_B67),
940 _ => Err(()),
941 }
942 }
943}
944
945impl Display for VideoFormat {
946 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
947 match self {
948 VideoFormat::Pixel(format) => write!(f, "{:?}", format),
949 VideoFormat::Compression(format) => write!(f, "{:?}", format),
950 }
951 }
952}
953
954impl VideoFormat {
955 pub fn is_compressed(&self) -> bool {
956 matches!(self, VideoFormat::Compression(_))
957 }
958
959 pub fn is_yuv(&self) -> bool {
960 match self {
961 VideoFormat::Pixel(format) => format.is_yuv(),
962 VideoFormat::Compression(CompressionFormat::MJPEG) => true,
963 }
964 }
965}
966
967const COMPRESSION_MASK: u32 = 0x8000;
968
969impl Into<u32> for VideoFormat {
970 fn into(self) -> u32 {
971 match self {
972 VideoFormat::Pixel(format) => format as u32,
973 VideoFormat::Compression(format) => format as u32 | COMPRESSION_MASK,
974 }
975 }
976}
977
978impl TryFrom<u32> for VideoFormat {
979 type Error = ();
980
981 fn try_from(value: u32) -> Result<Self, Self::Error> {
982 if value & COMPRESSION_MASK != 0 {
983 let format_value = value & !COMPRESSION_MASK;
984 CompressionFormat::try_from(format_value as u8).map(VideoFormat::Compression).map_err(|_| ())
985 } else {
986 PixelFormat::try_from(value as u8).map(VideoFormat::Pixel).map_err(|_| ())
987 }
988 }
989}