зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1171330: P1. Add ContainerParser::MediaSegmentRange() method. r=kentuckyfriedtakahe
And add abilities to MoofParser to indicate if a media segment is complete. In MP4 a media segment is made of a moof atom followed by one (or more) mdat atoms. --HG-- extra : rebase_source : 0b0db48d55462025d9d45bf9b3bbdbc806b0e7a8
This commit is contained in:
Родитель
6b3455d8e9
Коммит
584ec04c52
|
@ -92,6 +92,12 @@ ContainerParser::InitData()
|
|||
return mInitData;
|
||||
}
|
||||
|
||||
MediaByteRange
|
||||
ContainerParser::MediaSegmentRange()
|
||||
{
|
||||
return mCompleteByteRange;
|
||||
}
|
||||
|
||||
class WebMContainerParser : public ContainerParser {
|
||||
public:
|
||||
explicit WebMContainerParser(const nsACString& aType)
|
||||
|
@ -103,7 +109,7 @@ public:
|
|||
static const unsigned NS_PER_USEC = 1000;
|
||||
static const unsigned USEC_PER_SEC = 1000000;
|
||||
|
||||
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData)
|
||||
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override
|
||||
{
|
||||
ContainerParser::IsInitSegmentPresent(aData);
|
||||
// XXX: This is overly primitive, needs to collect data as it's appended
|
||||
|
@ -126,7 +132,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
|
||||
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override
|
||||
{
|
||||
ContainerParser::IsMediaSegmentPresent(aData);
|
||||
// XXX: This is overly primitive, needs to collect data as it's appended
|
||||
|
@ -148,7 +154,7 @@ public:
|
|||
}
|
||||
|
||||
bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
|
||||
int64_t& aStart, int64_t& aEnd)
|
||||
int64_t& aStart, int64_t& aEnd) override
|
||||
{
|
||||
bool initSegment = IsInitSegmentPresent(aData);
|
||||
if (initSegment) {
|
||||
|
@ -219,7 +225,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
int64_t GetRoundingError()
|
||||
int64_t GetRoundingError() override
|
||||
{
|
||||
int64_t error = mParser.GetTimecodeScale() / NS_PER_USEC;
|
||||
return error * 2;
|
||||
|
@ -239,7 +245,7 @@ public:
|
|||
, mMonitor("MP4ContainerParser Index Monitor")
|
||||
{}
|
||||
|
||||
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData)
|
||||
bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override
|
||||
{
|
||||
ContainerParser::IsInitSegmentPresent(aData);
|
||||
// Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
|
||||
|
@ -259,7 +265,7 @@ public:
|
|||
(*aData)[7] == 'p';
|
||||
}
|
||||
|
||||
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData)
|
||||
bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override
|
||||
{
|
||||
ContainerParser::IsMediaSegmentPresent(aData);
|
||||
if (aData->Length() < 8) {
|
||||
|
@ -280,7 +286,7 @@ public:
|
|||
}
|
||||
|
||||
bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData,
|
||||
int64_t& aStart, int64_t& aEnd)
|
||||
int64_t& aStart, int64_t& aEnd) override
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
|
||||
// but mParser requires us to hold a monitor.
|
||||
|
@ -306,17 +312,16 @@ public:
|
|||
mParser->RebuildFragmentedIndex(byteRanges);
|
||||
|
||||
if (initSegment || !HasCompleteInitData()) {
|
||||
const MediaByteRange& range = mParser->mInitRange;
|
||||
uint32_t length = range.mEnd - range.mStart;
|
||||
if (length) {
|
||||
if (!mInitData->SetLength(length, fallible)) {
|
||||
MediaByteRange& range = mParser->mInitRange;
|
||||
if (range.Length()) {
|
||||
if (!mInitData->SetLength(range.Length(), fallible)) {
|
||||
// Super unlikely OOM
|
||||
return false;
|
||||
}
|
||||
char* buffer = reinterpret_cast<char*>(mInitData->Elements());
|
||||
mResource->ReadFromCache(buffer, range.mStart, length);
|
||||
mResource->ReadFromCache(buffer, range.mStart, range.Length());
|
||||
MSE_DEBUG(MP4ContainerParser ,"Stashed init of %u bytes.",
|
||||
length);
|
||||
range.Length());
|
||||
} else {
|
||||
MSE_DEBUG(MP4ContainerParser, "Incomplete init found.");
|
||||
}
|
||||
|
@ -326,6 +331,7 @@ public:
|
|||
mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
|
||||
mParser->GetCompositionRange(byteRanges);
|
||||
|
||||
mCompleteByteRange = mParser->FirstCompleteMediaSegment();
|
||||
ErrorResult rv;
|
||||
mResource->EvictData(mParser->mOffset, mParser->mOffset, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
|
@ -345,7 +351,7 @@ public:
|
|||
|
||||
// Gaps of up to 35ms (marginally longer than a single frame at 30fps) are considered
|
||||
// to be sequential frames.
|
||||
int64_t GetRoundingError()
|
||||
int64_t GetRoundingError() override
|
||||
{
|
||||
return 35000;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "MediaResource.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -51,6 +52,9 @@ public:
|
|||
}
|
||||
|
||||
bool HasCompleteInitData();
|
||||
// Return the byte range of the first complete media segment or an empty
|
||||
// range if not complete.
|
||||
MediaByteRange MediaSegmentRange();
|
||||
|
||||
static ContainerParser* CreateForMIMEType(const nsACString& aType);
|
||||
|
||||
|
@ -58,6 +62,7 @@ protected:
|
|||
nsRefPtr<MediaLargeByteBuffer> mInitData;
|
||||
nsRefPtr<SourceBufferResource> mResource;
|
||||
bool mHasInitData;
|
||||
MediaByteRange mCompleteByteRange;
|
||||
const nsCString mType;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "mp4_demuxer/Box.h"
|
||||
#include "mp4_demuxer/SinfParser.h"
|
||||
#include <limits>
|
||||
#include "Intervals.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
|
@ -42,6 +43,7 @@ bool
|
|||
MoofParser::RebuildFragmentedIndex(BoxContext& aContext)
|
||||
{
|
||||
bool foundValidMoof = false;
|
||||
bool foundMdat = false;
|
||||
|
||||
for (Box box(&aContext, mOffset); box.IsAvailable(); box = box.Next()) {
|
||||
if (box.IsType("moov")) {
|
||||
|
@ -62,13 +64,34 @@ MoofParser::RebuildFragmentedIndex(BoxContext& aContext)
|
|||
}
|
||||
|
||||
mMoofs.AppendElement(moof);
|
||||
mMediaRanges.AppendElement(moof.mRange);
|
||||
foundValidMoof = true;
|
||||
} else if (box.IsType("mdat") && !Moofs().IsEmpty()) {
|
||||
// Check if we have all our data from last moof.
|
||||
Moof& moof = Moofs().LastElement();
|
||||
media::Interval<int64_t> datarange(moof.mMdatRange.mStart, moof.mMdatRange.mEnd, 0);
|
||||
media::Interval<int64_t> mdat(box.Range().mStart, box.Range().mEnd, 0);
|
||||
if (datarange.Intersects(mdat)) {
|
||||
mMediaRanges.LastElement() =
|
||||
mMediaRanges.LastElement().Extents(box.Range());
|
||||
}
|
||||
}
|
||||
mOffset = box.NextOffset();
|
||||
}
|
||||
return foundValidMoof;
|
||||
}
|
||||
|
||||
MediaByteRange
|
||||
MoofParser::FirstCompleteMediaSegment()
|
||||
{
|
||||
for (uint32_t i = 0 ; i < mMediaRanges.Length(); i++) {
|
||||
if (mMediaRanges[i].Contains(Moofs()[i].mMdatRange)) {
|
||||
return mMediaRanges[i];
|
||||
}
|
||||
}
|
||||
return MediaByteRange();
|
||||
}
|
||||
|
||||
class BlockingStream : public Stream {
|
||||
public:
|
||||
explicit BlockingStream(Stream* aStream) : mStream(aStream)
|
||||
|
|
|
@ -225,6 +225,7 @@ public:
|
|||
|
||||
bool BlockingReadNextMoof();
|
||||
bool HasMetadata();
|
||||
MediaByteRange FirstCompleteMediaSegment();
|
||||
|
||||
mozilla::MediaByteRange mInitRange;
|
||||
nsRefPtr<Stream> mSource;
|
||||
|
@ -240,6 +241,7 @@ public:
|
|||
nsTArray<Moof>& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; }
|
||||
private:
|
||||
nsTArray<Moof> mMoofs;
|
||||
nsTArray<MediaByteRange> mMediaRanges;
|
||||
bool mIsAudio;
|
||||
};
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче