Skip to content

Commit 470e701

Browse files
author
Christian Feldmann
committed
Refactoring of csv parser and test data
1 parent 9e9508f commit 470e701

File tree

6 files changed

+354
-231
lines changed

6 files changed

+354
-231
lines changed

YUViewLib/src/statistics/StatisticsFileBase.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,12 @@ class StatisticsFileBase : public QObject
7373
{
7474
enum class FileSorting
7575
{
76+
Unknown,
7677
SortedByPOC,
7778
SortedByType
7879
};
7980

80-
FileSorting fileSorting{FileSorting::SortedByType};
81+
FileSorting fileSorting{FileSorting::Unknown};
8182

8283
int maxPocEncountered{};
8384
std::optional<int> pocWithDataOutsideOfFrame{};

YUViewLib/src/statistics/StatisticsFileCSV.cpp

Lines changed: 151 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,119 @@ QStringList parseCSVLine(const QString &srcLine, char delimiter)
5959
return line.split(delimiter);
6060
}
6161

62+
std::optional<int> toInteger(const QString &text)
63+
{
64+
bool ok = true;
65+
const auto value = text.toInt(&ok);
66+
if (ok)
67+
return value;
68+
return {};
69+
}
70+
71+
std::optional<Color> toColorWithClipping(const QString &textR,
72+
const QString &textG,
73+
const QString &textB,
74+
const QString &textA)
75+
{
76+
bool ok = true;
77+
78+
const auto r = toInteger(textR);
79+
const auto g = toInteger(textG);
80+
const auto b = toInteger(textB);
81+
const auto a = toInteger(textA);
82+
83+
if (r && g && b && a)
84+
return Color(functions::clip(*r, 0, 255),
85+
functions::clip(*g, 0, 255),
86+
functions::clip(*b, 0, 255),
87+
functions::clip(*a, 0, 255));
88+
return {};
89+
}
90+
91+
enum class SpecifiedType
92+
{
93+
map,
94+
range,
95+
vector,
96+
line
97+
};
98+
99+
struct ParsedType
100+
{
101+
int typeID{};
102+
std::string typeName{};
103+
std::optional<SpecifiedType> specifiedType{};
104+
105+
std::optional<StatisticsType::ValueDataOptions> valueDataOptions;
106+
std::optional<StatisticsType::VectorDataOptions> vectorDataOptions;
107+
StatisticsType::GridOptions gridOptions;
108+
};
109+
110+
void checkAndAddTypeToStatisticsData(StatisticsData &statisticsData,
111+
const std::optional<ParsedType> &type)
112+
{
113+
if (!type)
114+
return;
115+
116+
const bool hasNoValueOrDataOptions = (!type->valueDataOptions && !type->vectorDataOptions);
117+
if (hasNoValueOrDataOptions)
118+
return;
119+
120+
statisticsData.addStatType(StatisticsTypeBuilder(type->typeID, type->typeName)
121+
.withOptionalValueDataOptions(type->valueDataOptions)
122+
.withOptionalVectorDataOptions(type->vectorDataOptions)
123+
.withGridOptions(type->gridOptions)
124+
.build());
125+
}
126+
127+
std::optional<ParsedType> parseHeaderLine(const QStringList &lineItems)
128+
{
129+
if (lineItems.count() < 5)
130+
return {};
131+
132+
ParsedType newType;
133+
134+
if (const auto typeID = toInteger(lineItems[2]))
135+
newType.typeID = *typeID;
136+
else
137+
return {};
138+
139+
newType.typeName = lineItems[3].toStdString();
140+
141+
const auto typeEntry = lineItems[4];
142+
if (typeEntry == "map")
143+
newType.specifiedType = SpecifiedType::map;
144+
else if (typeEntry == "range")
145+
newType.specifiedType = SpecifiedType::range;
146+
else if (typeEntry == "vector")
147+
newType.specifiedType = SpecifiedType::vector;
148+
else if (typeEntry == "line")
149+
newType.specifiedType = SpecifiedType::line;
150+
else
151+
return {};
152+
153+
return newType;
154+
}
155+
156+
std::optional<color::ColorMapper> parseColorMapperFromRange(const QStringList &lineItems)
157+
{
158+
if (lineItems.count() < 12)
159+
return {};
160+
161+
const auto minValue = toInteger(lineItems[2]);
162+
const auto minColor =
163+
toColorWithClipping(lineItems[4], lineItems[6], lineItems[8], lineItems[10]);
164+
165+
const auto maxValue = toInteger(lineItems[3]);
166+
const auto maxColor =
167+
toColorWithClipping(lineItems[5], lineItems[7], lineItems[9], lineItems[11]);
168+
169+
if (!minValue || !minColor || !maxValue || !maxColor)
170+
return {};
171+
172+
return color::ColorMapper({*minValue, *maxValue}, *minColor, *maxColor);
173+
}
174+
62175
} // namespace
63176

64177
StatisticsFileCSV::StatisticsFileCSV(const std::string &filename, StatisticsData &statisticsData)
@@ -94,7 +207,6 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
94207
uint64_t lineBufferStartPos = 0;
95208
int lastPOC = INT_INVALID;
96209
int lastType = INT_INVALID;
97-
bool sortingFixed = false;
98210

