Bug 1050060 - Optimise MP4 range calculation; r=edwin

This commit is contained in:
Anthony Jones 2014-08-13 17:13:28 +12:00
Родитель 4f53a7c1a6
Коммит 2c2bccb36d
7 изменённых файлов: 95 добавлений и 60 удалений

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include <algorithm>
// For HTTP seeking, if number of bytes needing to be // For HTTP seeking, if number of bytes needing to be
// seeked forward is less than this value then a read is // seeked forward is less than this value then a read is
@ -151,6 +152,12 @@ public:
return aByteRange.mStart >= mStart && aByteRange.mEnd <= mEnd; 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; int64_t mStart, mEnd;
}; };

Просмотреть файл

@ -83,11 +83,16 @@ Index::Index(const stagefright::Vector<MediaSource::Indice>& aIndex,
} }
} }
Index::~Index() {}
void void
Index::ConvertByteRangesToTimeRanges( Index::ConvertByteRangesToTimeRanges(
const nsTArray<MediaByteRange>& aByteRanges, const nsTArray<MediaByteRange>& aByteRanges,
nsTArray<Interval<Microseconds>>* aTimeRanges) nsTArray<Interval<Microseconds>>* aTimeRanges)
{ {
RangeFinder rangeFinder(aByteRanges);
nsTArray<Interval<Microseconds>> timeRanges;
nsTArray<stagefright::MediaSource::Indice> moofIndex; nsTArray<stagefright::MediaSource::Indice> moofIndex;
nsTArray<stagefright::MediaSource::Indice>* index; nsTArray<stagefright::MediaSource::Indice>* index;
if (mMoofParser) { if (mMoofParser) {
@ -98,16 +103,21 @@ Index::ConvertByteRangesToTimeRanges(
// We take the index out of the moof parser and move it into a local // 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 // variable so we don't get concurrency issues. It gets freed when we
// exit this function. // 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; index = &moofIndex;
} else { } else {
index = &mIndex; index = &mIndex;
} }
nsTArray<Interval<Microseconds>> timeRanges;
RangeFinder rangeFinder(aByteRanges);
bool hasSync = false; bool hasSync = false;
for (size_t i = 0; i < index->Length(); i++) { for (size_t i = 0; i < index->Length(); i++) {
const MediaSource::Indice& indice = (*index)[i]; const MediaSource::Indice& indice = (*index)[i];

Просмотреть файл

@ -4,52 +4,26 @@
#include "mp4_demuxer/MoofParser.h" #include "mp4_demuxer/MoofParser.h"
#include "mp4_demuxer/Box.h" #include "mp4_demuxer/Box.h"
#include "MediaResource.h"
using namespace stagefright;
using namespace mozilla;
namespace mp4_demuxer namespace mp4_demuxer
{ {
class Moof using namespace stagefright;
{ using namespace mozilla;
public:
Moof(Box& aBox, MoofParser* aMoofParser);
void ParseTraf(Box& aBox);
void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt);
private:
MoofParser* mMoofParser;
};
void void
MoofParser::RebuildFragmentedIndex(const nsTArray<MediaByteRange>& aByteRanges) MoofParser::RebuildFragmentedIndex(const nsTArray<MediaByteRange>& aByteRanges)
{ {
BoxContext context(mSource, aByteRanges); BoxContext context(mSource, aByteRanges);
mIndex.Clear(); Box box(&context, mOffset);
size_t moofCount = 0; for (; box.IsAvailable(); box = box.Next()) {
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()) {
if (box.IsType("moov")) { if (box.IsType("moov")) {
ParseMoov(box); ParseMoov(box);
} else if (box.IsType("moof")) { } else if (box.IsType("moof")) {
if (mMoofOffsets.IsEmpty() || mMoofs.AppendElement(Moof(box, mTrex, mMdhd));
mMoofOffsets.LastElement() != box.Offset()) {
mMoofOffsets.AppendElement(box.Offset());
}
Moof(box, this);
} }
mOffset = box.NextOffset();
} }
} }
@ -73,7 +47,9 @@ MoofParser::ParseTrak(Box& aBox)
if (box.IsType("tkhd")) { if (box.IsType("tkhd")) {
tkhd = Tkhd(box); tkhd = Tkhd(box);
} else if (box.IsType("mdia")) { } 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()) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("mdhd")) { 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()) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("trex")) { 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()) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("traf")) { if (box.IsType("traf")) {
ParseTraf(box); ParseTraf(box, aTrex, aMdhd);
} }
} }
} }
void void
Moof::ParseTraf(Box& aBox) Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd)
{ {
Tfhd tfhd(mMoofParser->mTrex); Tfhd tfhd(aTrex);
Tfdt tfdt; Tfdt tfdt;
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) { for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
if (box.IsType("tfhd")) { if (box.IsType("tfhd")) {
tfhd = Tfhd(box, mMoofParser->mTrex); tfhd = Tfhd(box, aTrex);
} else if (box.IsType("tfdt")) { } else if (box.IsType("tfdt")) {
tfdt = Tfdt(box); tfdt = Tfdt(box);
} else if (box.IsType("trun")) { } else if (box.IsType("trun")) {
if (mMoofParser->mTrackId == tfhd.mTrackId) { if (tfhd.mTrackId == aTrex.mTrackId) {
ParseTrun(box, tfhd, tfdt); ParseTrun(box, tfhd, tfdt, aMdhd);
} }
} }
} }
} }
void 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; return;
} }
@ -147,6 +124,7 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt)
bool hasFirstSampleFlags = flags & 4; bool hasFirstSampleFlags = flags & 4;
uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0; uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0;
uint64_t decodeTime = aTfdt.mBaseMediaDecodeTime; uint64_t decodeTime = aTfdt.mBaseMediaDecodeTime;
nsTArray<Interval<Microseconds>> timeRanges;
for (size_t i = 0; i < sampleCount; i++) { for (size_t i = 0; i < sampleCount; i++) {
uint32_t sampleDuration = uint32_t sampleDuration =
flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration; flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration;
@ -164,15 +142,26 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt)
indice.end_offset = offset; indice.end_offset = offset;
indice.start_composition = indice.start_composition =
((decodeTime + ctsOffset) * 1000000ll) / mMoofParser->mMdhd.mTimescale; ((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale;
decodeTime += sampleDuration; decodeTime += sampleDuration;
indice.end_composition = indice.end_composition =
((decodeTime + ctsOffset) * 1000000ll) / mMoofParser->mMdhd.mTimescale; ((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale;
indice.sync = !(sampleFlags & 0x1010000); 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<Microseconds>::SemiNormalAppend(
timeRanges,
Interval<Microseconds>(indice.start_composition, indice.end_composition));
} }
Interval<Microseconds>::Normalize(timeRanges, &mTimeRanges);
} }
Tkhd::Tkhd(Box& aBox) Tkhd::Tkhd(Box& aBox)

Просмотреть файл

@ -39,6 +39,9 @@ public:
bool IsAvailable() const { return !mRange.IsNull(); } bool IsAvailable() const { return !mRange.IsNull(); }
uint64_t Offset() const { return mRange.mStart; } uint64_t Offset() const { return mRange.mStart; }
uint64_t Length() const { return mRange.mEnd - 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; } const Box* Parent() const { return mParent; }
bool IsType(const char* aType) const bool IsType(const char* aType) const

Просмотреть файл

@ -20,6 +20,8 @@ class Index
public: public:
Index(const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex, Index(const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex,
Stream* aSource, uint32_t aTrackId); Stream* aSource, uint32_t aTrackId);
~Index();
void ConvertByteRangesToTimeRanges( void ConvertByteRangesToTimeRanges(
const nsTArray<mozilla::MediaByteRange>& aByteRanges, const nsTArray<mozilla::MediaByteRange>& aByteRanges,
nsTArray<Interval<Microseconds>>* aTimeRanges); nsTArray<Interval<Microseconds>>* aTimeRanges);

Просмотреть файл

@ -41,6 +41,17 @@ struct Interval
T start; T start;
T end; T end;
static void SemiNormalAppend(nsTArray<Interval<T>>& aIntervals,
Interval<T> aInterval)
{
if (!aIntervals.IsEmpty() &&
aIntervals.LastElement().end == aInterval.start) {
aIntervals.LastElement().end = aInterval.end;
} else {
aIntervals.AppendElement(aInterval);
}
}
static void Normalize(const nsTArray<Interval<T>>& aIntervals, static void Normalize(const nsTArray<Interval<T>>& aIntervals,
nsTArray<Interval<T>>* aNormalized) nsTArray<Interval<T>>* aNormalized)
{ {

Просмотреть файл

@ -7,13 +7,13 @@
#include "media/stagefright/MediaSource.h" #include "media/stagefright/MediaSource.h"
#include "mp4_demuxer/mp4_demuxer.h" #include "mp4_demuxer/mp4_demuxer.h"
#include "MediaResource.h"
namespace mozilla { class MediaByteRange; }
namespace mp4_demuxer { namespace mp4_demuxer {
class Stream; class Stream;
class Box; class Box;
class Moof;
class Tkhd class Tkhd
{ {
@ -54,9 +54,9 @@ public:
class Trex class Trex
{ {
public: public:
Trex() Trex(uint32_t aTrackId)
: mFlags(0) : mFlags(0)
, mTrackId(0) , mTrackId(aTrackId)
, mDefaultSampleDescriptionIndex(0) , mDefaultSampleDescriptionIndex(0)
, mDefaultSampleDuration(0) , mDefaultSampleDuration(0)
, mDefaultSampleSize(0) , mDefaultSampleSize(0)
@ -92,11 +92,24 @@ public:
uint64_t mBaseMediaDecodeTime; 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<Interval<Microseconds>> mTimeRanges;
nsTArray<stagefright::MediaSource::Indice> mIndex;
};
class MoofParser class MoofParser
{ {
public: public:
MoofParser(Stream* aSource, uint32_t aTrackId) MoofParser(Stream* aSource, uint32_t aTrackId)
: mSource(aSource), mTrackId(aTrackId) : mSource(aSource), mOffset(0), mTrex(aTrackId)
{ {
} }
void RebuildFragmentedIndex( void RebuildFragmentedIndex(
@ -107,12 +120,12 @@ public:
void ParseMvex(Box& aBox); void ParseMvex(Box& aBox);
nsRefPtr<Stream> mSource; nsRefPtr<Stream> mSource;
uint32_t mTrackId; uint64_t mOffset;
nsTArray<uint64_t> mMoofOffsets; nsTArray<uint64_t> mMoofOffsets;
Mdhd mMdhd; Mdhd mMdhd;
Trex mTrex; Trex mTrex;
Tfdt mTfdt; Tfdt mTfdt;
nsTArray<stagefright::MediaSource::Indice> mIndex; nsTArray<Moof> mMoofs;
}; };
} }