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/TimeStamp.h"
#include "nsThreadUtils.h"
#include <algorithm>
// 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;
};

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

@ -83,11 +83,16 @@ Index::Index(const stagefright::Vector<MediaSource::Indice>& aIndex,
}
}
Index::~Index() {}
void
Index::ConvertByteRangesToTimeRanges(
const nsTArray<MediaByteRange>& aByteRanges,
nsTArray<Interval<Microseconds>>* aTimeRanges)
{
RangeFinder rangeFinder(aByteRanges);
nsTArray<Interval<Microseconds>> timeRanges;
nsTArray<stagefright::MediaSource::Indice> moofIndex;
nsTArray<stagefright::MediaSource::Indice>* 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<Interval<Microseconds>> timeRanges;
RangeFinder rangeFinder(aByteRanges);
bool hasSync = false;
for (size_t i = 0; i < index->Length(); i++) {
const MediaSource::Indice& indice = (*index)[i];

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

@ -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<MediaByteRange>& 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<Interval<Microseconds>> 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<Microseconds>::SemiNormalAppend(
timeRanges,
Interval<Microseconds>(indice.start_composition, indice.end_composition));
}
Interval<Microseconds>::Normalize(timeRanges, &mTimeRanges);
}
Tkhd::Tkhd(Box& aBox)

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

@ -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

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

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

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

@ -41,6 +41,17 @@ struct Interval
T start;
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,
nsTArray<Interval<T>>* aNormalized)
{

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

@ -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<Interval<Microseconds>> mTimeRanges;
nsTArray<stagefright::MediaSource::Indice> 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<Stream> mSource;
uint32_t mTrackId;
uint64_t mOffset;
nsTArray<uint64_t> mMoofOffsets;
Mdhd mMdhd;
Trex mTrex;
Tfdt mTfdt;
nsTArray<stagefright::MediaSource::Indice> mIndex;
nsTArray<Moof> mMoofs;
};
}