From 86b2519a92e21a3db16b7247cde71d1654b63b77 Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Fri, 3 May 2024 09:03:04 +0200 Subject: [PATCH 1/4] Add File packet comparison app --- src/app/CMakeLists.txt | 8 + src/app/FilePacketComparer.cpp | 276 +++++++++++++++++++++++++++++++++ src/app/FileProber.cpp | 101 +----------- src/app/Formatting.h | 107 +++++++++++++ 4 files changed, 398 insertions(+), 94 deletions(-) create mode 100644 src/app/FilePacketComparer.cpp create mode 100644 src/app/Formatting.h diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 32da1bd..ec1b32a 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -4,3 +4,11 @@ target_include_directories(fileProber PRIVATE ${CMAKE_SOURCE_DIR}/src/lib) target_link_libraries (fileProber libFFmpeg++) install(TARGETS fileProber RUNTIME DESTINATION bin COMPONENT applications) + + +add_executable(filePacketComparer FilePacketComparer.cpp) + +target_include_directories(filePacketComparer PRIVATE ${CMAKE_SOURCE_DIR}/src/lib) +target_link_libraries (filePacketComparer libFFmpeg++) + +install(TARGETS filePacketComparer RUNTIME DESTINATION bin COMPONENT applications) diff --git a/src/app/FilePacketComparer.cpp b/src/app/FilePacketComparer.cpp new file mode 100644 index 0000000..de2e9b9 --- /dev/null +++ b/src/app/FilePacketComparer.cpp @@ -0,0 +1,276 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#include +#include +#include + +#include "Formatting.h" + +#include +#include +#include +#include +#include +#include + +using namespace libffmpeg; +using PacketQueue = std::queue; + +void showUsage() +{ + std::cout << "FilePacketComparer takes 2 input files and compares the packets of one\n"; + std::cout << "stream in each of the inputs. Packets are checked for data identity.\n"; + std::cout << "Usage:\n"; + std::cout + << " FilePacketComparer : : [options]\n"; + std::cout << "\n"; + std::cout << "Options:\n"; + std::cout << " -loglevelDebug Set log level to debug output\n"; + std::cout << " -loglevelInfo Set log level to info output\n"; + std::cout << " -loglevelWarning Set log level to warning output\n"; + std::cout << " -libPath Set a search path for the ffmpeg libraries\n"; +} + +struct CompareFile +{ + std::string filename; + int streamIndex{}; +}; + +struct Settings +{ + CompareFile file1{}; + CompareFile file2{}; + bool showPackets{}; + std::filesystem::path libraryPath{}; + libffmpeg::LogLevel logLevel{libffmpeg::LogLevel::Error}; +}; + +std::optional parseFileNameAndStreamIndex(const std::string &variable) +{ + const auto columnPos = variable.rfind(":"); + if (columnPos >= variable.size()) + return {}; + + CompareFile file; + + file.filename = variable.substr(0, columnPos); + if (!std::filesystem::exists(file.filename)) + { + std::cout << "Given file " << file.filename << " not found."; + return {}; + } + + try + { + file.streamIndex = std::stoi(variable.substr(columnPos + 1)); + } + catch (const std::exception &e) + { + return {}; + } + + return file; +} + +void compareQueuePacketsAndDrain(PacketQueue &queue1, PacketQueue &queue2) +{ + while (!queue1.empty() && !queue2.empty()) + { + auto packet1 = std::move(queue1.front()); + auto packet2 = std::move(queue2.front()); + + queue1.pop(); + queue2.pop(); + + const auto streamIndex1 = packet1.getStreamIndex(); + const auto streamIndex2 = packet2.getStreamIndex(); + + static int packetCount = -1; + ++packetCount; + + if (packet1.getDuration() != packet2.getDuration()) + { + std::cout << "Error comparing packet " << packetCount << ". Duration unequal (" + << packet1.getDuration() << " vs " << packet2.getDuration() << ").\n"; + return; + } + + // if (packet1.getDataSize() != packet2.getDataSize()) + // std::cout << "Error comparing packet. Data size unequal (" << packet1.getDataSize() << " vs + // " + // << packet2.getDataSize() << ").\n"; + + // COmpare data + + std::cout << "Match for packet " << packetCount << ". Duration " << packet1.getDuration() + << ".\n"; + } +} + +void logPacketQueueState(const std::string &queueName, const PacketQueue &queue) +{ + if (!queue.empty()) + { + std::cout << "Queue " << queueName << " is not empty. " << queue.size() + << " packets not matched."; + } +} + +std::optional parseCommandLineArguments(int argc, char const *argv[]) +{ + Settings settings; + + if (argc < 2) + { + std::cout << "Not enough arguemnts. Two files must be given"; + return {}; + } + + for (int i = 1; i < argc; ++i) + { + const auto argument = std::string(argv[i]); + + if (1 == i || 2 == i) + { + if (const auto file = parseFileNameAndStreamIndex(argument)) + { + if (i == 1) + settings.file1 = *file; + else + settings.file2 = *file; + } + else + return {}; + } + if (argument == "-showAllPackets") + settings.showPackets = true; + if (argument == "-loglevelDebug") + settings.logLevel = libffmpeg::LogLevel::Debug; + if (argument == "-loglevelInfo") + settings.logLevel = libffmpeg::LogLevel::Info; + if (argument == "-loglevelWarning") + settings.logLevel = libffmpeg::LogLevel::Warning; + if (argument == "-libPath") + { + i++; + if (i < argc) + { + const auto nextArgument = std::string(argv[i]); + const auto path = std::filesystem::path(nextArgument); + const auto fileStatus = std::filesystem::status(path); + if (fileStatus.type() == std::filesystem::file_type::not_found) + std::cout << "The given library path " << nextArgument + << " could not be found. Ignoring the given path."; + else + settings.libraryPath = path; + } + else + { + std::cout << "Missing argument for parameter -libPath"; + return {}; + } + } + } + return settings; +} + +void loggingFunction(const LogLevel logLevel, const std::string &message) +{ + static std::map LogLevelToName = {{LogLevel::Debug, "Debug"}, + {LogLevel::Info, "Info"}, + {LogLevel::Warning, "Warning"}, + {LogLevel::Error, "Error"}}; + + std::cout << "[" << LogLevelToName.at(logLevel) << "]" << message << "\n"; +} + +int main(int argc, char const *argv[]) +{ + const auto settings = parseCommandLineArguments(argc, argv); + if (!settings) + { + showUsage(); + return 1; + } + + const auto loadingResult = FFmpegLibrariesBuilder() + .withLoggingFunction(&loggingFunction, settings->logLevel) + .tryLoadingOfLibraries(); + + if (!loadingResult.ffmpegLibraries) + { + std::cout << "Error when loading libraries\n"; + return 1; + } + else + { + std::cout << "Successfully loaded ffmpeg libraries.\n"; + std::cout << "\nLibraries info:\n"; + for (const auto info : loadingResult.ffmpegLibraries->getLibrariesInfo()) + { + std::cout << " " << info.name << ":\n"; + std::cout << " Path : " << info.path << ":\n"; + std::cout << " Version: " << info.version << ":\n"; + } + } + + Demuxer demuxer1(loadingResult.ffmpegLibraries); + if (!demuxer1.openFile(settings->file1.filename)) + { + std::cout << "Error when opening first input file : " + settings->file1.filename + "\n "; + return 1; + } + std::cout << "Successfully opened file " + settings->file1.filename + ".\n"; + + Demuxer demuxer2(loadingResult.ffmpegLibraries); + if (!demuxer2.openFile(settings->file2.filename)) + { + std::cout << "Error when opening second input file : " + settings->file2.filename + "\n "; + return 1; + } + std::cout << "Successfully opened file " + settings->file2.filename + ".\n"; + + const auto formatContext1 = demuxer1.getFormatContext(); + const auto inputFormat1 = formatContext1->getInputFormat(); + + std::cout << "\nFile one info:\n"; + printInputFormat(formatContext1, inputFormat1); + + const auto formatContext2 = demuxer2.getFormatContext(); + const auto inputFormat2 = formatContext2->getInputFormat(); + + std::cout << "\nFile two info:\n"; + printInputFormat(formatContext2, inputFormat2); + + PacketQueue packetQueue1; + PacketQueue packetQueue2; + + // We don't assume that the packets from both files are iin the same order. So we have to queue + // them for comparison. + while (true) + { + auto packet1 = demuxer1.getNextPacket(); + if (packet1 && packet1->getStreamIndex() == settings->file1.streamIndex) + packetQueue1.push(std::move(*packet1)); + + auto packet2 = demuxer2.getNextPacket(); + if (packet2 && packet2->getStreamIndex() == settings->file2.streamIndex) + packetQueue2.push(std::move(*packet2)); + + compareQueuePacketsAndDrain(packetQueue1, packetQueue2); + // We could possibly check if the queues run too full + + if (!packet1 && !packet2) + break; + } + + logPacketQueueState("1", packetQueue1); + logPacketQueueState("2", packetQueue2); + + return 0; +} diff --git a/src/app/FileProber.cpp b/src/app/FileProber.cpp index 6ecc901..eade610 100644 --- a/src/app/FileProber.cpp +++ b/src/app/FileProber.cpp @@ -8,6 +8,8 @@ #include #include +#include "Formatting.h" + #include #include #include @@ -29,59 +31,6 @@ void showUsage() std::cout << " -libPath Set a search path for the ffmpeg libraries\n"; } -std::string to_string(const avcodec::CodecDescriptorProperties &properties) -{ - std::string str; - if (properties.intraOnly) - str += "Intra Only, "; - if (properties.lossy) - str += "Lossy, "; - if (properties.lossless) - str += "Lossless, "; - if (properties.reorder) - str += "Reorder, "; - if (properties.bitmapSub) - str += "Bitmap Subtitles, "; - if (properties.textSub) - str += "Text Subtitles, "; - - if (str.empty()) - return {}; - return str.substr(0, str.length() - 2); -} - -std::string to_string(const Rational rational) -{ - return std::to_string(rational.numerator) + "/" + std::to_string(rational.denominator); -} - -std::string to_string(const Size size) -{ - return std::to_string(size.width) + "x" + std::to_string(size.height); -} - -std::string to_string(const ByteVector &bytes) -{ - std::ostringstream stream; - for (const auto &byte : bytes) - stream << "0x" << std::hex << std::to_integer(byte) << " "; - return stream.str(); -} - -template std::string to_string(const std::map &map) -{ - std::ostringstream stream; - auto isFirst = false; - for (const auto [key, value] : map) - { - if (!isFirst) - stream << ", "; - stream << "[" << key << ", " << value << "]"; - isFirst = false; - } - return stream.str(); -} - struct Settings { std::string filename{}; @@ -204,50 +153,14 @@ int main(int argc, char const *argv[]) const auto inputFormat = formatContext->getInputFormat(); std::cout << "\nFile info:\n"; - - std::cout << " Format:\n"; - std::cout << " Name : " << inputFormat.getName() << "\n"; - std::cout << " Long Name : " << inputFormat.getLongName() << "\n"; - std::cout << " Flags : " << to_string(inputFormat.getFlags()) << "\n"; - std::cout << " Extensions : " << inputFormat.getExtensions() << "\n"; - std::cout << " Mime Type : " << inputFormat.getMimeType() << "\n"; - std::cout << " Start time : " << formatContext->getStartTime() << "\n"; - std::cout << " Duration : " << formatContext->getDuration() << "\n"; - - for (const auto &stream : formatContext->getStreams()) - { - std::cout << " Streams " << stream.getIndex() << ":\n"; - std::cout << " Codec Type : " - << avutil::mediaTypeMapper.getName(stream.getCodecType()) << "\n"; - - std::cout << " Codec Description\n"; - if (const auto codecDescriptor = stream.getCodecDescriptor()) - { - std::cout << " Media Type : " - << avutil::mediaTypeMapper.getName(codecDescriptor->mediaType) << "\n"; - std::cout << " Name : " << codecDescriptor->codecName << "\n"; - std::cout << " Long Name : " << codecDescriptor->longName << "\n"; - std::cout << " Properties : " << to_string(codecDescriptor->properties) << "\n"; - std::cout << " Mime Types : " << to_string(codecDescriptor->mimeTypes) << "\n"; - std::cout << " Profiles : " << to_string(codecDescriptor->profiles) << "\n"; - - std::cout << " Average Framerate : " << to_string(stream.getAverageFrameRate()) << "\n"; - std::cout << " Time Base : " << to_string(stream.getTimeBase()) << "\n"; - std::cout << " Frame Size : " << to_string(stream.getFrameSize()) << "\n"; - std::cout << " Colorspace : " - << avutil::colorSpaceMapper.getName(stream.getColorspace()) << " - " - << avutil::colorSpaceMapper.getText(stream.getColorspace()) << "\n"; - std::cout << " Pixel Format : " << stream.getPixelFormat().name << "\n"; - std::cout << " Extradata : " << to_string(stream.getExtradata()) << "\n"; - } - } + printInputFormat(formatContext, inputFormat); struct StreamCounters { - int packetCount{0}; - std::map packetCountPerDuration{}; - std::map packetCountPerPtsIncrease{}; - std::map packetCountPerDtsIncrease{}; + int packetCount{0}; + std::map packetCountPerDuration{}; + std::map packetCountPerPtsIncrease{}; + std::map packetCountPerDtsIncrease{}; }; std::map streamPacketCounters; diff --git a/src/app/Formatting.h b/src/app/Formatting.h new file mode 100644 index 0000000..2a31ab2 --- /dev/null +++ b/src/app/Formatting.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2023 Christian Feldmann [christian.feldmann@gmx.de]. + * All rights reserved. + * This work is licensed under the terms of the MIT license. + * For a copy, see . + */ + +#include +#include + +#include +#include + +using namespace libffmpeg; + +std::string to_string(const avcodec::CodecDescriptorProperties &properties) +{ + std::string str; + if (properties.intraOnly) + str += "Intra Only, "; + if (properties.lossy) + str += "Lossy, "; + if (properties.lossless) + str += "Lossless, "; + if (properties.reorder) + str += "Reorder, "; + if (properties.bitmapSub) + str += "Bitmap Subtitles, "; + if (properties.textSub) + str += "Text Subtitles, "; + + if (str.empty()) + return {}; + return str.substr(0, str.length() - 2); +} + +std::string to_string(const Rational rational) +{ + return std::to_string(rational.numerator) + "/" + std::to_string(rational.denominator); +} + +std::string to_string(const Size size) +{ + return std::to_string(size.width) + "x" + std::to_string(size.height); +} + +std::string to_string(const ByteVector &bytes) +{ + std::ostringstream stream; + for (const auto &byte : bytes) + stream << "0x" << std::hex << std::to_integer(byte) << " "; + return stream.str(); +} + +template std::string to_string(const std::map &map) +{ + std::ostringstream stream; + auto isFirst = false; + for (const auto [key, value] : map) + { + if (!isFirst) + stream << ", "; + stream << "[" << key << ", " << value << "]"; + isFirst = false; + } + return stream.str(); +} + +void printInputFormat(const avformat::AVFormatContextWrapper *formatContext, + const avformat::AVInputFormatWrapper & inputFormat) +{ + std::cout << " Format:\n"; + std::cout << " Name : " << inputFormat.getName() << "\n"; + std::cout << " Long Name : " << inputFormat.getLongName() << "\n"; + std::cout << " Flags : " << to_string(inputFormat.getFlags()) << "\n"; + std::cout << " Extensions : " << inputFormat.getExtensions() << "\n"; + std::cout << " Mime Type : " << inputFormat.getMimeType() << "\n"; + std::cout << " Start time : " << formatContext->getStartTime() << "\n"; + std::cout << " Duration : " << formatContext->getDuration() << "\n"; + + for (const auto &stream : formatContext->getStreams()) + { + std::cout << " Streams " << stream.getIndex() << ":\n"; + std::cout << " Codec Type : " + << avutil::mediaTypeMapper.getName(stream.getCodecType()) << "\n"; + + std::cout << " Codec Description\n"; + if (const auto codecDescriptor = stream.getCodecDescriptor()) + { + std::cout << " Media Type : " + << avutil::mediaTypeMapper.getName(codecDescriptor->mediaType) << "\n"; + std::cout << " Name : " << codecDescriptor->codecName << "\n"; + std::cout << " Long Name : " << codecDescriptor->longName << "\n"; + std::cout << " Properties : " << to_string(codecDescriptor->properties) << "\n"; + std::cout << " Mime Types : " << to_string(codecDescriptor->mimeTypes) << "\n"; + std::cout << " Profiles : " << to_string(codecDescriptor->profiles) << "\n"; + + std::cout << " Average Framerate : " << to_string(stream.getAverageFrameRate()) << "\n"; + std::cout << " Time Base : " << to_string(stream.getTimeBase()) << "\n"; + std::cout << " Frame Size : " << to_string(stream.getFrameSize()) << "\n"; + std::cout << " Colorspace : " + << avutil::colorSpaceMapper.getName(stream.getColorspace()) << " - " + << avutil::colorSpaceMapper.getText(stream.getColorspace()) << "\n"; + std::cout << " Pixel Format : " << stream.getPixelFormat().name << "\n"; + std::cout << " Extradata : " << to_string(stream.getExtradata()) << "\n"; + } + } +} From 6ded2c3d2202bff10a36b785ef990020c2c566b0 Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Fri, 3 May 2024 11:27:16 +0200 Subject: [PATCH 2/4] Improve comparison of packets. Raw comparison of data as well as packet wise is supported. Also check data. --- src/app/FilePacketComparer.cpp | 199 +++++++++++++++++++++++++-------- 1 file changed, 153 insertions(+), 46 deletions(-) diff --git a/src/app/FilePacketComparer.cpp b/src/app/FilePacketComparer.cpp index de2e9b9..f6b17aa 100644 --- a/src/app/FilePacketComparer.cpp +++ b/src/app/FilePacketComparer.cpp @@ -19,6 +19,7 @@ using namespace libffmpeg; using PacketQueue = std::queue; +using DataQueue = std::deque; void showUsage() { @@ -50,6 +51,16 @@ struct Settings libffmpeg::LogLevel logLevel{libffmpeg::LogLevel::Error}; }; +/* For some codecs (e.g. aac) the packet sizes and durations must be identical. + * For other codecs (e.g. raw data like pcm), the size of the packets is not so + * important but the data (byte by byte) must match. + */ +enum class ComparisonMode +{ + Packets, + Data +}; + std::optional parseFileNameAndStreamIndex(const std::string &variable) { const auto columnPos = variable.rfind(":"); @@ -77,6 +88,66 @@ std::optional parseFileNameAndStreamIndex(const std::string &variab return file; } +Demuxer openInput(std::shared_ptr ffmpegLibraries, const std::string &filename) +{ + Demuxer demuxer(ffmpegLibraries); + if (!demuxer.openFile(filename)) + throw std::runtime_error("Error when opening first input file : " + filename + "\n "); + + std::cout << "Successfully opened file " + filename + ".\n"; + + const auto formatContext = demuxer.getFormatContext(); + const auto inputFormat = formatContext->getInputFormat(); + + std::cout << "\nFile info:\n"; + printInputFormat(formatContext, inputFormat); + std::cout << "\n"; + + return demuxer; +} + +ComparisonMode checkStreamsAndGetComparMode(Demuxer & demuxer1, + Demuxer & demuxer2, + const int streamIndex1, + const int streamIndex2) +{ + const auto streams1 = demuxer1.getFormatContext()->getStreams(); + const auto streams2 = demuxer2.getFormatContext()->getStreams(); + + if (streamIndex1 >= streams1.size()) + throw std::runtime_error("Given stream index for stream 1 not found."); + if (streamIndex2 >= streams2.size()) + throw std::runtime_error("Given stream index for stream 2 not found."); + + const auto codecType1 = streams1.at(streamIndex1).getCodecType(); + const auto codecType2 = streams2.at(streamIndex2).getCodecType(); + if (codecType1 != codecType2) + throw std::runtime_error("Stream types of streams to compare do not match. Type 1 " + + avutil::mediaTypeMapper.getName(codecType1) + " and type 2 " + + avutil::mediaTypeMapper.getName(codecType2)); + + const auto codecDescriptor1 = streams1.at(streamIndex1).getCodecDescriptor(); + if (!codecDescriptor1) + throw std::runtime_error("Error getting codec descriptor for stream 1."); + const auto codecDescriptor2 = streams2.at(streamIndex2).getCodecDescriptor(); + if (!codecDescriptor2) + throw std::runtime_error("Error getting codec descriptor for stream 2."); + + if (codecDescriptor1->codecName != codecDescriptor2->codecName) + throw std::runtime_error("Codec name of streams to compare do not match. Name 1 " + + codecDescriptor1->codecName + " and name 2 " + + codecDescriptor2->codecName); + + if (codecDescriptor1->codecName.find("pcm") == 0) + return ComparisonMode::Data; + return ComparisonMode::Packets; +} + +bool compareData(const ByteVector &data1, const ByteVector &data2) +{ + return std::equal(data1.begin(), data1.end(), data2.begin(), data2.end()); +} + void compareQueuePacketsAndDrain(PacketQueue &queue1, PacketQueue &queue2) { while (!queue1.empty() && !queue2.empty()) @@ -100,24 +171,59 @@ void compareQueuePacketsAndDrain(PacketQueue &queue1, PacketQueue &queue2) return; } - // if (packet1.getDataSize() != packet2.getDataSize()) - // std::cout << "Error comparing packet. Data size unequal (" << packet1.getDataSize() << " vs - // " - // << packet2.getDataSize() << ").\n"; + if (packet1.getDataSize() != packet2.getDataSize()) + { + std::cout << "Error comparing packet " << packetCount << ". Data size unequal (" + << packet1.getDataSize() << " vs " << packet2.getDataSize() << ").\n"; + return; + } - // COmpare data + if (!compareData(packet1.getData(), packet2.getData())) + { + std::cout << "Error comparing packet " << packetCount << ". Data unequal.\n"; + return; + } std::cout << "Match for packet " << packetCount << ". Duration " << packet1.getDuration() << ".\n"; } } -void logPacketQueueState(const std::string &queueName, const PacketQueue &queue) +void compareDataQueueAndDrain(DataQueue &queue1, DataQueue &queue2) +{ + int bytesMatched = 0; + bool matched = true; + + while (!queue1.empty() && !queue2.empty()) + { + const auto byte1 = queue1.front(); + const auto byte2 = queue2.front(); + + queue1.pop_front(); + queue2.pop_front(); + + static int byteCounter = -1; + ++byteCounter; + ++bytesMatched; + + if (byte1 != byte2) + { + std::cout << "Error comparing data. Byte " << byteCounter << " differs.\n"; + matched = false; + } + } + + if (bytesMatched > 0) + std::cout << (matched ? "Successfully matched " : "Failed to match ") << bytesMatched + << " bytes.\n"; +} + +template void logQueueState(const std::string &queueName, const T &queue) { if (!queue.empty()) { std::cout << "Queue " << queueName << " is not empty. " << queue.size() - << " packets not matched."; + << " items not matched."; } } @@ -219,58 +325,59 @@ int main(int argc, char const *argv[]) } } - Demuxer demuxer1(loadingResult.ffmpegLibraries); - if (!demuxer1.openFile(settings->file1.filename)) - { - std::cout << "Error when opening first input file : " + settings->file1.filename + "\n "; - return 1; - } - std::cout << "Successfully opened file " + settings->file1.filename + ".\n"; - - Demuxer demuxer2(loadingResult.ffmpegLibraries); - if (!demuxer2.openFile(settings->file2.filename)) - { - std::cout << "Error when opening second input file : " + settings->file2.filename + "\n "; - return 1; - } - std::cout << "Successfully opened file " + settings->file2.filename + ".\n"; + auto demuxer1 = openInput(loadingResult.ffmpegLibraries, settings->file1.filename); + auto demuxer2 = openInput(loadingResult.ffmpegLibraries, settings->file2.filename); - const auto formatContext1 = demuxer1.getFormatContext(); - const auto inputFormat1 = formatContext1->getInputFormat(); + const auto compareMode = checkStreamsAndGetComparMode( + demuxer1, demuxer2, settings->file1.streamIndex, settings->file2.streamIndex); - std::cout << "\nFile one info:\n"; - printInputFormat(formatContext1, inputFormat1); + PacketQueue packetQueue[2]; + DataQueue dataQueue[2]; - const auto formatContext2 = demuxer2.getFormatContext(); - const auto inputFormat2 = formatContext2->getInputFormat(); - - std::cout << "\nFile two info:\n"; - printInputFormat(formatContext2, inputFormat2); - - PacketQueue packetQueue1; - PacketQueue packetQueue2; + auto addPacketToQueue = [&packetQueue, &dataQueue, compareMode](avcodec::AVPacketWrapper &&packet, + const int streamIndex, + const int queueIndex) { + const auto packetStreamIndex = packet.getStreamIndex(); + if (packetStreamIndex != streamIndex) + return; + if (compareMode == ComparisonMode::Packets) + packetQueue[queueIndex].push(std::move(packet)); + else + { + const auto data = packet.getData(); + dataQueue[queueIndex].insert(dataQueue[queueIndex].end(), data.begin(), data.end()); + } + }; - // We don't assume that the packets from both files are iin the same order. So we have to queue - // them for comparison. while (true) { auto packet1 = demuxer1.getNextPacket(); - if (packet1 && packet1->getStreamIndex() == settings->file1.streamIndex) - packetQueue1.push(std::move(*packet1)); - auto packet2 = demuxer2.getNextPacket(); - if (packet2 && packet2->getStreamIndex() == settings->file2.streamIndex) - packetQueue2.push(std::move(*packet2)); - - compareQueuePacketsAndDrain(packetQueue1, packetQueue2); - // We could possibly check if the queues run too full if (!packet1 && !packet2) break; + + if (packet1) + addPacketToQueue(std::move(*packet1), settings->file1.streamIndex, 0); + if (packet2) + addPacketToQueue(std::move(*packet2), settings->file2.streamIndex, 1); + + if (compareMode == ComparisonMode::Packets) + compareQueuePacketsAndDrain(packetQueue[0], packetQueue[1]); + else + compareDataQueueAndDrain(dataQueue[0], dataQueue[1]); } - logPacketQueueState("1", packetQueue1); - logPacketQueueState("2", packetQueue2); + if (compareMode == ComparisonMode::Packets) + { + logQueueState("1", packetQueue[0]); + logQueueState("2", packetQueue[1]); + } + else + { + logQueueState("1", dataQueue[0]); + logQueueState("2", dataQueue[1]); + } return 0; } From 79af8a3b29af4f30c568a55907828da3a48d700d Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Fri, 3 May 2024 11:59:05 +0200 Subject: [PATCH 3/4] Improve data check a bit --- src/app/FilePacketComparer.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app/FilePacketComparer.cpp b/src/app/FilePacketComparer.cpp index f6b17aa..6c5c497 100644 --- a/src/app/FilePacketComparer.cpp +++ b/src/app/FilePacketComparer.cpp @@ -164,28 +164,30 @@ void compareQueuePacketsAndDrain(PacketQueue &queue1, PacketQueue &queue2) static int packetCount = -1; ++packetCount; + bool match = true; + if (packet1.getDuration() != packet2.getDuration()) { std::cout << "Error comparing packet " << packetCount << ". Duration unequal (" << packet1.getDuration() << " vs " << packet2.getDuration() << ").\n"; - return; + match = false; } if (packet1.getDataSize() != packet2.getDataSize()) { std::cout << "Error comparing packet " << packetCount << ". Data size unequal (" << packet1.getDataSize() << " vs " << packet2.getDataSize() << ").\n"; - return; + match = false; } - - if (!compareData(packet1.getData(), packet2.getData())) + else if (!compareData(packet1.getData(), packet2.getData())) { std::cout << "Error comparing packet " << packetCount << ". Data unequal.\n"; - return; + match = false; } - std::cout << "Match for packet " << packetCount << ". Duration " << packet1.getDuration() - << ".\n"; + if (match) + std::cout << "Match for packet " << packetCount << ". Duration " << packet1.getDuration() + << ".\n"; } } From 2d2d47ab524ffebe728eb94400b58b461c98dac1 Mon Sep 17 00:00:00 2001 From: ChristianFeldmann Date: Wed, 31 Jul 2024 21:54:34 +0200 Subject: [PATCH 4/4] Missing header --- src/app/Formatting.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/Formatting.h b/src/app/Formatting.h index 2a31ab2..42f0b59 100644 --- a/src/app/Formatting.h +++ b/src/app/Formatting.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -66,7 +67,7 @@ template std::string to_string(const std::map } void printInputFormat(const avformat::AVFormatContextWrapper *formatContext, - const avformat::AVInputFormatWrapper & inputFormat) + const avformat::AVInputFormatWrapper &inputFormat) { std::cout << " Format:\n"; std::cout << " Name : " << inputFormat.getName() << "\n";