decklink/device/output/
mod.rs

1mod audio;
2mod device;
3mod enums;
4mod video;
5mod video_callback;
6
7use crate::device::output::device::DecklinkOutputDevicePtr;
8use crate::device::output::video_callback::register_callback;
9use crate::display_mode::{
10    iterate_display_modes, wrap_display_mode, DecklinkDisplayMode, DecklinkDisplayModeId,
11};
12use crate::frame::DecklinkPixelFormat;
13use crate::{sdk, SdkError};
14use num_traits::FromPrimitive;
15use std::ptr::null_mut;
16use std::rc::Rc;
17use std::sync::atomic::{AtomicBool, Ordering};
18use std::sync::Arc;
19
20pub use crate::device::output::audio::DecklinkOutputDeviceAudio;
21pub use crate::device::output::enums::*;
22pub use crate::device::output::video::{
23    DecklinkOutputDeviceVideoScheduled, DecklinkOutputDeviceVideoSync,
24};
25pub use crate::device::output::video_callback::DeckLinkVideoOutputCallback;
26use crate::device::{DecklinkDeviceDisplayModes, DecklinkDisplayModeSupport};
27
28use self::video::DecklinkOutputDeviceVideoImpl;
29
30pub struct DecklinkOutputDevice {
31    ptr: Arc<DecklinkOutputDevicePtr>,
32}
33
34impl DecklinkDeviceDisplayModes<enums::DecklinkVideoOutputFlags> for DecklinkOutputDevice {
35    fn does_support_video_mode(
36        &self,
37        mode: DecklinkDisplayModeId,
38        pixel_format: DecklinkPixelFormat,
39        flags: enums::DecklinkVideoOutputFlags,
40    ) -> Result<(DecklinkDisplayModeSupport, Option<DecklinkDisplayMode>), SdkError> {
41        let mut supported = sdk::_DecklinkDisplayModeSupport_decklinkDisplayModeNotSupported;
42        let mut display_mode = null_mut();
43        let result = unsafe {
44            sdk::cdecklink_output_does_support_video_mode(
45                self.ptr.dev,
46                mode as u32,
47                pixel_format as u32,
48                flags.bits(),
49                &mut supported,
50                &mut display_mode,
51            )
52        };
53        SdkError::result_or_else(result, move || {
54            let supported2 = DecklinkDisplayModeSupport::from_u32(supported)
55                .unwrap_or(DecklinkDisplayModeSupport::NotSupported);
56            if display_mode.is_null() || supported2 == DecklinkDisplayModeSupport::NotSupported {
57                (DecklinkDisplayModeSupport::NotSupported, None)
58            } else {
59                unsafe { (supported2, Some(wrap_display_mode(display_mode))) }
60            }
61        })
62    }
63
64    fn display_modes(&self) -> Result<Vec<DecklinkDisplayMode>, SdkError> {
65        unsafe {
66            let mut it = null_mut();
67            let ok = sdk::cdecklink_output_get_display_mode_iterator(self.ptr.dev, &mut it);
68            if SdkError::is_ok(ok) {
69                let v = iterate_display_modes(it);
70                sdk::cdecklink_display_mode_iterator_release(it);
71                v
72            } else {
73                Err(SdkError::from(ok))
74            }
75        }
76    }
77}
78// TODO - this is currently a bag of methods, and it could do with some more sanity checking (eg allow schedule when video not enabled etc)
79impl DecklinkOutputDevice {
80    pub(crate) fn from(ptr: *mut crate::sdk::cdecklink_output_t) -> DecklinkOutputDevice {
81        DecklinkOutputDevice {
82            ptr: Arc::new(DecklinkOutputDevicePtr {
83                dev: ptr,
84                video_active: Rc::new(AtomicBool::new(false)),
85                audio_active: Rc::new(AtomicBool::new(false)),
86            }),
87        }
88    }
89
90    /* Video Output */
91
92    unsafe fn enable_video_output_inner(
93        &self,
94        mode: DecklinkDisplayModeId,
95        flags: enums::DecklinkVideoOutputFlags,
96    ) -> i32 {
97        if self.ptr.video_active.swap(true, Ordering::Relaxed) {
98            // TODO - better mode
99            SdkError::ACCESSDENIED as i32
100        } else {
101            sdk::cdecklink_output_enable_video_output(self.ptr.dev, mode as u32, flags.bits())
102        }
103    }
104
105    pub fn is_scheduled_playback_running(&self) -> Result<bool, SdkError> {
106        unsafe {
107            let mut running = false;
108            let result =
109                sdk::cdecklink_output_is_scheduled_playback_running(self.ptr.dev, &mut running);
110            SdkError::result_or(result, running)
111        }
112    }
113
114    pub fn enable_video_output_scheduled(
115        &self,
116        mode: DecklinkDisplayModeId,
117        flags: enums::DecklinkVideoOutputFlags,
118        timescale: i64,
119    ) -> Result<Box<dyn DecklinkOutputDeviceVideoScheduled>, SdkError> {
120        match register_callback(&self.ptr) {
121            // Don't do this if already running?
122            Err(e) => Err(e),
123            Ok(wrapper) => {
124                // TODO - this leaks on error
125                let result = unsafe { self.enable_video_output_inner(mode, flags) };
126                SdkError::result_or_else(result, || {
127                    let r: Box<dyn DecklinkOutputDeviceVideoScheduled> = Box::new(
128                        DecklinkOutputDeviceVideoImpl::from(&self.ptr, wrapper, timescale),
129                    );
130                    r
131                })
132            }
133        }
134    }
135    pub fn enable_video_output_sync(
136        &self,
137        mode: DecklinkDisplayModeId,
138        flags: enums::DecklinkVideoOutputFlags,
139    ) -> Result<Box<dyn DecklinkOutputDeviceVideoSync>, SdkError> {
140        let result = unsafe { self.enable_video_output_inner(mode, flags) };
141        SdkError::result_or_else(result, || {
142            let r: Box<dyn DecklinkOutputDeviceVideoSync> = Box::new(
143                DecklinkOutputDeviceVideoImpl::from(&self.ptr, null_mut(), 1000),
144            );
145            r
146        })
147    }
148
149    /* Audio Output */
150
151    pub fn enable_audio_output(
152        &self,
153        sample_rate: enums::DecklinkAudioSampleRate,
154        sample_type: enums::DecklinkAudioSampleType,
155        channels: u32,
156        stream_type: enums::DecklinkAudioOutputStreamType,
157    ) -> Result<DecklinkOutputDeviceAudio, SdkError> {
158        if self.ptr.audio_active.swap(true, Ordering::Relaxed) {
159            // TODO - better mode
160            Err(SdkError::ACCESSDENIED)
161        } else {
162            unsafe {
163                let result = sdk::cdecklink_output_enable_audio_output(
164                    self.ptr.dev,
165                    sample_rate as u32,
166                    sample_type as u32,
167                    channels,
168                    stream_type as u32,
169                );
170                SdkError::result_or_else(result, || DecklinkOutputDeviceAudio::from(&self.ptr))
171            }
172        }
173    }
174}