FastLED 3.9.3
Loading...
Searching...
No Matches
frame_interpolator.cpp
1#include "fx/video/frame_interpolator.h"
2#include "fx/detail/circular_buffer.h"
3#include "fx/detail/data_stream.h"
4#include "math_macros.h"
5#include "namespace.h"
6
7FASTLED_NAMESPACE_BEGIN
8
9FrameInterpolator::FrameInterpolator(size_t nframes, float fps)
10 : mFrames(MAX(1, nframes)), mInterval(fps) {
11}
12
13bool FrameInterpolator::draw(uint32_t now, Frame *dst) {
14 bool ok = draw(now, dst->rgb(), dst->alpha(), &now);
15 if (ok) {
16 dst->setTimestamp(now);
17 }
18 return ok;
19}
20
21bool FrameInterpolator::draw(uint32_t now, CRGB* leds, uint8_t* alpha, uint32_t* precise_timestamp) {
22 const Frame *frameMin = nullptr;
23 const Frame *frameMax = nullptr;
24 if (!selectFrames(now, &frameMin, &frameMax)) {
25 return false;
26 }
27 if (!frameMin || !frameMax) {
28 // we should not be here
29 return false;
30 }
31 // Calculate interpolation factor
32 uint32_t total_duration = frameMax->getTimestamp() - frameMin->getTimestamp();
33 if (frameMin == frameMax || total_duration == 0) {
34 // There is only one frame, so just copy it
35 frameMax->draw(leds, alpha);
36 if (precise_timestamp) {
37 *precise_timestamp = frameMax->getTimestamp();
38 }
39 return true;
40 }
41 uint32_t elapsed = now - frameMin->getTimestamp();
42 uint8_t progress = (elapsed * 255) / total_duration;
43 // Interpolate between the two frames
44 Frame::interpolate(*frameMin, *frameMax, progress, leds, alpha);
45 if (precise_timestamp) {
46 *precise_timestamp = frameMin->getTimestamp() + elapsed;
47 }
48 return true;
49}
50
51bool FrameInterpolator::addWithTimestamp(const Frame &frame,
52 uint32_t timestamp) {
53 // Check if the new frame's timestamp is newer than all existing frames
54 if (!mFrames.empty() && timestamp <= mFrames.back()->getTimestamp()) {
55 return false; // Reject the frame if it's not newer than the newest
56 // frame
57 }
58
59 if (mFrames.empty()) {
60 // Insert the first frame
61 FrameRef newFrame = FrameRef::New(frame.size(), !!frame.alpha());
62 newFrame->copy(frame);
63 newFrame->setTimestamp(timestamp);
64 mFrames.push_back(newFrame);
65 return true;
66 }
67
68 if (timestamp <= mFrames.front()->getTimestamp()) {
69 // Reject the frame as it's older than newest frame.
70 return false;
71 }
72
73 FrameRef newFrame;
74 if (mFrames.full()) {
75 // Reuse the oldest frame
76 bool ok = mFrames.pop_back(&newFrame);
77 if (!ok || !newFrame) {
78 // Something unexpected happened. This should never occur.
79 return false;
80 }
81 } else {
82 // Allocate a new frame
83 newFrame = FrameRef::New(frame.size(), !!frame.alpha());
84 }
85 newFrame->copy(frame);
86 newFrame->setTimestamp(timestamp);
87
88 // Insert the new frame at the front
89 mFrames.push_front(newFrame);
90
91 return true;
92}
93
94bool FrameInterpolator::add(const Frame &frame) {
95 return addWithTimestamp(frame, frame.getTimestamp());
96}
97
98bool FrameInterpolator::selectFrames(uint32_t now, const Frame **frameMin,
99 const Frame **frameMax) const {
100 if (mFrames.empty()) {
101 *frameMin = *frameMax = nullptr;
102 return false;
103 }
104
105 if (mFrames.size() == 1) {
106 *frameMin = *frameMax = mFrames.front().get();
107 return true;
108 }
109
110 // handle case before first timestamp
111 if (now <= mFrames.back()->getTimestamp())
112 {
113 *frameMin = mFrames.back().get();
114 *frameMax = mFrames.back().get();
115 return true;
116 }
117
118
119 // Handle case after the last frame
120 if (now >= mFrames.front()->getTimestamp()) {
121 Frame* cur = mFrames.front().get();
122 *frameMin = cur;
123 *frameMax = cur;
124 return true;
125 }
126
127 // Find the two frames that bracket the given timestamp
128 for (size_t i = 0; i < mFrames.size() - 1; ++i) {
129 if (now <= mFrames[i]->getTimestamp() && mFrames[i + 1]->getTimestamp() <= now) {
130 *frameMax = mFrames[i].get();
131 *frameMin = mFrames[i + 1].get();
132 return true;
133 }
134 }
135 return false;
136}
137
138FASTLED_NAMESPACE_END
Definition frame.h:18
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:39