27 #define PERROR(x) LERROR("In file " << JEVOIS_ENGINE_CONFIG_FILE << ':' << linenum << ": " << x)
30 std::string jevois::VideoMapping::sopath()
const
32 if (ispython)
return JEVOIS_MODULE_PATH
"/" + vendor +
'/' + modulename +
'/' + modulename +
".py";
33 else return JEVOIS_MODULE_PATH
"/" + vendor +
'/' + modulename +
'/' + modulename +
".so";
37 std::string jevois::VideoMapping::srcpath()
const
39 if (ispython)
return JEVOIS_MODULE_PATH
"/" + vendor +
'/' + modulename +
'/' + modulename +
".py";
40 else return JEVOIS_MODULE_PATH
"/" + vendor +
'/' + modulename +
'/' + modulename +
".C";
44 unsigned int jevois::VideoMapping::osize()
const
48 unsigned int jevois::VideoMapping::csize()
const
52 unsigned int jevois::VideoMapping::c2size()
const
56 float jevois::VideoMapping::uvcToFps(
unsigned int interval)
59 return float(1000000000U / interval) * 0.01F;
63 unsigned int jevois::VideoMapping::fpsToUvc(
float fps)
65 return (
unsigned int)(10000000.0F / fps + 0.499F);
69 float jevois::VideoMapping::v4l2ToFps(
struct v4l2_fract
const & interval)
72 return float(interval.denominator * 100U / interval.numerator) * 0.01F;
76 struct v4l2_fract
jevois::VideoMapping::fpsToV4l2(float fps)
78 return { 100U, (
unsigned int)(fps * 100.0
F) };
82 std::string jevois::VideoMapping::ostr()
const
84 std::ostringstream ss;
85 ss <<
jevois::fccstr(ofmt) <<
' ' << ow <<
'x' << oh <<
" @ " << ofps <<
"fps";
90 std::string jevois::VideoMapping::cstr()
const
92 std::ostringstream ss;
93 ss <<
jevois::fccstr(cfmt) <<
' ' << cw <<
'x' << ch <<
" @ " << cfps <<
"fps";
98 std::string jevois::VideoMapping::c2str()
const
100 std::ostringstream ss;
101 ss <<
jevois::fccstr(c2fmt) <<
' ' << c2w <<
'x' << c2h <<
" @ " << cfps <<
"fps";
106 std::string jevois::VideoMapping::cstrall()
const
108 std::string ret = cstr();
109 if (crop == jevois::CropType::CropScale) ret +=
" + " + c2str();
114 std::string jevois::VideoMapping::str()
const
116 std::ostringstream ss;
118 ss <<
"OUT: " << ostr() <<
" CAM: " << cstr();
119 if (crop == jevois::CropType::CropScale) ss <<
" CAM2: " << c2str();
121 ss <<
" MOD: " << vendor <<
':' << modulename <<
' ' << (ispython ?
"Python" :
"C++");
127 std::string jevois::VideoMapping::menustr()
const
129 std::ostringstream ss;
131 ss << modulename << (ispython ?
" (Py)" :
" (C++)");
132 ss <<
" CAM: " << cstr();
133 if (crop == jevois::CropType::CropScale) ss <<
" + " << c2str();
139 bool jevois::VideoMapping::hasSameSpecsAs(VideoMapping
const & other)
const
141 return (ofmt == other.ofmt && ow == other.ow && oh == other.oh && std::abs(ofps - other.ofps) < 0.01F &&
142 cfmt == other.cfmt && cw == other.cw && ch == other.ch && std::abs(cfps - other.cfps) < 0.01F &&
143 crop == other.crop &&
144 (crop != jevois::CropType::CropScale ||
145 (c2fmt == other.c2fmt && c2w == other.c2w && c2h == other.c2h && std::abs(cfps - other.cfps) < 0.01F)));
149 bool jevois::VideoMapping::isSameAs(VideoMapping
const & other)
const
151 return (hasSameSpecsAs(other) && wdr == other.wdr && vendor == other.vendor && modulename == other.modulename &&
152 ispython == other.ispython);
156 std::ostream & jevois::operator<<(std::ostream & out, jevois::VideoMapping
const & m)
158 out <<
jevois::fccstr(m.ofmt) <<
' ' << m.ow <<
' ' << m.oh <<
' ' << m.ofps <<
' ';
160 if (m.wdr != jevois::WDRtype::Linear)
165 case jevois::CropType::Scale:
168 out << m.crop <<
':';
break;
169 case jevois::CropType::CropScale:
170 out << m.crop <<
'=' <<
jevois::fccstr(m.c2fmt) <<
'@' << m.c2w <<
'x' << m.c2h <<
':';
break;
173 out <<
jevois::fccstr(m.cfmt) <<
' ' << m.cw <<
' ' << m.ch <<
' ' << m.cfps <<
' '
174 << m.vendor <<
' ' << m.modulename;
181 int parse_relative_dim(std::string
const & str,
int c)
183 if (str.empty())
throw std::range_error(
"Invalid empty output width");
184 if (str[0] ==
'+')
return c + std::stoi(str.substr(1));
185 else if (str[0] ==
'-')
return c - std::stoi(str.substr(1));
186 return std::stoi(str);
189 void parse_cam_format(std::string
const & str,
unsigned int & fmt, jevois::WDRtype & wdr, jevois::CropType & crop,
190 unsigned int & c2fmt,
unsigned int & c2w,
unsigned int & c2h)
193 wdr = jevois::WDRtype::Linear;
194 crop = jevois::CropType::Scale;
198 if (tok.empty())
throw std::range_error(
"Empty camera format is not allowed");
200 for (std::string & t : tok)
203 try { wdr = jevois::from_string<jevois::WDRtype>(t);
continue; }
catch (...) { }
207 if (ttok.empty())
throw std::range_error(
"Invalid empty camera format modifier: " + t);
211 crop = jevois::from_string<jevois::CropType>(ttok[0]);
216 case jevois::CropType::Scale:
if (ttok.size() == 1)
continue;
break;
217 case jevois::CropType::CropScale:
218 if (ttok.size() == 4)
221 c2w = std::stoi(ttok[2]);
222 c2h = std::stoi(ttok[3]);
228 throw std::range_error(
"Invalid camera format modifier [" + t +
229 "] - must be Linear|DOL or Crop|Scale|CropScale=FCC@WxH");
235 std::istream & jevois::operator>>(std::istream & in, jevois::VideoMapping & m)
237 std::string of, cf, ows, ohs;
238 in >> of >> ows >> ohs >> m.ofps >> cf >> m.cw >> m.ch >> m.cfps >> m.vendor >> m.modulename;
242 m.ow = parse_relative_dim(ows, m.cw);
243 m.oh = parse_relative_dim(ohs, m.ch);
248 parse_cam_format(cf, m.cfmt, m.wdr, m.crop, m.c2fmt, m.c2w, m.c2h);
256 std::vector<jevois::VideoMapping> jevois::loadVideoMappings(jevois::CameraSensor s,
size_t & defidx,
bool checkso,
259 std::ifstream ifs(JEVOIS_ENGINE_CONFIG_FILE);
260 if (ifs.is_open() ==
false)
LFATAL(
"Could not open [" << JEVOIS_ENGINE_CONFIG_FILE <<
']');
261 return jevois::videoMappingsFromStream(s, ifs, defidx, checkso, hasgui);
265 std::vector<jevois::VideoMapping> jevois::videoMappingsFromStream(jevois::CameraSensor s, std::istream & is,
266 size_t & defidx,
bool checkso,
bool hasgui)
269 std::vector<jevois::VideoMapping> mappings;
270 jevois::VideoMapping defmapping = { };
272 for (std::string line; std::getline(is, line); ++linenum)
275 if (tok.empty())
continue;
276 if (tok.size() == 1 && tok[0].empty())
continue;
277 if (tok[0][0] ==
'#')
continue;
278 if (tok.size() < 10) {
PERROR(
"Found " << tok.size() <<
" tokens instead of >= 10 -- SKIPPING");
continue; }
280 jevois::VideoMapping m;
284 m.ofps = std::stof(tok[3]);
286 parse_cam_format(tok[4], m.cfmt, m.wdr, m.crop, m.c2fmt, m.c2w, m.c2h);
287 m.cw = std::stoi(tok[5]);
288 m.ch = std::stoi(tok[6]);
289 m.cfps = std::stof(tok[7]);
291 m.ow = parse_relative_dim(tok[1], m.cw);
292 m.oh = parse_relative_dim(tok[2], m.ch);
294 catch (std::exception
const & e) {
PERROR(
"Skipping entry because of parsing error: " << e.what());
continue; }
295 catch (...) {
PERROR(
"Skipping entry because of parsing errors");
continue; }
298 m.modulename = tok[9];
301 try { m.setModuleType(); }
305 {
PERROR(
"No .so|.py found for " << m.vendor <<
'/' << m.modulename <<
" -- SKIPPING.");
continue; }
309 if (m.sensorOk(s) ==
false)
310 {
PERROR(
"Camera video format [" << m.cstr() <<
"] not supported by sensor -- SKIPPING.");
continue; }
314 {
PERROR(
"Graphical user interface not available or disabled -- SKIPPING");
continue; }
319 {
PERROR(
"GUI output only supported on JeVois-Pro -- SKIPPING");
continue; }
321 #ifndef JEVOIS_PLATFORM
324 {
PERROR(
"Crop or Crop+Scale camera input only supported on JeVois-Pro platform -- SKIPPING");
continue; }
325 #endif // JEVOIS_PLATFORM
333 if (defmapping.cfmt == 0) defmapping = m;
334 if (tok.size() > 11 && tok[11][0] !=
'#')
PERROR(
"Extra garbage after 11th token ignored");
336 else if (tok[10][0] !=
'#')
PERROR(
"Extra garbage after 10th token ignored");
339 mappings.push_back(m);
344 std::sort(mappings.begin(), mappings.end(),
345 [=](jevois::VideoMapping
const & a, jevois::VideoMapping
const & b)
348 if (a.ofmt < b.ofmt) return true;
349 if (a.ofmt == b.ofmt) {
350 if (a.ow > b.ow) return true;
352 if (a.oh > b.oh) return true;
354 if (a.ofps > b.ofps) return true;
355 if (std::abs(a.ofps - b.ofps) < 0.01F) {
358 if (a.ofmt != 0 && a.ofmt != JEVOISPRO_FMT_GUI)
359 PERROR(
"WARNING: Two modes have identical output format: " << a.ostr());
362 if (a.cfmt < b.cfmt) return true;
363 if (a.cfmt == b.cfmt) {
364 if (a.cw > b.cw) return true;
366 if (a.ch > b.ch) return true;
368 if (a.cfps > b.cfps) return true;
383 if (checkso ==
false) { defidx = 0;
return mappings; }
386 if (mappings.empty() || mappings.back().ofmt == 0 || mappings.back().ofmt ==
JEVOISPRO_FMT_GUI)
388 PERROR(
"No valid video mapping with UVC output found -- INSERTING A DEFAULT ONE");
389 jevois::VideoMapping m;
390 m.ofmt = V4L2_PIX_FMT_YUYV; m.ow = 640; m.oh = 480; m.ofps = 30.0F;
391 m.cfmt = V4L2_PIX_FMT_YUYV; m.cw = 640; m.ch = 480; m.cfps = 30.0F;
392 m.vendor =
"JeVois"; m.modulename =
"PassThrough"; m.ispython =
false;
396 mappings.push_back(m);
403 auto a = mappings.begin(), b = a + 1;
404 while (b != mappings.end())
407 if (a->isSameAs(*b)) { b = mappings.erase(b);
continue; }
408 else if (b->ofmt != 0 && b->ofmt !=
JEVOISPRO_FMT_GUI && a->ofmt == b->ofmt && a->ow == b->ow && a->oh == b->oh)
410 if (std::abs(a->ofps - b->ofps) < 0.01F) b->ofps -= 1.0F;
411 else if (b->ofps > a->ofps) b->ofps = a->ofps - 1.0F;
417 if (defmapping.cfmt == 0)
419 LERROR(
"No default video mapping provided, using first one with UVC output");
420 for (
size_t i = 0; i < mappings.size(); ++i)
if (mappings[i].ofmt) { defidx = i;
break; }
425 for (
size_t i = 0; i < mappings.size(); ++i)
426 if (mappings[i].ofmt == defmapping.ofmt && mappings[i].ow == defmapping.ow &&
427 mappings[i].oh == defmapping.oh && mappings[i].ofps == defmapping.ofps)
428 { defidx = i;
break; }
435 unsigned int ofmt = ~0U, ow = ~0U, oh = ~0U, iformat = 0, iframe = 0;
436 for (jevois::VideoMapping & m : mappings)
438 if (m.ofmt == 0 || m.ofmt ==
JEVOISPRO_FMT_GUI) { m.uvcformat = 0; m.uvcframe = 0;
LDEBUG(m.str());
continue; }
439 if (m.ofmt != ofmt) { ofmt = m.ofmt; ow = ~0U; oh = ~0U; ++iformat; iframe = 0; }
440 if (m.ow != ow || m.oh != oh) { ow = m.ow; oh = m.oh; ++iframe; }
441 m.uvcformat = iformat; m.uvcframe = iframe;
449 bool jevois::VideoMapping::match(
unsigned int oformat,
unsigned int owidth,
unsigned int oheight,
450 float oframespersec)
const
452 if (ofmt == oformat && ow == owidth && oh == oheight && (std::abs(ofps - oframespersec) < 0.1
F))
return true;
457 bool jevois::VideoMapping::sensorOk(jevois::CameraSensor s)
463 void jevois::VideoMapping::setModuleType()
467 std::string sopa = sopath();
468 std::ifstream testifs(sopa);
469 if (testifs.is_open() ==
false)
472 ispython =
true; sopa = sopath();
473 std::ifstream testifs2(sopa);
474 if (testifs2.is_open() ==
false)
throw std::runtime_error(
"Could not open module file " + sopa +
"|.so");