FastLED 3.10.8
Loading...
Searching...
No Matches

◆ begin()

bool fl::video::PixelStream::begin ( fl::filebuf_ptr h)

Definition at line 40 of file pixel_stream.cpp.hpp.

40 {
41 close();
42 if (!h || mBaseBytesPerFrame <= 0) {
43 return false;
44 }
45 mHandle = h;
51 mHasVideoColor = false;
52 mHasFledContainer = false;
56 mStreamingRejected = false;
57 // Probe seekability: if seek-to-start succeeds, this is a seekable file.
59 if (mType == kFile) {
60 // A file without FLED magic remains a legacy headerless RGB stream.
61 // Once magic is recognized, though, every invalidity is a container
62 // error: falling back would render its header bytes as LEDs.
63 if (mHandle->size() >= 4) {
64 char hdr[kFledHeaderBytes];
65 fl::size_t got = mHandle->read(hdr, kFledHeaderBytes);
66 const bool hasFledMagic = got >= 4
67 && static_cast<fl::u8>(hdr[0]) == kFledMagic[0]
68 && static_cast<fl::u8>(hdr[1]) == kFledMagic[1]
69 && static_cast<fl::u8>(hdr[2]) == kFledMagic[2]
70 && static_cast<fl::u8>(hdr[3]) == kFledMagic[3];
71 if (hasFledMagic) {
72 const bool supportedFled = got == kFledHeaderBytes
73 && static_cast<fl::u8>(hdr[4]) == kFledVersionV1
74 && static_cast<fl::u8>(hdr[6]) == 0
75 && static_cast<fl::u8>(hdr[7]) == 0
76 && fled::bytesPerLed(static_cast<fl::u8>(hdr[5])) != 0;
77 if (!supportedFled) {
78 close();
79 return false;
80 }
81 const fl::u8 pixelFormat = static_cast<fl::u8>(hdr[5]);
82 const fl::u32 jsonLen =
83 static_cast<fl::u32>(static_cast<fl::u8>(hdr[8]))
84 | (static_cast<fl::u32>(static_cast<fl::u8>(hdr[9])) << 8)
85 | (static_cast<fl::u32>(static_cast<fl::u8>(hdr[10])) << 16)
86 | (static_cast<fl::u32>(static_cast<fl::u8>(hdr[11])) << 24);
87 // Cap the JSON length against a defensive maximum BEFORE
88 // doing any size arithmetic — guards against a malformed
89 // file declaring a multi-gigabyte json_length that would
90 // either overflow the offset calc or trigger a huge resize.
91 const fl::size_t jsonLenSz = static_cast<fl::size_t>(jsonLen);
92 const fl::size_t fileSize = mHandle->size();
93 const bool jsonInRange = jsonLenSz <= kFledMaxJsonBytes
94 && jsonLenSz <= fileSize - kFledHeaderBytes;
95 if (jsonInRange) {
96 mEmbeddedScreenMapJson.resize(static_cast<fl::size>(jsonLenSz));
97 fl::size_t jr = jsonLenSz > 0
98 ? mHandle->read(&mEmbeddedScreenMapJson[0], jsonLenSz)
99 : 0;
100 if (jr == jsonLenSz) {
101 mPayloadOffset = kFledHeaderBytes + jsonLenSz;
102 mFledPixelFormat = pixelFormat;
103 mFledBytesPerLed = fled::bytesPerLed(pixelFormat);
104 mHasFledContainer = true;
105 if (mbytesPerFrame % 3 != 0) {
106 close();
107 return false;
108 }
109 const fl::i32 ledCount = mbytesPerFrame / 3;
110 const fl::i32 bytesPerLed =
111 static_cast<fl::i32>(mFledBytesPerLed);
112 if (ledCount > (fl::numeric_limits<fl::i32>::max)() /
113 bytesPerLed) {
114 close();
115 return false;
116 }
117 mbytesPerFrame = ledCount * bytesPerLed;
118 if ((fileSize - mPayloadOffset) %
119 static_cast<fl::size_t>(mbytesPerFrame) != 0) {
120 close();
121 return false;
122 }
123 fl::json envelope;
124 if (!mEmbeddedScreenMapJson.empty()) {
126 }
127 const bool validEnvelope = mEmbeddedScreenMapJson.empty() ||
128 (envelope.has_value() && envelope.is_object());
129 if (!validEnvelope) {
130 close();
131 return false;
132 }
133 const bool colorOk =
135 &mVideoColor) ==
137 mHasVideoColor = colorOk;
138 if (!colorOk) {
139 fled::PixelStorage storage;
140 const bool advisoryRgb8 = pixelStorage(&storage) &&
141 storage.mFormat == fl::PixelFormat::Rgb8;
142 if (!mBestEffortFled || !advisoryRgb8) {
143 close();
144 return false;
145 }
146 FL_WARN("FLED video.color rejected; using explicit best-effort RGB8 playback");
147 }
148 // Stream is now positioned at the first frame byte.
149 return mHandle->available();
150 }
152 }
153 // FLED magic was recognized, so malformed/truncated
154 // containers must not become headerless raw RGB.
155 close();
156 return false;
157 }
158 // No magic: rewind so subsequent reads see raw RGB triplets.
159 mHandle->seek(0, seek_dir::beg);
160 }
161 return mHandle->available();
162 }
163 // A partial FLED prefix stays buffered until enough bytes arrive to
164 // classify it. A raw mismatch is replayed through readBytes().
166 if (!probeStreamingMagic()) {
167 close();
168 return false;
169 }
170 return true;
171}
bool is_object() const FL_NO_EXCEPT
Definition json.h:391
bool has_value() const FL_NO_EXCEPT
Definition json.h:819
static json parse(const fl::string &txt) FL_NO_EXCEPT
Definition json.h:842
fl::filebuf_ptr mHandle
const fl::i32 mBaseBytesPerFrame
bool probeStreamingMagic() const FL_NO_EXCEPT
bool pixelStorage(fled::PixelStorage *out) const FL_NO_EXCEPT
fl::size_t mStreamingPrefixPos
void close() FL_NO_EXCEPT
fl::size_t mStreamingPrefixSize
fled::VideoColor mVideoColor
fl::string mEmbeddedScreenMapJson
#define FL_WARN(...)
Definition log.h:437
__SIZE_TYPE__ size_t
Definition s16x16x4.h:16
fl::u8 bytesPerLed(fl::u8 pixelFormat) FL_NO_EXCEPT
ColorStatus resolveVideoColor(const fl::json &envelope, fl::u8 pixelFormat, VideoColor *out) FL_NO_EXCEPT
unsigned char u8
Definition stdint.h:131
static constexpr T max() FL_NO_EXCEPT
Definition limits.h:108

References fl::beg, fl::fled::bytesPerLed(), close(), fl::FL_NO_EXCEPT, FL_WARN, fl::json::has_value(), fl::json::is_object(), kFile, kStreaming, fl::numeric_limits< T >::max(), mBaseBytesPerFrame, mBestEffortFled, mbytesPerFrame, mEmbeddedScreenMapJson, mFledBytesPerLed, mFledPixelFormat, fl::fled::PixelStorage::mFormat, mHandle, mHasFledContainer, mHasVideoColor, mPayloadOffset, mStreamingPrefixPos, mStreamingPrefixSize, mStreamingProbePending, mStreamingRejected, mType, mVideoColor, fl::fled::Ok, fl::json::parse(), pixelStorage(), probeStreamingMagic(), fl::fled::resolveVideoColor(), and fl::Rgb8.

+ Here is the call graph for this function: