Apply MP4 track meta-data also when not writing chunk-by-chunk
This commit is contained in:
parent
03383a18b9
commit
f323061767
|
@ -393,11 +393,7 @@ void Mp4Container::internalMakeFile()
|
|||
}
|
||||
break;
|
||||
case Mp4AtomIds::Track:
|
||||
// add size of track atoms only if not writing chunk-by-chunk (otherwise sizes are added separately)
|
||||
if(!writeChunkByChunk) {
|
||||
movieAtomSize += level1Atom->totalSize();
|
||||
level1Atom->makeBuffer();
|
||||
}
|
||||
// ignore track atoms here; they are added separately
|
||||
break;
|
||||
default:
|
||||
// add size of unknown childs of the movie atom
|
||||
|
@ -413,12 +409,9 @@ void Mp4Container::internalMakeFile()
|
|||
movieAtomSize += userDataAtomSize;
|
||||
}
|
||||
|
||||
// add size of track atoms when writing chunk-by-chunk
|
||||
if(writeChunkByChunk) {
|
||||
// note: Mp4Track API has to be changed when Mp4Track::makeTrack() gets a real implementation.
|
||||
for(const auto &track : tracks()) {
|
||||
movieAtomSize += track->requiredSize();
|
||||
}
|
||||
// add size of track atoms
|
||||
for(const auto &track : tracks()) {
|
||||
movieAtomSize += track->requiredSize();
|
||||
}
|
||||
|
||||
// add header size
|
||||
|
@ -555,6 +548,11 @@ calculatePadding:
|
|||
// TODO: reduce code duplication
|
||||
|
||||
} else { // !rewriteRequired
|
||||
// ensure everything to make track atoms is buffered before altering the source file
|
||||
for(const auto &track : tracks()) {
|
||||
track->bufferTrackAtoms();
|
||||
}
|
||||
|
||||
// reopen original file to ensure it is opened for writing
|
||||
try {
|
||||
fileInfo().close();
|
||||
|
@ -596,12 +594,9 @@ calculatePadding:
|
|||
// -> write movie atom header
|
||||
Mp4Atom::makeHeader(movieAtomSize, Mp4AtomIds::Movie, outputWriter);
|
||||
|
||||
// -> write track atoms (only if writing chunk-by-chunk; otherwise track atoms are written with other children)
|
||||
if(writeChunkByChunk) {
|
||||
// note: Mp4Track API has to be changed when Mp4Track::makeTrack() gets a real implementation.
|
||||
for(auto &track : tracks()) {
|
||||
track->makeTrack();
|
||||
}
|
||||
// -> write track atoms
|
||||
for(auto &track : tracks()) {
|
||||
track->makeTrack();
|
||||
}
|
||||
|
||||
// -> write other movie atom children
|
||||
|
@ -609,13 +604,8 @@ calculatePadding:
|
|||
for(level1Atom = level0Atom->firstChild(); level1Atom; level1Atom = level1Atom->nextSibling()) {
|
||||
switch(level1Atom->id()) {
|
||||
case Mp4AtomIds::UserData:
|
||||
break;
|
||||
case Mp4AtomIds::Track:
|
||||
// write buffered data
|
||||
if(!writeChunkByChunk) {
|
||||
level1Atom->copyBuffer(outputStream);
|
||||
level1Atom->discardBuffer();
|
||||
}
|
||||
// track and user data atoms are written separately
|
||||
break;
|
||||
default:
|
||||
// write buffered data
|
||||
|
|
|
@ -928,10 +928,47 @@ void Mp4Track::addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track)
|
|||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Buffers all atoms required by the makeTrack() method.
|
||||
*
|
||||
* This allows to invoke makeTrack() also when the input stream is going to be
|
||||
* modified (eg. to apply changed tags without rewriting the file).
|
||||
*/
|
||||
void Mp4Track::bufferTrackAtoms()
|
||||
{
|
||||
if(m_tkhdAtom) {
|
||||
m_tkhdAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *trefAtom = m_trakAtom->childById(Mp4AtomIds::TrackReference)) {
|
||||
trefAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *edtsAtom = m_trakAtom->childById(Mp4AtomIds::Edit)) {
|
||||
edtsAtom->makeBuffer();
|
||||
}
|
||||
if(m_minfAtom) {
|
||||
if(Mp4Atom *vmhdAtom = m_minfAtom->childById(Mp4AtomIds::VideoMediaHeader)) {
|
||||
vmhdAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *smhdAtom = m_minfAtom->childById(Mp4AtomIds::SoundMediaHeader)) {
|
||||
smhdAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *hmhdAtom = m_minfAtom->childById(Mp4AtomIds::HintMediaHeader)) {
|
||||
hmhdAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *nmhdAtom = m_minfAtom->childById(Mp4AtomIds::NullMediaHeaderBox)) {
|
||||
nmhdAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *dinfAtom = m_minfAtom->childById(Mp4AtomIds::DataInformation)) {
|
||||
dinfAtom->makeBuffer();
|
||||
}
|
||||
if(Mp4Atom *stblAtom = m_minfAtom->childById(Mp4AtomIds::SampleTable)) {
|
||||
stblAtom->makeBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of bytes written when calling makeTrack().
|
||||
* \todo Get rid of const_cast. This is currently required because GenericFileElement::childById() is
|
||||
* not const.
|
||||
*/
|
||||
uint64 Mp4Track::requiredSize() const
|
||||
{
|
||||
|
@ -978,9 +1015,12 @@ uint64 Mp4Track::requiredSize() const
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the track entry ("trak"-atom) for the track. The data is written to the assigned output stream
|
||||
* at the current position.
|
||||
* \remarks Currently the "trak"-atom from the source file is just copied to the output stream.
|
||||
* \brief Makes the track entry ("trak"-atom) for the track.
|
||||
*
|
||||
* The data is written to the assigned output stream at the current position. Note that this method
|
||||
* uses the assigned input stream to copy some parts from the source file. Hence the input stream must
|
||||
* still be valid when calling this method. To avoid this limitation call bufferTrackAtoms() before
|
||||
* invalidating the input stream.
|
||||
*/
|
||||
void Mp4Track::makeTrack()
|
||||
{
|
||||
|
@ -992,11 +1032,11 @@ void Mp4Track::makeTrack()
|
|||
makeTrackHeader();
|
||||
// write tref atom (if one exists)
|
||||
if(Mp4Atom *trefAtom = trakAtom().childById(Mp4AtomIds::TrackReference)) {
|
||||
trefAtom->copyEntirely(outputStream());
|
||||
trefAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// write edts atom (if one exists)
|
||||
if(Mp4Atom *edtsAtom = trakAtom().childById(Mp4AtomIds::Edit)) {
|
||||
edtsAtom->copyEntirely(outputStream());
|
||||
edtsAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// write mdia atom
|
||||
makeMedia();
|
||||
|
@ -1033,17 +1073,21 @@ void Mp4Track::makeTrackHeader()
|
|||
writer().writeUInt32BE(0); // reserved
|
||||
if(m_tkhdAtom) {
|
||||
// use existing values
|
||||
char buffer[48];
|
||||
m_istream->seekg(m_tkhdAtom->startOffset() + 52);
|
||||
m_istream->read(buffer, sizeof(buffer));
|
||||
m_ostream->write(buffer, sizeof(buffer));
|
||||
if(m_tkhdAtom->buffer()) {
|
||||
m_ostream->write(m_tkhdAtom->buffer().get() + 52, 48);
|
||||
} else {
|
||||
char buffer[48];
|
||||
m_istream->seekg(m_tkhdAtom->startOffset() + 52);
|
||||
m_istream->read(buffer, sizeof(buffer));
|
||||
m_ostream->write(buffer, sizeof(buffer));
|
||||
}
|
||||
} else {
|
||||
// write default values
|
||||
writer().writeInt16BE(0); // layer
|
||||
writer().writeInt16BE(0); // alternate group
|
||||
writer().writeFixed8BE(1.0); // volume
|
||||
writer().writeUInt16BE(0); // reserved
|
||||
for(int32 value : {0x00010000,0,0,0,0x00010000,0,0,0,0x40000000}) { // unity matrix
|
||||
for(const int32 value : {0x00010000,0,0,0,0x00010000,0,0,0,0x40000000}) { // unity matrix
|
||||
writer().writeInt32BE(value);
|
||||
}
|
||||
writer().writeFixed16BE(1.0); // width
|
||||
|
@ -1126,23 +1170,23 @@ void Mp4Track::makeMediaInfo()
|
|||
if(m_minfAtom) {
|
||||
// copy existing vmhd atom
|
||||
if(Mp4Atom *vmhdAtom = m_minfAtom->childById(Mp4AtomIds::VideoMediaHeader)) {
|
||||
vmhdAtom->copyEntirely(outputStream());
|
||||
vmhdAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// copy existing smhd atom
|
||||
if(Mp4Atom *smhdAtom = m_minfAtom->childById(Mp4AtomIds::SoundMediaHeader)) {
|
||||
smhdAtom->copyEntirely(outputStream());
|
||||
smhdAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// copy existing hmhd atom
|
||||
if(Mp4Atom *hmhdAtom = m_minfAtom->childById(Mp4AtomIds::HintMediaHeader)) {
|
||||
hmhdAtom->copyEntirely(outputStream());
|
||||
hmhdAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// copy existing nmhd atom
|
||||
if(Mp4Atom *nmhdAtom = m_minfAtom->childById(Mp4AtomIds::NullMediaHeaderBox)) {
|
||||
nmhdAtom->copyEntirely(outputStream());
|
||||
nmhdAtom->copyPreferablyFromBuffer(outputStream());
|
||||
}
|
||||
// copy existing dinf atom
|
||||
if(Mp4Atom *dinfAtom = m_minfAtom->childById(Mp4AtomIds::DataInformation)) {
|
||||
dinfAtom->copyEntirely(outputStream());
|
||||
dinfAtom->copyPreferablyFromBuffer(outputStream());
|
||||
dinfAtomWritten = true;
|
||||
}
|
||||
}
|
||||
|
@ -1166,13 +1210,12 @@ void Mp4Track::makeMediaInfo()
|
|||
bool stblAtomWritten = false;
|
||||
if(m_minfAtom) {
|
||||
if(Mp4Atom *stblAtom = m_minfAtom->childById(Mp4AtomIds::SampleTable)) {
|
||||
stblAtom->copyEntirely(outputStream());
|
||||
stblAtom->copyPreferablyFromBuffer(outputStream());
|
||||
stblAtomWritten = true;
|
||||
}
|
||||
}
|
||||
if(!stblAtomWritten) {
|
||||
addNotification(NotificationType::Critical, "Unable to make stbl atom from scratch.", "making stbl atom");
|
||||
throw NotImplementedException();
|
||||
addNotification(NotificationType::Critical, "Source track does not contain mandatory stbl atom and the tagparser lib is unable to make one from scratch.", "making stbl atom");
|
||||
}
|
||||
// write size (of minf atom)
|
||||
Mp4Atom::seekBackAndWriteAtomSize(outputStream(), minfStartOffset);
|
||||
|
|
|
@ -144,8 +144,9 @@ public:
|
|||
std::vector<uint64> readChunkSizes();
|
||||
|
||||
// methods to make the track header
|
||||
void makeTrack();
|
||||
void bufferTrackAtoms();
|
||||
uint64 requiredSize() const;
|
||||
void makeTrack();
|
||||
void makeTrackHeader();
|
||||
void makeMedia();
|
||||
void makeMediaInfo();
|
||||
|
@ -177,8 +178,6 @@ private:
|
|||
Mp4Atom *m_stscAtom;
|
||||
Mp4Atom *m_stcoAtom;
|
||||
Mp4Atom *m_stszAtom;
|
||||
//Mp4Atom *m_codecConfigAtom;
|
||||
//Mp4Atom *m_esDescAtom;
|
||||
uint16 m_framesPerSample;
|
||||
std::vector<uint32> m_sampleSizes;
|
||||
unsigned int m_chunkOffsetSize;
|
||||
|
|
Loading…
Reference in New Issue