]> git.sesse.net Git - casparcg/blobdiff - core/consumer/output.cpp
2.0. stage: Changed error handling.
[casparcg] / core / consumer / output.cpp
index 23661e09fdd5b05014e97077767d2056f7282dbb..426013cac5e63790167c084bbfa36fac45b788ce 100644 (file)
@@ -17,6 +17,7 @@
 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
 *\r
 */\r
+// TODO: Try to recover consumer from bad_alloc...\r
 #include "../StdAfx.h"\r
 \r
 #ifdef _MSC_VER\r
 #include <common/utility/timer.h>\r
 #include <common/memory/memshfl.h>\r
 \r
+#include <tbb/mutex.h>\r
+\r
 namespace caspar { namespace core {\r
-       \r
+\r
 struct output::implementation\r
 {      \r
-       typedef std::pair<safe_ptr<const read_frame>, safe_ptr<const read_frame>> fill_and_key;\r
+       typedef std::pair<safe_ptr<read_frame>, safe_ptr<read_frame>> fill_and_key;\r
        \r
-       video_channel_context& channel_;\r
+       video_channel_context&          channel_;\r
+       const std::function<void()> restart_channel_;\r
 \r
        std::map<int, safe_ptr<frame_consumer>> consumers_;\r
        typedef std::map<int, safe_ptr<frame_consumer>>::value_type layer_t;\r
@@ -50,15 +54,23 @@ struct output::implementation
        high_prec_timer timer_;\r
                \r
 public:\r
-       implementation(video_channel_context& video_channel) \r
-               : channel_(video_channel){}     \r
+       implementation(video_channel_context& video_channel, const std::function<void()>& restart_channel) \r
+               : channel_(video_channel)\r
+               , restart_channel_(restart_channel)\r
+       {\r
+       }       \r
        \r
        void add(int index, safe_ptr<frame_consumer>&& consumer)\r
        {               \r
-               consumer->initialize(channel_.get_format_desc());\r
                channel_.execution().invoke([&]\r
                {\r
                        consumers_.erase(index);\r
+               });\r
+\r
+               consumer->initialize(channel_.get_format_desc());\r
+\r
+               channel_.execution().invoke([&]\r
+               {\r
                        consumers_.insert(std::make_pair(index, consumer));\r
 \r
                        CASPAR_LOG(info) << print() << L" " << consumer->print() << L" Added.";\r
@@ -79,44 +91,60 @@ public:
        }\r
                                                \r
        void execute(const safe_ptr<read_frame>& frame)\r
-       {               \r
-               try\r
-               {               \r
-                       if(!has_synchronization_clock())\r
-                               timer_.tick(1.0/channel_.get_format_desc().fps);\r
-                                               \r
-                       auto fill = frame;\r
-                       auto key = get_key_frame(frame);\r
+       {                       \r
+               if(!has_synchronization_clock())\r
+                       timer_.tick(1.0/channel_.get_format_desc().fps);\r
 \r
-                       auto it = consumers_.begin();\r
-                       while(it != consumers_.end())\r
+               if(frame->image_size() != channel_.get_format_desc().size)\r
+               {\r
+                       timer_.tick(1.0/channel_.get_format_desc().fps);\r
+                       return;\r
+               }\r
+               \r
+               auto it = consumers_.begin();\r
+               while(it != consumers_.end())\r
+               {\r
+                       auto consumer = it->second;\r
+\r
+                       if(consumer->get_video_format_desc() != channel_.get_format_desc())\r
+                               consumer->initialize(channel_.get_format_desc());\r
+\r
+                       try\r
+                       {\r
+                               if(consumer->send(frame))\r
+                                       ++it;\r
+                               else\r
+                                       consumers_.erase(it++);\r
+                       }\r
+                       catch(...)\r
                        {\r
+                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                               CASPAR_LOG(warning) << "Trying to restart consumer: " << consumer->print() << L".";\r
                                try\r
                                {\r
-                                       auto consumer = it->second;\r
+                                       consumer->initialize(channel_.get_format_desc());\r
+                                       consumer->send(frame);\r
+                               }\r
+                               catch(...)\r
+                               {       \r
+                                       CASPAR_LOG_CURRENT_EXCEPTION(); \r
+                                       CASPAR_LOG(warning) << "Consumer restart failed, trying to restart channel: " << consumer->print() << L".";     \r
 \r
-                                       if(consumer->get_video_format_desc() != channel_.get_format_desc())\r
+                                       try\r
+                                       {\r
+                                               restart_channel_();\r
                                                consumer->initialize(channel_.get_format_desc());\r
-\r
-                                       auto frame = consumer->key_only() ? key : fill;\r
-\r
-                                       if(static_cast<size_t>(frame->image_data().size()) == consumer->get_video_format_desc().size)\r
                                                consumer->send(frame);\r
-\r
-                                       ++it;\r
-                               }\r
-                               catch(...)\r
-                               {\r
-                                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-                                       CASPAR_LOG(error) << print() << L" " << it->second->print() << L" Removed.";\r
-                                       consumers_.erase(it++);\r
+                                       }\r
+                                       catch(...)\r
+                                       {\r
+                                               CASPAR_LOG_CURRENT_EXCEPTION();\r
+                                               CASPAR_LOG(error) << "Failed to recover consumer: " << consumer->print() << L". Removing it.";\r
+                                               consumers_.erase(it++);\r
+                                       }\r
                                }\r
                        }\r
                }\r
-               catch(...)\r
-               {\r
-                       CASPAR_LOG_CURRENT_EXCEPTION();\r
-               }\r
        }\r
 \r
 private:\r
@@ -128,25 +156,6 @@ private:
                        return p.second->has_synchronization_clock();\r
                });\r
        }\r
-\r
-       safe_ptr<const read_frame> get_key_frame(const safe_ptr<const read_frame>& frame)\r
-       {\r
-               bool has_key_only = std::any_of(consumers_.begin(), consumers_.end(), [](const decltype(*consumers_.begin())& p)\r
-               {\r
-                       return p.second->key_only();\r
-               });\r
-\r
-               if(has_key_only)\r
-               {\r
-                       // Currently do key_only transform on cpu. Unsure if the extra 400MB/s (1080p50) overhead is worth it to do it on gpu.\r
-                       auto key_data = channel_.ogl().create_host_buffer(frame->image_data().size(), host_buffer::write_only);                         \r
-                       fast_memsfhl(key_data->data(), frame->image_data().begin(), frame->image_data().size(), 0x0F0F0F0F, 0x0B0B0B0B, 0x07070707, 0x03030303);\r
-                       std::vector<int16_t> audio_data(frame->audio_data().begin(), frame->audio_data().end());\r
-                       return make_safe<read_frame>(std::move(key_data), std::move(audio_data));\r
-               }\r
-               \r
-               return make_safe<read_frame>();\r
-       }\r
        \r
        std::wstring print() const\r
        {\r
@@ -154,7 +163,7 @@ private:
        }\r
 };\r
 \r
-output::output(video_channel_context& video_channel) : impl_(new implementation(video_channel)){}\r
+output::output(video_channel_context& video_channel, const std::function<void()>& restart_channel) : impl_(new implementation(video_channel, restart_channel)){}\r
 void output::add(int index, safe_ptr<frame_consumer>&& consumer){impl_->add(index, std::move(consumer));}\r
 void output::remove(int index){impl_->remove(index);}\r
 void output::execute(const safe_ptr<read_frame>& frame) {impl_->execute(frame); }\r