core_video/
display_link.rs

1use std::ptr::{null, null_mut};
2
3use block::{Block, ConcreteBlock};
4use core_foundation::base::{Boolean, CFIndex, CFTypeID, TCFType};
5use core_graphics::display::CGDirectDisplayID;
6use libc::c_void;
7
8#[repr(C)]
9pub struct __CVDisplayLink(c_void);
10
11pub type CVDisplayLinkRef = *mut __CVDisplayLink;
12
13use crate::{
14    base::{CVOptionFlags, CVTime, CVTimeStamp},
15    r#return::{kCVReturnSuccess, CVReturn},
16    CGLContextObj, CGLPixelFormatObj,
17};
18
19pub type CVDisplayLinkOutputCallback = extern "C" fn(
20    displayLink: CVDisplayLinkRef,
21    inNow: *const CVTimeStamp,
22    inOutputTime: *const CVTimeStamp,
23    flagsIn: CVOptionFlags,
24    flagsOut: *mut CVOptionFlags,
25    displayLinkContext: *mut c_void,
26) -> CVReturn;
27
28pub type CVDisplayLinkOutputHandler =
29    *const Block<(CVDisplayLinkRef, *const CVTimeStamp, *const CVTimeStamp, CVOptionFlags, *mut CVOptionFlags), CVReturn>;
30
31pub type CGOpenGLDisplayMask = u32;
32
33extern "C" {
34    pub fn CVDisplayLinkGetTypeID() -> CFTypeID;
35    pub fn CVDisplayLinkCreateWithCGDisplays(
36        displayArray: *const CGDirectDisplayID,
37        count: CFIndex,
38        displayLinkOut: *mut CVDisplayLinkRef,
39    ) -> CVReturn;
40    pub fn CVDisplayLinkCreateWithOpenGLDisplayMask(mask: CGOpenGLDisplayMask, displayLinkOut: *mut CVDisplayLinkRef) -> CVReturn;
41    pub fn CVDisplayLinkCreateWithCGDisplay(displayID: CGDirectDisplayID, displayLinkOut: *mut CVDisplayLinkRef) -> CVReturn;
42    pub fn CVDisplayLinkCreateWithActiveCGDisplays(displayLinkOut: *mut CVDisplayLinkRef) -> CVReturn;
43    pub fn CVDisplayLinkSetCurrentCGDisplay(displayLink: CVDisplayLinkRef, displayID: CGDirectDisplayID) -> CVReturn;
44    pub fn CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
45        displayLink: CVDisplayLinkRef,
46        cglContext: CGLContextObj,
47        CGLPixelFormatObj: CGLPixelFormatObj,
48    ) -> CVReturn;
49    pub fn CVDisplayLinkGetCurrentCGDisplay(displayLink: CVDisplayLinkRef) -> CGDirectDisplayID;
50    pub fn CVDisplayLinkSetOutputCallback(displayLink: CVDisplayLinkRef, callback: CVDisplayLinkOutputCallback, userInfo: *mut c_void) -> CVReturn;
51    pub fn CVDisplayLinkSetOutputHandler(displayLink: CVDisplayLinkRef, handler: CVDisplayLinkOutputHandler) -> CVReturn;
52    pub fn CVDisplayLinkStart(displayLink: CVDisplayLinkRef) -> CVReturn;
53    pub fn CVDisplayLinkStop(displayLink: CVDisplayLinkRef) -> CVReturn;
54    pub fn CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink: CVDisplayLinkRef) -> CVTime;
55    pub fn CVDisplayLinkGetOutputVideoLatency(displayLink: CVDisplayLinkRef) -> CVTime;
56    pub fn CVDisplayLinkGetActualOutputVideoRefreshPeriod(displayLink: CVDisplayLinkRef) -> CVTime;
57    pub fn CVDisplayLinkIsRunning(displayLink: CVDisplayLinkRef) -> Boolean;
58    pub fn CVDisplayLinkGetCurrentTime(displayLink: CVDisplayLinkRef, outTime: *mut CVTime) -> CVReturn;
59    pub fn CVDisplayLinkTranslateTime(displayLink: CVDisplayLinkRef, inTime: *const CVTime, outTime: *mut CVTime) -> CVReturn;
60    pub fn CVDisplayLinkRetain(displayLink: CVDisplayLinkRef) -> CVDisplayLinkRef;
61    pub fn CVDisplayLinkRelease(displayLink: CVDisplayLinkRef);
62}
63
64pub struct CVDisplayLink(CVDisplayLinkRef);
65
66impl Drop for CVDisplayLink {
67    fn drop(&mut self) {
68        unsafe { CVDisplayLinkRelease(self.0) }
69    }
70}
71
72impl_TCFType!(CVDisplayLink, CVDisplayLinkRef, CVDisplayLinkGetTypeID);
73impl_CFTypeDescription!(CVDisplayLink);
74
75impl CVDisplayLink {
76    #[inline]
77    pub fn from_cg_displays(display_array: &[CGDirectDisplayID]) -> Result<CVDisplayLink, CVReturn> {
78        let mut display_link: CVDisplayLinkRef = null_mut();
79        unsafe {
80            let result = CVDisplayLinkCreateWithCGDisplays(display_array.as_ptr(), display_array.len() as CFIndex, &mut display_link);
81            if result == kCVReturnSuccess {
82                Ok(TCFType::wrap_under_create_rule(display_link))
83            } else {
84                Err(result)
85            }
86        }
87    }
88
89    #[inline]
90    pub fn from_opengl_display_mask(mask: CGOpenGLDisplayMask) -> Result<CVDisplayLink, CVReturn> {
91        let mut display_link: CVDisplayLinkRef = null_mut();
92        unsafe {
93            let result = CVDisplayLinkCreateWithOpenGLDisplayMask(mask, &mut display_link);
94            if result == kCVReturnSuccess {
95                Ok(TCFType::wrap_under_create_rule(display_link))
96            } else {
97                Err(result)
98            }
99        }
100    }
101
102    #[inline]
103    pub fn from_cg_display(display_id: CGDirectDisplayID) -> Result<CVDisplayLink, CVReturn> {
104        let mut display_link: CVDisplayLinkRef = null_mut();
105        unsafe {
106            let result = CVDisplayLinkCreateWithCGDisplay(display_id, &mut display_link);
107            if result == kCVReturnSuccess {
108                Ok(TCFType::wrap_under_create_rule(display_link))
109            } else {
110                Err(result)
111            }
112        }
113    }
114
115    #[inline]
116    pub fn from_active_cg_displays() -> Result<CVDisplayLink, CVReturn> {
117        let mut display_link: CVDisplayLinkRef = null_mut();
118        unsafe {
119            let result = CVDisplayLinkCreateWithActiveCGDisplays(&mut display_link);
120            if result == kCVReturnSuccess {
121                Ok(TCFType::wrap_under_create_rule(display_link))
122            } else {
123                Err(result)
124            }
125        }
126    }
127
128    #[inline]
129    pub fn set_current_cg_display(&self, display_id: CGDirectDisplayID) -> Result<(), CVReturn> {
130        let result = unsafe { CVDisplayLinkSetCurrentCGDisplay(self.as_concrete_TypeRef(), display_id) };
131        if result == kCVReturnSuccess {
132            Ok(())
133        } else {
134            Err(result)
135        }
136    }
137
138    #[inline]
139    pub unsafe fn set_current_cg_display_from_opengl_context(
140        &self,
141        cgl_context: CGLContextObj,
142        cgl_pixel_format: CGLPixelFormatObj,
143    ) -> Result<(), CVReturn> {
144        let result = unsafe { CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self.as_concrete_TypeRef(), cgl_context, cgl_pixel_format) };
145        if result == kCVReturnSuccess {
146            Ok(())
147        } else {
148            Err(result)
149        }
150    }
151
152    #[inline]
153    pub fn get_current_cg_display(&self) -> CGDirectDisplayID {
154        unsafe { CVDisplayLinkGetCurrentCGDisplay(self.as_concrete_TypeRef()) }
155    }
156
157    pub unsafe fn set_output_callback(&self, callback: CVDisplayLinkOutputCallback, user_info: *mut c_void) -> Result<(), CVReturn> {
158        let result = unsafe { CVDisplayLinkSetOutputCallback(self.as_concrete_TypeRef(), callback, user_info) };
159        if result == kCVReturnSuccess {
160            Ok(())
161        } else {
162            Err(result)
163        }
164    }
165
166    pub fn set_output_closure<F>(&self, closure: Option<F>) -> Result<(), CVReturn>
167    where
168        F: Fn(&CVDisplayLink, &CVTimeStamp, &CVTimeStamp, CVOptionFlags, &mut CVOptionFlags) -> CVReturn + 'static,
169    {
170        let handler = closure.map(|closure| {
171            ConcreteBlock::new(
172                move |display_link: CVDisplayLinkRef,
173                      in_now: *const CVTimeStamp,
174                      in_output_time: *const CVTimeStamp,
175                      flags_in: CVOptionFlags,
176                      flags_out: *mut CVOptionFlags|
177                      -> CVReturn {
178                    let display_link = unsafe { CVDisplayLink::wrap_under_get_rule(display_link) };
179                    let in_now = unsafe { &*in_now };
180                    let in_output_time = unsafe { &*in_output_time };
181                    let flags_out = unsafe { &mut *flags_out };
182                    closure(&display_link, &in_now, &in_output_time, flags_in, flags_out)
183                },
184            )
185            .copy()
186        });
187        let result = unsafe { CVDisplayLinkSetOutputHandler(self.as_concrete_TypeRef(), handler.as_ref().map_or(null(), |h| &**h)) };
188        if result == kCVReturnSuccess {
189            Ok(())
190        } else {
191            Err(result)
192        }
193    }
194
195    #[inline]
196    pub fn start(&self) -> Result<(), CVReturn> {
197        let result = unsafe { CVDisplayLinkStart(self.as_concrete_TypeRef()) };
198        if result == kCVReturnSuccess {
199            Ok(())
200        } else {
201            Err(result)
202        }
203    }
204
205    #[inline]
206    pub fn stop(&self) -> Result<(), CVReturn> {
207        let result = unsafe { CVDisplayLinkStop(self.as_concrete_TypeRef()) };
208        if result == kCVReturnSuccess {
209            Ok(())
210        } else {
211            Err(result)
212        }
213    }
214
215    #[inline]
216    pub fn get_nominal_output_video_refresh_period(&self) -> CVTime {
217        unsafe { CVDisplayLinkGetNominalOutputVideoRefreshPeriod(self.as_concrete_TypeRef()) }
218    }
219
220    #[inline]
221    pub fn get_output_video_latency(&self) -> CVTime {
222        unsafe { CVDisplayLinkGetOutputVideoLatency(self.as_concrete_TypeRef()) }
223    }
224
225    #[inline]
226    pub fn get_actual_output_video_refresh_period(&self) -> CVTime {
227        unsafe { CVDisplayLinkGetActualOutputVideoRefreshPeriod(self.as_concrete_TypeRef()) }
228    }
229
230    #[inline]
231    pub fn is_running(&self) -> bool {
232        unsafe { CVDisplayLinkIsRunning(self.as_concrete_TypeRef()) != 0 }
233    }
234
235    #[inline]
236    pub fn get_current_time(&self) -> Result<CVTime, CVReturn> {
237        let mut outTime = CVTime::default();
238        let result = unsafe { CVDisplayLinkGetCurrentTime(self.as_concrete_TypeRef(), &mut outTime) };
239        if result == kCVReturnSuccess {
240            Ok(outTime)
241        } else {
242            Err(result)
243        }
244    }
245
246    #[inline]
247    pub fn translate_time(&self, in_time: &CVTime) -> Result<CVTime, CVReturn> {
248        let mut out_time = CVTime::default();
249        let result = unsafe { CVDisplayLinkTranslateTime(self.as_concrete_TypeRef(), in_time, &mut out_time) };
250        if result == kCVReturnSuccess {
251            Ok(out_time)
252        } else {
253            Err(result)
254        }
255    }
256}