From 849027e91f102dc1d8b2448dd59d4aacfdfcb9e0 Mon Sep 17 00:00:00 2001 From: Christian Feldmann Date: Sun, 24 Mar 2024 19:07:52 +0100 Subject: [PATCH] Add lhvC parsing --- YUViewLib/src/common/Functions.cpp | 10 +++ YUViewLib/src/common/Functions.h | 2 + YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp | 25 ++++++ YUViewLib/src/ffmpeg/AVInputFormatWrapper.h | 6 ++ .../src/filesource/FileSourceFFmpegFile.cpp | 44 ++++++++++ .../src/filesource/FileSourceFFmpegFile.h | 4 + ...{HVCC.cpp => DecoderConfigurationHvcC.cpp} | 58 +++----------- .../{HVCC.h => DecoderConfigurationHvcC.h} | 43 ++-------- .../AVFormat/DecoderConfigurationLhvC.cpp | 76 ++++++++++++++++++ .../AVFormat/DecoderConfigurationLhvC.h | 66 +++++++++++++++ .../AVFormat/DecoderConfigurationNalArray.cpp | 80 +++++++++++++++++++ .../AVFormat/DecoderConfigurationNalArray.h | 71 ++++++++++++++++ .../src/parser/AVFormat/ParserAVFormat.cpp | 47 +++++++---- .../src/parser/AVFormat/ParserAVFormat.h | 22 +++-- YUViewLib/src/playlistitem/playlistItems.cpp | 2 + 15 files changed, 446 insertions(+), 110 deletions(-) rename YUViewLib/src/parser/AVFormat/{HVCC.cpp => DecoderConfigurationHvcC.cpp} (67%) rename YUViewLib/src/parser/AVFormat/{HVCC.h => DecoderConfigurationHvcC.h} (73%) create mode 100644 YUViewLib/src/parser/AVFormat/DecoderConfigurationLhvC.cpp create mode 100644 YUViewLib/src/parser/AVFormat/DecoderConfigurationLhvC.h create mode 100644 YUViewLib/src/parser/AVFormat/DecoderConfigurationNalArray.cpp create mode 100644 YUViewLib/src/parser/AVFormat/DecoderConfigurationNalArray.h diff --git a/YUViewLib/src/common/Functions.cpp b/YUViewLib/src/common/Functions.cpp index 07a7b7b0f..ce6d6ebdf 100644 --- a/YUViewLib/src/common/Functions.cpp +++ b/YUViewLib/src/common/Functions.cpp @@ -168,6 +168,16 @@ std::string toLower(std::string str) return str; } +ByteVector readData(std::istream &istream, const size_t nrBytes) +{ + ByteVector data; + data.resize(nrBytes); + istream.read(reinterpret_cast(data.data()), nrBytes); + const auto nrBytesActuallyRead = istream.gcount(); + data.resize(nrBytesActuallyRead); + return data; +} + std::optional toUnsigned(const std::string &text) { try diff --git a/YUViewLib/src/common/Functions.h b/YUViewLib/src/common/Functions.h index 667c7fe41..a06553ea6 100644 --- a/YUViewLib/src/common/Functions.h +++ b/YUViewLib/src/common/Functions.h @@ -34,6 +34,7 @@ #include +#include #include namespace functions @@ -64,6 +65,7 @@ QString formatDataSize(double size, bool isBits = false); QStringList toQStringList(const std::vector &stringVec); std::string toLower(std::string str); +ByteVector readData(std::istream &istream, const size_t nrBytes); inline std::string boolToString(bool b) { diff --git a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp b/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp index 7362e3372..0193e9145 100644 --- a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp +++ b/YUViewLib/src/ffmpeg/AVInputFormatWrapper.cpp @@ -65,6 +65,31 @@ AVInputFormatWrapper::AVInputFormatWrapper(AVInputFormat *f, LibraryVersion v) this->update(); } +QString AVInputFormatWrapper::getName() const +{ + return this->name; +} + +QString AVInputFormatWrapper::getLongName() const +{ + return this->long_name; +} + +int AVInputFormatWrapper::getFlags() const +{ + return this->flags; +} + +QString AVInputFormatWrapper::getExtensions() const +{ + return this->extensions; +} + +QString AVInputFormatWrapper::getMimeType() const +{ + return this->mime_type; +} + void AVInputFormatWrapper::update() { if (this->fmt == nullptr) diff --git a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h b/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h index ec1ebdf2c..c9fdda8d6 100644 --- a/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h +++ b/YUViewLib/src/ffmpeg/AVInputFormatWrapper.h @@ -43,6 +43,12 @@ class AVInputFormatWrapper AVInputFormatWrapper(); AVInputFormatWrapper(AVInputFormat *f, LibraryVersion v); + QString getName() const; + QString getLongName() const; + int getFlags() const; + QString getExtensions() const; + QString getMimeType() const; + explicit operator bool() const { return fmt != nullptr; }; private: diff --git a/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp b/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp index 4e34b631b..29e8bbcff 100644 --- a/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp +++ b/YUViewLib/src/filesource/FileSourceFFmpegFile.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -56,8 +57,18 @@ namespace auto startCode = QByteArrayLiteral("\x00\x00\x01"); +uint64_t getBoxSize(ByteVector::const_iterator iterator) +{ + uint64_t size = 0; + size += static_cast(*(iterator++)) << (8 * 3); + size += static_cast(*(iterator++)) << (8 * 2); + size += static_cast(*(iterator++)) << (8 * 1); + size += static_cast(*iterator); + return size; } +} // namespace + FileSourceFFmpegFile::FileSourceFFmpegFile() { connect(&this->fileWatcher, @@ -217,6 +228,38 @@ StringPairVec FileSourceFFmpegFile::getMetadata() return ff.getDictionaryEntries(this->formatCtx.getMetadata(), "", 0); } +ByteVector FileSourceFFmpegFile::getLhvCData() +{ + const auto inputFormat = this->formatCtx.getInputFormat(); + const auto isMp4 = inputFormat.getName().contains("mp4"); + if (!this->getVideoStreamCodecID().isHEVC() || !isMp4) + return {}; + + // This is a bit of a hack. The problem is that FFmpeg can currently not extract this for us. + // Maybe this will be added in the future. So the only option we have here is to manually extract + // the lhvC data from the mp4 file. + std::ifstream input(this->fileName.toStdString(), std::ios::binary); + const auto rawFileData = functions::readData(input, 1024); + if (rawFileData.empty()) + return {}; + + const std::string searchString = "lhvC"; + const auto lhvcPos = + std::search(rawFileData.begin(), rawFileData.end(), searchString.begin(), searchString.end()); + if (lhvcPos == rawFileData.end()) + return {}; + + if (std::distance(rawFileData.begin(), lhvcPos) < 4) + return {}; + + const auto boxSize = getBoxSize(lhvcPos - 4); + if (boxSize == 0 || boxSize > std::distance(lhvcPos, rawFileData.end())) + return {}; + + // We just return the payload without the box size or the "lhvC" tag + return ByteVector(lhvcPos + 4, lhvcPos + boxSize - 4); +} + QList FileSourceFFmpegFile::getParameterSets() { if (!this->isFileOpened) @@ -484,6 +527,7 @@ void FileSourceFFmpegFile::openFileAndFindVideoStream(QString fileName) if (!this->ff.openInput(this->formatCtx, fileName)) return; + this->fileName = fileName; this->formatCtx.getInputFormat(); for (unsigned idx = 0; idx < this->formatCtx.getNbStreams(); idx++) diff --git a/YUViewLib/src/filesource/FileSourceFFmpegFile.h b/YUViewLib/src/filesource/FileSourceFFmpegFile.h index 0505def37..acc51d4cd 100644 --- a/YUViewLib/src/filesource/FileSourceFFmpegFile.h +++ b/YUViewLib/src/filesource/FileSourceFFmpegFile.h @@ -35,6 +35,7 @@ #include "FileSource.h" #include #include +#include #include #include #include