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
|
// We need the entire moof in order to play anything
|
||||||
if (rangeFinder.Contains(moof.mRange)) {
|
if (rangeFinder.Contains(moof.mRange)) {
|
||||||
if (rangeFinder.Contains(moof.mMdatRange)) {
|
if (rangeFinder.Contains(moof.mMdatRange)) {
|
||||||
timeRanges.AppendElements(moof.mTimeRanges);
|
Interval<Microseconds>::SemiNormalAppend(timeRanges, moof.mTimeRange);
|
||||||
} else {
|
} else {
|
||||||
indexes.AppendElement(&moof.mIndex);
|
indexes.AppendElement(&moof.mIndex);
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ Index::GetEvictionOffset(Microseconds aTime)
|
|||||||
for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) {
|
for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) {
|
||||||
Moof& moof = mMoofParser->mMoofs[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,
|
offset = std::min(offset, uint64_t(std::min(moof.mRange.mStart,
|
||||||
moof.mMdatRange.mStart)));
|
moof.mMdatRange.mStart)));
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,15 @@ MoofParser::RebuildFragmentedIndex(const nsTArray<MediaByteRange>& aByteRanges)
|
|||||||
if (box.IsType("moov")) {
|
if (box.IsType("moov")) {
|
||||||
ParseMoov(box);
|
ParseMoov(box);
|
||||||
} else if (box.IsType("moof")) {
|
} 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();
|
mOffset = box.NextOffset();
|
||||||
}
|
}
|
||||||
@ -32,10 +40,7 @@ MoofParser::GetCompositionRange()
|
|||||||
{
|
{
|
||||||
Interval<Microseconds> compositionRange;
|
Interval<Microseconds> compositionRange;
|
||||||
for (size_t i = 0; i < mMoofs.Length(); i++) {
|
for (size_t i = 0; i < mMoofs.Length(); i++) {
|
||||||
nsTArray<Interval<Microseconds>>& compositionRanges = mMoofs[i].mTimeRanges;
|
compositionRange = compositionRange.Extents(mMoofs[i].mTimeRange);
|
||||||
for (int j = 0; j < compositionRanges.Length(); j++) {
|
|
||||||
compositionRange = compositionRange.Extents(compositionRanges[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return compositionRange;
|
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()) {
|
for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
|
||||||
if (box.IsType("traf")) {
|
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
|
void
|
||||||
Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
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();
|
uint32_t sampleCount = reader->ReadU32();
|
||||||
|
if (sampleCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
|
uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
|
||||||
bool hasFirstSampleFlags = flags & 4;
|
bool hasFirstSampleFlags = flags & 4;
|
||||||
uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0;
|
uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0;
|
||||||
@ -163,8 +195,8 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
|||||||
offset += sampleSize;
|
offset += sampleSize;
|
||||||
|
|
||||||
sample.mCompositionRange = Interval<Microseconds>(
|
sample.mCompositionRange = Interval<Microseconds>(
|
||||||
((decodeTime + ctsOffset) * 1000000ll) / aMdhd.mTimescale,
|
aMdhd.ToMicroseconds(decodeTime + ctsOffset),
|
||||||
((decodeTime + sampleDuration + ctsOffset) * 1000000ll) / aMdhd.mTimescale);
|
aMdhd.ToMicroseconds(decodeTime + ctsOffset + sampleDuration));
|
||||||
decodeTime += sampleDuration;
|
decodeTime += sampleDuration;
|
||||||
|
|
||||||
sample.mSync = !(sampleFlags & 0x1010000);
|
sample.mSync = !(sampleFlags & 0x1010000);
|
||||||
@ -172,10 +204,22 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd)
|
|||||||
mIndex.AppendElement(sample);
|
mIndex.AppendElement(sample);
|
||||||
|
|
||||||
mMdatRange = mMdatRange.Extents(sample.mByteRange);
|
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)
|
Tkhd::Tkhd(Box& aBox)
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#define INDEX_H_
|
#define INDEX_H_
|
||||||
|
|
||||||
#include "media/stagefright/MediaSource.h"
|
#include "media/stagefright/MediaSource.h"
|
||||||
#include "mozilla/Monitor.h"
|
|
||||||
#include "mp4_demuxer/mp4_demuxer.h"
|
#include "mp4_demuxer/mp4_demuxer.h"
|
||||||
|
|
||||||
namespace mp4_demuxer
|
namespace mp4_demuxer
|
||||||
|
@ -44,6 +44,11 @@ public:
|
|||||||
}
|
}
|
||||||
Mdhd(Box& aBox);
|
Mdhd(Box& aBox);
|
||||||
|
|
||||||
|
Microseconds ToMicroseconds(uint64_t aTimescaleUnits)
|
||||||
|
{
|
||||||
|
return aTimescaleUnits * 1000000ll / mTimescale;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t mCreationTime;
|
uint64_t mCreationTime;
|
||||||
uint64_t mModificationTime;
|
uint64_t mModificationTime;
|
||||||
uint32_t mTimescale;
|
uint32_t mTimescale;
|
||||||
@ -102,13 +107,17 @@ class Moof
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd);
|
Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd);
|
||||||
void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd);
|
void FixRounding(const Moof& aMoof);
|
||||||
void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd);
|
|
||||||
|
|
||||||
mozilla::MediaByteRange mRange;
|
mozilla::MediaByteRange mRange;
|
||||||
mozilla::MediaByteRange mMdatRange;
|
mozilla::MediaByteRange mMdatRange;
|
||||||
nsTArray<Interval<Microseconds>> mTimeRanges;
|
Interval<Microseconds> mTimeRange;
|
||||||
nsTArray<Sample> mIndex;
|
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
|
class MoofParser
|
||||||
|
@ -253,7 +253,7 @@ MP4Demuxer::GetEvictionOffset(Microseconds aTime)
|
|||||||
for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
|
for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
|
||||||
offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime));
|
offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime));
|
||||||
}
|
}
|
||||||
return offset;
|
return offset == std::numeric_limits<uint64_t>::max() ? -1 : offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mp4_demuxer
|
} // namespace mp4_demuxer
|
||||||
|
Loading…
Reference in New Issue
Block a user