Preserve order of atoms within moov tree

Maybe it helps with https://github.com/Martchus/tageditor/issues/45
This commit is contained in:
Martchus 2019-04-16 21:48:33 +02:00
parent da15530f53
commit c09f93c441
1 changed files with 61 additions and 32 deletions

View File

@ -587,43 +587,42 @@ calculatePadding:
// write movie atom / padding and media data // write movie atom / padding and media data
for (byte pass = 0; pass != 2; ++pass) { for (byte pass = 0; pass != 2; ++pass) {
if (newTagPos == (pass ? ElementPosition::AfterData : ElementPosition::BeforeData)) { if (newTagPos == (pass ? ElementPosition::AfterData : ElementPosition::BeforeData)) {
// write movie atom // define function to write tracks
// -> write movie atom header bool tracksWritten = false;
Mp4Atom::makeHeader(movieAtomSize, Mp4AtomIds::Movie, outputWriter); const auto writeTracks = [&] {
if (tracksWritten) {
// -> write track atoms return;
for (auto &track : tracks()) { }
track->makeTrack(diag);
} for (auto &track : tracks()) {
track->makeTrack(diag);
// -> write other movie atom children }
for (level0Atom = movieAtom; level0Atom; level0Atom = level0Atom->siblingById(Mp4AtomIds::Movie, diag)) { tracksWritten = true;
for (level1Atom = level0Atom->firstChild(); level1Atom; level1Atom = level1Atom->nextSibling()) { };
switch (level1Atom->id()) {
case Mp4AtomIds::UserData: // define function to write user data
case Mp4AtomIds::Track: bool userDataWritten = false;
// track and user data atoms are written separately const auto writeUserData = [&] {
break; if (userDataWritten || !userDataAtomSize) {
default: return;
// write buffered data
level1Atom->copyBuffer(outputStream);
level1Atom->discardBuffer();
}
} }
}
// -> write user data atom
if (userDataAtomSize) {
// writer user data atom header // writer user data atom header
Mp4Atom::makeHeader(userDataAtomSize, Mp4AtomIds::UserData, outputWriter); Mp4Atom::makeHeader(userDataAtomSize, Mp4AtomIds::UserData, outputWriter);
// write other children of user data atom // write children of user data atom
for (level0Atom = movieAtom; level0Atom; level0Atom = level0Atom->siblingById(Mp4AtomIds::Movie, diag)) { bool metaAtomWritten = false;
for (level1Atom = level0Atom->childById(Mp4AtomIds::UserData, diag); level1Atom; for (Mp4Atom *level0Atom = movieAtom; level0Atom; level0Atom = level0Atom->siblingById(Mp4AtomIds::Movie, diag)) {
for (Mp4Atom *level1Atom = level0Atom->childById(Mp4AtomIds::UserData, diag); level1Atom;
level1Atom = level1Atom->siblingById(Mp4AtomIds::UserData, diag)) { level1Atom = level1Atom->siblingById(Mp4AtomIds::UserData, diag)) {
for (level2Atom = level1Atom->firstChild(); level2Atom; level2Atom = level2Atom->nextSibling()) { for (Mp4Atom *level2Atom = level1Atom->firstChild(); level2Atom; level2Atom = level2Atom->nextSibling()) {
switch (level2Atom->id()) { switch (level2Atom->id()) {
case Mp4AtomIds::Meta: case Mp4AtomIds::Meta:
// write meta atom
for (auto &maker : tagMaker) {
maker.make(outputStream, diag);
}
metaAtomWritten = true;
break; break;
default: default:
// write buffered data // write buffered data
@ -634,12 +633,42 @@ calculatePadding:
} }
} }
// write meta atom // write meta atom if not already written
for (auto &maker : tagMaker) { if (!metaAtomWritten) {
maker.make(outputStream, diag); for (auto &maker : tagMaker) {
maker.make(outputStream, diag);
}
}
userDataWritten = true;
};
// write movie atom
// -> write movie atom header
Mp4Atom::makeHeader(movieAtomSize, Mp4AtomIds::Movie, outputWriter);
// -> write children of movie atom preserving the original order
for (level0Atom = movieAtom; level0Atom; level0Atom = level0Atom->siblingById(Mp4AtomIds::Movie, diag)) {
for (level1Atom = level0Atom->firstChild(); level1Atom; level1Atom = level1Atom->nextSibling()) {
switch (level1Atom->id()) {
case Mp4AtomIds::Track:
writeTracks();
break;
case Mp4AtomIds::UserData:
writeUserData();
break;
default:
// write buffered data
level1Atom->copyBuffer(outputStream);
level1Atom->discardBuffer();
}
} }
} }
// -> write tracks and user data atoms if not already happened within the loop
writeTracks();
writeUserData();
} else { } else {
// write padding // write padding
if (newPadding) { if (newPadding) {