]> git.sesse.net Git - casparcg/blobdiff - modules/decklink/util/util.h
Only memcpy on Linux if the decklink card will attempt DMA directly from BGRA buffer...
[casparcg] / modules / decklink / util / util.h
index dbe22acd3f755f1dbdeda4e2f0a3b234a69cd0a5..e91a42e2babe374a80b68442305ca315c7940ae9 100644 (file)
 #include <common/log.h>
 #include <core/video_format.h>
 
-#include "../interop/DeckLinkAPI_h.h"
+#include "../decklink_api.h"
 
 #include <boost/lexical_cast.hpp>
 
-#include <atlbase.h>
-
 #include <string>
 
 namespace caspar { namespace decklink {
        
 static BMDDisplayMode get_decklink_video_format(core::video_format fmt) 
 {
-       switch(fmt.value())
+       switch(fmt)
        {
        case core::video_format::pal:                   return bmdModePAL;
        case core::video_format::ntsc:                  return bmdModeNTSC;
@@ -61,14 +59,20 @@ static BMDDisplayMode get_decklink_video_format(core::video_format fmt)
        case core::video_format::x1080p5000:    return bmdModeHD1080p50;
        case core::video_format::x1080p5994:    return bmdModeHD1080p5994;
        case core::video_format::x1080p6000:    return bmdModeHD1080p6000;
-       case core::video_format::x2k2398:               return bmdMode2k2398;
-       case core::video_format::x2k2400:               return bmdMode2k24;
-       case core::video_format::x2k2500:               return bmdMode2k25;
-       case core::video_format::x4k2398:               return bmdMode4K2160p2398;
-       case core::video_format::x4k2400:               return bmdMode4K2160p24;
-       case core::video_format::x4k2500:               return bmdMode4K2160p25;
-       case core::video_format::x4k2997:               return bmdMode4K2160p2997;
-       case core::video_format::x4k3000:               return bmdMode4K2160p30;
+       case core::video_format::x1556p2398:    return bmdMode2k2398;
+       case core::video_format::x1556p2400:    return bmdMode2k24;
+       case core::video_format::x1556p2500:    return bmdMode2k25;
+       case core::video_format::dci1080p2398:  return bmdMode2kDCI2398;
+       case core::video_format::dci1080p2400:  return bmdMode2kDCI24;
+       case core::video_format::dci1080p2500:  return bmdMode2kDCI25;
+       case core::video_format::x2160p2398:    return bmdMode4K2160p2398;
+       case core::video_format::x2160p2400:    return bmdMode4K2160p24;
+       case core::video_format::x2160p2500:    return bmdMode4K2160p25;
+       case core::video_format::x2160p2997:    return bmdMode4K2160p2997;
+       case core::video_format::x2160p3000:    return bmdMode4K2160p30;
+       case core::video_format::dci2160p2398:  return bmdMode4kDCI2398;
+       case core::video_format::dci2160p2400:  return bmdMode4kDCI24;
+       case core::video_format::dci2160p2500:  return bmdMode4kDCI25;
        default:                                                                return (BMDDisplayMode)ULONG_MAX;
        }
 }
@@ -77,95 +81,118 @@ static core::video_format get_caspar_video_format(BMDDisplayMode fmt)
 {
        switch(fmt)
        {
-       case bmdModePAL:                                                return core::video_format::pal;         
-       case bmdModeNTSC:                                               return core::video_format::ntsc;                
-       case bmdModeHD720p50:                                   return core::video_format::x720p5000;   
-       case bmdModeHD720p5994:                                 return core::video_format::x720p5994;   
-       case bmdModeHD720p60:                                   return core::video_format::x720p6000;   
-       case bmdModeHD1080p2398:                                return core::video_format::x1080p2398;  
-       case bmdModeHD1080p24:                                  return core::video_format::x1080p2400;  
-       case bmdModeHD1080i50:                                  return core::video_format::x1080i5000;  
-       case bmdModeHD1080i5994:                                return core::video_format::x1080i5994;  
-       case bmdModeHD1080i6000:                                return core::video_format::x1080i6000;  
+       case bmdModePAL:                                                return core::video_format::pal;
+       case bmdModeNTSC:                                               return core::video_format::ntsc;
+       case bmdModeHD720p50:                                   return core::video_format::x720p5000;
+       case bmdModeHD720p5994:                                 return core::video_format::x720p5994;
+       case bmdModeHD720p60:                                   return core::video_format::x720p6000;
+       case bmdModeHD1080p2398:                                return core::video_format::x1080p2398;
+       case bmdModeHD1080p24:                                  return core::video_format::x1080p2400;
+       case bmdModeHD1080i50:                                  return core::video_format::x1080i5000;
+       case bmdModeHD1080i5994:                                return core::video_format::x1080i5994;
+       case bmdModeHD1080i6000:                                return core::video_format::x1080i6000;
        case bmdModeHD1080p25:                                  return core::video_format::x1080p2500;
        case bmdModeHD1080p2997:                                return core::video_format::x1080p2997;
        case bmdModeHD1080p30:                                  return core::video_format::x1080p3000;
        case bmdModeHD1080p50:                                  return core::video_format::x1080p5000;
        case bmdModeHD1080p5994:                                return core::video_format::x1080p5994;
        case bmdModeHD1080p6000:                                return core::video_format::x1080p6000;
-       case bmdMode2k2398:                                             return core::video_format::x2k2398;  
-       case bmdMode2k24:                                               return core::video_format::x2k2400;  
-       case bmdMode2k25:                                               return core::video_format::x2k2500;  
-       case bmdMode4K2160p2398:                                return core::video_format::x4k2398;  
-       case bmdMode4K2160p24:                                  return core::video_format::x4k2400;  
-       case bmdMode4K2160p25:                                  return core::video_format::x4k2500;  
-       case bmdMode4K2160p2997:                                return core::video_format::x4k2997;  
-       case bmdMode4K2160p30:                                  return core::video_format::x4k3000;  
-       default:                                                                return core::video_format::invalid;     
+       case bmdMode2k2398:                                             return core::video_format::x1556p2398;
+       case bmdMode2k24:                                               return core::video_format::x1556p2400;
+       case bmdMode2k25:                                               return core::video_format::x1556p2500;
+       case bmdMode2kDCI2398:                                  return core::video_format::dci1080p2398;
+       case bmdMode2kDCI24:                                    return core::video_format::dci1080p2400;
+       case bmdMode2kDCI25:                                    return core::video_format::dci1080p2500;
+       case bmdMode4K2160p2398:                                return core::video_format::x2160p2398;
+       case bmdMode4K2160p24:                                  return core::video_format::x2160p2400;
+       case bmdMode4K2160p25:                                  return core::video_format::x2160p2500;
+       case bmdMode4K2160p2997:                                return core::video_format::x2160p2997;
+       case bmdMode4K2160p30:                                  return core::video_format::x2160p3000;
+       case bmdMode4kDCI2398:                                  return core::video_format::dci2160p2398;
+       case bmdMode4kDCI24:                                    return core::video_format::dci2160p2400;
+       case bmdMode4kDCI25:                                    return core::video_format::dci2160p2500;
+       default:                                                                return core::video_format::invalid;
        }
 }
 
+static std::wstring get_mode_name(const com_ptr<IDeckLinkDisplayMode>& mode)
+{
+       String mode_name;
+       mode->GetName(&mode_name);
+       return u16(mode_name);
+}
+
 template<typename T, typename F>
-BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag)
+BMDDisplayMode get_display_mode(const T& device, BMDDisplayMode format, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma)
 {
-       CComPtr<IDeckLinkDisplayModeIterator> iterator;
-       CComPtr<IDeckLinkDisplayMode>             mode;
-       
-       if(SUCCEEDED(device->GetDisplayModeIterator(&iterator)))
+    IDeckLinkDisplayMode* m = nullptr;
+    IDeckLinkDisplayModeIterator* iter;
+    if(SUCCEEDED(device->GetDisplayModeIterator(&iter)))
        {
-               while(SUCCEEDED(iterator->Next(&mode)) && 
-                               mode != nullptr && 
-                               mode->GetDisplayMode() != format){}
+        auto iterator = wrap_raw<com_ptr>(iter, true);
+        while(SUCCEEDED(iterator->Next(&m)) &&
+                m != nullptr &&
+                m->GetDisplayMode() != format)
+        {
+            m->Release();
+        }
        }
 
-       if(!mode)
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device could not find requested video-format.") 
-                                                                                                << arg_value_info(boost::lexical_cast<std::string>(format))
-                                                                                                << arg_name_info("format"));
-               
+    if(!m)
+               CASPAR_THROW_EXCEPTION(user_error() << msg_info("Device could not find requested video-format: " + boost::lexical_cast<std::string>(format)));
+
+       com_ptr<IDeckLinkDisplayMode> mode = wrap_raw<com_ptr>(m, true);
+
        BMDDisplayModeSupport displayModeSupport;
-       if(FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)) || displayModeSupport == bmdDisplayModeNotSupported)
-               CASPAR_LOG(warning) << L"Device does not support video-format: " << mode->GetDisplayMode();
-               //CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Device does not support requested video-format.")
-               //                                                                               << arg_value_info(boost::lexical_cast<std::string>(format))
-               //                                                                               << arg_name_info("format"));
-       else if(displayModeSupport == bmdDisplayModeSupportedWithConversion)
-               CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << mode->GetDisplayMode();
+       will_attempt_dma = false;
+
+       if (FAILED(device->DoesSupportVideoMode(mode->GetDisplayMode(), pix_fmt, flag, &displayModeSupport, nullptr)))
+               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Could not determine whether device supports requested video format: " + get_mode_name(mode)));
+       else if (displayModeSupport == bmdDisplayModeNotSupported)
+               CASPAR_LOG(warning) << L"Device does not support video-format: " << get_mode_name(mode);
+       else if (displayModeSupport == bmdDisplayModeSupportedWithConversion)
+               CASPAR_LOG(warning) << L"Device supports video-format with conversion: " << get_mode_name(mode);
+       else
+               will_attempt_dma = true;
 
        return mode->GetDisplayMode();
 }
 
 template<typename T, typename F>
