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:
Jean-Yves Avenard 2015-06-11 15:49:49 +10:00
Родитель 6b3455d8e9
Коммит 584ec04c52
4 изменённых файлов: 50 добавлений и 14 удалений

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

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