From 2c2bccb36d3138003b417719ab4b574627602484 Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Wed, 13 Aug 2014 17:13:28 +1200 Subject: [PATCH] Bug 1050060 - Optimise MP4 range calculation; r=edwin --- content/media/MediaResource.h | 7 ++ media/libstagefright/binding/Index.cpp | 18 +++- media/libstagefright/binding/MoofParser.cpp | 87 ++++++++----------- .../binding/include/mp4_demuxer/Box.h | 3 + .../binding/include/mp4_demuxer/Index.h | 2 + .../binding/include/mp4_demuxer/Interval.h | 11 +++ .../binding/include/mp4_demuxer/MoofParser.h | 27 ++++-- 7 files changed, 95 insertions(+), 60 deletions(-) diff --git a/content/media/MediaResource.h b/content/media/MediaResource.h index f386df90de1d..12892b25d3c5 100644 --- a/content/media/MediaResource.h +++ b/content/media/MediaResource.h @@ -17,6 +17,7 @@ #include "mozilla/Attributes.h" #include "mozilla/TimeStamp.h" #include "nsThreadUtils.h" +#include // For HTTP seeking, if number of bytes needing to be // seeked forward is less than this value then a read is @@ -151,6 +152,12 @@ public: return aByteRange.mStart >= mStart && aByteRange.mEnd <= mEnd; } + MediaByteRange Extents(const MediaByteRange& aByteRange) const + { + return MediaByteRange(std::min(mStart, aByteRange.mStart), + std::max(mEnd, aByteRange.mEnd)); + } + int64_t mStart, mEnd; }; diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 75e2374dc095..eaed3b2c16f0 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -83,11 +83,16 @@ Index::Index(const stagefright::Vector& aIndex, } } +Index::~Index() {} + void Index::ConvertByteRangesToTimeRanges( const nsTArray& aByteRanges, nsTArray>* aTimeRanges) { + RangeFinder rangeFinder(aByteRanges); + nsTArray> timeRanges; + nsTArray moofIndex; nsTArray* index; if (mMoofParser) { @@ -98,16 +103,21 @@ Index::ConvertByteRangesToTimeRanges( // We take the index out of the moof parser and move it into a local // variable so we don't get concurrency issues. It gets freed when we // exit this function. - moofIndex = mMoofParser->mIndex; + for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) { + Moof& moof = mMoofParser->mMoofs[i]; + if (rangeFinder.Contains(moof.mRange) && + rangeFinder.Contains(moof.mMdatRange)) { + timeRanges.AppendElements(moof.mTimeRanges); + } else { + moofIndex.AppendElements(mMoofParser->mMoofs[i].mIndex); + } + } } index = &moofIndex; } else { index = &mIndex; } - nsTArray> timeRanges; - RangeFinder rangeFinder(aByteRanges); - bool hasSync = false; for (size_t i = 0; i < index->Length(); i++) { const MediaSource::Indice& indice = (*index)[i]; diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 45625bd4fb5c..89bf631b83a0 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -4,52 +4,26 @@ #include "mp4_demuxer/MoofParser.h" #include "mp4_demuxer/Box.h" -#include "MediaResource.h" - -using namespace stagefright; -using namespace mozilla; namespace mp4_demuxer { -class Moof -{ -public: - Moof(Box& aBox, MoofParser* aMoofParser); - void ParseTraf(Box& aBox); - void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt); - -private: - MoofParser* mMoofParser; -}; +using namespace stagefright; +using namespace mozilla; void MoofParser::RebuildFragmentedIndex(const nsTArray& aByteRanges) { BoxContext context(mSource, aByteRanges); - mIndex.Clear(); - size_t moofCount = 0; - for (size_t i = 0; i + 1 < mMoofOffsets.Length(); i++) { - Box box(&context, mMoofOffsets[i]); - if (box.IsAvailable()) { - MOZ_ASSERT(box.IsType("moof")); - Moof(box, this); - } - } - for (Box box = mMoofOffsets.IsEmpty() - ? Box(&context, 0) - : Box(&context, mMoofOffsets.LastElement()); - box.IsAvailable(); box = box.Next()) { + Box box(&context, mOffset); + for (; box.IsAvailable(); box = box.Next()) { if (box.IsType("moov")) { ParseMoov(box); } else if (box.IsType("moof")) { - if (mMoofOffsets.IsEmpty() || - mMoofOffsets.LastElement() != box.Offset()) { - mMoofOffsets.AppendElement(box.Offset()); - } - Moof(box, this); + mMoofs.AppendElement(Moof(box, mTrex, mMdhd)); } + mOffset = box.NextOffset(); } } @@ -73,7 +47,9 @@ MoofParser::ParseTrak(Box& aBox) if (box.IsType("tkhd")) { tkhd = Tkhd(box); } else if (box.IsType("mdia")) { - ParseMdia(box, tkhd); + if (tkhd.mTrackId == mTrex.mTrackId) { + ParseMdia(box, tkhd); + } } } } @@ -83,9 +59,7 @@ MoofParser::ParseMdia(Box& aBox, Tkhd& aTkhd) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("mdhd")) { - if (mTrackId == aTkhd.mTrackId) { - mMdhd = Mdhd(box); - } + mMdhd = Mdhd(box); } } } @@ -95,42 +69,45 @@ MoofParser::ParseMvex(Box& aBox) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("trex")) { - mTrex = Trex(box); + Trex trex = Trex(box); + if (trex.mTrackId == mTrex.mTrackId) { + mTrex = trex; + } } } } -Moof::Moof(Box& aBox, MoofParser* aMoofParser) : mMoofParser(aMoofParser) +Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd) : mRange(aBox.Range()) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("traf")) { - ParseTraf(box); + ParseTraf(box, aTrex, aMdhd); } } } void -Moof::ParseTraf(Box& aBox) +Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd) { - Tfhd tfhd(mMoofParser->mTrex); + Tfhd tfhd(aTrex); Tfdt tfdt; for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { if (box.IsType("tfhd")) { - tfhd = Tfhd(box, mMoofParser->mTrex); + tfhd = Tfhd(box, aTrex); } else if (box.IsType("tfdt")) { tfdt = Tfdt(box); } else if (box.IsType("trun")) { - if (mMoofParser->mTrackId == tfhd.mTrackId) { - ParseTrun(box, tfhd, tfdt); + if (tfhd.mTrackId == aTrex.mTrackId) { + ParseTrun(box, tfhd, tfdt, aMdhd); } } } } void -Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt) +Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd) { - if (!mMoofParser->mMdhd.mTimescale) { + if (!aMdhd.mTimescale) { return; } @@ -147,6 +124,7 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt) bool hasFirstSampleFlags = flags & 4; uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0; uint64_t decodeTime = aTfdt.mBaseMediaDecodeTime; + nsTArray> timeRanges; for (size_t i = 0; i < sampleCount; i++) { uint32_t sampleDuration = flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration; @@ -164,15 +142,26 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt) indice.end_offset = offset; indice.start_composition = - ((decodeTime + ctsOffset) * 1000000ll) / mMoofParser->mMdhd.mTimescale; + ((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale; decodeTime += sampleDuration; indice.end_composition = - ((decodeTime + ctsOffset) * 1000000ll) / mMoofParser->mMdhd.mTimescale; + ((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale; indice.sync = !(sampleFlags & 0x1010000); - mMoofParser->mIndex.AppendElement(indice); + mIndex.AppendElement(indice); + + MediaByteRange compositionRange(indice.start_offset, indice.end_offset); + if (mMdatRange.IsNull()) { + mMdatRange = compositionRange; + } else { + mMdatRange = mMdatRange.Extents(compositionRange); + } + Interval::SemiNormalAppend( + timeRanges, + Interval(indice.start_composition, indice.end_composition)); } + Interval::Normalize(timeRanges, &mTimeRanges); } Tkhd::Tkhd(Box& aBox) diff --git a/media/libstagefright/binding/include/mp4_demuxer/Box.h b/media/libstagefright/binding/include/mp4_demuxer/Box.h index c5dbf600bd0d..d0cb81ae5f48 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Box.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h @@ -39,6 +39,9 @@ public: bool IsAvailable() const { return !mRange.IsNull(); } uint64_t Offset() const { return mRange.mStart; } uint64_t Length() const { return mRange.mEnd - mRange.mStart; } + uint64_t NextOffset() const { return mRange.mEnd; } + const MediaByteRange& Range() const { return mRange; } + const Box* Parent() const { return mParent; } bool IsType(const char* aType) const diff --git a/media/libstagefright/binding/include/mp4_demuxer/Index.h b/media/libstagefright/binding/include/mp4_demuxer/Index.h index 81bb23824ade..618a905d4c75 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Index.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h @@ -20,6 +20,8 @@ class Index public: Index(const stagefright::Vector& aIndex, Stream* aSource, uint32_t aTrackId); + ~Index(); + void ConvertByteRangesToTimeRanges( const nsTArray& aByteRanges, nsTArray>* aTimeRanges); diff --git a/media/libstagefright/binding/include/mp4_demuxer/Interval.h b/media/libstagefright/binding/include/mp4_demuxer/Interval.h index 2e16c675b66a..61268acdb8a4 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Interval.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Interval.h @@ -41,6 +41,17 @@ struct Interval T start; T end; + static void SemiNormalAppend(nsTArray>& aIntervals, + Interval aInterval) + { + if (!aIntervals.IsEmpty() && + aIntervals.LastElement().end == aInterval.start) { + aIntervals.LastElement().end = aInterval.end; + } else { + aIntervals.AppendElement(aInterval); + } + } + static void Normalize(const nsTArray>& aIntervals, nsTArray>* aNormalized) { diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 25d5074cf7c5..2f0cbdef7476 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -7,13 +7,13 @@ #include "media/stagefright/MediaSource.h" #include "mp4_demuxer/mp4_demuxer.h" - -namespace mozilla { class MediaByteRange; } +#include "MediaResource.h" namespace mp4_demuxer { class Stream; class Box; +class Moof; class Tkhd { @@ -54,9 +54,9 @@ public: class Trex { public: - Trex() + Trex(uint32_t aTrackId) : mFlags(0) - , mTrackId(0) + , mTrackId(aTrackId) , mDefaultSampleDescriptionIndex(0) , mDefaultSampleDuration(0) , mDefaultSampleSize(0) @@ -92,11 +92,24 @@ public: uint64_t mBaseMediaDecodeTime; }; +class Moof +{ +public: + Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd); + void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd); + void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd); + + mozilla::MediaByteRange mRange; + mozilla::MediaByteRange mMdatRange; + nsTArray> mTimeRanges; + nsTArray mIndex; +}; + class MoofParser { public: MoofParser(Stream* aSource, uint32_t aTrackId) - : mSource(aSource), mTrackId(aTrackId) + : mSource(aSource), mOffset(0), mTrex(aTrackId) { } void RebuildFragmentedIndex( @@ -107,12 +120,12 @@ public: void ParseMvex(Box& aBox); nsRefPtr mSource; - uint32_t mTrackId; + uint64_t mOffset; nsTArray mMoofOffsets; Mdhd mMdhd; Trex mTrex; Tfdt mTfdt; - nsTArray mIndex; + nsTArray mMoofs; }; }