overloads for read, write, remove

Changes made

mp4chapterlist.h
• Added (​MP4::​File*) overloads for read, write, remove
• Replaced broken class ​File; forward declaration with #include "mp4file​.h" (fixed a subtle C++ name-resolution linker bug where Atoms(​File*) resolved to MP4::​File* instead of Tag​Lib::​File*)

mp4chapterlist.cpp
• Refactored: path-based overloads are now thin wrappers that delegate to file-based overloads
• File-based overloads construct Atoms locally — no Atoms* in the public API
• Removed chpl​Header​Size = 9 constant; replaced the minimum-size guard in parse​Chpl​Data with a correct 5-byte check (the old constant was version-1 specific and would reject valid version-0 atoms)

mp4qtchapterlist.h
• Added (​MP4::​File*) overloads for read, write, remove
• Removed Atoms* parameters entirely from the public API

mp4qtchapterlist.cpp
• Same refactor: path-based overloads delegate; file-based overloads construct Atoms locally
• Added empty-chapter guard: write(​MP4::​File*, {}) delegates to remove(file) instead of writing a 0-sample chapter track

tests/test_mp4.cpp
• Added test​Chapter​List​File​API and test​QTChapter​List​File​API — exercise the full write/read/remove cycle via the file-based API
• Updated test bodies to use the simplified (​MP4::​File*) API (no MP4::​Atoms construction in test code)
This commit is contained in:
Ryan Francesconi
2026-04-14 14:23:35 -07:00
parent 4a73d73b20
commit c5ea13bb34
5 changed files with 246 additions and 60 deletions

View File

@@ -115,6 +115,8 @@ class TestMP4 : public CppUnit::TestFixture
CPPUNIT_TEST(testQTChapterListOverwrite);
CPPUNIT_TEST(testQTChapterListTimestampPrecision);
CPPUNIT_TEST(testQTChapterListNonZeroFirstChapter);
CPPUNIT_TEST(testChapterListFileAPI);
CPPUNIT_TEST(testQTChapterListFileAPI);
CPPUNIT_TEST_SUITE_END();
public:
@@ -1313,6 +1315,109 @@ public:
CPPUNIT_ASSERT_EQUAL(String("Three"), chapters[2].title);
}
}
void testChapterListFileAPI()
{
ScopedFileCopy copy("no-tags", ".m4a");
string filename = copy.fileName();
// Write chapters via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid() && !file.readOnly());
MP4::ChapterList chapters;
MP4::Chapter ch1;
ch1.startTime = 0;
ch1.title = "Alpha";
chapters.append(ch1);
MP4::Chapter ch2;
ch2.startTime = 200000000LL; // 20 seconds
ch2.title = "Beta";
chapters.append(ch2);
CPPUNIT_ASSERT(MP4::MP4ChapterList::write(&file, chapters));
}
// Read back via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid());
MP4::ChapterList chapters = MP4::MP4ChapterList::read(&file);
CPPUNIT_ASSERT_EQUAL(2U, chapters.size());
CPPUNIT_ASSERT_EQUAL(0LL, chapters[0].startTime);
CPPUNIT_ASSERT_EQUAL(String("Alpha"), chapters[0].title);
CPPUNIT_ASSERT_EQUAL(200000000LL, chapters[1].startTime);
CPPUNIT_ASSERT_EQUAL(String("Beta"), chapters[1].title);
}
// Remove via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid() && !file.readOnly());
CPPUNIT_ASSERT(MP4::MP4ChapterList::remove(&file));
}
// Verify removed
{
MP4::ChapterList chapters = MP4::MP4ChapterList::read(filename.c_str());
CPPUNIT_ASSERT(chapters.isEmpty());
}
}
void testQTChapterListFileAPI()
{
ScopedFileCopy copy("no-tags", ".m4a");
string filename = copy.fileName();
// Write chapters via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid() && !file.readOnly());
MP4::ChapterList chapters;
MP4::Chapter ch1;
ch1.startTime = 0;
ch1.title = "Alpha";
chapters.append(ch1);
MP4::Chapter ch2;
ch2.startTime = 200000000LL; // 20 seconds
ch2.title = "Beta";
chapters.append(ch2);
CPPUNIT_ASSERT(MP4::MP4QTChapterList::write(&file, chapters));
}
// Read back via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid());
MP4::ChapterList chapters = MP4::MP4QTChapterList::read(&file);
CPPUNIT_ASSERT_EQUAL(2U, chapters.size());
CPPUNIT_ASSERT_EQUAL(0LL, chapters[0].startTime);
CPPUNIT_ASSERT_EQUAL(String("Alpha"), chapters[0].title);
CPPUNIT_ASSERT_EQUAL(200000000LL, chapters[1].startTime);
CPPUNIT_ASSERT_EQUAL(String("Beta"), chapters[1].title);
}
// Remove via the file-based API
{
MP4::File file(filename.c_str(), false);
CPPUNIT_ASSERT(file.isOpen() && file.isValid() && !file.readOnly());
CPPUNIT_ASSERT(MP4::MP4QTChapterList::remove(&file));
}
// Verify removed
{
MP4::ChapterList chapters = MP4::MP4QTChapterList::read(filename.c_str());
CPPUNIT_ASSERT(chapters.isEmpty());
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);