Bug 1232313: [mp4] Use cumulative decode time if tfdt box is not present. r=kentuckyfriedtakahe
Per ISO 14496-12, the Track fragment decode time (tfdt) is optional.
MozReview-Commit-ID: LNrMPYlkDvt
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -41,17 +41,17 @@ MoofParser::RebuildFragmentedIndex(BoxCo
bool foundValidMoof = false;
bool foundMdat = false;
for (Box box(&aContext, mOffset); box.IsAvailable(); box = box.Next()) {
if (box.IsType("moov") && mInitRange.IsEmpty()) {
mInitRange = MediaByteRange(0, box.Range().mEnd);
ParseMoov(box);
} else if (box.IsType("moof")) {
- Moof moof(box, mTrex, mMvhd, mMdhd, mEdts, mSinf, mIsAudio);
+ Moof moof(box, mTrex, mMvhd, mMdhd, mEdts, mSinf, &mLastDecodeTime, mIsAudio);
if (!moof.IsValid() && !box.Next().IsAvailable()) {
// Moof isn't valid abort search for now.
break;
}
if (!mMoofs.IsEmpty()) {
// Stitch time ranges together in the case of a (hopefully small) time
@@ -341,23 +341,23 @@ MoofParser::ParseEncrypted(Box& aBox)
if (mSinf.IsValid()) {
break;
}
}
}
}
-Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio)
+Moof::Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
: mRange(aBox.Range())
, mMaxRoundingError(35000)
{
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("traf")) {
- ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aIsAudio);
+ ParseTraf(box, aTrex, aMvhd, aMdhd, aEdts, aSinf, aDecodeTime, aIsAudio);
}
}
if (IsValid()) {
ProcessCenc();
}
}
bool
@@ -420,18 +420,19 @@ Moof::ProcessCenc()
}
for (int i = 0; i < cencRanges.Length(); i++) {
mIndex[i].mCencRange = cencRanges[i];
}
return true;
}
void
-Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio)
+Moof::ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio)
{
+ MOZ_ASSERT(aDecodeTime);
Tfhd tfhd(aTrex);
Tfdt tfdt;
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("tfhd")) {
tfhd = Tfhd(box, aTrex);
} else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
if (box.IsType("tfdt")) {
tfdt = Tfdt(box);
@@ -440,32 +441,30 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex,
} else if (box.IsType("saio")) {
mSaios.AppendElement(Saio(box, aSinf.mDefaultEncryptionType));
}
}
}
if (aTrex.mTrackId && tfhd.mTrackId != aTrex.mTrackId) {
return;
}
- if (!tfdt.IsValid()) {
- LOG(Moof, "Invalid tfdt dependency");
- return;
- }
// Now search for TRUN boxes.
- uint64_t decodeTime = tfdt.mBaseMediaDecodeTime;
+ uint64_t decodeTime =
+ tfdt.IsValid() ? tfdt.mBaseMediaDecodeTime : *aDecodeTime;
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("trun")) {
if (ParseTrun(box, tfhd, aMvhd, aMdhd, aEdts, &decodeTime, aIsAudio)) {
mValid = true;
} else {
mValid = false;
break;
}
}
}
+ *aDecodeTime = decodeTime;
}
void
Moof::FixRounding(const Moof& aMoof) {
Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
if (gap > 0 && gap <= mMaxRoundingError) {
mTimeRange.end = aMoof.mTimeRange.start;
}
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -168,46 +168,48 @@ private:
int64_t mMoofOffset;
Saiz& mSaiz;
Saio& mSaio;
};
class Moof : public Atom
{
public:
- Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
+ Moof(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecoderTime, bool aIsAudio);
bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
void FixRounding(const Moof& aMoof);
mozilla::MediaByteRange mRange;
mozilla::MediaByteRange mMdatRange;
Interval<Microseconds> mTimeRange;
FallibleTArray<Sample> mIndex;
nsTArray<Saiz> mSaizs;
nsTArray<Saio> mSaios;
private:
- void ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
+ // aDecodeTime is updated to the end of the parsed TRAF on return.
+ void ParseTraf(Box& aBox, Trex& aTrex, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, uint64_t* aDecodeTime, bool aIsAudio);
// aDecodeTime is updated to the end of the parsed TRUN on return.
bool ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio);
void ParseSaiz(Box& aBox);
void ParseSaio(Box& aBox);
bool ProcessCenc();
uint64_t mMaxRoundingError;
};
class MoofParser
{
public:
MoofParser(Stream* aSource, uint32_t aTrackId, bool aIsAudio)
: mSource(aSource)
, mOffset(0)
, mTrex(aTrackId)
, mIsAudio(aIsAudio)
+ , mLastDecodeTime(0)
{
// Setting the mTrex.mTrackId to 0 is a nasty work around for calculating
// the composition range for MSE. We need an array of tracks.
}
bool RebuildFragmentedIndex(
const mozilla::MediaByteRangeSet& aByteRanges);
bool RebuildFragmentedIndex(BoxContext& aContext);
Interval<Microseconds> GetCompositionRange(
@@ -242,12 +244,13 @@ public:
Sinf mSinf;
nsTArray<Moof>& Moofs() { return mMoofs; }
private:
void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
mozilla::MediaByteRange& aMoov);
nsTArray<Moof> mMoofs;
nsTArray<MediaByteRange> mMediaRanges;
bool mIsAudio;
+ uint64_t mLastDecodeTime;
};
}
#endif