MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
FrameSeekProcessor.cpp
Go to the documentation of this file.
2
5
9
11
12namespace MayaFlux::Kakshya {
13
14void FrameSeekProcessor::on_attach(const std::shared_ptr<SignalSourceContainer>& container)
15{
17 reset();
18}
19
20void FrameSeekProcessor::set_time_map(const std::shared_ptr<const Kinesis::TimeMap>& map)
21{
22 if (map == m_time_map) {
23 return;
24 }
25
26 m_time_map = map;
27 reset();
28}
29
30void FrameSeekProcessor::set_repeat(const std::shared_ptr<const Kinesis::TimeMap>& length)
31{
32 if (length == m_repeat) {
33 return;
34 }
35
39}
40
41void FrameSeekProcessor::trail(double write_head, Kinesis::TimeMap lag)
42{
43 const double fps = m_global_fps > 0.0 ? m_global_fps : 60.0;
44
45 set_time_map(std::make_shared<const Kinesis::TimeMap>(
46 Kinesis::TimeMaps::lagged(write_head, fps, std::move(lag))));
47}
48
49void FrameSeekProcessor::trail(double write_head, double lag_frames)
50{
51 trail(write_head, Kinesis::constant<double, double>(lag_frames));
52}
53
55{
56 m_ticks = 0;
59}
60
62{
63 const double fps = m_global_fps > 0.0 ? m_global_fps : 60.0;
64 double seconds = static_cast<double>(tick) / fps;
65
66 if (m_repeat && m_repeat->fn) {
67 if (m_repeat_length == 0 || tick - m_repeat_start >= m_repeat_length) {
68 m_repeat_start = tick;
69 const double length = std::max((*m_repeat)(seconds), 0.0);
70 m_repeat_length = std::max<uint64_t>(1, static_cast<uint64_t>(std::llround(length * fps)));
71 }
72
73 seconds = static_cast<double>(tick - m_repeat_start) / fps;
74 }
75
76 return (*m_time_map)(seconds);
77}
78
79void FrameSeekProcessor::process(const std::shared_ptr<SignalSourceContainer>& container)
80{
81 auto source = m_source_container_weak.lock();
82 auto video = std::dynamic_pointer_cast<VideoStreamContainer>(source);
83
84 if (video) {
85 m_total_frames = video->get_num_frames();
86 }
87
88 if (!m_time_map || !m_time_map->fn) {
90 return;
91 }
92
93 if (!m_prepared) {
95 "FrameSeekProcessor not prepared for processing");
96 return;
97 }
98
99 if (!video || source.get() != container.get()) {
101 "FrameSeekProcessor: source container mismatch, expired or not a VideoStreamContainer");
102 return;
103 }
104
105 if (m_total_frames == 0 || m_frame_byte_size == 0) {
106 return;
107 }
108
109 m_is_processing = true;
110
111 auto lo = 0.0;
112 auto hi = static_cast<double>(m_total_frames);
113
114 if (m_looping_enabled) {
115 if (!m_loop_region.start_coordinates.empty()) {
116 lo = static_cast<double>(m_loop_region.start_coordinates[0]);
117 }
118 if (!m_loop_region.end_coordinates.empty()) {
119 hi = std::min(hi, static_cast<double>(m_loop_region.end_coordinates[0] + 1));
120 }
121 if (hi <= lo) {
122 lo = 0.0;
123 hi = static_cast<double>(m_total_frames);
124 }
125 }
126
127 auto& processed = container->get_processed_data();
128 processed.resize(1);
129
130 auto* dest = std::get_if<std::vector<uint8_t>>(&processed[0]);
131 if (!dest) {
132 processed[0] = std::vector<uint8_t>();
133 dest = std::get_if<std::vector<uint8_t>>(&processed[0]);
134 }
136
137 uint8_t* out = dest->data();
138 uint64_t last_frame = 0;
139 bool all_ok = true;
140
141 for (uint64_t k = 0; k < m_frames_per_batch; ++k, out += m_frame_byte_size) {
142 const double position = position_at(m_ticks + k);
143 const double s = m_looping_enabled
144 ? Kinesis::wrap<double>(position, lo, hi)
145 : std::clamp(position, lo, hi - 1.0);
146 const double whole = std::floor(s);
147 const double weight = s - whole;
148 const auto first = static_cast<uint64_t>(whole);
149 last_frame = first;
150
151 const auto a = video->get_frame_pixels(first);
152 if (a.empty()) {
153 std::memset(out, 0, m_frame_byte_size);
154 all_ok = false;
155 continue;
156 }
157
158 if (m_blend && weight > 0.0) {
159 auto next = first + 1;
160 if (static_cast<double>(next) >= hi) {
161 next = m_looping_enabled ? static_cast<uint64_t>(lo) : first;
162 }
163
164 const auto b = video->get_frame_pixels(next);
165 if (!b.empty() && blend_frames(video->get_format(), a, b, out, weight)) {
166 continue;
167 }
168 }
169
170 std::memcpy(out, a.data(), m_frame_byte_size);
171 }
172
173 if (!all_ok) {
175 "FrameSeekProcessor: one or more frames unavailable near frame {}", last_frame);
176 }
177
179 m_current_frame = last_frame;
180 video->update_read_position_for_channel(0, last_frame);
181
182 m_is_processing = false;
183}
184
185} // namespace MayaFlux::Kakshya
#define MF_RT_ERROR(comp, ctx,...)
uint64_t length
Definition Composite.cpp:11
std::optional< glm::vec3 > position
Definition Decoder.cpp:93
bool fps
size_t a
double weight
size_t b
Factories for TimeMap: seconds since a voice started in, position in recorded material out (frames fo...
std::vector< float > * out
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Extract the current frame(s) into the container's processed_data.
std::weak_ptr< SignalSourceContainer > m_source_container_weak
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Attach the processor to a video container.
std::shared_ptr< const Kinesis::TimeMap > m_time_map
void reset()
Restart the clock and the repeat.
void set_repeat(const std::shared_ptr< const Kinesis::TimeMap > &length)
Restart the time map over and over, with a length that can change.
void trail(double write_head, Kinesis::TimeMap lag)
Trail a stream that is being written, by a lag that can change.
void set_time_map(const std::shared_ptr< const Kinesis::TimeMap > &map)
Drive the read position from a function of time.
void on_attach(const std::shared_ptr< SignalSourceContainer > &container) override
Attach the processor to a video container.
void process(const std::shared_ptr< SignalSourceContainer > &container) override
Extract the current frame(s) into the container's processed_data.
std::shared_ptr< const Kinesis::TimeMap > m_repeat
@ ContainerProcessing
Container operations (Kakshya - file/stream/region processing)
@ Kakshya
Containers[Signalsource, Stream, File], Regions, DataProcessors.
bool blend_frames(ImageFormat format, std::span< const uint8_t > a, std::span< const uint8_t > b, uint8_t *out, double weight)
Linearly blend two frames of the same size and format.
TimeMap lagged(double origin, double rate, TimeMap lag)
Position of a moving reference minus a lag that can itself change.
Definition TimeMap.hpp:95
std::vector< uint64_t > end_coordinates
Ending frame index (inclusive)
Definition Region.hpp:78
std::vector< uint64_t > start_coordinates
Starting frame index (inclusive)
Definition Region.hpp:75
Typed, composable, stateless callable from domain D to range R.
Definition Tendency.hpp:22