4#include "fx/detail/data_stream.h"
6#include "fx/video/frame_interpolator.h"
9#define DEBUG_IO_STREAM 1
11#define DEBUG_IO_STREAM 0
24FASTLED_NAMESPACE_BEGIN
28FASTLED_SMART_REF(
Frame);
35 VideoImpl(
size_t pixelsPerFrame,
float fpsVideo,
36 size_t frameHistoryCount = 0);
39 void begin(FileHandleRef h);
40 void beginStream(ByteStreamRef s);
41 bool draw(uint32_t now,
CRGB *leds, uint8_t *alpha =
nullptr);
45 bool draw(uint32_t now,
Frame *frame);
48 void pushNewest(FrameRef frame);
51 bool updateBufferIfNecessary(uint32_t now);
52 uint32_t mPixelsPerFrame = 0;
53 DataStreamRef mStream;
54 FrameInterpolatorRef mInterpolator;
57VideoImpl::VideoImpl(
size_t pixelsPerFrame,
float fpsVideo,
58 size_t nFramesInBuffer)
59 : mPixelsPerFrame(pixelsPerFrame),
61 FrameInterpolatorRef::New(MAX(1, nFramesInBuffer), fpsVideo)) {}
63VideoImpl::~VideoImpl() { end(); }
65void VideoImpl::begin(FileHandleRef h) {
68 mStream = DataStreamRef::New(mPixelsPerFrame);
72void VideoImpl::beginStream(ByteStreamRef bs) {
74 mStream = DataStreamRef::New(mPixelsPerFrame);
76 mStream->beginStream(bs);
79void VideoImpl::end() {
80 mInterpolator->clear();
85void VideoImpl::pushNewest(FrameRef frame) {
86 mInterpolator->push_front(frame, frame->getTimestamp());
89bool VideoImpl::full()
const {
return mInterpolator->getFrames()->full(); }
91FrameRef VideoImpl::popOldest() {
93 mInterpolator->pop_back(&frame);
97bool VideoImpl::draw(uint32_t now,
Frame *frame) {
101 updateBufferIfNecessary(now);
105 return mInterpolator->draw(now, frame);
108bool VideoImpl::draw(uint32_t now,
CRGB *leds, uint8_t *alpha) {
112 bool ok = updateBufferIfNecessary(now);
115 memset(leds, 0, mPixelsPerFrame *
sizeof(
CRGB));
117 memset(alpha, 0, mPixelsPerFrame);
121 mInterpolator->draw(now, leds, alpha);
125bool VideoImpl::updateBufferIfNecessary(uint32_t now) {
127 uint32_t precise_timestamp;
130 bool needs_frame = mInterpolator->needsFrame(now, &precise_timestamp);
138 if (mInterpolator->full()) {
139 if (!mInterpolator->popOldest(&frame)) {
140 DBG(cout <<
"popOldest failed" << endl);
144 frame = FrameRef::New(mPixelsPerFrame,
false);
146 if (mStream->readFrame(frame.get())) {
147 if (mInterpolator->pushNewest(frame, now)) {
149 mInterpolator->incrementFrameCounter();
153 DBG(cout <<
"readFrame failed" << endl);
155 mInterpolator->push_front(frame, frame->getTimestamp());
160bool VideoImpl::rewind() {
161 if (!mStream || !mStream->rewind()) {
164 mInterpolator->clear();
168Video::Video() =
default;
169Video::Video(FileHandleRef h,
size_t pixelsPerFrame,
float fps,
size_t frameHistoryCount) {
170 begin(h, pixelsPerFrame, fps, frameHistoryCount);
172Video::Video(ByteStreamRef s,
size_t pixelsPerFrame,
float fps,
size_t frameHistoryCount) {
173 beginStream(s, pixelsPerFrame, fps, frameHistoryCount);
175Video::~Video() =
default;
176Video::Video(
const Video &) =
default;
177Video &Video::operator=(
const Video &) =
default;
179void Video::begin(FileHandleRef h,
size_t pixelsPerFrame,
float fps,
180 size_t frameHistoryCount) {
182 mImpl = VideoImplRef::New(pixelsPerFrame, fps, frameHistoryCount);
186void Video::beginStream(ByteStreamRef bs,
size_t pixelsPerFrame,
float fps,
187 size_t frameHistoryCount) {
189 mImpl = VideoImplRef::New(pixelsPerFrame, fps, frameHistoryCount);
190 mImpl->beginStream(bs);
193bool Video::draw(uint32_t now,
CRGB *leds, uint8_t *alpha) {
197 bool ok = mImpl->draw(now, leds, alpha);
205bool Video::draw(uint32_t now,
Frame *frame) {
209 return mImpl->draw(now, frame);
218bool Video::finished() {
225bool Video::rewind() {
229 return mImpl->rewind();
236 mFrame = FrameRef::New(mXyMap.getTotal(),
false);
238 bool ok = mVideo.draw(context.now, mFrame.get());
241 ok = mVideo.draw(context.now, mFrame.get());
250 const CRGB *src_pixels = mFrame->rgb();
251 CRGB *dst_pixels = context.leds;
253 for (uint16_t w = 0; w < mXyMap.getWidth(); w++) {
254 for (uint16_t h = 0; h < mXyMap.getHeight(); h++) {
255 const size_t index = mXyMap.mapToIndex(w, h);
256 if (index < mFrame->size()) {
257 dst_pixels[dst_pos++] = src_pixels[index];
263const char * VideoFx::fxName(
int)
const {
return "video"; }
void draw(DrawContext context) override
Representation of an RGB pixel (Red, Green, Blue)