]> git.sesse.net Git - casparcg/commitdiff
2.0. Reduced frame latency by 3 frames.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 22 Jun 2011 08:56:03 +0000 (08:56 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Wed, 22 Jun 2011 08:56:03 +0000 (08:56 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@938 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

13 files changed:
core/consumer/frame_consumer.h
core/consumer/output.cpp
core/mixer/image/image_mixer.cpp
core/mixer/mixer.cpp
core/mixer/read_frame.cpp
core/mixer/read_frame.h
modules/bluefish/consumer/bluefish_consumer.cpp
modules/decklink/consumer/decklink_consumer.cpp
modules/ffmpeg/consumer/ffmpeg_consumer.cpp
modules/flash/producer/flash_producer.cpp
modules/oal/consumer/oal_consumer.cpp
modules/oal/consumer/oal_consumer.h
modules/ogl/consumer/ogl_consumer.cpp

index 1a8c19bbd43d8d65fd7f146fa9d426f078f42a8c..04b30821b2be0a83ec2c9b6090c14a81f8ab4ef5 100644 (file)
@@ -29,7 +29,7 @@
 #include <string>\r
 #include <vector>\r
 \r
-static const size_t CONSUMER_BUFFER_DEPTH = 7;\r
+static const size_t CONSUMER_BUFFER_DEPTH = 6;\r
 \r
 namespace caspar { namespace core {\r
        \r
@@ -40,7 +40,7 @@ struct frame_consumer : boost::noncopyable
 {\r
        virtual ~frame_consumer() {}\r
        \r
-       virtual void send(const safe_ptr<const read_frame>& frame) = 0;\r
+       virtual void send(const safe_ptr<read_frame>& frame) = 0;\r
        virtual size_t buffer_depth() const {return 1;}\r
        virtual bool key_only() const{ return false;}\r
        virtual void initialize(const video_format_desc& format_desc) = 0;\r
@@ -53,7 +53,7 @@ struct frame_consumer : boost::noncopyable
                struct empty_frame_consumer : public frame_consumer\r
                {\r
                        core::video_format_desc format_desc;\r
-                       virtual void send(const safe_ptr<const read_frame>&){}\r
+                       virtual void send(const safe_ptr<read_frame>&){}\r
                        virtual size_t buffer_depth() const{return 0;}\r
                        virtual void initialize(const video_format_desc&){}\r
                        virtual std::wstring print() const {return L"empty";}\r
index b68de7c48590414cceaffcf127fea28b21b018f3..44774d42a3cc3776f22e671a93ffced955576129 100644 (file)
 #include <common/utility/timer.h>\r
 #include <common/memory/memshfl.h>\r
 \r
+#include <tbb/mutex.h>\r
+\r
 namespace caspar { namespace core {\r
+\r
+class key_read_frame_adapter : public core::read_frame\r
+{\r
+       ogl_device&                                              ogl_;\r
+       safe_ptr<read_frame>                     fill_;\r
+       std::shared_ptr<host_buffer>     key_;\r
+       tbb::mutex                                           mutex_;\r
+public:\r
+       key_read_frame_adapter(ogl_device& ogl, const safe_ptr<read_frame>& fill)\r
+               : ogl_(ogl)\r
+               , fill_(fill)\r
+       {\r
+       }\r
+\r
+       virtual const boost::iterator_range<const uint8_t*> image_data()\r
+       {\r
+               tbb::mutex::scoped_lock lock(mutex_);\r
+               if(!key_)\r
+               {\r
+                       key_ = ogl_.create_host_buffer(fill_->image_data().size(), host_buffer::write_only);                            \r
+                       fast_memsfhl(key_->data(), fill_->image_data().begin(), fill_->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
+               }\r
+\r
+               auto ptr = static_cast<const uint8_t*>(key_->data());\r
+               return boost::iterator_range<const uint8_t*>(ptr, ptr + key_->size());\r
+       }\r
+\r
+       virtual const boost::iterator_range<const int16_t*> audio_data()\r
+       {\r
+               return fill_->audio_data();\r
+       }       \r
+};\r
        \r
 struct output::implementation\r
 {      \r
-       typedef std::pair<safe_ptr<const read_frame>, safe_ptr<const read_frame>> fill_and_key;\r
+       typedef std::pair<safe_ptr<read_frame>, safe_ptr<read_frame>> fill_and_key;\r
        \r
        video_channel_context& channel_;\r
 \r
@@ -86,7 +120,7 @@ public:
                                timer_.tick(1.0/channel_.get_format_desc().fps);\r
                                                \r
                        auto fill = frame;\r
-                       auto key = get_key_frame(frame);\r
+                       auto key = make_safe<key_read_frame_adapter>(channel_.ogl(), frame);\r
 \r
                        auto it = consumers_.begin();\r
                        while(it != consumers_.end())\r
@@ -128,25 +162,6 @@ private:
                        return p.second->has_synchronization_clock();\r
                });\r
        }\r
-\r
-       safe_ptr<const read_frame> get_key_frame(const safe_ptr<const read_frame>& frame)\r
-       {\r
-               const bool has_key_only = std::any_of(consumers_.begin(), consumers_.end(), [](const decltype(*consumers_.begin())& p)\r
-               {\r
-                       return p.second->key_only();\r
-               });\r
-\r
-               if(has_key_only)\r
-               {\r
-                       // Currently do key_only transform on cpu. Unsure if the extra 400MB/s (1080p50) overhead is worth it to do it on gpu.\r
-                       auto key_data = channel_.ogl().create_host_buffer(frame->image_data().size(), host_buffer::write_only);                         \r
-                       fast_memsfhl(key_data->data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                       std::vector<int16_t> audio_data(frame->audio_data().begin(), frame->audio_data().end());\r
-                       return make_safe<read_frame>(std::move(key_data), std::move(audio_data));\r
-               }\r
-               \r
-               return make_safe<read_frame>();\r
-       }\r
        \r
        std::wstring print() const\r
        {\r
index 7abac7769c790b88413d443b019a0e0a2850429e..5f9ace0c9748d80f768bfa6a7e2f12813173e8fb 100644 (file)
@@ -64,7 +64,6 @@ struct image_mixer::implementation : boost::noncopyable
        \r
        image_kernel                                                    kernel_;\r
                \r
-       safe_ptr<host_buffer>                                   read_buffer_;\r
        safe_ptr<device_buffer>                                 draw_buffer_;\r
        safe_ptr<device_buffer>                                 write_buffer_;\r
 \r
@@ -77,7 +76,6 @@ struct image_mixer::implementation : boost::noncopyable
 public:\r
        implementation(video_channel_context& video_channel) \r
                : channel_(video_channel)\r
-               , read_buffer_(video_channel.ogl().create_host_buffer(video_channel.get_format_desc().size, host_buffer::read_only))\r
                , draw_buffer_(video_channel.ogl().create_device_buffer(video_channel.get_format_desc().width, channel_.get_format_desc().height, 4))\r
                , write_buffer_ (video_channel.ogl().create_device_buffer(video_channel.get_format_desc().width, channel_.get_format_desc().height, 4))\r
                , local_key_buffer_(video_channel.ogl().create_device_buffer(video_channel.get_format_desc().width, channel_.get_format_desc().height, 1))\r
@@ -121,7 +119,6 @@ public:
 \r
        void reinitialize_buffers()\r
        {\r
-               read_buffer_      = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only);\r
                draw_buffer_      = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
                write_buffer_     = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 4);\r
                local_key_buffer_ = channel_.ogl().create_device_buffer(channel_.get_format_desc().width, channel_.get_format_desc().height, 1);\r
@@ -131,16 +128,11 @@ public:
 \r
        safe_ptr<host_buffer> render()\r
        {               \r
-               auto read_buffer = read_buffer_;\r
-               auto result = channel_.ogl().begin_invoke([=]()  -> safe_ptr<host_buffer>\r
-               {\r
-                       read_buffer->map();\r
-                       return read_buffer;\r
-               });\r
+               auto read_buffer = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only);          \r
 \r
                auto render_queue = std::move(render_queue_);\r
 \r
-               channel_.ogl().begin_invoke([=]() mutable\r
+               channel_.ogl().invoke([=]() mutable\r
                {\r
                        if(draw_buffer_->width() != channel_.get_format_desc().width || draw_buffer_->height() != channel_.get_format_desc().height)\r
                                reinitialize_buffers();\r
@@ -186,12 +178,11 @@ public:
 \r
                        std::swap(draw_buffer_, write_buffer_);\r
 \r
-                       // Start transfer from device to host.  \r
-                       read_buffer_ = channel_.ogl().create_host_buffer(channel_.get_format_desc().size, host_buffer::read_only);                                      \r
-                       write_buffer_->write(*read_buffer_);\r
+                       // Start transfer from device to host.                          \r
+                       write_buffer_->write(*read_buffer);\r
                });\r
 \r
-               return std::move(result.get());\r
+               return read_buffer;\r
        }\r
        \r
        void draw(const std::vector<render_item>& stream)\r
index 749bf040e9612aca8ee92344d7ae2e589e94e0d5..6ab208031252dbf979560268b7dc22a867b8a897 100644 (file)
@@ -113,7 +113,7 @@ public:
                        auto image = mix_image(frames);\r
                        auto audio = mix_audio(frames);\r
                        \r
-                       return make_safe<read_frame>(std::move(image), std::move(audio));\r
+                       return make_safe<read_frame>(channel_.ogl(), std::move(image), std::move(audio));\r
                }\r
                catch(...)\r
                {\r
index d588155a511054f88f025a0659b076d4c5d7b156..59846af825fecbce8121f5cff514d76cf44a2f5a 100644 (file)
@@ -28,37 +28,44 @@ namespace caspar { namespace core {
                                                                                                                                                                                                                                                                                                                        \r
 struct read_frame::implementation : boost::noncopyable\r
 {\r
-       std::shared_ptr<host_buffer> image_data_;\r
-       std::vector<int16_t> audio_data_;\r
+       ogl_device&                                             ogl_;\r
+       safe_ptr<host_buffer>                   image_data_;\r
+       std::vector<int16_t>                    audio_data_;\r
 \r
 public:\r
-       implementation(safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data) \r
-               : image_data_(std::move(image_data))\r
+       implementation(ogl_device& ogl, safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data) \r
+               : ogl_(ogl)\r
+               , image_data_(std::move(image_data))\r
                , audio_data_(std::move(audio_data)){}  \r
        \r
        const boost::iterator_range<const uint8_t*> image_data()\r
        {\r
-               if(!image_data_)\r
-                       return boost::iterator_range<const uint8_t*>();\r
+               if(!image_data_->data())\r
+               {\r
+                       ogl_.invoke([=]\r
+                       {\r
+                               image_data_->map();\r
+                       }, high_priority);\r
+               }\r
 \r
                auto ptr = static_cast<const uint8_t*>(image_data_->data());\r
                return boost::iterator_range<const uint8_t*>(ptr, ptr + image_data_->size());\r
        }\r
-       const boost::iterator_range<const int16_t*> audio_data() const\r
+       const boost::iterator_range<const int16_t*> audio_data()\r
        {\r
                return boost::iterator_range<const int16_t*>(audio_data_.data(), audio_data_.data() + audio_data_.size());\r
        }\r
 };\r
 \r
-read_frame::read_frame(safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data) \r
-       : impl_(new implementation(std::move(image_data), std::move(audio_data))){}\r
+read_frame::read_frame(ogl_device& ogl, safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data) \r
+       : impl_(new implementation(ogl, std::move(image_data), std::move(audio_data))){}\r
 read_frame::read_frame(){}\r
-const boost::iterator_range<const uint8_t*> read_frame::image_data() const\r
+const boost::iterator_range<const uint8_t*> read_frame::image_data()\r
 {\r
        return impl_ ? impl_->image_data() : boost::iterator_range<const uint8_t*>();\r
 }\r
 \r
-const boost::iterator_range<const int16_t*> read_frame::audio_data() const\r
+const boost::iterator_range<const int16_t*> read_frame::audio_data()\r
 {\r
        return impl_ ? impl_->audio_data() : boost::iterator_range<const int16_t*>();\r
 }\r
index 70fffdc14c878462e07489eea283da22082b328e..35ae10432fad495e5a997b8318fd722b734dd62f 100644 (file)
@@ -37,10 +37,10 @@ class read_frame : boost::noncopyable
 {\r
 public:\r
        read_frame();\r
-       read_frame(safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data);\r
+       read_frame(ogl_device& ogl, safe_ptr<host_buffer>&& image_data, std::vector<int16_t>&& audio_data);\r
 \r
-       virtual const boost::iterator_range<const uint8_t*> image_data() const;\r
-       virtual const boost::iterator_range<const int16_t*> audio_data() const;\r
+       virtual const boost::iterator_range<const uint8_t*> image_data();\r
+       virtual const boost::iterator_range<const int16_t*> audio_data();\r
                \r
 private:\r
        struct implementation;\r
index ca87f509249c48a46248e50149ea499e0ab65643..bd1e0063f65211e85f781596e6a5fc12970dcd14 100644 (file)
@@ -57,7 +57,7 @@ struct bluefish_consumer : boost::noncopyable
        unsigned int                                            vid_fmt_;\r
 \r
        std::array<blue_dma_buffer_ptr, 4>      reserved_frames_;       \r
-       tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> frame_buffer_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> frame_buffer_;\r
 \r
        int                                                                     preroll_count_;\r
 \r
@@ -189,7 +189,7 @@ public:
                        CASPAR_LOG(error)<< print() << TEXT(" Failed to disable video output.");                \r
        }\r
        \r
-       void send(const safe_ptr<const core::read_frame>& frame)\r
+       void send(const safe_ptr<core::read_frame>& frame)\r
        {       \r
                if(preroll_count_ < executor_.capacity())\r
                {\r
@@ -200,7 +200,7 @@ public:
                schedule_next_video(frame);                     \r
        }\r
        \r
-       void schedule_next_video(const safe_ptr<const core::read_frame>& frame)\r
+       void schedule_next_video(const safe_ptr<core::read_frame>& frame)\r
        {\r
                static std::vector<int16_t> silence(MAX_HANC_BUFFER_SIZE, 0);\r
                \r
@@ -321,7 +321,7 @@ public:
                consumer_.reset(new bluefish_consumer(format_desc, device_index_, embedded_audio_));\r
        }\r
        \r
-       virtual void send(const safe_ptr<const core::read_frame>& frame)\r
+       virtual void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                consumer_->send(frame);\r
        }\r
index b394544f19fada43f267d86668071000c4acb4fe..965bde2627fb8d3b12e7f14242d5b3b4e61811a2 100644 (file)
@@ -62,10 +62,10 @@ struct configuration
 \r
 class decklink_frame_adapter : public IDeckLinkVideoFrame\r
 {\r
-       const safe_ptr<const core::read_frame>  frame_;\r
+       const safe_ptr<core::read_frame>        frame_;\r
        const core::video_format_desc                   format_desc_;\r
 public:\r
-       decklink_frame_adapter(const safe_ptr<const core::read_frame>& frame, const core::video_format_desc& format_desc)\r
+       decklink_frame_adapter(const safe_ptr<core::read_frame>& frame, const core::video_format_desc& format_desc)\r
                : frame_(frame)\r
                , format_desc_(format_desc){}\r
        \r
@@ -117,8 +117,8 @@ struct decklink_consumer : public IDeckLinkVideoOutputCallback, public IDeckLink
        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<short>> audio_container_;\r
 \r
-       tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> video_frame_buffer_;\r
-       tbb::concurrent_bounded_queue<std::shared_ptr<const core::read_frame>> audio_frame_buffer_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> video_frame_buffer_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<core::read_frame>> audio_frame_buffer_;\r
        \r
        std::shared_ptr<diagnostics::graph> graph_;\r
        boost::timer tick_timer_;\r
@@ -288,7 +288,7 @@ public:
                                return frame.get() == completed_frame;\r
                        }));\r
 \r
-                       std::shared_ptr<const core::read_frame> frame;  \r
+                       std::shared_ptr<core::read_frame> frame;        \r
                        video_frame_buffer_.pop(frame);                                 \r
                        schedule_next_video(make_safe(frame));                  \r
                }\r
@@ -320,7 +320,7 @@ public:
                        }\r
                        else\r
                        {\r
-                               std::shared_ptr<const core::read_frame> frame;\r
+                               std::shared_ptr<core::read_frame> frame;\r
                                audio_frame_buffer_.pop(frame);\r
                                schedule_next_audio(make_safe(frame));  \r
                        }\r
@@ -334,7 +334,7 @@ public:
                return S_OK;\r
        }\r
 \r
-       void schedule_next_audio(const safe_ptr<const core::read_frame>& frame)\r
+       void schedule_next_audio(const safe_ptr<core::read_frame>& frame)\r
        {\r
                static std::vector<short> silence(48000, 0);\r
                \r
@@ -348,7 +348,7 @@ public:
                        CASPAR_LOG(error) << print() << L" Failed to schedule audio.";\r
        }\r
                        \r
-       void schedule_next_video(const safe_ptr<const core::read_frame>& frame)\r
+       void schedule_next_video(const safe_ptr<core::read_frame>& frame)\r
        {\r
                frame_container_.push_back(std::make_shared<decklink_frame_adapter>(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
@@ -358,7 +358,7 @@ public:
                tick_timer_.restart();\r
        }\r
 \r
-       void send(const safe_ptr<const core::read_frame>& frame)\r
+       void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                if(exception_ != nullptr)\r
                        std::rethrow_exception(exception_);\r
@@ -393,7 +393,7 @@ public:
                context_.reset([&]{return new decklink_consumer(config_, format_desc);});\r
        }\r
        \r
-       virtual void send(const safe_ptr<const core::read_frame>& frame)\r
+       virtual void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                context_->send(frame);\r
        }\r
index e19515756a6e2acea2d0b3fb22b2af81ff3b0314..4a490c964daf39fda0e220e32a96ca1cc6bed7b2 100644 (file)
@@ -266,7 +266,7 @@ public:
                }\r
        }\r
   \r
-       void encode_video_frame(const safe_ptr<const core::read_frame>& frame)\r
+       void encode_video_frame(const safe_ptr<core::read_frame>& frame)\r
        { \r
                if(!video_st_)\r
                        return;\r
@@ -321,7 +321,7 @@ public:
                }               \r
        }\r
                \r
-       void encode_audio_frame(const safe_ptr<const core::read_frame>& frame)\r
+       void encode_audio_frame(const safe_ptr<core::read_frame>& frame)\r
        {       \r
                if(!audio_st_)\r
                        return;\r
@@ -372,7 +372,7 @@ public:
                return true;\r
        }\r
         \r
-       void send(const safe_ptr<const core::read_frame>& frame)\r
+       void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                executor_.begin_invoke([=]\r
                {                               \r
@@ -404,7 +404,7 @@ public:
                consumer_.reset(new ffmpeg_consumer(narrow(filename_), format_desc, bitrate_));\r
        }\r
        \r
-       virtual void send(const safe_ptr<const core::read_frame>& frame)\r
+       virtual void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                consumer_->send(frame);\r
        }\r
index e0ee5f3863ed4c6d34e7d613fe3e2e1a7e02feb5..75fca1989dc9e3aa7c05ba2efbdab851e504c1e1 100644 (file)
@@ -240,7 +240,7 @@ public:
                graph_ = diagnostics::create_graph([this]{return print();});\r
                graph_->set_color("output-buffer", diagnostics::color(0.0f, 1.0f, 0.0f));\r
                \r
-               frame_buffer_.set_capacity(2);\r
+               frame_buffer_.set_capacity(1);\r
 \r
                initialize();                           \r
        }\r
index cbd7a73acf1b29752254c079c54f9b99829f340a..9b60f725be5a94615b44630eeedeafcf3dd8e0b3 100644 (file)
@@ -74,7 +74,7 @@ public:
                CASPAR_LOG(info) << print() << L" Shutting down.";      \r
        }\r
        \r
