From e6bb98d6e6809d0e6ba3f4ebee3453b4939d915b Mon Sep 17 00:00:00 2001 From: Martchus Date: Tue, 8 Aug 2023 17:18:02 +0200 Subject: [PATCH] Improve dealing with muxing/writing application of Matroska files * Allow reading the current muxing/writing application * Allow to preserve the original muxing/writing application instead of always overriding --- abstractcontainer.cpp | 49 +++++++++++++++++++++++++++++++++- abstractcontainer.h | 6 +++++ matroska/matroskacontainer.cpp | 21 +++++++++++---- matroska/matroskaid.h | 2 +- mediafileinfo.h | 6 ++++- 5 files changed, 76 insertions(+), 8 deletions(-) diff --git a/abstractcontainer.cpp b/abstractcontainer.cpp index cbd2723..4a23a2d 100644 --- a/abstractcontainer.cpp +++ b/abstractcontainer.cpp @@ -7,7 +7,9 @@ using namespace CppUtilities; namespace TagParser { /// \brief The AbstractContainerPrivate struct contains private fields of the AbstractContainer class. -struct AbstractContainerPrivate {}; +struct AbstractContainerPrivate { + std::vector muxingApps, writingApps; +}; /*! * \class TagParser::AbstractContainer @@ -475,6 +477,40 @@ bool AbstractContainer::supportsTitle() const return false; } +/*! + * \brief Returns the muxing applications specified as meta-data. + */ +const std::vector &AbstractContainer::muxingApplications() const +{ + static const auto empty = std::vector(); + return m_p ? m_p->muxingApps : empty; +} + +/*! + * \brief Returns the muxing applications specified as meta-data. + */ +std::vector &AbstractContainer::muxingApplications() +{ + return p()->muxingApps; +} + +/*! + * \brief Returns the writing applications specified as meta-data. + */ +const std::vector &AbstractContainer::writingApplications() const +{ + static const auto empty = std::vector(); + return m_p ? m_p->writingApps : empty; +} + +/*! + * \brief Returns the writing applications specified as meta-data. + */ +std::vector &AbstractContainer::writingApplications() +{ + return p()->writingApps; +} + /*! * \brief Returns the number of segments. */ @@ -502,4 +538,15 @@ void AbstractContainer::reset() m_titles.clear(); } +/*! + * \brief Returns the private data for the container. + */ +std::unique_ptr &AbstractContainer::p() +{ + if (!m_p) { + m_p = std::make_unique(); + } + return m_p; +} + } // namespace TagParser diff --git a/abstractcontainer.h b/abstractcontainer.h index db7e5bf..d693668 100644 --- a/abstractcontainer.h +++ b/abstractcontainer.h @@ -80,6 +80,8 @@ public: const std::vector &titles() const; void setTitle(std::string_view title, std::size_t segmentIndex = 0); virtual bool supportsTitle() const; + const std::vector &muxingApplications() const; + const std::vector &writingApplications() const; virtual std::size_t segmentCount() const; CppUtilities::TimeSpan duration() const; CppUtilities::DateTime creationTime() const; @@ -97,6 +99,8 @@ protected: virtual void internalParseChapters(Diagnostics &diag, AbortableProgressFeedback &progress); virtual void internalParseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress); virtual void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress); + std::vector &muxingApplications(); + std::vector &writingApplications(); std::uint64_t m_version; std::uint64_t m_readVersion; @@ -117,6 +121,8 @@ protected: bool m_attachmentsParsed; private: + std::unique_ptr &p(); + std::uint64_t m_startOffset; std::iostream *m_stream; CppUtilities::BinaryReader m_reader; diff --git a/matroska/matroskacontainer.cpp b/matroska/matroskacontainer.cpp index 266bf3c..5b6697b 100644 --- a/matroska/matroskacontainer.cpp +++ b/matroska/matroskacontainer.cpp @@ -627,6 +627,12 @@ void MatroskaContainer::parseSegmentInfo(Diagnostics &diag) case MatroskaIds::TimeCodeScale: timeScale = subElement->readUInteger(); break; + case MatroskaIds::MuxingApp: + muxingApplications().emplace_back(subElement->readString()); + break; + case MatroskaIds::WrittingApp: + writingApplications().emplace_back(subElement->readString()); + break; } subElement = subElement->nextSibling(); } @@ -942,13 +948,18 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee const std::uint64_t ebmlHeaderSize = 4 + EbmlElement::calculateSizeDenotationLength(ebmlHeaderDataSize) + ebmlHeaderDataSize; // calculate size of "WritingLib"-element - constexpr std::string_view muxingAppName = APP_NAME " v" APP_VERSION; - constexpr std::uint64_t muxingAppElementTotalSize = 2 + 1 + muxingAppName.size(); + const auto &muxingApps = const_cast(this)->muxingApplications(); + const auto muxingAppName = (fileInfo().fileHandlingFlags() == MediaFileHandlingFlags::PreserveMuxingApplication && !muxingApps.empty()) + ? std::string_view(muxingApps.front()) + : std::string_view(APP_NAME " v" APP_VERSION); + const auto muxingAppElementTotalSize = std::uint64_t(2 + 1 + muxingAppName.size()); // calculate size of "WritingApp"-element - const std::uint64_t writingAppElementDataSize - = fileInfo().writingApplication().empty() ? muxingAppName.size() : fileInfo().writingApplication().size(); - const std::uint64_t writingAppElementTotalSize = 2 + 1 + writingAppElementDataSize; + const auto writingApps = const_cast(this)->writingApplications(); + const auto writingAppName = (fileInfo().fileHandlingFlags() == MediaFileHandlingFlags::PreserveWritingApplication && !writingApps.empty()) + ? std::string_view(writingApps.front()) + : std::string_view(fileInfo().writingApplication().empty() ? muxingAppName : std::string_view(fileInfo().writingApplication())); + const auto writingAppElementTotalSize = std::uint64_t(2 + 1 + writingAppName.size()); try { // calculate size of "Tags"-element diff --git a/matroska/matroskaid.h b/matroska/matroskaid.h index 4187a24..1dfd837 100644 --- a/matroska/matroskaid.h +++ b/matroska/matroskaid.h @@ -43,7 +43,7 @@ enum SeekIds { SeekID = 0x53AB, SeekPosition = 0x53AC }; enum SegmentInfoIds { TimeCodeScale = 0x2AD7B1, Duration = 0x4489, - WrittingApp = 0x5741, + WrittingApp = 0x5741, // TODOv13: change to WritingApp MuxingApp = 0x4D80, DateUTC = 0x4461, SegmentUID = 0x73A4, diff --git a/mediafileinfo.h b/mediafileinfo.h index a25f1d5..8c029bb 100644 --- a/mediafileinfo.h +++ b/mediafileinfo.h @@ -64,6 +64,8 @@ enum class MediaFileHandlingFlags : std::uint64_t { ForceIndexPosition = (1 << 3), /**< enforces the index position when applying changes, see remarks of MediaFileInfo::setIndexPosition() */ NormalizeKnownTagFieldIds = (1 << 4), /**< normalizes known tag field IDs when parsing to match the tag specification's recommendations */ PreserveRawTimingValues = (1 << 8), /**< preverves raw timing values (so far only used when making MP4 tracks) */ + PreserveMuxingApplication = (1 << 9), /**< preverves the muxing application (so far only used when making Matroska container) */ + PreserveWritingApplication = (1 << 10), /**< preverves the writing application (so far only used when making Matroska container) */ }; } // namespace TagParser @@ -471,7 +473,9 @@ inline const std::string &MediaFileInfo::writingApplication() const /*! * \brief Sets the writing application as container-level meta-data. Put the name of your application here. - * \remarks Might not be used (depends on the format). + * \remarks + * - Currently only used when making Matroska files. + * - The assigned value is ignored when MediaFileHandlingFlags::PreserveWritingApplication is set. */ inline void MediaFileInfo::setWritingApplication(std::string_view writingApplication) {