]> git.sesse.net Git - casparcg/commitdiff
2.0.0.2:
authorronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 11 Dec 2010 10:43:29 +0000 (10:43 +0000)
committerronag <ronag@362d55ac-95cf-4e76-9f9a-cbaa9c17b72d>
Sat, 11 Dec 2010 10:43:29 +0000 (10:43 +0000)
 - Refactored frame framework into non-nullable types.
 - Improved executor to avoid deadlocks when called on owner thread.

git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches/2.0.0.2@280 362d55ac-95cf-4e76-9f9a-cbaa9c17b72d

46 files changed:
common/concurrency/executor.h
core/channel.cpp
core/channel.h
core/consumer/bluefish/bluefish_consumer.cpp
core/consumer/decklink/decklink_consumer.cpp
core/consumer/frame_consumer.h
core/consumer/frame_consumer_device.cpp
core/consumer/ogl/ogl_consumer.cpp
core/core.vcxproj
core/core.vcxproj.filters
core/processor/composite_frame.cpp
core/processor/composite_frame.h
core/processor/consumer_frame.h [new file with mode: 0644]
core/processor/frame_processor_device.cpp
core/processor/frame_processor_device.h
core/processor/frame_renderer.cpp
core/processor/frame_renderer.h
core/processor/frame_shader.cpp
core/processor/frame_shader.h
core/processor/fwd.h
core/processor/producer_frame.h [new file with mode: 0644]
core/processor/read_frame.cpp
core/processor/read_frame.h
core/processor/transform_frame.cpp
core/processor/transform_frame.h
core/processor/write_frame.cpp
core/processor/write_frame.h
core/producer/color/color_producer.cpp
core/producer/ffmpeg/ffmpeg_producer.cpp
core/producer/ffmpeg/video/video_transformer.cpp
core/producer/ffmpeg/video/video_transformer.h
core/producer/flash/cg_producer.cpp
core/producer/flash/cg_producer.h
core/producer/flash/ct_producer.cpp
core/producer/flash/flash_producer.cpp
core/producer/flash/flash_producer.h
core/producer/frame_producer.h
core/producer/frame_producer_device.cpp
core/producer/frame_producer_device.h
core/producer/image/image_producer.cpp
core/producer/image/image_scroll_producer.cpp
core/producer/layer.cpp
core/producer/layer.h
core/producer/transition/transition_producer.cpp
core/producer/transition/transition_producer.h
core/protocol/amcp/AMCPCommandsImpl.cpp

index 21b53e918efea74189f88d0d089ca83ffc4d3edd..23f8dafba090424149f0dd82b16c53c1340ba0b6 100644 (file)
@@ -74,7 +74,7 @@ public:
        {\r
                execution_queue_.push([=]{try{func();}catch(...){CASPAR_LOG_CURRENT_EXCEPTION();}});\r
        }\r
-\r
+       \r
        template<typename Func>\r
        auto begin_invoke(Func&& func) -> boost::unique_future<decltype(func())>\r
        {       \r
@@ -83,10 +83,23 @@ public:
                auto task = std::make_shared<boost::packaged_task<result_type>>(std::forward<Func>(func));      \r
                auto future = task->get_future();\r
                \r
-               if(boost::this_thread::get_id() != thread_.get_id())\r
-                       execution_queue_.push([=]{(*task)();});\r
-               else\r
-                       (*task)();\r
+               task->set_wait_callback(std::function<void(decltype(*task)& task)>([=](decltype(*task)& task) // The std::function wrapper is required in order to add ::result_type to functor class.\r
+               {\r
+                       try\r
+                       {\r
+                               if(boost::this_thread::get_id() == thread_.get_id())  // Avoids potential deadlock.\r
+                                       task();\r
+                       }\r
+                       catch(boost::task_already_started&){}\r
+               }));\r
+               execution_queue_.push([=]\r
+               {\r
+                       try\r
+                       {\r
+                               (*task)();    \r
+                       }\r
+                       catch(boost::task_already_started&){}\r
+               });\r
 \r
                return std::move(future);               \r
        }\r
@@ -94,6 +107,9 @@ public:
        template<typename Func>\r
        auto invoke(Func&& func) -> decltype(func())\r
        {\r
+               if(boost::this_thread::get_id() == thread_.get_id())  // Avoids potential deadlock.\r
+                       return func();\r
+               \r
                return begin_invoke(std::forward<Func>(func)).get();\r
        }\r
 \r
index 76b3a56b37dec114924666391d1244faf7d8e05a..5df253ea02f01f99c28c8056fd08aaf2a1983cc6 100644 (file)
@@ -51,12 +51,12 @@ public:
                producer_device_->clear();\r
        }\r
        \r
-       frame_producer_ptr foreground(int render_layer) const\r
+       boost::unique_future<frame_producer_ptr> foreground(int render_layer) const\r
        {\r
                return producer_device_->foreground(render_layer);\r
        }\r
 \r
-       frame_producer_ptr background(int render_layer) const\r
+       boost::unique_future<frame_producer_ptr> background(int render_layer) const\r
        {\r
                return producer_device_->background(render_layer);\r
        }\r
@@ -80,8 +80,8 @@ void channel::play(int render_layer){impl_->play(render_layer);}
 void channel::stop(int render_layer){impl_->stop(render_layer);}\r
 void channel::clear(int render_layer){impl_->clear(render_layer);}\r
 void channel::clear(){impl_->clear();}\r
-frame_producer_ptr channel::foreground(int render_layer) const{        return impl_->foreground(render_layer);}\r
-frame_producer_ptr channel::background(int render_layer) const{return impl_->background(render_layer);}\r
+boost::unique_future<frame_producer_ptr> channel::foreground(int render_layer) const{  return impl_->foreground(render_layer);}\r
+boost::unique_future<frame_producer_ptr> channel::background(int render_layer) const{return impl_->background(render_layer);}\r
 const video_format_desc& channel::get_video_format_desc() const{       return impl_->get_video_format_desc();}\r
 \r
 }}
\ No newline at end of file
index 7ddfd11896b35065a1133bf6ba1942707bb80933..a19df4bd9503060889504b0e2342015f7ec081e7 100644 (file)
@@ -31,8 +31,8 @@ public:
        void stop(int render_layer);\r
        void clear(int render_layer);\r
        void clear();   \r
-       frame_producer_ptr foreground(int render_layer) const;\r
-       frame_producer_ptr background(int render_layer) const;\r
+       boost::unique_future<frame_producer_ptr> foreground(int render_layer) const;\r
+       boost::unique_future<frame_producer_ptr> background(int render_layer) const;\r
        const video_format_desc& get_video_format_desc() const;\r
 private:\r
        struct implementation;\r
index 3a2bdbad5bdf1571dc2bff15349cbc2585f191f6..48a4724a1eec5a63acfef734ca6194293d0a6494 100644 (file)
@@ -190,8 +190,8 @@ struct consumer::implementation : boost::noncopyable
 \r
                                        encode_hanc(reinterpret_cast<BLUE_UINT32*>(hanc->data()), const_cast<short*>(frame_audio_data.data()), audio_samples, audio_nchannels);\r
                                                                \r
-                                       sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.data().begin()), \r
-                                                                                                        frame.data().size(), \r
+                                       sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.pixel_data().begin()), \r
+                                                                                                        frame.pixel_data().size(), \r
                                                                                                         nullptr, \r
                                                                                                         BlueImage_HANC_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
 \r
@@ -205,8 +205,8 @@ struct consumer::implementation : boost::noncopyable
                                }\r
                                else\r
                                {\r
-                                       sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.data().begin()),\r
-                                                                                                        frame.data().size(), \r
+                                       sdk_->system_buffer_write_async(const_cast<unsigned char*>(frame.pixel_data().begin()),\r
+                                                                                                        frame.pixel_data().size(), \r
                                                                                                         nullptr,                 \r
                                                                                                         BlueImage_DMABuffer(current_id_, BLUE_DATA_IMAGE));\r
                        \r
