зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1195073: [MSE] P5. Detect out of order appends and recreate demuxer. r=gerald
The webm demuxer will only handle data where frames's a monotonically increasing.
This commit is contained in:
Родитель
3cd00ea187
Коммит
e4dff83b7a
|
@ -97,6 +97,7 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBufferAttributes* aAttribute
|
|||
, mAppendState(AppendState::WAITING_FOR_SEGMENT)
|
||||
, mBufferFull(false)
|
||||
, mFirstInitializationSegmentReceived(false)
|
||||
, mNewSegmentStarted(false)
|
||||
, mActiveTrack(false)
|
||||
, mType(aType)
|
||||
, mParser(ContainerParser::CreateForMIMEType(aType))
|
||||
|
@ -655,10 +656,12 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
// This is a new initialization segment. Obsolete the old one.
|
||||
RecreateParser(false);
|
||||
}
|
||||
mNewSegmentStarted = true;
|
||||
continue;
|
||||
}
|
||||
if (mParser->IsMediaSegmentPresent(mInputBuffer)) {
|
||||
SetAppendState(AppendState::PARSING_MEDIA_SEGMENT);
|
||||
mNewSegmentStarted = true;
|
||||
continue;
|
||||
}
|
||||
// We have neither an init segment nor a media segment, this is either
|
||||
|
@ -669,7 +672,7 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
}
|
||||
|
||||
int64_t start, end;
|
||||
mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
|
||||
bool newData = mParser->ParseStartAndEndTimestamps(mInputBuffer, start, end);
|
||||
mProcessedInput += mInputBuffer->Length();
|
||||
|
||||
// 5. If the append state equals PARSING_INIT_SEGMENT, then run the
|
||||
|
@ -696,6 +699,22 @@ TrackBuffersManager::SegmentParserLoop()
|
|||
NeedMoreData();
|
||||
return;
|
||||
}
|
||||
|
||||
// We can't feed some demuxers (WebMDemuxer) with data that do not have
|
||||
// monotonizally increasing timestamps. So we check if we have a
|
||||
// discontinuity from the previous segment parsed.
|
||||
// If so, recreate a new demuxer to ensure that the demuxer is only fed
|
||||
// monotonically increasing data.
|
||||
if (newData) {
|
||||
if (mNewSegmentStarted && mLastParsedEndTime.isSome() &&
|
||||
start < mLastParsedEndTime.ref().ToMicroseconds()) {
|
||||
ResetDemuxingState();
|
||||
return;
|
||||
}
|
||||
mNewSegmentStarted = false;
|
||||
mLastParsedEndTime = Some(TimeUnit::FromMicroseconds(end));
|
||||
}
|
||||
|
||||
// 3. If the input buffer contains one or more complete coded frames, then run the coded frame processing algorithm.
|
||||
nsRefPtr<TrackBuffersManager> self = this;
|
||||
mProcessingRequest.Begin(CodedFrameProcessing()
|
||||
|
@ -756,6 +775,7 @@ TrackBuffersManager::ShutdownDemuxers()
|
|||
mAudioTracks.mDemuxer = nullptr;
|
||||
}
|
||||
mInputDemuxer = nullptr;
|
||||
mLastParsedEndTime.reset();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -780,6 +800,58 @@ TrackBuffersManager::CreateDemuxerforMIMEType()
|
|||
return;
|
||||
}
|
||||
|
||||
// We reset the demuxer by creating a new one and initializing it.
|
||||
void
|
||||
TrackBuffersManager::ResetDemuxingState()
|
||||
{
|
||||
MOZ_ASSERT(mParser && mParser->HasInitData());
|
||||
RecreateParser(true);
|
||||
mCurrentInputBuffer = new SourceBufferResource(mType);
|
||||
// The demuxer isn't initialized yet ; we don't want to notify it
|
||||
// that data has been appended yet ; so we simply append the init segment
|
||||
// to the resource.
|
||||
mCurrentInputBuffer->AppendData(mParser->InitData());
|
||||
CreateDemuxerforMIMEType();
|
||||
if (!mInputDemuxer) {
|
||||
RejectAppend(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
mDemuxerInitRequest.Begin(mInputDemuxer->Init()
|
||||
->Then(GetTaskQueue(), __func__,
|
||||
this,
|
||||
&TrackBuffersManager::OnDemuxerResetDone,
|
||||
&TrackBuffersManager::OnDemuxerInitFailed));
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::OnDemuxerResetDone(nsresult)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MSE_DEBUG("mAbort:%d", static_cast<bool>(mAbort));
|
||||
mDemuxerInitRequest.Complete();
|
||||
if (mAbort) {
|
||||
RejectAppend(NS_ERROR_ABORT, __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// Recreate track demuxers.
|
||||
uint32_t numVideos = mInputDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
|
||||
if (numVideos) {
|
||||
// We currently only handle the first video track.
|
||||
mVideoTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
|
||||
MOZ_ASSERT(mVideoTracks.mDemuxer);
|
||||
}
|
||||
|
||||
uint32_t numAudios = mInputDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
|
||||
if (numAudios) {
|
||||
// We currently only handle the first audio track.
|
||||
mAudioTracks.mDemuxer = mInputDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
|
||||
MOZ_ASSERT(mAudioTracks.mDemuxer);
|
||||
}
|
||||
|
||||
SegmentParserLoop();
|
||||
}
|
||||
|
||||
void
|
||||
TrackBuffersManager::AppendDataToCurrentInputBuffer(MediaByteBuffer* aData)
|
||||
{
|
||||
|
@ -1056,6 +1128,14 @@ TrackBuffersManager::CodedFrameProcessing()
|
|||
// The mediaRange is offset by the init segment position previously added.
|
||||
uint32_t length =
|
||||
mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length());
|
||||
if (!length) {
|
||||
// We've completed our earlier media segment and no new data is to be
|
||||
// processed. This happens with some containers that can't detect that a
|
||||
// media segment is ending until a new one starts.
|
||||
nsRefPtr<CodedFrameProcessingPromise> p = mProcessingPromise.Ensure(__func__);
|
||||
CompleteCodedFrameProcessing();
|
||||
return p;
|
||||
}
|
||||
nsRefPtr<MediaByteBuffer> segment = new MediaByteBuffer;
|
||||
if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) {
|
||||
return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__);
|
||||
|
|
|
@ -113,6 +113,7 @@ private:
|
|||
void InitializationSegmentReceived();
|
||||
void ShutdownDemuxers();
|
||||
void CreateDemuxerforMIMEType();
|
||||
void ResetDemuxingState();
|
||||
void NeedMoreData();
|
||||
void RejectAppend(nsresult aRejectValue, const char* aName);
|
||||
// Will return a promise that will be resolved once all frames of the current
|
||||
|
@ -151,6 +152,8 @@ private:
|
|||
// TODO: Unused for now.
|
||||
Atomic<bool> mBufferFull;
|
||||
bool mFirstInitializationSegmentReceived;
|
||||
// Set to true once a new segment is started.
|
||||
bool mNewSegmentStarted;
|
||||
bool mActiveTrack;
|
||||
Maybe<media::TimeUnit> mGroupStartTimestamp;
|
||||
media::TimeUnit mGroupEndTimestamp;
|
||||
|
@ -171,9 +174,11 @@ private:
|
|||
nsRefPtr<MediaDataDemuxer> mInputDemuxer;
|
||||
// Length already processed in current media segment.
|
||||
uint32_t mProcessedInput;
|
||||
Maybe<media::TimeUnit> mLastParsedEndTime;
|
||||
|
||||
void OnDemuxerInitDone(nsresult);
|
||||
void OnDemuxerInitFailed(DemuxerFailureReason aFailure);
|
||||
void OnDemuxerResetDone(nsresult);
|
||||
MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
|
||||
bool mEncrypted;
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ void WebMBufferedParser::Append(const unsigned char* aBuffer, uint32_t aLength,
|
|||
if (!mSkipBytes) {
|
||||
if (mInitEndOffset < 0) {
|
||||
mInitEndOffset = mCurrentOffset + (p - aBuffer);
|
||||
mBlockEndOffset = mCurrentOffset + (p - aBuffer);
|
||||
}
|
||||
mState = READ_ELEMENT_ID;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче