]> git.sesse.net Git - casparcg/commitdiff
[reroute] Fixed serious out of memory situation where too many audio samples are...
authorHelge Norberg <helge.norberg@svt.se>
Fri, 17 Mar 2017 16:41:11 +0000 (17:41 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Fri, 17 Mar 2017 16:41:11 +0000 (17:41 +0100)
core/producer/framerate/framerate_producer.cpp
modules/reroute/producer/channel_producer.cpp
modules/reroute/producer/layer_producer.cpp
modules/reroute/producer/layer_producer.h
modules/reroute/producer/reroute_producer.cpp

index 5125ebae3baeb7391775a0fdb6b0de5327dd8d50..e855dd41b9346ed37da00d26b7db06e4a52c770d 100644 (file)
@@ -135,7 +135,7 @@ public:
 
        void visit(const const_frame& frame) override
        {
-               if (!frame.audio_data().empty() && !transform_stack_.top().is_still)
+               if (!frame.audio_data().empty() && !transform_stack_.top().is_still && !transform_stack_.top().volume == 0.0)
                        on_frame_(frame);
        }
 };
index ca1d802e7584d92ff3b5f92afe8a2530babca512..1248f8622439a643d1bf232dc3de3678fea63210 100644 (file)
@@ -27,6 +27,7 @@
 #include <core/consumer/frame_consumer.h>
 #include <core/consumer/output.h>
 #include <core/producer/frame_producer.h>
+#include <core/producer/framerate/framerate_producer.h>
 #include <core/video_channel.h>
 
 #include <core/frame/frame.h>
@@ -56,7 +57,7 @@
 namespace caspar { namespace reroute {
 
 class channel_consumer : public core::frame_consumer
-{      
+{
        core::monitor::subject                                                          monitor_subject_;
        tbb::concurrent_bounded_queue<core::const_frame>        frame_buffer_;
        core::video_format_desc                                                         format_desc_;
@@ -139,7 +140,7 @@ public:
                info.add(L"channel-index", channel_index_);
                return info;
        }
-       
+
        bool has_synchronization_clock() const override
        {
                return false;
@@ -161,7 +162,7 @@ public:
        }
 
        // channel_consumer
-       
+
        const core::video_format_desc& get_video_format_desc()
        {
                return format_desc_;
@@ -185,7 +186,7 @@ public:
 
                if (!is_running_)
                        return frame;
-               
+
                if (frame_buffer_.try_pop(frame))
                        current_age_ = frame.get_age_millis();
 
@@ -197,7 +198,7 @@ public:
                is_running_ = false;
        }
 };
-       
+
 class channel_producer : public core::frame_producer_base
 {
        core::monitor::subject                                          monitor_subject_;
@@ -208,14 +209,12 @@ class channel_producer : public core::frame_producer_base
        core::constraints                                                       pixel_constraints_;
 
        std::queue<core::draw_frame>                            frame_buffer_;
-       uint64_t                                                                        frame_number_;
 
 public:
        explicit channel_producer(const core::frame_producer_dependencies& dependecies, const spl::shared_ptr<core::video_channel>& channel, int frames_delay)
                : frame_factory_(dependecies.frame_factory)
                , output_format_desc_(dependecies.format_desc)
                , consumer_(spl::make_shared<channel_consumer>(frames_delay))
-               , frame_number_(0)
        {
                pixel_constraints_.width.set(output_format_desc_.width);
                pixel_constraints_.height.set(output_format_desc_.height);
@@ -231,7 +230,7 @@ public:
        }
 
        // frame_producer
-                       
+
        core::draw_frame receive_impl() override
        {
                auto format_desc = consumer_->get_video_format_desc();
@@ -242,41 +241,25 @@ public:
                        frame_buffer_.pop();
                        return frame;
                }
-               
+
                auto read_frame = consumer_->receive();
                if(read_frame == core::const_frame::empty() || read_frame.image_data().empty())
                        return core::draw_frame::late();
 
-               frame_number_++;
-               
-               bool double_speed       = std::abs(output_format_desc_.fps / 2.0 - format_desc.fps) < 0.01;
-               bool half_speed         = std::abs(format_desc.fps / 2.0 - output_format_desc_.fps) < 0.01;
-
-               if(half_speed && frame_number_ % 2 == 0) // Skip frame
-                       return receive_impl();
-
                core::pixel_format_desc desc;
                desc.format = core::pixel_format::bgra;
                desc.planes.push_back(core::pixel_format_desc::plane(format_desc.width, format_desc.height, 4));
                auto frame = frame_factory_->create_frame(this, desc, consumer_->get_audio_channel_layout());
 
-               bool copy_audio = !double_speed && !half_speed;
-
-               if (copy_audio)
-               {
-                       frame.audio_data().reserve(read_frame.audio_data().size());
-                       boost::copy(read_frame.audio_data(), std::back_inserter(frame.audio_data()));
-               }
+               frame.audio_data().reserve(read_frame.audio_data().size());
+               boost::copy(read_frame.audio_data(), std::back_inserter(frame.audio_data()));
 
                fast_memcpy(frame.image_data().begin(), read_frame.image_data().begin(), read_frame.image_data().size());
 
                frame_buffer_.push(core::draw_frame(std::move(frame)));
-               
-               if(double_speed)
-                       frame_buffer_.push(frame_buffer_.back());
 
                return receive_impl();
-       }       
+       }
 
        std::wstring name() const override
        {
@@ -311,7 +294,12 @@ spl::shared_ptr<core::frame_producer> create_channel_producer(
                const spl::shared_ptr<core::video_channel>& channel,
                int frames_delay)
 {
-       return spl::make_shared<channel_producer>(dependencies, channel, frames_delay);
+       return core::create_framerate_producer(
+                       spl::make_shared<channel_producer>(dependencies, channel, frames_delay),
+                       [channel] { return channel->video_format_desc().framerate; }    ,
+                       dependencies.format_desc.framerate,
+                       dependencies.format_desc.field_mode,
+                       dependencies.format_desc.audio_cadence);
 }
 
 }}
index 9b5bad96c10234327b517674966cc7bd26214a69..1f4346cd0eee062acafa6378d01cb05f9ef68980 100644 (file)
@@ -30,6 +30,7 @@
 #include <core/frame/frame_factory.h>
 #include <core/producer/frame_producer.h>
 #include <core/producer/stage.h>
+#include <core/producer/framerate/framerate_producer.h>
 
 #include <common/except.h>
 #include <common/semaphore.h>
@@ -90,6 +91,51 @@ public:
        }
 };
 
+std::vector<core::draw_frame> extract_actual_frames(core::draw_frame original, core::field_mode field_order)
+{
+       if (field_order == core::field_mode::progressive)
+               return { std::move(original) };
+
+       struct field_extractor : public core::frame_visitor
+       {
+               std::vector<core::draw_frame>   fields;
+               core::field_mode                                field_order_first;
+               core::field_mode                                visiting_mode = core::field_mode::progressive;
+
+               field_extractor(core::field_mode field_order_)
+                       : field_order_first(field_order_)
+               {
+               }
+
+               void push(const core::frame_transform& transform) override
+               {
+                       if (visiting_mode == core::field_mode::progressive)
+                               visiting_mode = transform.image_transform.field_mode;
+               }
+
+               void visit(const core::const_frame& frame) override
+               {
+                       if (visiting_mode == field_order_first && fields.size() == 0)
+                               fields.push_back(core::draw_frame(core::const_frame(frame)));
+                       else if (visiting_mode != core::field_mode::progressive && visiting_mode != field_order_first && fields.size() == 1)
+                               fields.push_back(core::draw_frame(core::const_frame(frame)));
+               }
+
+               void pop() override
+               {
+                       visiting_mode = core::field_mode::progressive;
+               };
+       };
+
+       field_extractor extractor(field_order);
+       original.accept(extractor);
+
+       if (extractor.fields.size() == 2)
+               return std::move(extractor.fields);
+       else
+               return { std::move(original) };
+}
+
 class layer_producer : public core::frame_producer_base
 {
        core::monitor::subject                                          monitor_subject_;
@@ -98,23 +144,25 @@ class layer_producer : public core::frame_producer_base
        const spl::shared_ptr<layer_consumer>           consumer_;
 
        core::draw_frame                                                        last_frame_;
-       uint64_t                                                                        frame_number_;
 
        const spl::shared_ptr<core::video_channel>      channel_;
        core::constraints                                                       pixel_constraints_;
 
+       tbb::atomic<bool>                                                       double_framerate_;
+       std::queue<core::draw_frame>                            frame_buffer_;
+
 public:
        explicit layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer, int frames_delay)
                : layer_(layer)
                , consumer_(spl::make_shared<layer_consumer>(frames_delay))
                , channel_(channel)
                , last_frame_(core::draw_frame::late())