index 959689d881c29390bd1ab5694cf3ef511d53a45c..099737f4bfd3b56cf19d75ad757e8f01e32108b5 100644 (file)
@@ -55,22 +55,22 @@ namespace caspar { namespace core { namespace decklink{
 \r
 struct decklink_consumer::Implementation : boost::noncopyable\r
 {\r
-       Implementation(const video_format_desc& format_desc, bool internalKey) : format_desc_(format_desc), currentFormat_(video_format::pal), internalKey_(internalKey), current_index_(0)\r
+       Implementation(const video_format_desc& format_desc, bool internalKey) : format_desc_(format_desc), currentFormat_(video_format::pal), internalKey_(internalKey)\r
        {       \r
                executor_.start();\r
                executor_.invoke([=]\r
                {\r
                        if(FAILED(CoInitialize(nullptr))) \r
-                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("Initialization of COM failed."));         \r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Initialization of COM failed."));               \r
 \r
                        CComPtr<IDeckLinkIterator> pDecklinkIterator;\r
                        if(FAILED(pDecklinkIterator.CoCreateInstance(CLSID_CDeckLinkIterator)))\r
-                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("No Decklink drivers installed."));\r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: No Decklink drivers installed."));\r
 \r
                        while(pDecklinkIterator->Next(&decklink_) == S_OK && !decklink_){}      \r
 \r
                        if(decklink_ == nullptr)\r
-                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("No Decklink card found"));\r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: No Decklink card found."));\r
 \r
                        output_ = decklink_;\r
                        keyer_ = decklink_;\r
@@ -88,30 +88,29 @@ struct decklink_consumer::Implementation : boost::noncopyable
 \r
                        BMDDisplayModeSupport displayModeSupport;\r
                        if(FAILED(output_->DoesSupportVideoMode((BMDDisplayMode)decklinkVideoFormat, bmdFormat8BitBGRA, &displayModeSupport)))\r
-                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Card does not support requested videoformat"));\r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Card does not support requested videoformat."));\r
                \r
                        output_->DisableAudioOutput();\r
                        if(FAILED(output_->EnableVideoOutput((BMDDisplayMode)decklinkVideoFormat, bmdVideoOutputFlagDefault))) \r
-                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Could not enable video output"));\r
+                               BOOST_THROW_EXCEPTION(caspar_exception() << msg_info("DECKLINK: Could not enable video output."));\r
 \r
                        if(internalKey_) \r
                        {\r
                                if(FAILED(keyer_->Enable(FALSE)))                       \r
-                                       CASPAR_LOG(error) << "DECKLINK: Failed to enable internal keyer";                       \r
+                                       CASPAR_LOG(error) << "DECKLINK: Failed to enable internal keye.r";                      \r
                                else if(FAILED(keyer_->SetLevel(255)))                  \r
-                                       CASPAR_LOG(error) << "DECKLINK: Keyer - Failed to set blend-level to max";\r
+                                       CASPAR_LOG(error) << "DECKLINK: Keyer - Failed to set key-level to max.";\r
                                else\r
-                                       CASPAR_LOG(info) << "DECKLINK: Successfully configured internal keyer";         \r
+                                       CASPAR_LOG(info) << "DECKLINK: Successfully configured internal keyer.";                \r
                        }\r
                        else\r
                        {\r
                                if(FAILED(keyer_->Enable(TRUE)))                        \r
-                                       CASPAR_LOG(error) << "DECKLINK: Failed to enable external keyer";       \r
+                                       CASPAR_LOG(error) << "DECKLINK: Failed to enable external keyer.";      \r
                                else\r
-                                       CASPAR_LOG(info) << "DECKLINK: Successfully configured external keyer";                 \r
+                                       CASPAR_LOG(info) << "DECKLINK: Successfully configured external keyer.";                        \r
                        }\r
                \r
-                       reserved_frames_.resize(3);\r
                        for(int n = 0; n < reserved_frames_.size(); ++n)\r
                        {\r
                                if(FAILED(output_->CreateVideoFrame(format_desc_.width, format_desc_.height, format_desc_.size/format_desc_.height, bmdFormat8BitBGRA, bmdFrameFlagDefault, &reserved_frames_[n].second)))\r
@@ -128,28 +127,21 @@ struct decklink_consumer::Implementation : boost::noncopyable
        ~Implementation()\r
        {               \r
                if(output_) \r
-               {\r
-                       BOOL bIsRunning = FALSE;\r
-                       output_->IsScheduledPlaybackRunning(&bIsRunning);\r
-                       if(bIsRunning)\r
-                               output_->StopScheduledPlayback(0, NULL, 0);\r
-\r
                        output_->DisableVideoOutput();\r
-               }\r
+               \r
                CoUninitialize();\r
        }\r
        \r
-       void send(const consumer_frame& input_frame)\r
+       void send(const consumer_frame& frame)\r
        {\r
                active_ = executor_.begin_invoke([=]\r
-               {\r
-                       auto& output_frame = reserved_frames_[current_index_];\r
-                       current_index_ = (++current_index_) % reserved_frames_.size();\r
-               \r
-                       std::copy(input_frame.data().begin(), input_frame.data().end(), static_cast<char*>(output_frame.first));\r
+               {               \r
+                       std::copy(frame.pixel_data().begin(), frame.pixel_data().end(), static_cast<char*>(reserved_frames_.front().first));\r
                                \r
-                       if(FAILED(output_->DisplayVideoFrameSync(output_frame.second)))\r
+                       if(FAILED(output_->DisplayVideoFrameSync(reserved_frames_.front().second)))\r
                                CASPAR_LOG(error) << L"DECKLINK: Failed to display frame.";\r
+\r
+                       std::rotate(reserved_frames_.begin(), reserved_frames_.begin() + 1, reserved_frames_.end());\r
                });\r
        }\r
        \r
@@ -167,8 +159,7 @@ struct decklink_consumer::Implementation : boost::noncopyable
        boost::unique_future<void> active_;\r
        common::executor executor_;\r
 \r
-       std::vector<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>> reserved_frames_;\r
-       size_t  current_index_;\r
+       std::array<std::pair<void*, CComPtr<IDeckLinkMutableVideoFrame>>, 3> reserved_frames_;\r
 \r
        bool                                            internalKey_;\r
        CComPtr<IDeckLink>                      decklink_;\r
index 619770c011159e4538e7c87085c0daadb33116e7..5e529d78c6dbbc5f5c590870d558336f0c97b92e 100644 (file)
@@ -20,7 +20,7 @@
 #pragma once\r
 \r
 #include "../format/video_format.h"\r
-#include "../processor/read_frame.h"\r
+#include "../processor/consumer_frame.h"\r
 \r
 #include <boost/noncopyable.hpp>\r
 \r
@@ -38,7 +38,7 @@ struct frame_consumer : boost::noncopyable
 \r
        virtual ~frame_consumer() {}\r
 \r
-       virtual void send(const consumer_frame&) = 0;\r
+       virtual void send(const consumer_frame& frame) = 0;\r
        virtual sync_mode synchronize() = 0;\r
        virtual size_t buffer_depth() const = 0;\r
 };\r
index 34622fb99228f120823b06f3179e4c216cb33bc5..b17cabc0d32fc60039dba8d7698bada8a7034863 100644 (file)
@@ -9,13 +9,11 @@
 #include "../format/video_format.h"\r
 #include "../processor/write_frame.h"\r
 #include "../processor/frame_processor_device.h"\r
+#include "../../common/concurrency/executor.h"\r
 \r
 #include <tbb/concurrent_queue.h>\r
 #include <tbb/atomic.h>\r
 \r
-#include <boost/foreach.hpp>\r
-#include <boost/thread.hpp>\r
-\r
 #include <boost/date_time/posix_time/posix_time.hpp>\r
 \r
 #include <boost/range/algorithm_ext/erase.hpp>\r
@@ -47,31 +45,18 @@ public:
                std::vector<size_t> depths;\r
                boost::range::transform(consumers_, std::back_inserter(depths), std::mem_fn(&frame_consumer::buffer_depth));\r
                max_depth_ = *boost::range::max_element(depths);\r
-               display_thread_ = boost::thread([=]{run();});\r
-       }\r
-\r
-       ~implementation()\r
-       {\r
-               is_running_ = false;\r
-               display_thread_.join();\r
+               executor_.start();\r
+               executor_.begin_invoke([=]{tick();});\r
        }\r
-                               \r
-       void run()\r
+                                       \r
+       void tick()\r
        {\r
-               is_running_ = true;\r
-               CASPAR_LOG(warning) << "Starting frame_consumer_device.";               \r
-\r
-               win32_exception::install_handler();\r
-                                                               \r
-               while(is_running_)                                              \r
-               {\r
-                       display_frame(frame_processor_->receive());             \r
-                       is_running_ = !consumers_.empty();\r
-               }\r
-               CASPAR_LOG(warning) << "Shutting down frame_consumer_device.";                  \r
+               process(frame_processor_->receive());           \r
+               if(!consumers_.empty())\r
+                       executor_.begin_invoke([=]{tick();});\r
        }\r
 \r
-       void display_frame(const consumer_frame& frame)\r
+       void process(const consumer_frame& frame)\r
        {               \r
                buffer_.push_back(frame);\r
 \r
@@ -111,11 +96,10 @@ public:
                        buffer_.pop_front();\r
        }\r
 \r
+       common::executor executor_;     \r
+\r
        size_t max_depth_;\r
-       std::deque<consumer_frame> buffer_;\r
-               \r
-       tbb::atomic<bool> is_running_;\r
-       boost::thread display_thread_;\r
+       std::deque<consumer_frame> buffer_;             \r
 \r
        std::vector<frame_consumer_ptr> consumers_;\r
        \r
index 0c1cb930240ac61bdc5036686623d25c5943a61d..dd11ee859d190499377dc77572db5737ae040a25 100644 (file)
@@ -45,31 +45,31 @@ struct consumer::implementation : boost::noncopyable
                : format_desc_(format_desc), stretch_(stretch), screen_width_(0), screen_height_(0), windowed_(windowed)\r
        {               \r
 #ifdef _WIN32\r
-               DISPLAY_DEVICE dDevice;                 \r
-               memset(&dDevice,0,sizeof(dDevice));\r
-               dDevice.cb = sizeof(dDevice);\r
+               DISPLAY_DEVICE d_device;                        \r
+               memset(&d_device, 0, sizeof(d_device));\r
+               d_device.cb = sizeof(d_device);\r
 \r
                std::vector<DISPLAY_DEVICE> displayDevices;\r
-               for(int n = 0; EnumDisplayDevices(NULL, n, &dDevice, NULL); ++n)\r
+               for(int n = 0; EnumDisplayDevices(NULL, n, &d_device, NULL); ++n)\r
                {\r
-                       displayDevices.push_back(dDevice);\r
-                       memset(&dDevice,0,sizeof(dDevice));\r
-                       dDevice.cb = sizeof(dDevice);\r
+                       displayDevices.push_back(d_device);\r
+                       memset(&d_device, 0, sizeof(d_device));\r
+                       d_device.cb = sizeof(d_device);\r
                }\r
 \r
                if(screen_index >= displayDevices.size())\r
                        BOOST_THROW_EXCEPTION(out_of_range() << arg_name_info("screen_index_"));\r
                \r
                DEVMODE devmode;\r
-               memset(&devmode,0,sizeof(devmode));\r
+               memset(&devmode, 0, sizeof(devmode));\r
                \r
                if(!EnumDisplaySettings(displayDevices[screen_index].DeviceName, ENUM_CURRENT_SETTINGS, &devmode))\r
                        BOOST_THROW_EXCEPTION(invalid_operation() << arg_name_info("screen_index") << msg_info("EnumDisplaySettings"));\r
                \r
                screen_width_ = windowed ? format_desc_.width : devmode.dmPelsWidth;\r
                screen_height_ = windowed ? format_desc_.height : devmode.dmPelsHeight;\r
-               screenX_ = devmode.dmPosition.x;\r
-               screenY_ = devmode.dmPosition.y;\r
+               screen_x_ = devmode.dmPosition.x;\r
+               screen_y_ = devmode.dmPosition.y;\r
 #else\r
                if(!windowed)\r
                        BOOST_THROW_EXCEPTION(not_supported() << msg_info("OGLConsumer doesn't support non-Win32 fullscreen"));\r
@@ -79,8 +79,8 @@ struct consumer::implementation : boost::noncopyable
                \r
                screen_width_ = format_desc_.width;\r
                screen_height_ = format_desc_.height;\r
-               screenX_ = 0;\r
-               screenY_ = 0;\r
+               screen_x_ = 0;\r
+               screen_y_ = 0;\r
 #endif\r
 \r
                executor_.start();\r
@@ -88,7 +88,7 @@ struct consumer::implementation : boost::noncopyable
                {\r
                        window_.Create(sf::VideoMode(format_desc_.width, format_desc_.height, 32), "CasparCG", windowed_ ? sf::Style::Titlebar : sf::Style::Fullscreen);\r
                        window_.ShowMouseCursor(false);\r
-                       window_.SetPosition(screenX_, screenY_);\r
+                       window_.SetPosition(screen_x_, screen_y_);\r
                        window_.SetSize(screen_width_, screen_height_);\r
                        window_.SetActive();\r
                        GL(glEnable(GL_TEXTURE_2D));\r
@@ -153,7 +153,7 @@ struct consumer::implementation : boost::noncopyable
        void render(const consumer_frame& frame)\r
        {                                               \r
                auto ptr = pbos_.front().end_write();\r
-               std::copy_n(frame.data().begin(), frame.data().size(), reinterpret_cast<char*>(ptr));\r
+               std::copy_n(frame.pixel_data().begin(), frame.pixel_data().size(), reinterpret_cast<char*>(ptr));\r
 \r
                GL(glClear(GL_COLOR_BUFFER_BIT));       \r
                pbos_.back().bind_texture();                            \r
@@ -206,8 +206,8 @@ struct consumer::implementation : boost::noncopyable
        bool windowed_;\r
        unsigned int screen_width_;\r
        unsigned int screen_height_;\r
-       unsigned int screenX_;\r
-       unsigned int screenY_;\r
+       unsigned int screen_x_;\r
+       unsigned int screen_y_;\r
                                \r
        stretch stretch_;\r
        video_format_desc format_desc_;\r
index 8961b49e244a9b0ac6935df017b4e0393976e0c4..958089ec9a5f8230b6df1810c89e147a52927823 100644 (file)
     <ClInclude Include="format\pixel_format.h" />\r
     <ClInclude Include="format\video_format.h" />\r
     <ClInclude Include="processor\composite_frame.h" />\r
+    <ClInclude Include="processor\consumer_frame.h" />\r
     <ClInclude Include="processor\frame_processor_device.h" />\r
     <ClInclude Include="processor\frame_renderer.h" />\r
     <ClInclude Include="processor\frame_shader.h" />\r
     <ClInclude Include="processor\fwd.h" />\r
-    <ClInclude Include="processor\gpu_frame.h" />\r
+    <ClInclude Include="processor\producer_frame.h" />\r
     <ClInclude Include="processor\read_frame.h" />\r
     <ClInclude Include="processor\transform_frame.h" />\r
     <ClInclude Include="processor\write_frame.h" />\r
index 5e4b339a87e86408cfa1a2d29534bd6f8974989c..f6db5d36737124aeac2e544ff92509192a05cdc5 100644 (file)
     <ClInclude Include="processor\fwd.h">\r
       <Filter>Source\channel\processor</Filter>\r
     </ClInclude>\r
-    <ClInclude Include="processor\gpu_frame.h">\r
-      <Filter>Source\channel\processor\frame</Filter>\r
+    <ClInclude Include="processor\producer_frame.h">\r
+      <Filter>Source\channel\processor</Filter>\r
+    </ClInclude>\r
+    <ClInclude Include="processor\consumer_frame.h">\r
+      <Filter>Source\channel\processor</Filter>\r
     </ClInclude>\r
   </ItemGroup>\r
   <ItemGroup>\r
index 9800f92948809844b1b05a19c72bcab869fea12d..08da985cda7b62432618c20be150bd3963fb8b83 100644 (file)
@@ -1,5 +1,6 @@
 #include "../StdAfx.h"\r
 \r
+#include "producer_frame.h"\r
 #include "composite_frame.h"\r
 #include "transform_frame.h"\r
 #include "../../common/gl/utility.h"\r
@@ -16,25 +17,21 @@ namespace caspar { namespace core {
        \r
 struct composite_frame::implementation : boost::noncopyable\r
 {      \r
-       implementation(const std::vector<gpu_frame_ptr>& frames) : frames_(frames)\r
-       {\r
-               boost::range::remove_erase(frames_, nullptr);\r
-       }\r
+       implementation(const std::vector<producer_frame>& frames) : frames_(frames)     {}\r
        \r
        void begin_write()\r
        {\r
-               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::begin_write));          \r
+               boost::range::for_each(frames_, std::mem_fn(&producer_frame::begin_write));             \r
        }\r
 \r
        void end_write()\r
        {\r
-               boost::range::for_each(frames_, std::mem_fn(&gpu_frame::end_write));                            \r
+               boost::range::for_each(frames_, std::mem_fn(&producer_frame::end_write));                               \r
        }\r
        \r
        void draw(frame_shader& shader)\r
        {\r
-               for(size_t n = 0; n < frames_.size(); ++n)\r
-                       frames_[n]->draw(shader);\r
+               boost::range::for_each(frames_, std::bind(&producer_frame::draw, std::placeholders::_1, std::ref(shader)));     \r
        }\r
                        \r
        std::vector<short>& audio_data()\r
@@ -46,14 +43,14 @@ struct composite_frame::implementation : boost::noncopyable
                                \r
                for(size_t n = 0; n < frames_.size(); ++n)\r
                {\r
-                       auto frame = frames_[n];\r
+                       auto& frame = frames_[n];\r
                        tbb::parallel_for\r
                        (\r
-                               tbb::blocked_range<size_t>(0, frame->audio_data().size()),\r
+                               tbb::blocked_range<size_t>(0, frame.audio_data().size()),\r
                                [&](const tbb::blocked_range<size_t>& r)\r
                                {\r
                                        for(size_t n = r.begin(); n < r.end(); ++n)                                     \r
-                                               audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n]) + static_cast<int>(frame->audio_data()[n])) & 0xFFFF);                                            \r
+                                               audio_data_[n] = static_cast<short>((static_cast<int>(audio_data_[n]) + static_cast<int>(frame.audio_data()[n])) & 0xFFFF);                                             \r
                                }\r
                        );\r
                }\r
@@ -61,7 +58,7 @@ struct composite_frame::implementation : boost::noncopyable
                return audio_data_;\r
        }\r
        \r
-       std::vector<gpu_frame_ptr> frames_;\r
+       std::vector<producer_frame> frames_;\r
        std::vector<short> audio_data_;\r
 };\r
 \r
