]> git.sesse.net Git - casparcg/blobdiff - modules/decklink/consumer/decklink_consumer.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[casparcg] / modules / decklink / consumer / decklink_consumer.cpp
index 9ead7d9bbf1ace07d8975cb2e7591d27ad60a771..d0949fd807a1ef4b43e5aa8650a32e0ca2ddd70c 100644 (file)
@@ -38,6 +38,7 @@
 #include <core/consumer/frame_consumer.h>\r
 \r
 #include <tbb/concurrent_queue.h>\r
+#include <tbb/cache_aligned_allocator.h>\r
 \r
 #include <boost/circular_buffer.hpp>\r
 #include <boost/timer.hpp>\r
@@ -64,29 +65,62 @@ struct configuration
 \r
 class decklink_frame : public IDeckLinkVideoFrame\r
 {\r
-       const safe_ptr<core::read_frame>        frame_;\r
-       const core::video_format_desc           format_desc_;\r
+       tbb::atomic<int>                                                                                        ref_count_;\r
+       std::shared_ptr<core::read_frame>                                                       frame_;\r
+       const core::video_format_desc                                                           format_desc_;\r
+\r
+       bool                                                                                                            key_only_;\r
+       std::vector<uint8_t, tbb::cache_aligned_allocator<uint8_t>> key_data_;\r
 public:\r
-       decklink_frame(const safe_ptr<core::read_frame>& frame, const core::video_format_desc& format_desc)\r
+       decklink_frame(const safe_ptr<core::read_frame>& frame, const core::video_format_desc& format_desc, bool key_only)\r
                : frame_(frame)\r
-               , format_desc_(format_desc){}\r
+               , format_desc_(format_desc)\r
+               , key_only_(key_only)\r
+       {\r
+               ref_count_ = 0;\r
+       }\r
        \r
-       STDMETHOD (QueryInterface(REFIID, LPVOID*))     {return E_NOINTERFACE;}\r
-       STDMETHOD_(ULONG, AddRef())                                     {return 1;}\r
-       STDMETHOD_(ULONG, Release())                            {return 1;}\r
+       STDMETHOD (QueryInterface(REFIID, LPVOID*))             {return E_NOINTERFACE;}\r
+       STDMETHOD_(ULONG,                       AddRef())                       \r
+       {\r
+               return ++ref_count_;\r
+       }\r
+       STDMETHOD_(ULONG,                       Release())                      \r
+       {\r
+               --ref_count_;\r
+               if(ref_count_ == 0)\r
+                       delete this;\r
+               return ref_count_;\r
+       }\r
 \r
-       STDMETHOD_(long, GetWidth())                            {return format_desc_.width;}        \r
-    STDMETHOD_(long, GetHeight())                              {return format_desc_.height;}        \r
-    STDMETHOD_(long, GetRowBytes())                            {return format_desc_.width*4;}        \r
-       STDMETHOD_(BMDPixelFormat, GetPixelFormat()){return bmdFormat8BitBGRA;}        \r
-    STDMETHOD_(BMDFrameFlags, GetFlags())              {return bmdFrameFlagDefault;}\r
+       STDMETHOD_(long,                        GetWidth())                     {return format_desc_.width;}        \r
+    STDMETHOD_(long,                   GetHeight())            {return format_desc_.height;}        \r
+    STDMETHOD_(long,                   GetRowBytes())          {return format_desc_.width*4;}        \r
+       STDMETHOD_(BMDPixelFormat,      GetPixelFormat())       {return bmdFormat8BitBGRA;}        \r
+    STDMETHOD_(BMDFrameFlags,  GetFlags())                     {return bmdFrameFlagDefault;}\r
         \r
     STDMETHOD(GetBytes(void** buffer))\r
        {\r
                static std::vector<uint8_t> zeros(1920*1080*4, 0);\r
-               *buffer = const_cast<uint8_t*>(frame_->image_data().begin());\r
                if(static_cast<size_t>(frame_->image_data().size()) != format_desc_.size)\r
+               {\r
                        *buffer = zeros.data();\r
+                       return S_OK;\r
+               }\r
+\r
+               if(!key_only_)\r
+                       *buffer = const_cast<uint8_t*>(frame_->image_data().begin());\r
+               else\r
+               {\r
+                       if(key_data_.empty())\r
+                       {\r
+                               key_data_.resize(frame_->image_data().size());\r
+                               fast_memshfl(key_data_.data(), frame_->image_data().begin(), frame_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+                               frame_.reset();\r
+                       }\r
+                       *buffer = key_data_.data();\r
+               }\r
+\r
                return S_OK;\r
        }\r
         \r
@@ -96,7 +130,7 @@ public:
 \r
 struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable\r
 {              \r
-       const configuration config_;\r
+       const configuration                                     config_;\r
 \r
        CComPtr<IDeckLink>                                      decklink_;\r
        CComQIPtr<IDeckLinkOutput>                      output_;\r
@@ -117,7 +151,6 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink
 \r
        size_t                                                          preroll_count_;\r
                \r
-       std::list<std::shared_ptr<IDeckLinkVideoFrame>> frame_container_; // Must be std::list in order to guarantee that pointers are always valid.\r
        boost::circular_buffer<std::vector<int16_t>>    audio_container_;\r
 \r
        tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> video_frame_buffer_;\r
@@ -169,8 +202,6 @@ public:
 \r
                if(!config.embedded_audio)\r
                        start_playback();\r
-                               \r
-               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
        }\r
 \r
        ~decklink_consumer()\r
@@ -286,11 +317,6 @@ public:
                        else if(result == bmdOutputFrameFlushed)\r
                                graph_->add_tag("flushed-frame");\r
 \r
-                       frame_container_.erase(std::find_if(frame_container_.begin(), frame_container_.end(), [&](const std::shared_ptr<IDeckLinkVideoFrame>& frame)\r
-                       {\r
-                               return frame.get() == completed_frame;\r
-                       }));\r
-\r
                        std::shared_ptr<core::read_frame> frame;        \r
                        video_frame_buffer_.pop(frame);                                 \r
                        schedule_next_video(make_safe(frame));  \r
@@ -351,8 +377,8 @@ public:
                        \r
        void schedule_next_video(const safe_ptr<core::read_frame>& frame)\r
        {\r
-               frame_container_.push_back(std::make_shared<decklink_frame>(frame, format_desc_));\r
-               if(FAILED(output_->ScheduleVideoFrame(frame_container_.back().get(), (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale)))\r
+               CComPtr<IDeckLinkVideoFrame> frame2(new decklink_frame(frame, format_desc_, config_.key_only));\r
+               if(FAILED(output_->ScheduleVideoFrame(frame2, (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale)))\r
                        CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
 \r
                graph_->update_value("tick-time", tick_timer_.elapsed()*format_desc_.fps*0.5);\r
@@ -395,11 +421,20 @@ public:
                , fail_count_(0)\r
        {\r
        }\r
+\r
+       ~decklink_consumer_proxy()\r
+       {\r
+               auto str = print();\r
+               context_.reset();\r
+               CASPAR_LOG(info) << str << L" Successfully Uninitialized.";     \r
+       }\r
        \r
        virtual void initialize(const core::video_format_desc& format_desc)\r
        {\r
                format_desc_ = format_desc;\r
-               context_.reset([&]{return new decklink_consumer(config_, format_desc_);});\r
+               context_.reset([&]{return new decklink_consumer(config_, format_desc_);});              \r
+                               \r
+               CASPAR_LOG(info) << print() << L" Successfully Initialized.";   \r
        }\r
        \r
        virtual bool send(const safe_ptr<core::read_frame>& frame)\r
@@ -427,14 +462,9 @@ public:
        \r
        virtual std::wstring print() const\r
        {\r
-               return context_->print();\r
-       }\r
-\r
-       virtual bool key_only() const\r
-       {\r
-               return config_.key_only;\r
+               return context_ ? context_->print() : L"decklink_consumer";\r
        }\r
-               \r
+                       \r
        virtual const core::video_format_desc& get_video_format_desc() const\r
        {\r
                return format_desc_;\r