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
This commit is contained in:
Martchus 2023-08-08 17:18:02 +02:00
parent f5497fb300
commit e6bb98d6e6
5 changed files with 76 additions and 8 deletions

View File

@ -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<std::string> 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<std::string> &AbstractContainer::muxingApplications() const
{
static const auto empty = std::vector<std::string>();
return m_p ? m_p->muxingApps : empty;
}
/*!
* \brief Returns the muxing applications specified as meta-data.
*/
std::vector<std::string> &AbstractContainer::muxingApplications()
{
return p()->muxingApps;
}
/*!
* \brief Returns the writing applications specified as meta-data.
*/
const std::vector<std::string> &AbstractContainer::writingApplications() const
{
static const auto empty = std::vector<std::string>();
return m_p ? m_p->writingApps : empty;
}
/*!
* \brief Returns the writing applications specified as meta-data.
*/
std::vector<std::string> &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<AbstractContainerPrivate> &AbstractContainer::p()
{
if (!m_p) {
m_p = std::make_unique<AbstractContainerPrivate>();
}
return m_p;
}
} // namespace TagParser

View File

@ -80,6 +80,8 @@ public:
const std::vector<std::string> &titles() const;
void setTitle(std::string_view title, std::size_t segmentIndex = 0);
virtual bool supportsTitle() const;
const std::vector<std::string> &muxingApplications() const;
const std::vector<std::string> &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<std::string> &muxingApplications();
std::vector<std::string> &writingApplications();
std::uint64_t m_version;
std::uint64_t m_readVersion;
@ -117,6 +121,8 @@ protected:
bool m_attachmentsParsed;
private:
std::unique_ptr<AbstractContainerPrivate> &p();
std::uint64_t m_startOffset;
std::iostream *m_stream;
CppUtilities::BinaryReader m_reader;

View File

@ -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<const MatroskaContainer *>(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<const MatroskaContainer *>(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

View File

@ -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,

View File

@ -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)
{