Skip to content

Commit

Permalink
Add new implementation of FileSourceAnnexB test
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristianFeldmann committed Jul 15, 2024
1 parent 38b3269 commit 7e9371f
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 1 deletion.
3 changes: 2 additions & 1 deletion YUViewUnitTest/YUViewUnitTest.pro
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ SOURCES += $$files(*.cpp, true)
HEADERS += $$files(*.h, true)

INCLUDEPATH += $$top_srcdir/submodules/googletest/googletest/include \
$$top_srcdir/YUViewLib/src
$$top_srcdir/YUViewLib/src \
$$top_srcdir/YUViewUnitTest/common
LIBS += -L$$top_builddir/submodules/googletest-qmake/gtest -lgtest
LIBS += -L$$top_builddir/submodules/googletest-qmake/gtest_main -lgtest_main
LIBS += -L$$top_builddir/YUViewLib -lYUViewLib
Expand Down
95 changes: 95 additions & 0 deletions YUViewUnitTest/common/TemporaryFile.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* This file is part of YUView - The YUV player with advanced analytics toolset
* <https://github.com/IENT/YUView>
* Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations including
* the two.
*
* You must obey the GNU General Public License in all respects for all
* of the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do
* so, delete this exception statement from your version. If you delete
* this exception statement from all source files in the program, then
* also delete it here.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "TemporaryFile.h"

#include <fstream>
#include <random>

namespace yuviewTest
{

namespace
{

char mapRandomNumberToAlphaChar(const int i)
{
constexpr auto ASCII_OFFSET_TO_0 = 48;
constexpr auto ASCII_OFFSET_TO_A = 65;
constexpr auto ASCII_OFFSET_TO_a = 97;

if (i < 10)
return static_cast<char>(i + ASCII_OFFSET_TO_0);
if (i < 36)
return static_cast<char>(i - 10 + ASCII_OFFSET_TO_A);
return static_cast<char>(i - 36 + ASCII_OFFSET_TO_a);
}

std::string generateRandomFileName()
{
std::random_device randomDevice;
std::mt19937 generator(randomDevice());

std::uniform_int_distribution<int> distribution(0, 61);

const auto value = distribution(generator);

std::stringstream s;
constexpr auto NR_CHARACTERS = 40;
for (int i = 0; i < NR_CHARACTERS; ++i)
s << mapRandomNumberToAlphaChar(distribution(generator));
return s.str();
}

} // namespace

TemporaryFile::TemporaryFile(const ByteVector &data)
{
this->temporaryFilePath = std::filesystem::temp_directory_path() / generateRandomFileName();

std::ofstream tempFileWriter(this->temporaryFilePath, std::iostream::out | std::iostream::binary);
std::for_each(
data.begin(), data.end(), [&tempFileWriter](const unsigned char c) { tempFileWriter << c; });
tempFileWriter.close();
}

TemporaryFile::~TemporaryFile()
{
std::filesystem::remove(this->temporaryFilePath);
}

std::filesystem::path TemporaryFile::getFilePath() const
{
return this->temporaryFilePath;
}

} // namespace yuviewTest
54 changes: 54 additions & 0 deletions YUViewUnitTest/common/TemporaryFile.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* This file is part of YUView - The YUV player with advanced analytics toolset
* <https://github.com/IENT/YUView>
* Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations including
* the two.
*
* You must obey the GNU General Public License in all respects for all
* of the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do
* so, delete this exception statement from your version. If you delete
* this exception statement from all source files in the program, then
* also delete it here.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <common/Typedef.h>

#include <filesystem>

namespace yuviewTest
{

class TemporaryFile
{
public:
TemporaryFile(const ByteVector &data);
~TemporaryFile();

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

private:
std::filesystem::path temporaryFilePath;
};

} // namespace yuviewTest
157 changes: 157 additions & 0 deletions YUViewUnitTest/filesource/FileSourceAnnexBTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* This file is part of YUView - The YUV player with advanced analytics toolset
* <https://github.com/IENT/YUView>
* Copyright (C) 2015 Institut für Nachrichtentechnik, RWTH Aachen University, GERMANY
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations including
* the two.
*
* You must obey the GNU General Public License in all respects for all
* of the code used other than OpenSSL. If you modify file(s) with this
* exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do
* so, delete this exception statement from your version. If you delete
* this exception statement from all source files in the program, then
* also delete it here.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "gtest/gtest.h"

using ::testing::TestWithParam;
using ::testing::Values;

#include <TemporaryFile.h>
#include <filesource/FileSourceAnnexBFile.h>

