]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2: Further reduced frame latency at the cost of larger memory requirements.
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 26 May 2011 09:00:59 +0000 (09:00 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Thu, 26 May 2011 09:00:59 +0000 (09:00 +0000)
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@812 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

14 files changed:
common/concurrency/executor.h
core/mixer/audio/audio_mixer.cpp
core/mixer/audio/audio_mixer.h
core/mixer/frame_mixer_device.cpp
core/mixer/gpu/host_buffer.cpp
core/mixer/image/image_mixer.cpp
core/mixer/image/image_mixer.h
core/mixer/write_frame.cpp
core/mixer/write_frame.h
modules/decklink/producer/decklink_producer.cpp
modules/ffmpeg/producer/ffmpeg_producer.cpp
modules/ffmpeg/producer/video/video_decoder.cpp
modules/flash/producer/flash_producer.cpp
modules/image/producer/image_producer.cpp

index a2427d3ceb3a951d25b0d3c99fdd70378678a421..c133980ffb7b5fb9331fb001d0674e87d80635ac 100644 (file)
@@ -201,7 +201,6 @@ private:
                detail::SetThreadName(GetCurrentThreadId(), name_.c_str());\r
                while(is_running_)\r
                        execute();\r
-               is_running_ = false;\r
        }       \r
 };\r
 \r
index bfe61002884542f7cbb5b04b140aba0dc69903ce..687812e219fa489acedec765626c04e950e49fb6 100644 (file)
@@ -107,19 +107,18 @@ public:
                transform_stack_.pop();\r
        }\r
 \r
-       std::vector<short> begin_pass()\r
+       void begin_pass()\r
        {\r
-               auto result = std::move(audio_data_.front());\r
-               audio_data_.pop_front();\r
-               \r
                audio_data_.push_back(std::vector<short>());\r
-\r
-               return result;\r
        }\r
 \r
-       void end_pass()\r
+       std::vector<short>  end_pass()\r
        {\r
                prev_audio_transforms_ = std::move(next_audio_transforms_);\r
+\r
+               auto result = std::move(audio_data_.front());\r
+               audio_data_.pop_front();                \r
+               return result;\r
        }\r
 };\r
 \r
@@ -127,7 +126,7 @@ audio_mixer::audio_mixer() : impl_(new implementation()){}
 void audio_mixer::begin(const core::basic_frame& frame){impl_->begin(frame);}\r
 void audio_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
 void audio_mixer::end(){impl_->end();}\r
-std::vector<short> audio_mixer::begin_pass(){return impl_->begin_pass();}      \r
-void audio_mixer::end_pass(){impl_->end_pass();}\r
+void audio_mixer::begin_pass(){ impl_->begin_pass();}  \r
+std::vector<short> audio_mixer::end_pass(){return impl_->end_pass();}\r
 \r
 }}
\ No newline at end of file
index b3adb26162270310bf9e4ffe20a0baea579c00ba..e855aaacee8c77c3af495cbf00bfeb2b6f85c2e2 100644 (file)
@@ -35,8 +35,8 @@ public:
        virtual void visit(core::write_frame& frame);\r
        virtual void end();\r
 \r
-       std::vector<short> begin_pass();\r
-       void end_pass();\r
+       void begin_pass();\r
+       std::vector<short> end_pass();\r
 \r
 private:\r
        struct implementation;\r
index 663a9a1e8e76efee8408fee23c134d85ad2d168a..ea8154afb724153472556e67e7321eeecbc24edc 100644 (file)
@@ -171,7 +171,7 @@ public:
                auto& root_audio_transform = boost::fusion::at_key<core::audio_transform>(root_transforms_);\r
                auto& audio_transforms = boost::fusion::at_key<core::audio_transform>(transforms_);\r
 \r
-               auto audio = audio_mixer_.begin_pass();\r
+               audio_mixer_.begin_pass();\r
                BOOST_FOREACH(auto& frame, frames)\r
                {\r
                        int num = format_desc_.mode == core::video_mode::progressive ? 1 : 2;\r
@@ -180,8 +180,7 @@ public:
                        frame1->get_audio_transform() = root_audio_transform.fetch_and_tick(num)*audio_transforms[frame.first].fetch_and_tick(num);\r
                        frame1->accept(audio_mixer_);\r
                }\r
-               audio_mixer_.end_pass();\r
-               return audio;\r
+               return audio_mixer_.end_pass();\r
        }\r
                \r
        void send(const std::map<int, safe_ptr<core::basic_frame>>& frames)\r
