+
+ void update_source_framerate()
+ {
+ auto source_framerate = get_source_framerate_();
+
+ if (source_framerate_ == source_framerate)
+ return;
+
+ source_framerate_ = source_framerate;
+ destination_framerate_ = original_destination_framerate_;
+ destination_fieldmode_ = original_destination_fieldmode_;
+
+ // Coarse adjustment to correct fps family (23.98 - 30 vs 47.95 - 60)
+ if (destination_fieldmode_ != field_mode::progressive) // Interlaced output
+ {
+ auto diff_double = boost::abs(source_framerate_ - destination_framerate_ * 2);
+ auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
+
+ if (diff_double < diff_keep) // Double rate interlaced
+ {
+ destination_framerate_ *= 2;
+ }
+ else // Progressive non interlaced
+ {
+ destination_fieldmode_ = field_mode::progressive;
+ }
+ }
+ else // Progressive
+ {
+ auto diff_halve = boost::abs(source_framerate_ * 2 - destination_framerate_);
+ auto diff_keep = boost::abs(source_framerate_ - destination_framerate_);
+
+ if (diff_halve < diff_keep) // Repeat every frame two times
+ {
+ destination_framerate_ /= 2;
+ output_repeat_ = 2;
+ }
+ }
+
+ speed_ = boost::rational<int64_t>(source_framerate_ / destination_framerate_);
+
+ // drop_and_skip will only be used by default for exact framerate multiples (half, same and double)
+ // for all other framerates a frame interpolator will be chosen.
+ if (speed_ != 1 && speed_ * 2 != 1 && speed_ != 2)
+ {
+ auto high_source_framerate = source_framerate_ > 47;
+ auto high_destination_framerate = destination_framerate_ > 47
+ || destination_fieldmode_ != field_mode::progressive;
+
+ if (high_source_framerate && high_destination_framerate) // The bluriness of blend_all is acceptable on high framerates.
+ interpolator_ = blend_all();
+ else // blend_all is mostly too blurry on low framerates. blend provides a compromise.
+ interpolator_ = &blend;
+
+ CASPAR_LOG(warning) << source_->print() << L" Frame blending frame rate conversion required to conform to channel frame rate.";
+ }
+ }