-               , frame_number_(0)
        {
                pixel_constraints_.width.set(channel->video_format_desc().width);
                pixel_constraints_.height.set(channel->video_format_desc().height);
                channel_->stage().add_layer_consumer(this, layer_, consumer_);
                consumer_->block_until_first_frame_available();
+               double_framerate_ = false;
                CASPAR_LOG(info) << print() << L" Initialized";
        }
 
@@ -128,12 +176,24 @@ public:
 
        core::draw_frame receive_impl() override
        {
+               if (!frame_buffer_.empty())
+               {
+                       last_frame_ = frame_buffer_.front();
+                       frame_buffer_.pop();
+                       return last_frame_;
+               }
+
                auto consumer_frame = consumer_->receive();
                if (consumer_frame == core::draw_frame::late())
                        return last_frame_;
 
-               frame_number_++;
-               return last_frame_ = consumer_frame;
+               auto actual_frames = extract_actual_frames(std::move(consumer_frame), channel_->video_format_desc().field_mode);
+               double_framerate_ = actual_frames.size() == 2;
+
+               for (auto& frame : actual_frames)
+                       frame_buffer_.push(std::move(frame));
+
+               return receive_impl();
        }
 
        core::draw_frame last_frame() override
@@ -167,11 +227,29 @@ public:
        {
                return pixel_constraints_;
        }
+
+       boost::rational<int> current_framerate() const
+       {
+               return double_framerate_
+                               ? channel_->video_format_desc().framerate * 2
+                               : channel_->video_format_desc().framerate;
+       }
 };
 
-spl::shared_ptr<core::frame_producer> create_layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer, int frames_delay)
+spl::shared_ptr<core::frame_producer> create_layer_producer(
+               const spl::shared_ptr<core::video_channel>& channel,
+               int layer,
+               int frames_delay,
+               const core::video_format_desc& destination_mode)
 {
-       return spl::make_shared<layer_producer>(channel, layer, frames_delay);
+       auto producer = spl::make_shared<layer_producer>(channel, layer, frames_delay);
+
+       return core::create_framerate_producer(
+                       producer,
+                       std::bind(&layer_producer::current_framerate, producer),
+                       destination_mode.framerate,
+                       destination_mode.field_mode,
+                       destination_mode.audio_cadence);
 }
 
 }}
index 463d78937dcd09f186eaaf161b060780c7f444eb..5375f9af7827eea202ca0a171c25c5aad5b825e6 100644 (file)
 
 namespace caspar { namespace reroute {
 
-spl::shared_ptr<core::frame_producer> create_layer_producer(const spl::shared_ptr<core::video_channel>& channel, int layer, int frames_delay);
+spl::shared_ptr<core::frame_producer> create_layer_producer(
+               const spl::shared_ptr<core::video_channel>& channel,
+               int layer,
+               int frames_delay,
+               const core::video_format_desc& destination_mode);
 
 }}
index e34a43018423a6d36c767c064312f4646d03d5fe..cd281afe33b11a5fe4d6d2114cfac8c07881f68d 100644 (file)
@@ -100,7 +100,7 @@ spl::shared_ptr<core::frame_producer> create_producer(
        {
                auto layer = boost::lexical_cast<int>(channel_layer_spec.substr(dash + 1));
 
-               return create_layer_producer(*found_channel, layer, frames_delay);
+               return create_layer_producer(*found_channel, layer, frames_delay, dependencies.format_desc);
        }
        else
        {