@@ -69,10 +66,10 @@ struct composite_frame::implementation : boost::noncopyable
 #pragma warning (disable : 4355) // 'this' : used in base member initializer list\r
 #endif\r
 \r
-composite_frame::composite_frame(const std::vector<gpu_frame_ptr>& frames) : impl_(new implementation(frames)){}\r
-composite_frame::composite_frame(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2)\r
+composite_frame::composite_frame(const std::vector<producer_frame>& frames) : impl_(new implementation(frames)){}\r
+composite_frame::composite_frame(const producer_frame& frame1, const producer_frame& frame2)\r
 {\r
-       std::vector<gpu_frame_ptr> frames;\r
+       std::vector<producer_frame> frames;\r
        frames.push_back(frame1);\r
        frames.push_back(frame2);\r
        impl_.reset(new implementation(frames));\r
@@ -84,7 +81,7 @@ void composite_frame::draw(frame_shader& shader){impl_->draw(shader);}
 std::vector<short>& composite_frame::audio_data(){return impl_->audio_data();}\r
 const std::vector<short>& composite_frame::audio_data() const{return impl_->audio_data();}\r
 \r
-composite_frame_ptr composite_frame::interlace(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2, video_mode::type mode)\r
+composite_frame_ptr composite_frame::interlace(const producer_frame& frame1, const producer_frame& frame2, video_mode::type mode)\r
 {                      \r
        auto my_frame1 = std::make_shared<transform_frame>(frame1);\r
        auto my_frame2 = std::make_shared<transform_frame>(frame2);\r
index 6aa924472cde23d147d7c5b0b2398c05a18c4287..5c2bead1b66d26c9823a95bdf24c644e7c20f552 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once\r
 \r
-#include "gpu_frame.h"\r
+#include "fwd.h"\r
 \r
 #include "../format/video_format.h"\r
 \r
@@ -9,22 +9,20 @@
 \r
 namespace caspar { namespace core {\r
        \r
-class composite_frame : public gpu_frame\r
+class composite_frame\r
 {\r
 public:\r
-       composite_frame(const std::vector<gpu_frame_ptr>& frames);\r
-       composite_frame(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2);\r
+       composite_frame(const std::vector<producer_frame>& frames);\r
+       composite_frame(const producer_frame& frame1, const producer_frame& frame2);\r
 \r
-       static std::shared_ptr<composite_frame> interlace(const gpu_frame_ptr& frame1, const gpu_frame_ptr& frame2, video_mode::type mode);\r
+       static std::shared_ptr<composite_frame> interlace(const producer_frame& frame1, const producer_frame& frame2, video_mode::type mode);\r
        \r
-       virtual const std::vector<short>& audio_data() const;\r
-\r
-protected:     \r
-       virtual std::vector<short>& audio_data();\r
-\r
-       virtual void begin_write();\r
-       virtual void end_write();\r
-       virtual void draw(frame_shader& shader);\r
+       const std::vector<short>& audio_data() const;\r
+       std::vector<short>& audio_data();\r
+       \r
+       void begin_write();\r
+       void end_write();\r
+       void draw(frame_shader& shader);\r
 \r
 private:\r
        struct implementation;\r
diff --git a/core/processor/consumer_frame.h b/core/processor/consumer_frame.h
new file mode 100644 (file)
index 0000000..f23de1e
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once\r
+\r
+#include "read_frame.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+\r
+#include <memory>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class consumer_frame\r
+{\r
+public:        \r
+       consumer_frame(const read_frame_ptr& frame) : frame_(frame){}\r
+       const boost::iterator_range<const unsigned char*> pixel_data() const {return frame_->pixel_data();}\r
+       const std::vector<short>& audio_data() const {return frame_->audio_data();}\r
+       \r
+private:\r
+       read_frame_ptr frame_;\r
+};\r
+typedef std::shared_ptr<consumer_frame> consumer_frame_ptr;\r
+typedef std::unique_ptr<consumer_frame> consumer_frame_uptr;\r
+\r
+}}
\ No newline at end of file
index f21e8f9e5ad65bbded509f43c135913ea4c2e0da..cd14efcb780809c61558a63ec6e07f67fd006a2a 100644 (file)
@@ -6,6 +6,7 @@
 #include "write_frame.h"\r
 #include "read_frame.h"\r
 #include "composite_frame.h"\r
+#include "producer_frame.h"\r
 \r
 #include "../format/video_format.h"\r
 \r
@@ -41,12 +42,7 @@ struct frame_processor_device::implementation : boost::noncopyable
                        renderer_.reset(new frame_renderer(format_desc));\r
                });\r
        }\r
-\r
-       ~implementation()\r
-       {\r
-               executor_.stop(); // Wait for executor before destroying anything.\r
-       }\r
-       \r
+               \r
        write_frame_ptr create_frame(const pixel_format_desc& desc)\r
        {\r
                auto pool = &frame_pools_[desc];\r
@@ -65,12 +61,9 @@ struct frame_processor_device::implementation : boost::noncopyable
                });\r
        }\r
                \r
-       void send(const gpu_frame_ptr& input_frame)\r
-       {                       \r
-               if(input_frame == nullptr)\r
-                       return;\r
-                               \r
-               auto future = executor_.begin_invoke([=]{return renderer_->render(input_frame);});      \r
+       void send(const producer_frame& frame)\r
+       {                                                       \r
+               auto future = executor_.begin_invoke([=]{return renderer_->render(frame);});    \r
                output_.push(std::move(future)); // Blocks\r
        }\r
 \r
@@ -93,21 +86,21 @@ struct frame_processor_device::implementation : boost::noncopyable
 \r
                return future.get();\r
        }\r
-                                       \r
-       std::unique_ptr<sf::Context> ogl_context_;\r
-       std::unique_ptr<frame_renderer> renderer_;\r
-       \r
+                               \r
        common::executor executor_;     \r
+\r
+       std::unique_ptr<sf::Context> ogl_context_;\r
+       std::unique_ptr<frame_renderer> renderer_;      \r
                                \r
        tbb::concurrent_bounded_queue<boost::shared_future<consumer_frame>> output_;    \r
        tbb::concurrent_unordered_map<pixel_format_desc, tbb::concurrent_bounded_queue<write_frame_ptr>, std::hash<pixel_format_desc>> frame_pools_;\r
        \r
