27#define PERROR(x) LERROR("In file " << JEVOIS_ENGINE_CONFIG_FILE << ':' << linenum << ": " << x)
38 if (ispython)
return JEVOIS_MODULE_PATH "/" + vendor +
'/' + modulename +
'/' + modulename +
".py";
42 std::filesystem::path
const stem = modulename +
".so";
45 for (
auto const & entry : std::filesystem::directory_iterator(dir))
46 if (entry.path().stem() == stem)
47 try { ver = std::max(ver, std::stoi(entry.path().extension().string().substr(1))); }
52 std::filesystem::path
const latest = (dir / stem).
string() +
'.' + std::to_string(ver);
54 if (delete_old_versions)
55 for (
auto const & entry : std::filesystem::directory_iterator(dir))
56 if (entry.path().stem() == stem && entry.path() != latest)
57 std::filesystem::remove(entry.path());
59 return latest.string();
62 return (dir / stem).string();
68 if (ispython)
return JEVOIS_MODULE_PATH "/" + vendor +
'/' + modulename +
'/' + modulename +
".py";
69 else return JEVOIS_MODULE_PATH "/" + vendor +
'/' + modulename +
'/' + modulename +
".C";
100 return float(1000000000U / interval) * 0.01F;
106 return (
unsigned int)(10000000.0F / fps + 0.499F);
113 return float(interval.denominator * 100U / interval.numerator) * 0.01F;
119 return { 100U, (
unsigned int)(fps * 100.0F) };
125 std::ostringstream ss;
126 ss <<
jevois::fccstr(ofmt) <<
' ' << ow <<
'x' << oh <<
" @ " << ofps <<
"fps";
133 std::ostringstream ss;
134 ss <<
jevois::fccstr(cfmt) <<
' ' << cw <<
'x' << ch <<
" @ " << cfps <<
"fps";
141 std::ostringstream ss;
142 ss <<
jevois::fccstr(c2fmt) <<
' ' << c2w <<
'x' << c2h <<
" @ " << cfps <<
"fps";
149 std::string ret = cstr();
150 if (crop == jevois::CropType::CropScale) ret +=
" + " + c2str();
157 std::ostringstream ss;
159 ss <<
"OUT: " << ostr() <<
" CAM: " << cstr();
160 if (crop == jevois::CropType::CropScale) ss <<
" CAM2: " << c2str();
162 ss <<
" MOD: " << vendor <<
':' << modulename <<
' ' << (ispython ?
"Python" :
"C++");
170 std::ostringstream ss;
172 ss << modulename << (ispython ?
" (Py)" :
" (C++)");
173 ss <<
" CAM: " << cstr();
174 if (crop == jevois::CropType::CropScale) ss <<
" + " << c2str();
182 std::ostringstream ss;
184 ss << modulename << (ispython ?
" (Py)" :
" (C++)");
185 ss <<
" CAM: " << cstr();
186 if (crop == jevois::CropType::CropScale) ss <<
" + " << c2str();
191 case 0: ss <<
", OUT: None (headless)";
break;
192 default: ss <<
", OUT: " << ostr() <<
' ';
201 return (ofmt == other.
ofmt && ow == other.
ow && oh == other.
oh && std::abs(ofps - other.
ofps) < 0.01F &&
202 cfmt == other.
cfmt && cw == other.
cw && ch == other.
ch && std::abs(cfps - other.
cfps) < 0.01F &&
203 crop == other.
crop &&
204 (crop != jevois::CropType::CropScale ||
205 (c2fmt == other.
c2fmt && c2w == other.
c2w && c2h == other.
c2h && std::abs(cfps - other.
cfps) < 0.01F)));
211 return (hasSameSpecsAs(other) && wdr == other.
wdr && vendor == other.
vendor && modulename == other.
modulename &&
220 if (m.
wdr != jevois::WDRtype::Linear)
225 case jevois::CropType::Scale:
227 case jevois::CropType::Crop:
228 out << m.
crop <<
':';
break;
229 case jevois::CropType::CropScale:
241 int parse_relative_dim(std::string
const & str,
int c)
243 if (str.empty())
throw std::range_error(
"Invalid empty output width");
244 if (str[0] ==
'+')
return c + std::stoi(str.substr(1));
245 else if (str[0] ==
'-')
return c - std::stoi(str.substr(1));
246 return std::stoi(str);
249 void parse_cam_format(std::string
const & str,
unsigned int & fmt, jevois::WDRtype & wdr, jevois::CropType & crop,
250 unsigned int & c2fmt,
unsigned int & c2w,
unsigned int & c2h)
253 wdr = jevois::WDRtype::Linear;
254 crop = jevois::CropType::Scale;
259 if (tok.empty())
throw std::range_error(
"Empty camera format is not allowed");
261 for (std::string & t : tok)
264 try { wdr = jevois::from_string<jevois::WDRtype>(t);
continue; }
catch (...) { }
268 if (ttok.empty())
throw std::range_error(
"Invalid empty camera format modifier: " + t);
272 crop = jevois::from_string<jevois::CropType>(ttok[0]);
276 case jevois::CropType::Crop:
if (ttok.size() == 1)
continue;
break;
277 case jevois::CropType::Scale:
if (ttok.size() == 1)
continue;
break;
278 case jevois::CropType::CropScale:
279 if (ttok.size() == 4)
282 c2w = std::stoi(ttok[2]);
283 c2h = std::stoi(ttok[3]);
289 throw std::range_error(
"Invalid camera format modifier [" + t +
290 "] - must be Linear|DOL or Crop|Scale|CropScale=FCC@WxH");
298 std::string of, cf, ows, ohs;
303 m.
ow = parse_relative_dim(ows, m.
cw);
304 m.
oh = parse_relative_dim(ohs, m.
ch);
317std::vector<jevois::VideoMapping> jevois::loadVideoMappings(jevois::CameraSensor s,
size_t & defidx,
bool checkso,
322 return jevois::videoMappingsFromStream(s, ifs, defidx, checkso, hasgui);
326std::vector<jevois::VideoMapping> jevois::videoMappingsFromStream(jevois::CameraSensor s, std::istream & is,
327 size_t & defidx,
bool checkso,
bool hasgui)
330 std::vector<jevois::VideoMapping> mappings;
333 for (std::string line; std::getline(is, line); ++linenum)
336 if (tok.empty())
continue;
337 if (tok.size() == 1 && tok[0].empty())
continue;
338 if (tok[0][0] ==
'#')
continue;
339 if (tok.size() < 10) {
PERROR(
"Found " << tok.size() <<
" tokens instead of >= 10 -- SKIPPING");
continue; }
345 m.
ofps = std::stof(tok[3]);
348 m.
cw = std::stoi(tok[5]);
349 m.
ch = std::stoi(tok[6]);
350 m.
cfps = std::stof(tok[7]);
352 m.
ow = parse_relative_dim(tok[1], m.
cw);
353 m.
oh = parse_relative_dim(tok[2], m.
ch);
355 catch (std::exception
const & e) {
PERROR(
"Skipping entry because of parsing error: " << e.what());
continue; }
356 catch (...) {
PERROR(
"Skipping entry because of parsing errors");
continue; }
371 {
PERROR(
"Camera video format [" << m.
cstr() <<
"] not supported by sensor -- SKIPPING.");
continue; }
375 {
PERROR(
"Graphical user interface not available or disabled -- SKIPPING");
continue; }
380 {
PERROR(
"GUI output only supported on JeVois-Pro -- SKIPPING");
continue; }
382#ifndef JEVOIS_PLATFORM
384 if (m.
crop == jevois::CropType::CropScale || m.
crop == jevois::CropType::Crop)
385 {
PERROR(
"Crop or Crop+Scale camera input only supported on JeVois-Pro platform -- SKIPPING");
continue; }
394 if (defmapping.
cfmt == 0) { defmapping = m;
LINFO(
"Default in videomappings.cfg is " << m.
str()); }
395 if (tok.size() > 11 && tok[11][0] !=
'#')
PERROR(
"Extra garbage after 11th token ignored");
397 else if (tok[10][0] !=
'#')
PERROR(
"Extra garbage after 10th token ignored");
400 mappings.push_back(m);
405 std::sort(mappings.begin(), mappings.end(),
409 if (a.ofmt < b.ofmt) return true;
410 if (a.ofmt == b.ofmt) {
411 if (a.ow > b.ow) return true;
413 if (a.oh > b.oh) return true;
415 if (a.ofps > b.ofps) return true;
416 if (std::abs(a.ofps - b.ofps) < 0.01F) {
420 if (a.ofmt != 0 && a.ofmt != JEVOISPRO_FMT_GUI)
421 PERROR(
"WARNING: Two modes have identical output format: " << a.ostr());
424 if (a.cfmt < b.cfmt) return true;
425 if (a.cfmt == b.cfmt) {
426 if (a.cw > b.cw) return true;
428 if (a.ch > b.ch) return true;
430 if (a.cfps > b.cfps) return true;
445 if (checkso ==
false) { defidx = 0;
return mappings; }
448 if (mappings.empty() || mappings.back().ofmt == 0 || mappings.back().ofmt ==
JEVOISPRO_FMT_GUI)
450 PERROR(
"No valid video mapping with UVC output found -- INSERTING A DEFAULT ONE");
452 m.
ofmt = V4L2_PIX_FMT_YUYV; m.
ow = 640; m.
oh = 480; m.
ofps = 30.0F;
453 m.
cfmt = V4L2_PIX_FMT_YUYV; m.
cw = 640; m.
ch = 480; m.
cfps = 30.0F;
458 mappings.push_back(m);
465 auto a = mappings.begin(), b = a + 1;
466 while (b != mappings.end())
469 if (a->isSameAs(*b)) { b = mappings.erase(b);
continue; }
471 else if (b->ofmt != 0 && b->ofmt !=
JEVOISPRO_FMT_GUI && a->ofmt == b->ofmt && a->ow == b->ow && a->oh == b->oh)
473 if (std::abs(a->ofps - b->ofps) < 0.01F) b->ofps -= 1.0F;
474 else if (b->ofps > a->ofps) b->ofps = a->ofps - 1.0F;
481 if (defmapping.
cfmt == 0)
483 LERROR(
"No default video mapping provided, using first one with UVC output");
484 for (
size_t i = 0; i < mappings.size(); ++i)
if (mappings[i].ofmt) { defidx = i;
break; }
490 for (
size_t i = 0; i < mappings.size(); ++i)
if (mappings[i].isSameAs(defmapping)) { defidx = i;
break; }
497 unsigned int ofmt = ~0U, ow = ~0U, oh = ~0U, iformat = 0, iframe = 0;
501 if (m.
ofmt != ofmt) { ofmt = m.
ofmt; ow = ~0U; oh = ~0U; ++iformat; iframe = 0; }
502 if (m.
ow != ow || m.
oh != oh) { ow = m.
ow; oh = m.
oh; ++iframe; }
512 float oframespersec)
const
514 if (ofmt == oformat && ow == owidth && oh == oheight && (std::abs(ofps - oframespersec) < 0.1F))
return true;
523 std::string sopa = sopath();
524 std::ifstream testifs(sopa);
525 if (testifs.is_open() ==
false)
528 ispython =
true; sopa = sopath();
529 std::ifstream testifs2(sopa);
530 if (testifs2.is_open() ==
false)
throw std::runtime_error(
"Could not open module file " + sopa +
"|.so");
#define JEVOIS_MODULE_PATH
Base path for modules.
#define JEVOIS_ENGINE_CONFIG_FILE
Location of the engine videomappings.cfg definition file.
#define JEVOISPRO_FMT_GUI
JeVois-Pro zero-copy display of camera input frame (to be used as output mode in VideoMapping)
bool sensorSupportsFormat(CameraSensor s, VideoMapping const &m)
Check whether a given resolution and frame rate is supported by a sensor.
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
#define LDEBUG(msg)
Convenience macro for users to print out console or syslog messages, DEBUG level.
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
unsigned int strfcc(std::string const &str)
Convert a JeVois video format string to V4L2 four-cc code (V4L2_PIX_FMT_...)
std::string fccstr(unsigned int fcc)
Convert a V4L2 four-cc code (V4L2_PIX_FMT_...) to a 4-char string.
std::vector< std::string > split(std::string const &input, std::string const ®ex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...
unsigned int v4l2ImageSize(unsigned int fcc, unsigned int width, unsigned int height)
Return the image size in bytes for a given V4L2_PIX_FMT_..., width, height.
Main namespace for all JeVois classes and functions.
Simple struct to hold video mapping definitions for the processing Engine.
WDRtype wdr
Type of wide-dynamic-range (WDR) to use, if sensor supports it.
static struct v4l2_fract fpsToV4l2(float fps)
Convert from fps to V4L2 interval.
unsigned int cfmt
camera pixel format
unsigned int ow
output width
unsigned int csize() const
Return the size in bytes of a camera image.
unsigned int c2fmt
When crop is CropScale, pixel format of the scaled images, otherwise 0.
static float v4l2ToFps(struct v4l2_fract const &interval)
Convert from V4L2 interval to fps.
static unsigned int fpsToUvc(float fps)
Convert from fps to USB/UVC interval.
std::string modinfopath() const
Return the full absolute path and file name of the module's modinfo.html file.
bool hasSameSpecsAs(VideoMapping const &other) const
Equality operator for specs but not vendor or module name.
unsigned int c2w
When crop is CropScale, width of the scaled images, otherwise 0.
CropType crop
Type of crop/scale to apply if camera size does not match sensor native.
std::string modulename
Name of the Module that will process this mapping.
unsigned int osize() const
Return the size in bytes of an output image.
std::string ostr() const
Convenience function to print out FCC WxH @ fps, for the output (UVC) format.
std::string cstr() const
Convenience function to print out FCC WxH @ fps, for the input (camera) format.
std::string str() const
Convenience function to print out the whole mapping in a human-friendly way.
std::string c2str() const
Convenience function to print out FCC WxH @ fps, for the scaled camera input format,...
std::string cstrall() const
Convenience function to print out FCC WxH @ fps plus possibly second stream, for the input (camera) f...
float cfps
camera frame rate in frames/sec
bool ispython
True if the module is written in Python; affects behavior of sopath() only.
std::string menustr2() const
Convenience function to print out the whole mapping in a human-friendly way to be used in a menu.
void setModuleType()
Determine whether module is C++ or python and set ispython flag accordingly.
unsigned int c2size() const
Return the size in bytes of a scaled camera image, if stream==RawAndScaled, otherwise 0.
std::string path() const
Return the full absolute path the module's directory.
unsigned int cw
camera width
float ofps
output frame rate in frames/sec
unsigned int c2h
When crop is CropScale, height of the scaled images, otherwise 0.
unsigned int ch
camera height
bool isSameAs(VideoMapping const &other) const
Equality operator for specs and also vendor or module name.
unsigned int oh
output height
unsigned int uvcformat
USB-UVC format number (1-based)
static float uvcToFps(unsigned int interval)
Convert from USB/UVC interval to fps.
unsigned int uvcframe
USB UVC frame number (1-based)
std::string srcpath() const
Return the full absolute path and file name of the module's .C or .py file.
std::string menustr() const
Convenience function to print out the whole mapping in a human-friendly way to be used in a menu.
std::string vendor
Module creator name, used as a directory to organize the modules.
std::string sopath(bool delete_old_versions=false) const
Return the full absolute path and file name of the module's .so or .py file.
bool match(unsigned int oformat, unsigned int owidth, unsigned int oheight, float oframespersec) const
Return true if this VideoMapping's output format is a match to the given output parameters.
std::string cmakepath() const
Return the full absolute path and file name of the module's CMakeLists.txt file.
unsigned int ofmt
output pixel format, or 0 for no output over USB