1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use core_foundation::{
    array::{CFArray, CFArrayRef},
    base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, CFIndex, CFType, TCFType},
    dictionary::{CFDictionary, CFDictionaryRef},
    number::CFNumber,
    string::{CFString, CFStringRef},
};
use libc::c_void;

use crate::{pixel_buffer::CVPixelBufferRef, OSType};

pub type CVFillExtendedPixelsCallBack = extern "C" fn(pixelBuffer: CVPixelBufferRef, refCon: *mut c_void) -> Boolean;

#[repr(C)]
pub struct CVFillExtendedPixelsCallBackData {
    pub version: CFIndex,
    pub fillCallBack: CVFillExtendedPixelsCallBack,
    pub refCon: *mut c_void,
}

extern "C" {
    pub static kCVPixelFormatName: CFStringRef;
    pub static kCVPixelFormatConstant: CFStringRef;
    pub static kCVPixelFormatCodecType: CFStringRef;
    pub static kCVPixelFormatFourCC: CFStringRef;
    pub static kCVPixelFormatContainsAlpha: CFStringRef;
    pub static kCVPixelFormatContainsYCbCr: CFStringRef;
    pub static kCVPixelFormatContainsRGB: CFStringRef;
    pub static kCVPixelFormatComponentRange: CFStringRef;
    pub static kCVPixelFormatComponentRange_VideoRange: CFStringRef;
    pub static kCVPixelFormatComponentRange_FullRange: CFStringRef;
    pub static kCVPixelFormatComponentRange_WideRange: CFStringRef;
    pub static kCVPixelFormatPlanes: CFStringRef;
    pub static kCVPixelFormatBlockWidth: CFStringRef;
    pub static kCVPixelFormatBlockHeight: CFStringRef;
    pub static kCVPixelFormatBitsPerBlock: CFStringRef;
    pub static kCVPixelFormatBlockHorizontalAlignment: CFStringRef;
    pub static kCVPixelFormatBlockVerticalAlignment: CFStringRef;
    pub static kCVPixelFormatBlackBlock: CFStringRef;
    pub static kCVPixelFormatHorizontalSubsampling: CFStringRef;
    pub static kCVPixelFormatVerticalSubsampling: CFStringRef;
    pub static kCVPixelFormatOpenGLFormat: CFStringRef;
    pub static kCVPixelFormatOpenGLType: CFStringRef;
    pub static kCVPixelFormatOpenGLInternalFormat: CFStringRef;
    pub static kCVPixelFormatCGBitmapInfo: CFStringRef;
    pub static kCVPixelFormatQDCompatibility: CFStringRef;
    pub static kCVPixelFormatCGBitmapContextCompatibility: CFStringRef;
    pub static kCVPixelFormatCGImageCompatibility: CFStringRef;
    pub static kCVPixelFormatOpenGLCompatibility: CFStringRef;
    #[cfg(target_os = "ios")]
    pub static kCVPixelFormatOpenGLESCompatibility: CFStringRef;
    pub static kCVPixelFormatFillExtendedPixelsCallback: CFStringRef;

    pub fn CVPixelFormatDescriptionCreateWithPixelFormatType(allocator: CFAllocatorRef, pixelFormat: OSType) -> CFDictionaryRef;
    pub fn CVPixelFormatDescriptionArrayCreateWithAllPixelFormatTypes(allocator: CFAllocatorRef) -> CFArrayRef;
    pub fn CVPixelFormatDescriptionRegisterDescriptionWithPixelFormatType(description: CFDictionaryRef, pixelFormat: OSType);
    pub fn CVIsCompressedPixelFormatAvailable(pixelFormat: OSType) -> Boolean;
}

pub enum CVPixelFormatDescriptionKeys {
    Name,
    Constant,
    CodecType,
    FourCC,
    ContainsAlpha,
    ContainsYCbCr,
    ContainsRGB,
    ComponentRange,
    ComponentRange_VideoRange,
    ComponentRange_FullRange,
    ComponentRange_WideRange,
    Planes,
    BlockWidth,
    BlockHeight,
    BitsPerBlock,
    BlockHorizontalAlignment,
    BlockVerticalAlignment,
    BlackBlock,
    HorizontalSubsampling,
    VerticalSubsampling,
    OpenGLFormat,
    OpenGLType,
    OpenGLInternalFormat,
    CGBitmapInfo,
    QDCompatibility,
    CGBitmapContextCompatibility,
    CGImageCompatibility,
    OpenGLCompatibility,
    #[cfg(target_os = "ios")]
    OpenGLESCompatibility,
    FillExtendedPixelsCallback,
}

impl From<CVPixelFormatDescriptionKeys> for CFStringRef {
    fn from(key: CVPixelFormatDescriptionKeys) -> Self {
        unsafe {
            match key {
                CVPixelFormatDescriptionKeys::Name => kCVPixelFormatName,
                CVPixelFormatDescriptionKeys::Constant => kCVPixelFormatConstant,
                CVPixelFormatDescriptionKeys::CodecType => kCVPixelFormatCodecType,
                CVPixelFormatDescriptionKeys::FourCC => kCVPixelFormatFourCC,
                CVPixelFormatDescriptionKeys::ContainsAlpha => kCVPixelFormatContainsAlpha,
                CVPixelFormatDescriptionKeys::ContainsYCbCr => kCVPixelFormatContainsYCbCr,
                CVPixelFormatDescriptionKeys::ContainsRGB => kCVPixelFormatContainsRGB,
                CVPixelFormatDescriptionKeys::ComponentRange => kCVPixelFormatComponentRange,
                CVPixelFormatDescriptionKeys::ComponentRange_VideoRange => kCVPixelFormatComponentRange_VideoRange,
                CVPixelFormatDescriptionKeys::ComponentRange_FullRange => kCVPixelFormatComponentRange_FullRange,
                CVPixelFormatDescriptionKeys::ComponentRange_WideRange => kCVPixelFormatComponentRange_WideRange,
                CVPixelFormatDescriptionKeys::Planes => kCVPixelFormatPlanes,
                CVPixelFormatDescriptionKeys::BlockWidth => kCVPixelFormatBlockWidth,
                CVPixelFormatDescriptionKeys::BlockHeight => kCVPixelFormatBlockHeight,
                CVPixelFormatDescriptionKeys::BitsPerBlock => kCVPixelFormatBitsPerBlock,
                CVPixelFormatDescriptionKeys::BlockHorizontalAlignment => kCVPixelFormatBlockHorizontalAlignment,
                CVPixelFormatDescriptionKeys::BlockVerticalAlignment => kCVPixelFormatBlockVerticalAlignment,
                CVPixelFormatDescriptionKeys::BlackBlock => kCVPixelFormatBlackBlock,
                CVPixelFormatDescriptionKeys::HorizontalSubsampling => kCVPixelFormatHorizontalSubsampling,
                CVPixelFormatDescriptionKeys::VerticalSubsampling => kCVPixelFormatVerticalSubsampling,
                CVPixelFormatDescriptionKeys::OpenGLFormat => kCVPixelFormatOpenGLFormat,
                CVPixelFormatDescriptionKeys::OpenGLType => kCVPixelFormatOpenGLType,
                CVPixelFormatDescriptionKeys::OpenGLInternalFormat => kCVPixelFormatOpenGLInternalFormat,
                CVPixelFormatDescriptionKeys::CGBitmapInfo => kCVPixelFormatCGBitmapInfo,
                CVPixelFormatDescriptionKeys::QDCompatibility => kCVPixelFormatQDCompatibility,
                CVPixelFormatDescriptionKeys::CGBitmapContextCompatibility => kCVPixelFormatCGBitmapContextCompatibility,
                CVPixelFormatDescriptionKeys::CGImageCompatibility => kCVPixelFormatCGImageCompatibility,
                CVPixelFormatDescriptionKeys::OpenGLCompatibility => kCVPixelFormatOpenGLCompatibility,
                #[cfg(target_os = "ios")]
                CVPixelFormatDescriptionKeys::OpenGLESCompatibility => kCVPixelFormatOpenGLESCompatibility,
                CVPixelFormatDescriptionKeys::FillExtendedPixelsCallback => kCVPixelFormatFillExtendedPixelsCallback,
            }
        }
    }
}

impl From<CVPixelFormatDescriptionKeys> for CFString {
    fn from(key: CVPixelFormatDescriptionKeys) -> Self {
        unsafe { CFString::wrap_under_get_rule(CFStringRef::from(key)) }
    }
}

pub fn pixel_format_description_create_with_pixel_format_type(pixel_format: OSType) -> Result<CFDictionary<CFString, CFType>, ()> {
    unsafe {
        let description = CVPixelFormatDescriptionCreateWithPixelFormatType(kCFAllocatorDefault, pixel_format);
        if description.is_null() {
            Err(())
        } else {
            Ok(TCFType::wrap_under_create_rule(description))
        }
    }
}

pub fn pixel_format_description_array_create_with_all_pixel_format_types() -> Result<CFArray<CFNumber>, ()> {
    unsafe {
        let array = CVPixelFormatDescriptionArrayCreateWithAllPixelFormatTypes(kCFAllocatorDefault);
        if array.is_null() {
            Err(())
        } else {
            Ok(TCFType::wrap_under_create_rule(array))
        }
    }
}

pub fn is_compressed_pixel_format_available(pixel_format: OSType) -> bool {
    unsafe { CVIsCompressedPixelFormatAvailable(pixel_format) != 0 }
}