mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1057225 - Fix MP4 timestamp discontinuities due to rounding; r=edwin
This commit is contained in:
parent
c6ef15ed08
commit
6199191782
@ -153,7 +153,7 @@ Index::ConvertByteRangesToTimeRanges(
|
||||
// We need the entire moof in order to play anything
|
||||
if (rangeFinder.Contains(moof.mRange)) {
|
||||
if (rangeFinder.Contains(moof.mMdatRange)) {
|
||||
timeRanges.AppendElements(moof.mTimeRanges);
|
||||
Interval<Microseconds>::SemiNormalAppend(timeRanges, moof.mTimeRange);
|
||||
} else {
|
||||
indexes.AppendElement(&moof.mIndex);
|
||||
}
|
||||
@ -199,7 +199,7 @@ Index::GetEvictionOffset(Microseconds aTime)
|
||||
for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) {
|
||||
Moof& moof = mMoofParser->mMoofs[i];
|
||||
|
||||
if (!moof.mTimeRanges.IsEmpty() && moof.mTimeRanges[0].end > aTime) {
|
||||
if (moof.mTimeRange.Length() && moof.mTimeRange.end > aTime) {
|
||||
offset = std::min(offset, uint64_t(std::min(moof.mRange.mStart,
|
||||
moof.mMdatRange.mStart)));
|
||||
}
|
||||
|
@ -21,7 +21,15 @@ MoofParser::RebuildFragmentedIndex(const nsTArray<MediaByteRange>& aByteRanges)
|
||||
if (box.IsType("moov")) {
|
||||
ParseMoov(box);
|
||||
} else if (box.IsType("moof")) {
|
||||
mMoofs.AppendElement(Moof(box, mTrex, mMdhd));
|
||||
Moof moof(box, mTrex, mMdhd);
|
||||
|
||||
if (!mMoofs.IsEmpty()) {
|
||||
// Stitch time ranges together in the case of a (hopefully small) time
|
||||
// range gap between moofs.
|
||||
mMoofs.LastElement().FixRounding(moof);
|
||||
}
|
||||
|
||||
mMoofs.AppendElement(moof);
|
||||
}
|
||||
mOffset = box.NextOffset();
|
||||
}
|
||||
@ -32,10 +40,7 @@ MoofParser::GetCompositionRange()
|
||||
{
|
||||
Interval<Microseconds> compositionRange;
|
||||
for (size_t i = 0; i < mMoofs.Length(); i++) {
|
||||
nsTArray<Interval<Microseconds>>& compositionRanges = mMoofs[i].mTimeRanges;
|
||||
for (int j = 0; j < compositionRanges.Length(); j++) {
|
||||
compositionRange = compositionRange.Extents(compositionRanges[j]);
|
||||
}
|
||||
compositionRange = compositionRange.Extents(mMoofs[i].mTimeRange);
|
||||
}
|
||||
return compositionRange;
|
||||
}
|
||||
@ -97,7 +102,8 @@ MoofParser::ParseMvex(Box& aBox)
|
||||
}
|
||||
}
|
||||
|
||||
Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd) : mRange(aBox.Range())
|
||||
Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd) :
|
||||
mRange(aBox.Range()), mMaxRoundingError(0)
|
||||
{
|
||||
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
|
||||
if (box.IsType("traf")) {
|
||||
@ -126,6 +132,28 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Moof::FixRounding(const Moof& aMoof) {
|
||||
Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
|
||||
if (gap > 0 && gap <= mMaxRoundingError) {
|
||||
mTimeRange.end = aMoof.mTimeRange.start;
|
||||
}
|
||||
}
|
||||
|
||||
class CtsComparator
|
||||
{
|
||||
public:
|
||||
bool Equals(Sample* const aA, Sample* const aB) const
|
||||
{
|
||||
return aA->mCompositionRange.start == aB->mCompositionRange.start;
|
||||
}
|
||||
bool
|
||||
LessThan(Sample* const aA, Sample* const aB) const
|
||||
{
|
||||
return aA->mCompositionRange.start < aB->mCompositionRange.start;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
||||
{
|
||||
@ -142,6 +170,10 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
||||
}
|
||||
|
||||
uint32_t sampleCount = reader->ReadU32();
|
||||
if (sampleCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
|
||||
bool hasFirstSampleFlags = flags & 4;
|
||||
uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0;
|
||||
@ -163,8 +195,8 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
||||
offset += sampleSize;
|
||||
|
||||
sample.mCompositionRange = Interval<Microseconds>(
|
||||
((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale,
|
||||
((decodeTime + sampleDuration + ctsOffset) * 1000000ll) / aMdhd.mTimescale);
|
||||
aMdhd.ToMicroseconds(decodeTime + ctsOffset),
|
||||
aMdhd.ToMicroseconds(decodeTime + ctsOffset + sampleDuration));
|
||||
decodeTime += sampleDuration;
|
||||
|
||||
sample.mSync = !(sampleFlags & 0x1010000);
|
||||
@ -172,10 +204,22 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
||||
mIndex.AppendElement(sample);
|
||||
|
||||
mMdatRange = mMdatRange.Extents(sample.mByteRange);
|
||||
Interval<Microseconds>::SemiNormalAppend(timeRanges,
|
||||
sample.mCompositionRange);
|
||||
}
|
||||
Interval<Microseconds>::Normalize(timeRanges, &mTimeRanges);
|
||||
mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount);
|
||||
|
||||
nsTArray<Sample*> ctsOrder;
|
||||
for (int i = 0; i < mIndex.Length(); i++) {
|
||||
ctsOrder.AppendElement(&mIndex[i]);
|
||||
}
|
||||
ctsOrder.Sort(CtsComparator());
|
||||
|
||||
for (int i = 0; i < ctsOrder.Length(); i++) {
|
||||
if (i + 1 < ctsOrder.Length()) {
|
||||
ctsOrder[i]->mCompositionRange.end = ctsOrder[i + 1]->mCompositionRange.start;
|
||||
}
|
||||
}
|
||||
mTimeRange = Interval<Microseconds>(ctsOrder[0]->mCompositionRange.start,
|
||||
ctsOrder.LastElement()->mCompositionRange.end);
|
||||
}
|
||||
|
||||
Tkhd::Tkhd(Box& aBox)
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define INDEX_H_
|
||||
|
||||
#include "media/stagefright/MediaSource.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mp4_demuxer/mp4_demuxer.h"
|
||||
|
||||
namespace mp4_demuxer
|
||||
|
@ -44,6 +44,11 @@ public:
|
||||
}
|
||||
Mdhd(Box& aBox);
|
||||
|
||||
Microseconds ToMicroseconds(uint64_t aTimescaleUnits)
|
||||
{
|
||||
return aTimescaleUnits * 1000000ll / mTimescale;
|
||||
}
|
||||
|
||||
uint64_t mCreationTime;
|
||||
uint64_t mModificationTime;
|
||||
uint32_t mTimescale;
|
||||
@ -102,13 +107,17 @@ 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);
|
||||
void FixRounding(const Moof& aMoof);
|
||||
|
||||
mozilla::MediaByteRange mRange;
|
||||
mozilla::MediaByteRange mMdatRange;
|
||||
nsTArray<Interval<Microseconds>> mTimeRanges;
|
||||
Interval<Microseconds> mTimeRange;
|
||||
nsTArray<Sample> mIndex;
|
||||
|
||||
private:
|
||||
void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd);
|
||||
void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd);
|
||||
uint64_t mMaxRoundingError;
|
||||
};
|
||||
|
||||
class MoofParser
|
||||
|
@ -253,7 +253,7 @@ MP4Demuxer::GetEvictionOffset(Microseconds aTime)
|
||||
for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
|
||||
offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime));
|
||||
}
|
||||
return offset;
|
||||
return offset == std::numeric_limits<uint64_t>::max() ? -1 : offset;
|
||||
}
|
||||
|
||||
} // namespace mp4_demuxer
|
||||
|
Loading…
Reference in New Issue
Block a user