2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Robert Nagy, ronag89@gmail.com
24 #include <common/except.h>
25 #include <common/log.h>
26 #include <core/video_format.h>
28 #include "../decklink_api.h"
30 #include <boost/lexical_cast.hpp>
34 namespace caspar { namespace decklink {
36 static BMDDisplayMode get_decklink_video_format(core::video_format fmt)
40 case core::video_format::pal: return bmdModePAL;
41 case core::video_format::ntsc: return bmdModeNTSC;
42 case core::video_format::x576p2500: return (BMDDisplayMode)ULONG_MAX;
43 case core::video_format::x720p2398: return (BMDDisplayMode)ULONG_MAX;
44 case core::video_format::x720p2400: return (BMDDisplayMode)ULONG_MAX;
45 case core::video_format::x720p2500: return (BMDDisplayMode)ULONG_MAX;
46 case core::video_format::x720p5000: return bmdModeHD720p50;
47 case core::video_format::x720p2997: return (BMDDisplayMode)ULONG_MAX;
48 case core::video_format::x720p5994: return bmdModeHD720p5994;
49 case core::video_format::x720p3000: return (BMDDisplayMode)ULONG_MAX;
50 case core::video_format::x720p6000: return bmdModeHD720p60;
51 case core::video_format::x1080p2398: return bmdModeHD1080p2398;
52 case core::video_format::x1080p2400: return bmdModeHD1080p24;
53 case core::video_format::x1080i5000: return bmdModeHD1080i50;
54 case core::video_format::x1080i5994: return bmdModeHD1080i5994;
55 case core::video_format::x1080i6000: return bmdModeHD1080i6000;
56 case core::video_format::x1080p2500: return bmdModeHD1080p25;
57 case core::video_format::x1080p2997: return bmdModeHD1080p2997;
58 case core::video_format::x1080p3000: return bmdModeHD1080p30;
59 case core::video_format::x1080p5000: return bmdModeHD1080p50;
60 case core::video_format::x1080p5994: return bmdModeHD1080p5994;
61 case core::video_format::x1080p6000: return bmdModeHD1080p6000;
62 case core::video_format::x1556p2398: return bmdMode2k2398;
63 case core::video_format::x1556p2400: return bmdMode2k24;
64 case core::video_format::x1556p2500: return bmdMode2k25;
65 case core::video_format::dci1080p2398: return bmdMode2kDCI2398;
66 case core::video_format::dci1080p2400: return bmdMode2kDCI24;
67 case core::video_format::dci1080p2500: return bmdMode2kDCI25;
68 case core::video_format::x2160p2398: return bmdMode4K2160p2398;
69 case core::video_format::x2160p2400: return bmdMode4K2160p24;
70 case core::video_format::x2160p2500: return bmdMode4K2160p25;
71 case core::video_format::x2160p2997: return bmdMode4K2160p2997;
72 case core::video_format::x2160p3000: return bmdMode4K2160p30;
73 case core::video_format::x2160p5000: return bmdMode4K2160p50;
74 case core::video_format::x2160p5994: return bmdMode4K2160p5994;
75 case core::video_format::x2160p6000: return bmdMode4K2160p60;
76 case core::video_format::dci2160p2398: return bmdMode4kDCI2398;
77 case core::video_format::dci2160p2400: return bmdMode4kDCI24;
78 case core::video_format::dci2160p2500: return bmdMode4kDCI25;
79 default: return (BMDDisplayMode)ULONG_MAX;
83 static core::video_format get_caspar_video_format(BMDDisplayMode fmt)
87 case bmdModePAL: return core::video_format::pal;
88 case bmdModeNTSC: return core::video_format::ntsc;
89 case bmdModeHD720p50: return core::video_format::x720p5000;
90 case bmdModeHD720p5994: return core::video_format::x720p5994;
91 case bmdModeHD720p60: return core::video_format::x720p6000;
92 case bmdModeHD1080p2398: return core::video_format::x1080p2398;
93 case bmdModeHD1080p24: return core::video_format::x1080p2400;
94 case bmdModeHD1080i50: return core::video_format::x1080i5000;
95 case bmdModeHD1080i5994: return core::video_format::x1080i5994;
96 case bmdModeHD1080i6000: return core::video_format::x1080i6000;
97 case bmdModeHD1080p25: return core::video_format::x1080p2500;
98 case bmdModeHD1080p2997: return core::video_format::x1080p2997;
99 case bmdModeHD1080p30: return core::video_format::x1080p3000;
100 case bmdModeHD1080p50: return core::video_format::x1080p5000;
101 case bmdModeHD1080p5994: return core::video_format::x1080p5994;
102 case bmdModeHD1080p6000: return core::video_format::x1080p6000;
103 case bmdMode2k2398: return core::video_format::x1556p2398;
104 case bmdMode2k24: return core::video_format::x1556p2400;
105 case bmdMode2k25: return core::video_format::x1556p2500;
106 case bmdMode2kDCI2398: return core::video_format::dci1080p2398;
107 case bmdMode2kDCI24: return core::video_format::dci1080p2400;
108 case bmdMode2kDCI25: return core::video_format::dci1080p2500;
109 case bmdMode4K2160p2398: return core::video_format::x2160p2398;
110 case bmdMode4K2160p24: return core::video_format::x2160p2400;
111 case bmdMode4K2160p25: return core::video_format::x2160p2500;
112 case bmdMode4K2160p2997: return core::video_format::x2160p2997;
113 case bmdMode4K2160p30: return core::video_format::x2160p3000;
114 case bmdMode4K2160p50: return core::video_format::x2160p5000;
115 case bmdMode4K2160p5994: return core::video_format::x2160p5994;
116 case bmdMode4K2160p60: return core::video_format::x2160p6000;
117 case bmdMode4kDCI2398: return core::video_format::dci2160p2398;
118 case bmdMode4kDCI24: return core::video_format::dci2160p2400;
119 case bmdMode4kDCI25: return core::video_format::dci2160p2500;
120 default: return core::video_format::invalid;
124 static std::wstring get_mode_name(const com_ptr<IDeckLinkDisplayMode>& mode)
127 mode->GetName(&mode_name);
128 return u16(mode_name);
131 template<typename T, typename F>
132 BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma)
134 IDeckLinkDisplayMode* m = nullptr;
135 IDeckLinkDisplayModeIterator* iter;
136 if(SUCCEEDED(device->GetDisplayModeIterator(&iter)))
138 auto iterator = wrap_raw<com_ptr>(iter, true);
139 while(SUCCEEDED(iterator->Next(&m)) &&
141 m->GetDisplayMode() != format)
148 CASPAR_THROW_EXCEPTION(user_error() << msg_info("Device could not find requested video-format: " + boost::lexical_cast<std::string>(format)));
150 com_ptr<IDeckLinkDisplayMode> mode = wrap_raw<com_ptr>(m, true);
152 BMDDisplayModeSupport displayModeSupport;
153 will_attempt_dma = false;
155 if (FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)))
156 CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Could not determine whether device supports requested video format: " + get_mode_name(mode)));
157 else if (displayModeSupport == bmdDisplayModeNotSupported)
158 CASPAR_LOG(warning) << L"Device does not support video-format: " << get_mode_name(mode);
159 else if (displayModeSupport == bmdDisplayModeSupportedWithConversion)
160 CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << get_mode_name(mode);
162 will_attempt_dma = true;
164 return mode->GetDisplayMode();
167 template<typename T, typename F>
168 static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma)
170 return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag, will_attempt_dma);
174 static std::wstring version(T iterator)
176 auto info = iface_cast<IDeckLinkAPIInformation>(iterator);
181 info->GetString(BMDDeckLinkAPIVersion, &ver);
186 static com_ptr<IDeckLink> get_device(size_t device_index)
188 auto pDecklinkIterator = create_iterator();
191 com_ptr<IDeckLink> decklink;
192 IDeckLink* current = nullptr;
193 while(n < device_index && pDecklinkIterator->Next(¤t) == S_OK)
196 decklink = wrap_raw<com_ptr>(current);
200 if(n != device_index || !decklink)
201 CASPAR_THROW_EXCEPTION(user_error() << msg_info("Decklink device " + boost::lexical_cast<std::string>(device_index) + " not found."));
206 template <typename T>
207 static std::wstring get_model_name(const T& device)
210 device->GetModelName(&pModelName);
211 return u16(pModelName);
214 class reference_signal_detector
216 com_iface_ptr<IDeckLinkOutput> output_;
217 BMDReferenceStatus last_reference_status_ = static_cast<BMDReferenceStatus>(-1);
219 reference_signal_detector(const com_iface_ptr<IDeckLinkOutput>& output)
224 template<typename Print>
225 void detect_change(const Print& print)
227 BMDReferenceStatus reference_status;
229 if (output_->GetReferenceStatus(&reference_status) != S_OK)
231 CASPAR_LOG(error) << print() << L" Reference signal: failed while querying status";
233 else if (reference_status != last_reference_status_)
235 last_reference_status_ = reference_status;
237 if (reference_status == 0)
238 CASPAR_LOG(info) << print() << L" Reference signal: not detected.";
239 else if (reference_status & bmdReferenceNotSupportedByHardware)
240 CASPAR_LOG(info) << print() << L" Reference signal: not supported by hardware.";
241 else if (reference_status & bmdReferenceLocked)
242 CASPAR_LOG(info) << print() << L" Reference signal: locked.";
244 CASPAR_LOG(info) << print() << L" Reference signal: Unhandled enum bitfield: " << reference_status;