13 std::span<const std::uint8_t>
bytes,
17 (
static_cast<std::uint32_t
>(
bytes[
offset + 1]) << 8U) |
18 (
static_cast<std::uint32_t
>(
bytes[
offset + 2]) << 16U) |
19 (
static_cast<std::uint32_t
>(
bytes[
offset + 3]) << 24U);
23 std::span<const std::uint8_t>
bytes,
32 std::span<const std::uint8_t>, std::string>
34 std::span<const std::uint8_t>
bytes,
42 const auto payload =
offset + 8;
43 if (payload + size >
bytes.size())
44 return std::unexpected(
45 "AVI chunk exceeds containing RIFF data");
48 return bytes.subspan(payload, size);
55 payload + 4, size - 4);
62 return std::unexpected(
"AVI chunk not found");
67 std::int32_t
frame)
noexcept
70 frame < status.numberOfFrames;
74 std::expected<AviMetadata, std::string>
77 if (
bytes.size() < 12 ||
80 return std::unexpected(
81 "video is not a RIFF AVI stream");
86 return std::unexpected(
87 "AVI RIFF size exceeds supplied data");
92 if (!
avih)
return std::unexpected(
avih.error());
93 if (
avih->size() < 40)
94 return std::unexpected(
95 "AVI main header is truncated");
103 if (result.microsecondsPerFrame == 0)
104 return std::unexpected(
105 "AVI main header has zero frame duration");
106 if (result.totalFrames == 0)
107 return std::unexpected(
108 "AVI main header has zero frames");
109 if (result.width == 0 || result.height == 0)
110 return std::unexpected(
111 "AVI main header has zero dimensions");
116 std::span<const std::uint8_t>
aviBytes,
130 static_cast<std::uint32_t
>(std::numeric_limits<std::int32_t>::max()))
131 return std::unexpected(
"video metadata is outside runtime limits");
137 status_.
ended =
false;
139 alternatives_.clear();
140 pendingJump_.reset();
151 alternatives_.clear();
152 pendingJump_.reset();
156 std::int32_t desiredFrame)
159 return std::unexpected(
160 "video runtime is not open");
161 if (desiredFrame < 0)
162 return std::unexpected(
163 "desired video frame is negative");
173 status_.
ended =
true;
179 status_.
ended =
false;
183 const auto decision = alternatives_.lower_bound(begin);
184 if (decision != alternatives_.end() &&
185 decision->first <= desiredFrame)
190 decision->second.takeJump};
192 if (decision->second.takeJump)
194 if (!
validFrame(status_, decision->second.jumpToFrame))
195 return std::unexpected(
196 "video alternative jump target is out of range");
212 std::expected<std::int32_t, std::string>
214 std::uint64_t elapsedMicroseconds)
const
217 return std::unexpected(
218 "video runtime is not open");
222 static_cast<std::uint64_t
>(
223 std::numeric_limits<std::int32_t>::max()))
224 return std::unexpected(
225 "elapsed video time exceeds runtime range");
226 return static_cast<std::int32_t
>(
frame);
233 return std::unexpected(
234 "video runtime is not open");
236 return std::unexpected(
237 "video cut target is out of range");
240 status_.
ended =
false;
245 std::int32_t decisionFrame,
246 std::int32_t jumpToFrame)
249 return std::unexpected(
250 "video runtime is not open");
252 return std::unexpected(
253 "video alternative decision frame is out of range");
256 alternatives_.erase(decisionFrame);
260 return std::unexpected(
261 "video alternative jump frame is out of range");
263 alternatives_[decisionFrame] =
264 Alternative{jumpToFrame,
false};
269 std::int32_t decisionFrame,
270 bool takeJump)
noexcept
273 alternatives_.find(decisionFrame);
274 if (
found == alternatives_.end())
276 found->second.takeJump = takeJump;
282 alternatives_.clear();
287 auto result = pendingJump_;
288 pendingJump_.reset();
LegacyBitmapMetadata metadata
std::vector< std::byte > bytes
const AviMetadata & metadata() const noexcept
std::expected< void, std::string > cutToFrame(std::int32_t frame)
std::expected< std::int32_t, std::string > frameAtElapsed(std::uint64_t elapsedMicroseconds) const
std::expected< Status, std::string > feedToFrame(std::int32_t desiredFrame)
std::optional< JumpEvent > takeJumpEvent() noexcept
bool open() const noexcept
std::expected< void, std::string > setAlternative(std::int32_t decisionFrame, std::int32_t jumpToFrame)
void forgetAlternatives() noexcept
bool changeAlternative(std::int32_t decisionFrame, bool takeJump) noexcept
std::expected< AviMetadata, std::string > parseAviMetadata(std::span< const std::uint8_t > bytes)
std::int32_t desiredFrame
std::int32_t currentFrame
std::int32_t numberOfFrames