99211
this->parsingInfo.parsingProgress = 0.0;
100212

@@ -148,14 +260,8 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
148260
// we found a new type but the POC stayed the same.
149261
// This seems to be an interleaved file
150262
// Check if we already collected a start position for this type
151-
if (!sortingFixed)
152-
{
153-
// we only check the first occurence of this, in a non-interleaved file
154-
// the above condition can be met and will reset fileSortedByPOC
155-
263+
if (this->parsingInfo.fileSorting == FileSorting::Unknown)
156264
this->parsingInfo.fileSorting = FileSorting::SortedByPOC;
157-
sortingFixed = true;
158-
}
159265
lastType = typeID;
160266
if (this->pocTypeFileposMap[poc].count(typeID) == 0)
161267
{
@@ -166,8 +272,8 @@ void StatisticsFileCSV::readFrameAndTypePositionsFromFile(std::atomic_bool &brea
166272
else if (poc != lastPOC)
167273
{
168274
// this is apparently not sorted by POCs and we will not check it further
169-
if (!sortingFixed)
170-
sortingFixed = true;
275+
if (this->parsingInfo.fileSorting == FileSorting::Unknown)
276+
this->parsingInfo.fileSorting = FileSorting::SortedByType;
171277

172278
// We found a new POC
173279
if (this->parsingInfo.fileSorting == FileSorting::SortedByPOC)
@@ -346,21 +452,10 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
346452
return;
347453

348454
statisticsData.clear();
349-
350-
struct ParsedData
351-
{
352-
int typeID{};
353-
std::string typeName{};
354-
355-
std::optional<StatisticsType::ValueDataOptions> valueDataOptions;
356-
std::optional<StatisticsType::VectorDataOptions> vectorDataOptions;
357-
StatisticsType::GridOptions gridOptions;
358-
};
359-
std::optional<ParsedData> type;
455+
std::optional<ParsedType> currentType;
360456

361457
while (!this->file.atEnd())
362458
{
363-
// read one line
364459
auto aLineByteArray = this->file.readLine();
365460
QString aLine(aLineByteArray);
366461

@@ -370,44 +465,19 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
370465
if (rowItemList[0].isEmpty())
371466
continue;
372467

373-
// either a new type or a line which is not header finishes the last type
374-
if (((rowItemList[1] == "type") || (rowItemList[0][0] != '%')) && type)
468+
const bool isNonHeaderLine = (rowItemList[0][0] != '%');
469+
if (isNonHeaderLine)
375470
{
376-
// Last type is complete. Store this initial state.
377-
statisticsData.addStatType(StatisticsTypeBuilder(type->typeID, type->typeName)
378-
.withOptionalValueDataOptions(type->valueDataOptions)
379-
.withOptionalVectorDataOptions(type->vectorDataOptions)
380-
.withGridOptions(type->gridOptions)
381-
.build());
382-
383-
type.reset();
384-
385-
// if we found a non-header line, stop here
386-
if (rowItemList[0][0] != '%')
387-
return;
471+
checkAndAddTypeToStatisticsData(statisticsData, currentType);
472+
return;
388473
}
389474

390475
if (rowItemList[1] == "type")
391476
{
392-
// Start of a new type
393-
type.emplace();
394-
type->typeID = rowItemList[2].toInt();
395-
type->typeName = rowItemList[3].toStdString();
477+
checkAndAddTypeToStatisticsData(statisticsData, currentType);
478+
currentType.reset();
396479

397-
// The next entry (4) is "map", "range", or "vector"
398-
if (rowItemList.count() >= 5)
399-
{
400-
if (rowItemList[4] == "map" || rowItemList[4] == "range")
401-
{
402-
type->valueDataOptions = StatisticsType::ValueDataOptions();
403-
}
404-
else if (rowItemList[4] == "vector" || rowItemList[4] == "line")
405-
{
406-
type->vectorDataOptions = StatisticsType::VectorDataOptions();
407-
if (rowItemList[4] == "line")
408-
type->vectorDataOptions->arrowHead = ArrowHead::none;
409-
}
410-
}
480+
currentType = parseHeaderLine(rowItemList);
411481
}
412482
else if (rowItemList[1] == "mapColor")
413483
{
@@ -419,60 +489,53 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
419489
auto b = (unsigned char)rowItemList[5].toInt();
420490
auto a = (unsigned char)rowItemList[6].toInt();
421491

422-
type->valueDataOptions->colorMapper->mappingType = color::MappingType::Map;
423-
type->valueDataOptions->colorMapper->colorMap[id] = Color(r, g, b, a);
492+
if (!currentType->valueDataOptions)
493+
currentType->valueDataOptions.emplace();
494+
currentType->valueDataOptions->colorMapper->mappingType = color::MappingType::Map;
495+
currentType->valueDataOptions->colorMapper->colorMap[id] = Color(r, g, b, a);
424496
}
425497
else if (rowItemList[1] == "range")
426498
{
427-
// This is a range with min/max
428-
auto min = rowItemList[2].toInt();
429-
auto r = (unsigned char)rowItemList[4].toInt();
430-
auto g = (unsigned char)rowItemList[6].toInt();
431-
auto b = (unsigned char)rowItemList[8].toInt();
432-
auto a = (unsigned char)rowItemList[10].toInt();
433-
auto minColor = Color(r, g, b, a);
434-
435-
auto max = rowItemList[3].toInt();
436-
r = rowItemList[5].toInt();
437-
g = rowItemList[7].toInt();
438-
b = rowItemList[9].toInt();
439-
a = rowItemList[11].toInt();
440-
auto maxColor = Color(r, g, b, a);
441-
442-
type->valueDataOptions->colorMapper = color::ColorMapper({min, max}, minColor, maxColor);
499+
if (currentType->specifiedType == SpecifiedType::range)
500+
if (const auto colorMapper = parseColorMapperFromRange(rowItemList))
501+
{
502+
if (!currentType->valueDataOptions)
503+
currentType->valueDataOptions.emplace();
504+
currentType->valueDataOptions->colorMapper = *colorMapper;
505+
}
443506
}
444507
else if (rowItemList[1] == "defaultRange")
445508
{
446-
// This is a color gradient function
447509
int min = rowItemList[2].toInt();
448510
int max = rowItemList[3].toInt();
449511
auto rangeName = rowItemList[4].toStdString();
450512

451-
type->valueDataOptions->colorMapper = color::ColorMapper({min, max}, rangeName);
513+
currentType->valueDataOptions->colorMapper->mappingType = color::MappingType::Predefined;
514+
currentType->valueDataOptions->colorMapper = color::ColorMapper({min, max}, rangeName);
452515
}
453516
else if (rowItemList[1] == "vectorColor")
454517
{
455-
auto r = (unsigned char)rowItemList[2].toInt();
456-
auto g = (unsigned char)rowItemList[3].toInt();
457-
auto b = (unsigned char)rowItemList[4].toInt();
458-
auto a = (unsigned char)rowItemList[5].toInt();
459-
type->vectorDataOptions->style->color = Color(r, g, b, a);
518+
auto r = (unsigned char)rowItemList[2].toInt();
519+
auto g = (unsigned char)rowItemList[3].toInt();
520+
auto b = (unsigned char)rowItemList[4].toInt();
521+
auto a = (unsigned char)rowItemList[5].toInt();
522+
currentType->vectorDataOptions->style->color = Color(r, g, b, a);
460523
}
461524
else if (rowItemList[1] == "gridColor")
462525
{
463-
auto r = (unsigned char)rowItemList[2].toInt();
464-
auto g = (unsigned char)rowItemList[3].toInt();
465-
auto b = (unsigned char)rowItemList[4].toInt();
466-
auto a = 255;
467-
type->gridOptions.style->color = Color(r, g, b, a);
526+
auto r = (unsigned char)rowItemList[2].toInt();
527+
auto g = (unsigned char)rowItemList[3].toInt();
528+
auto b = (unsigned char)rowItemList[4].toInt();
529+
auto a = 255;
530+
currentType->gridOptions.style->color = Color(r, g, b, a);
468531
}
469532
else if (rowItemList[1] == "scaleFactor")
470533
{
471-
type->vectorDataOptions->scale = rowItemList[2].toInt();
534+
currentType->vectorDataOptions->scale = rowItemList[2].toInt();
472535
}
473536
else if (rowItemList[1] == "scaleToBlockSize")
474537
{
475-
type->valueDataOptions->scaleToBlockSize = (rowItemList[2] == "1");
538+
currentType->valueDataOptions->scaleToBlockSize = (rowItemList[2] == "1");
476539
}
477540
else if (rowItemList[1] == "seq-specs")
478541
{
@@ -488,6 +551,8 @@ void StatisticsFileCSV::readHeaderFromFile(StatisticsData &statisticsData)
488551
this->framerate = rowItemList[6].toDouble();
489552
}
490553
}
554+
555+
checkAndAddTypeToStatisticsData(statisticsData, currentType);
491556
}
492557
catch (const char *str)
493558
{

YUViewUnitTest/common/TemporaryFile.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ TemporaryFile::TemporaryFile(const char *data)
8989
tempFileWriter.close();
9090
}
9191

92+
TemporaryFile::TemporaryFile(std::string_view data)
93+
{
94+
this->temporaryFilePath = std::filesystem::temp_directory_path() / generateRandomFileName();
95+
96+
std::ofstream tempFileWriter(this->temporaryFilePath, std::iostream::out | std::iostream::binary);
97+
tempFileWriter << data;
98+
tempFileWriter.close();
99+
}
100+
92101
TemporaryFile::~TemporaryFile()
93102
{
94103
std::filesystem::remove(this->temporaryFilePath);

YUViewUnitTest/common/TemporaryFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class TemporaryFile
4444
public:
4545
TemporaryFile(const ByteVector &data);
4646
TemporaryFile(const char *data);
47+
TemporaryFile(std::string_view data);
4748
~TemporaryFile();
4849

4950
std::filesystem::path getFilePath() const;

0 commit comments

Comments
 (0)