Add tests for FLAC files
This commit is contained in:
parent
a84ac37dbe
commit
53f0903c3b
|
@ -43,7 +43,7 @@ download() {
|
|||
skipping
|
||||
fi
|
||||
popd
|
||||
|
||||
|
||||
# extraction
|
||||
mkdir "$destdir"
|
||||
pushd "$destdir"
|
||||
|
@ -59,12 +59,12 @@ download() {
|
|||
popd
|
||||
else
|
||||
skipping
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
download_rsync() {
|
||||
title="$1" cmd="$2"
|
||||
|
||||
|
||||
inform "Downloading \"$title\" ..."
|
||||
if [[ ! -d $destdir ]]; then
|
||||
# actual download
|
||||
|
@ -75,7 +75,7 @@ download_rsync() {
|
|||
fi
|
||||
else
|
||||
skipping
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# enter testfiles directory
|
||||
|
@ -95,3 +95,8 @@ download \
|
|||
download_rsync \
|
||||
'MTX Test Data' \
|
||||
'rsync -rv --links --delete belgarath.bunkus.org::mtx-test-data mtx-test-data'
|
||||
|
||||
# convert FLAC files for FLAC tests with ffmpeg
|
||||
mkdir -p flac
|
||||
[[ ! -f flac/test.flac ]] && ffmpeg -i mtx-test-data/alac/othertest-itunes.m4a -c:a flac flac/test.flac # raw FLAC stream
|
||||
[[ ! -f flac/test.ogg ]] && ffmpeg -i flac/test.flac -c:a copy flac/test.ogg # FLAC in Ogg
|
||||
|
|
|
@ -51,6 +51,20 @@ VorbisComment *FlacStream::createVorbisComment()
|
|||
return m_vorbisComment.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes the assigned Vorbis comment if one is assigned; does nothing otherwise.
|
||||
* \returns Returns whether there were a Vorbis comment assigned.
|
||||
*/
|
||||
bool FlacStream::removeVorbisComment()
|
||||
{
|
||||
if(m_vorbisComment) {
|
||||
m_vorbisComment.reset();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlacStream::internalParseHeader()
|
||||
{
|
||||
static const string context("parsing raw FLAC header");
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
TrackType type() const;
|
||||
VorbisComment *vorbisComment() const;
|
||||
VorbisComment *createVorbisComment();
|
||||
bool removeVorbisComment();
|
||||
uint32 paddingSize() const;
|
||||
uint32 streamOffset() const;
|
||||
|
||||
|
|
|
@ -512,16 +512,16 @@ void MediaFileInfo::parseEverything()
|
|||
* \param requiredTargets Specifies the required targets. Targets are ignored if not supported by the container.
|
||||
* \return Returns an indication whether appropriate tags could be created for the file.
|
||||
* \remarks
|
||||
* - The ID3 related arguments are only practiced when the file format is MP3 or when the file format
|
||||
* is unknown and \a treatUnknownFilesAsMp3Files is true. These arguments are ignored when creating
|
||||
* tags for other known file formats such as MP4.
|
||||
* - Tags might be removed as well. For example the existing ID3v1 tag of an MP3 file will be removed
|
||||
* if \a id3v1Usage is set to TagUsage::Never.
|
||||
* - The method might do nothing if the file already has appropriate tags.
|
||||
* - This is only a convenience method. The task can be done by manually using the methods createId3v1Tag(),
|
||||
* createId3v2Tag(), removeId3v1Tag() ... as well.
|
||||
* - Some tag information might be discarded. For example when an ID3v2 tag needs to be removed (\a id3v2usage is set to TagUsage::Never)
|
||||
* and an ID3v1 tag will be created instead not all fields can be transfered.
|
||||
* - The ID3 related arguments are only practiced when the file format is MP3 or when the file format
|
||||
* is unknown and \a treatUnknownFilesAsMp3Files is true. These arguments are ignored when creating
|
||||
* tags for other known file formats such as MP4.
|
||||
* - Tags might be removed as well. For example the existing ID3v1 tag of an MP3 file will be removed
|
||||
* if \a id3v1Usage is set to TagUsage::Never.
|
||||
* - The method might do nothing if the file already has appropriate tags.
|
||||
* - This is only a convenience method. The task can be done by manually using the methods createId3v1Tag(),
|
||||
* createId3v2Tag(), removeId3v1Tag() ... as well.
|
||||
* - Some tag information might be discarded. For example when an ID3v2 tag needs to be removed (\a id3v2usage is set to TagUsage::Never)
|
||||
* and an ID3v1 tag will be created instead not all fields can be transfered.
|
||||
*/
|
||||
bool MediaFileInfo::createAppropriateTags(bool treatUnknownFilesAsMp3Files, TagUsage id3v1usage, TagUsage id3v2usage, bool mergeMultipleSuccessiveId3v2Tags, bool keepExistingId3v2version, uint32 id3v2version, const std::vector<TagTarget> &requiredTargets)
|
||||
{
|
||||
|
@ -911,7 +911,6 @@ bool MediaFileInfo::removeId3v2Tag(Id3v2Tag *tag)
|
|||
* To apply the removal and other changings call the applyChanges() method.
|
||||
*
|
||||
* \returns Returns whether there where ID3v2 tags assigned which could be removed.
|
||||
*
|
||||
* \sa applyChanges()
|
||||
*/
|
||||
bool MediaFileInfo::removeAllId3v2Tags()
|
||||
|
@ -934,10 +933,8 @@ bool MediaFileInfo::removeAllId3v2Tags()
|
|||
* To apply the created tag and other changings call the applyChanges() method.
|
||||
*
|
||||
* \returns Returns the first ID3v2 tag of the current file.
|
||||
*
|
||||
* \remarks The MediaFileInfo keeps the ownership over the created tag. It will be
|
||||
* destroyed when the MediaFileInfo is invalidated.
|
||||
*
|
||||
* \sa applyChanges()
|
||||
*/
|
||||
Id3v2Tag *MediaFileInfo::createId3v2Tag()
|
||||
|
@ -988,6 +985,9 @@ void MediaFileInfo::removeAllTags()
|
|||
if(m_container) {
|
||||
m_container->removeAllTags();
|
||||
}
|
||||
if(m_singleTrack && m_containerFormat == ContainerFormat::Flac) {
|
||||
static_cast<FlacStream *>(m_singleTrack.get())->removeVorbisComment();
|
||||
}
|
||||
m_id3v1Tag.reset();
|
||||
m_id3v2Tags.clear();
|
||||
}
|
||||
|
@ -1347,6 +1347,69 @@ bool MediaFileInfo::id3v2ToId3v1()
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a Vorbis comment for the current file.
|
||||
*
|
||||
* This method does nothing if the tags/tracks of the current file haven't been parsed using
|
||||
* the parseTags() and parseTracks() methods.
|
||||
*
|
||||
* If the file has already a Vorbis comment no new tag will be created.
|
||||
*
|
||||
* To apply the created tag and other changings call the applyChanges() method.
|
||||
*
|
||||
* \returns Returns the Vorbis comment or nullptr if creation is not possible.
|
||||
*
|
||||
* \sa applyChanges()
|
||||
*/
|
||||
VorbisComment *MediaFileInfo::createVorbisComment()
|
||||
{
|
||||
switch(m_containerFormat) {
|
||||
case ContainerFormat::Ogg:
|
||||
if(m_container) {
|
||||
return static_cast<OggContainer *>(m_container.get())->createTag(TagTarget());
|
||||
}
|
||||
break;
|
||||
case ContainerFormat::Flac:
|
||||
if(m_singleTrack) {
|
||||
return static_cast<FlacStream *>(m_singleTrack.get())->createVorbisComment();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes all assigned Vorbis comment from the current file.
|
||||
*
|
||||
* To apply the removal and other changings call the applyChanges() method.
|
||||
*
|
||||
* \returns Returns whether there was an Vorbis comment assigned which could be removed.
|
||||
*
|
||||
* \sa applyChanges()
|
||||
*/
|
||||
bool MediaFileInfo::removeVorbisComment()
|
||||
{
|
||||
switch(m_containerFormat) {
|
||||
case ContainerFormat::Ogg:
|
||||
if(m_container) {
|
||||
bool hadTags = static_cast<OggContainer *>(m_container.get())->tagCount();
|
||||
static_cast<OggContainer *>(m_container.get())->removeAllTags();
|
||||
return hadTags;
|
||||
}
|
||||
break;
|
||||
case ContainerFormat::Flac:
|
||||
if(m_singleTrack) {
|
||||
return static_cast<FlacStream *>(m_singleTrack.get())->removeVorbisComment();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Stores all tags assigned to the current file in the specified vector.
|
||||
*
|
||||
|
|
|
@ -131,6 +131,8 @@ public:
|
|||
void mergeId3v2Tags();
|
||||
bool id3v1ToId3v2();
|
||||
bool id3v2ToId3v1();
|
||||
VorbisComment *createVorbisComment();
|
||||
bool removeVorbisComment();
|
||||
|
||||
// methods to get/wipe notifications
|
||||
bool haveRelatedObjectsNotifications() const;
|
||||
|
|
|
@ -419,7 +419,9 @@ void OggContainer::internalMakeFile()
|
|||
|
||||
// check whether there is a new comment to be inserted into the current page
|
||||
if(m_iterator.currentPageIndex() == currentParams->lastPageIndex && currentParams->firstSegmentIndex == static_cast<size_t>(-1)) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
|
||||
if(!currentParams->removed) {
|
||||
makeVorbisCommentSegment(buffer, copyHelper, newSegmentSizes, currentComment, currentParams);
|
||||
}
|
||||
// proceed with next comment
|
||||
if(++tagIterator != tagEnd) {
|
||||
currentParams = &(currentComment = tagIterator->get())->oggParams();
|
||||
|
|
|
@ -45,6 +45,8 @@ class OverallTests : public TestFixture
|
|||
CPPUNIT_TEST(testMp3Making);
|
||||
CPPUNIT_TEST(testOggParsing);
|
||||
CPPUNIT_TEST(testOggMaking);
|
||||
CPPUNIT_TEST(testFlacParsing);
|
||||
CPPUNIT_TEST(testFlacMaking);
|
||||
CPPUNIT_TEST(testMkvParsing);
|
||||
CPPUNIT_TEST(testMkvMaking);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
@ -83,6 +85,9 @@ public:
|
|||
void checkOggTestfile2();
|
||||
void checkOggTestMetaData();
|
||||
|
||||
void checkFlacTestfile1();
|
||||
void checkFlacTestfile2();
|
||||
|
||||
void setMkvTestMetaData();
|
||||
void setMp4TestMetaData();
|
||||
void setMp3TestMetaData();
|
||||
|
@ -97,6 +102,8 @@ public:
|
|||
void testMp3Making();
|
||||
void testOggParsing();
|
||||
void testOggMaking();
|
||||
void testFlacParsing();
|
||||
void testFlacMaking();
|
||||
|
||||
private:
|
||||
MediaFileInfo m_fileInfo;
|
||||
|
@ -967,6 +974,7 @@ void OverallTests::checkOggTestfile1()
|
|||
switch(m_tagStatus) {
|
||||
case TagStatus::Original:
|
||||
CPPUNIT_ASSERT(tags.size() == 1);
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Encoder).toString() == "ffmpeg2theora 0.13");
|
||||
// Theora tags are currently not supported and hence only the Vorbis comment is
|
||||
// taken into account here
|
||||
break;
|
||||
|
@ -1003,6 +1011,7 @@ void OverallTests::checkOggTestfile2()
|
|||
switch(m_tagStatus) {
|
||||
case TagStatus::Original:
|
||||
CPPUNIT_ASSERT(tags.size() == 1);
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Encoder).toString() == "opusenc from opus-tools 0.1.6");
|
||||
break;
|
||||
case TagStatus::TestMetaDataPresent:
|
||||
checkOggTestMetaData();
|
||||
|
@ -1034,6 +1043,76 @@ void OverallTests::checkOggTestMetaData()
|
|||
m_preservedMetaData.pop();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks "flac/test.flac" (converted from "mtx-test-data/alac/othertest-itunes.m4a" via ffmpeg).
|
||||
* \remarks Raw FLAC stream.
|
||||
*/
|
||||
void OverallTests::checkFlacTestfile1()
|
||||
{
|
||||
CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Flac);
|
||||
const auto tracks = m_fileInfo.tracks();
|
||||
CPPUNIT_ASSERT(tracks.size() == 1);
|
||||
for(const auto &track : tracks) {
|
||||
CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
|
||||
CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Flac);
|
||||
CPPUNIT_ASSERT(track->channelCount() == 2);
|
||||
CPPUNIT_ASSERT(track->samplingFrequency() == 44100);
|
||||
CPPUNIT_ASSERT(track->bitsPerSample() == 16);
|
||||
}
|
||||
const auto tags = m_fileInfo.tags();
|
||||
switch(m_tagStatus) {
|
||||
case TagStatus::Original:
|
||||
// ffmpeg is able to set some tags from the original file (mtx-test-data/alac/othertest-itunes.m4a)
|
||||
CPPUNIT_ASSERT(tags.size() == 1);
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Title).toString() == "Sad Song");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Artist).toString() == "Oasis");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Album).toString() == "Don't Go Away (Apple Lossless)");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Genre).toString() == "Alternative & Punk");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Encoder).toString() == "Lavf57.25.100");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Year).toString() == "1998");
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::Comment).isEmpty());
|
||||
//CPPUNIT_ASSERT(tags.front()->value(KnownField::Cover).dataSize() == 0x58f3);
|
||||
//CPPUNIT_ASSERT(BE::toUInt64(tags.front()->value(KnownField::Cover).dataPointer()) == 0xFFD8FFE000104A46);
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::TrackPosition).toPositionInSet() == PositionInSet(3, 4));
|
||||
CPPUNIT_ASSERT(tags.front()->value(KnownField::DiskPosition).toPositionInSet() == PositionInSet(1, 1));
|
||||
break;
|
||||
case TagStatus::TestMetaDataPresent:
|
||||
checkOggTestMetaData();
|
||||
break;
|
||||
case TagStatus::Removed:
|
||||
CPPUNIT_ASSERT(tags.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks "flac/test.ogg" (converted from "flac/test.flac" via ffmpeg).
|
||||
* \remarks FLAC in Ogg.
|
||||
*/
|
||||
void OverallTests::checkFlacTestfile2()
|
||||
{
|
||||
CPPUNIT_ASSERT(m_fileInfo.containerFormat() == ContainerFormat::Ogg);
|
||||
const auto tracks = m_fileInfo.tracks();
|
||||
CPPUNIT_ASSERT(tracks.size() == 1);
|
||||
for(const auto &track : tracks) {
|
||||
CPPUNIT_ASSERT(track->mediaType() == MediaType::Audio);
|
||||
CPPUNIT_ASSERT(track->format() == GeneralMediaFormat::Flac);
|
||||
CPPUNIT_ASSERT(track->channelCount() == 2);
|
||||
CPPUNIT_ASSERT(track->samplingFrequency() == 44100);
|
||||
CPPUNIT_ASSERT(track->bitsPerSample() == 16);
|
||||
}
|
||||
const auto tags = m_fileInfo.tags();
|
||||
switch(m_tagStatus) {
|
||||
case TagStatus::Original:
|
||||
CPPUNIT_ASSERT(tags.size() == 1);
|
||||
break;
|
||||
case TagStatus::TestMetaDataPresent:
|
||||
checkOggTestMetaData();
|
||||
break;
|
||||
case TagStatus::Removed:
|
||||
CPPUNIT_ASSERT(tags.size() == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates a tag targeting the first track with some test meta data.
|
||||
*/
|
||||
|
@ -1115,7 +1194,7 @@ void OverallTests::setMp3TestMetaData()
|
|||
void OverallTests::setOggTestMetaData()
|
||||
{
|
||||
// ensure a tag exists
|
||||
Tag *tag = m_fileInfo.container()->createTag();
|
||||
VorbisComment *tag = m_fileInfo.createVorbisComment();
|
||||
|
||||
// assign test meta data
|
||||
tag->setValue(KnownField::Title, m_testTitle);
|
||||
|
@ -1373,6 +1452,7 @@ void OverallTests::testMp3Making()
|
|||
|
||||
/*!
|
||||
* \brief Tests the Ogg parser via MediaFileInfo.
|
||||
* \remarks FLAC in Ogg is tested in testFlacParsing().
|
||||
*/
|
||||
void OverallTests::testOggParsing()
|
||||
{
|
||||
|
@ -1385,7 +1465,9 @@ void OverallTests::testOggParsing()
|
|||
|
||||
/*!
|
||||
* \brief Tests the Ogg maker via MediaFileInfo.
|
||||
* \remarks Relies on the parser to check results.
|
||||
* \remarks
|
||||
* - Relies on the parser to check results.
|
||||
* - FLAC in Ogg is tested in testFlacMaking().
|
||||
*/
|
||||
void OverallTests::testOggMaking()
|
||||
{
|
||||
|
@ -1414,3 +1496,46 @@ void OverallTests::testOggMaking()
|
|||
makeFile(TestUtilities::workingCopyPath("mtx-test-data/opus/v-opus.ogg"), modifyRoutine, &OverallTests::checkOggTestfile2);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests the FLAC parser via MediaFileInfo.
|
||||
*/
|
||||
void OverallTests::testFlacParsing()
|
||||
{
|
||||
cerr << endl << "FLAC parser" << endl;
|
||||
m_fileInfo.setForceFullParse(false);
|
||||
m_tagStatus = TagStatus::Original;
|
||||
parseFile(TestUtilities::testFilePath("flac/test.flac"), &OverallTests::checkFlacTestfile1);
|
||||
parseFile(TestUtilities::testFilePath("flac/test.ogg"), &OverallTests::checkFlacTestfile2);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Tests the FLAC maker via MediaFileInfo.
|
||||
* \remarks Relies on the parser to check results.
|
||||
*/
|
||||
void OverallTests::testFlacMaking()
|
||||
{
|
||||
// full parse is required to determine padding
|
||||
m_fileInfo.setForceFullParse(true);
|
||||
|
||||
// do the test under different conditions
|
||||
for(m_mode = 0; m_mode != 0x2; ++m_mode) {
|
||||
// TODO: setup test conditions
|
||||
|
||||
// print test conditions
|
||||
list<string> testConditions;
|
||||
if(m_mode & 0x1) {
|
||||
testConditions.emplace_back("removing tag");
|
||||
} else {
|
||||
testConditions.emplace_back("modifying tag");
|
||||
}
|
||||
cerr << endl << "FLAC maker - testmode " << m_mode << ": " << joinStrings(testConditions, ", ") << endl;
|
||||
|
||||
// do actual tests
|
||||
bool remove = m_mode & 0x1;
|
||||
m_tagStatus = remove ? TagStatus::Removed : TagStatus::TestMetaDataPresent;
|
||||
void (OverallTests::*modifyRoutine)(void) = remove ? &OverallTests::removeAllTags : &OverallTests::setOggTestMetaData;
|
||||
makeFile(TestUtilities::workingCopyPath("flac/test.flac"), modifyRoutine, &OverallTests::checkFlacTestfile1);
|
||||
makeFile(TestUtilities::workingCopyPath("flac/test.ogg"), modifyRoutine, &OverallTests::checkFlacTestfile2);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue