From 1c872ac3f4be8361cf7dc082b8f0ee059ca3a307 Mon Sep 17 00:00:00 2001 From: Helge Norberg Date: Fri, 17 Mar 2017 17:41:11 +0100 Subject: [PATCH] [reroute] Fixed serious out of memory situation where too many audio samples are queued. This also has the side effect of mismatching framerates between routed from and routed to channels work. Also audio is always routed, instead of only when framerate matches. --- .../producer/framerate/framerate_producer.cpp | 2 +- modules/reroute/producer/channel_producer.cpp | 46 ++++------ modules/reroute/producer/layer_producer.cpp | 90 +++++++++++++++++-- modules/reroute/producer/layer_producer.h | 6 +- modules/reroute/producer/reroute_producer.cpp | 2 +- 5 files changed, 108 insertions(+), 38 deletions(-) diff --git a/core/producer/framerate/framerate_producer.cpp b/core/producer/framerate/framerate_producer.cpp index 5125ebae3..e855dd41b 100644 --- a/core/producer/framerate/framerate_producer.cpp +++ b/core/producer/framerate/framerate_producer.cpp @@ -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); } }; diff --git a/modules/reroute/producer/channel_producer.cpp b/modules/reroute/producer/channel_producer.cpp index ca1d802e7..1248f8622 100644 --- a/modules/reroute/producer/channel_producer.cpp +++ b/modules/reroute/producer/channel_producer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,7 @@ namespace caspar { namespace reroute { class channel_consumer : public core::frame_consumer -{ +{ core::monitor::subject monitor_subject_; tbb::concurrent_bounded_queue 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 frame_buffer_; - uint64_t frame_number_; public: explicit channel_producer(const core::frame_producer_dependencies& dependecies, const spl::shared_ptr& channel, int frames_delay) : frame_factory_(dependecies.frame_factory) , output_format_desc_(dependecies.format_desc) , consumer_(spl::make_shared(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 create_channel_producer( const spl::shared_ptr& channel, int frames_delay) { - return spl::make_shared(dependencies, channel, frames_delay); + return core::create_framerate_producer( + spl::make_shared(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); } }} diff --git a/modules/reroute/producer/layer_producer.cpp b/modules/reroute/producer/layer_producer.cpp index 9b5bad96c..1f4346cd0 100644 --- a/modules/reroute/producer/layer_producer.cpp +++ b/modules/reroute/producer/layer_producer.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -90,6 +91,51 @@ public: } }; +std::vector 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 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 consumer_; core::draw_frame last_frame_; - uint64_t frame_number_; const spl::shared_ptr channel_; core::constraints pixel_constraints_; + tbb::atomic double_framerate_; + std::queue frame_buffer_; + public: explicit layer_producer(const spl::shared_ptr& channel, int layer, int frames_delay) : layer_(layer) , consumer_(spl::make_shared(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 current_framerate() const + { + return double_framerate_ + ? channel_->video_format_desc().framerate * 2 + : channel_->video_format_desc().framerate; + } }; -spl::shared_ptr create_layer_producer(const spl::shared_ptr& channel, int layer, int frames_delay) +spl::shared_ptr create_layer_producer( + const spl::shared_ptr& channel, + int layer, + int frames_delay, + const core::video_format_desc& destination_mode) { - return spl::make_shared(channel, layer, frames_delay); + auto producer = spl::make_shared(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); } }} diff --git a/modules/reroute/producer/layer_producer.h b/modules/reroute/producer/layer_producer.h index 463d78937..5375f9af7 100644 --- a/modules/reroute/producer/layer_producer.h +++ b/modules/reroute/producer/layer_producer.h @@ -27,6 +27,10 @@ namespace caspar { namespace reroute { -spl::shared_ptr create_layer_producer(const spl::shared_ptr& channel, int layer, int frames_delay); +spl::shared_ptr create_layer_producer( + const spl::shared_ptr& channel, + int layer, + int frames_delay, + const core::video_format_desc& destination_mode); }} diff --git a/modules/reroute/producer/reroute_producer.cpp b/modules/reroute/producer/reroute_producer.cpp index e34a43018..cd281afe3 100644 --- a/modules/reroute/producer/reroute_producer.cpp +++ b/modules/reroute/producer/reroute_producer.cpp @@ -100,7 +100,7 @@ spl::shared_ptr create_producer( { auto layer = boost::lexical_cast(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 { -- 2.39.2