2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
4 * This file is part of CasparCG (www.casparcg.com).
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
19 * Author: Helge Norberg, helge.norberg@svt.se
22 #include "../../StdAfx.h"
24 #include "framerate_producer.h"
26 #include "../frame_producer.h"
27 #include "../../frame/audio_channel_layout.h"
28 #include "../../frame/draw_frame.h"
29 #include "../../frame/frame.h"
30 #include "../../frame/frame_transform.h"
31 #include "../../frame/pixel_format.h"
32 #include "../../monitor/monitor.h"
34 #include <common/future.h>
40 namespace caspar { namespace core {
42 draw_frame drop_and_skip(const draw_frame& source, const draw_frame&, const boost::rational<int64_t>&)
47 // Blends next frame with current frame when the distance is not 0.
48 // Completely sharp when distance is 0 but blurry when in between.
49 draw_frame blend(const draw_frame& source, const draw_frame& destination, const boost::rational<int64_t>& distance)
51 if (destination == draw_frame::empty())
55 auto over = destination;
56 double float_distance = static_cast<double>(distance.numerator()) / static_cast<double>(distance.denominator());
58 under.transform().image_transform.is_mix = true;
59 under.transform().image_transform.opacity = 1 - float_distance;
60 over.transform().image_transform.is_mix = true;
61 over.transform().image_transform.opacity = float_distance;
63 return draw_frame::over(under, over);
66 // Blends a moving window with a width of 1 frame duration.
67 // * A distance of 0.0 gives 50% previous, 50% current and 0% next.
68 // * A distance of 0.5 gives 25% previous, 50% current and 25% next.
69 // * A distance of 0.75 gives 12.5% previous, 50% current and 37.5% next.
70 // This is blurrier than blend, but gives a more even bluriness, instead of sharp, blurry, sharp, blurry.
73 draw_frame previous_frame = draw_frame::empty();
74 draw_frame last_source = draw_frame::empty();
75 draw_frame last_destination = draw_frame::empty();
77 draw_frame operator()(const draw_frame& source, const draw_frame& destination, const boost::rational<int64_t>& distance)
79 if (last_source != draw_frame::empty() && last_source != source)
81 if (last_destination == source)
82 previous_frame = last_source;
83 else // A two frame jump
84 previous_frame = last_destination;
88 last_destination = destination;
90 bool has_previous = previous_frame != draw_frame::empty();
93 return blend(source, destination, distance);
95 auto middle = last_source;
96 auto next_frame = destination;
97 previous_frame.transform().image_transform.is_mix = true;
98 middle.transform().image_transform.is_mix = true;
99 next_frame.transform().image_transform.is_mix = true;
101 double float_distance = static_cast<double>(distance.numerator()) / static_cast<double>(distance.denominator());
102 previous_frame.transform().image_transform.opacity = std::max(0.0, 0.5 - float_distance * 0.5);
103 middle.transform().image_transform.opacity = 0.5;
104 next_frame.transform().image_transform.opacity = 1.0 - previous_frame.transform().image_transform.opacity - middle.transform().image_transform.opacity;
106 std::vector<draw_frame> combination { previous_frame, middle, next_frame };
108 return draw_frame(std::move(combination));
112 struct audio_extractor : public frame_visitor
114 std::function<void(const const_frame& frame)> on_frame_;
116 audio_extractor(std::function<void(const const_frame& frame)> on_frame)
117 : on_frame_(std::move(on_frame))
121 void push(const frame_transform& transform) override { }
122 void pop() override { }
123 void visit(const const_frame& frame) override
125 if (!frame.audio_data().empty())
130 class framerate_producer : public frame_producer_base
132 spl::shared_ptr<frame_producer> source_;
133 boost::rational<int> source_framerate_;
134 audio_channel_layout source_channel_layout_ = audio_channel_layout::invalid();
135 boost::rational<int> destination_framerate_;
136 field_mode destination_fieldmode_;
137 std::vector<int> destination_audio_cadence_;
138 boost::rational<std::int64_t> speed_;
139 std::function<draw_frame (
140 const draw_frame& source,
141 const draw_frame& destination,
142 const boost::rational<int64_t>& distance)> interpolator_ = drop_and_skip;
144 boost::rational<std::int64_t> current_frame_number_ = 0;
145 draw_frame previous_frame_ = draw_frame::empty();
146 draw_frame next_frame_ = draw_frame::empty();
147 mutable_audio_buffer audio_samples_;
149 unsigned int output_repeat_ = 0;
150 unsigned int output_frame_ = 0;
153 spl::shared_ptr<frame_producer> source,
154 boost::rational<int> source_framerate,
155 boost::rational<int> destination_framerate,
156 field_mode destination_fieldmode,
157 std::vector<int> destination_audio_cadence)
158 : source_(std::move(source))
159 , source_framerate_(std::move(source_framerate))
160 , destination_framerate_(std::move(destination_framerate))
161 , destination_fieldmode_(destination_fieldmode)
162 , destination_audio_cadence_(std::move(destination_audio_cadence))
164 // Coarse adjustment to correct fps family (23.98 - 30 vs 47.95 - 60)
165 if (destination_fieldmode_ != field_mode::progressive) // Interlaced output
167 auto diff_double = boost::abs(source_framerate_ - destination_framerate_ * 2);
168 auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
170 if (diff_double < diff_keep) // Double rate interlaced
172 destination_framerate_ *= 2;
174 else // Progressive non interlaced
176 destination_fieldmode_ = field_mode::progressive;
181 auto diff_halve = boost::abs(source_framerate_ * 2 - destination_framerate_);
182 auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
184 if (diff_halve < diff_keep) // Repeat every frame two times
186 destination_framerate_ /= 2;
191 speed_ = boost::rational<int64_t>(source_framerate_ / destination_framerate_);
193 // drop_and_skip will only be used by default for exact framerate multiples (half, same and double)
194 // for all other framerates a frame interpolator will be chosen.
195 if (speed_ != 1 && speed_ * 2 != 1 && speed_ != 2)
197 if (source_framerate_ > 47) // The bluriness of blend_all is acceptable on high framerates.
198 interpolator_ = blend_all();
199 else // blend_all is mostly too blurry on low framerates. blend provides a compromise.
200 interpolator_ = &blend;
202 CASPAR_LOG(warning) << source_->print() << L" Frame blending frame rate conversion required to conform to channel frame rate.";
205 // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)
206 // This cadence fills the audio mixer most optimally.
207 boost::range::rotate(destination_audio_cadence_, std::end(destination_audio_cadence_) - 1);
210 draw_frame receive_impl() override
212 if (destination_fieldmode_ == field_mode::progressive)
214 return do_render_progressive_frame(true);
218 auto field1 = do_render_progressive_frame(true);
219 auto field2 = do_render_progressive_frame(false);
221 return draw_frame::interlace(field1, field2, destination_fieldmode_);
225 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
227 if (!boost::iequals(params.at(0), L"framerate") || params.size() != 3)
228 return source_->call(params);
230 if (boost::iequals(params.at(1), L"interpolation"))
232 if (boost::iequals(params.at(2), L"blend"))
233 interpolator_ = &blend;
234 else if (boost::iequals(params.at(2), L"blend_all"))
235 interpolator_ = blend_all();
237 interpolator_ = &drop_and_skip;
239 else if (boost::iequals(params.at(1), L"output_repeat")) // Only for debugging purposes
241 output_repeat_ = boost::lexical_cast<unsigned int>(params.at(2));
244 return make_ready_future<std::wstring>(L"");
247 monitor::subject& monitor_output() override
249 return source_->monitor_output();
252 std::wstring print() const override
254 return source_->print();
257 std::wstring name() const override
259 return source_->name();
262 boost::property_tree::wptree info() const override
264 return source_->info();
267 constraints& pixel_constraints() override
269 return source_->pixel_constraints();
272 draw_frame do_render_progressive_frame(bool sound)
274 if (output_repeat_ && ++output_frame_ % output_repeat_)
276 auto frame = draw_frame::still(last_frame());
278 frame.transform().audio_transform.volume = 0.0;
280 return attach_sound(frame);
283 if (previous_frame_ == draw_frame::empty())
284 previous_frame_ = pop_frame_from_source();
286 auto current_frame_number = current_frame_number_;
287 auto distance = current_frame_number_ - boost::rational_cast<int64_t>(current_frame_number_);
288 bool needs_next = distance > 0 || !enough_sound();
290 if (needs_next && next_frame_ == draw_frame::empty())
291 next_frame_ = pop_frame_from_source();
293 auto result = interpolator_(previous_frame_, next_frame_, distance);
295 auto next_frame_number = current_frame_number_ += get_speed();
296 auto integer_current_frame = boost::rational_cast<std::int64_t>(current_frame_number);
297 auto integer_next_frame = boost::rational_cast<std::int64_t>(next_frame_number);
299 fast_forward_integer_frames(integer_next_frame - integer_current_frame);
302 return attach_sound(result);
307 void fast_forward_integer_frames(std::int64_t num_frames)
312 for (std::int64_t i = 0; i < num_frames; ++i)
314 previous_frame_ = std::move(next_frame_);
316 next_frame_ = pop_frame_from_source();
320 boost::rational<std::int64_t> get_speed() const
325 draw_frame pop_frame_from_source()
327 auto frame = source_->receive();
329 audio_extractor extractor([this](const const_frame& frame)
331 if (source_channel_layout_ != frame.audio_channel_layout())
333 source_channel_layout_ = frame.audio_channel_layout();
335 // Insert silence samples so that the audio mixer is guaranteed to be filled.
336 auto min_num_samples_per_frame = *boost::min_element(destination_audio_cadence_);
337 auto max_num_samples_per_frame = *boost::max_element(destination_audio_cadence_);
338 auto cadence_safety_samples = max_num_samples_per_frame - min_num_samples_per_frame;
339 audio_samples_.resize(source_channel_layout_.num_channels * cadence_safety_samples, 0);
342 auto& buffer = frame.audio_data();
343 audio_samples_.insert(audio_samples_.end(), buffer.begin(), buffer.end());
346 frame.accept(extractor);
347 frame.transform().audio_transform.volume = 0.0;
352 draw_frame attach_sound(draw_frame frame)
354 if (source_channel_layout_ == audio_channel_layout::invalid())
357 mutable_audio_buffer buffer;
359 if (destination_audio_cadence_.front() * source_channel_layout_.num_channels == audio_samples_.size())
361 buffer.swap(audio_samples_);
363 else if (audio_samples_.size() >= destination_audio_cadence_.front() * source_channel_layout_.num_channels)
365 auto begin = audio_samples_.begin();
366 auto end = begin + destination_audio_cadence_.front() * source_channel_layout_.num_channels;
368 buffer.insert(buffer.begin(), begin, end);
369 audio_samples_.erase(begin, end);
373 auto needed = destination_audio_cadence_.front();
374 auto got = audio_samples_.size() / source_channel_layout_.num_channels;
375 CASPAR_LOG(debug) << print() << L" Too few audio samples. Needed " << needed << L" but got " << got;
376 buffer.swap(audio_samples_);
377 buffer.resize(needed * source_channel_layout_.num_channels, 0);
380 boost::range::rotate(destination_audio_cadence_, std::begin(destination_audio_cadence_) + 1);
382 auto audio_frame = mutable_frame(
387 source_channel_layout_);
388 return draw_frame::over(frame, draw_frame(std::move(audio_frame)));
391 bool enough_sound() const
393 return source_channel_layout_ == core::audio_channel_layout::invalid()
394 || audio_samples_.size() / source_channel_layout_.num_channels >= destination_audio_cadence_.at(0);
398 spl::shared_ptr<frame_producer> create_framerate_producer(
399 spl::shared_ptr<frame_producer> source,
400 boost::rational<int> source_framerate,
401 boost::rational<int> destination_framerate,
402 field_mode destination_fieldmode,
403 std::vector<int> destination_audio_cadence)
405 return spl::make_shared<framerate_producer>(
407 std::move(source_framerate),
408 std::move(destination_framerate),
409 destination_fieldmode,
410 std::move(destination_audio_cadence));