6#include "fl/math_macros.h"
14VideoImpl::VideoImpl(
size_t pixelsPerFrame,
float fpsVideo,
15 size_t nFramesInBuffer)
16 : mPixelsPerFrame(pixelsPerFrame),
18 FrameInterpolatorPtr::New(MAX(1, nFramesInBuffer), fpsVideo)) {}
20void VideoImpl::pause(uint32_t now) {
22 mTime = TimeScalePtr::New(now);
26void VideoImpl::resume(uint32_t now) {
28 mTime = TimeScalePtr::New(now);
33void VideoImpl::setTimeScale(
float timeScale) {
34 mTimeScale = timeScale;
36 mTime->setScale(timeScale);
40void VideoImpl::setFade(uint32_t fadeInTime, uint32_t fadeOutTime) {
41 mFadeInTime = fadeInTime;
42 mFadeOutTime = fadeOutTime;
45bool VideoImpl::needsFrame(uint32_t now)
const {
47 bool out = mFrameInterpolator->needsFrame(now, &f1, &f2);
51VideoImpl::~VideoImpl() { end(); }
53void VideoImpl::begin(FileHandlePtr h) {
56 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
61void VideoImpl::beginStream(ByteStreamPtr bs) {
63 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
65 mStream->beginStream(bs);
69void VideoImpl::end() {
70 mFrameInterpolator->clear();
75bool VideoImpl::full()
const {
return mFrameInterpolator->getFrames()->full(); }
77bool VideoImpl::draw(uint32_t now,
Frame *frame) {
78 return draw(now, frame->rgb());
81int32_t VideoImpl::durationMicros()
const {
85 int32_t frames = mStream->framesRemaining();
89 uint32_t micros_per_frame = mFrameInterpolator->getFrameTracker().microsecondsPerFrame();
90 return (frames * micros_per_frame);
93bool VideoImpl::draw(uint32_t now,
CRGB *leds) {
95 mTime = TimeScalePtr::New(now);
96 mTime->setScale(mTimeScale);
99 now = mTime->update(now);
101 FASTLED_WARN(
"no stream");
104 bool ok = updateBufferIfNecessary(mPrevNow, now);
107 FASTLED_WARN(
"updateBufferIfNecessary failed");
110 mFrameInterpolator->draw(now, leds);
112 uint32_t time = mTime->time();
113 uint32_t brightness = 255;
115 if (mFadeInTime || mFadeOutTime) {
117 if (time <= mFadeInTime) {
118 if (mFadeInTime == 0) {
121 brightness = time * 255 / mFadeInTime;
123 }
else if (mFadeOutTime) {
124 int32_t frames_remaining = mStream->framesRemaining();
125 if (frames_remaining < 0) {
130 mFrameInterpolator->getFrameTracker();
131 uint32_t micros_per_frame =
132 frame_tracker.microsecondsPerFrame();
133 uint32_t millis_left =
134 (frames_remaining * micros_per_frame) / 1000;
135 if (millis_left < mFadeOutTime) {
136 brightness = millis_left * 255 / mFadeOutTime;
141 if (brightness < 255) {
142 if (brightness == 0) {
143 for (
size_t i = 0; i < mPixelsPerFrame; ++i) {
147 for (
size_t i = 0; i < mPixelsPerFrame; ++i) {
155bool VideoImpl::updateBufferFromStream(uint32_t now) {
156 FASTLED_ASSERT(mTime,
"mTime is null");
158 FASTLED_WARN(
"no stream");
161 if (mStream->atEnd()) {
165 uint32_t currFrameNumber = 0;
166 uint32_t nextFrameNumber = 0;
168 mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
173 if (mFrameInterpolator->capacity() == 0) {
174 FASTLED_WARN(
"capacity == 0");
178 const bool has_current_frame = mFrameInterpolator->has(currFrameNumber);
179 const bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
182 if (!has_current_frame) {
183 frame_numbers.push_back(currFrameNumber);
185 size_t capacity = mFrameInterpolator->capacity();
186 if (capacity > 1 && !has_next_frame) {
187 frame_numbers.push_back(nextFrameNumber);
190 for (
size_t i = 0; i < frame_numbers.size(); ++i) {
191 FramePtr recycled_frame;
192 if (mFrameInterpolator->full()) {
193 uint32_t frame_to_erase = 0;
195 mFrameInterpolator->get_oldest_frame_number(&frame_to_erase);
197 FASTLED_WARN(
"get_oldest_frame_number failed");
200 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
201 if (!recycled_frame) {
202 FASTLED_WARN(
"erase failed for frame: " << frame_to_erase);
206 uint32_t frame_to_fetch = frame_numbers[i];
207 if (!recycled_frame) {
209 recycled_frame = FramePtr::New(mPixelsPerFrame);
212 if (!mStream->readFrame(recycled_frame.get())) {
213 if (mStream->atEnd()) {
214 if (!mStream->rewind()) {
215 FASTLED_WARN(
"rewind failed");
220 if (!mStream->readFrameAt(frame_to_fetch,
221 recycled_frame.get())) {
222 FASTLED_WARN(
"readFrameAt failed");
226 FASTLED_WARN(
"We failed for some other reason");
230 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
232 FASTLED_WARN(
"insert failed");
239bool VideoImpl::updateBufferFromFile(uint32_t now,
bool forward) {
240 uint32_t currFrameNumber = 0;
241 uint32_t nextFrameNumber = 0;
243 mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
247 bool has_curr_frame = mFrameInterpolator->has(currFrameNumber);
248 bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
249 if (has_curr_frame && has_next_frame) {
252 if (mFrameInterpolator->capacity() == 0) {
253 FASTLED_WARN(
"capacity == 0");
258 if (!mFrameInterpolator->has(currFrameNumber)) {
259 frame_numbers.push_back(currFrameNumber);
261 if (mFrameInterpolator->capacity() > 1 &&
262 !mFrameInterpolator->has(nextFrameNumber)) {
263 frame_numbers.push_back(nextFrameNumber);
266 for (
size_t i = 0; i < frame_numbers.size(); ++i) {
267 FramePtr recycled_frame;
268 if (mFrameInterpolator->full()) {
269 uint32_t frame_to_erase = 0;
272 ok = mFrameInterpolator->get_oldest_frame_number(
275 FASTLED_WARN(
"get_oldest_frame_number failed");
279 ok = mFrameInterpolator->get_newest_frame_number(
282 FASTLED_WARN(
"get_newest_frame_number failed");
286 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
287 if (!recycled_frame) {
288 FASTLED_WARN(
"erase failed for frame: " << frame_to_erase);
292 uint32_t frame_to_fetch = frame_numbers[i];
293 if (!recycled_frame) {
295 recycled_frame = FramePtr::New(mPixelsPerFrame);
299 if (!mStream->readFrameAt(frame_to_fetch, recycled_frame.get())) {
304 if (mStream->atEnd()) {
305 if (!mStream->rewind()) {
306 FASTLED_WARN(
"rewind failed");
311 if (!mStream->readFrameAt(frame_to_fetch,
312 recycled_frame.get())) {
313 FASTLED_WARN(
"readFrameAt failed");
318 FASTLED_WARN(
"We failed for some other reason");
324 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
326 FASTLED_WARN(
"insert failed");
333bool VideoImpl::updateBufferIfNecessary(uint32_t prev, uint32_t now) {
334 const bool forward = now >= prev;
336 PixelStream::Type type = mStream->getType();
338 case PixelStream::kFile:
339 return updateBufferFromFile(now, forward);
340 case PixelStream::kStreaming:
341 return updateBufferFromStream(now);
343 FASTLED_WARN(
"Unknown type: " << uint32_t(type));
348bool VideoImpl::rewind() {
349 if (!mStream || !mStream->rewind()) {
352 mFrameInterpolator->clear();
Implements the FastLED namespace macros.
Implements a simple red square effect for 2D LED grids.
Representation of an RGB pixel (Red, Green, Blue)
CRGB & nscale8(uint8_t scaledown)
Scale down a RGB to N/256ths of its current brightness, using "plain math" dimming rules.