namespace
{

struct TestParameters
{
int startCodeLength{};
int totalDataLength{};
std::vector<int> startCodePositions{};
};

using NalSizes = std::vector<int>;
std::pair<NalSizes, ByteVector> generateAnnexBStream(const TestParameters &testParameters)
{
NalSizes nalSizes;
ByteVector data;

std::optional<int> lastStartPos;
for (const auto pos : testParameters.startCodePositions)
{
unsigned nonStartCodeBytesToAdd;
if (lastStartPos)
{
EXPECT_GT(pos,
*lastStartPos +
testParameters.startCodeLength); // Start codes can not be closer together
nonStartCodeBytesToAdd = pos - *lastStartPos - testParameters.startCodeLength;
nalSizes.push_back(nonStartCodeBytesToAdd + testParameters.startCodeLength);
}
else
nonStartCodeBytesToAdd = pos;
lastStartPos = pos;

data.insert(data.end(), nonStartCodeBytesToAdd, static_cast<char>(128));

static constexpr auto START_CODE_4BYTES = {char(0), char(0), char(0), char(1)};
static constexpr auto START_CODE_3BYTES = {char(0), char(0), char(1)};

if (testParameters.startCodeLength == 4)
data.insert(data.end(), START_CODE_4BYTES.begin(), START_CODE_4BYTES.end());
else
data.insert(data.end(), START_CODE_3BYTES.begin(), START_CODE_3BYTES.end());
}

const auto remainder =
testParameters.totalDataLength - *lastStartPos - testParameters.startCodeLength;
nalSizes.push_back(remainder + testParameters.startCodeLength);
data.insert(data.end(), remainder, char(128));

return {nalSizes, data};
}

class FileSourceAnnexBTest : public TestWithParam<TestParameters>
{
};

std::string getTestName(const testing::TestParamInfo<TestParameters> &testParam)
{
const auto testParameters = testParam.param;
std::stringstream s;
s << "TestAnnexBWithParameters_";
s << "startCodeLength_" << testParameters.startCodeLength << "_";
s << "totalDataLength_" << testParameters.totalDataLength << "_";
s << "startCodePositions_";
for (const auto &position : testParameters.startCodePositions)
s << position << "_";
return s.str();
}

TEST_P(FileSourceAnnexBTest, TestNalUnitParsing)
{
const auto testParameters = GetParam();

const auto [nalSizes, data] = generateAnnexBStream(testParameters);
yuviewTest::TemporaryFile temporaryFile(data);

FileSourceAnnexBFile annexBFile(QString::fromStdString(temporaryFile.getFilePath().string()));
EXPECT_EQ(static_cast<int>(annexBFile.getNrBytesBeforeFirstNAL()),
testParameters.startCodePositions.at(0));

auto nalData = annexBFile.getNextNALUnit();
int counter = 0;
while (nalData.size() > 0)
{
EXPECT_EQ(nalSizes.at(counter++), static_cast<int>(nalData.size()));
nalData = annexBFile.getNextNALUnit();
}
}

INSTANTIATE_TEST_SUITE_P(
FilesourceTest,
FileSourceAnnexBTest,
Values(TestParameters({3, 10000, {80, 208, 500}}),
TestParameters({3, 10000, {0, 80, 208, 500}}),
TestParameters({3, 10000, {1, 80, 208, 500}}),
TestParameters({3, 10000, {2, 80, 208, 500}}),
TestParameters({3, 10000, {3, 80, 208, 500}}),
TestParameters({3, 10000, {4, 80, 208, 500}}),
TestParameters({3, 10000, {4, 80, 208, 9990}}),
TestParameters({3, 10000, {4, 80, 208, 9997}}),

// Test cases where a buffer reload is needed (the buffer is 500k)
TestParameters({3, 1000000, {80, 208, 500, 50000, 800000}}),

// The buffer is 500k in size. Test all variations with a start code around this position
TestParameters({3, 800000, {80, 208, 500, 50000, 499997}}),
TestParameters({3, 800000, {80, 208, 500, 50000, 499998}}),
TestParameters({3, 800000, {80, 208, 500, 50000, 499999}}),
TestParameters({3, 800000, {80, 208, 500, 50000, 500000}}),
TestParameters({3, 800000, {80, 208, 500, 50000, 500001}}),
TestParameters({3, 800000, {80, 208, 500, 50000, 500002}}),

TestParameters({3, 10000, {80, 208, 500, 9995}}),
TestParameters({3, 10000, {80, 208, 500, 9996}}),
TestParameters({3, 10000, {80, 208, 500, 9997}})),
getTestName);

} // namespace

0 comments on commit 7e9371f

Please sign in to comment.