291 lines
7.5 KiB
C++
291 lines
7.5 KiB
C++
|
|
#include <lcameraBuffParams.h>
|
||
|
|
#include <sstream>
|
||
|
|
#include <stdexcept>
|
||
|
|
#include <unordered_map>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
namespace smo {
|
||
|
|
namespace stim_buff {
|
||
|
|
namespace lcamera_buff {
|
||
|
|
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
constexpr const char *mutuallyExclusiveResolutionMessage =
|
||
|
|
"lcameraBuff: explicit dimension width/height params cannot be combined "
|
||
|
|
"with vertical-resolution shorthand params";
|
||
|
|
|
||
|
|
constexpr const char *missingResolutionMessage =
|
||
|
|
"lcameraBuff: specify either explicit dimension width and height, or a "
|
||
|
|
"vertical-resolution shorthand (v-res, vres, etc.)";
|
||
|
|
|
||
|
|
constexpr const char *incompleteExplicitResolutionMessage =
|
||
|
|
"lcameraBuff: both dimension width and height are required when using "
|
||
|
|
"explicit dimension params";
|
||
|
|
|
||
|
|
const std::vector<std::string> widthParamSynonyms = {
|
||
|
|
"frame-width",
|
||
|
|
"frame-w",
|
||
|
|
"dimension-width",
|
||
|
|
"dimension-w",
|
||
|
|
"dim-width",
|
||
|
|
"dim-w",
|
||
|
|
};
|
||
|
|
|
||
|
|
const std::vector<std::string> heightParamSynonyms = {
|
||
|
|
"frame-height",
|
||
|
|
"frame-h",
|
||
|
|
"dimension-height",
|
||
|
|
"dimension-h",
|
||
|
|
"dim-height",
|
||
|
|
"dim-h",
|
||
|
|
};
|
||
|
|
|
||
|
|
const std::vector<std::string> verticalResolutionParamSynonyms = {
|
||
|
|
"vertical-resolution",
|
||
|
|
"v-resolution",
|
||
|
|
"v-res",
|
||
|
|
"vres",
|
||
|
|
};
|
||
|
|
|
||
|
|
const std::vector<std::string> colourSpaceParamSynonyms = {
|
||
|
|
"colorspace",
|
||
|
|
"color-space",
|
||
|
|
"colourspace",
|
||
|
|
"colour-space",
|
||
|
|
};
|
||
|
|
|
||
|
|
const std::vector<std::string> optPlanarParamSynonyms = {
|
||
|
|
"full-planar-is-optional",
|
||
|
|
"opt-planar",
|
||
|
|
};
|
||
|
|
|
||
|
|
std::string normalizeVerticalResolutionToken(const std::string& token)
|
||
|
|
{
|
||
|
|
std::string normalizedToken =
|
||
|
|
device::DeviceAttachmentSpec::normalizeParamToken(token);
|
||
|
|
|
||
|
|
if (normalizedToken.empty())
|
||
|
|
{
|
||
|
|
throw std::runtime_error(
|
||
|
|
"lcameraBuff: vertical-resolution value is empty");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (normalizedToken.back() == 'p')
|
||
|
|
{
|
||
|
|
normalizedToken.pop_back();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (normalizedToken.empty())
|
||
|
|
{
|
||
|
|
throw std::runtime_error(
|
||
|
|
"lcameraBuff: vertical-resolution value is empty after "
|
||
|
|
"normalization");
|
||
|
|
}
|
||
|
|
|
||
|
|
return normalizedToken;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct VerticalResolutionPreset
|
||
|
|
{
|
||
|
|
unsigned width;
|
||
|
|
unsigned height;
|
||
|
|
};
|
||
|
|
|
||
|
|
const std::unordered_map<std::string, VerticalResolutionPreset>&
|
||
|
|
verticalResolutionPresetTable()
|
||
|
|
{
|
||
|
|
static const std::unordered_map<std::string, VerticalResolutionPreset>
|
||
|
|
presets = {
|
||
|
|
{"360", {640, 360}},
|
||
|
|
{"480", {640, 480}},
|
||
|
|
{"720", {1280, 720}},
|
||
|
|
{"1080", {1920, 1080}},
|
||
|
|
};
|
||
|
|
|
||
|
|
return presets;
|
||
|
|
}
|
||
|
|
|
||
|
|
VerticalResolutionPreset resolveVerticalResolutionPreset(
|
||
|
|
const std::string& token)
|
||
|
|
{
|
||
|
|
const std::string normalizedToken =
|
||
|
|
normalizeVerticalResolutionToken(token);
|
||
|
|
|
||
|
|
const std::unordered_map<std::string, VerticalResolutionPreset>& presets =
|
||
|
|
verticalResolutionPresetTable();
|
||
|
|
|
||
|
|
const auto presetIt = presets.find(normalizedToken);
|
||
|
|
if (presetIt == presets.end())
|
||
|
|
{
|
||
|
|
std::ostringstream supportedStream;
|
||
|
|
bool first = true;
|
||
|
|
for (const auto& entry : presets)
|
||
|
|
{
|
||
|
|
if (!first) {
|
||
|
|
supportedStream << ", ";
|
||
|
|
}
|
||
|
|
|
||
|
|
supportedStream << entry.first << "p";
|
||
|
|
first = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
throw std::runtime_error(
|
||
|
|
"lcameraBuff: unsupported vertical-resolution '"
|
||
|
|
+ token + "'; supported values: "
|
||
|
|
+ supportedStream.str());
|
||
|
|
}
|
||
|
|
|
||
|
|
return presetIt->second;
|
||
|
|
}
|
||
|
|
|
||
|
|
lcamera_dev::LcameraDevColourSpace parseColourSpaceValue(
|
||
|
|
const std::string& value)
|
||
|
|
{
|
||
|
|
const std::string lowered =
|
||
|
|
device::DeviceAttachmentSpec::normalizeParamToken(value);
|
||
|
|
if (lowered == "yuv") {
|
||
|
|
return lcamera_dev::LcameraDevColourSpace::Yuv;
|
||
|
|
}
|
||
|
|
|
||
|
|
throw std::runtime_error(
|
||
|
|
"lcameraBuff: unsupported colour-space '" + value
|
||
|
|
+ "'; supported values: yuv");
|
||
|
|
}
|
||
|
|
|
||
|
|
void applyExplicitDimensions(
|
||
|
|
const std::vector<std::pair<std::string, std::string>>& params,
|
||
|
|
LcameraBuffParsedParams& parsedParams)
|
||
|
|
{
|
||
|
|
const std::optional<std::pair<std::string, std::string>> widthParam =
|
||
|
|
device::DeviceAttachmentSpec::findOptionalParamWithSynonyms(
|
||
|
|
params, widthParamSynonyms);
|
||
|
|
const std::optional<std::pair<std::string, std::string>> heightParam =
|
||
|
|
device::DeviceAttachmentSpec::findOptionalParamWithSynonyms(
|
||
|
|
params, heightParamSynonyms);
|
||
|
|
|
||
|
|
if (!widthParam && !heightParam) { return; }
|
||
|
|
|
||
|
|
const std::optional<std::pair<std::string, std::string>>
|
||
|
|
verticalResolutionParam =
|
||
|
|
device::DeviceAttachmentSpec::findOptionalParamWithSynonyms(
|
||
|
|
params, verticalResolutionParamSynonyms);
|
||
|
|
|
||
|
|
if (verticalResolutionParam) {
|
||
|
|
throw std::runtime_error(mutuallyExclusiveResolutionMessage);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!widthParam || !heightParam) {
|
||
|
|
throw std::runtime_error(incompleteExplicitResolutionMessage);
|
||
|
|
}
|
||
|
|
|
||
|
|
parsedParams.width = static_cast<unsigned>(
|
||
|
|
device::DeviceAttachmentSpec::parseParamValueAsPositiveInt(
|
||
|
|
widthParam->first, widthParam->second));
|
||
|
|
parsedParams.height = static_cast<unsigned>(
|
||
|
|
device::DeviceAttachmentSpec::parseParamValueAsPositiveInt(
|
||
|
|
heightParam->first, heightParam->second));
|
||
|
|
}
|
||
|
|
|
||
|
|
void applyVerticalResolutionShorthand(
|
||
|
|
const std::vector<std::pair<std::string, std::string>>& params,
|
||
|
|
LcameraBuffParsedParams& parsedParams)
|
||
|
|
{
|
||
|
|
const std::optional<std::string> verticalResolutionValue =
|
||
|
|
device::DeviceAttachmentSpec::parseOptionalParamValueWithSynonyms(
|
||
|
|
params,
|
||
|
|
verticalResolutionParamSynonyms,
|
||
|
|
"lcameraBuff: vertical-resolution param requires a value "
|
||
|
|
"(e.g. v-res=480p)");
|
||
|
|
|
||
|
|
if (!verticalResolutionValue) { return; }
|
||
|
|
|
||
|
|
const VerticalResolutionPreset preset =
|
||
|
|
resolveVerticalResolutionPreset(*verticalResolutionValue);
|
||
|
|
parsedParams.width = preset.width;
|
||
|
|
parsedParams.height = preset.height;
|
||
|
|
}
|
||
|
|
|
||
|
|
void applyColourSpaceParam(
|
||
|
|
const std::vector<std::pair<std::string, std::string>>& params,
|
||
|
|
LcameraBuffParsedParams& parsedParams)
|
||
|
|
{
|
||
|
|
const std::optional<std::string> colourSpaceValue =
|
||
|
|
device::DeviceAttachmentSpec::parseOptionalParamValueWithSynonyms(
|
||
|
|
params,
|
||
|
|
colourSpaceParamSynonyms,
|
||
|
|
"lcameraBuff: colour-space param requires a value "
|
||
|
|
"(e.g. colour-space=yuv)");
|
||
|
|
|
||
|
|
if (!colourSpaceValue) { return; }
|
||
|
|
|
||
|
|
parsedParams.colourSpace = parseColourSpaceValue(*colourSpaceValue);
|
||
|
|
}
|
||
|
|
|
||
|
|
void finalizeCheckResolutionValues(const LcameraBuffParsedParams& parsedParams)
|
||
|
|
{
|
||
|
|
if (parsedParams.width == 0 || parsedParams.height == 0)
|
||
|
|
{
|
||
|
|
throw std::runtime_error(missingResolutionMessage);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace
|
||
|
|
|
||
|
|
LcameraBuffParsedParams parseLcameraBuffParams(
|
||
|
|
const device::DeviceAttachmentSpec& spec)
|
||
|
|
{
|
||
|
|
const auto& params = spec.stimBuffApiParams;
|
||
|
|
|
||
|
|
device::DeviceAttachmentSpec::rejectUnknownParams(
|
||
|
|
params,
|
||
|
|
"lcameraBuff: unknown stimbuff-api param '",
|
||
|
|
widthParamSynonyms,
|
||
|
|
heightParamSynonyms,
|
||
|
|
verticalResolutionParamSynonyms,
|
||
|
|
colourSpaceParamSynonyms,
|
||
|
|
optPlanarParamSynonyms);
|
||
|
|
|
||
|
|
LcameraBuffParsedParams parsedParams;
|
||
|
|
|
||
|
|
applyExplicitDimensions(params, parsedParams);
|
||
|
|
applyVerticalResolutionShorthand(params, parsedParams);
|
||
|
|
applyColourSpaceParam(params, parsedParams);
|
||
|
|
|
||
|
|
/* Presence flag: opt-planar or opt-planar= with no value means true. */
|
||
|
|
parsedParams.fullPlanarIsOptional =
|
||
|
|
device::DeviceAttachmentSpec::parseOptionalParamAsBoolWithSynonyms(
|
||
|
|
params,
|
||
|
|
optPlanarParamSynonyms,
|
||
|
|
/*defaultValue=*/false,
|
||
|
|
/*emptyMeansTrue=*/true);
|
||
|
|
|
||
|
|
finalizeCheckResolutionValues(parsedParams);
|
||
|
|
|
||
|
|
return parsedParams;
|
||
|
|
}
|
||
|
|
|
||
|
|
lcamera_dev::LcameraDevCameraModeRequest toCameraModeRequest(
|
||
|
|
const LcameraBuffParsedParams& parsedParams)
|
||
|
|
{
|
||
|
|
lcamera_dev::LcameraDevCameraModeRequest request;
|
||
|
|
request.width = parsedParams.width;
|
||
|
|
request.height = parsedParams.height;
|
||
|
|
request.colourSpace = parsedParams.colourSpace;
|
||
|
|
request.fullPlanarIsOptional = parsedParams.fullPlanarIsOptional;
|
||
|
|
return request;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool lcameraBuffParamsEqual(
|
||
|
|
const LcameraBuffParsedParams& left,
|
||
|
|
const LcameraBuffParsedParams& right)
|
||
|
|
{
|
||
|
|
return left.width == right.width
|
||
|
|
&& left.height == right.height
|
||
|
|
&& left.colourSpace == right.colourSpace
|
||
|
|
&& left.fullPlanarIsOptional == right.fullPlanarIsOptional;
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace lcamera_buff
|
||
|
|
} // namespace stim_buff
|
||
|
|
} // namespace smo
|