@@ -205,8 +204,8 @@ public:
        }\r
                \r
        safe_ptr<core::write_frame> create_frame(void* tag, const core::pixel_format_desc& desc)\r
-       {\r
-               return make_safe<write_frame>(reinterpret_cast<int>(tag), desc, image_mixer_.create_buffers(desc));\r
+       {               \r
+               return image_mixer_.create_frame(tag, desc);\r
        }\r
                        \r
        template<typename T>    \r
index d19e63fd5d1e3a1da6c2118b535fb24d142aea85..d9fe6933545dd28e1e3e9a9b418ba1899f3fa1cf 100644 (file)
@@ -45,7 +45,8 @@ public:
        {\r
                GL(glGenBuffers(1, &pbo_));\r
                GL(glBindBuffer(target_, pbo_));\r
-               GL(glBufferData(target_, size_, NULL, usage_)); \r
+               if(usage_ != write_only)        \r
+                       GL(glBufferData(target_, size_, NULL, usage_)); \r
                GL(glBindBuffer(target_, 0));\r
 \r
                if(!pbo_)\r
@@ -63,6 +64,9 @@ public:
        {\r
                if(data_)\r
                        return;\r
+\r
+               if(usage_ == write_only)                        \r
+                       GL(glBufferData(target_, size_, NULL, usage_)); // Notify OpenGL that we don't care about previous data.\r
                \r
                GL(glBindBuffer(target_, pbo_));\r
                data_ = glMapBuffer(target_, usage_ == GL_STREAM_DRAW ? GL_WRITE_ONLY : GL_READ_ONLY);  \r
index 319add062e715383f46b83e21152e236876418f6..8342dfb49f1160cbc04deec8bb83405e083c96b2 100644 (file)
@@ -49,16 +49,15 @@ struct image_mixer::implementation : boost::noncopyable
 \r
        struct render_item\r
        {\r
-               core::pixel_format_desc desc;\r
+               pixel_format_desc                                        desc;\r
                std::vector<safe_ptr<device_buffer>> textures;\r
-               core::image_transform transform;\r
+               core::image_transform                            transform;\r
        };\r
 \r
        const core::video_format_desc format_desc_;\r
        \r
        std::stack<core::image_transform>               transform_stack_;\r
-       std::vector<std::vector<render_item>>   transferring_queue_;\r
-       std::vector<std::vector<render_item>>   render_queue_;\r
+       std::queue<std::queue<render_item>>             render_queue_;\r
        \r
        image_kernel kernel_;\r
                        \r
@@ -90,29 +89,9 @@ public:
        }\r
                \r
        void visit(core::write_frame& frame)\r
-       {                                               \r
-               auto desc               = frame.get_pixel_format_desc();\r
-               auto buffers    = frame.get_plane_buffers();\r
-               auto transform  = transform_stack_.top()*frame.get_image_transform();\r
-\r
-               ogl_device::begin_invoke([=]\r
-               {\r
-                       render_item item;\r
-\r
-                       item.desc = desc;\r
-                       item.transform = transform;\r
-                       \r
-                       // Start transfer from host to device.\r
-\r
-                       for(size_t n = 0; n < buffers.size(); ++n)\r
-                       {\r
-                               auto texture = ogl_device::create_device_buffer(desc.planes[n].width, desc.planes[n].height, desc.planes[n].channels);\r
-                               texture->read(*buffers[n]);\r
-                               item.textures.push_back(texture);\r
-                       }       \r
-\r
-                       transferring_queue_.back().push_back(item);\r
-               });\r
+       {                       \r
+               render_item item = {frame.get_pixel_format_desc(), frame.get_textures(), transform_stack_.top()*frame.get_image_transform()};   \r
+               render_queue_.back().push(item);\r
        }\r
 \r
        void end()\r
@@ -122,10 +101,7 @@ public:
 \r
        void begin_layer()\r
        {\r
-               ogl_device::begin_invoke([=]\r
-               {\r
-                       transferring_queue_.push_back(std::vector<render_item>());\r
-               });\r
+               render_queue_.push(std::queue<render_item>());\r
        }\r
 \r
        void end_layer()\r
@@ -135,8 +111,10 @@ public:
        boost::unique_future<safe_ptr<const host_buffer>> render()\r
        {\r
                auto result = ogl_device::create_host_buffer(format_desc_.size, host_buffer::read_only);\r
-                                       \r
-               ogl_device::begin_invoke([=]\r
+                       \r
+               auto render_queue = std::move(render_queue_);\r
+\r
+               ogl_device::begin_invoke([=]() mutable\r
                {\r
                        local_key_ = false;\r
                        layer_key_ = false;\r
@@ -148,14 +126,18 @@ public:
 \r
                        // Draw items in device.\r
 \r
-                       BOOST_FOREACH(auto layer, render_queue_)\r
+                       while(!render_queue.empty())\r
                        {\r
+                               auto layer = render_queue.front();\r
+                               render_queue.pop();\r
+                               \r
                                draw_buffer_->attach(); \r
 \r
-                               BOOST_FOREACH(auto item, layer)                 \r
-                               {       \r
+                               while(!layer.empty())\r
+                               {\r
+                                       draw(layer.front());\r
+                                       layer.pop();\r
                                        ogl_device::yield(); // Allow quick buffer allocation to execute.\r
-                                       draw(item);     \r
                                }\r
 \r
                                layer_key_ = local_key_; // If there was only key in last layer then use it as key for the entire next layer.\r
@@ -164,10 +146,6 @@ public:
                                std::swap(local_key_buffer_, layer_key_buffer_);\r
                        }\r
 \r
-                       // Move waiting items to queue.\r
-\r
-                       render_queue_ = std::move(transferring_queue_);\r
-\r
                        // Start transfer from device to host.\r
 \r
                        draw_buffer_->write(*result);\r
@@ -224,14 +202,23 @@ public:
                kernel_.draw(format_desc_.width, format_desc_.height, item.desc, item.transform, local_key, layer_key); \r
        }\r
                        \r
-       std::vector<safe_ptr<host_buffer>> create_buffers(const core::pixel_format_desc& format)\r
+       safe_ptr<write_frame> create_frame(void* tag, const core::pixel_format_desc& desc)\r
        {\r
                std::vector<safe_ptr<host_buffer>> buffers;\r
-               std::transform(format.planes.begin(), format.planes.end(), std::back_inserter(buffers), [&](const core::pixel_format_desc::plane& plane)\r
+               std::vector<safe_ptr<device_buffer>> textures;\r
+               ogl_device::invoke([&]\r
                {\r
-                       return ogl_device::create_host_buffer(plane.size, host_buffer::write_only);\r
+                       std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(buffers), [&](const core::pixel_format_desc::plane& plane)\r
+                       {\r
+                               return ogl_device::create_host_buffer(plane.size, host_buffer::write_only);\r
+                       });\r
+                       std::transform(desc.planes.begin(), desc.planes.end(), std::back_inserter(textures), [&](const core::pixel_format_desc::plane& plane)\r
+                       {\r
+                               return ogl_device::create_device_buffer(plane.width, plane.height, plane.channels);\r
+                       });\r
                });\r
-               return buffers;\r
+\r
+               return make_safe<write_frame>(reinterpret_cast<int>(tag), desc, buffers, textures);\r
        }\r
 };\r
 \r
@@ -240,7 +227,7 @@ void image_mixer::begin(const core::basic_frame& frame){impl_->begin(frame);}
 void image_mixer::visit(core::write_frame& frame){impl_->visit(frame);}\r
 void image_mixer::end(){impl_->end();}\r
 boost::unique_future<safe_ptr<const host_buffer>> image_mixer::render(){return impl_->render();}\r
-std::vector<safe_ptr<host_buffer>> image_mixer::create_buffers(const core::pixel_format_desc& format){return impl_->create_buffers(format);}\r
+safe_ptr<write_frame> image_mixer::create_frame(void* tag, const core::pixel_format_desc& desc){return impl_->create_frame(tag, desc);}\r
 void image_mixer::begin_layer(){impl_->begin_layer();}\r
 void image_mixer::end_layer(){impl_->end_layer();}\r
 \r
index 00b97e5135d4cb8ed03ffbc32657655b565b2267..aab31eec247d9e00b5fa3f4930f157004ae37600 100644 (file)
@@ -50,7 +50,7 @@ public:
        \r
        boost::unique_future<safe_ptr<const host_buffer>> render();\r
 \r
-       std::vector<safe_ptr<host_buffer>> create_buffers(const core::pixel_format_desc& format);\r
+       safe_ptr<write_frame> create_frame(void* tag, const core::pixel_format_desc& format);\r
 \r
 private:\r
        struct implementation;\r
index 1c95860172c66b940ce37f471061aa71f81c5a26..c56edb4d02c9a55b7e612ee6b8065b9125fa3fed 100644 (file)
@@ -21,6 +21,8 @@
 \r
 #include "write_frame.h"\r
 \r
+#include "gpu/ogl_device.h"\r
+\r
 #include <core/producer/frame/pixel_format.h>\r
 \r
 #include <common/gl/gl_check.h>\r
@@ -32,15 +34,18 @@ namespace caspar { namespace core {
 struct write_frame::implementation : boost::noncopyable\r
 {                              \r
        std::vector<safe_ptr<host_buffer>> buffers_;\r
+       std::vector<safe_ptr<device_buffer>> textures_;\r
        std::vector<short> audio_data_;\r
        const core::pixel_format_desc desc_;\r
        int tag_;\r
 \r
 public:\r
-       implementation(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers) \r
+       implementation(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures\r
                : desc_(desc)\r
                , buffers_(buffers)\r
-               , tag_(tag){}\r
+               , textures_(textures)\r
+               , tag_(tag)\r
+       {}\r
        \r
        void accept(write_frame& self, core::frame_visitor& visitor)\r
        {\r
@@ -64,9 +69,29 @@ public:
                auto ptr = static_cast<const unsigned char*>(buffers_[index]->data());\r
                return boost::iterator_range<const unsigned char*>(ptr, ptr+buffers_[index]->size());\r
        }\r
+\r
+       void commit()\r
+       {\r
+               for(size_t n = 0; n < buffers_.size(); ++n)\r
+                       commit(n);\r
+       }\r
+\r
+       void commit(size_t plane_index)\r
+       {\r
+               if(plane_index >= buffers_.size())\r
+                       return;\r
+                               \r
+               auto texture = textures_[plane_index];\r
+               auto buffer = std::move(buffers_[plane_index]);\r
+\r
+               ogl_device::begin_invoke([=]\r
+               {\r
+                       texture->read(*buffer);\r
+               });\r
+       }\r
 };\r
        \r
-write_frame::write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers) : impl_(new implementation(tag, desc, buffers)){}\r
+write_frame::write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures) : impl_(new implementation(tag, desc, buffers, textures)){}\r
 void write_frame::accept(core::frame_visitor& visitor){impl_->accept(*this, visitor);}\r
 \r
 boost::iterator_range<unsigned char*> write_frame::image_data(size_t index){return impl_->image_data(index);}\r
@@ -81,5 +106,8 @@ const boost::iterator_range<const short*> write_frame::audio_data() const
 }\r
 int write_frame::tag() const {return impl_->tag_;}\r
 const core::pixel_format_desc& write_frame::get_pixel_format_desc() const{return impl_->desc_;}\r
-const std::vector<safe_ptr<host_buffer>>& write_frame::get_plane_buffers() const{return impl_->buffers_;}\r
+const std::vector<safe_ptr<device_buffer>>& write_frame::get_textures() const{return impl_->textures_;}\r
+const std::vector<safe_ptr<host_buffer>>& write_frame::get_buffers() const{return impl_->buffers_;}\r
+void write_frame::commit(size_t plane_index){impl_->commit(plane_index);}\r
+void write_frame::commit(){impl_->commit();}\r
 }}
\ No newline at end of file
index a41b362180a10936c8e9f01e8f98e8da27170862..9c48e29e4d8f04b14e2a79bf32895c0f194a87f3 100644 (file)
@@ -25,6 +25,7 @@
 #include <core/producer/frame/pixel_format.h>\r
 \r
 #include "gpu/host_buffer.h"\r
+#include "gpu/device_buffer.h"\r
 \r
 #include <boost/noncopyable.hpp>\r
 #include <boost/range/iterator_range.hpp>\r
@@ -37,7 +38,7 @@ namespace caspar { namespace core {
 class write_frame : public core::basic_frame, boost::noncopyable\r
 {\r
 public:        \r
-       explicit write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers);\r
+       explicit write_frame(int tag, const core::pixel_format_desc& desc, const std::vector<safe_ptr<host_buffer>>& buffers, const std::vector<safe_ptr<device_buffer>>& textures);\r
                        \r
        // core::write_frame\r
        virtual boost::iterator_range<unsigned char*> image_data(size_t plane_index = 0);       \r
@@ -46,6 +47,9 @@ public:
        virtual const boost::iterator_range<const unsigned char*> image_data(size_t plane_index = 0) const;\r
        virtual const boost::iterator_range<const short*> audio_data() const;\r
 \r
+       void commit(size_t plane_index);\r
+       void commit();\r
+\r
        virtual void accept(core::frame_visitor& visitor);\r
 \r
        virtual int tag() const;\r
@@ -54,7 +58,8 @@ private:
        friend class image_mixer;\r
 \r
        const core::pixel_format_desc& get_pixel_format_desc() const;\r
-       const std::vector<safe_ptr<host_buffer>>& get_plane_buffers() const;\r
+       const std::vector<safe_ptr<device_buffer>>& get_textures() const;\r
+       const std::vector<safe_ptr<host_buffer>>& get_buffers() const;\r
 \r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index b3d544f6a89fff48e7575ae5f7a0045c1a3752e3..7b3e46d4b9c2c0fa52e18f7dcef02614a4f9ceb6 100644 (file)
@@ -164,6 +164,8 @@ public:
                                }\r
                        });\r
 \r
+                       frame->commit();\r
+\r
                        // It is assumed that audio is always equal or ahead of video.\r
                        if(audio && SUCCEEDED(audio->GetBytes(&bytes)))\r
                        {\r
index 1ae521869c39449fd9c63c155aa478a9562922ff..362851b621998ca6189f63f0133d56eed7010a44 100644 (file)
@@ -109,12 +109,12 @@ public:
                (\r
                        [&]\r
                        {\r
-                               if(video_decoder_ && video_frames_.empty())\r
+                               if(video_decoder_ && video_frames_.size() < 2)\r
                                        video_frames_ = video_decoder_->receive();              \r
                        }, \r
                        [&]\r
                        {\r
-                               if(audio_decoder_ && audio_chunks_.empty())\r
+                               if(audio_decoder_ && audio_chunks_.size() < 2)\r
                                        audio_chunks_ = audio_decoder_->receive();                      \r
                        }\r
                );\r
index d768059c54ed0fe588cdc62d258fd919ef0f09d2..43518d17458ee5b91365b2b625790dadea81e21d 100644 (file)
@@ -33,6 +33,8 @@
 \r
 #include <tbb/parallel_for.h>\r
 \r
+#include <boost/range/algorithm_ext.hpp>\r
+\r
 #if defined(_MSC_VER)\r
 #pragma warning (push)\r
 #pragma warning (disable : 4244)\r
@@ -158,7 +160,7 @@ public:
                \r
                std::shared_ptr<AVPacket> pkt;\r
                for(int n = 0; n < 32 && result.empty() && input_.try_pop_video_packet(pkt); ++n)       \r
-                       result = decode(pkt);\r
+                       boost::range::push_back(result, decode(pkt));\r
 \r
                return result;\r
        }\r
@@ -212,6 +214,8 @@ public:
                                        for(size_t y = r.begin(); y != r.end(); ++y)\r
                                                memcpy(result + y*plane.linesize, decoded + y*decoded_linesize, plane.linesize);\r
                                });\r
+\r
+                               write->commit(n);\r
                        });\r
                }\r
                else\r
