]> git.sesse.net Git - casparcg/blobdiff - modules/decklink/consumer/decklink_consumer.cpp
Only memcpy on Linux if the decklink card will attempt DMA directly from BGRA buffer...
[casparcg] / modules / decklink / consumer / decklink_consumer.cpp
index 2031d19d675afdb00cbac41b76d739c5c06c83f4..c8492e6538af9899db059ae9b0cf0d2d53ae65d6 100644 (file)
@@ -40,6 +40,8 @@
 #include <common/diagnostics/graph.h>
 #include <common/except.h>
 #include <common/memshfl.h>
+#include <common/memcpy.h>
+#include <common/no_init_proxy.h>
 #include <common/array.h>
 #include <common/future.h>
 #include <common/cache_aligned_vector.h>
@@ -168,19 +170,28 @@ void set_keyer(
 
 class decklink_frame : public IDeckLinkVideoFrame
 {
-       tbb::atomic<int>                                ref_count_;
-       core::const_frame                               frame_;
-       const core::video_format_desc   format_desc_;
+       tbb::atomic<int>                                                                ref_count_;
+       core::const_frame                                                               frame_;
+       const core::video_format_desc                                   format_desc_;
 
-       const bool                                              key_only_;
-       cache_aligned_vector<uint8_t>   data_;
+       const bool                                                                              key_only_;
+       bool                                                                                    needs_to_copy_;
+       cache_aligned_vector<no_init_proxy<uint8_t>>    data_;
 public:
-       decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only)
+       decklink_frame(core::const_frame frame, const core::video_format_desc& format_desc, bool key_only, bool will_attempt_dma)
                : frame_(frame)
                , format_desc_(format_desc)
                , key_only_(key_only)
        {
                ref_count_ = 0;
+
+#if !defined(_MSC_VER)
+               // On Linux Decklink cannot DMA transfer from memory returned by glMapBuffer
+               needs_to_copy_ = will_attempt_dma;
+#else
+               // On Windows it does
+               needs_to_copy_ = false;
+#endif
        }
        
        // IUnknown
@@ -216,7 +227,7 @@ public:
                {
                        if(static_cast<int>(frame_.image_data().size()) != format_desc_.size)
                        {
-                               data_.resize(format_desc_.size, 0);
+                               data_.resize(format_desc_.size);
                                *buffer = data_.data();
                        }
                        else if(key_only_)
@@ -229,7 +240,16 @@ public:
                                *buffer = data_.data();
                        }
                        else
+                       {
                                *buffer = const_cast<uint8_t*>(frame_.image_data().begin());
+
+                               if (needs_to_copy_)
+                               {
+                                       data_.resize(frame_.image_data().size());
+                                       fast_memcpy(data_.data(), *buffer, frame_.image_data().size());
+                                       *buffer = data_.data();
+                               }
+                       }
                }
                catch(...)
                {
@@ -343,6 +363,7 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink
        tbb::atomic<bool>                                                                       is_running_;
                
        const std::wstring                                                                      model_name_                             = get_model_name(decklink_);
+       bool                                                                                            will_attempt_dma_;
        const core::video_format_desc                                           format_desc_;
        const core::audio_channel_layout                                        in_channel_layout_;
        const core::audio_channel_layout                                        out_channel_layout_             = config_.get_adjusted_layout(in_channel_layout_);
@@ -407,7 +428,7 @@ public:
                graph_->set_text(print());
                diagnostics::register_graph(graph_);
                
-               enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault));
+               enable_video(get_display_mode(output_, format_desc_.format, bmdFormat8BitBGRA, bmdVideoOutputFlagDefault, will_attempt_dma_));
                                
                if(config.embedded_audio)
                        enable_audio();
@@ -600,12 +621,12 @@ public:
        {
                if (key_context_)
                {
-                       auto key_frame = wrap_raw<com_ptr, IDeckLinkVideoFrame>(new decklink_frame(frame, format_desc_, true));
+                       auto key_frame = wrap_raw<com_ptr, IDeckLinkVideoFrame>(new decklink_frame(frame, format_desc_, true, will_attempt_dma_));
                        if (FAILED(key_context_->output_->ScheduleVideoFrame(get_raw(key_frame), video_scheduled_, format_desc_.duration, format_desc_.time_scale)))
                                CASPAR_LOG(error) << print() << L" Failed to schedule key video.";
                }
 
-               auto fill_frame = wrap_raw<com_ptr, IDeckLinkVideoFrame>(new decklink_frame(frame, format_desc_, config_.key_only));
+               auto fill_frame = wrap_raw<com_ptr, IDeckLinkVideoFrame>(new decklink_frame(frame, format_desc_, config_.key_only, will_attempt_dma_));
                if (FAILED(output_->ScheduleVideoFrame(get_raw(fill_frame), video_scheduled_, format_desc_.duration, format_desc_.time_scale)))
                        CASPAR_LOG(error) << print() << L" Failed to schedule fill video.";