-       video_format_desc fmt_;\r
+       const video_format_desc fmt_;\r
        long underrun_count_;\r
 };\r
        \r
 frame_processor_device::frame_processor_device(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-void frame_processor_device::send(const gpu_frame_ptr& frame){impl_->send(frame);}\r
+void frame_processor_device::send(const producer_frame& frame){impl_->send(frame);}\r
 consumer_frame frame_processor_device::receive(){return impl_->receive();}\r
 const video_format_desc& frame_processor_device::get_video_format_desc() const { return impl_->fmt_; }\r
 \r
index 6383ca94e27d81c943ddda8abe290d02157d9af3..8f96ed615392d33878317eceecd9a35d334cab62 100644 (file)
@@ -34,7 +34,7 @@ class frame_processor_device : boost::noncopyable
 public:\r
        frame_processor_device(const video_format_desc& format_desc);\r
                \r
-       void send(const gpu_frame_ptr& frame);\r
+       void send(const producer_frame& frame);\r
        consumer_frame receive();\r
        \r
        write_frame_ptr create_frame(const pixel_format_desc& desc);            \r
index 3c819dbd71f6501d3b3fa78af7a3941255b80797..d8185d19d99f24f64e02dcdf5440e7e38dc43f07 100644 (file)
@@ -5,6 +5,8 @@
 #include "frame_shader.h"\r
 #include "write_frame.h"\r
 #include "read_frame.h"\r
+#include "producer_frame.h"\r
+#include "consumer_frame.h"\r
 \r
 #include "../format/video_format.h"\r
 \r
@@ -26,7 +28,7 @@ namespace caspar { namespace core {
 struct frame_renderer::implementation : boost::noncopyable\r
 {      \r
        implementation(const video_format_desc& format_desc) : shader_(format_desc), format_desc_(format_desc),\r
-               reading_(new read_frame(0, 0)), writing_(new write_frame(pixel_format_desc())), drawing_(new write_frame(pixel_format_desc())), fbo_(format_desc.width, format_desc.height)\r
+               reading_(new read_frame(0, 0)), writing_(producer_frame::empty()), drawing_(producer_frame::empty()), fbo_(format_desc.width, format_desc.height)\r
        {       \r
                GL(glEnable(GL_POLYGON_STIPPLE));\r
                GL(glEnable(GL_TEXTURE_2D));\r
@@ -36,32 +38,29 @@ struct frame_renderer::implementation : boost::noncopyable
                GL(glViewport(0, 0, format_desc.width, format_desc.height));\r
        }\r
                                \r
-       consumer_frame render(const gpu_frame_ptr& frame)\r
+       consumer_frame render(const producer_frame& frame)\r
        {\r
-               if(frame == nullptr)\r
-                       return nullptr;\r
-\r
                read_frame_ptr result;\r
                try\r
                {\r
                        drawing_ = writing_;\r
                        writing_ = frame;\r
                                                \r
-                       writing_->begin_write(); // Note: end_write is done when returned to pool, write_frame::reset();\r
+                       writing_.begin_write(); // Note: end_write is done when returned to pool, write_frame::reset();\r
                                                \r
                        reading_->end_read();\r
                        result = reading_; \r
                                                \r
                        GL(glClear(GL_COLOR_BUFFER_BIT));\r
                                                \r
-                       drawing_->draw(shader_);\r
+                       drawing_.draw(shader_);\r
                                \r
                        reading_ = create_output_frame();\r
                        \r
                        reading_->begin_read();\r
-                       reading_->audio_data() = std::move(drawing_->audio_data());\r
+                       reading_->audio_data() = drawing_.audio_data();\r
                                                \r
-                       drawing_ = nullptr;\r
+                       drawing_ = producer_frame::empty();\r
                }\r
                catch(...)\r
                {\r
@@ -84,8 +83,8 @@ struct frame_renderer::implementation : boost::noncopyable
        common::gl::frame_buffer_object fbo_;\r
 \r
        read_frame_ptr  reading_;       \r
-       gpu_frame_ptr   writing_;\r
-       gpu_frame_ptr   drawing_;\r
+       producer_frame  writing_;\r
+       producer_frame  drawing_;\r
        \r
        frame_shader shader_;\r
 \r
@@ -93,7 +92,7 @@ struct frame_renderer::implementation : boost::noncopyable
 };\r
        \r
 frame_renderer::frame_renderer(const video_format_desc& format_desc) : impl_(new implementation(format_desc)){}\r
-consumer_frame frame_renderer::render(const gpu_frame_ptr& frame)\r
+consumer_frame frame_renderer::render(const producer_frame& frame)\r
 {\r
        return impl_->render(frame);\r
 }\r
index c417ba8434de86c448dd2d17206fa4d1a5fc43cd..fd345caa524827283929e49ae337c46582eea255 100644 (file)
@@ -34,7 +34,7 @@ class frame_renderer :  boost::noncopyable
 public:\r
        frame_renderer(const video_format_desc& format_desc_);\r
                \r
-       consumer_frame render(const gpu_frame_ptr& frame);\r
+       consumer_frame render(const producer_frame& frame);\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index f2989516e6bc9f5b4074e79fe1c3f381457554af..81f5acc76a4258a28b7ea37af6010d0ba91e20b4 100644 (file)
@@ -183,7 +183,7 @@ struct frame_shader::implementation
        double alpha_;\r
        std::stack<shader_transform> transform_stack_;\r
 \r
-       video_format_desc format_desc_;\r
+       const video_format_desc format_desc_;\r
        pixel_format::type current_;\r
        std::unordered_map<pixel_format::type, common::gl::shader_program> shaders_;\r
 };\r
index 5073d3af781f29e55ca37abf6de1630159135943..9b3756a40850f805a208945cea2b4e7fb5eeabe5 100644 (file)
@@ -25,7 +25,7 @@ public:
        frame_shader(const video_format_desc& format_desc);\r
 \r
        void begin(const shader_transform& transform);\r
-       void render(const pixel_format_desc& image);\r
+       void render(const pixel_format_desc& desc);\r
        void end();\r
 private:\r
        struct implementation;\r
index 9a25b94ee40d3d30e3a0da878e4de7aca1c48dbe..65392fbf2eb9d8d9de18e62ca84c00445911dfbc 100644 (file)
@@ -4,8 +4,8 @@
 \r
 namespace caspar { namespace core {\r
                \r
-class gpu_frame;\r
-typedef std::shared_ptr<gpu_frame> gpu_frame_ptr;\r
+class read_frame;\r
+typedef std::shared_ptr<read_frame> read_frame_ptr;\r
 \r
 class write_frame;\r
 typedef std::shared_ptr<write_frame> write_frame_ptr;\r
@@ -17,6 +17,7 @@ class composite_frame;
 typedef std::shared_ptr<composite_frame> composite_frame_ptr;\r
 \r
 class consumer_frame;\r
+class producer_frame;\r
 \r
 class frame_shader;\r
 typedef std::shared_ptr<frame_shader> frame_shader_ptr;\r
diff --git a/core/processor/producer_frame.h b/core/processor/producer_frame.h
new file mode 100644 (file)
index 0000000..07d5410
--- /dev/null
@@ -0,0 +1,124 @@
+#pragma once\r
+\r
+#include "write_frame.h"\r
+#include "composite_frame.h"\r
+#include "transform_frame.h"\r
+\r
+#include <boost/noncopyable.hpp>\r
+#include <boost/range/iterator_range.hpp>\r
+#include <boost/variant.hpp>\r
+\r
+#include <memory>\r
+#include <vector>\r
+\r
+namespace caspar { namespace core {\r
+\r
+class producer_frame\r
+{\r
+public:        \r
+       typedef boost::iterator_range<const unsigned char*> pixel_data_type;\r
+       typedef std::vector<short> audio_data_type;\r
+       \r
+       producer_frame() : frame_(empty_frame()){}\r
+       producer_frame(const write_frame_ptr& frame) : frame_(frame){if(!frame) frame_ = eof_frame();}\r
+       producer_frame(const composite_frame_ptr& frame) : frame_(frame){if(!frame) frame_ = eof_frame();}\r
+       producer_frame(const transform_frame_ptr& frame) : frame_(frame){if(!frame) frame_ = eof_frame();}\r
+\r
+       producer_frame(const producer_frame& other) : frame_(other.frame_){}\r
+       producer_frame(producer_frame&& other) : frame_(std::move(other.frame_)){}\r
+\r
+       producer_frame& operator=(const producer_frame& other)\r
+       {\r
+               producer_frame temp(other);\r
+               frame_.swap(temp.frame_);\r
+               return *this;\r
+       }\r
+\r
+       producer_frame& operator=(producer_frame&& other)\r
+       {\r
+               frame_ = std::move(other.frame_);\r
+               return *this;\r
+       }\r
+               \r
+       const audio_data_type& audio_data() const {return boost::apply_visitor(audio_data_visitor(), frame_);}\r
+\r
+       void begin_write() {boost::apply_visitor(begin_write_visitor(), frame_);}       \r
+       void draw(frame_shader& shader) {boost::apply_visitor(draw_visitor(shader), frame_);    }\r
+       void end_write() {boost::apply_visitor(end_write_visitor(), frame_);}\r
+       \r
+       static const producer_frame& eof()\r
+       {\r
+               static producer_frame eof(eof_frame());\r
+               return eof;\r
+       }\r
+\r
+       static const producer_frame& empty()\r
+       {\r
+               static producer_frame empty(empty_frame());\r
+               return empty;\r
+       }\r
+\r
+       bool operator==(const producer_frame& other)\r
+       {\r
+               return frame_ == other.frame_;\r
+       }\r
+\r
+       bool operator!=(const producer_frame& other)\r
+       {\r
+               return !(*this == other);\r
+       }\r
+\r
+private:\r
+\r
+       friend class frame_processor_device;\r
+       friend class frame_renderer;\r
+       \r
+       struct null_frame\r
+       {\r
+               void begin_write(){}\r
+               void draw(frame_shader& shader){}\r
+               void end_write(){}\r
+               audio_data_type& audio_data() { static audio_data_type audio_data; return audio_data;} \r
+       };\r
+       typedef std::shared_ptr<null_frame> null_frame_ptr;\r
+\r
+       producer_frame(const null_frame_ptr& frame) : frame_(frame){}\r
+               \r
+       static const null_frame_ptr& eof_frame()\r
+       {\r
+               static null_frame_ptr eof(new null_frame());\r
+               return eof;\r
+       }\r
+\r
+       static const null_frame_ptr& empty_frame()\r
+       {\r
+               static null_frame_ptr empty(new null_frame());\r
+               return empty;\r
+       }\r
+\r
+       struct audio_data_visitor : public boost::static_visitor<audio_data_type&>\r
+       {\r
+               template<typename P> audio_data_type& operator()(P& frame) const{return frame->audio_data();}\r
+       };\r
+\r
+       struct begin_write_visitor : public boost::static_visitor<void>\r
+       {\r
+               template<typename P> void operator()(P& frame) const{frame->begin_write();}\r
+       };\r
+       \r
+       struct draw_visitor : public boost::static_visitor<void>\r
+       {\r
+               draw_visitor(frame_shader& shader) : shader_(shader){}\r
+               template<typename P> void operator()(P& frame) const{frame->draw(shader_);}\r
+               frame_shader& shader_;\r
+       };\r
+\r
+       struct end_write_visitor : public boost::static_visitor<void>\r
+       {\r
+               template<typename P> void operator()(P& frame) const{frame->end_write();}\r
+       };\r
+\r
+       boost::variant<write_frame_ptr, composite_frame_ptr, transform_frame_ptr, null_frame_ptr> frame_;\r
+};\r
+\r
+}}
\ No newline at end of file
index 39e1bef47ae594c7e9fdf7a91193f462bf2d7bf1..689d3248d9c52c8d16847cccfb38d63fdcf178cb 100644 (file)
@@ -40,7 +40,7 @@ struct read_frame::implementation : boost::noncopyable
 read_frame::read_frame(size_t width, size_t height) : impl_(new implementation(width, height)){}\r
 void read_frame::begin_read(){impl_->begin_read();}\r
 void read_frame::end_read(){impl_->end_read();}\r
-const boost::iterator_range<const unsigned char*> read_frame::data() const\r
+const boost::iterator_range<const unsigned char*> read_frame::pixel_data() const\r
 {\r
        auto ptr = static_cast<const unsigned char*>(impl_->pixel_data_);\r
        return boost::iterator_range<const unsigned char*>(ptr, ptr+impl_->pbo_->size());\r
index da5af0830ac3c8bd0ec924beb003d3bfbaacf0aa..3180edfd2d0ff3a11fa825fa862be8fb40925f14 100644 (file)
@@ -16,7 +16,7 @@ class read_frame : boost::noncopyable
 public:        \r
        explicit read_frame(size_t width, size_t height);\r
 \r
-       const boost::iterator_range<const unsigned char*> data() const;\r
+       const boost::iterator_range<const unsigned char*> pixel_data() const;\r
        const std::vector<short>& audio_data() const;\r
        std::vector<short>& audio_data();\r
        \r
@@ -28,18 +28,4 @@ private:
        std::shared_ptr<implementation> impl_;\r
 };\r
 typedef std::shared_ptr<read_frame> read_frame_ptr;\r
-               \r
-class consumer_frame\r
-{\r
-public:        \r
-       consumer_frame(const read_frame_ptr& frame) : frame_(frame){}\r
-       const boost::iterator_range<const unsigned char*> data() const {return frame_->data();}\r
-       const std::vector<short>& audio_data() const {return frame_->audio_data();}\r
-       \r
-private:\r
-       read_frame_ptr frame_;\r
-};\r
-typedef std::shared_ptr<consumer_frame> consumer_frame_ptr;\r
-typedef std::unique_ptr<consumer_frame> consumer_frame_uptr;\r
-\r
 }}
\ No newline at end of file
index 8709b1f35fd55e92683b5b0bb76f7b72d40e233c..f0ef051fff678c01a4d00738c3fea8823fddf601 100644 (file)
@@ -2,6 +2,7 @@
 \r
 #include "transform_frame.h"\r
 \r
+#include "producer_frame.h"\r
 #include "frame_shader.h"\r
 \r
 #include "../format/pixel_format.h"\r
@@ -16,24 +17,28 @@ namespace caspar { namespace core {
                                                                                                                                                                                                                                                                                                                \r
 struct transform_frame::implementation : boost::noncopyable\r
 {\r
-       implementation(const gpu_frame_ptr& frame) : frame_(frame), audio_volume_(255){}\r
+       implementation(const producer_frame& frame) : frame_(frame), audio_volume_(255), calculated_audio_volume_(audio_volume_){}\r
        \r
+       void begin_write(){frame_.begin_write();}\r
+       void end_write(){frame_.end_write();}\r
+\r
        void draw(frame_shader& shader)\r
        {\r
-               if(!frame_)\r
+               if(frame_ == producer_frame::empty() || frame_ == producer_frame::eof())\r
                        return;\r
 \r
                shader.begin(transform_);\r
-               frame_->draw(shader);\r
+               frame_.draw(shader);\r
                shader.end();\r
        }\r
 \r
        std::vector<short>& audio_data()\r
        {\r
-               if(!audio_data_.empty() || !frame_)\r
+               if(!audio_data_.empty() && calculated_audio_volume_ == audio_volume_)\r
                        return audio_data_;\r
                \r
-               audio_data_ = frame_->audio_data();\r
+               calculated_audio_volume_ = audio_volume_;\r
+               audio_data_ = frame_.audio_data();\r
                tbb::parallel_for\r
                (\r
                        tbb::blocked_range<size_t>(0, audio_data_.size()),\r
@@ -46,28 +51,17 @@ struct transform_frame::implementation : boost::noncopyable
                \r
                return audio_data_;\r
        }\r
-\r
-       void begin_write()\r
-       {\r
-               if(frame_)\r
-                       frame_->begin_write();\r
-       }\r
-\r
-       void end_write()\r
-       {\r
-               if(frame_)\r
-                       frame_->end_write();\r
-       }\r
                \r
        std::vector<short> audio_data_;\r
        \r
        shader_transform transform_;\r
-\r
+       \r
+       unsigned char calculated_audio_volume_;\r
        unsigned char audio_volume_;\r
-       gpu_frame_ptr frame_;\r
+       producer_frame frame_;\r
 };\r
        \r
-transform_frame::transform_frame(const gpu_frame_ptr& frame) : impl_(new implementation(frame)){}\r
+transform_frame::transform_frame(const producer_frame& frame) : impl_(new implementation(frame)){}\r
 void transform_frame::begin_write(){impl_->begin_write();}\r
 void transform_frame::end_write(){impl_->end_write();} \r
 void transform_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
index b4c2cc797347dfa68511599c684ed755cd2b33ba..7397c5d20beb2562e1b7b40805bc817ab7edc37e 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once\r
 \r
-#include "gpu_frame.h"\r
+#include "fwd.h"\r
 \r
 #include "../format/video_format.h"\r
 #include "../format/pixel_format.h"\r
 \r
 namespace caspar { namespace core {\r
                \r
-class transform_frame : public gpu_frame\r
+class transform_frame\r
 {\r
 public:\r
-       explicit transform_frame(const gpu_frame_ptr& frame);\r
+       explicit transform_frame(const producer_frame& frame);\r
        \r
-       virtual std::vector<short>& audio_data();\r
-       virtual const std::vector<short>& audio_data() const;\r
+       std::vector<short>& audio_data();\r
+       const std::vector<short>& audio_data() const;\r
 \r
        void audio_volume(unsigned char volume);\r
        void translate(double x, double y);\r
@@ -28,10 +28,9 @@ public:
        void video_mode(video_mode::type mode);\r
        void alpha(double value);\r
 \r
-protected:                     \r
-       virtual void begin_write();\r
-       virtual void end_write();\r
-       virtual void draw(frame_shader& shader);\r
+       void begin_write();\r
+       void end_write();\r
+       void draw(frame_shader& shader);\r
 \r
 private:\r
        struct implementation;\r
index 6fb31a9da39a65ba3549a6dcc0ce82a14f24532c..fe3d773d355098331fe307ed4401506fcc0218dc 100644 (file)
@@ -2,6 +2,7 @@
 \r
 #include "write_frame.h"\r
 \r
+#include "producer_frame.h"\r
 #include "frame_shader.h"\r
 \r
 #include "../format/pixel_format.h"\r
@@ -88,12 +89,12 @@ write_frame::write_frame(const pixel_format_desc& desc) : impl_(new implementati
 void write_frame::begin_write(){impl_->begin_write();}\r
 void write_frame::end_write(){impl_->end_write();}     \r
 void write_frame::draw(frame_shader& shader){impl_->draw(shader);}\r
-boost::iterator_range<unsigned char*> write_frame::data(size_t index)\r
+boost::iterator_range<unsigned char*> write_frame::pixel_data(size_t index)\r
 {\r
        auto ptr = static_cast<unsigned char*>(impl_->pixel_data_[index]);\r
        return boost::iterator_range<unsigned char*>(ptr, ptr+impl_->desc_.planes[index].size);\r
 }\r
-const boost::iterator_range<const unsigned char*> write_frame::data(size_t index) const\r
+const boost::iterator_range<const unsigned char*> write_frame::pixel_data(size_t index) const\r
 {\r
        auto ptr = static_cast<const unsigned char*>(impl_->pixel_data_[index]);\r
        return boost::iterator_range<const unsigned char*>(ptr, ptr+impl_->desc_.planes[index].size);\r
index e9518941cc89c900c25b2dce024345c4b08a4220..eb2b3fdfb2aeb52e6874210ba63743d244a6ed97 100644 (file)
@@ -2,8 +2,6 @@
 \r
 #include "fwd.h"\r
 \r
-#include "gpu_frame.h"\r
-\r
 #include "../format/video_format.h"\r
 #include "../format/pixel_format.h"\r
 \r
 \r
 namespace caspar { namespace core {\r
                \r
-class write_frame : public gpu_frame\r
+class write_frame\r
 {\r
-       friend class frame_renderer;\r
-       friend class frame_processor_device;\r
-\r
 public:        \r
-       boost::iterator_range<unsigned char*> data(size_t index = 0);\r
-       const boost::iterator_range<const unsigned char*> data(size_t index = 0) const;\r
-\r
-       virtual std::vector<short>& audio_data();\r
-       virtual const std::vector<short>& audio_data() const;\r
-       \r
-private:\r
        explicit write_frame(const pixel_format_desc& desc);\r
 \r
-       virtual void reset();\r
+       boost::iterator_range<unsigned char*> pixel_data(size_t index = 0);\r
+       const boost::iterator_range<const unsigned char*> pixel_data(size_t index = 0) const;\r
+\r
+       std::vector<short>& audio_data();\r
+       const std::vector<short>& audio_data() const;\r
+       \r
+       void reset();\r
                \r
-       virtual void begin_write();\r
-       virtual void end_write();\r
-       virtual void draw(frame_shader& shader);\r
+       void begin_write();\r
+       void end_write();\r
+       void draw(frame_shader& shader);\r
 \r
+private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
 };\r
index 37ced840288564a346119af41323c5c79feb08a5..45314db3cce9b67216fbad041574f7c80a13f1ed 100644 (file)
@@ -22,6 +22,7 @@
 \r
 #include "color_producer.h"\r
 \r
+#include "../../processor/producer_frame.h"\r
 #include "../../format/video_format.h"\r
 \r
 #include <intrin.h>\r
@@ -65,9 +66,9 @@ unsigned int get_pixel_color_value(const std::wstring& parameter)
 class color_producer : public frame_producer\r
 {\r
 public:\r
-       explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)){}\r
+       explicit color_producer(const std::wstring& color) : color_str_(color), color_value_(get_pixel_color_value(color)), frame_(producer_frame::empty()){}\r
        \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        { \r
                return frame_;\r
        }\r
@@ -75,7 +76,7 @@ public:
        void initialize(const frame_processor_device_ptr& frame_processor)\r
        {\r
                auto frame = frame_processor->create_frame();\r
-               __stosd(reinterpret_cast<unsigned long*>(frame->data().begin()), color_value_, frame->data().size() / sizeof(unsigned long));\r
+               __stosd(reinterpret_cast<unsigned long*>(frame->pixel_data().begin()), color_value_, frame->pixel_data().size() / sizeof(unsigned long));\r
                frame_ = frame;\r
        }\r
        \r
@@ -84,7 +85,7 @@ public:
                return + L"color_producer. color: " + color_str_;\r
        }\r
 \r
-       gpu_frame_ptr frame_;\r
+       producer_frame frame_;\r
        unsigned int color_value_;\r
        std::wstring color_str_;\r
 };\r
index 11c5e56963a7329bb049741d8663fbbd41aeb6d3..a6db77baf4172fd7024399425cfc3ce69a4d8beb 100644 (file)
@@ -28,6 +28,7 @@ extern "C"
 #include "video/video_transformer.h"\r
 \r
 #include "../../format/video_format.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../../common/utility/scope_exit.h"\r
 #include "../../server.h"\r
 \r
@@ -79,7 +80,7 @@ public:
                video_transformer_->initialize(frame_processor);\r
        }\r
                \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {\r
                while(ouput_channel_.empty() && !input_->is_eof())\r
                {       \r
@@ -110,8 +111,7 @@ public:
                                        CASPAR_LOG(warning) << "### File read underflow has STARTED.";\r
 \r
                                // Return last frame without audio.\r
-                               if(last_frame_)\r
-                                       last_frame_->audio_data().clear();\r
+                               //last_frame_.audio_data().clear(); TODO\r
                                return last_frame_;\r
                        }\r
                        else if(underrun_count_ > 0)\r
@@ -122,13 +122,13 @@ public:
 \r
                        while(!video_frame_channel_.empty() && (!audio_chunk_channel_.empty() || !has_audio_))\r
                        {\r
-                               if(has_audio_ && video_frame_channel_.front() != nullptr)\r
+                               if(has_audio_ && video_frame_channel_.front()\r
                                {\r
                                        video_frame_channel_.front()->audio_data() = std::move(audio_chunk_channel_.front());\r
                                        audio_chunk_channel_.pop_front();\r
                                }\r
                                \r
-                               gpu_frame_ptr frame = video_frame_channel_.front();\r
+                               auto frame = video_frame_channel_.front();\r
                                video_frame_channel_.pop_front();\r
                                ouput_channel_.push(std::move(frame));\r
                        }                               \r
@@ -140,7 +140,7 @@ public:
                        ouput_channel_.pop();\r
                }\r
                else if(input_->is_eof())\r
-                       last_frame_ = nullptr;\r
+                       last_frame_ = producer_frame::eof();\r
 \r
                return last_frame_;\r
        }\r
@@ -156,18 +156,18 @@ public:
 \r
        video_decoder_uptr                                      video_decoder_;\r
        video_transformer_uptr                          video_transformer_;\r
-       std::deque<gpu_frame_ptr>                       video_frame_channel_;\r
+       std::deque<transform_frame_ptr>         video_frame_channel_;\r
        \r
        audio_decoder_ptr                                       audio_decoder_;\r
        std::deque<std::vector<short>>          audio_chunk_channel_;\r
 \r
-       std::queue<gpu_frame_ptr>                       ouput_channel_;\r
+       std::queue<transform_frame_ptr>         ouput_channel_;\r
        \r
        std::wstring                                            filename_;\r
 \r
        long                                                            underrun_count_;\r
 \r
-       gpu_frame_ptr                                           last_frame_;\r
+       producer_frame                                          last_frame_;\r
 };\r
 \r
 frame_producer_ptr create_ffmpeg_producer(const  std::vector<std::wstring>& params)\r
index 51794294d36b9a57b0cc7b430ce03a84a10eb6f0..fb435ca85cc7d318134406b8d248f1fc24f41375 100644 (file)
@@ -5,6 +5,7 @@
 #include "../../../format/video_format.h"\r
 #include "../../../processor/write_frame.h"\r
 #include "../../../processor/transform_frame.h"\r
+#include "../../../processor/producer_frame.h"\r
 #include "../../../processor/frame_processor_device.h"\r
 \r
 #include <tbb/parallel_for.h>\r
@@ -104,7 +105,7 @@ struct video_transformer::implementation : boost::noncopyable
                }\r
        }\r
        \r
-       gpu_frame_ptr execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
+       transform_frame_ptr execute(const std::shared_ptr<AVFrame>& decoded_frame)\r
        {                               \r
                if(decoded_frame == nullptr)\r
                        return nullptr;\r
@@ -117,7 +118,7 @@ struct video_transformer::implementation : boost::noncopyable
                        tbb::parallel_for(0, static_cast<int>(desc_.planes.size()), 1, [&](int n)\r
                        {\r
                                auto plane            = desc_.planes[n];\r
-                               auto result           = result_frame->data(n).begin();\r
+                               auto result           = result_frame->pixel_data(n).begin();\r
                                auto decoded          = decoded_frame->data[n];\r
                                auto decoded_linesize = decoded_frame->linesize[n];\r
                                \r
@@ -133,20 +134,17 @@ struct video_transformer::implementation : boost::noncopyable
 \r
                        AVFrame av_frame;       \r
                        avcodec_get_frame_defaults(&av_frame);\r
-                       avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), result_frame->data().begin(), PIX_FMT_BGRA, width_, height_);\r
+                       avpicture_fill(reinterpret_cast<AVPicture*>(&av_frame), result_frame->pixel_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
-\r
+               \r
+               auto transform = std::make_shared<transform_frame>(result_frame);\r
                // TODO: Make generic for all formats and modes.\r
-               if(codec_context_->codec_id == CODEC_ID_DVVIDEO) // Move up one field\r
-               {\r
-                       auto transform = std::make_shared<transform_frame>(result_frame);\r
-                       transform->translate(0.0f, 1.0/static_cast<double>(frame_processor_->get_video_format_desc().height));\r
-                       return transform;\r
-               }\r
+               if(codec_context_->codec_id == CODEC_ID_DVVIDEO) // Move up one field           \r
+                       transform->translate(0.0f, 1.0/static_cast<double>(frame_processor_->get_video_format_desc().height));          \r
                \r
-               return result_frame;\r
+               return transform;\r
        }\r
        void initialize(const frame_processor_device_ptr& frame_processor)\r
        {\r
@@ -165,6 +163,6 @@ struct video_transformer::implementation : boost::noncopyable
 };\r
 \r
 video_transformer::video_transformer(AVCodecContext* codec_context) : impl_(new implementation(codec_context)){}\r
-gpu_frame_ptr video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
+transform_frame_ptr video_transformer::execute(const std::shared_ptr<AVFrame>& decoded_frame){return impl_->execute(decoded_frame);}\r
 void video_transformer::initialize(const frame_processor_device_ptr& frame_processor){impl_->initialize(frame_processor); }\r
 }}}
\ No newline at end of file
index a5e6ece22f5f25ba8504d41fc9b08492bdcadabb..c27ecf6f5698914388ae894be2762d7a61dd05d0 100644 (file)
@@ -13,7 +13,7 @@ class video_transformer : boost::noncopyable
 {\r
 public:\r
        video_transformer(AVCodecContext* codec_context);\r
-       gpu_frame_ptr execute(const std::shared_ptr<AVFrame>& video_packet);    \r
+       transform_frame_ptr execute(const std::shared_ptr<AVFrame>& video_packet);      \r
        void initialize(const frame_processor_device_ptr& frame_processor);\r
 private:\r
        struct implementation;\r
index c9e7c9c4282ca63b91abf123231fd33f59c963c7..2c2723f01353915c96d7a81ce5649721be7f4b77 100644 (file)
@@ -7,7 +7,7 @@
 #include "cg_producer.h"\r
 #include "flash_producer.h"\r
 \r
-#include "../../processor/write_frame.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../Server.h"\r
 \r
 #include <boost/filesystem.hpp>\r
@@ -146,9 +146,9 @@ public:
                flash_producer_->param(param.str());\r
        }\r
 \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {\r
-               return flash_producer_ ? flash_producer_->receive() : nullptr;\r
+               return flash_producer_ ? flash_producer_->receive() : producer_frame::empty();\r
        }\r
                \r
        void initialize(const frame_processor_device_ptr& frame_processor)\r
@@ -173,7 +173,7 @@ cg_producer_ptr get_default_cg_producer(const channel_ptr& channel, int render_l
        if(!channel)\r
                BOOST_THROW_EXCEPTION(null_argument() << msg_info("channel"));\r
        \r
-       auto producer = std::dynamic_pointer_cast<cg_producer>(channel->foreground(render_layer));\r
+       auto producer = std::dynamic_pointer_cast<cg_producer>(channel->foreground(render_layer).get());\r
        if(producer == nullptr)\r
        {\r
                producer = std::make_shared<cg_producer>();             \r
@@ -184,7 +184,7 @@ cg_producer_ptr get_default_cg_producer(const channel_ptr& channel, int render_l
 }\r
 \r
 cg_producer::cg_producer() : impl_(new implementation()){}\r
-gpu_frame_ptr cg_producer::receive(){return impl_->receive();}\r
+producer_frame cg_producer::receive(){return impl_->receive();}\r
 void cg_producer::clear(){impl_->clear();}\r
 void cg_producer::add(int layer, const std::wstring& template_name,  bool play_on_load, const std::wstring& startFromLabel, const std::wstring& data){impl_->add(layer, template_name, play_on_load, startFromLabel, data);}\r
 void cg_producer::remove(int layer){impl_->remove(layer);}\r
index b0778a42f1682e4ec77981f88cfdb54d00aaf37a..5b754181284933911fdf5286b4dd3916f7a0d09a 100644 (file)
@@ -13,7 +13,7 @@ public:
 \r
        cg_producer();\r
        \r
-       virtual gpu_frame_ptr receive();\r
+       virtual producer_frame receive();\r
        virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
 \r
        void clear();\r
index be5efa9f109fe1019ed8abbe7d7dd7d673a45b91..8b62ecacc8455e7c279de8a694667c17d3ee9aa8 100644 (file)
@@ -24,7 +24,7 @@
 \r
 #include "cg_producer.h"\r
 \r
-#include "../../processor/write_frame.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../server.h"\r
 \r
 #include <boost/assign/list_of.hpp>\r
@@ -37,7 +37,7 @@ struct ct_producer : public cg_producer
 {\r
        ct_producer(const std::wstring& filename) : filename_(filename), initialized_(false){}\r
 \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {\r
                if(!initialized_)\r
                {\r
index a0a1a65aac8d3f0d2e20b7a53086cf88f52fd4f0..5845e64cb10a4854d7bfc1e0a64d86774d3a285d 100644 (file)
@@ -34,7 +34,7 @@
 #include "../../../common/concurrency/executor.h"\r
 #include "../../../common/utility/scope_exit.h"\r
 \r
-#include "../../processor/write_frame.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../processor/composite_frame.h"\r
 \r
 #include <boost/assign.hpp>\r
@@ -182,7 +182,7 @@ struct flash_producer::implementation
                                stop();\r
 \r
                                frame_buffer_.clear();\r
-                               frame_buffer_.try_push(nullptr); // EOF\r
+                               frame_buffer_.try_push(producer_frame::eof()); // EOF\r
                \r
                                current_frame_ = nullptr;\r
                        });\r
@@ -225,14 +225,14 @@ struct flash_producer::implementation
                        auto format_desc = frame_processor_->get_video_format_desc();\r
                        bool is_progressive = format_desc.mode == video_mode::progressive || (flashax_container_->GetFPS() - format_desc.fps/2 == 0);\r
 \r
-                       gpu_frame_ptr result;\r
+                       producer_frame result;\r
 \r
                        if(is_progressive)                                                      \r
                                result = do_receive();          \r
                        else\r
                        {\r
-                               gpu_frame_ptr frame1 = do_receive();\r
-                               gpu_frame_ptr frame2 = do_receive();\r
+                               producer_frame frame1 = do_receive();\r
+                               producer_frame frame2 = do_receive();\r
                                result = composite_frame::interlace(frame1, frame2, format_desc.mode);\r
                        }\r
 \r
@@ -241,7 +241,7 @@ struct flash_producer::implementation
                }\r
        }\r
                \r
-       gpu_frame_ptr do_receive()\r
+       producer_frame do_receive()\r
        {\r
                auto format_desc = frame_processor_->get_video_format_desc();\r
 \r
@@ -255,20 +255,19 @@ struct flash_producer::implementation
                }       \r
 \r
                auto frame = frame_processor_->create_frame(format_desc.width, format_desc.height);\r
-               std::copy(current_frame_->data(), current_frame_->data() + current_frame_->size(), frame->data().begin());\r
+               std::copy(current_frame_->data(), current_frame_->data() + current_frame_->size(), frame->pixel_data().begin());\r
                return frame;\r
        }\r
                \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {               \r
-               return (frame_buffer_.try_pop(last_frame_) || !is_empty_) && last_frame_ ? last_frame_ : empty_;\r
+               return (frame_buffer_.try_pop(last_frame_) || !is_empty_) ? last_frame_ : producer_frame::empty();\r
        }\r
 \r
        void initialize(const frame_processor_device_ptr& frame_processor)\r
        {\r
                frame_processor_ = frame_processor;\r
                auto format_desc = frame_processor_->get_video_format_desc();\r
-               empty_ = frame_processor_->create_frame(pixel_format_desc());\r
                bmp_frame_ = std::make_shared<bitmap>(format_desc.width, format_desc.height);\r
                start(false);\r
        }\r
@@ -280,10 +279,9 @@ struct flash_producer::implementation
        \r
        CComObject<flash::FlashAxContainer>* flashax_container_;\r
                \r
-       tbb::concurrent_bounded_queue<gpu_frame_ptr> frame_buffer_;\r
+       tbb::concurrent_bounded_queue<producer_frame> frame_buffer_;\r
 \r
-       gpu_frame_ptr empty_;\r
-       gpu_frame_ptr last_frame_;\r
+       producer_frame last_frame_;\r
 \r
        bitmap_ptr current_frame_;\r
        bitmap_ptr bmp_frame_;\r
@@ -299,7 +297,7 @@ struct flash_producer::implementation
 };\r
 \r
 flash_producer::flash_producer(const std::wstring& filename) : impl_(new implementation(this, filename)){}\r
-gpu_frame_ptr flash_producer::receive(){return impl_->receive();}\r
+producer_frame flash_producer::receive(){return impl_->receive();}\r
 void flash_producer::param(const std::wstring& param){impl_->param(param);}\r
 void flash_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
 std::wstring flash_producer::print() const {return impl_->print();}\r
index 1e6fa7284668077d7b04e1dbbcad5cde920c6ed2..af67fe0ec7292a9465b8c132842a51bbe6ce28c6 100644 (file)
@@ -38,7 +38,7 @@ public:
 \r
        flash_producer(const std::wstring& filename);\r
 \r
-       virtual gpu_frame_ptr receive();\r
+       virtual producer_frame receive();\r
        virtual void initialize(const frame_processor_device_ptr& frame_processor);\r
        virtual std::wstring print() const;\r
 \r
index f2644735ecbbf813ecea90ee5fd330eddcfbd66e..3efae50c21f62a6d9af5adecde5eec58974ce494 100644 (file)
@@ -34,7 +34,7 @@ public:
        virtual ~frame_producer(){}     \r
 \r
        ////////////////////////////////////////////////////////////////////////////////////////////////////\r
-       /// \fn virtual gpu_frame_ptr :::receive() = 0;\r
+       /// \fn virtual producer_frame :::receive() = 0;\r
        ///\r
        /// \brief      Renders a frame.\r
        ///             \r
@@ -42,7 +42,7 @@ public:
        ///\r
        /// \return     The frame. \r
        ////////////////////////////////////////////////////////////////////////////////////////////////////\r
-       virtual gpu_frame_ptr receive() = 0;\r
+       virtual producer_frame receive() = 0;\r
 \r
        ////////////////////////////////////////////////////////////////////////////////////////////////////\r
        /// \fn virtual std::shared_ptr<frame_producer> :::get_following_producer() const\r
index fef0d47e8309160189e2d6606c59d29881a34afa..3f6319d6610b0a839335f92357f128dcb40945d2 100644 (file)
@@ -6,8 +6,10 @@
 \r
 #include "../format/video_format.h"\r
 #include "../processor/composite_frame.h"\r
+#include "../processor/producer_frame.h"\r
 \r
 #include "../../common/utility/scope_exit.h"\r
+#include "../../common/concurrency/executor.h"\r
 \r
 #include <boost/thread.hpp>\r
 #include <boost/range/algorithm_ext/erase.hpp>\r
@@ -20,9 +22,9 @@
        \r
 namespace caspar { namespace core {\r
        \r
-std::vector<gpu_frame_ptr> receives(std::map<int, layer>& layers)\r
+std::vector<producer_frame> receives(std::map<int, layer>& layers)\r
 {      \r
-       std::vector<gpu_frame_ptr> frames(layers.size(), nullptr);\r
+       std::vector<producer_frame> frames(layers.size(), producer_frame::empty());\r
        tbb::parallel_for(tbb::blocked_range<size_t>(0, frames.size()), \r
        [&](const tbb::blocked_range<size_t>& r)\r
        {\r
@@ -36,114 +38,113 @@ std::vector<gpu_frame_ptr> receives(std::map<int, layer>& layers)
 \r
 struct frame_producer_device::implementation : boost::noncopyable\r
 {      \r
-       implementation(const frame_processor_device_ptr& frame_processor)  \r
-               : frame_processor_(frame_processor)\r
+       implementation(const frame_processor_device_ptr& frame_processor)  : frame_processor_(frame_processor)\r
        {\r
-               render_thread_ = boost::thread([=]{run();});\r
+               executor_.start();\r
+               executor_.begin_invoke([=]{tick();});\r
        }\r
-                       \r
-       ~implementation()\r
-       {\r
-               is_running_ = false;\r
-               render_thread_.join();\r
-       }\r
-               \r
-       void run()\r
+                                       \r
+       void tick()\r
        {               \r
-               win32_exception::install_handler();\r
-               \r
-               is_running_ = true;\r
-               while(is_running_)\r
+               try\r
+               {       \r
+                       frame_processor_->send(std::make_shared<composite_frame>(receives(layers_)));\r
+               }\r
+               catch(...)\r
                {\r
-                       try\r
-                       {       \r
-                               std::vector<gpu_frame_ptr> frames;\r
-                               {\r
-                                       tbb::mutex::scoped_lock lock(layers_mutex_);    \r
-                                       frames = receives(layers_);\r
-                               }                               \r
-                               frame_processor_->send(std::make_shared<composite_frame>(frames));\r
-                       }\r
-                       catch(...)\r
-                       {\r
-                               try\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       layers_.clear();\r
-                                       CASPAR_LOG(error) << "Unexpected exception. Cleared layers in render-device";\r
-                               }\r
-                               catch(...){}\r
-                       }\r
+                       CASPAR_LOG_CURRENT_EXCEPTION();\r
+                       layers_.clear();\r
+                       CASPAR_LOG(error) << "Unexpected exception. Cleared layers in render-device";\r
                }\r
+               executor_.begin_invoke([=]{tick();});\r
        }\r
 \r
        void load(int render_layer, const frame_producer_ptr& producer, load_option::type option)\r
        {\r
                producer->initialize(frame_processor_);\r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               layers_[render_layer].load(producer, option);\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       layers_[render_layer].load(producer, option);\r
+               });\r
        }\r
                        \r
        void pause(int render_layer)\r
        {               \r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               if(it != layers_.end())\r
-                       it->second.pause();             \r
+               executor_.begin_invoke([=]\r
+               {                       \r
+                       auto it = layers_.find(render_layer);\r
+                       if(it != layers_.end())\r
+                               it->second.pause();             \r
+               });\r
        }\r
 \r
        void play(int render_layer)\r
        {               \r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               if(it != layers_.end())\r
-                       it->second.play();              \r
+               executor_.begin_invoke([=]\r
+               {\r
+                       auto it = layers_.find(render_layer);\r
+                       if(it != layers_.end())\r
+                               it->second.play();              \r
+               });\r
        }\r
 \r
        void stop(int render_layer)\r
        {               \r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               if(it != layers_.end())\r
-                       it->second.stop();\r
+               executor_.begin_invoke([=]\r
+               {\r
+                       auto it = layers_.find(render_layer);\r
+                       if(it != layers_.end())\r
+                       {\r
+                               it->second.stop();\r
+                               if(!it->second.background())\r
+                                       layers_.erase(it);\r
+                       }\r
+               });\r
        }\r
 \r
        void clear(int render_layer)\r
        {\r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               if(it != layers_.end())\r
-                       it->second.clear();             \r
+               executor_.begin_invoke([=]\r
+               {                       \r
+                       auto it = layers_.find(render_layer);\r
+                       if(it != layers_.end())\r
+                       {\r
+                               it->second.clear();             \r
+                               layers_.erase(it);\r
+                       }\r
+               });\r
        }\r
                \r
        void clear()\r
        {\r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               layers_.clear();\r
+               executor_.begin_invoke([=]\r
+               {                       \r
+                       layers_.clear();\r
+               });\r
        }               \r
 \r
-       frame_producer_ptr foreground(int render_layer) const\r
+       boost::unique_future<frame_producer_ptr> foreground(int render_layer) const\r
        {\r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               return it != layers_.end() ? it->second.foreground() : nullptr;\r
+               return executor_.begin_invoke([=]() -> frame_producer_ptr\r
+               {                       \r
+                       auto it = layers_.find(render_layer);\r
+                       return it != layers_.end() ? it->second.foreground() : nullptr;\r
+               });\r
        }\r
        \r
-       frame_producer_ptr background(int render_layer) const\r
+       boost::unique_future<frame_producer_ptr> background(int render_layer) const\r
        {\r
-               tbb::mutex::scoped_lock lock(layers_mutex_);\r
-               auto it = layers_.find(render_layer);\r
-               return it != layers_.end() ? it->second.background() : nullptr;\r
+               return executor_.begin_invoke([=]() -> frame_producer_ptr\r
+               {\r
+                       auto it = layers_.find(render_layer);\r
+                       return it != layers_.end() ? it->second.background() : nullptr;\r
+               });\r
        }\r
+       mutable common::executor executor_;\r
                                \r
        frame_processor_device_ptr frame_processor_;\r
-\r
-       boost::thread render_thread_;\r
-                                       \r
-       mutable tbb::mutex layers_mutex_;\r
-       std::map<int, layer> layers_;\r
-       \r
-       tbb::atomic<bool> is_running_;          \r
+                                               \r
+       std::map<int, layer> layers_;           \r
 };\r
 \r
 frame_producer_device::frame_producer_device(const frame_processor_device_ptr& frame_processor) \r
@@ -154,6 +155,6 @@ void frame_producer_device::play(int render_layer){impl_->play(render_layer);}
 void frame_producer_device::stop(int render_layer){impl_->stop(render_layer);}\r
 void frame_producer_device::clear(int render_layer){impl_->clear(render_layer);}\r
 void frame_producer_device::clear(){impl_->clear();}\r
-frame_producer_ptr frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
-frame_producer_ptr frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\r
+boost::unique_future<frame_producer_ptr> frame_producer_device::foreground(int render_layer) const {return impl_->foreground(render_layer);}\r
+boost::unique_future<frame_producer_ptr> frame_producer_device::background(int render_layer) const {return impl_->background(render_layer);}\r
 }}\r
index f586a849514466e1f7d9c2e1c79c33c75e39947c..bc400233f5ea1b860fe77a8763f8771d48bba868 100644 (file)
@@ -6,6 +6,8 @@
 \r
 #include "layer.h"\r
 \r
+#include <boost/thread.hpp>\r
+\r
 #include <functional>\r
 \r
 namespace caspar { namespace core {\r
@@ -22,8 +24,8 @@ public:
        void clear(int render_layer);\r
        void clear();\r
        \r
-       frame_producer_ptr foreground(int render_layer) const;\r
-       frame_producer_ptr background(int render_layer) const;\r
+       boost::unique_future<frame_producer_ptr> foreground(int render_layer) const;\r
+       boost::unique_future<frame_producer_ptr> background(int render_layer) const;\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index 25096bf3610e12746b12e3727c5d158cdec1bc39..b4303f875a00eebd339ba5708255e06a26f4fd6f 100644 (file)
@@ -4,6 +4,7 @@
 #include "image_loader.h"\r
 \r
 #include "../../processor/frame_processor_device.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../format/video_format.h"\r
 #include "../../server.h"\r
 \r
@@ -19,7 +20,7 @@ struct image_producer : public frame_producer
 {\r
        image_producer(const std::wstring& filename) : filename_(filename)      {}\r
        \r
-       gpu_frame_ptr receive(){return frame_;}\r
+       producer_frame receive(){return frame_;}\r
 \r
        void initialize(const frame_processor_device_ptr& frame_processor)\r
        {\r
@@ -27,7 +28,7 @@ struct image_producer : public frame_producer
                auto bitmap = load_image(filename_);\r
                FreeImage_FlipVertical(bitmap.get());\r
                auto frame = frame_processor->create_frame(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()));\r
-               std::copy_n(FreeImage_GetBits(bitmap.get()), frame->data().size(), frame->data().begin());\r
+               std::copy_n(FreeImage_GetBits(bitmap.get()), frame->pixel_data().size(), frame->pixel_data().begin());\r
                frame_ = frame;\r
        }\r
 \r
@@ -38,7 +39,7 @@ struct image_producer : public frame_producer
        \r
        frame_processor_device_ptr frame_processor_;\r
        std::wstring filename_;\r
-       gpu_frame_ptr frame_;\r
+       producer_frame frame_;\r
 };\r
 \r
 frame_producer_ptr create_image_producer(const  std::vector<std::wstring>& params)\r
index 873e9bf12033a2968020477e9cd7cf7d31ee24ac..b899c0bb6b3a71eb464707bfb112460c0a0f7bcc 100644 (file)
@@ -4,7 +4,7 @@
 \r
 #include "image_loader.h"\r
 \r
-#include "../../processor/write_frame.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../processor/composite_frame.h"\r
 #include "../../format/video_format.h"\r
 #include "../../processor/frame_processor_device.h"\r
@@ -67,15 +67,15 @@ struct image_scroll_producer : public frame_producer
                        std::copy_n(&pBits[i* width * 4], width * 4, &image_.get()[i * image_width_ * 4]);\r
        }\r
 \r
-       gpu_frame_ptr do_receive()\r
+       producer_frame do_receive()\r
        {\r
                auto frame = frame_processor_->create_frame(format_desc_.width, format_desc_.height);\r
-               std::fill(frame->data().begin(), frame->data().end(), 0);\r
+               std::fill(frame->pixel_data().begin(), frame->pixel_data().end(), 0);\r
 \r
                const int delta_x = direction_ == direction::Left ? speed_ : -speed_;\r
                const int delta_y = direction_ == direction::Up ? speed_ : -speed_;\r
 \r
-               unsigned char* frame_data = frame->data().begin();\r
+               unsigned char* frame_data = frame->pixel_data().begin();\r
                unsigned char* image_data = image_.get();\r
        \r
                if (direction_ == direction::Up || direction_ == direction::Down)\r
@@ -112,12 +112,12 @@ struct image_scroll_producer : public frame_producer
                return frame;\r
        }\r
                \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {               \r
                if(format_desc_.mode != video_mode::progressive)                                \r
                {\r
-                       gpu_frame_ptr frame1;\r
-                       gpu_frame_ptr frame2;\r
+                       producer_frame frame1;\r
+                       producer_frame frame2;\r
                        tbb::parallel_invoke([&]{ frame1 = do_receive(); }, [&]{ frame2 = do_receive(); });\r
                        return composite_frame::interlace(frame1, frame2, format_desc_.mode);\r
                }                       \r
index 5d362075dcee198e674227170d2780111a494b69..fe9d688adece23d1cdb0be51bc09689b0fd08e3a 100644 (file)
@@ -2,6 +2,7 @@
 \r
 #include "layer.h"\r
 \r
+#include "../processor/producer_frame.h"\r
 #include "../producer/frame_producer.h"\r
 \r
 #include "../format/video_format.h"\r
@@ -10,13 +11,10 @@ namespace caspar { namespace core {
 \r
 struct layer::implementation\r
 {              \r
-       implementation() : foreground_(nullptr), background_(nullptr), last_frame_(nullptr) {}\r
+       implementation() : foreground_(nullptr), background_(nullptr), last_frame_(producer_frame::empty()) {}\r
        \r
        void load(const frame_producer_ptr& frame_producer, load_option::type option)\r
-       {\r
-               if(frame_producer == nullptr) \r
-                       BOOST_THROW_EXCEPTION(null_argument() << arg_name_info("frame_producer"));\r
-                       \r
+       {                       \r
                background_ = frame_producer;\r
                if(option == load_option::preview)              \r
                {\r
@@ -46,17 +44,17 @@ struct layer::implementation
        void stop()\r
        {\r
                foreground_ = nullptr;\r
-               last_frame_ = nullptr;\r
+               last_frame_ = producer_frame::empty();\r
        }\r
 \r
        void clear()\r
        {\r
                foreground_ = nullptr;\r
                background_ = nullptr;\r
-               last_frame_ = nullptr;\r
+               last_frame_ = producer_frame::empty();\r
        }\r
        \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {               \r
                if(!foreground_ || is_paused_)\r
                        return last_frame_;\r
@@ -65,7 +63,7 @@ struct layer::implementation
                {\r
                        last_frame_ = foreground_->receive();\r
 \r
-                       if(last_frame_ == nullptr)\r
+                       if(last_frame_ == producer_frame::eof())\r
                        {\r
                                CASPAR_LOG(info) << L"EOF: " << foreground_->print();\r
                                auto following = foreground_->get_following_producer();\r
@@ -81,7 +79,7 @@ struct layer::implementation
                                CASPAR_LOG_CURRENT_EXCEPTION();\r
                                CASPAR_LOG(warning) << L"Removed " << (foreground_ ? foreground_->print() : L"empty") << L" from layer.";\r
                                foreground_ = nullptr;\r
-                               last_frame_ = nullptr;\r
+                               last_frame_ = producer_frame::empty();\r
                        }\r
                        catch(...){}\r
                }\r
@@ -90,7 +88,7 @@ struct layer::implementation
        }       \r
                \r
        tbb::atomic<bool>       is_paused_;\r
-       gpu_frame_ptr                   last_frame_;\r
+       producer_frame          last_frame_;\r
        frame_producer_ptr      foreground_;\r
        frame_producer_ptr      background_;\r
 };\r
@@ -108,7 +106,7 @@ void layer::play(){impl_->play();}
 void layer::pause(){impl_->pause();}\r
 void layer::stop(){impl_->stop();}\r
 void layer::clear(){impl_->clear();}\r
-gpu_frame_ptr layer::receive() {return impl_->receive();}\r
+producer_frame layer::receive() {return impl_->receive();}\r
 frame_producer_ptr layer::foreground() const { return impl_->foreground_;}\r
 frame_producer_ptr layer::background() const { return impl_->background_;}\r
 }}
\ No newline at end of file
index 881c8f0c08cae4b904fe5c8ece8b8f928f0f4321..584ad574c30be87b834fb3bfcf80d0476ee73a1c 100644 (file)
@@ -32,7 +32,7 @@ public:
        frame_producer_ptr foreground() const;\r
        frame_producer_ptr background() const;\r
 \r
-       gpu_frame_ptr receive();\r
+       producer_frame receive();\r
 private:\r
        struct implementation;\r
        std::shared_ptr<implementation> impl_;\r
index d0c6bcf975ee6b224615b9e82142d3fb19433ba2..1fa5e71b2f9cd4a28eeab07d53660ba070608baa 100644 (file)
@@ -22,6 +22,7 @@
 #include "transition_producer.h"\r
 \r
 #include "../../format/video_format.h"\r
+#include "../../processor/producer_frame.h"\r
 #include "../../processor/composite_frame.h"\r
 #include "../../processor/transform_frame.h"\r
 #include "../../processor/frame_processor_device.h"\r
@@ -51,18 +52,18 @@ struct transition_producer::implementation : boost::noncopyable
                org_source_producer_ = source_producer_ = producer;\r
        }\r
                \r
-       gpu_frame_ptr receive()\r
+       producer_frame receive()\r
        {\r
                if(current_frame_ == 0)\r
                        CASPAR_LOG(info) << "Transition started.";\r
 \r
-               gpu_frame_ptr result = [&]() -> gpu_frame_ptr\r
+               producer_frame result = [&]() -> producer_frame\r
                {\r
                        if(current_frame_++ >= info_.duration)\r
-                               return nullptr;\r
+                               return producer_frame::eof();\r
 \r
-                       gpu_frame_ptr source;\r
-                       gpu_frame_ptr dest;\r
+                       producer_frame source;\r
+                       producer_frame dest;\r
 \r
                        tbb::parallel_invoke\r
                        (\r
@@ -73,18 +74,18 @@ struct transition_producer::implementation : boost::noncopyable
                        return compose(dest, source);\r
                }();\r
 \r
-               if(!result)\r
+               if(result == producer_frame::eof())\r
                        CASPAR_LOG(info) << "Transition ended.";\r
 \r
                return result;\r
        }\r
 \r
-       gpu_frame_ptr receive(frame_producer_ptr& producer)\r
+       producer_frame receive(frame_producer_ptr& producer)\r
        {\r
                if(!producer)\r
-                       return nullptr;\r
+                       return producer_frame::eof();\r
 \r
-               gpu_frame_ptr frame;\r
+               producer_frame frame = producer_frame::eof();\r
                try\r
                {\r
                        frame = producer->receive();\r
@@ -96,10 +97,10 @@ struct transition_producer::implementation : boost::noncopyable
                        CASPAR_LOG(warning) << "Removed producer from transition.";\r
                }\r
 \r
-               if(frame == nullptr)\r
+               if(frame == producer_frame::eof())\r
                {\r
                        if(!producer || !producer->get_following_producer())\r
-                               return nullptr;\r
+                               return producer_frame::eof();\r
 \r
                        try\r
                        {\r
@@ -119,10 +120,10 @@ struct transition_producer::implementation : boost::noncopyable
                return frame;\r
        }\r
                                        \r
-       gpu_frame_ptr compose(gpu_frame_ptr dest_frame, gpu_frame_ptr src_frame) \r
+       producer_frame compose(producer_frame dest_frame, producer_frame src_frame) \r
        {       \r
-               if(!dest_frame && !src_frame)\r
-                       return nullptr;\r
+               if(dest_frame == producer_frame::eof() && src_frame == producer_frame::eof())\r
+                       return producer_frame::eof();\r
 \r
                if(info_.type == transition::cut)               \r
                        return src_frame;\r
@@ -180,7 +181,7 @@ struct transition_producer::implementation : boost::noncopyable
 };\r
 \r
 transition_producer::transition_producer(const frame_producer_ptr& dest, const transition_info& info) : impl_(new implementation(dest, info)){}\r
-gpu_frame_ptr transition_producer::receive(){return impl_->receive();}\r
+producer_frame transition_producer::receive(){return impl_->receive();}\r
 frame_producer_ptr transition_producer::get_following_producer() const{return impl_->get_following_producer();}\r
 void transition_producer::set_leading_producer(const frame_producer_ptr& producer) { impl_->set_leading_producer(producer); }\r
 void transition_producer::initialize(const frame_processor_device_ptr& frame_processor) { impl_->initialize(frame_processor);}\r
index 9f90a779a1897555d596bd0658211af9a06b8757..f1815db2ab2014d5060aa210c818048637f03aee 100644 (file)
@@ -62,7 +62,7 @@ class transition_producer : public frame_producer
 public:\r
        transition_producer(const frame_producer_ptr& destination, const transition_info& info);\r
 \r
-       gpu_frame_ptr receive();\r
+       producer_frame receive();\r
 \r
        frame_producer_ptr get_following_producer() const;\r
        void set_leading_producer(const frame_producer_ptr& producer);\r
index 6f9f00def13b76149dc598264f8ca4479d77b93b..ebefa9bafb813a1110d4a864351f25cebff6e99b 100644 (file)
@@ -729,7 +729,7 @@ bool CinfCommand::DoExecute()
 \r
 void GenerateChannelInfo(int index, const channel_ptr& pChannel, std::wstringstream& replyString)\r
 {\r
-       replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name  << TEXT("\r\n") << (pChannel->foreground(0) != nullptr ? TEXT(" PLAYING") : TEXT(" STOPPED"));\r
+       replyString << index << TEXT(" ") << pChannel->get_video_format_desc().name  << TEXT("\r\n") << (pChannel->foreground(0).get() != nullptr ? TEXT(" PLAYING") : TEXT(" STOPPED"));\r
 }\r
 \r
 bool InfoCommand::DoExecute()\r