#include "effects/video_effect.hpp" #include #include #include #include "core/video.hpp" #include "effects/source_fill.hpp" namespace effector { double Moment::length() const noexcept { return static_cast(std::max(1, frame_.count)) / std::max(1, frame_.fps); } double Moment::loopRate(double perSecond) const noexcept { const double clip = length(); return std::max(1.0, std::round(perSecond * clip)) / clip; } double Moment::cycle(double perSecond) const noexcept { return std::fmod(seconds() * loopRate(perSecond), 1.0); } Rng Moment::fresh() const noexcept { return Rng(seed_ ^ (0x9e3779b97f4a7c15ULL * static_cast(frame_.index + 1))); } Image VideoEffect::render(const std::vector& sources, int width, int height, Rng& rng, const ParamValues& values) const { return renderFrame(sources, width, height, rng, values, FrameTime{0, kDefaultFps, kDefaultFps}); } Image VideoEffect::renderFrame(const std::vector& sources, int width, int height, Rng& rng, const ParamValues& values, const FrameTime& frame) const { if (width < 1 || height < 1) throw EffectError("Canvas size must be at least 1x1 pixels."); const FrameTime at = frame.video() ? frame : FrameTime{0, kDefaultFps, kDefaultFps}; // An effect built from the sources takes no crop, only the one seed // everything it draws comes from -- the same value on every frame. if (needsSources()) { if (sources.empty()) throw EffectError("No source images."); const std::uint64_t seed = rng.next(); return compose(sources, width, height, values, Moment(at, seed)); } // Both of these take the same values from the shared rng on every frame: // the crop a leading stage starts from, and the one seed everything the // effect draws comes from. Image input = canvasFromSources(sources, width, height, rng); const std::uint64_t seed = rng.next(); return animate(std::move(input), values, Moment(at, seed)); } // A video effect writes one of these two; the other is never called. Image VideoEffect::animate(Image, const ParamValues&, const Moment&) const { throw std::logic_error(name() + " is a transform but writes no animate()"); } Image VideoEffect::compose(const std::vector&, int, int, const ParamValues&, const Moment&) const { throw std::logic_error(name() + " needs sources but writes no compose()"); } } // namespace effector