7#include "fl/math_macros.h"
11#define DBG FASTLED_DBG
17VideoImpl::VideoImpl(
size_t pixelsPerFrame,
float fpsVideo,
18 size_t nFramesInBuffer)
19 : mPixelsPerFrame(pixelsPerFrame),
21 FrameInterpolatorPtr::New(MAX(1, nFramesInBuffer), fpsVideo)) {}
23void VideoImpl::pause(uint32_t now) {
25 mTimeScale = TimeScalePtr::New(now);
27 mTimeScale->pause(now);
29void VideoImpl::resume(uint32_t now) {
31 mTimeScale = TimeScalePtr::New(now);
33 mTimeScale->resume(now);
36void VideoImpl::setTimeScale(
float timeScale) {
38 mTimeScale = TimeScalePtr::New(0, timeScale);
40 mTimeScale->setScale(timeScale);
43bool VideoImpl::needsFrame(uint32_t now)
const {
45 bool out = mFrameInterpolator->needsFrame(now, &f1, &f2);
49VideoImpl::~VideoImpl() { end(); }
51void VideoImpl::begin(FileHandlePtr h) {
54 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
59void VideoImpl::beginStream(ByteStreamPtr bs) {
61 mStream = PixelStreamPtr::New(mPixelsPerFrame * kSizeRGB8);
63 mStream->beginStream(bs);
67void VideoImpl::end() {
68 mFrameInterpolator->clear();
73bool VideoImpl::full()
const {
return mFrameInterpolator->getFrames()->full(); }
75bool VideoImpl::draw(uint32_t now,
Frame *frame) {
81 updateBufferIfNecessary(mPrevNow, now);
86 bool ok = mFrameInterpolator->draw(now, frame);
90bool VideoImpl::draw(uint32_t now,
CRGB *leds) {
93 mTimeScale = TimeScalePtr::New(now);
95 now = mTimeScale->update(now);
100 bool ok = updateBufferIfNecessary(mPrevNow, now);
103 DBG(
"updateBufferIfNecessary failed");
106 mFrameInterpolator->draw(now, leds);
111bool VideoImpl::updateBufferFromStream(uint32_t now) {
113 FASTLED_DBG(
"no stream");
116 if (mStream->atEnd()) {
120 uint32_t currFrameNumber = 0;
121 uint32_t nextFrameNumber = 0;
122 bool needs_frame = mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
127 if (mFrameInterpolator->capacity() == 0) {
128 DBG(
"capacity == 0");
132 const bool has_current_frame = mFrameInterpolator->has(currFrameNumber);
133 const bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
136 if (!has_current_frame) {
137 frame_numbers.push_back(currFrameNumber);
139 size_t capacity = mFrameInterpolator->capacity();
140 if (capacity > 1 && !has_next_frame) {
141 frame_numbers.push_back(nextFrameNumber);
144 for (
size_t i = 0; i < frame_numbers.size(); ++i) {
145 FramePtr recycled_frame;
146 if (mFrameInterpolator->full()) {
147 uint32_t frame_to_erase = 0;
148 bool ok = mFrameInterpolator->get_oldest_frame_number(&frame_to_erase);
150 DBG(
"get_oldest_frame_number failed");
153 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
154 if (!recycled_frame) {
155 DBG(
"erase failed for frame: " << frame_to_erase);
159 uint32_t frame_to_fetch = frame_numbers[i];
160 if (!recycled_frame) {
162 recycled_frame = FramePtr::New(mPixelsPerFrame);
165 if (!mStream->readFrame(recycled_frame.get())) {
166 if (mStream->atEnd()) {
167 if (!mStream->rewind()) {
168 DBG(
"rewind failed");
171 mTimeScale->reset(now);
173 if (!mStream->readFrameAt(frame_to_fetch, recycled_frame.get())) {
174 DBG(
"readFrameAt failed");
178 DBG(
"We failed for some other reason");
182 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
184 DBG(
"insert failed");
191bool VideoImpl::updateBufferFromFile(uint32_t now,
bool forward) {
192 uint32_t currFrameNumber = 0;
193 uint32_t nextFrameNumber = 0;
194 bool needs_frame = mFrameInterpolator->needsFrame(now, &currFrameNumber, &nextFrameNumber);
198 bool has_curr_frame = mFrameInterpolator->has(currFrameNumber);
199 bool has_next_frame = mFrameInterpolator->has(nextFrameNumber);
200 if (has_curr_frame && has_next_frame) {
203 if (mFrameInterpolator->capacity() == 0) {
204 DBG(
"capacity == 0");
209 if (!mFrameInterpolator->has(currFrameNumber)) {
210 frame_numbers.push_back(currFrameNumber);
212 if (mFrameInterpolator->capacity() > 1 && !mFrameInterpolator->has(nextFrameNumber)) {
213 frame_numbers.push_back(nextFrameNumber);
216 for (
size_t i = 0; i < frame_numbers.size(); ++i) {
217 FramePtr recycled_frame;
218 if (mFrameInterpolator->full()) {
219 uint32_t frame_to_erase = 0;
222 ok = mFrameInterpolator->get_oldest_frame_number(&frame_to_erase);
224 DBG(
"get_oldest_frame_number failed");
228 ok = mFrameInterpolator->get_newest_frame_number(&frame_to_erase);
230 DBG(
"get_newest_frame_number failed");
234 recycled_frame = mFrameInterpolator->erase(frame_to_erase);
235 if (!recycled_frame) {
236 DBG(
"erase failed for frame: " << frame_to_erase);
240 uint32_t frame_to_fetch = frame_numbers[i];
241 if (!recycled_frame) {
243 recycled_frame = FramePtr::New(mPixelsPerFrame);
247 if (!mStream->readFrameAt(frame_to_fetch, recycled_frame.get())) {
252 if (mStream->atEnd()) {
253 if (!mStream->rewind()) {
254 DBG(
"rewind failed");
257 mTimeScale->reset(now);
259 if (!mStream->readFrameAt(frame_to_fetch, recycled_frame.get())) {
260 DBG(
"readFrameAt failed");
265 DBG(
"We failed for some other reason");
271 bool ok = mFrameInterpolator->insert(frame_to_fetch, recycled_frame);
273 DBG(
"insert failed");
280bool VideoImpl::updateBufferIfNecessary(uint32_t prev, uint32_t now) {
281 const bool forward = now >= prev;
283 PixelStream::Type type = mStream->getType();
285 case PixelStream::kFile:
286 return updateBufferFromFile(now, forward);
287 case PixelStream::kStreaming:
288 return updateBufferFromStream(now);
290 DBG(
"Unknown type: " << type);
295bool VideoImpl::rewind() {
296 if (!mStream || !mStream->rewind()) {
299 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)