#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
\r
class decklink_frame : public IDeckLinkVideoFrame\r
{\r
- const safe_ptr<core::read_frame> frame_;\r
- const core::video_format_desc format_desc_;\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
- STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;}\r
- STDMETHOD_(ULONG, AddRef()) {return 1;}\r
- STDMETHOD_(ULONG, Release()) {return 1;}\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 (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;}\r
+ STDMETHOD_(ULONG, AddRef()) {return 1;}\r
+ STDMETHOD_(ULONG, Release()) {return 1;}\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
\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
\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
\r
if(!config.embedded_audio)\r
start_playback();\r
- \r
- CASPAR_LOG(info) << print() << L" Successfully Initialized."; \r
}\r
\r
~decklink_consumer()\r
\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
+ frame_container_.push_back(std::make_shared<decklink_frame>(frame, format_desc_, config_.key_only));\r
if(FAILED(output_->ScheduleVideoFrame(frame_container_.back().get(), (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale)))\r
CASPAR_LOG(error) << print() << L" Failed to schedule video.";\r
\r
, 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
\r
virtual std::wstring print() const\r
{\r
- return context_->print();\r
+ return context_ ? context_->print() : L"decklink_consumer";\r
}\r
\r
virtual bool key_only() const\r