зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1050060 - Optimise MP4 range calculation; r=edwin
This commit is contained in:
Родитель
4f53a7c1a6
Коммит
2c2bccb36d
|
@ -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,9 +47,11 @@ 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")) {
|
||||||
|
if (tkhd.mTrackId == mTrex.mTrackId) {
|
||||||
ParseMdia(box, tkhd);
|
ParseMdia(box, tkhd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -83,11 +59,9 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче