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>
35 #include <common/tweener.h>
41 namespace caspar { namespace core {
43 draw_frame drop_and_skip(const draw_frame& source, const draw_frame&, const boost::rational<int64_t>&)
48 // Blends next frame with current frame when the distance is not 0.
49 // Completely sharp when distance is 0 but blurry when in between.
50 draw_frame blend(const draw_frame& source, const draw_frame& destination, const boost::rational<int64_t>& distance)
52 if (destination == draw_frame::empty())
56 auto over = destination;
57 double float_distance = static_cast<double>(distance.numerator()) / static_cast<double>(distance.denominator());
59 under.transform().image_transform.is_mix = true;
60 under.transform().image_transform.opacity = 1 - float_distance;
61 over.transform().image_transform.is_mix = true;
62 over.transform().image_transform.opacity = float_distance;
64 return draw_frame::over(under, over);
67 // Blends a moving window with a width of 1 frame duration.
68 // * A distance of 0.0 gives 50% previous, 50% current and 0% next.
69 // * A distance of 0.5 gives 25% previous, 50% current and 25% next.
70 // * A distance of 0.75 gives 12.5% previous, 50% current and 37.5% next.
71 // This is blurrier than blend, but gives a more even bluriness, instead of sharp, blurry, sharp, blurry.
74 draw_frame previous_frame = draw_frame::empty();
75 draw_frame last_source = draw_frame::empty();
76 draw_frame last_destination = draw_frame::empty();
78 draw_frame operator()(const draw_frame& source, const draw_frame& destination, const boost::rational<int64_t>& distance)
80 if (last_source != draw_frame::empty() && last_source != source)
82 if (last_destination == source)
83 previous_frame = last_source;
84 else // A two frame jump
85 previous_frame = last_destination;
89 last_destination = destination;
91 bool has_previous = previous_frame != draw_frame::empty();
94 return blend(source, destination, distance);
96 auto middle = last_source;
97 auto next_frame = destination;
98 previous_frame.transform().image_transform.is_mix = true;
99 middle.transform().image_transform.is_mix = true;
100 next_frame.transform().image_transform.is_mix = true;
102 double float_distance = static_cast<double>(distance.numerator()) / static_cast<double>(distance.denominator());
103 previous_frame.transform().image_transform.opacity = std::max(0.0, 0.5 - float_distance * 0.5);
104 middle.transform().image_transform.opacity = 0.5;
105 next_frame.transform().image_transform.opacity = 1.0 - previous_frame.transform().image_transform.opacity - middle.transform().image_transform.opacity;
107 std::vector<draw_frame> combination { previous_frame, middle, next_frame };
109 return draw_frame(std::move(combination));
113 struct audio_extractor : public frame_visitor
115 std::function<void(const const_frame& frame)> on_frame_;
117 audio_extractor(std::function<void(const const_frame& frame)> on_frame)
118 : on_frame_(std::move(on_frame))
122 void push(const frame_transform& transform) override { }
123 void pop() override { }
124 void visit(const const_frame& frame) override
126 if (!frame.audio_data().empty())
131 // Like tweened_transform but for framerates
134 boost::rational<int64_t> source_ = 1LL;
135 boost::rational<int64_t> dest_ = 1LL;
140 speed_tweener() = default;
142 const boost::rational<int64_t>& source,
143 const boost::rational<int64_t>& dest,
145 const tweener& tween)
148 , duration_(duration)
154 const boost::rational<int64_t>& dest() const
159 boost::rational<int64_t> fetch() const
161 if (time_ == duration_)
163 double source = static_cast<double>(source_.numerator()) / static_cast<double>(source_.denominator());
164 double delta = static_cast<double>(dest_.numerator()) / static_cast<double>(dest_.denominator()) - source;
165 double result = tweener_(time_, source, delta, duration_);
167 return boost::rational<int64_t>(static_cast<int64_t>(result * 1000000.0), 1000000);
170 boost::rational<int64_t> fetch_and_tick()
172 time_ = std::min(time_ + 1, duration_);
177 class framerate_producer : public frame_producer_base
179 spl::shared_ptr<frame_producer> source_;
180 boost::rational<int> source_framerate_;
181 audio_channel_layout source_channel_layout_ = audio_channel_layout::invalid();
182 boost::rational<int> destination_framerate_;
183 field_mode destination_fieldmode_;
184 std::vector<int> destination_audio_cadence_;
185 boost::rational<std::int64_t> speed_;
186 speed_tweener user_speed_;
187 std::function<draw_frame (
188 const draw_frame& source,
189 const draw_frame& destination,
190 const boost::rational<int64_t>& distance)> interpolator_ = drop_and_skip;
192 boost::rational<std::int64_t> current_frame_number_ = 0;
193 draw_frame previous_frame_ = draw_frame::empty();
194 draw_frame next_frame_ = draw_frame::empty();
195 mutable_audio_buffer audio_samples_;
197 unsigned int output_repeat_ = 0;
198 unsigned int output_frame_ = 0;
201 spl::shared_ptr<frame_producer> source,
202 boost::rational<int> source_framerate,
203 boost::rational<int> destination_framerate,
204 field_mode destination_fieldmode,
205 std::vector<int> destination_audio_cadence)
206 : source_(std::move(source))
207 , source_framerate_(std::move(source_framerate))
208 , destination_framerate_(std::move(destination_framerate))
209 , destination_fieldmode_(destination_fieldmode)
210 , destination_audio_cadence_(std::move(destination_audio_cadence))
212 // Coarse adjustment to correct fps family (23.98 - 30 vs 47.95 - 60)
213 if (destination_fieldmode_ != field_mode::progressive) // Interlaced output
215 auto diff_double = boost::abs(source_framerate_ - destination_framerate_ * 2);
216 auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
218 if (diff_double < diff_keep) // Double rate interlaced
220 destination_framerate_ *= 2;
222 else // Progressive non interlaced
224 destination_fieldmode_ = field_mode::progressive;
229 auto diff_halve = boost::abs(source_framerate_ * 2 - destination_framerate_);
230 auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
232 if (diff_halve < diff_keep) // Repeat every frame two times
234 destination_framerate_ /= 2;
239 speed_ = boost::rational<int64_t>(source_framerate_ / destination_framerate_);
241 // drop_and_skip will only be used by default for exact framerate multiples (half, same and double)
242 // for all other framerates a frame interpolator will be chosen.
243 if (speed_ != 1 && speed_ * 2 != 1 && speed_ != 2)
245 if (source_framerate_ > 47) // The bluriness of blend_all is acceptable on high framerates.
246 interpolator_ = blend_all();
247 else // blend_all is mostly too blurry on low framerates. blend provides a compromise.
248 interpolator_ = &blend;
250 CASPAR_LOG(warning) << source_->print() << L" Frame blending frame rate conversion required to conform to channel frame rate.";
253 // Note: Uses 1 step rotated cadence for 1001 modes (1602, 1602, 1601, 1602, 1601)
254 // This cadence fills the audio mixer most optimally.
255 boost::range::rotate(destination_audio_cadence_, std::end(destination_audio_cadence_) - 1);
258 draw_frame receive_impl() override
260 if (destination_fieldmode_ == field_mode::progressive)
262 return do_render_progressive_frame(true);
266 auto field1 = do_render_progressive_frame(true);
267 auto field2 = do_render_progressive_frame(false);
269 return draw_frame::interlace(field1, field2, destination_fieldmode_);
273 std::future<std::wstring> call(const std::vector<std::wstring>& params) override
275 if (!boost::iequals(params.at(0), L"framerate"))
276 return source_->call(params);
278 if (boost::iequals(params.at(1), L"speed"))
280 auto destination_user_speed = boost::rational<std::int64_t>(
281 static_cast<std::int64_t>(boost::lexical_cast<double>(params.at(2)) * 1000000.0),
283 auto frames = params.size() > 3 ? boost::lexical_cast<int>(params.at(3)) : 0;
284 auto easing = params.size() > 4 ? params.at(4) : L"linear";
286 user_speed_ = speed_tweener(user_speed_.fetch(), destination_user_speed, frames, tweener(easing));
288 else if (boost::iequals(params.at(1), L"interpolation"))
290 if (boost::iequals(params.at(2), L"blend"))
291 interpolator_ = &blend;
292 else if (boost::iequals(params.at(2), L"blend_all"))
293 interpolator_ = blend_all();
295 interpolator_ = &drop_and_skip;
297 else if (boost::iequals(params.at(1), L"output_repeat")) // Only for debugging purposes
299 output_repeat_ = boost::lexical_cast<unsigned int>(params.at(2));
302 return make_ready_future<std::wstring>(L"");
305 monitor::subject& monitor_output() override
307 return source_->monitor_output();
310 std::wstring print() const override
312 return source_->print();
315 std::wstring name() const override
317 return source_->name();
320 boost::property_tree::wptree info() const override
322 return source_->info();
325 constraints& pixel_constraints() override
327 return source_->pixel_constraints();
330 draw_frame do_render_progressive_frame(bool sound)
332 user_speed_.fetch_and_tick();
334 if (output_repeat_ && ++output_frame_ % output_repeat_)
336 auto frame = draw_frame::still(last_frame());
338 frame.transform().audio_transform.volume = 0.0;
340 return attach_sound(frame);
343 if (previous_frame_ == draw_frame::empty())
344 previous_frame_ = pop_frame_from_source();
346 auto current_frame_number = current_frame_number_;
347 auto distance = current_frame_number_ - boost::rational_cast<int64_t>(current_frame_number_);
348 bool needs_next = distance > 0 || !enough_sound();
350 if (needs_next && next_frame_ == draw_frame::empty())
351 next_frame_ = pop_frame_from_source();
353 auto result = interpolator_(previous_frame_, next_frame_, distance);
355 auto next_frame_number = current_frame_number_ += get_speed();
356 auto integer_current_frame = boost::rational_cast<std::int64_t>(current_frame_number);
357 auto integer_next_frame = boost::rational_cast<std::int64_t>(next_frame_number);
359 fast_forward_integer_frames(integer_next_frame - integer_current_frame);
362 return attach_sound(result);
367 void fast_forward_integer_frames(std::int64_t num_frames)
372 for (std::int64_t i = 0; i < num_frames; ++i)
374 previous_frame_ = std::move(next_frame_);
376 next_frame_ = pop_frame_from_source();
380 boost::rational<std::int64_t> get_speed() const
382 return speed_ * user_speed_.fetch();
385 draw_frame pop_frame_from_source()
387 auto frame = source_->receive();
389 if (user_speed_.fetch() == 1)
391 audio_extractor extractor([this](const const_frame& frame)
393 if (source_channel_layout_ != frame.audio_channel_layout())
395 source_channel_layout_ = frame.audio_channel_layout();
397 // Insert silence samples so that the audio mixer is guaranteed to be filled.
398 auto min_num_samples_per_frame = *boost::min_element(destination_audio_cadence_);
399 auto max_num_samples_per_frame = *boost::max_element(destination_audio_cadence_);
400 auto cadence_safety_samples = max_num_samples_per_frame - min_num_samples_per_frame;
401 audio_samples_.resize(source_channel_layout_.num_channels * cadence_safety_samples, 0);
404 auto& buffer = frame.audio_data();
405 audio_samples_.insert(audio_samples_.end(), buffer.begin(), buffer.end());
408 frame.accept(extractor);
412 source_channel_layout_ = audio_channel_layout::invalid();
413 audio_samples_.clear();
416 frame.transform().audio_transform.volume = 0.0;
421 draw_frame attach_sound(draw_frame frame)
423 if (user_speed_.fetch() != 1 || source_channel_layout_ == audio_channel_layout::invalid())
426 mutable_audio_buffer buffer;
428 if (destination_audio_cadence_.front() * source_channel_layout_.num_channels == audio_samples_.size())
430 buffer.swap(audio_samples_);
432 else if (audio_samples_.size() >= destination_audio_cadence_.front() * source_channel_layout_.num_channels)
434 auto begin = audio_samples_.begin();
435 auto end = begin + destination_audio_cadence_.front() * source_channel_layout_.num_channels;
437 buffer.insert(buffer.begin(), begin, end);
438 audio_samples_.erase(begin, end);
442 auto needed = destination_audio_cadence_.front();
443 auto got = audio_samples_.size() / source_channel_layout_.num_channels;
444 CASPAR_LOG(debug) << print() << L" Too few audio samples. Needed " << needed << L" but got " << got;
445 buffer.swap(audio_samples_);
446 buffer.resize(needed * source_channel_layout_.num_channels, 0);
449 boost::range::rotate(destination_audio_cadence_, std::begin(destination_audio_cadence_) + 1);
451 auto audio_frame = mutable_frame(
456 source_channel_layout_);
457 return draw_frame::over(frame, draw_frame(std::move(audio_frame)));
460 bool enough_sound() const
462 return source_channel_layout_ == core::audio_channel_layout::invalid()
463 || user_speed_.fetch() != 1
464 || audio_samples_.size() / source_channel_layout_.num_channels >= destination_audio_cadence_.at(0);
468 spl::shared_ptr<frame_producer> create_framerate_producer(
469 spl::shared_ptr<frame_producer> source,
470 boost::rational<int> source_framerate,
471 boost::rational<int> destination_framerate,
472 field_mode destination_fieldmode,
473 std::vector<int> destination_audio_cadence)
475 return spl::make_shared<framerate_producer>(
477 std::move(source_framerate),
478 std::move(destination_framerate),
479 destination_fieldmode,
480 std::move(destination_audio_cadence));