Bug 1195073: [MSE/webm] P4. Limit nestegg reads to the last block's boundaries. r=kinetik

This prevent entering into an unrecoverable error state when parsing incomplete data as often seen with MSE.
This commit is contained in:
Jean-Yves Avenard 2015-08-19 15:27:18 +10:00
parent 83205f837d
commit 3cd00ea187
3 changed files with 43 additions and 15 deletions

View File

@ -100,6 +100,11 @@ public:
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
virtual bool IsExpectingMoreData() override
{
return false;
}
// Used by SourceBuffer.
void AppendData(MediaByteBuffer* aData);
void Ended();

View File

@ -36,40 +36,39 @@ extern PRLogModuleInfo* gNesteggLog;
// Functions for reading and seeking using WebMDemuxer required for
// nestegg_io. The 'user data' passed to these functions is the
// demuxer's MediaResourceIndex
// demuxer.
static int webmdemux_read(void* aBuffer, size_t aLength, void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
int64_t length = resource->GetLength();
MOZ_ASSERT(aLength < UINT32_MAX);
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
int64_t length = demuxer->GetEndDataOffset();
uint32_t count = aLength;
if (length >= 0 && count + resource->Tell() > length) {
count = uint32_t(length - resource->Tell());
int64_t position = demuxer->GetResource()->Tell();
if (length >= 0 && count + position > length) {
count = length - position;
}
uint32_t bytes = 0;
nsresult rv = resource->Read(static_cast<char*>(aBuffer), count, &bytes);
bool eof = !bytes;
nsresult rv =
demuxer->GetResource()->Read(static_cast<char*>(aBuffer), count, &bytes);
bool eof = bytes < aLength;
return NS_FAILED(rv) ? -1 : eof ? 0 : 1;
}
static int webmdemux_seek(int64_t aOffset, int aWhence, void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
nsresult rv = resource->Seek(aWhence, aOffset);
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
nsresult rv = demuxer->GetResource()->Seek(aWhence, aOffset);
return NS_SUCCEEDED(rv) ? 0 : -1;
}
static int64_t webmdemux_tell(void* aUserData)
{
MOZ_ASSERT(aUserData);
MediaResourceIndex* resource =
reinterpret_cast<MediaResourceIndex*>(aUserData);
return resource->Tell();
WebMDemuxer* demuxer = reinterpret_cast<WebMDemuxer*>(aUserData);
return demuxer->GetResource()->Tell();
}
static void webmdemux_log(nestegg* aContext,
@ -130,6 +129,8 @@ WebMDemuxer::WebMDemuxer(MediaResource* aResource)
, mHasVideo(false)
, mHasAudio(false)
, mNeedReIndex(true)
, mLastWebMBlockOffset(-1)
, mIsExpectingMoreData(true)
{
if (!gNesteggLog) {
gNesteggLog = PR_NewLogModule("Nestegg");
@ -254,7 +255,7 @@ WebMDemuxer::ReadMetadata()
io.read = webmdemux_read;
io.seek = webmdemux_seek;
io.tell = webmdemux_tell;
io.userdata = &mResource;
io.userdata = this;
int64_t maxOffset = mBufferedState->GetInitEndOffset();
if (maxOffset == -1) {
maxOffset = mResource.GetLength();
@ -443,6 +444,8 @@ WebMDemuxer::EnsureUpToDateIndex()
if (!mInitData && mBufferedState->GetInitEndOffset() != -1) {
mInitData = mResource.MediaReadAt(0, mBufferedState->GetInitEndOffset());
}
mLastWebMBlockOffset = mBufferedState->GetLastBlockOffset();
mIsExpectingMoreData = mResource.GetResource()->IsExpectingMoreData();
mNeedReIndex = false;
}
@ -469,6 +472,8 @@ WebMDemuxer::GetCrypto()
bool
WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType, MediaRawDataQueue *aSamples)
{
EnsureUpToDateIndex();
nsRefPtr<NesteggPacketHolder> holder(NextPacket(aType));
if (!holder) {

View File

@ -85,6 +85,18 @@ public:
// Pushes a packet to the front of the video packet queue.
virtual void PushVideoPacket(NesteggPacketHolder* aItem);
// Public accessor for nestegg callbacks
MediaResourceIndex* GetResource()
{
return &mResource;
}
int64_t GetEndDataOffset()
{
return mLastWebMBlockOffset < 0 || mIsExpectingMoreData
? mResource.GetLength() : mLastWebMBlockOffset;
}
private:
friend class WebMTrackDemuxer;
@ -152,6 +164,12 @@ private:
bool mHasVideo;
bool mHasAudio;
bool mNeedReIndex;
// The last complete block parsed by the WebMBufferedState. -1 if not set.
// We cache those values rather than retrieving them for performance reasons
// as nestegg only performs 1-byte read at a time.
int64_t mLastWebMBlockOffset;
bool mIsExpectingMoreData;
};
class WebMTrackDemuxer : public MediaTrackDemuxer