35 #include <SimoxUtility/algorithm/string/string_tools.h>
52 PlaybackImageProvider::PlaybackImageProvider()
54 m_stereo_initialized =
false;
57 PlaybackImageProvider::~PlaybackImageProvider()
62 namespace fs = std::filesystem;
65 PlaybackImageProvider::onInitCapturingImageProvider()
67 getProperty(m_stereo_reference_frame,
"stereo.reference_frame");
68 getProperty(m_stereo_calibration_file,
"stereo.calibration_file");
70 fs::path basePath = getProperty<std::string>(
"base_path").getValue();
71 std::string recordingFilesStr = getProperty<std::string>(
"recording_files").getValue();
72 std::vector<std::string> recordingFiles =
simox::alg::split(recordingFilesStr,
";");
74 if (m_stereo_calibration_file !=
"" or m_stereo_reference_frame !=
"")
76 if (recordingFiles.size() != 2)
78 throw LocalException() <<
"Stereo calibration file and/or reference frame were set, "
79 <<
"but there are " << recordingFiles.size() <<
" recording "
80 <<
"files (expected 2).";
83 init_stereo_calibration_file();
84 init_stereo_calibration();
87 auto parse_fps = [](
const std::string& setting,
double source_fps) -> std::tuple<double, double>
92 const unsigned long int prefix_length = std::string(
"sourceX").size();
93 std::string setting_value;
94 std::function<double(
double,
double)> operation;
97 if (setting ==
"source")
99 return std::make_tuple(source_fps, 1.);
105 operation = [](
double x,
double y) ->
double {
return x * y; };
106 setting_value = setting.substr(prefix_length);
112 operation = [](
double x,
double y) ->
double {
return x / y; };
113 setting_value = setting.substr(prefix_length);
118 return std::make_tuple(std::stod(setting.substr(prefix_length)), 1.);
124 operation = [](double,
double fps) ->
double {
return fps; };
125 setting_value = setting;
128 const double derived_fps = operation(source_fps, std::stod(setting_value));
129 const double playback_speed_normalisation = source_fps / derived_fps;
131 return std::make_tuple(derived_fps, playback_speed_normalisation);
134 unsigned int refFrameHeight = 0;
135 unsigned int refFrameWidth = 0;
136 unsigned int actual_source_fps = 0;
139 for (std::string
const& recordingFile : recordingFiles)
141 fs::path fullPath = basePath !=
"" ? basePath / recordingFile : fs::path(recordingFile);
143 m_playbacks.push_back(playback);
147 ARMARX_ERROR <<
"Could not find a playback strategy for '" << fullPath.string() <<
"'";
154 if (refFrameHeight == 0 and refFrameWidth == 0)
156 refFrameHeight = playback->getFrameHeight();
157 refFrameWidth = playback->getFrameWidth();
162 <<
"Image source frame height cannot be 0 pixel";
164 <<
"Image source frame width cannot be 0 pixel";
168 <<
"Image source frames must have the same dimensions";
170 <<
"Image source frames must have the same dimensions";
174 if (playback->getFps() > actual_source_fps)
176 actual_source_fps = playback->getFps();
181 double playback_speed_normalisation;
182 std::tie(frameRate, playback_speed_normalisation) =
183 parse_fps(getProperty<std::string>(
"fps"), actual_source_fps);
185 playback_speed_normalisation * getProperty<double>(
"playback_speed_multiplier");
187 ARMARX_INFO <<
"Playback at " << frameRate <<
" FPS, advancing " << m_frame_advance
191 setNumberImages(
static_cast<int>(m_playbacks.size()));
193 ImageDimension(
static_cast<int>(refFrameWidth),
static_cast<int>(refFrameHeight)),
196 setImageSyncMode(eFpsSynchronization);
200 PlaybackImageProvider::onExitCapturingImageProvider()
202 for (
Playback& playback : m_playbacks)
204 playback->stopPlayback();
211 PlaybackImageProvider::onStartCapture(
float)
217 PlaybackImageProvider::onStopCapture()
223 PlaybackImageProvider::capture(
void** imageBuffer)
225 const bool loop = getProperty<bool>(
"loop");
228 for (
unsigned int i = 0; i < static_cast<unsigned int>(getNumberImages()); ++i)
233 if (not playback->hasNextFrame() and loop)
238 const unsigned int current_frame =
static_cast<unsigned int>(std::round(m_current_frame));
239 const unsigned int min_frame = 0;
240 const unsigned int max_frame = playback->getFrameCount() - 1;
241 unsigned int frame_index =
std::clamp(current_frame, min_frame, max_frame);
242 playback->setCurrentFrame(frame_index);
243 success |= playback->getNextFrame(imageBuffer[i]);
246 m_current_frame += m_frame_advance;
255 const bool memoryEnabled = getProperty<bool>(
"memory.enable");
256 if (memoryEnabled and imageBuffer !=
nullptr)
258 getImagesServerPlugin().commitImages(imageBuffer, time);
265 PlaybackImageProvider::getStereoCalibration(
const Ice::Current&)
267 assert_stereo_initialized();
268 return m_stereo_calibration;
272 PlaybackImageProvider::getImagesAreUndistorted(
const Ice::Current&)
274 assert_stereo_initialized();
279 PlaybackImageProvider::getReferenceFrame(
const Ice::Current&)
281 assert_stereo_initialized();
282 return m_stereo_reference_frame;
286 PlaybackImageProvider::getDefaultName()
const
288 return "PlaybackImageProvider";
292 PlaybackImageProvider::createPropertyDefinitions()
298 "List of recording files, separated by semicolons `;` for each channel. For video files, "
299 "use the filename, for image sequences, use the folder name where the image sequence is "
300 "located or any frame as pattern.\n"
301 "Wildcards (e.g. `frame_left_*.jpg;frame_right_*.jpg`) are supported as well.\n"
302 "Files will be interpreted as absolute paths, or relative paths to the current working "
303 "directory if base_path is not set. If base_path is set, all paths in recording_files are "
304 "interpreted relative to base_path");
305 defs->defineOptionalProperty<std::string>(
308 "Common base path of recording_files (will be prepened if set). To unset, use \"\"");
309 defs->defineOptionalProperty<
double>(
"playback_speed_multiplier",
311 "Adjust the playback speed with this multiplier, e.g. `2` "
312 "= double playback speed, `0.5` = "
313 "half playback speed")
315 defs->defineOptionalProperty<std::string>(
318 "Lock the FPS to an absolute value, or a value relative to source FPS. Valid inputs:\n"
319 " 1) `source` => Derive FPS from source\n"
320 " 2) `source*<X>`, with <X> being a positive decimal or integer => Playback with FPS "
322 "source FPS multiplied by <X>\n"
323 " 3) `source/<X>`, with <X> being a positive decimal or integer => Playback with FPS "
325 "source FPS devided by <X>\n"
326 " 4) `<X>`, with <X> being a positive decimal or integer => Playback with FPS at <X>\n"
327 " 5) `source=<X>`, with <X> being a positive decimal or integer => Playback with FPS "
329 "<X>, ignoring source FPS completely (Assume that <X> is source FPS)\n"
330 "With the exception of 5), all settings only have direct effect of the FPS the image "
331 "provider delivers the frames, but not on the playback speed. "
332 "Use `playback_speed_multiplier` to adjust that.\n"
333 "5) is only useful if the metadata of the recording is incomplete or incorrect (for "
334 "example when replaying generic image sequences where the FPS cannot be derived)")
336 R
"(source(\/|\*|=)(\d+(\.\d*)?|\.\d+)|(\d+(\.\d*)?|\.\d+)|(\d+(\.\d*)?|\.\d+)|source)");
337 defs->defineOptionalProperty<bool>(
338 "loop",
true,
"Whether the playback should restart after the last frame was provided");
341 defs->defineOptionalProperty<std::string>(
342 "stereo.calibration_file",
344 "Path to a stereo calibration file that should additionally be provided.");
345 defs->defineOptionalProperty<std::string>(
346 "stereo.reference_frame",
348 "Path to a stereo calibration file that should additionally be provided.");
352 defs->defineOptionalProperty<
bool>(
353 "memory.enable",
true,
"If true, also provide the images as a memory server.");
359 PlaybackImageProvider::init_stereo_calibration_file()
362 m_stereo_calibration_file);
371 PlaybackImageProvider::init_stereo_calibration()
373 const bool transform_left_camera_to_identity =
true;
374 const bool loading_calibration_sucessful = m_stereo_calibration_ivt.LoadCameraParameters(
375 m_stereo_calibration_file.c_str(), transform_left_camera_to_identity);
377 if (not loading_calibration_sucessful)
383 m_stereo_initialized =
true;
387 PlaybackImageProvider::assert_stereo_initialized()
389 if (not m_stereo_initialized)
391 throw LocalException() <<
"Stereo calibration API was called, but the calibration of this "
392 <<
"PlaybackProvider (instance name '" << getName() <<
"') was "
393 <<
"never initialized.\n"
394 <<
"Provide this PlaybackProvider instance with a calibration file "
395 <<
"using the 'stereo.calibration_file' property.";