-       void send(const safe_ptr<const core::read_frame>& frame)\r
+       void send(const safe_ptr<core::read_frame>& frame)\r
        {                       \r
                if(preroll_count_ < input_.capacity())\r
                {\r
@@ -113,7 +113,7 @@ public:
 \r
 oal_consumer::oal_consumer(){}\r
 oal_consumer::oal_consumer(oal_consumer&& other) : impl_(std::move(other.impl_)){}\r
-void oal_consumer::send(const safe_ptr<const core::read_frame>& frame){impl_->send(frame);}\r
+void oal_consumer::send(const safe_ptr<core::read_frame>& frame){impl_->send(frame);}\r
 size_t oal_consumer::buffer_depth() const{return impl_->buffer_depth();}\r
 void oal_consumer::initialize(const core::video_format_desc& format_desc){impl_.reset(new implementation(format_desc));}\r
 std::wstring oal_consumer::print() const { return impl_->print(); }\r
index 77ad1a04883d449989b153a812d9e1e4a7b5b25a..efa6f38a6e7f919a9763c690fb07207c7407fed0 100644 (file)
@@ -34,7 +34,7 @@ public:
 \r
        // frame_consumer\r
        virtual void initialize(const core::video_format_desc& format_desc);    \r
-       virtual void send(const safe_ptr<const core::read_frame>&);\r
+       virtual void send(const safe_ptr<core::read_frame>&);\r
        virtual size_t buffer_depth() const;\r
        virtual std::wstring print() const;\r
        virtual const core::video_format_desc& get_video_format_desc() const;\r
index 487f5c7114bfbff53ffe919f6da8909c6eaacb27..c130b270125734e1248c75db8219f958f127da33 100644 (file)
@@ -76,7 +76,7 @@ struct ogl_consumer : boost::noncopyable
        size_t                                  square_width_;\r
        size_t                                  square_height_;\r
 \r
-       boost::circular_buffer<safe_ptr<const core::read_frame>> frame_buffer_;\r
+       boost::circular_buffer<safe_ptr<core::read_frame>> frame_buffer_;\r
 \r
        executor                                executor_;\r
 public:\r
@@ -241,7 +241,7 @@ public:
                return std::make_pair(width, height);\r
        }\r
 \r
-       void render(const safe_ptr<const core::read_frame>& frame)\r
+       void render(const safe_ptr<core::read_frame>& frame)\r
        {                       \r
                glBindTexture(GL_TEXTURE_2D, texture_);\r
 \r
@@ -273,7 +273,7 @@ public:
                std::rotate(pbos_.begin(), pbos_.begin() + 1, pbos_.end());\r
        }\r
 \r
-       void send(const safe_ptr<const core::read_frame>& frame)\r
+       void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                frame_buffer_.push_back(frame);\r
 \r
@@ -281,7 +281,7 @@ public:
                        do_send(frame_buffer_.front());\r
        }\r
                \r
-       void do_send(const safe_ptr<const core::read_frame>& frame)\r
+       void do_send(const safe_ptr<core::read_frame>& frame)\r
        {               \r
                executor_.try_begin_invoke([=]\r
                {\r
@@ -329,7 +329,7 @@ public:
                consumer_.reset(new ogl_consumer(screen_index_, stretch_, windowed_, format_desc));\r
        }\r
        \r
-       virtual void send(const safe_ptr<const core::read_frame>& frame)\r
+       virtual void send(const safe_ptr<core::read_frame>& frame)\r
        {\r
                consumer_->send(frame);\r
        }\r