<think>我们有一个枚举类型CaptureImageSize,现在需要将给定的分辨率字符串(如"1280x720")转换为对应的枚举值(如CAPTURE_IMAGE_SIZE_720P)。
注意:枚举中有些分辨率有多个制式(如PAL和NTSC),但我们在转换时只需匹配宽高数字,忽略制式说明。另外,有些枚举值对应多个分辨率(如4K有两种),但我们在转换时只需要匹配数字部分。
步骤:
1. 解析输入字符串,提取宽度和高度数字。
2. 遍历枚举值对应的分辨率字符串(或预先建立的映射表),找到匹配的枚举值。
但是,枚举定义中有些分辨率在字符串中包含了多种制式(如D1:704*576(PAL)和704*480(NTSC)),我们只需要匹配数字部分,即“704*576”或“704*480”都可以匹配到CAPTURE_IMAGE_SIZE_D1。
然而,枚举中有些条目是单一分辨率(如VGA:640*480),有些是多个(如D1)。因此,我们需要为每个枚举值建立一组可能的数字分辨率字符串(去掉制式说明)的集合。
注意:枚举值中有些是纯数字,有些包含了乘号(×或*),在匹配时我们需要统一处理。
另外,枚举中有一些重复的尺寸(例如,CAPTURE_IMAGE_SIZE_5M和CAPTURE_IMAGE_SIZE_5M_N都是1872*1408),但它们是不同的枚举值。因此,我们需要根据实际需求决定如何区分,或者按照枚举定义分别对应。
但是,用户输入的分辨率字符串可能没有制式信息,比如用户输入"704*576"或"704x576",我们都应该匹配到D1。
设计:
1. 我们可以构建一个从分辨率字符串(规范化为"宽x高"或"宽*高")到枚举值的映射表。注意,一个枚举值可能对应多个分辨率字符串(如D1对应两个),那么映射表中每个分辨率字符串都映射到同一个枚举值。
2. 规范化用户输入:将用户输入的字符串中的乘号(可能是'x','X','*','×'等)统一替换为一个标准符号(比如'*'),然后分割出宽度和高度,再重新组合成标准字符串(比如"宽*高")。
3. 在映射表中查找这个字符串,如果找到则返回对应的枚举值;否则,尝试另一种组合(比如用户输入的是"高度x宽度",但我们的映射表是"宽度x高度",这种情况通常不需要,因为分辨率都是宽度在前)?注意,一般情况下分辨率都是宽度在前。
但是,枚举中有些尺寸的表示使用了不同的符号(如×和*),例如:
CAPTURE_IMAGE_SIZE_6M: "3072×2048"
CAPTURE_IMAGE_SIZE_8M: "3264×2448"
我们需要在构建映射表时统一使用一个符号(比如'*'),并将枚举中的分辨率字符串中的乘号也替换为这个符号。
另外,枚举中有些分辨率有多个表示(如4K:4096*2160/3840*2160),我们需要拆分成两个字符串:4096*2160和3840*2160,都映射到CAPTURE_IMAGE_SIZE_4K。
因此,我们需要为每个枚举值生成一个或多个分辨率字符串(只包含数字和乘号),并建立映射。
特殊枚举值:
- 跳过计数枚举值(如NR, EXT_NR, EXT_V3_NR等)
- 注意:枚举中有些枚举值被赋予了相同的数值(如CAPTURE_IMAGE_SIZE_NR和CAPTURE_IMAGE_SIZE_ND1都是9),但它们是不同的枚举常量,我们只需要处理有实际分辨率意义的枚举常量。
具体步骤:
1. 创建一个映射表(std::map或std::unordered_map),键为规范化的分辨率字符串(如"1280*720"),值为枚举值。
2. 遍历枚举中每个有实际分辨率定义的项(跳过计数项),将每个项的分辨率字符串解析成一个或多个规范化字符串(用'*'连接宽高),然后插入到映射表中(注意:同一个枚举值可能有多个键)。
3. 处理用户输入:去除空格,将'x','X','×'等替换为'*',然后尝试在映射表中查找。
4. 如果找到,返回枚举值;否则,返回一个错误(如抛出异常或返回一个表示未知的枚举值)。
枚举值列表(只取有实际分辨率的)及其对应的分辨率字符串(我们将其拆分成多个规范化字符串):
CAPTURE_IMAGE_SIZE_D1: ["704*576", "704*480"]
CAPTURE_IMAGE_SIZE_HD1: ["704*288", "704*240"]
CAPTURE_IMAGE_SIZE_BCIF: ["352*576", "352*480"]
CAPTURE_IMAGE_SIZE_CIF: ["352*288", "352*240"]
CAPTURE_IMAGE_SIZE_QCIF: ["176*144", "176*120"]
CAPTURE_IMAGE_SIZE_VGA: ["640*480"]
CAPTURE_IMAGE_SIZE_QVGA: ["320*240"]
CAPTURE_IMAGE_SIZE_SVCD: ["480*480"]
CAPTURE_IMAGE_SIZE_QQVGA: ["160*128"]
CAPTURE_IMAGE_SIZE_ND1: ["240*192"]
CAPTURE_IMAGE_SIZE_650TVL: ["926*576"]
CAPTURE_IMAGE_SIZE_720P: ["1280*720"]
CAPTURE_IMAGE_SIZE_1_3M: ["1280*960"]
CAPTURE_IMAGE_SIZE_UXGA: ["1600*1200"]
CAPTURE_IMAGE_SIZE_1080P: ["1920*1080"]
CAPTURE_IMAGE_SIZE_WUXGA: ["1920*1200"]
CAPTURE_IMAGE_SIZE_2_5M: ["1872*1408"]
CAPTURE_IMAGE_SIZE_3M: ["2048*1536"]
CAPTURE_IMAGE_SIZE_5M: ["3744*1408"]
CAPTURE_IMAGE_SIZE_1080N: ["960*1080"]
CAPTURE_IMAGE_SIZE_4M: ["2592*1520"]
CAPTURE_IMAGE_SIZE_6M: ["3072*2048"] // 注意原字符串是×,替换为*
CAPTURE_IMAGE_SIZE_8M: ["3264*2448"] // 同上
CAPTURE_IMAGE_SIZE_12M: ["4000*3000"]
CAPTURE_IMAGE_SIZE_4K: ["4096*2160", "3840*2160"]
CAPTURE_IMAGE_SIZE_720N: ["640*720"]
CAPTURE_IMAGE_SIZE_WSVGA: ["1024*576"]
CAPTURE_IMAGE_SIZE_NHD: ["640*360"]
CAPTURE_IMAGE_SIZE_3M_N: ["1024*1536"]
CAPTURE_IMAGE_SIZE_4M_N: ["1296*1520"]
CAPTURE_IMAGE_SIZE_5M_N: ["1872*1408"] // 注意:与CAPTURE_IMAGE_SIZE_2_5M相同,但枚举值不同,所以需要分别映射
CAPTURE_IMAGE_SIZE_4K_N: ["2048*2160", "1920*2160"]
注意:CAPTURE_IMAGE_SIZE_5M和CAPTURE_IMAGE_SIZE_5M_N都是1872*1408?但是枚举中CAPTURE_IMAGE_SIZE_5M是3744*1408,而CAPTURE_IMAGE_SIZE_5M_N是1872*1408。所以不会重复。
但是,CAPTURE_IMAGE_SIZE_2_5M是1872*1408,而CAPTURE_IMAGE_SIZE_5M_N也是1872*1408。这两个枚举值对应相同的分辨率字符串。因此,在映射表中,同一个分辨率字符串将对应两个枚举值?这不行,因为键是唯一的。
问题:同一个分辨率可能对应多个枚举值?我们需要根据上下文区分吗?但用户输入一个分辨率字符串,我们无法知道是指哪个枚举值。因此,我们需要设计一个策略:
方案1:不允许重复的分辨率字符串。但枚举中确实出现了重复(如2_5M和5M_N都是1872*1408)。这可能是枚举定义的问题,或者实际应用中它们代表不同的含义(比如不同的传感器模式)。但我们的转换函数无法区分,所以只能选择一个(比如按照枚举值顺序选择第一个出现的,或者按照枚举值的大小选择第一个?)。
方案2:在映射表中,同一个分辨率字符串映射到多个枚举值?但这样函数返回就不唯一了。
方案3:在构建映射表时,如果遇到重复,则只保留一个(比如保留先出现的那个)。但这样会丢失信息。
方案4:在枚举定义中,这些重复的分辨率字符串实际上对应不同的枚举值,但我们的转换函数无法通过分辨率字符串区分它们,因此我们只能返回一个错误(当出现重复时,要求用户使用其他方式指定,或者返回一个错误值)。但这样不友好。
重新检查枚举定义:
CAPTURE_IMAGE_SIZE_2_5M = 17, ///< 1872*1408
...
CAPTURE_IMAGE_SIZE_5M_N = 32, //< 1872*1408
因此,同一个分辨率字符串"1872*1408"对应两个枚举值:CAPTURE_IMAGE_SIZE_2_5M和CAPTURE_IMAGE_SIZE_5M_N。
如何解决?
由于转换函数无法通过字符串区分这两个枚举值,因此我们只能选择其中一个。但这样会丢失信息。
考虑到实际使用中,用户可能期望的是其中一个(比如2_5M是标准定义,而5M_N是某种特殊模式),我们可能需要根据实际系统设计来决定。但这里没有上下文,我们可以按照枚举值出现的顺序(数值大小)选择较小的那个(即CAPTURE_IMAGE_SIZE_2_5M,因为它的枚举值17比32小)?或者按照枚举定义中的顺序(先定义2_5M,后定义5M_N)?
但是,枚举值的大小并不代表顺序(因为枚举值可以赋值,而这里2_5M=17, 5M_N=32,所以17<32),所以我们可以选择数值较小的那个(即先定义的)?但枚举定义中2_5M确实在5M_N之前。
然而,这并不合理,因为用户可能期望的是5M_N。所以,我们需要避免这种歧义。
实际上,在枚举定义中,5M_N的注释中明确写了“通用”或“海思”,所以它们可能是针对不同平台的。但在转换函数中,我们无法知道平台。
因此,我们可能需要修改需求:转换函数不支持有歧义的分辨率字符串。当出现歧义时,我们返回错误(比如抛出异常,或者返回一个特定的错误枚举值)。
但是,我们也可以要求用户输入时指定平台或其他信息?这超出了当前函数的范围。
权衡后,我们决定:在映射表中,如果同一个分辨率字符串已经存在,则记录一个错误(比如记录到日志),然后跳过后续的重复项。这样,当用户输入这个分辨率字符串时,我们返回的是先出现的枚举值。同时,我们在文档中说明:如果存在重复的分辨率字符串,则返回第一个匹配的枚举值。
另一种做法:在构建映射表时,如果遇到重复,则将该键删除(即该分辨率字符串不映射到任何枚举值)。这样当用户输入这个字符串时,我们返回错误(未知分辨率)。但这样会导致这两个枚举值都无法通过字符串转换。
考虑到实际使用中,用户可能更常用的是2_5M,而5M_N可能是特定平台,我们可以暂时将5M_N的分辨率字符串映射到5M_N,但这样就会覆盖2_5M。所以不行。
因此,我们只能保留一个。我们决定保留先出现的枚举值(即枚举值数值较小的那个)。所以对于"1872*1408",我们只保留CAPTURE_IMAGE_SIZE_2_5M(枚举值17)。
但是,CAPTURE_IMAGE_SIZE_5M_N的注释中说明是“1872*1408”,我们也可以将其映射到5M_N,但这样就会覆盖2_5M。所以我们需要在构建映射表时,先添加枚举值小的,当遇到重复时,不添加后面的重复项。这样,2_5M会先被添加,5M_N的相同字符串就不会添加了。那么5M_N就无法通过这个字符串转换。
或者,我们可以为5M_N添加一个不同的键?但它的分辨率字符串就是1872*1408,没有其他表示。
所以,我们只能牺牲5M_N的转换。或者,在5M_N的键上加上后缀?比如"1872*1408(N)",但这样用户输入时也要带后缀,不符合要求。
结论:暂时先按保留第一个出现的枚举值来处理。如果用户需要转换5M_N,则必须使用其他方式(比如直接使用枚举值)。或者,我们提供另一个函数,可以指定平台来转换。
由于问题中没有提到平台区分,我们先按简单处理:保留第一个出现的枚举值。
实现步骤:
1. 创建一个映射表:std::unordered_map<std::string, CaptureImageSize> resolutionMap;
2. 按枚举值从小到大的顺序(即枚举定义的顺序)遍历每个有实际分辨率的枚举常量,对于每个枚举常量,将其对应的分辨率字符串(可能有多个)逐个处理:
a. 将字符串中的非数字字符(除了乘号)去除,但这里我们的字符串已经是数字和乘号(或×)了。
b. 将字符串中的'×'替换为'*',然后分割字符串,提取出宽度和高度(注意:有些字符串可能有多个分辨率,用斜杠分隔,如4K)。
c. 对于每个用斜杠分隔的分辨率,单独处理(拆分成多个字符串)。
d. 将每个拆分后的字符串规范化(去除空格,确保宽高顺序,并组合成"宽*高"的字符串)。
e. 检查这个规范化字符串是否已经在映射表中,如果已经存在,则跳过(不覆盖,因为我们要保留先出现的)。
f. 如果不存在,则添加到映射表中。
但是,枚举值的顺序不是数值顺序,而是定义顺序(在C++枚举中,如果没有指定数值,则按定义顺序从0开始递增,但这里有些指定了数值)。我们遍历的顺序应该按照枚举值数值从小到大的顺序?但枚举定义中有些后定义的枚举值数值小(比如CAPTURE_IMAGE_SIZE_ND1=9,而CAPTURE_IMAGE_SIZE_650TVL=10,所以数值顺序就是定义顺序)。
因此,我们可以按枚举值数值顺序遍历(从0到最大值)。但枚举定义中,枚举值并不是连续的(比如从0到25,然后跳到19,然后又到25,再到26...)。而且,有些枚举值(计数用的)我们没有实际分辨率。
所以,我们改为按枚举定义中出现的顺序(即代码中的顺序)来遍历,并且跳过计数枚举值。
我们可以手动列出有实际分辨率的枚举常量(按照定义顺序):
CAPTURE_IMAGE_SIZE_D1, // 0
CAPTURE_IMAGE_SIZE_HD1, // 1
CAPTURE_IMAGE_SIZE_BCIF, // 2
CAPTURE_IMAGE_SIZE_CIF, // 3
CAPTURE_IMAGE_SIZE_QCIF, // 4
CAPTURE_IMAGE_SIZE_VGA, // 5
CAPTURE_IMAGE_SIZE_QVGA, // 6
CAPTURE_IMAGE_SIZE_SVCD, // 7
CAPTURE_IMAGE_SIZE_QQVGA, // 8
// 跳过 CAPTURE_IMAGE_SIZE_NR = 9 (计数,跳过)
CAPTURE_IMAGE_SIZE_ND1 = 9, // 9 -> 注意,这里和NR相同数值,但它是实际分辨率
CAPTURE_IMAGE_SIZE_650TVL, // 10
CAPTURE_IMAGE_SIZE_720P, // 11
CAPTURE_IMAGE_SIZE_1_3M, // 12
CAPTURE_IMAGE_SIZE_UXGA, // 13
CAPTURE_IMAGE_SIZE_1080P, // 14
CAPTURE_IMAGE_SIZE_WUXGA, // 15
CAPTURE_IMAGE_SIZE_2_5M, // 16
CAPTURE_IMAGE_SIZE_3M, // 17
CAPTURE_IMAGE_SIZE_5M, // 18
// 跳过 CAPTURE_IMAGE_SIZE_EXT_NR = 19 (计数)
CAPTURE_IMAGE_SIZE_1080N = 19, // 19
CAPTURE_IMAGE_SIZE_4M, // 20
CAPTURE_IMAGE_SIZE_6M, // 21
CAPTURE_IMAGE_SIZE_8M, // 22
CAPTURE_IMAGE_SIZE_12M, // 23
CAPTURE_IMAGE_SIZE_4K, // 24
// 跳过 CAPTURE_IMAGE_SIZE_EXT_V2_NR =25 (计数)
CAPTURE_IMAGE_SIZE_720N = 25, // 25
CAPTURE_IMAGE_SIZE_WSVGA, // 26
CAPTURE_IMAGE_SIZE_NHD, // 27
CAPTURE_IMAGE_SIZE_3M_N, // 28
CAPTURE_IMAGE_SIZE_4M_N, // 29
CAPTURE_IMAGE_SIZE_5M_N, // 30
CAPTURE_IMAGE_SIZE_4K_N, // 31
// 跳过 CAPTURE_IMAGE_SIZE_EXT_V3_NR // 32(这个没有指定数值?在枚举中最后一个,所以应该是32)
注意:枚举值相同的项(如NR和ND1都是9)在枚举类型中是不同的常量,但它们的数值相同。在switch-case中,它们会进入同一个case。所以我们在遍历时,只能取其中一个(按照定义顺序,先定义的是NR,然后是ND1)。但NR是计数,我们跳过,所以我们取ND1(因为它有实际分辨率)。
因此,我们按数值顺序从0到32(最大值)遍历,但只处理有实际分辨率的项,并且跳过计数项。
但是,枚举值相同的情况下,我们无法通过数值来区分不同的常量(因为它们是同一个数值)。所以,我们只能按定义顺序,并且只处理一次每个数值(如果同一个数值有多个常量,我们只取第一个有实际分辨率的那个)。
具体做法:我们创建一个数组,按枚举值数值作为索引,存储对应的分辨率字符串集合(如果有多个常量对应同一个数值,我们只存储第一个有实际分辨率的那个,忽略后面的?或者存储最后一个?)。但这里,我们按照定义顺序,当遇到一个数值时,如果已经处理过这个数值,则跳过。
由于枚举定义中,同一个数值的多个常量是连续定义的,我们可以这样处理:
但是,我们的枚举定义中,同一个数值的常量(如9)有两个:NR和ND1,我们只想处理ND1(因为NR是计数,而ND1有实际分辨率)。所以,我们在处理数值9时,应该使用ND1,而不是NR。
因此,我们需要根据常量名称来判断?这样就不通用了。
所以,我们改为手动构建一个列表,只包含有实际分辨率的枚举常量(按定义顺序)及其对应的分辨率字符串。
我们手动列出(如上所示),然后按这个列表的顺序构建映射表。
为了代码可维护性,我们可以使用一个静态的向量,每个元素是一个结构体,包含枚举值和对应的原始字符串。然后按顺序处理。
代码实现:
由于枚举值较多,我们使用一个辅助函数来初始化映射表。
注意:枚举值中有些分辨率字符串包含非数字字符(如PAL/NTSC说明),我们需要过滤掉这些字符,只保留数字和乘号(或×)。然后拆分成多个分辨率。
具体步骤:
初始化映射表函数:
std::unordered_map<std::string, CaptureImageSize> createResolutionMap() {
std::unordered_map<std::string, CaptureImageSize> map;
// 按顺序添加枚举值及其分辨率字符串(原始字符串)
std::vector<std::pair<CaptureImageSize, std::string>> enumResolutions = {
{CAPTURE_IMAGE_SIZE_D1, "704*576(PAL) 704*480(NTSC)"},
{CAPTURE_IMAGE_SIZE_HD1, "704*288(PAL) 704*240(NTSC)"},
... // 其他项
};
for (const auto& item : enumResolutions) {
// 处理原始字符串:按空格分割,然后每个部分再提取数字和乘号(或×)
// 但是,原始字符串中可能用空格分隔了多个分辨率,每个分辨率包含数字和乘号以及制式说明。
// 我们可以用空格分割,然后过滤掉空字符串,然后对每个子字符串提取数字和乘号(或×)
std::string raw = item.second;
// 分割raw
std::vector<std::string> parts;
// 简单的空格分割(可能有多个空格)
// 使用字符串流分割
std::istringstream iss(raw);
std::string part;
while (iss >> part) {
if (!part.empty()) {
parts.push_back(part);
}
}
// 现在parts的每个元素可能是"704*576(PAL)"这样的字符串
for (auto& p : parts) {
// 提取分辨率部分:从开始到第一个非数字非乘号(非'*'和'×')之前
// 或者,我们只保留数字和'*','×',其他都去掉
std::string clean;
for (char c : p) {
if (isdigit(c) || c=='*' || c=='×') {
clean += c;
}
}
// 现在clean是类似"704*576"的字符串,但可能中间是'×',我们统一替换为'*'
std::replace(clean.begin(), clean.end(), '×', '*');
// 检查clean是否为空
if (clean.empty()) continue;
// 检查clean中是否包含'*',如果不包含,则不是有效的分辨率字符串,跳过。
if (clean.find('*') == std::string::npos) {
continue;
}
// 现在clean是规范化的字符串,如"704*576"
// 检查映射表中是否已有这个字符串,如果有,则跳过(不添加,保留先出现的)
if (map.find(clean) == map.end()) {
map[clean] = item.first;
}
// 否则,已经存在,跳过(保留先出现的)
}
}
return map;
}
但是,有些枚举项的分辨率字符串不是用空格分隔多个分辨率,而是用斜杠,如:
CAPTURE_IMAGE_SIZE_4K: return "4096*2160/3840*2160"
所以,我们还需要处理斜杠。
因此,在分割原始字符串时,除了空格,还要考虑斜杠(和可能的分隔符)。我们可以先替换斜杠为空格,然后再分割。
修改:在原始字符串处理时,将可能的分隔符(如'/', '、'等)替换为空格,然后用空格分割。
另外,有些项只有一个分辨率,没有制式说明(如VGA:640*480),所以我们的处理是通用的。
但是,枚举项CAPTURE_IMAGE_SIZE_5M_N: "1872*1408",只有一个,没有制式。
所以,我们修改原始字符串处理:将非数字非乘号非分隔符的字符先替换为空格?或者直接按上述方法提取每个连续的数字和乘号序列?但这样会丢失分隔符信息。
我们换一种方法:我们不需要制式信息,所以可以删除括号内的内容,然后再分割。
例如:对于"704*576(PAL)",我们删除括号及其内容,变成"704*576"。
所以,我们可以这样做:
// 删除括号及其内容
std::string removeParentheses(const std::string& s) {
std::string result;
bool inParentheses = false;
for (char c : s) {
if (c == '(') {
inParentheses = true;
} else if (c == ')') {
inParentheses = false;
} else if (!inParentheses) {
result += c;
}
}
return result;
}
然后,将原始字符串应用这个函数,得到的结果就是去除了括号内容的字符串。然后,这个字符串中可能包含多个分辨率,用空格或斜杠分隔。我们再用空格和斜杠作为分隔符来分割。
但是,斜杠可能出现在两个分辨率之间,如"4096*2160/3840*2160",我们将其替换为空格,然后分割。
所以,步骤:
raw = removeParentheses(raw); // 去除括号内容
// 替换斜杠为空格
std::replace(raw.begin(), raw.end(), '/', ' ');
// 然后按空格分割
这样,处理后的raw字符串中,多个分辨率用空格分隔。
然后,分割后每个部分就是一个分辨率字符串(只包含数字和乘号),然后我们将其中的'×'替换为'*',然后检查是否包含'*',如果包含,则作为键。
注意:有些分辨率字符串可能没有乘号?不可能,因为我们定义中都有。
最后,构建映射表。
但是,有些枚举项的分辨率字符串中使用了'×'(如6M和8M),我们已经在替换中统一为'*'了。
现在,我们编写代码:
由于枚举值较多,我们使用一个列表来初始化enumResolutions。注意,我们只列出有实际分辨率的枚举项,按照定义顺序。
注意:枚举项CAPTURE_IMAGE_SIZE_ND1的分辨率字符串是"240*192",没有制式说明。
我们手动列出所有有实际分辨率的枚举项及其原始字符串(从枚举的注释中获取):
{CAPTURE_IMAGE_SIZE_D1, "704*576(PAL) 704*480(NTSC)"},
{CAPTURE_IMAGE_SIZE_HD1, "704*288(PAL) 704*240(NTSC)"},
{CAPTURE_IMAGE_SIZE_BCIF, "352*576(PAL) 352*480(NTSC)"},
{CAPTURE_IMAGE_SIZE_CIF, "352*288(PAL) 352*240(NTSC)"},
{CAPTURE_IMAGE_SIZE_QCIF, "176*144(PAL) 176*120(NTSC)"},
{CAPTURE_IMAGE_SIZE_VGA, "640*480"}, // 注意:原始注释是"640*480(PAL) 640*480(NTSC)"?但实际注释没有,所以写"640*480"
{CAPTURE_IMAGE_SIZE_QVGA, "320*240"},
{CAPTURE_IMAGE_SIZE_SVCD, "480*480"},
{CAPTURE_IMAGE_SIZE_QQVGA, "160*128"},
{CAPTURE_IMAGE_SIZE_ND1, "240*192"},
{CAPTURE_IMAGE_SIZE_650TVL, "926*576"},
{CAPTURE_IMAGE_SIZE_720P, "1280*720"},
{CAPTURE_IMAGE_SIZE_1_3M, "1280*960"},
{CAPTURE_IMAGE_SIZE_UXGA, "1600*1200"},
{CAPTURE_IMAGE_SIZE_1080P, "1920*1080"},
{CAPTURE_IMAGE_SIZE_WUXGA, "1920*1200"},
{CAPTURE_IMAGE_SIZE_2_5M, "1872*1408"},
{CAPTURE_IMAGE_SIZE_3M, "2048*1536"},
{CAPTURE_IMAGE_SIZE_5M, "3744*1408"},
{CAPTURE_IMAGE_SIZE_1080N, "960*1080"},
{CAPTURE_IMAGE_SIZE_4M, "2592*1520"},
{CAPTURE_IMAGE_SIZE_6M, "3072×2048"}, // 注意这里是×
{CAPTURE_IMAGE_SIZE_8M, "3264×2448"},
{CAPTURE_IMAGE_SIZE_12M, "4000*3000"},
{CAPTURE_IMAGE_SIZE_4K, "4096 * 2160/3840*2160"}, // 注意空格和斜杠
{CAPTURE_IMAGE_SIZE_720N, "640*720"},
{CAPTURE_IMAGE_SIZE_WSVGA, "1024*576"},
{CAPTURE_IMAGE_SIZE_NHD, "640*360"},
{CAPTURE_IMAGE_SIZE_3M_N, "1024*1536"},
{CAPTURE_IMAGE_SIZE_4M_N, "1296*1520"},
{CAPTURE_IMAGE_SIZE_5M_N, "1872*1408"},
{CAPTURE_IMAGE_SIZE_4K_N, "2048 * 2160/1920*2160"},
注意:有些分辨率字符串中有空格(如4K的"4096 * 2160"),我们在去除括号内容后,需要将空格删除?或者不去除,因为我们在分割时是按空格分割的,所以分割后会有"4096"和"*"和"2160"?这样不行。
所以,在去除括号内容后,我们还要删除所有空格,然后再替换斜杠为空格,再分割?不行,因为删除空格后,4096*2160会变成4096*2160(没有空格),而3840*2160也是,所以整个字符串变成"4096*21603840*2160",这不行。
因此,我们保留空格,但在分割之前,将空格作为分隔符(字符串流默认以空格分隔),这样分割后,每个部分应该是连续的非空格字符串。而"4096*2160"是一个字符串(因为中间没有空格?但原字符串中有空格:4096 * 2160,所以分割后会是三个部分:"4096", "*", "2160"),这不行。
所以,我们需要在去除括号内容后,将字符串中的空格都删除,这样"4096 * 2160"就变成"4096*2160"(如果删除空格)?不对,删除空格后变成"4096*2160"。
因此,我们在去除括号内容后,删除字符串中的所有空格,然后将斜杠替换为空格(用于分割),然后再分割。
步骤:
raw = removeParentheses(raw); // 去除括号内容
// 删除所有空格
raw.erase(std::remove_if(raw.begin(), raw.end(), ::isspace), raw.end());
// 替换斜杠为空格
std::replace(raw.begin(), raw.end(), '/', ' ');
// 然后分割
这样,原始字符串"4096 * 2160/3840*2160" 变成 "4096*2160 3840*2160"(删除空格后为"4096*2160/3840*2160",然后替换斜杠为空格,变成"4096*2160 3840*2160"),分割后得到两个字符串:"4096*2160"和"3840*2160"。
完美。
现在,我们编写函数:
由于代码较长,我们将其分为几个辅助函数。
最终,我们有一个全局的映射表(静态变量),并在第一次调用转换函数时初始化。
转换函数:
CaptureImageSize stringToCaptureImageSize(const std::string& resolutionStr) {
static const std::unordered_map<std::string, CaptureImageSize> resolutionMap = createResolutionMap();
// 规范化用户输入
std::string user = resolutionStr;
// 删除用户输入中的空格
user.erase(std::remove_if(user.begin(), user.end(), ::isspace), user.end());
// 将用户输入中的'x','X','×'替换为'*'
std::replace(user.begin(), user.end(), 'x', '*');
std::replace(user.begin(), user.end(), 'X', '*');
std::replace(user.begin(), user.end(), '×', '*');
// 现在user是类似"1280*720"的字符串
auto it = resolutionMap.find(user);
if (it != resolutionMap.end()) {
return it->second;
}
// 没有找到,尝试另一种可能:用户输入可能是高度在前?但一般不会,所以我们返回错误
throw std::invalid_argument("Unsupported resolution string");
}
注意:这个函数可能抛出异常,调用者需要捕获。
另外,我们也可以考虑不抛出异常,而是返回一个特定的枚举值(如CAPTURE_IMAGE_SIZE_NR,但它是计数,不合适)。或者,我们可以定义一个表示错误的枚举值(但枚举中没有)。所以,我们选择抛出异常。
最后,我们还需要考虑用户输入的分辨率字符串中的数字可能有前导零?比如"0640*0480",但这种情况很少,我们不做处理。如果出现,就会匹配失败。所以,用户输入应该和枚举中定义的一致(没有前导零)。
如果枚举中定义有前导零,那我们在构建映射表时也删除了空格,所以不会有前导零(因为数字前面的空格被删除了,但数字内部的前导零不会被删除)。所以,我们构建的映射表中键是没有空格的,用户输入我们也删除了空格,所以只要数字一致就能匹配。
但是,枚举中定义的数字都是没有前导零的,所以用户输入也不应该有前导零。
现在,我们编写完整的代码。
注意:由于枚举值较多,且createResolutionMap函数较长,我们将其实现为静态函数。
由于代码较长,这里只给出关键部分。
考虑到代码量,我们可能需要在头文件中声明函数,在cpp文件中实现映射表。
但是,这里我们给出完整示例。
注意:枚举类型的定义我们假设已经存在。
代码示例:</think>### 分辨率字符串到枚举值的转换实现
根据需求,需要将分辨率字符串(如 "1280x720")转换为对应的 `CaptureImageSize` 枚举值(如 `CAPTURE_IMAGE_SIZE_720P`)。以下是完整的转换方案:
#### 转换函数实现(C++)
```cpp
#include <string>
#include <unordered_map>
#include <algorithm>
#include <stdexcept>
CaptureImageSize stringToCaptureImageSize(const std::string& resolutionStr) {
// 规范化输入字符串:移除空格,统一小写
std::string normalized = resolutionStr;
normalized.erase(std::remove_if(normalized.begin(), normalized.end(), ::isspace), normalized.end());
std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::tolower);
// 替换分隔符为统一格式(支持 x/X/*)
size_t pos;
while ((pos = normalized.find_first_of("x*×")) != std::string::npos) {
normalized.replace(pos, 1, "x");
}
// 分辨率到枚举值的映射表
static const std::unordered_map<std::string, CaptureImageSize> resolutionMap = {
{"704x576", CAPTURE_IMAGE_SIZE_D1}, // 兼容 PAL
{"704x480", CAPTURE_IMAGE_SIZE_D1}, // 兼容 NTSC
{"704x288", CAPTURE_IMAGE_SIZE_HD1},
{"704x240", CAPTURE_IMAGE_SIZE_HD1},
{"352x576", CAPTURE_IMAGE_SIZE_BCIF},
{"352x480", CAPTURE_IMAGE_SIZE_BCIF},
{"352x288", CAPTURE_IMAGE_SIZE_CIF},
{"352x240", CAPTURE_IMAGE_SIZE_CIF},
{"176x144", CAPTURE_IMAGE_SIZE_QCIF},
{"176x120", CAPTURE_IMAGE_SIZE_QCIF},
{"640x480", CAPTURE_IMAGE_SIZE_VGA},
{"320x240", CAPTURE_IMAGE_SIZE_QVGA},
{"480x480", CAPTURE_IMAGE_SIZE_SVCD},
{"160x128", CAPTURE_IMAGE_SIZE_QQVGA},
{"240x192", CAPTURE_IMAGE_SIZE_ND1},
{"926x576", CAPTURE_IMAGE_SIZE_650TVL},
{"1280x720", CAPTURE_IMAGE_SIZE_720P},
{"1280x960", CAPTURE_IMAGE_SIZE_1_3M},
{"1600x1200", CAPTURE_IMAGE_SIZE_UXGA},
{"1920x1080", CAPTURE_IMAGE_SIZE_1080P},
{"1920x1200", CAPTURE_IMAGE_SIZE_WUXGA},
{"1872x1408", CAPTURE_IMAGE_SIZE_2_5M},
{"2048x1536", CAPTURE_IMAGE_SIZE_3M},
{"3744x1408", CAPTURE_IMAGE_SIZE_5M},
{"960x1080", CAPTURE_IMAGE_SIZE_1080N},
{"2592x1520", CAPTURE_IMAGE_SIZE_4M},
{"3072x2048", CAPTURE_IMAGE_SIZE_6M},
{"3264x2448", CAPTURE_IMAGE_SIZE_8M},
{"4000x3000", CAPTURE_IMAGE_SIZE_12M},
{"4096x2160", CAPTURE_IMAGE_SIZE_4K}, // 电影级4K
{"3840x2160", CAPTURE_IMAGE_SIZE_4K}, // UHD 4K
{"640x720", CAPTURE_IMAGE_SIZE_720N},
{"1024x576", CAPTURE_IMAGE_SIZE_WSVGA},
{"640x360", CAPTURE_IMAGE_SIZE_NHD},
{"1024x1536", CAPTURE_IMAGE_SIZE_3M_N},
{"1296x1520", CAPTURE_IMAGE_SIZE_4M_N},
{"1872x1408", CAPTURE_IMAGE_SIZE_5M_N},
{"2048x2160", CAPTURE_IMAGE_SIZE_4K_N}, // 通用
{"1920x2160", CAPTURE_IMAGE_SIZE_4K_N} // 海思方案
};
// 查找匹配项
auto it = resolutionMap.find(normalized);
if (it != resolutionMap.end()) {
return it->second;
}
throw std::invalid_argument("Unsupported resolution: " + resolutionStr);
}
```
#### 设计要点说明
1. **输入规范化处理**
- 移除所有空格:`"1280 x 720"` → `"1280x720"`
- 统一小写格式:`"1280X720"` → `"1280x720"`
- 支持多种分隔符:`x`/`X`/`*`/`×` 统一转为 `x`
2. **多格式兼容设计**
- 支持 PAL/NTSC 双格式:`704x576` 和 `704x480` 均映射到 `CAPTURE_IMAGE_SIZE_D1`
- 支持 4K 多标准:`4096x2160`(电影)和 `3840x2160`(UHD)均映射到 `CAPTURE_IMAGE_SIZE_4K`
3. **特殊案例处理**
- 高冲突分辨率:`1872x1408` 同时映射到:
```cpp
{"1872x1408", CAPTURE_IMAGE_SIZE_2_5M}, // 标准2.5M
{"1872x1408", CAPTURE_IMAGE_SIZE_5M_N} // 特殊5M_N模式
```
实际使用中需根据上下文选择(默认优先返回首次匹配值)
4. **错误处理机制**
- 抛出 `std::invalid_argument` 异常处理未知分辨率
- 包含原始字符串的错误信息便于调试
#### 使用示例
```cpp
// 将分辨率字符串转换为枚举值
std::string input = "1920x1080";
try {
CaptureImageSize size = stringToCaptureImageSize(input);
std::cout << "Converted to enum: " << static_cast<int>(size) << std::endl;
// 输出: Converted to enum: 14 (CAPTURE_IMAGE_SIZE_1080P)
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
// 处理特殊分辨率
std::string specialRes = "1872x1408";
CaptureImageSize size = stringToCaptureImageSize(specialRes);
// 返回 CAPTURE_IMAGE_SIZE_2_5M 或 CAPTURE_IMAGE_SIZE_5M_N
```
### 视频采集参数配置建议
在视频采集系统中,分辨率选择常与采集参数配合使用[^1]:
```cpp
// 设置理想分辨率(浏览器优先尝试匹配)
void setIdealResolution(CaptureImageSize size) {
int width = 0, height = 0;
// ... 获取分辨率对应的宽高值
// 配置媒体约束
mediaConstraints.video = {
{ "width", { ideal: width } },
{ "height", { ideal: height } }
};
}
```
当需要精确匹配分辨率时:
```cpp
// 设置精确分辨率(强制匹配)
void setExactResolution(CaptureImageSize size) {
int width = 0, height = 0;
// ... 获取分辨率对应的宽高值
mediaConstraints.video = {
{ "width", { exact: width } },
{ "height", { exact: height } }
};
}
```