Add API to allow aborting overall/expensive parsing functions
* Not really implemented within the various code paths of the parsers at this point; this commit mainly adds the API. * Adjust example in README
This commit is contained in:
parent
763eb1bd53
commit
65597fd71e
71
README.md
71
README.md
|
@ -51,33 +51,74 @@ This example shows how to read and write tag fields in a format-independent way:
|
||||||
```
|
```
|
||||||
#include <tagparser/mediafileinfo.h>
|
#include <tagparser/mediafileinfo.h>
|
||||||
#include <tagparser/diagnostics.h>
|
#include <tagparser/diagnostics.h>
|
||||||
|
#include <tagparser/progressfeedback.h>
|
||||||
|
|
||||||
// create a MediaFileInfo for high-level access to overall functionality of the library
|
// create a MediaFileInfo for high-level access to overall functionality of the library
|
||||||
TagParser::MediaFileInfo fileInfo;
|
auto fileInfo = MediaFileInfo();
|
||||||
|
|
||||||
// create container for errors, warnings, etc.
|
// create container for errors, warnings, etc.
|
||||||
Diagnostics diag;
|
auto diag = Diagnostics();
|
||||||
|
|
||||||
|
// create handle to abort gracefully and get feedback during during long operations
|
||||||
|
auto progress = AbortableProgressFeedback([callback for status update], [callback for percentage-only updates]);
|
||||||
|
|
||||||
// open file (might throw ios_base::failure)
|
// open file (might throw ios_base::failure)
|
||||||
fileInfo.setPath("/path/to/some/file");
|
fileInfo.setPath("/path/to/some/file");
|
||||||
fileInfo.open();
|
fileInfo.open();
|
||||||
// parse tags
|
|
||||||
// (might throw exception derived from TagParser::Failure for fatal parsing error or ios_base::failure for IO errors)
|
|
||||||
fileInfo.parseTags(diag);
|
|
||||||
|
|
||||||
// get first tag as an object derived from the Tag class
|
// parse container format, tags, attachments and/or chapters as needed
|
||||||
|
// notes:
|
||||||
|
// - These functions might throw exceptions derived from ios_base::failure for IO errors and
|
||||||
|
// populate diag with possibly critical parsing messages you definitely want to check in production
|
||||||
|
// code.
|
||||||
|
// - Parsing a file can be expensive if the file is big or the disk IO is slow. You might want to
|
||||||
|
// run it in a separate thread.
|
||||||
|
// - At this point the parser does not make much use of the progress object.
|
||||||
|
fileInfo.parseContainerFormat(diag, progress);
|
||||||
|
fileInfo.parseTags(diag, progress);
|
||||||
|
fileInfo.parseAttachments(diag, progress);
|
||||||
|
fileInfo.parseChapters(diag, progress);
|
||||||
|
fileInfo.parseEverything(diag, progress); // just use that one if you want all over the above
|
||||||
|
|
||||||
|
// get tag as an object derived from the Tag class
|
||||||
|
// notes:
|
||||||
|
// - In real code you might want to check how many tags are assigned or use
|
||||||
|
// fileInfo.createAppropriateTags(…) to create tags as needed.
|
||||||
auto tag = fileInfo.tags().at(0);
|
auto tag = fileInfo.tags().at(0);
|
||||||
// extract title and convert it to UTF-8 std::string
|
|
||||||
// (toString() might throw ConversionException)
|
// extract a field value and convert it to UTF-8 std::string (toString() might throw ConversionException)
|
||||||
|
#include <tagparser/tag.h>
|
||||||
|
#include <tagparser/tagvalue.h>
|
||||||
auto title = tag->value(TagParser::KnownField::Title).toString(TagParser::TagTextEncoding::Utf8);
|
auto title = tag->value(TagParser::KnownField::Title).toString(TagParser::TagTextEncoding::Utf8);
|
||||||
|
|
||||||
// change album using an encoding suitable for the tag format
|
// change a field value using an encoding suitable for the tag format
|
||||||
tag->setValue(TagParser::KnownField::Album, TagParser::TagValue("some UTF-8 string", TagParser::TagTextEncoding::Utf8, tag->proposedTextEncoding()));
|
tag->setValue(KnownField::Album, TagValue("some UTF-8 string", TagTextEncoding::Utf8, tag->proposedTextEncoding()));
|
||||||
|
|
||||||
// create progress
|
// get/remove/create attachments
|
||||||
TagParser::AbortableProgressFeedback progress([callback for status update], [callback for percentage-only updates]);
|
#include <tagparser/abstractattachment.h>
|
||||||
|
if (auto *const container = fileInfo.container()) {
|
||||||
|
for (auto i = 0, count = container->attachmentCount(); i != count; ++i) {
|
||||||
|
auto attachment = container->attachment(i);
|
||||||
|
if (attachment->mimeType() == "image/jpeg") {
|
||||||
|
attachment->setIgnored(true); // remove existing attachment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create new attachment
|
||||||
|
auto attachment = container->createAttachment();
|
||||||
|
attachment->setName("cover.jpg");
|
||||||
|
attachment->setFile(cover, diag);
|
||||||
|
}
|
||||||
|
|
||||||
// apply changes to the file on disk
|
// apply changes to the file on disk
|
||||||
// (might throw exception derived from TagParser::Failure for fatal processing error or ios_base::failure for IO errors)
|
// notes:
|
||||||
|
// - Might throw exception derived from TagParser::Failure for fatal processing error or ios_base::failure
|
||||||
|
// for IO errors.
|
||||||
|
// - Applying changes can be expensive if the file is big or the disk IO is slow. You might want to
|
||||||
|
// run it in a separate thread.
|
||||||
|
// - Use progress.tryToAbort() from another thread or an interrupt handler to abort gracefully without leaving
|
||||||
|
// the file in an inconsistent state.
|
||||||
|
// - Be sure everyting has been parsed before as the library needs to be aware of the whole file structure.
|
||||||
|
fileInfo.parseEverything(diag, progress);
|
||||||
fileInfo.applyChanges(diag, progress);
|
fileInfo.applyChanges(diag, progress);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -87,8 +128,8 @@ fileInfo.applyChanges(diag, progress);
|
||||||
* Fatal processing errors are propagated by throwing a class derived from `TagParser::Failure`.
|
* Fatal processing errors are propagated by throwing a class derived from `TagParser::Failure`.
|
||||||
* All operations which might generate warnings, non-fatal errors, ... take a `TagParser::Diagnostics` object to store
|
* All operations which might generate warnings, non-fatal errors, ... take a `TagParser::Diagnostics` object to store
|
||||||
those messages.
|
those messages.
|
||||||
* All operations which can be aborted or provide progress feedback take a `TagParser::AbortableProgressFeedback` object
|
* All operations which might be aborted or might provide progress feedback take a `TagParser::AbortableProgressFeedback`
|
||||||
for callbacks and aborting.
|
object for callbacks and aborting.
|
||||||
* Field values are stored using `TagParser::TagValue` objects. Those objects erase the actual type similar to `QVariant`
|
* Field values are stored using `TagParser::TagValue` objects. Those objects erase the actual type similar to `QVariant`
|
||||||
from the Qt framework. The documentation of `TagParser::TagValue` covers how different types and encodings are
|
from the Qt framework. The documentation of `TagParser::TagValue` covers how different types and encodings are
|
||||||
handled.
|
handled.
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "./exceptions.h"
|
#include "./exceptions.h"
|
||||||
#include "./mediafileinfo.h"
|
#include "./mediafileinfo.h"
|
||||||
|
#include "./progressfeedback.h"
|
||||||
|
|
||||||
#include <c++utilities/io/copy.h>
|
#include <c++utilities/io/copy.h>
|
||||||
|
|
||||||
|
@ -100,12 +101,12 @@ void StreamDataBlock::copyTo(ostream &stream) const
|
||||||
*
|
*
|
||||||
* \throws Throws ios_base::failure when an IO error occurs.
|
* \throws Throws ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
FileDataBlock::FileDataBlock(std::string_view path, Diagnostics &diag)
|
FileDataBlock::FileDataBlock(std::string_view path, Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
: m_fileInfo(make_unique<MediaFileInfo>())
|
: m_fileInfo(make_unique<MediaFileInfo>())
|
||||||
{
|
{
|
||||||
m_fileInfo->setPath(path);
|
m_fileInfo->setPath(path);
|
||||||
m_fileInfo->open(true);
|
m_fileInfo->open(true);
|
||||||
m_fileInfo->parseContainerFormat(diag);
|
m_fileInfo->parseContainerFormat(diag, progress);
|
||||||
m_startOffset = 0;
|
m_startOffset = 0;
|
||||||
m_endOffset = m_fileInfo->size();
|
m_endOffset = m_fileInfo->size();
|
||||||
m_stream = [this]() -> std::istream & { return this->m_fileInfo->stream(); };
|
m_stream = [this]() -> std::istream & { return this->m_fileInfo->stream(); };
|
||||||
|
@ -167,10 +168,10 @@ void AbstractAttachment::clear()
|
||||||
*
|
*
|
||||||
* When such an exception is thrown, the attachment remains unchanged.
|
* When such an exception is thrown, the attachment remains unchanged.
|
||||||
*/
|
*/
|
||||||
void AbstractAttachment::setFile(string_view path, Diagnostics &diag)
|
void AbstractAttachment::setFile(string_view path, Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
m_data.reset();
|
m_data.reset();
|
||||||
auto file = make_unique<FileDataBlock>(path, diag);
|
auto file = make_unique<FileDataBlock>(path, diag, progress);
|
||||||
const auto fileName = file->fileInfo()->fileName();
|
const auto fileName = file->fileInfo()->fileName();
|
||||||
if (!fileName.empty()) {
|
if (!fileName.empty()) {
|
||||||
m_name = fileName;
|
m_name = fileName;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
namespace TagParser {
|
namespace TagParser {
|
||||||
|
|
||||||
|
class AbortableProgressFeedback;
|
||||||
class MediaFileInfo;
|
class MediaFileInfo;
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT StreamDataBlock {
|
class TAG_PARSER_EXPORT StreamDataBlock {
|
||||||
|
@ -89,7 +90,7 @@ inline void StreamDataBlock::discardBuffer()
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT FileDataBlock : public StreamDataBlock {
|
class TAG_PARSER_EXPORT FileDataBlock : public StreamDataBlock {
|
||||||
public:
|
public:
|
||||||
FileDataBlock(std::string_view path, Diagnostics &diag);
|
FileDataBlock(std::string_view path, Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
~FileDataBlock();
|
~FileDataBlock();
|
||||||
const MediaFileInfo *fileInfo() const;
|
const MediaFileInfo *fileInfo() const;
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ public:
|
||||||
void setId(std::uint64_t id);
|
void setId(std::uint64_t id);
|
||||||
const StreamDataBlock *data() const;
|
const StreamDataBlock *data() const;
|
||||||
void setData(std::unique_ptr<StreamDataBlock> &&data);
|
void setData(std::unique_ptr<StreamDataBlock> &&data);
|
||||||
void setFile(std::string_view path, Diagnostics &diag);
|
void setFile(std::string_view path, Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
bool isDataFromFile() const;
|
bool isDataFromFile() const;
|
||||||
std::string label() const;
|
std::string label() const;
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "./abstractchapter.h"
|
#include "./abstractchapter.h"
|
||||||
|
#include "./progressfeedback.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -67,10 +68,10 @@ void AbstractChapter::clear()
|
||||||
*
|
*
|
||||||
* Clears all previous parsing results.
|
* Clears all previous parsing results.
|
||||||
*/
|
*/
|
||||||
void AbstractChapter::parse(Diagnostics &diag)
|
void AbstractChapter::parse(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
internalParse(diag);
|
internalParse(diag, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -78,12 +79,13 @@ void AbstractChapter::parse(Diagnostics &diag)
|
||||||
*
|
*
|
||||||
* Clears all previous parsing results.
|
* Clears all previous parsing results.
|
||||||
*/
|
*/
|
||||||
void AbstractChapter::parseNested(Diagnostics &diag)
|
void AbstractChapter::parseNested(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
progress.stopIfAborted();
|
||||||
clear();
|
clear();
|
||||||
internalParse(diag);
|
internalParse(diag, progress);
|
||||||
for (size_t i = 0, count = nestedChapterCount(); i < count; ++i) {
|
for (size_t i = 0, count = nestedChapterCount(); i < count; ++i) {
|
||||||
nestedChapter(i)->parseNested(diag);
|
nestedChapter(i)->parseNested(diag, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
namespace TagParser {
|
namespace TagParser {
|
||||||
|
|
||||||
|
class AbortableProgressFeedback;
|
||||||
class Diagnostics;
|
class Diagnostics;
|
||||||
|
|
||||||
class TAG_PARSER_EXPORT AbstractChapter {
|
class TAG_PARSER_EXPORT AbstractChapter {
|
||||||
|
@ -28,12 +29,12 @@ public:
|
||||||
virtual const AbstractChapter *nestedChapter(std::size_t index) const;
|
virtual const AbstractChapter *nestedChapter(std::size_t index) const;
|
||||||
virtual std::size_t nestedChapterCount() const;
|
virtual std::size_t nestedChapterCount() const;
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
void parse(Diagnostics &diag);
|
void parse(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseNested(Diagnostics &diag);
|
void parseNested(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractChapter();
|
AbstractChapter();
|
||||||
virtual void internalParse(Diagnostics &diag) = 0;
|
virtual void internalParse(Diagnostics &diag, AbortableProgressFeedback &progress) = 0;
|
||||||
|
|
||||||
std::uint64_t m_id;
|
std::uint64_t m_id;
|
||||||
std::vector<LocaleAwareString> m_names;
|
std::vector<LocaleAwareString> m_names;
|
||||||
|
|
|
@ -52,12 +52,12 @@ AbstractContainer::~AbstractContainer()
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws Failure or a derived class when an parsing error occurs.
|
* \throws Throws Failure or a derived class when an parsing error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::parseHeader(Diagnostics &diag)
|
void AbstractContainer::parseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if (!isHeaderParsed()) {
|
if (!isHeaderParsed()) {
|
||||||
removeAllTags();
|
removeAllTags();
|
||||||
removeAllTracks();
|
removeAllTracks();
|
||||||
internalParseHeader(diag);
|
internalParseHeader(diag, progress);
|
||||||
m_headerParsed = true;
|
m_headerParsed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,11 @@ void AbstractContainer::parseHeader(Diagnostics &diag)
|
||||||
* \sa parseChapters()
|
* \sa parseChapters()
|
||||||
* \sa tags()
|
* \sa tags()
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::parseTags(Diagnostics &diag)
|
void AbstractContainer::parseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if (!areTagsParsed()) {
|
if (!areTagsParsed()) {
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
internalParseTags(diag);
|
internalParseTags(diag, progress);
|
||||||
m_tagsParsed = true;
|
m_tagsParsed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ void AbstractContainer::parseTags(Diagnostics &diag)
|
||||||
* \sa parseTags()
|
* \sa parseTags()
|
||||||
* \sa tracks()
|
* \sa tracks()
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::parseTracks(Diagnostics &diag)
|
void AbstractContainer::parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if (!areTracksParsed()) {
|
if (!areTracksParsed()) {
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
internalParseTracks(diag);
|
internalParseTracks(diag, progress);
|
||||||
m_tracksParsed = true;
|
m_tracksParsed = true;
|
||||||
m_tracksAltered = false;
|
m_tracksAltered = false;
|
||||||
}
|
}
|
||||||
|
@ -123,11 +123,11 @@ void AbstractContainer::parseTracks(Diagnostics &diag)
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::parseChapters(Diagnostics &diag)
|
void AbstractContainer::parseChapters(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if (!areChaptersParsed()) {
|
if (!areChaptersParsed()) {
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
internalParseChapters(diag);
|
internalParseChapters(diag, progress);
|
||||||
m_chaptersParsed = true;
|
m_chaptersParsed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,11 +142,11 @@ void AbstractContainer::parseChapters(Diagnostics &diag)
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::parseAttachments(Diagnostics &diag)
|
void AbstractContainer::parseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
if (!areAttachmentsParsed()) {
|
if (!areAttachmentsParsed()) {
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
internalParseAttachments(diag);
|
internalParseAttachments(diag, progress);
|
||||||
m_attachmentsParsed = true;
|
m_attachmentsParsed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,9 +194,10 @@ ElementPosition AbstractContainer::determineIndexPosition(Diagnostics &diag) con
|
||||||
* \throws Throws Failure or a derived class when a parsing error occurs.
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::internalParseHeader(Diagnostics &diag)
|
void AbstractContainer::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag);
|
CPP_UTILITIES_UNUSED(diag);
|
||||||
|
CPP_UTILITIES_UNUSED(progress);
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,9 +209,10 @@ void AbstractContainer::internalParseHeader(Diagnostics &diag)
|
||||||
* \throws Throws Failure or a derived class when a parsing error occurs.
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::internalParseTags(Diagnostics &diag)
|
void AbstractContainer::internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag);
|
CPP_UTILITIES_UNUSED(diag);
|
||||||
|
CPP_UTILITIES_UNUSED(progress);
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +224,10 @@ void AbstractContainer::internalParseTags(Diagnostics &diag)
|
||||||
* \throws Throws Failure or a derived class when a parsing error occurs.
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::internalParseTracks(Diagnostics &diag)
|
void AbstractContainer::internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag);
|
CPP_UTILITIES_UNUSED(diag);
|
||||||
|
CPP_UTILITIES_UNUSED(progress);
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,9 +239,10 @@ void AbstractContainer::internalParseTracks(Diagnostics &diag)
|
||||||
* \throws Throws Failure or a derived class when a parsing error occurs.
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::internalParseChapters(Diagnostics &diag)
|
void AbstractContainer::internalParseChapters(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag);
|
CPP_UTILITIES_UNUSED(diag);
|
||||||
|
CPP_UTILITIES_UNUSED(progress);
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,9 +254,10 @@ void AbstractContainer::internalParseChapters(Diagnostics &diag)
|
||||||
* \throws Throws Failure or a derived class when a parsing error occurs.
|
* \throws Throws Failure or a derived class when a parsing error occurs.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractContainer::internalParseAttachments(Diagnostics &diag)
|
void AbstractContainer::internalParseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag);
|
CPP_UTILITIES_UNUSED(diag);
|
||||||
|
CPP_UTILITIES_UNUSED(progress);
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,11 +36,11 @@ public:
|
||||||
CppUtilities::BinaryReader &reader();
|
CppUtilities::BinaryReader &reader();
|
||||||
CppUtilities::BinaryWriter &writer();
|
CppUtilities::BinaryWriter &writer();
|
||||||
|
|
||||||
void parseHeader(Diagnostics &diag);
|
void parseHeader(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseTags(Diagnostics &diag);
|
void parseTags(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseTracks(Diagnostics &diag);
|
void parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseChapters(Diagnostics &diag);
|
void parseChapters(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseAttachments(Diagnostics &diag);
|
void parseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void makeFile(Diagnostics &diag, AbortableProgressFeedback &progress);
|
void makeFile(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
|
|
||||||
bool isHeaderParsed() const;
|
bool isHeaderParsed() const;
|
||||||
|
@ -89,11 +89,11 @@ public:
|
||||||
protected:
|
protected:
|
||||||
AbstractContainer(std::iostream &stream, std::uint64_t startOffset);
|
AbstractContainer(std::iostream &stream, std::uint64_t startOffset);
|
||||||
|
|
||||||
virtual void internalParseHeader(Diagnostics &diag);
|
virtual void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
virtual void internalParseTags(Diagnostics &diag);
|
virtual void internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
virtual void internalParseTracks(Diagnostics &diag);
|
virtual void internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
virtual void internalParseChapters(Diagnostics &diag);
|
virtual void internalParseChapters(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
virtual void internalParseAttachments(Diagnostics &diag);
|
virtual void internalParseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
virtual void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress);
|
virtual void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
|
|
||||||
std::uint64_t m_version;
|
std::uint64_t m_version;
|
||||||
|
|
|
@ -232,12 +232,12 @@ string AbstractTrack::shortDescription() const
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*/
|
*/
|
||||||
void AbstractTrack::parseHeader(Diagnostics &diag)
|
void AbstractTrack::parseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
m_flags -= TrackFlags::HeaderValid;
|
m_flags -= TrackFlags::HeaderValid;
|
||||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||||
try {
|
try {
|
||||||
internalParseHeader(diag);
|
internalParseHeader(diag, progress);
|
||||||
m_flags += TrackFlags::HeaderValid;
|
m_flags += TrackFlags::HeaderValid;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
namespace TagParser {
|
namespace TagParser {
|
||||||
|
|
||||||
|
class AbortableProgressFeedback;
|
||||||
class MpegAudioFrameStream;
|
class MpegAudioFrameStream;
|
||||||
class WaveAudioStream;
|
class WaveAudioStream;
|
||||||
class Mp4Track;
|
class Mp4Track;
|
||||||
|
@ -134,13 +135,13 @@ public:
|
||||||
std::string description() const;
|
std::string description() const;
|
||||||
std::string shortDescription() const;
|
std::string shortDescription() const;
|
||||||
|
|
||||||
void parseHeader(Diagnostics &diag);
|
void parseHeader(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
bool isHeaderValid() const;
|
bool isHeaderValid() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AbstractTrack(std::istream &inputStream, std::ostream &outputStream, std::uint64_t startOffset);
|
AbstractTrack(std::istream &inputStream, std::ostream &outputStream, std::uint64_t startOffset);
|
||||||
AbstractTrack(std::iostream &stream, std::uint64_t startOffset);
|
AbstractTrack(std::iostream &stream, std::uint64_t startOffset);
|
||||||
virtual void internalParseHeader(Diagnostics &diag) = 0;
|
virtual void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) = 0;
|
||||||
|
|
||||||
std::istream *m_istream;
|
std::istream *m_istream;
|
||||||
std::ostream *m_ostream;
|
std::ostream *m_ostream;
|
||||||
|
|
|
@ -15,9 +15,10 @@ namespace TagParser {
|
||||||
* \brief Implementation of TagParser::AbstractTrack for ADTS streams.
|
* \brief Implementation of TagParser::AbstractTrack for ADTS streams.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void AdtsStream::internalParseHeader(Diagnostics &diag)
|
void AdtsStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
CPP_UTILITIES_UNUSED(diag)
|
CPP_UTILITIES_UNUSED(diag)
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
//static const string context("parsing ADTS frame header");
|
//static const string context("parsing ADTS frame header");
|
||||||
if (!m_istream) {
|
if (!m_istream) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
TrackType type() const override;
|
TrackType type() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AdtsFrame m_firstFrame;
|
AdtsFrame m_firstFrame;
|
||||||
|
|
|
@ -62,8 +62,10 @@ bool FlacStream::removeVorbisComment()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlacStream::internalParseHeader(Diagnostics &diag)
|
void FlacStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing raw FLAC header");
|
static const string context("parsing raw FLAC header");
|
||||||
if (!m_istream) {
|
if (!m_istream) {
|
||||||
throw NoDataFoundException();
|
throw NoDataFoundException();
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
static void makePadding(std::ostream &stream, std::uint32_t size, bool isLast, Diagnostics &diag);
|
static void makePadding(std::ostream &stream, std::uint32_t size, bool isLast, Diagnostics &diag);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MediaFileInfo &m_mediaFileInfo;
|
MediaFileInfo &m_mediaFileInfo;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
GenericContainer(FileInfoType &fileInfo, std::uint64_t startOffset);
|
GenericContainer(FileInfoType &fileInfo, std::uint64_t startOffset);
|
||||||
~GenericContainer() override;
|
~GenericContainer() override;
|
||||||
|
|
||||||
void validateElementStructure(Diagnostics &diag, std::uint64_t *paddingSize = nullptr);
|
void validateElementStructure(Diagnostics &diag, AbortableProgressFeedback &progress, std::uint64_t *paddingSize = nullptr);
|
||||||
FileInfoType &fileInfo() const;
|
FileInfoType &fileInfo() const;
|
||||||
ElementType *firstElement() const;
|
ElementType *firstElement() const;
|
||||||
const std::vector<std::unique_ptr<ElementType>> &additionalElements() const;
|
const std::vector<std::unique_ptr<ElementType>> &additionalElements() const;
|
||||||
|
@ -96,11 +96,12 @@ GenericContainer<FileInfoType, TagType, TrackType, ElementType>::~GenericContain
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
*/
|
*/
|
||||||
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
template <class FileInfoType, class TagType, class TrackType, class ElementType>
|
||||||
inline void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::validateElementStructure(Diagnostics &diag, std::uint64_t *paddingSize)
|
inline void GenericContainer<FileInfoType, TagType, TrackType, ElementType>::validateElementStructure(
|
||||||
|
Diagnostics &diag, AbortableProgressFeedback &progress, std::uint64_t *paddingSize)
|
||||||
{
|
{
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
if (m_firstElement) {
|
if (m_firstElement) {
|
||||||
m_firstElement->validateSubsequentElementStructure(diag, paddingSize);
|
m_firstElement->validateSubsequentElementStructure(diag, paddingSize, &progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ public:
|
||||||
void clear();
|
void clear();
|
||||||
void parse(Diagnostics &diag);
|
void parse(Diagnostics &diag);
|
||||||
void reparse(Diagnostics &diag);
|
void reparse(Diagnostics &diag);
|
||||||
void validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize = nullptr);
|
void validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize = nullptr, AbortableProgressFeedback *progress = nullptr);
|
||||||
static constexpr std::uint32_t maximumIdLengthSupported();
|
static constexpr std::uint32_t maximumIdLengthSupported();
|
||||||
static constexpr std::uint32_t maximumSizeLengthSupported();
|
static constexpr std::uint32_t maximumSizeLengthSupported();
|
||||||
static constexpr std::uint8_t minimumElementSize();
|
static constexpr std::uint8_t minimumElementSize();
|
||||||
|
@ -812,14 +812,18 @@ template <class ImplementationType> void GenericFileElement<ImplementationType>:
|
||||||
* \sa parse()
|
* \sa parse()
|
||||||
*/
|
*/
|
||||||
template <class ImplementationType>
|
template <class ImplementationType>
|
||||||
void GenericFileElement<ImplementationType>::validateSubsequentElementStructure(Diagnostics &diag, std::uint64_t *paddingSize)
|
void GenericFileElement<ImplementationType>::validateSubsequentElementStructure(
|
||||||
|
Diagnostics &diag, std::uint64_t *paddingSize, AbortableProgressFeedback *progress)
|
||||||
{
|
{
|
||||||
|
if (progress) {
|
||||||
|
progress->stopIfAborted();
|
||||||
|
}
|
||||||
// validate element itself by just parsing it
|
// validate element itself by just parsing it
|
||||||
parse(diag);
|
parse(diag);
|
||||||
// validate children
|
// validate children
|
||||||
if (firstChild()) {
|
if (firstChild()) {
|
||||||
try {
|
try {
|
||||||
firstChild()->validateSubsequentElementStructure(diag, paddingSize);
|
firstChild()->validateSubsequentElementStructure(diag, paddingSize, progress);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
// ignore critical errors in child structure to continue validating siblings
|
// ignore critical errors in child structure to continue validating siblings
|
||||||
// (critical notifications about the errors should have already been added to diag, so nothing to do)
|
// (critical notifications about the errors should have already been added to diag, so nothing to do)
|
||||||
|
@ -829,7 +833,7 @@ void GenericFileElement<ImplementationType>::validateSubsequentElementStructure(
|
||||||
}
|
}
|
||||||
// validate siblings
|
// validate siblings
|
||||||
if (nextSibling()) {
|
if (nextSibling()) {
|
||||||
nextSibling()->validateSubsequentElementStructure(diag, paddingSize);
|
nextSibling()->validateSubsequentElementStructure(diag, paddingSize, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,10 @@ namespace TagParser {
|
||||||
* \sa https://wiki.multimedia.cx/index.php/IVF
|
* \sa https://wiki.multimedia.cx/index.php/IVF
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void IvfStream::internalParseHeader(Diagnostics &diag)
|
void IvfStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing IVF header");
|
static const string context("parsing IVF header");
|
||||||
if (!m_istream) {
|
if (!m_istream) {
|
||||||
throw NoDataFoundException();
|
throw NoDataFoundException();
|
||||||
|
|
|
@ -17,7 +17,7 @@ public:
|
||||||
void readFrame(Diagnostics &diag);
|
void readFrame(Diagnostics &diag);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<IvfFrame> m_frames;
|
std::vector<IvfFrame> m_frames;
|
||||||
|
|
|
@ -39,8 +39,10 @@ MatroskaChapter::~MatroskaChapter()
|
||||||
* - Fetches nested chapters but does not parse them.
|
* - Fetches nested chapters but does not parse them.
|
||||||
* - Clears all previous parsing results.
|
* - Clears all previous parsing results.
|
||||||
*/
|
*/
|
||||||
void MatroskaChapter::internalParse(Diagnostics &diag)
|
void MatroskaChapter::internalParse(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
// clear previous values and status
|
// clear previous values and status
|
||||||
static const string context("parsing \"ChapterAtom\"-element");
|
static const string context("parsing \"ChapterAtom\"-element");
|
||||||
clear();
|
clear();
|
||||||
|
|
|
@ -20,7 +20,7 @@ public:
|
||||||
void clear() override;
|
void clear() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParse(Diagnostics &diag) override;
|
void internalParse(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EbmlElement *m_chapterAtomElement;
|
EbmlElement *m_chapterAtomElement;
|
||||||
|
|
|
@ -82,7 +82,7 @@ void MatroskaContainer::reset()
|
||||||
* \brief Validates the file index (cue entries).
|
* \brief Validates the file index (cue entries).
|
||||||
* \remarks Checks only for cluster positions and missing, unknown or surplus elements.
|
* \remarks Checks only for cluster positions and missing, unknown or surplus elements.
|
||||||
*/
|
*/
|
||||||
void MatroskaContainer::validateIndex(Diagnostics &diag)
|
void MatroskaContainer::validateIndex(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
static const string context("validating Matroska file index (cues)");
|
static const string context("validating Matroska file index (cues)");
|
||||||
bool cuesElementsFound = false;
|
bool cuesElementsFound = false;
|
||||||
|
@ -98,6 +98,7 @@ void MatroskaContainer::validateIndex(Diagnostics &diag)
|
||||||
// iterate throught all child elements of the segment (only "Cues"- and "Cluster"-elements are relevant for this method)
|
// iterate throught all child elements of the segment (only "Cues"- and "Cluster"-elements are relevant for this method)
|
||||||
for (EbmlElement *segmentChildElement = segmentElement->firstChild(); segmentChildElement;
|
for (EbmlElement *segmentChildElement = segmentElement->firstChild(); segmentChildElement;
|
||||||
segmentChildElement = segmentChildElement->nextSibling()) {
|
segmentChildElement = segmentChildElement->nextSibling()) {
|
||||||
|
progress.stopIfAborted();
|
||||||
segmentChildElement->parse(diag);
|
segmentChildElement->parse(diag);
|
||||||
switch (segmentChildElement->id()) {
|
switch (segmentChildElement->id()) {
|
||||||
case EbmlIds::Void:
|
case EbmlIds::Void:
|
||||||
|
@ -108,6 +109,7 @@ void MatroskaContainer::validateIndex(Diagnostics &diag)
|
||||||
// parse children of "Cues"-element ("CuePoint"-elements)
|
// parse children of "Cues"-element ("CuePoint"-elements)
|
||||||
for (EbmlElement *cuePointElement = segmentChildElement->firstChild(); cuePointElement;
|
for (EbmlElement *cuePointElement = segmentChildElement->firstChild(); cuePointElement;
|
||||||
cuePointElement = cuePointElement->nextSibling()) {
|
cuePointElement = cuePointElement->nextSibling()) {
|
||||||
|
progress.stopIfAborted();
|
||||||
cuePointElement->parse(diag);
|
cuePointElement->parse(diag);
|
||||||
cueTimeFound = cueTrackPositionsFound = false; // to validate quantity of these elements
|
cueTimeFound = cueTrackPositionsFound = false; // to validate quantity of these elements
|
||||||
switch (cuePointElement->id()) {
|
switch (cuePointElement->id()) {
|
||||||
|
@ -398,8 +400,10 @@ ElementPosition MatroskaContainer::determineIndexPosition(Diagnostics &diag) con
|
||||||
return determineElementPosition(MatroskaIds::Cues, diag);
|
return determineElementPosition(MatroskaIds::Cues, diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaContainer::internalParseHeader(Diagnostics &diag)
|
void MatroskaContainer::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing header of Matroska container");
|
static const string context("parsing header of Matroska container");
|
||||||
// reset old results
|
// reset old results
|
||||||
m_firstElement = make_unique<EbmlElement>(*this, startOffset());
|
m_firstElement = make_unique<EbmlElement>(*this, startOffset());
|
||||||
|
@ -654,8 +658,10 @@ void MatroskaContainer::readTrackStatisticsFromTags(Diagnostics &diag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaContainer::internalParseTags(Diagnostics &diag)
|
void MatroskaContainer::internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing tags of Matroska container");
|
static const string context("parsing tags of Matroska container");
|
||||||
for (EbmlElement *element : m_tagsElements) {
|
for (EbmlElement *element : m_tagsElements) {
|
||||||
try {
|
try {
|
||||||
|
@ -689,7 +695,7 @@ void MatroskaContainer::internalParseTags(Diagnostics &diag)
|
||||||
readTrackStatisticsFromTags(diag);
|
readTrackStatisticsFromTags(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaContainer::internalParseTracks(Diagnostics &diag)
|
void MatroskaContainer::internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
static const string context("parsing tracks of Matroska container");
|
static const string context("parsing tracks of Matroska container");
|
||||||
for (EbmlElement *element : m_tracksElements) {
|
for (EbmlElement *element : m_tracksElements) {
|
||||||
|
@ -701,7 +707,7 @@ void MatroskaContainer::internalParseTracks(Diagnostics &diag)
|
||||||
case MatroskaIds::TrackEntry:
|
case MatroskaIds::TrackEntry:
|
||||||
m_tracks.emplace_back(make_unique<MatroskaTrack>(*subElement));
|
m_tracks.emplace_back(make_unique<MatroskaTrack>(*subElement));
|
||||||
try {
|
try {
|
||||||
m_tracks.back()->parseHeader(diag);
|
m_tracks.back()->parseHeader(diag, progress);
|
||||||
} catch (const NoDataFoundException &) {
|
} catch (const NoDataFoundException &) {
|
||||||
m_tracks.pop_back();
|
m_tracks.pop_back();
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
|
@ -725,7 +731,7 @@ void MatroskaContainer::internalParseTracks(Diagnostics &diag)
|
||||||
readTrackStatisticsFromTags(diag);
|
readTrackStatisticsFromTags(diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaContainer::internalParseChapters(Diagnostics &diag)
|
void MatroskaContainer::internalParseChapters(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
static const string context("parsing editions/chapters of Matroska container");
|
static const string context("parsing editions/chapters of Matroska container");
|
||||||
for (EbmlElement *element : m_chaptersElements) {
|
for (EbmlElement *element : m_chaptersElements) {
|
||||||
|
@ -737,7 +743,7 @@ void MatroskaContainer::internalParseChapters(Diagnostics &diag)
|
||||||
case MatroskaIds::EditionEntry:
|
case MatroskaIds::EditionEntry:
|
||||||
m_editionEntries.emplace_back(make_unique<MatroskaEditionEntry>(subElement));
|
m_editionEntries.emplace_back(make_unique<MatroskaEditionEntry>(subElement));
|
||||||
try {
|
try {
|
||||||
m_editionEntries.back()->parseNested(diag);
|
m_editionEntries.back()->parseNested(diag, progress);
|
||||||
} catch (const NoDataFoundException &) {
|
} catch (const NoDataFoundException &) {
|
||||||
m_editionEntries.pop_back();
|
m_editionEntries.pop_back();
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
|
@ -759,8 +765,10 @@ void MatroskaContainer::internalParseChapters(Diagnostics &diag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaContainer::internalParseAttachments(Diagnostics &diag)
|
void MatroskaContainer::internalParseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing attachments of Matroska container");
|
static const string context("parsing attachments of Matroska container");
|
||||||
for (EbmlElement *element : m_attachmentsElements) {
|
for (EbmlElement *element : m_attachmentsElements) {
|
||||||
try {
|
try {
|
||||||
|
@ -1839,7 +1847,9 @@ void MatroskaContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFee
|
||||||
}
|
}
|
||||||
reset();
|
reset();
|
||||||
try {
|
try {
|
||||||
parseHeader(diag);
|
parseHeader(diag, progress);
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
throw;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to reparse the header of the new file.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to reparse the header of the new file.", context);
|
||||||
throw;
|
throw;
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
MatroskaContainer(MediaFileInfo &stream, std::uint64_t startOffset);
|
MatroskaContainer(MediaFileInfo &stream, std::uint64_t startOffset);
|
||||||
~MatroskaContainer() override;
|
~MatroskaContainer() override;
|
||||||
|
|
||||||
void validateIndex(Diagnostics &diag);
|
void validateIndex(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
std::uint64_t maxIdLength() const;
|
std::uint64_t maxIdLength() const;
|
||||||
std::uint64_t maxSizeLength() const;
|
std::uint64_t maxSizeLength() const;
|
||||||
const std::vector<std::unique_ptr<MatroskaSeekInfo>> &seekInfos() const;
|
const std::vector<std::unique_ptr<MatroskaSeekInfo>> &seekInfos() const;
|
||||||
|
@ -49,11 +49,11 @@ public:
|
||||||
void reset() override;
|
void reset() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTags(Diagnostics &diag) override;
|
void internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTracks(Diagnostics &diag) override;
|
void internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseChapters(Diagnostics &diag) override;
|
void internalParseChapters(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseAttachments(Diagnostics &diag) override;
|
void internalParseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -93,11 +93,12 @@ void MatroskaEditionEntry::parse(Diagnostics &diag)
|
||||||
* - Parses also fetched chapters and nested chapters.
|
* - Parses also fetched chapters and nested chapters.
|
||||||
* - Clears all previous parsing results.
|
* - Clears all previous parsing results.
|
||||||
*/
|
*/
|
||||||
void MatroskaEditionEntry::parseNested(Diagnostics &diag)
|
void MatroskaEditionEntry::parseNested(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
progress.stopIfAborted();
|
||||||
parse(diag);
|
parse(diag);
|
||||||
for (auto &chapter : chapters()) {
|
for (auto &chapter : chapters()) {
|
||||||
chapter->parseNested(diag);
|
chapter->parseNested(diag, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
const std::vector<std::unique_ptr<MatroskaChapter>> &chapters() const;
|
const std::vector<std::unique_ptr<MatroskaChapter>> &chapters() const;
|
||||||
|
|
||||||
void parse(Diagnostics &diag);
|
void parse(Diagnostics &diag);
|
||||||
void parseNested(Diagnostics &diag);
|
void parseNested(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -283,8 +283,10 @@ void MatroskaTrack::readStatisticsFromTags(const std::vector<std::unique_ptr<Mat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MatroskaTrack::internalParseHeader(Diagnostics &diag)
|
void MatroskaTrack::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing header of Matroska track");
|
static const string context("parsing header of Matroska track");
|
||||||
try {
|
try {
|
||||||
m_trackElement->parse(diag);
|
m_trackElement->parse(diag);
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
void makeHeader(std::ostream &stream, Diagnostics &diag) const;
|
void makeHeader(std::ostream &stream, Diagnostics &diag) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename PropertyType, typename ConversionFunction>
|
template <typename PropertyType, typename ConversionFunction>
|
||||||
|
|
|
@ -144,12 +144,12 @@ MediaFileInfo::~MediaFileInfo()
|
||||||
* container(), mp4Container() and matroskaContainer() will return the parsed
|
* container(), mp4Container() and matroskaContainer() will return the parsed
|
||||||
* information.
|
* information.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
|
||||||
* error occurs.
|
|
||||||
* \sa isContainerParsed(), parseTracks(), parseTag(), parseChapters(), parseEverything()
|
* \sa isContainerParsed(), parseTracks(), parseTag(), parseChapters(), parseEverything()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseContainerFormat(Diagnostics &diag)
|
void MediaFileInfo::parseContainerFormat(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
// skip if container format already parsed
|
// skip if container format already parsed
|
||||||
if (containerParsingStatus() != ParsingStatus::NotParsedYet) {
|
if (containerParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||||
return;
|
return;
|
||||||
|
@ -168,6 +168,10 @@ void MediaFileInfo::parseContainerFormat(Diagnostics &diag)
|
||||||
char buff[16];
|
char buff[16];
|
||||||
const char *const buffEnd = buff + sizeof(buff), *buffOffset;
|
const char *const buffEnd = buff + sizeof(buff), *buffOffset;
|
||||||
startParsingSignature:
|
startParsingSignature:
|
||||||
|
if (progress.isAborted()) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Parsing the container format has been aborted.", context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (size() - containerOffset() >= 16) {
|
if (size() - containerOffset() >= 16) {
|
||||||
stream().seekg(m_containerOffset, ios_base::beg);
|
stream().seekg(m_containerOffset, ios_base::beg);
|
||||||
stream().read(buff, sizeof(buff));
|
stream().read(buff, sizeof(buff));
|
||||||
|
@ -224,7 +228,9 @@ startParsingSignature:
|
||||||
// MP4/QuickTime is handled using Mp4Container instance
|
// MP4/QuickTime is handled using Mp4Container instance
|
||||||
m_container = make_unique<Mp4Container>(*this, m_containerOffset);
|
m_container = make_unique<Mp4Container>(*this, m_containerOffset);
|
||||||
try {
|
try {
|
||||||
static_cast<Mp4Container *>(m_container.get())->validateElementStructure(diag, &m_paddingSize);
|
static_cast<Mp4Container *>(m_container.get())->validateElementStructure(diag, progress, &m_paddingSize);
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Validating the MP4 element structure has been aborted.", context);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
m_containerParsingStatus = ParsingStatus::CriticalFailure;
|
m_containerParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
}
|
}
|
||||||
|
@ -234,7 +240,7 @@ startParsingSignature:
|
||||||
// EBML/Matroska is handled using MatroskaContainer instance
|
// EBML/Matroska is handled using MatroskaContainer instance
|
||||||
auto container = make_unique<MatroskaContainer>(*this, m_containerOffset);
|
auto container = make_unique<MatroskaContainer>(*this, m_containerOffset);
|
||||||
try {
|
try {
|
||||||
container->parseHeader(diag);
|
container->parseHeader(diag, progress);
|
||||||
if (container->documentType() == "matroska") {
|
if (container->documentType() == "matroska") {
|
||||||
m_containerFormat = ContainerFormat::Matroska;
|
m_containerFormat = ContainerFormat::Matroska;
|
||||||
} else if (container->documentType() == "webm") {
|
} else if (container->documentType() == "webm") {
|
||||||
|
@ -243,9 +249,11 @@ startParsingSignature:
|
||||||
if (m_forceFullParse) {
|
if (m_forceFullParse) {
|
||||||
// validating the element structure of Matroska files takes too long when
|
// validating the element structure of Matroska files takes too long when
|
||||||
// parsing big files so do this only when explicitely desired
|
// parsing big files so do this only when explicitely desired
|
||||||
container->validateElementStructure(diag, &m_paddingSize);
|
container->validateElementStructure(diag, progress, &m_paddingSize);
|
||||||
container->validateIndex(diag);
|
container->validateIndex(diag, progress);
|
||||||
}
|
}
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Validating the Matroska element structure has been aborted.", context);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
m_containerParsingStatus = ParsingStatus::CriticalFailure;
|
m_containerParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
}
|
}
|
||||||
|
@ -299,12 +307,10 @@ startParsingSignature:
|
||||||
* hasTracksOfType() will return the parsed information.
|
* hasTracksOfType() will return the parsed information.
|
||||||
*
|
*
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
|
||||||
* error occurs.
|
|
||||||
* \remarks parseContainerFormat() must be called before.
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \sa areTracksParsed(), parseContainerFormat(), parseTags(), parseChapters(), parseEverything()
|
* \sa areTracksParsed(), parseContainerFormat(), parseTags(), parseChapters(), parseEverything()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseTracks(Diagnostics &diag)
|
void MediaFileInfo::parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// skip if tracks already parsed
|
// skip if tracks already parsed
|
||||||
if (tracksParsingStatus() != ParsingStatus::NotParsedYet) {
|
if (tracksParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||||
|
@ -315,7 +321,7 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
||||||
try {
|
try {
|
||||||
// parse tracks via container object
|
// parse tracks via container object
|
||||||
if (m_container) {
|
if (m_container) {
|
||||||
m_container->parseTracks(diag);
|
m_container->parseTracks(diag, progress);
|
||||||
m_tracksParsingStatus = ParsingStatus::Ok;
|
m_tracksParsingStatus = ParsingStatus::Ok;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +346,7 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
||||||
default:
|
default:
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
m_singleTrack->parseHeader(diag);
|
m_singleTrack->parseHeader(diag, progress);
|
||||||
|
|
||||||
// take padding for some "single-track" formats into account
|
// take padding for some "single-track" formats into account
|
||||||
switch (m_containerFormat) {
|
switch (m_containerFormat) {
|
||||||
|
@ -355,6 +361,8 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
||||||
} catch (const NotImplementedException &) {
|
} catch (const NotImplementedException &) {
|
||||||
diag.emplace_back(DiagLevel::Information, "Parsing tracks is not implemented for the container format of the file.", context);
|
diag.emplace_back(DiagLevel::Information, "Parsing tracks is not implemented for the container format of the file.", context);
|
||||||
m_tracksParsingStatus = ParsingStatus::NotSupported;
|
m_tracksParsingStatus = ParsingStatus::NotSupported;
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Parsing tracks has been aborted.", context);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse tracks.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to parse tracks.", context);
|
||||||
m_tracksParsingStatus = ParsingStatus::CriticalFailure;
|
m_tracksParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
|
@ -370,12 +378,10 @@ void MediaFileInfo::parseTracks(Diagnostics &diag)
|
||||||
*
|
*
|
||||||
* Previously assigned but not applied tag information will be discarted.
|
* Previously assigned but not applied tag information will be discarted.
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
|
||||||
* error occurs.
|
|
||||||
* \remarks parseContainerFormat() must be called before.
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \sa isTagParsed(), parseContainerFormat(), parseTracks(), parseChapters(), parseEverything()
|
* \sa isTagParsed(), parseContainerFormat(), parseTracks(), parseChapters(), parseEverything()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseTags(Diagnostics &diag)
|
void MediaFileInfo::parseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// skip if tags already parsed
|
// skip if tags already parsed
|
||||||
if (tagsParsingStatus() != ParsingStatus::NotParsedYet) {
|
if (tagsParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||||
|
@ -392,6 +398,9 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||||
m_actualExistingId3v1Tag = true;
|
m_actualExistingId3v1Tag = true;
|
||||||
} catch (const NoDataFoundException &) {
|
} catch (const NoDataFoundException &) {
|
||||||
m_id3v1Tag.reset();
|
m_id3v1Tag.reset();
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Parsing ID3v1 tag has been aborted.", context);
|
||||||
|
return;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse ID3v1 tag.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to parse ID3v1 tag.", context);
|
||||||
|
@ -408,6 +417,9 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||||
m_paddingSize += id3v2Tag->paddingSize();
|
m_paddingSize += id3v2Tag->paddingSize();
|
||||||
} catch (const NoDataFoundException &) {
|
} catch (const NoDataFoundException &) {
|
||||||
continue;
|
continue;
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Parsing ID3v2 tags has been aborted.", context);
|
||||||
|
return;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse ID3v2 tag.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to parse ID3v2 tag.", context);
|
||||||
|
@ -418,13 +430,13 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||||
// check for tags in tracks (FLAC only) or via container object
|
// check for tags in tracks (FLAC only) or via container object
|
||||||
try {
|
try {
|
||||||
if (m_containerFormat == ContainerFormat::Flac) {
|
if (m_containerFormat == ContainerFormat::Flac) {
|
||||||
parseTracks(diag);
|
parseTracks(diag, progress);
|
||||||
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
if (m_tagsParsingStatus == ParsingStatus::NotParsedYet) {
|
||||||
m_tagsParsingStatus = m_tracksParsingStatus;
|
m_tagsParsingStatus = m_tracksParsingStatus;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (m_container) {
|
} else if (m_container) {
|
||||||
m_container->parseTags(diag);
|
m_container->parseTags(diag, progress);
|
||||||
} else {
|
} else {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -440,6 +452,9 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||||
m_tagsParsingStatus = ParsingStatus::NotSupported;
|
m_tagsParsingStatus = ParsingStatus::NotSupported;
|
||||||
}
|
}
|
||||||
diag.emplace_back(DiagLevel::Information, "Parsing tags is not implemented for the container format of the file.", context);
|
diag.emplace_back(DiagLevel::Information, "Parsing tags is not implemented for the container format of the file.", context);
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
diag.emplace_back(DiagLevel::Information, "Parsing tags from container/streams has been aborted.", context);
|
||||||
|
return;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
m_tagsParsingStatus = ParsingStatus::CriticalFailure;
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse tag.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to parse tag.", context);
|
||||||
|
@ -452,12 +467,10 @@ void MediaFileInfo::parseTags(Diagnostics &diag)
|
||||||
* This method parses the chapters of the current file if not been parsed yet.
|
* This method parses the chapters of the current file if not been parsed yet.
|
||||||
*
|
*
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
|
||||||
* error occurs.
|
|
||||||
* \remarks parseContainerFormat() must be called before.
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything()
|
* \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseChapters(Diagnostics &diag)
|
void MediaFileInfo::parseChapters(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// skip if chapters already parsed
|
// skip if chapters already parsed
|
||||||
if (chaptersParsingStatus() != ParsingStatus::NotParsedYet) {
|
if (chaptersParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||||
|
@ -470,7 +483,7 @@ void MediaFileInfo::parseChapters(Diagnostics &diag)
|
||||||
if (!m_container) {
|
if (!m_container) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
m_container->parseChapters(diag);
|
m_container->parseChapters(diag, progress);
|
||||||
m_chaptersParsingStatus = ParsingStatus::Ok;
|
m_chaptersParsingStatus = ParsingStatus::Ok;
|
||||||
} catch (const NotImplementedException &) {
|
} catch (const NotImplementedException &) {
|
||||||
m_chaptersParsingStatus = ParsingStatus::NotSupported;
|
m_chaptersParsingStatus = ParsingStatus::NotSupported;
|
||||||
|
@ -487,12 +500,10 @@ void MediaFileInfo::parseChapters(Diagnostics &diag)
|
||||||
* This method parses the attachments of the current file if not been parsed yet.
|
* This method parses the attachments of the current file if not been parsed yet.
|
||||||
*
|
*
|
||||||
* \throws Throws std::ios_base::failure when an IO error occurs.
|
* \throws Throws std::ios_base::failure when an IO error occurs.
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a parsing
|
|
||||||
* error occurs.
|
|
||||||
* \remarks parseContainerFormat() must be called before.
|
* \remarks parseContainerFormat() must be called before.
|
||||||
* \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything()
|
* \sa areChaptersParsed(), parseContainerFormat(), parseTracks(), parseTags(), parseEverything()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseAttachments(Diagnostics &diag)
|
void MediaFileInfo::parseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// skip if attachments already parsed
|
// skip if attachments already parsed
|
||||||
if (attachmentsParsingStatus() != ParsingStatus::NotParsedYet) {
|
if (attachmentsParsingStatus() != ParsingStatus::NotParsedYet) {
|
||||||
|
@ -505,7 +516,7 @@ void MediaFileInfo::parseAttachments(Diagnostics &diag)
|
||||||
if (!m_container) {
|
if (!m_container) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
m_container->parseAttachments(diag);
|
m_container->parseAttachments(diag, progress);
|
||||||
m_attachmentsParsingStatus = ParsingStatus::Ok;
|
m_attachmentsParsingStatus = ParsingStatus::Ok;
|
||||||
} catch (const NotImplementedException &) {
|
} catch (const NotImplementedException &) {
|
||||||
m_attachmentsParsingStatus = ParsingStatus::NotSupported;
|
m_attachmentsParsingStatus = ParsingStatus::NotSupported;
|
||||||
|
@ -522,13 +533,25 @@ void MediaFileInfo::parseAttachments(Diagnostics &diag)
|
||||||
* See the individual methods to for more details and exceptions which might be thrown.
|
* See the individual methods to for more details and exceptions which might be thrown.
|
||||||
* \sa parseContainerFormat(), parseTracks(), parseTags()
|
* \sa parseContainerFormat(), parseTracks(), parseTags()
|
||||||
*/
|
*/
|
||||||
void MediaFileInfo::parseEverything(Diagnostics &diag)
|
void MediaFileInfo::parseEverything(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
parseContainerFormat(diag);
|
parseContainerFormat(diag, progress);
|
||||||
parseTracks(diag);
|
if (progress.isAborted()) {
|
||||||
parseTags(diag);
|
return;
|
||||||
parseChapters(diag);
|
}
|
||||||
parseAttachments(diag);
|
parseTracks(diag, progress);
|
||||||
|
if (progress.isAborted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseTags(diag, progress);
|
||||||
|
if (progress.isAborted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseChapters(diag, progress);
|
||||||
|
if (progress.isAborted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parseAttachments(diag, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -52,12 +52,12 @@ public:
|
||||||
~MediaFileInfo() override;
|
~MediaFileInfo() override;
|
||||||
|
|
||||||
// methods to parse file
|
// methods to parse file
|
||||||
void parseContainerFormat(Diagnostics &diag);
|
void parseContainerFormat(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseTracks(Diagnostics &diag);
|
void parseTracks(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseTags(Diagnostics &diag);
|
void parseTags(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseChapters(Diagnostics &diag);
|
void parseChapters(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseAttachments(Diagnostics &diag);
|
void parseAttachments(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
void parseEverything(Diagnostics &diag);
|
void parseEverything(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
|
|
||||||
// methods to apply changes
|
// methods to apply changes
|
||||||
void applyChanges(Diagnostics &diag, AbortableProgressFeedback &progress);
|
void applyChanges(Diagnostics &diag, AbortableProgressFeedback &progress);
|
||||||
|
|
|
@ -69,9 +69,9 @@ ElementPosition Mp4Container::determineIndexPosition(Diagnostics &diag) const
|
||||||
return ElementPosition::Keep;
|
return ElementPosition::Keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Container::internalParseHeader(Diagnostics &diag)
|
void Mp4Container::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
//const string context("parsing header of MP4 container"); will be used when generating notifications
|
CPP_UTILITIES_UNUSED(progress) //const string context("parsing header of MP4 container"); will be used when generating notifications
|
||||||
m_firstElement = make_unique<Mp4Atom>(*this, startOffset());
|
m_firstElement = make_unique<Mp4Atom>(*this, startOffset());
|
||||||
m_firstElement->parse(diag);
|
m_firstElement->parse(diag);
|
||||||
auto *const ftypAtom = m_firstElement->siblingByIdIncludingThis(Mp4AtomIds::FileType, diag);
|
auto *const ftypAtom = m_firstElement->siblingByIdIncludingThis(Mp4AtomIds::FileType, diag);
|
||||||
|
@ -85,8 +85,9 @@ void Mp4Container::internalParseHeader(Diagnostics &diag)
|
||||||
m_version = reader().readUInt32BE();
|
m_version = reader().readUInt32BE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Container::internalParseTags(Diagnostics &diag)
|
void Mp4Container::internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
const string context("parsing tags of MP4 container");
|
const string context("parsing tags of MP4 container");
|
||||||
auto *const udtaAtom = firstElement()->subelementByPath(diag, Mp4AtomIds::Movie, Mp4AtomIds::UserData);
|
auto *const udtaAtom = firstElement()->subelementByPath(diag, Mp4AtomIds::Movie, Mp4AtomIds::UserData);
|
||||||
if (!udtaAtom) {
|
if (!udtaAtom) {
|
||||||
|
@ -114,7 +115,7 @@ void Mp4Container::internalParseTags(Diagnostics &diag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Container::internalParseTracks(Diagnostics &diag)
|
void Mp4Container::internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
static const string context("parsing tracks of MP4 container");
|
static const string context("parsing tracks of MP4 container");
|
||||||
try {
|
try {
|
||||||
|
@ -185,7 +186,7 @@ void Mp4Container::internalParseTracks(Diagnostics &diag)
|
||||||
// parse the trak atom using the Mp4Track class
|
// parse the trak atom using the Mp4Track class
|
||||||
m_tracks.emplace_back(make_unique<Mp4Track>(*trakAtom));
|
m_tracks.emplace_back(make_unique<Mp4Track>(*trakAtom));
|
||||||
try { // try to parse header
|
try { // try to parse header
|
||||||
m_tracks.back()->parseHeader(diag);
|
m_tracks.back()->parseHeader(diag, progress);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse track ", trackNum, '.'), context);
|
diag.emplace_back(DiagLevel::Critical, argsToString("Unable to parse track ", trackNum, '.'), context);
|
||||||
}
|
}
|
||||||
|
@ -843,7 +844,9 @@ calculatePadding:
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
try {
|
try {
|
||||||
parseTracks(diag);
|
parseTracks(diag, progress);
|
||||||
|
} catch (const OperationAbortedException &) {
|
||||||
|
throw;
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
diag.emplace_back(DiagLevel::Critical, "Unable to reparse the new file.", context);
|
diag.emplace_back(DiagLevel::Critical, "Unable to reparse the new file.", context);
|
||||||
throw;
|
throw;
|
||||||
|
@ -877,7 +880,7 @@ calculatePadding:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
progress.updateStep("Updating chunk offset table for each track ...");
|
progress.updateStep("Updating chunk offset table for each track ...");
|
||||||
updateOffsets(origMediaDataOffsets, newMediaDataOffsets, diag);
|
updateOffsets(origMediaDataOffsets, newMediaDataOffsets, diag, progress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,7 +905,8 @@ calculatePadding:
|
||||||
* \throws Throws TagParser::Failure or a derived exception when a making
|
* \throws Throws TagParser::Failure or a derived exception when a making
|
||||||
* error occurs.
|
* error occurs.
|
||||||
*/
|
*/
|
||||||
void Mp4Container::updateOffsets(const std::vector<std::int64_t> &oldMdatOffsets, const std::vector<std::int64_t> &newMdatOffsets, Diagnostics &diag)
|
void Mp4Container::updateOffsets(const std::vector<std::int64_t> &oldMdatOffsets, const std::vector<std::int64_t> &newMdatOffsets, Diagnostics &diag,
|
||||||
|
AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// do NOT invalidate the status here since this method is internally called by internalMakeFile(), just update the status
|
// do NOT invalidate the status here since this method is internally called by internalMakeFile(), just update the status
|
||||||
const string context("updating MP4 container chunk offset table");
|
const string context("updating MP4 container chunk offset table");
|
||||||
|
@ -972,7 +976,7 @@ void Mp4Container::updateOffsets(const std::vector<std::int64_t> &oldMdatOffsets
|
||||||
for (auto &track : tracks()) {
|
for (auto &track : tracks()) {
|
||||||
if (!track->isHeaderValid()) {
|
if (!track->isHeaderValid()) {
|
||||||
try {
|
try {
|
||||||
track->parseHeader(diag);
|
track->parseHeader(diag, progress);
|
||||||
} catch (const Failure &) {
|
} catch (const Failure &) {
|
||||||
diag.emplace_back(DiagLevel::Warning,
|
diag.emplace_back(DiagLevel::Warning,
|
||||||
"The chunk offsets of track " % track->name() + " couldn't be updated because the track seems to be invalid..", context);
|
"The chunk offsets of track " % track->name() + " couldn't be updated because the track seems to be invalid..", context);
|
||||||
|
|
|
@ -27,13 +27,14 @@ public:
|
||||||
ElementPosition determineIndexPosition(Diagnostics &diag) const override;
|
ElementPosition determineIndexPosition(Diagnostics &diag) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTags(Diagnostics &diag) override;
|
void internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTracks(Diagnostics &diag) override;
|
void internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateOffsets(const std::vector<std::int64_t> &oldMdatOffsets, const std::vector<std::int64_t> &newMdatOffsets, Diagnostics &diag);
|
void updateOffsets(const std::vector<std::int64_t> &oldMdatOffsets, const std::vector<std::int64_t> &newMdatOffsets, Diagnostics &diag,
|
||||||
|
AbortableProgressFeedback &progress);
|
||||||
|
|
||||||
bool m_fragmented;
|
bool m_fragmented;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1472,8 +1472,10 @@ void Mp4Track::makeSampleTable(Diagnostics &diag)
|
||||||
// Mp4Atom::seekBackAndWriteAtomSize(outputStream(), stblStartOffset, diag);
|
// Mp4Atom::seekBackAndWriteAtomSize(outputStream(), stblStartOffset, diag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mp4Track::internalParseHeader(Diagnostics &diag)
|
void Mp4Track::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing MP4 track");
|
static const string context("parsing MP4 track");
|
||||||
using namespace Mp4AtomIds;
|
using namespace Mp4AtomIds;
|
||||||
if (!m_trakAtom) {
|
if (!m_trakAtom) {
|
||||||
|
|
|
@ -162,7 +162,7 @@ public:
|
||||||
static void addInfo(const Av1Configuration &av1Config, AbstractTrack &track);
|
static void addInfo(const Av1Configuration &av1Config, AbstractTrack &track);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// private helper methods
|
// private helper methods
|
||||||
|
|
|
@ -27,8 +27,10 @@ void MpegAudioFrameStream::addInfo(const MpegAudioFrame &frame, AbstractTrack &t
|
||||||
track.m_samplingFrequency = frame.samplingFrequency();
|
track.m_samplingFrequency = frame.samplingFrequency();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag)
|
void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing MPEG audio frame header");
|
static const string context("parsing MPEG audio frame header");
|
||||||
if (!m_istream) {
|
if (!m_istream) {
|
||||||
throw NoDataFoundException();
|
throw NoDataFoundException();
|
||||||
|
|
|
@ -19,7 +19,7 @@ public:
|
||||||
static void addInfo(const MpegAudioFrame &frame, AbstractTrack &track);
|
static void addInfo(const MpegAudioFrame &frame, AbstractTrack &track);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<MpegAudioFrame> m_frames;
|
std::list<MpegAudioFrame> m_frames;
|
||||||
|
|
|
@ -183,8 +183,10 @@ void OggContainer::removeAllTags()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggContainer::internalParseHeader(Diagnostics &diag)
|
void OggContainer::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing OGG bitstream header");
|
static const string context("parsing OGG bitstream header");
|
||||||
bool pagesSkipped = false;
|
bool pagesSkipped = false;
|
||||||
|
|
||||||
|
@ -258,10 +260,10 @@ void OggContainer::internalParseHeader(Diagnostics &diag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggContainer::internalParseTags(Diagnostics &diag)
|
void OggContainer::internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
// tracks needs to be parsed before because tags are stored at stream level
|
// tracks needs to be parsed before because tags are stored at stream level
|
||||||
parseTracks(diag);
|
parseTracks(diag, progress);
|
||||||
for (auto &comment : m_tags) {
|
for (auto &comment : m_tags) {
|
||||||
OggParameter ¶ms = comment->oggParams();
|
OggParameter ¶ms = comment->oggParams();
|
||||||
m_iterator.setPageIndex(params.firstPageIndex);
|
m_iterator.setPageIndex(params.firstPageIndex);
|
||||||
|
@ -304,12 +306,15 @@ void OggContainer::announceComment(std::size_t pageIndex, std::size_t segmentInd
|
||||||
m_tags.back()->oggParams().set(pageIndex, segmentIndex, lastMetaDataBlock, mediaFormat);
|
m_tags.back()->oggParams().set(pageIndex, segmentIndex, lastMetaDataBlock, mediaFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggContainer::internalParseTracks(Diagnostics &diag)
|
void OggContainer::internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
static const string context("parsing OGG stream");
|
static const string context("parsing OGG stream");
|
||||||
for (auto &stream : m_tracks) {
|
for (auto &stream : m_tracks) {
|
||||||
|
if (progress.isAborted()) {
|
||||||
|
throw OperationAbortedException();
|
||||||
|
}
|
||||||
try { // try to parse header
|
try { // try to parse header
|
||||||
stream->parseHeader(diag);
|
stream->parseHeader(diag, progress);
|
||||||
if (stream->duration() > m_duration) {
|
if (stream->duration() > m_duration) {
|
||||||
m_duration = stream->duration();
|
m_duration = stream->duration();
|
||||||
}
|
}
|
||||||
|
@ -367,7 +372,7 @@ void OggContainer::internalMakeFile(Diagnostics &diag, AbortableProgressFeedback
|
||||||
{
|
{
|
||||||
const string context("making OGG file");
|
const string context("making OGG file");
|
||||||
progress.updateStep("Prepare for rewriting OGG file ...");
|
progress.updateStep("Prepare for rewriting OGG file ...");
|
||||||
parseTags(diag); // tags need to be parsed before the file can be rewritten
|
parseTags(diag, progress); // tags need to be parsed before the file can be rewritten
|
||||||
string backupPath;
|
string backupPath;
|
||||||
NativeFileStream backupStream;
|
NativeFileStream backupStream;
|
||||||
|
|
||||||
|
|
|
@ -144,9 +144,9 @@ public:
|
||||||
void removeAllTags() override;
|
void removeAllTags() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTags(Diagnostics &diag) override;
|
void internalParseTags(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalParseTracks(Diagnostics &diag) override;
|
void internalParseTracks(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
void internalMakeFile(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -46,8 +46,10 @@ OggStream::~OggStream()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggStream::internalParseHeader(Diagnostics &diag)
|
void OggStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
static const string context("parsing OGG page header");
|
static const string context("parsing OGG page header");
|
||||||
|
|
||||||
// read basic information from first page
|
// read basic information from first page
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
std::size_t startPage() const;
|
std::size_t startPage() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calculateDurationViaSampleCount(std::uint16_t preSkip = 0);
|
void calculateDurationViaSampleCount(std::uint16_t preSkip = 0);
|
||||||
|
|
|
@ -15,7 +15,7 @@ public:
|
||||||
using Callback = std::function<void(ActualProgressFeedback &feedback)>;
|
using Callback = std::function<void(ActualProgressFeedback &feedback)>;
|
||||||
|
|
||||||
explicit BasicProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
explicit BasicProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
||||||
explicit BasicProgressFeedback(Callback &&callback, Callback &&percentageOnlyCallback = Callback());
|
explicit BasicProgressFeedback(Callback &&callback = Callback(), Callback &&percentageOnlyCallback = Callback());
|
||||||
|
|
||||||
const std::string &step() const;
|
const std::string &step() const;
|
||||||
std::uint8_t stepPercentage() const;
|
std::uint8_t stepPercentage() const;
|
||||||
|
@ -159,8 +159,8 @@ inline void BasicProgressFeedback<ActualProgressFeedback>::updateOverallPercenta
|
||||||
|
|
||||||
class ProgressFeedback : public BasicProgressFeedback<ProgressFeedback> {
|
class ProgressFeedback : public BasicProgressFeedback<ProgressFeedback> {
|
||||||
public:
|
public:
|
||||||
ProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
explicit ProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
||||||
ProgressFeedback(Callback &&callback, Callback &&percentageOnlyCallback = Callback());
|
explicit ProgressFeedback(Callback &&callback = Callback(), Callback &&percentageOnlyCallback = Callback());
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -185,8 +185,8 @@ inline ProgressFeedback::ProgressFeedback(Callback &&callback, Callback &&percen
|
||||||
|
|
||||||
class AbortableProgressFeedback : public BasicProgressFeedback<AbortableProgressFeedback> {
|
class AbortableProgressFeedback : public BasicProgressFeedback<AbortableProgressFeedback> {
|
||||||
public:
|
public:
|
||||||
AbortableProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
explicit AbortableProgressFeedback(const Callback &callback, const Callback &percentageOnlyCallback = Callback());
|
||||||
AbortableProgressFeedback(Callback &&callback, Callback &&percentageOnlyCallback = Callback());
|
explicit AbortableProgressFeedback(Callback &&callback = Callback(), Callback &&percentageOnlyCallback = Callback());
|
||||||
|
|
||||||
bool isAborted() const;
|
bool isAborted() const;
|
||||||
void tryToAbort();
|
void tryToAbort();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "../abstracttrack.h"
|
#include "../abstracttrack.h"
|
||||||
#include "../mediafileinfo.h"
|
#include "../mediafileinfo.h"
|
||||||
|
#include "../progressfeedback.h"
|
||||||
#include "../tag.h"
|
#include "../tag.h"
|
||||||
|
|
||||||
#include <c++utilities/tests/testutils.h>
|
#include <c++utilities/tests/testutils.h>
|
||||||
|
@ -86,9 +87,10 @@ void MediaFileInfoTests::testFileSystemMethods()
|
||||||
void MediaFileInfoTests::testParsingUnsupportedFile()
|
void MediaFileInfoTests::testParsingUnsupportedFile()
|
||||||
{
|
{
|
||||||
Diagnostics diag;
|
Diagnostics diag;
|
||||||
|
AbortableProgressFeedback progress;
|
||||||
MediaFileInfo file(testFilePath("unsupported.bin"));
|
MediaFileInfo file(testFilePath("unsupported.bin"));
|
||||||
file.parseContainerFormat(diag);
|
file.parseContainerFormat(diag, progress);
|
||||||
file.parseTags(diag);
|
file.parseTags(diag, progress);
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.containerParsingStatus());
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.tagsParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotSupported, file.tagsParsingStatus());
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::NotParsedYet, file.tracksParsingStatus());
|
||||||
|
@ -101,13 +103,14 @@ void MediaFileInfoTests::testParsingUnsupportedFile()
|
||||||
void MediaFileInfoTests::testPartialParsingAndTagCreationOfMp4File()
|
void MediaFileInfoTests::testPartialParsingAndTagCreationOfMp4File()
|
||||||
{
|
{
|
||||||
Diagnostics diag;
|
Diagnostics diag;
|
||||||
|
AbortableProgressFeedback progress;
|
||||||
MediaFileInfo file(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"));
|
MediaFileInfo file(testFilePath("mtx-test-data/aac/he-aacv2-ps.m4a"));
|
||||||
file.open(true);
|
file.open(true);
|
||||||
file.parseContainerFormat(diag);
|
file.parseContainerFormat(diag, progress);
|
||||||
file.parseTags(diag);
|
file.parseTags(diag, progress);
|
||||||
file.parseAttachments(diag);
|
file.parseAttachments(diag, progress);
|
||||||
file.close();
|
file.close();
|
||||||
CPPUNIT_ASSERT_THROW_MESSAGE("std::ios_base::failure thrown if file closed", file.parseTracks(diag), std::ios_base::failure);
|
CPPUNIT_ASSERT_THROW_MESSAGE("std::ios_base::failure thrown if file closed", file.parseTracks(diag, progress), std::ios_base::failure);
|
||||||
CPPUNIT_ASSERT(file.areTagsSupported());
|
CPPUNIT_ASSERT(file.areTagsSupported());
|
||||||
CPPUNIT_ASSERT(file.areTracksSupported());
|
CPPUNIT_ASSERT(file.areTracksSupported());
|
||||||
CPPUNIT_ASSERT(!file.areChaptersSupported());
|
CPPUNIT_ASSERT(!file.areChaptersSupported());
|
||||||
|
@ -145,12 +148,13 @@ void MediaFileInfoTests::testPartialParsingAndTagCreationOfMp4File()
|
||||||
void MediaFileInfoTests::testFullParseAndFurtherProperties()
|
void MediaFileInfoTests::testFullParseAndFurtherProperties()
|
||||||
{
|
{
|
||||||
Diagnostics diag;
|
Diagnostics diag;
|
||||||
|
AbortableProgressFeedback progress;
|
||||||
MediaFileInfo file(testFilePath("matroska_wave1/test1.mkv"));
|
MediaFileInfo file(testFilePath("matroska_wave1/test1.mkv"));
|
||||||
file.open(true);
|
file.open(true);
|
||||||
file.parseEverything(diag);
|
file.parseEverything(diag, progress);
|
||||||
// calling parse methods twice should not do anything (and hence can not fail anymore because the file has already been closed)
|
// calling parse methods twice should not do anything (and hence can not fail anymore because the file has already been closed)
|
||||||
file.close();
|
file.close();
|
||||||
file.parseEverything(diag);
|
file.parseEverything(diag, progress);
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.containerParsingStatus());
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tagsParsingStatus());
|
||||||
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tracksParsingStatus());
|
CPPUNIT_ASSERT_EQUAL(ParsingStatus::Ok, file.tracksParsingStatus());
|
||||||
|
|
|
@ -37,7 +37,7 @@ void OverallTests::parseFile(const string &path, void (OverallTests::*checkRouti
|
||||||
m_diag.clear();
|
m_diag.clear();
|
||||||
m_fileInfo.setPath(path);
|
m_fileInfo.setPath(path);
|
||||||
m_fileInfo.reopen(true);
|
m_fileInfo.reopen(true);
|
||||||
m_fileInfo.parseEverything(m_diag);
|
m_fileInfo.parseEverything(m_diag, m_progress);
|
||||||
// invoke testroutine to check whether parsing results are correct
|
// invoke testroutine to check whether parsing results are correct
|
||||||
(this->*checkRoutine)();
|
(this->*checkRoutine)();
|
||||||
m_fileInfo.close();
|
m_fileInfo.close();
|
||||||
|
@ -55,7 +55,7 @@ void OverallTests::makeFile(const string &path, void (OverallTests::*modifyRouti
|
||||||
m_diag.clear();
|
m_diag.clear();
|
||||||
m_fileInfo.setPath(path);
|
m_fileInfo.setPath(path);
|
||||||
m_fileInfo.reopen(true);
|
m_fileInfo.reopen(true);
|
||||||
m_fileInfo.parseEverything(m_diag);
|
m_fileInfo.parseEverything(m_diag, m_progress);
|
||||||
|
|
||||||
// determine expected tag and index position
|
// determine expected tag and index position
|
||||||
switch (m_fileInfo.containerFormat()) {
|
switch (m_fileInfo.containerFormat()) {
|
||||||
|
@ -96,7 +96,7 @@ void OverallTests::makeFile(const string &path, void (OverallTests::*modifyRouti
|
||||||
m_fileInfo.applyChanges(m_diag, m_progress);
|
m_fileInfo.applyChanges(m_diag, m_progress);
|
||||||
m_fileInfo.clearParsingResults();
|
m_fileInfo.clearParsingResults();
|
||||||
// reparse the file and invoke testroutine to check whether changings have been applied correctly
|
// reparse the file and invoke testroutine to check whether changings have been applied correctly
|
||||||
m_fileInfo.parseEverything(m_diag);
|
m_fileInfo.parseEverything(m_diag, m_progress);
|
||||||
(this->*checkRoutine)();
|
(this->*checkRoutine)();
|
||||||
// invoke suitable testroutine to check padding constraints
|
// invoke suitable testroutine to check padding constraints
|
||||||
switch (m_fileInfo.containerFormat()) {
|
switch (m_fileInfo.containerFormat()) {
|
||||||
|
|
|
@ -622,7 +622,7 @@ void OverallTests::setMkvTestMetaData()
|
||||||
// assign an attachment
|
// assign an attachment
|
||||||
AbstractAttachment *const attachment = container->createAttachment();
|
AbstractAttachment *const attachment = container->createAttachment();
|
||||||
CPPUNIT_ASSERT_MESSAGE("create attachment", attachment);
|
CPPUNIT_ASSERT_MESSAGE("create attachment", attachment);
|
||||||
attachment->setFile(testFilePath("matroska_wave1/logo3_256x256.png"), m_diag);
|
attachment->setFile(testFilePath("matroska_wave1/logo3_256x256.png"), m_diag, m_progress);
|
||||||
attachment->setMimeType("image/png");
|
attachment->setMimeType("image/png");
|
||||||
attachment->setName("cover.jpg");
|
attachment->setName("cover.jpg");
|
||||||
}
|
}
|
||||||
|
|
|
@ -497,8 +497,8 @@ void OverallTests::alterMp4Tracks()
|
||||||
{
|
{
|
||||||
m_additionalFileInfo.setPath(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"));
|
m_additionalFileInfo.setPath(testFilePath("mtx-test-data/mp4/10-DanseMacabreOp.40.m4a"));
|
||||||
m_additionalFileInfo.reopen(true);
|
m_additionalFileInfo.reopen(true);
|
||||||
m_additionalFileInfo.parseContainerFormat(m_diag);
|
m_additionalFileInfo.parseContainerFormat(m_diag, m_progress);
|
||||||
m_additionalFileInfo.parseTracks(m_diag);
|
m_additionalFileInfo.parseTracks(m_diag, m_progress);
|
||||||
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_additionalFileInfo.containerFormat());
|
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_additionalFileInfo.containerFormat());
|
||||||
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
|
CPPUNIT_ASSERT_EQUAL(ContainerFormat::Mp4, m_fileInfo.containerFormat());
|
||||||
const auto &tracks = m_additionalFileInfo.tracks();
|
const auto &tracks = m_additionalFileInfo.tracks();
|
||||||
|
|
|
@ -144,8 +144,10 @@ void WaveAudioStream::addInfo(const WaveFormatHeader &waveHeader, AbstractTrack
|
||||||
track.m_bitrate = waveHeader.bitrate();
|
track.m_bitrate = waveHeader.bitrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaveAudioStream::internalParseHeader(Diagnostics &diag)
|
void WaveAudioStream::internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress)
|
||||||
{
|
{
|
||||||
|
CPP_UTILITIES_UNUSED(progress)
|
||||||
|
|
||||||
const string context("parsing RIFF/WAVE header");
|
const string context("parsing RIFF/WAVE header");
|
||||||
if (!m_istream) {
|
if (!m_istream) {
|
||||||
throw NoDataFoundException();
|
throw NoDataFoundException();
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track);
|
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void internalParseHeader(Diagnostics &diag) override;
|
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::uint64_t m_dataOffset;
|
std::uint64_t m_dataOffset;
|
||||||
|
|
Loading…
Reference in New Issue