x_media/
video.rs

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, // The identity matrix
108    BT709,            // BT.709
109    Unspecified,      // Unspecified
110    FCC      = 4,     // FCC Title 47 Code of Federal Regulations 73.682(a)(20)
111    BT470BG,          // BT.601 PAL & SECAM
112    SMPTE170M,        // BT.601 NTSC
113    SMPTE240M,        // SMPTE ST 240
114    YCgCo,            // YCgCo
115    BT2020NCL,        // BT.2020 non-constant luminance system
116    BT2020CL,         // BT.2020 constant luminance system
117    SMPTE2085,        // SMPTE ST 2085 Y'D'zD'x
118    ChromaDerivedNCL, // Chromaticity-derived non-constant luminance system
119    ChromaDerivedCL,  // Chromaticity-derived constant luminance system
120    ICtCp,            // BT.2100 ICtCp
121    SMPTE2128,        // SMPTE ST 2128
122}
123
124#[derive(Clone, Copy, Debug, Default, PartialEq)]
125#[repr(u8)]
126pub enum ColorPrimaries {
127    #[default]
128    Reserved  = 0, // Reserved
129    BT709,          // BT.709
130    Unspecified,    // Unspecified
131    BT470M    = 4,  // FCC Title 47 Code of Federal Regulations 73.682(a)(20)
132    BT470BG,        // BT.601 PAL & SECAM
133    SMPTE170M,      // BT.601 NTSC
134    SMPTE240M,      // SMPTE ST 240 / SMPTE C
135    Film,           // Generic film (color filters using illuminant C)
136    BT2020,         // BT.2020
137    SMPTE428,       // SMPTE ST 428-1 (CIE 1931 XYZ)
138    SMPTE431,       // SMPTE ST 431-2 (DCI P3)
139    SMPTE432,       // SMPTE ST 432-1 (P3 D65 / Display P3)
140    JEDEC_P22 = 22, // JEDEC P22 phosphors
141}
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, // Reserved
149    BT709,        // BT.709
150    Unspecified,  // Unspecified
151    BT470M   = 4, // gamma = 2.2 / FCC Title 47 Code of Federal Regulations 73.682(a)(20)
152    BT470BG,      // gamma = 2.8 / BT.601 PAL & SECAM
153    SMPTE170M,    // BT.601 NTSC
154    SMPTE240M,    // SMPTE ST 240
155    Linear,       // Linear transfer characteristics
156    Log,          // Logarithmic transfer characteristic (100 : 1 range)
157    LogSqrt,      // Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)
158    IEC61966_2_4, // IEC 61966-2-4
159    BT1361E,      // ITU-R BT1361 Extended Colour Gamut
160    IEC61966_2_1, // IEC 61966-2-1 (sRGB or sYCC)
161    BT2020_10,    // BT.2020 10-bit systems
162    BT2020_12,    // BT.2020 12-bit systems
163    SMPTE2084,    // SMPTE ST 2084 / BT.2100 perceptual quantization (PQ) system
164    SMPTE428,     // SMPTE ST 428-1
165    ARIB_STD_B67, // ARIB STD-B67 / BT.2100 hybrid log-gamma (HLG) system
166}
167
168#[repr(u8)]
169#[derive(Clone, Copy, Debug, Default, PartialEq, TryFromPrimitive)]
170pub enum PixelFormat {
171    #[default]
172    ARGB32 = 0, // packed ARGB, 32 bits, little-endian, BGRA in memory
173    BGRA32, // packed BGRA, 32 bits, little-endian, ARGB in memory
174    ABGR32, // packed ABGR, 32 bits, little-endian, RGBA in memory
175    RGBA32, // packed RGBA, 32 bits, little-endian, ABGR in memory
176    RGB24,  // packed RGB, 24 bits, little-endian, BGR in memory
177    BGR24,  // packed BGR, 24 bits, little-endian, RGB in memory
178    I420,   // planar YUV 4:2:0, 12 bits
179    I422,   // planar YUV 4:2:2, 16 bits
180    I444,   // planar YUV 4:4:4, 24 bits
181    NV12,   // biplanar YUV 4:2:0, 12 bits
182    NV21,   // biplanar YUV 4:2:0, 12 bits
183    NV16,   // biplanar YUV 4:2:2, 16 bits
184    NV61,   // biplanar YUV 4:2:2, 16 bits
185    NV24,   // biplanar YUV 4:4:4, 24 bits
186    NV42,   // biplanar YUV 4:4:4, 24 bits
187    YV12,   // planar YVU 4:2:0, 12 bits
188    YV16,   // planar YVU 4:2:2, 16 bits
189    YV24,   // planar YVU 4:4:4, 24 bits
190    YUYV,   // packed YUV 4:2:2, 16 bits, Y0 Cb Y1 Cr
191    YVYU,   // packed YUV 4:2:2, 16 bits, Y0 Cr Y1 Cb
192    UYVY,   // packed YUV 4:2:2, 16 bits, Cb Y0 Cr Y1
193    VYUY,   // packed YUV 4:2:2, 16 bits, Cr Y0 Cb Y1
194    AYUV,   // packed AYUV 4:4:4, 32 bits
195    Y8,     // greyscale, 8 bits Y
196    YA8,    // greyscale, 8 bits Y, 8 bits alpha
197    RGB30,  // packed RGB, 30 bits, 10 bits per channel, little-endian
198    BGR30,  // packed BGR, 30 bits, 10 bits per channel, little-endian
199    ARGB64, // packed ARGB, 64 bits, 16 bits per channel, little-endian
200    ABGR64, // packed ABGR, 64 bits, 16 bits per channel, little-endian
201    I010,   // planar YUV 4:2:0, 10 bits per channel
202    I210,   // planar YUV 4:2:2, 10 bits per channel
203    I410,   // planar YUV 4:4:4, 10 bits per channel
204    P010,   // biplanar YUV 4:2:0, 10 bits per channel
205    P210,   // biplanar YUV 4:2:2, 10 bits per channel
206    P410,   // biplanar YUV 4:4:4, 10 bits per channel
207    I012,   // planar YUV 4:2:2, 12 bits per channel
208    I212,   // planar YUV 4:2:2, 12 bits per channel
209    I412,   // planar YUV 4:4:4, 12 bits per channel
210    P012,   // biplanar YUV 4:2:0, 12 bits per channel
211    P212,   // biplanar YUV 4:2:2, 12 bits per channel
212    P412,   // biplanar YUV 4:4:4, 12 bits per channel
213    I016,   // planar YUV 4:2:0, 16 bits per channel
214    I216,   // planar YUV 4:2:2, 16 bits per channel
215    I416,   // planar YUV 4:4:4, 16 bits per channel
216    P016,   // biplanar YUV 4:2:0, 16 bits per channel
217    P216,   // biplanar YUV 4:2:2, 16 bits per channel
218    P416,   // biplanar YUV 4:4:4, 16 bits per channel
219    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    // ARGB32
321    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    // BGRA32
330    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    // ABGR32
339    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    // RGBA32
348    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    // RGB24
357    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    // BGR24
366    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    // I420
375    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    // I422
384    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    // I444
393    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    // NV12
402    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    // NV21
411    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    // NV16
420    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    // NV61
429    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    // NV24
438    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    // NV42
447    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    // YV12
456    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    // YV16
465    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    // YV24
474    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    // YUYV
483    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    // YVYU
492    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    // UYVY
501    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    // VYUY
510    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    // AYUV
519    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    // Y8
528    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    // YA8
537    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    // RGB30
546    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    // BGR30
555    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    // ARGB64
564    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    // ABGR64
573    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    // I010
582    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    // I210
591    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    // I410
600    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    // P010
609    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    // P210
618    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    // P410
627    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    // I012
636    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    // I212
645    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    // I412
654    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    // P012
663    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    // P212
672    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    // P412
681    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    // I016
690    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    // I216
699    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    // I416
708    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    // P016
717    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    // P216
726    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    // P416
735    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}