From ef45ae47b4f50ef057041b5122d0f34c1659cc11 Mon Sep 17 00:00:00 2001 From: ronag Date: Fri, 26 Aug 2011 11:07:57 +0000 Subject: [PATCH] 2.0. Optimized key-only. git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@1293 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d --- common/memory/memshfl.h | 6 +- core/consumer/frame_consumer.h | 1 - core/consumer/output.cpp | 39 +------------ .../bluefish/consumer/bluefish_consumer.cpp | 25 +++++---- .../decklink/consumer/decklink_consumer.cpp | 52 +++++++++++------ modules/ogl/consumer/ogl_consumer.cpp | 56 +++++++++++++++---- shell/casparcg.config | 15 ++++- 7 files changed, 113 insertions(+), 81 deletions(-) diff --git a/common/memory/memshfl.h b/common/memory/memshfl.h index 32b6c0a42..d3babc062 100644 --- a/common/memory/memshfl.h +++ b/common/memory/memshfl.h @@ -29,7 +29,7 @@ namespace caspar { namespace internal { -static void* fast_memsfhl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4) +static void* fast_memshfl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4) { __m128i* dest128 = reinterpret_cast<__m128i*>(dest); const __m128i* source128 = reinterpret_cast(source); @@ -56,12 +56,12 @@ static void* fast_memsfhl(void* dest, const void* source, size_t count, int m1, } -static void* fast_memsfhl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4) +static void* fast_memshfl(void* dest, const void* source, size_t count, int m1, int m2, int m3, int m4) { tbb::affinity_partitioner ap; tbb::parallel_for(tbb::blocked_range(0, count/128), [&](const tbb::blocked_range& r) { - internal::fast_memsfhl(reinterpret_cast(dest) + r.begin()*128, reinterpret_cast(source) + r.begin()*128, r.size()*128, m1, m2, m3, m4); + internal::fast_memshfl(reinterpret_cast(dest) + r.begin()*128, reinterpret_cast(source) + r.begin()*128, r.size()*128, m1, m2, m3, m4); }, ap); return dest; diff --git a/core/consumer/frame_consumer.h b/core/consumer/frame_consumer.h index bbea02a3f..4e6fef732 100644 --- a/core/consumer/frame_consumer.h +++ b/core/consumer/frame_consumer.h @@ -41,7 +41,6 @@ struct frame_consumer : boost::noncopyable virtual ~frame_consumer() {} virtual bool send(const safe_ptr& frame) = 0; - virtual bool key_only() const{ return false;} virtual void initialize(const video_format_desc& format_desc) = 0; virtual std::wstring print() const = 0; virtual bool has_synchronization_clock() const {return true;} diff --git a/core/consumer/output.cpp b/core/consumer/output.cpp index fce751112..dde9c009a 100644 --- a/core/consumer/output.cpp +++ b/core/consumer/output.cpp @@ -41,38 +41,6 @@ namespace caspar { namespace core { -class deferred_key_read_Frame : public core::read_frame -{ - ogl_device& ogl_; - safe_ptr fill_; - std::shared_ptr key_; - tbb::mutex mutex_; -public: - deferred_key_read_Frame(ogl_device& ogl, const safe_ptr& fill) - : ogl_(ogl) - , fill_(fill) - { - } - - virtual const boost::iterator_range image_data() - { - tbb::mutex::scoped_lock lock(mutex_); - if(!key_) - { - key_ = ogl_.create_host_buffer(fill_->image_data().size(), host_buffer::write_only); - fast_memsfhl(key_->data(), fill_->image_data().begin(), fill_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); - } - - auto ptr = static_cast(key_->data()); - return boost::iterator_range(ptr, ptr + key_->size()); - } - - virtual const boost::iterator_range audio_data() - { - return fill_->audio_data(); - } -}; - struct output::implementation { typedef std::pair, safe_ptr> fill_and_key; @@ -128,10 +96,7 @@ public: timer_.tick(1.0/channel_.get_format_desc().fps); return; } - - auto fill = frame; - auto key = make_safe(channel_.ogl(), frame); - + auto it = consumers_.begin(); while(it != consumers_.end()) { @@ -140,7 +105,7 @@ public: if(consumer->get_video_format_desc() != channel_.get_format_desc()) consumer->initialize(channel_.get_format_desc()); - if(consumer->send(consumer->key_only() ? key : fill)) + if(consumer->send(frame)) ++it; else consumers_.erase(it++); diff --git a/modules/bluefish/consumer/bluefish_consumer.cpp b/modules/bluefish/consumer/bluefish_consumer.cpp index 714d2e575..ab73cac35 100644 --- a/modules/bluefish/consumer/bluefish_consumer.cpp +++ b/modules/bluefish/consumer/bluefish_consumer.cpp @@ -28,8 +28,9 @@ #include #include -#include #include +#include +#include #include #include @@ -64,10 +65,11 @@ struct bluefish_consumer : boost::noncopyable int preroll_count_; const bool embedded_audio_; + const bool key_only_; executor executor_; public: - bluefish_consumer(const core::video_format_desc& format_desc, unsigned int device_index, bool embedded_audio) + bluefish_consumer(const core::video_format_desc& format_desc, unsigned int device_index, bool embedded_audio, bool key_only) : blue_(create_blue(device_index)) , device_index_(device_index) , format_desc_(format_desc) @@ -75,6 +77,7 @@ public: , vid_fmt_(get_video_mode(*blue_, format_desc)) , preroll_count_(0) , embedded_audio_(embedded_audio) + , key_only_(key_only) , executor_(print()) { executor_.set_capacity(core::consumer_buffer_depth()); @@ -218,10 +221,15 @@ public: // Copy to local buffers if(!frame->image_data().empty()) - fast_memcpy(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size()); + { + if(key_only_) + fast_memshfl(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); + else + fast_memcpy(reserved_frames_.front()->image_data(), frame->image_data().begin(), frame->image_data().size()); + } else fast_memclr(reserved_frames_.front()->image_data(), reserved_frames_.front()->image_size()); - + // Sync sync_timer_.restart(); @@ -325,13 +333,13 @@ public: virtual void initialize(const core::video_format_desc& format_desc) { format_desc_ = format_desc; - consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_)); + consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_, key_only_)); } virtual bool send(const safe_ptr& frame) { if(!consumer_) - consumer_.reset(new bluefish_consumer(format_desc_, device_index_, embedded_audio_)); + consumer_.reset(new bluefish_consumer(format_desc_, device_index_, embedded_audio_, key_only_)); try { @@ -363,11 +371,6 @@ public: return L"bluefish [" + boost::lexical_cast(device_index_) + L"]"; } - - virtual bool key_only() const - { - return key_only_; - } }; safe_ptr create_bluefish_consumer(const std::vector& params) diff --git a/modules/decklink/consumer/decklink_consumer.cpp b/modules/decklink/consumer/decklink_consumer.cpp index 601d87517..7699f7fd8 100644 --- a/modules/decklink/consumer/decklink_consumer.cpp +++ b/modules/decklink/consumer/decklink_consumer.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -64,29 +65,48 @@ struct configuration class decklink_frame : public IDeckLinkVideoFrame { - const safe_ptr frame_; - const core::video_format_desc format_desc_; + const std::shared_ptr frame_; + const core::video_format_desc format_desc_; + + bool key_only_; + std::vector> key_data_; public: - decklink_frame(const safe_ptr& frame, const core::video_format_desc& format_desc) + decklink_frame(const safe_ptr& frame, const core::video_format_desc& format_desc, bool key_only) : frame_(frame) - , format_desc_(format_desc){} + , format_desc_(format_desc) + , key_only_(key_only){} - STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;} - STDMETHOD_(ULONG, AddRef()) {return 1;} - STDMETHOD_(ULONG, Release()) {return 1;} - - STDMETHOD_(long, GetWidth()) {return format_desc_.width;} - STDMETHOD_(long, GetHeight()) {return format_desc_.height;} - STDMETHOD_(long, GetRowBytes()) {return format_desc_.width*4;} - STDMETHOD_(BMDPixelFormat, GetPixelFormat()){return bmdFormat8BitBGRA;} - STDMETHOD_(BMDFrameFlags, GetFlags()) {return bmdFrameFlagDefault;} + STDMETHOD (QueryInterface(REFIID, LPVOID*)) {return E_NOINTERFACE;} + STDMETHOD_(ULONG, AddRef()) {return 1;} + STDMETHOD_(ULONG, Release()) {return 1;} + + STDMETHOD_(long, GetWidth()) {return format_desc_.width;} + STDMETHOD_(long, GetHeight()) {return format_desc_.height;} + STDMETHOD_(long, GetRowBytes()) {return format_desc_.width*4;} + STDMETHOD_(BMDPixelFormat, GetPixelFormat()) {return bmdFormat8BitBGRA;} + STDMETHOD_(BMDFrameFlags, GetFlags()) {return bmdFrameFlagDefault;} STDMETHOD(GetBytes(void** buffer)) { static std::vector zeros(1920*1080*4, 0); - *buffer = const_cast(frame_->image_data().begin()); if(static_cast(frame_->image_data().size()) != format_desc_.size) + { *buffer = zeros.data(); + return S_OK; + } + + if(!key_only_) + *buffer = const_cast(frame_->image_data().begin()); + else + { + if(key_data_.empty()) + { + key_data_.resize(frame_->image_data().size()); + fast_memshfl(key_data_.data(), frame_->image_data().begin(), frame_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); + } + *buffer = key_data_.data(); + } + return S_OK; } @@ -96,7 +116,7 @@ public: struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLinkAudioOutputCallback, boost::noncopyable { - const configuration config_; + const configuration config_; CComPtr decklink_; CComQIPtr output_; @@ -349,7 +369,7 @@ public: void schedule_next_video(const safe_ptr& frame) { - frame_container_.push_back(std::make_shared(frame, format_desc_)); + frame_container_.push_back(std::make_shared(frame, format_desc_, config_.key_only)); if(FAILED(output_->ScheduleVideoFrame(frame_container_.back().get(), (frames_scheduled_++) * format_desc_.duration, format_desc_.duration, format_desc_.time_scale))) CASPAR_LOG(error) << print() << L" Failed to schedule video."; diff --git a/modules/ogl/consumer/ogl_consumer.cpp b/modules/ogl/consumer/ogl_consumer.cpp index 76c06055c..4cdfa93fe 100644 --- a/modules/ogl/consumer/ogl_consumer.cpp +++ b/modules/ogl/consumer/ogl_consumer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,7 @@ #include #include -#include +#include namespace caspar { @@ -61,6 +62,7 @@ struct ogl_consumer : boost::noncopyable core::video_format_desc format_desc_; GLuint texture_; + std::vector pbos_; float width_; float height_; @@ -87,10 +89,13 @@ struct ogl_consumer : boost::noncopyable boost::thread thread_; tbb::atomic is_running_; + + const bool key_only_; public: - ogl_consumer(unsigned int screen_index, stretch stretch, bool windowed, const core::video_format_desc& format_desc) + ogl_consumer(unsigned int screen_index, stretch stretch, bool windowed, const core::video_format_desc& format_desc, bool key_only) : format_desc_(format_desc) , texture_(0) + , pbos_(2, 0) , stretch_(stretch) , windowed_(windowed) , screen_index_(screen_index) @@ -100,6 +105,7 @@ public: , square_height_(format_desc.height) , graph_(diagnostics::create_graph(narrow(print()))) , input_buffer_(core::consumer_buffer_depth()-1) + , key_only_(key_only) { frame_buffer_.set_capacity(2); @@ -181,7 +187,15 @@ public: GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)); GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, format_desc_.width, format_desc_.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0)); GL(glBindTexture(GL_TEXTURE_2D, 0)); + + GL(glGenBuffers(2, pbos_.data())); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[0]); + glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbos_[1]); + glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, format_desc_.size, 0, GL_STREAM_DRAW_ARB); + glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + CASPAR_LOG(info) << print() << " Sucessfully Initialized."; } @@ -190,6 +204,12 @@ public: if(texture_) glDeleteTextures(1, &texture_); + BOOST_FOREACH(auto& pbo, pbos_) + { + if(pbo) + glDeleteBuffers(1, &pbo); + } + CASPAR_LOG(info) << print() << " Sucessfully Uninitialized."; } @@ -245,10 +265,27 @@ public: if(frame->image_data().empty()) return; - GL(glBindTexture(GL_TEXTURE_2D, texture_)); + glBindTexture(GL_TEXTURE_2D, texture_); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, 0); - GL(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, format_desc_.width, format_desc_.height, GL_BGRA, GL_UNSIGNED_BYTE, frame->image_data().begin())); - + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbos_[1]); + glBufferData(GL_PIXEL_UNPACK_BUFFER, format_desc_.size, 0, GL_STREAM_DRAW); + + auto ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if(ptr) + { + if(key_only_) + fast_memshfl(reinterpret_cast(ptr), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303); + else + fast_memcpy(reinterpret_cast(ptr), frame->image_data().begin(), frame->image_data().size()); + + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // release the mapped buffer + } + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + GL(glClear(GL_COLOR_BUFFER_BIT)); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1.0f); glVertex2f(-width_, -height_); @@ -258,6 +295,8 @@ public: glEnd(); glBindTexture(GL_TEXTURE_2D, 0); + + std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end()); } void send(const safe_ptr& frame) @@ -353,7 +392,7 @@ public: virtual void initialize(const core::video_format_desc& format_desc) { - consumer_.reset(new ogl_consumer(screen_index_, stretch_, windowed_, format_desc)); + consumer_.reset(new ogl_consumer(screen_index_, stretch_, windowed_, format_desc, key_only_)); } virtual bool send(const safe_ptr& frame) @@ -367,11 +406,6 @@ public: return consumer_->print(); } - virtual bool key_only() const - { - return key_only_; - } - virtual bool has_synchronization_clock() const { return false; diff --git a/shell/casparcg.config b/shell/casparcg.config index ecff4f7af..5730f9b0f 100644 --- a/shell/casparcg.config +++ b/shell/casparcg.config @@ -33,19 +33,30 @@ - PAL + 1080p5000 1 true true + true - true 1 + true + + 1080p5000 + + + 2 + true + true + + + -- 2.39.2