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