-static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag)
+static BMDDisplayMode get_display_mode(const T& device, core::video_format fmt, BMDPixelFormat pix_fmt, F flag, bool& will_attempt_dma)
 {      
-       return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag);
+       return get_display_mode(device, get_decklink_video_format(fmt), pix_fmt, flag, will_attempt_dma);
 }
 
 template<typename T>
-static std::wstring version(T& iterator)
+static std::wstring version(T iterator)
 {
-       CComQIPtr<IDeckLinkAPIInformation> info = iterator;
+    auto info = iface_cast<IDeckLinkAPIInformation>(iterator);
        if (!info)
                return L"Unknown";
        
-       BSTR ver;               
-       info->GetString(BMDDeckLinkAPIVersion, &ver);
+    String ver;
+    info->GetString(BMDDeckLinkAPIVersion, &ver);
                
-       return ver;                                     
+    return u16(ver);
 }
 
-static CComPtr<IDeckLink> get_device(size_t device_index)
+static com_ptr<IDeckLink> get_device(size_t device_index)
 {
-       CComPtr<IDeckLinkIterator> pDecklinkIterator;
-       if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink drivers not found."));
+    auto pDecklinkIterator = create_iterator();
                
        size_t n = 0;
-       CComPtr<IDeckLink> decklink;
-       while(n < device_index && pDecklinkIterator->Next(&decklink) == S_OK){++n;}     
+    com_ptr<IDeckLink> decklink;
+    IDeckLink* current = nullptr;
+    while(n < device_index && pDecklinkIterator->Next(&current) == S_OK)
+    {
+        ++n;
+        decklink = wrap_raw<com_ptr>(current);
+        current->Release();
+    }
 
        if(n != device_index || !decklink)
-               CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info("Decklink device not found.") << arg_name_info("device_index") << arg_value_info(boost::lexical_cast<std::string>(device_index)));
+               CASPAR_THROW_EXCEPTION(user_error() << msg_info("Decklink device " + boost::lexical_cast<std::string>(device_index) + " not found."));
                
        return decklink;
 }
@@ -173,9 +200,44 @@ static CComPtr<IDeckLink> get_device(size_t device_index)
 template <typename T>
 static std::wstring get_model_name(const T& device)
 {      
-       BSTR pModelName;
+    String pModelName;
        device->GetModelName(&pModelName);
-       return std::wstring(pModelName);
+    return u16(pModelName);
 }
 
-}}
\ No newline at end of file
+class reference_signal_detector
+{
+       com_iface_ptr<IDeckLinkOutput>  output_;
+       BMDReferenceStatus                              last_reference_status_  = static_cast<BMDReferenceStatus>(-1);
+public:
+       reference_signal_detector(const com_iface_ptr<IDeckLinkOutput>& output)
+               : output_(output)
+       {
+       }
+
+       template<typename Print>
+       void detect_change(const Print& print)
+       {
+               BMDReferenceStatus reference_status;
+
+               if (output_->GetReferenceStatus(&reference_status) != S_OK)
+               {
+                       CASPAR_LOG(error) << print() << L" Reference signal: failed while querying status";
+               }
+               else if (reference_status != last_reference_status_)
+               {
+                       last_reference_status_ = reference_status;
+
+                       if (reference_status == 0)
+                               CASPAR_LOG(info) << print() << L" Reference signal: not detected.";
+                       else if (reference_status & bmdReferenceNotSupportedByHardware)
+                               CASPAR_LOG(info) << print() << L" Reference signal: not supported by hardware.";
+                       else if (reference_status & bmdReferenceLocked)
+                               CASPAR_LOG(info) << print() << L" Reference signal: locked.";
+                       else
+                               CASPAR_LOG(info) << print() << L" Reference signal: Unhandled enum bitfield: " << reference_status;
+               }
+       }
+};
+
+}}