@@ -222,6 +226,8 @@ public:
                        avpicture_fill(reinterpret_cast<AVPicture*>(av_frame.get()), write->image_data().begin(), PIX_FMT_BGRA, width_, height_);\r
                 \r
                        sws_scale(sws_context_.get(), decoded_frame->data, decoded_frame->linesize, 0, height_, av_frame->data, av_frame->linesize);    \r
+\r
+                       write->commit();\r
                }       \r
 \r
                // DVVIDEO is in lower field. Make it upper field if needed.\r
index de7ffc78a5edadaf02dc17f63306290f229f1f14..69bcd50b04479caf589b346cd64a9c59b0448ff5 100644 (file)
@@ -185,6 +185,7 @@ public:
                \r
                        auto frame = frame_factory_->create_frame(this);\r
                        fast_memcpy(frame->image_data().begin(), bmp_.data(), format_desc_.size);\r
+                       frame->commit();\r
                        head_ = frame;\r
                }               \r
                                \r
index bd60fb66718e79ea5d87cebae58ce63daa632ed7..d55da62f4248c77545e06e8162e9f9213f5a947c 100644 (file)
@@ -50,6 +50,7 @@ struct image_producer : public core::frame_producer
                FreeImage_FlipVertical(bitmap.get());\r
                auto frame = frame_factory->create_frame(this, FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()));\r
                std::copy_n(FreeImage_GetBits(bitmap.get()), frame->image_data().size(), frame->image_data().begin());\r
+               frame->commit();\r
                frame_ = std::move(frame);\r
        }\r
        \r