]> git.sesse.net Git - casparcg/blobdiff - core/producer/channel/channel_producer.cpp
Fixed bug in channel_producer
[casparcg] / core / producer / channel / channel_producer.cpp
index 392ddb31cc82eff0b803c7ee1d9bf07d5424e553..98d845ca0880f5986a5199cfe5138e79ac26418c 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
-* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+* Copyright 2013 Sveriges Television AB http://casparcg.com/\r
 *\r
 * This file is part of CasparCG (www.casparcg.com).\r
 *\r
@@ -23,6 +23,7 @@
 \r
 #include "channel_producer.h"\r
 \r
+#include "../../monitor/monitor.h"\r
 #include "../../consumer/frame_consumer.h"\r
 #include "../../consumer/output.h"\r
 #include "../../video_channel.h"\r
@@ -33,6 +34,8 @@
 #include "../../mixer/read_frame.h"\r
 \r
 #include <common/exception/exceptions.h>\r
+#include <common/memory/memcpy.h>\r
+#include <common/concurrency/future_util.h>\r
 \r
 #include <tbb/concurrent_queue.h>\r
 \r
@@ -40,16 +43,18 @@ namespace caspar { namespace core {
 \r
 class channel_consumer : public frame_consumer\r
 {      \r
-       tbb::concurrent_bounded_queue<std::shared_ptr<read_frame>> frame_buffer_;\r
-       core::video_format_desc format_desc_;\r
-       int                                             channel_index_;\r
-       tbb::atomic<bool>               is_running_;\r
+       tbb::concurrent_bounded_queue<std::shared_ptr<read_frame>>      frame_buffer_;\r
+       core::video_format_desc                                                                         format_desc_;\r
+       int                                                                                                                     channel_index_;\r
+       tbb::atomic<bool>                                                                                       is_running_;\r
+       tbb::atomic<int64_t>                                                                            current_age_;\r
 \r
 public:\r
        channel_consumer() \r
        {\r
                is_running_ = true;\r
-               frame_buffer_.set_capacity(2);\r
+               current_age_ = 0;\r
+               frame_buffer_.set_capacity(3);\r
        }\r
 \r
        ~channel_consumer()\r
@@ -59,16 +64,21 @@ public:
 \r
        // frame_consumer\r
 \r
-       virtual bool send(const safe_ptr<read_frame>& frame) override\r
+       virtual boost::unique_future<bool> send(const safe_ptr<read_frame>& frame) override\r
        {\r
                frame_buffer_.try_push(frame);\r
-               return is_running_;\r
+               return caspar::wrap_as_future(is_running_.load());\r
        }\r
 \r
        virtual void initialize(const core::video_format_desc& format_desc, int channel_index) override\r
        {\r
                format_desc_    = format_desc;\r
-               channel_index_ = channel_index;\r
+               channel_index_  = channel_index;\r
+       }\r
+\r
+       virtual int64_t presentation_frame_age_millis() const override\r
+       {\r
+               return current_age_;\r
        }\r
 \r
        virtual std::wstring print() const override\r
@@ -117,24 +127,31 @@ public:
                if(!is_running_)\r
                        return make_safe<read_frame>();\r
                std::shared_ptr<read_frame> frame;\r
-               frame_buffer_.try_pop(frame);\r
+               \r
+               if (frame_buffer_.try_pop(frame))\r
+                       current_age_ = frame->get_age_millis();\r
+\r
                return frame;\r
        }\r
 };\r
        \r
 class channel_producer : public frame_producer\r
 {\r
+       monitor::subject                                        monitor_subject_;\r
+\r
        const safe_ptr<frame_factory>           frame_factory_;\r
        const safe_ptr<channel_consumer>        consumer_;\r
 \r
        std::queue<safe_ptr<basic_frame>>       frame_buffer_;\r
        safe_ptr<basic_frame>                           last_frame_;\r
+       uint64_t                                                        frame_number_;\r
 \r
 public:\r
        explicit channel_producer(const safe_ptr<frame_factory>& frame_factory, const safe_ptr<video_channel>& channel) \r
                : frame_factory_(frame_factory)\r
                , consumer_(make_safe<channel_consumer>())\r
                , last_frame_(basic_frame::empty())\r
+               , frame_number_(0)\r
        {\r
                channel->output()->add(consumer_);\r
                CASPAR_LOG(info) << print() << L" Initialized";\r
@@ -152,16 +169,7 @@ public:
        {\r
                auto format_desc = consumer_->get_video_format_desc();\r
 \r
-               bool half_speed = std::abs(format_desc.fps / 2.0 - frame_factory_->get_video_format_desc().fps) < 0.01;\r
-               \r
-               if(half_speed && frame_buffer_.size() >= 2)\r
-               {                               \r
-                       frame_buffer_.pop();\r
-                       auto frame = frame_buffer_.front();\r
-                       frame_buffer_.pop();\r
-                       return last_frame_ = frame;\r
-               }\r
-               else if(!frame_buffer_.empty())\r
+               if(frame_buffer_.size() > 1)\r
                {\r
                        auto frame = frame_buffer_.front();\r
                        frame_buffer_.pop();\r
@@ -171,19 +179,25 @@ public:
                auto read_frame = consumer_->receive();\r
                if(!read_frame || read_frame->image_data().empty())\r
                        return basic_frame::late();             \r
+\r
+               frame_number_++;\r
                \r
                core::pixel_format_desc desc;\r
+               bool double_speed       = std::abs(frame_factory_->get_video_format_desc().fps / 2.0 - format_desc.fps) < 0.01;         \r
+               bool half_speed         = std::abs(format_desc.fps / 2.0 - frame_factory_->get_video_format_desc().fps) < 0.01;\r
+\r
+               if(half_speed && frame_number_ % 2 == 0) // Skip frame\r
+                       return receive(0);\r
+\r
                desc.pix_fmt = core::pixel_format::bgra;\r
                desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));\r
                auto frame = frame_factory_->create_frame(this, desc);\r
 \r
-               memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
+               fast_memcpy(frame->image_data().begin(), read_frame->image_data().begin(), read_frame->image_data().size());\r
                frame->commit();\r
 \r
                frame_buffer_.push(frame);      \r
                \r
-               bool double_speed = std::abs(frame_factory_->get_video_format_desc().fps / 2.0 - format_desc.fps) < 0.01;\r
-\r
                if(double_speed)        \r
                        frame_buffer_.push(frame);\r
 \r
@@ -200,17 +214,23 @@ public:
                return L"channel[]";\r
        }\r
 \r
-       boost::property_tree::wptree info() const override\r
+       virtual boost::property_tree::wptree info() const override\r
        {\r
                boost::property_tree::wptree info;\r
                info.add(L"type", L"channel-producer");\r
                return info;\r
        }\r
+\r
+       monitor::source& monitor_output() \r
+       {\r
+               return monitor_subject_;\r
+       }\r
 };\r
 \r
 safe_ptr<frame_producer> create_channel_producer(const safe_ptr<core::frame_factory>& frame_factory, const safe_ptr<video_channel>& channel)\r
 {\r
-       return make_safe<channel_producer>(frame_factory, channel);\r
+       return create_producer_print_proxy(\r
+                       make_safe<channel_producer>(frame_factory, channel));\r
 }\r
 \r
 }}
\ No newline at end of file