FastLED 3.9.15
Loading...
Searching...
No Matches
video_impl.cpp
Go to the documentation of this file.
1
2
3#include "video_impl.h"
4
5#include "fl/assert.h"
6#include "fl/math_macros.h"
7#include "fl/namespace.h"
8#include "fl/warn.h"
9
10using namespace fl;
11
12namespace fl {
13
14VideoImpl::VideoImpl(size_t pixelsPerFrame, float fpsVideo,
15 size_t nFramesInBuffer)
16 : mPixelsPerFrame(pixelsPerFrame),
17 mFrameInterpolator(
18 FrameInterpolatorPtr::New(MAX(1, nFramesInBuffer), fpsVideo)) {}
19
20void VideoImpl::pause(uint32_t now) {
21 if (!mTime) {
22 mTime = TimeWarpPtr::New(now);
23 }
24 mTime->pause(now);
25}
26void VideoImpl::resume(uint32_t now) {
27 if (!mTime) {
28 mTime = TimeWarpPtr::New(now);
29 }
30 mTime->resume(now);
31}
32
33void VideoImpl::setTimeScale(float timeScale) {
34 mTimeScale = timeScale;
35 if (mTime) {
36 mTime->setSpeed(timeScale);
37 }
38}
39
40void VideoImpl::setFade(uint32_t fadeInTime, uint32_t fadeOutTime) {
41 mFadeInTime = fadeInTime;
42 mFadeOutTime = fadeOutTime;
43}
44
45bool VideoImpl::needsFrame(uint32_t now) const {
46 uint32_t f1, f2;
47 bool out = mFrameInterpolator->needsFrame(now, &f1, &f2);
48 return out;
49}
50
51VideoImpl::~VideoImpl() { end(); }
52
53void VideoImpl::begin(FileHandlePtr h) {
54 end();
55 // Removed setStartTime call
56 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
57 mStream->begin(h);
58 mPrevNow = 0;
59}
60
61void VideoImpl::beginStream(ByteStreamPtr bs) {
62 end();
63 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
64 // Removed setStartTime call
65 mStream->beginStream(bs);
66 mPrevNow = 0;
67}
68
69void VideoImpl::end() {
70 mFrameInterpolator->clear();
71 // Removed resetFrameCounter and setStartTime calls
72 mStream.reset();
73}
74
75bool VideoImpl::full() const { return mFrameInterpolator->getFrames()->full(); }
76
77bool VideoImpl::draw(uint32_t now, Frame *frame) {
78 return draw(now, frame->rgb());
79}
80
81int32_t VideoImpl::durationMicros() const {
82 if (!mStream) {
83 return -1;
84 }
85 int32_t frames = mStream->framesRemaining();
86 if (frames < 0) {
87 return -1; // Stream case, duration unknown
88 }
89 uint32_t micros_per_frame =
90 mFrameInterpolator->getFrameTracker().microsecondsPerFrame();
91 return (frames * micros_per_frame); // Convert to milliseconds
92}
93
94bool VideoImpl::draw(uint32_t now, CRGB *leds) {
95 if (!mTime) {
96 mTime = TimeWarpPtr::New(now);
97 mTime->setSpeed(mTimeScale);
98 mTime->reset(now);
99 }
100 now = mTime->update(now);
101 if (!mStream) {
102 FASTLED_WARN("no stream");
103 return false;
104 }
105 bool ok = updateBufferIfNecessary(mPrevNow, now);
106 mPrevNow = now;
107 if (!ok) {
108 FASTLED_WARN("updateBufferIfNecessary failed");
109 return false;
110 }
111 mFrameInterpolator->draw(now, leds);
112
113 uint32_t time = mTime->time();
114 uint32_t brightness = 255;
115 // Compute fade in/out brightness.
116 if (mFadeInTime || mFadeOutTime) {
117 brightness = 255;
118 if (time <= mFadeInTime) {
119 if (mFadeInTime == 0) {
120 brightness = 255;
121 } else {
122 brightness = time * 255 / mFadeInTime;
123 }
124 } else if (mFadeOutTime) {
125 int32_t frames_remaining = mStream->framesRemaining();
126 if (frames_remaining < 0) {
127 // -1 means this is a stream.
128 brightness = 255;
129 } else {
130 FrameTracker &frame_tracker =
131 mFrameInterpolator->getFrameTracker();
132 uint32_t micros_per_frame =
133 frame_tracker.microsecondsPerFrame();
134 uint32_t millis_left =
135 (frames_remaining * micros_per_frame) / 1000;
136 if (millis_left < mFadeOutTime) {
137 brightness = millis_left * 255 / mFadeOutTime;
138 }
139 }
140 }
141 }
142 if (brightness < 255) {
143 if (brightness == 0) {
144 for (size_t i = 0; i < mPixelsPerFrame; ++i) {
145 leds[i] = CRGB::Black;
146 }
147 } else {
148 for (size_t i = 0; i < mPixelsPerFrame; ++i) {
149 leds[i].nscale8(brightness);
150 }
151 }
152 }
153 return true;
154}
155
156bool VideoImpl::updateBufferFromStream(uint32_t now) {
157 FASTLED_ASSERT(mTime, "mTime is null");
158 if (!mStream) {
159 FASTLED_WARN("no stream");
160 return false;
161 }
162 if (mStream->atEnd()) {
163 return false;
164 }
165
166 uint32_t currFrameNumber = 0;
167 uint32_t nextFrameNumber = 0;
168 bool needs_frame =
169 mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
170 if (!needs_frame) {
171 return true;
172 }
173
174 if (mFrameInterpolator->capacity() == 0) {
175 FASTLED_WARN("capacity == 0");
176 return false;
177 }
178
179 const bool has_current_frame = mFrameInterpolator->has(currFrameNumber);
180 const bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
181
182 fl::FixedVector<uint32_t, 2> frame_numbers;
183 if (!has_current_frame) {
184 frame_numbers.push_back(currFrameNumber);
185 }
186 size_t capacity = mFrameInterpolator->capacity();
187 if (capacity > 1 && !has_next_frame) {
188 frame_numbers.push_back(nextFrameNumber);
189 }
190
191 for (size_t i = 0; i < frame_numbers.size(); ++i) {
192 FramePtr recycled_frame;
193 if (mFrameInterpolator->full()) {
194 uint32_t frame_to_erase = 0;
195 bool ok =
196 mFrameInterpolator->get_oldest_frame_number(&frame_to_erase);
197 if (!ok) {
198 FASTLED_WARN("get_oldest_frame_number failed");
199 return false;
200 }
201 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
202 if (!recycled_frame) {
203 FASTLED_WARN("erase failed for frame: " << frame_to_erase);
204 return false;
205 }
206 }
207 uint32_t frame_to_fetch = frame_numbers[i];
208 if (!recycled_frame) {
209 // Happens when we are not full and we need to allocate a new frame.
210 recycled_frame = FramePtr::New(mPixelsPerFrame);
211 }
212
213 if (!mStream->readFrame(recycled_frame.get())) {
214 if (mStream->atEnd()) {
215 if (!mStream->rewind()) {
216 FASTLED_WARN("rewind failed");
217 return false;
218 }
219 mTime->reset(now);
220 frame_to_fetch = 0;
221 if (!mStream->readFrameAt(frame_to_fetch,
222 recycled_frame.get())) {
223 FASTLED_WARN("readFrameAt failed");
224 return false;
225 }
226 } else {
227 FASTLED_WARN("We failed for some other reason");
228 return false;
229 }
230 }
231 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
232 if (!ok) {
233 FASTLED_WARN("insert failed");
234 return false;
235 }
236 }
237 return true;
238}
239
240bool VideoImpl::updateBufferFromFile(uint32_t now, bool forward) {
241 uint32_t currFrameNumber = 0;
242 uint32_t nextFrameNumber = 0;
243 bool needs_frame =
244 mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
245 if (!needs_frame) {
246 return true;
247 }
248 bool has_curr_frame = mFrameInterpolator->has(currFrameNumber);
249 bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
250 if (has_curr_frame && has_next_frame) {
251 return true;
252 }
253 if (mFrameInterpolator->capacity() == 0) {
254 FASTLED_WARN("capacity == 0");
255 return false;
256 }
257
258 fl::FixedVector<uint32_t, 2> frame_numbers;
259 if (!mFrameInterpolator->has(currFrameNumber)) {
260 frame_numbers.push_back(currFrameNumber);
261 }
262 if (mFrameInterpolator->capacity() > 1 &&
263 !mFrameInterpolator->has(nextFrameNumber)) {
264 frame_numbers.push_back(nextFrameNumber);
265 }
266
267 for (size_t i = 0; i < frame_numbers.size(); ++i) {
268 FramePtr recycled_frame;
269 if (mFrameInterpolator->full()) {
270 uint32_t frame_to_erase = 0;
271 bool ok = false;
272 if (forward) {
273 ok = mFrameInterpolator->get_oldest_frame_number(
274 &frame_to_erase);
275 if (!ok) {
276 FASTLED_WARN("get_oldest_frame_number failed");
277 return false;
278 }
279 } else {
280 ok = mFrameInterpolator->get_newest_frame_number(
281 &frame_to_erase);
282 if (!ok) {
283 FASTLED_WARN("get_newest_frame_number failed");
284 return false;
285 }
286 }
287 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
288 if (!recycled_frame) {
289 FASTLED_WARN("erase failed for frame: " << frame_to_erase);
290 return false;
291 }
292 }
293 uint32_t frame_to_fetch = frame_numbers[i];
294 if (!recycled_frame) {
295 // Happens when we are not full and we need to allocate a new frame.
296 recycled_frame = FramePtr::New(mPixelsPerFrame);
297 }
298
299 do { // only to use break
300 if (!mStream->readFrameAt(frame_to_fetch, recycled_frame.get())) {
301 if (!forward) {
302 // nothing more we can do, we can't go negative.
303 return false;
304 }
305 if (mStream->atEnd()) {
306 if (!mStream->rewind()) { // Is this still
307 FASTLED_WARN("rewind failed");
308 return false;
309 }
310 mTime->reset(now);
311 frame_to_fetch = 0;
312 if (!mStream->readFrameAt(frame_to_fetch,
313 recycled_frame.get())) {
314 FASTLED_WARN("readFrameAt failed");
315 return false;
316 }
317 break; // we have the frame, so we can break out of the loop
318 }
319 FASTLED_WARN("We failed for some other reason");
320 return false;
321 }
322 break;
323 } while (false);
324
325 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
326 if (!ok) {
327 FASTLED_WARN("insert failed");
328 return false;
329 }
330 }
331 return true;
332}
333
334bool VideoImpl::updateBufferIfNecessary(uint32_t prev, uint32_t now) {
335 const bool forward = now >= prev;
336
337 PixelStream::Type type = mStream->getType();
338 switch (type) {
340 return updateBufferFromFile(now, forward);
342 return updateBufferFromStream(now);
343 default:
344 FASTLED_WARN("Unknown type: " << uint32_t(type));
345 return false;
346 }
347}
348
349bool VideoImpl::rewind() {
350 if (!mStream || !mStream->rewind()) {
351 return false;
352 }
353 mFrameInterpolator->clear();
354 return true;
355}
356
357} // namespace fl
CRGB leds[NUM_LEDS]
Definition Apa102.ino:11
TimeWarp timeScale(0, 1.0f)
UISlider brightness("Brightness", 255, 0, 255, 1)
void draw(uint32_t now)
constexpr size_t size() const
Definition vector.h:134
void push_back(const T &value)
Definition vector.h:142
constexpr size_t capacity() const
Definition vector.h:139
bool insert(iterator pos, const T &value)
Definition vector.h:227
CRGB * rgb()
Definition frame.h:30
uint32_t microsecondsPerFrame() const
#define MAX(a, b)
Definition math_macros.h:11
Implements the FastLED namespace macros.
constexpr T && forward(typename remove_reference< T >::type &t) noexcept
Implements a simple red square effect for 2D LED grids.
Definition crgb.h:16
@ Black
<div style='background:#000000;width:4em;height:4em;'></div>
Definition crgb.h:504
Representation of an RGB pixel (Red, Green, Blue)
Definition crgb.h:55
#define FASTLED_WARN
Definition warn.h:7