Bug 1125776: Part2. appendBuffer scanning the data before firing updateend. r=mattwoodrow

This commit is contained in:
Jean-Yves Avenard 2015-02-04 20:20:15 +11:00
Родитель 80732517a0
Коммит a7911540c6
7 изменённых файлов: 127 добавлений и 46 удалений

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

@ -205,7 +205,7 @@ MediaSourceDecoder::DurationChanged(double aOldDuration, double aNewDuration)
}
void
MediaSourceDecoder::SetDecodedDuration(int64_t aDuration)
MediaSourceDecoder::SetInitialDuration(int64_t aDuration)
{
// Only use the decoded duration if one wasn't already
// set.
@ -218,7 +218,7 @@ MediaSourceDecoder::SetDecodedDuration(int64_t aDuration)
if (aDuration >= 0) {
duration /= USECS_PER_S;
}
DoSetMediaSourceDuration(duration);
SetMediaSourceDuration(duration, MSRangeRemovalAction::SKIP);
}
void
@ -226,13 +226,6 @@ MediaSourceDecoder::SetMediaSourceDuration(double aDuration, MSRangeRemovalActio
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
double oldDuration = mMediaSourceDuration;
DoSetMediaSourceDuration(aDuration);
ScheduleDurationChange(oldDuration, aDuration, aAction);
}
void
MediaSourceDecoder::DoSetMediaSourceDuration(double aDuration)
{
if (aDuration >= 0) {
mDecoderStateMachine->SetDuration(aDuration * USECS_PER_S);
mMediaSourceDuration = aDuration;
@ -243,6 +236,7 @@ MediaSourceDecoder::DoSetMediaSourceDuration(double aDuration)
if (mReader) {
mReader->SetMediaSourceDuration(mMediaSourceDuration);
}
ScheduleDurationChange(oldDuration, aDuration, aAction);
}
void

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

@ -56,7 +56,7 @@ public:
void Ended();
bool IsExpectingMoreData() MOZ_OVERRIDE;
void SetDecodedDuration(int64_t aDuration);
void SetInitialDuration(int64_t aDuration);
void SetMediaSourceDuration(double aDuration, MSRangeRemovalAction aAction);
double GetMediaSourceDuration();
void DurationChanged(double aOldDuration, double aNewDuration);

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

@ -897,8 +897,6 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
return NS_ERROR_FAILURE;
}
int64_t maxDuration = -1;
if (mAudioTrack) {
MOZ_ASSERT(mAudioTrack->IsReady());
mAudioReader = mAudioTrack->Decoders()[0]->GetReader();
@ -907,9 +905,9 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
MOZ_ASSERT(info.HasAudio());
mInfo.mAudio = info.mAudio;
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted;
maxDuration = std::max(maxDuration, mAudioReader->GetDecoder()->GetMediaDuration());
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p maxDuration=%lld",
this, mAudioReader.get(), maxDuration);
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata audio reader=%p duration=%lld",
this, mAudioReader.get(),
mAudioReader->GetDecoder()->GetMediaDuration());
}
if (mVideoTrack) {
@ -920,17 +918,11 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
MOZ_ASSERT(info.HasVideo());
mInfo.mVideo = info.mVideo;
mInfo.mIsEncrypted = mInfo.mIsEncrypted || info.mIsEncrypted;
maxDuration = std::max(maxDuration, mVideoReader->GetDecoder()->GetMediaDuration());
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p maxDuration=%lld",
this, mVideoReader.get(), maxDuration);
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata video reader=%p duration=%lld",
this, mVideoReader.get(),
mVideoReader->GetDecoder()->GetMediaDuration());
}
if (!maxDuration) {
// Treat a duration of 0 as infinity
maxDuration = -1;
}
static_cast<MediaSourceDecoder*>(mDecoder)->SetDecodedDuration(maxDuration);
*aInfo = mInfo;
*aTags = nullptr; // TODO: Handle metadata.

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

@ -269,6 +269,8 @@ SourceBuffer::RangeRemoval(double aStart, double aEnd)
void
SourceBuffer::DoRangeRemoval(double aStart, double aEnd)
{
MSE_DEBUG("SourceBuffer(%p)::DoRangeRemoval (updating:%d)",
this, mUpdating);
if (!mUpdating) {
// abort was called in between.
return;
@ -397,9 +399,11 @@ SourceBuffer::AbortUpdating()
void
SourceBuffer::CheckEndTime()
{
MOZ_ASSERT(NS_IsMainThread());
// Check if we need to update mMediaSource duration
double endTime = GetBufferedEnd();
if (endTime > mMediaSource->Duration()) {
double duration = mMediaSource->Duration();
if (endTime > duration) {
mMediaSource->SetDuration(endTime, MSRangeRemovalAction::SKIP);
}
}
@ -437,21 +441,41 @@ SourceBuffer::AppendData(LargeDataBuffer* aData, double aTimestampOffset)
MOZ_ASSERT(mMediaSource);
if (aData->Length()) {
if (!mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)) {
AppendError(true);
return;
}
if (!aData->Length()) {
StopUpdating();
return;
}
if (mTrackBuffer->HasInitSegment()) {
mMediaSource->QueueInitializationEvent();
}
mTrackBuffer->AppendData(aData, aTimestampOffset * USECS_PER_S)
->Then(NS_GetCurrentThread(), __func__, this,
&SourceBuffer::AppendDataCompletedWithSuccess,
&SourceBuffer::AppendDataErrored);
}
void
SourceBuffer::AppendDataCompletedWithSuccess(bool aGotMedia)
{
if (!mUpdating) {
// The buffer append algorithm has been interrupted by abort().
return;
}
if (mTrackBuffer->HasInitSegment()) {
mMediaSource->QueueInitializationEvent();
}
if (aGotMedia) {
CheckEndTime();
}
StopUpdating();
}
}
void
SourceBuffer::AppendDataErrored(nsresult aError)
{
AppendError(true);
}
void
SourceBuffer::AppendError(bool aDecoderError)

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

@ -153,6 +153,9 @@ private:
uint32_t aLength,
ErrorResult& aRv);
void AppendDataCompletedWithSuccess(bool aValue);
void AppendDataErrored(nsresult aError);
nsRefPtr<MediaSource> mMediaSource;
uint32_t mEvictionThreshold;

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

@ -102,6 +102,11 @@ public:
return true;
}
size_t Length()
{
return mDecoders.Length();
}
private:
TrackBuffer* mOwner;
nsAutoTArray<nsRefPtr<SourceBufferDecoder>,2> mDecoders;
@ -144,20 +149,24 @@ TrackBuffer::ContinueShutdown()
mShutdownPromise.Resolve(true, __func__);
}
bool
nsRefPtr<TrackBuffer::InitializationPromise>
TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
{
MOZ_ASSERT(NS_IsMainThread());
DecodersToInitialize decoders(this);
nsRefPtr<InitializationPromise> p = mInitializationPromise.Ensure(__func__);
// TODO: Run more of the buffer append algorithm asynchronously.
if (mParser->IsInitSegmentPresent(aData)) {
MSE_DEBUG("TrackBuffer(%p)::AppendData: New initialization segment.", this);
if (!decoders.NewDecoder(aTimestampOffset)) {
return false;
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
return p;
}
} else if (!mParser->HasInitData()) {
MSE_DEBUG("TrackBuffer(%p)::AppendData: Non-init segment appended during initialization.", this);
return false;
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
return p;
}
int64_t start = 0, end = 0;
@ -175,7 +184,8 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
// This data is earlier in the timeline than data we have already
// processed, so we must create a new decoder to handle the decoding.
if (!decoders.NewDecoder(aTimestampOffset)) {
return false;
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
return p;
}
MSE_DEBUG("TrackBuffer(%p)::AppendData: Decoder marked as initialized.", this);
nsRefPtr<LargeDataBuffer> initData = mParser->InitData();
@ -190,13 +200,22 @@ TrackBuffer::AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset)
}
if (!AppendDataToCurrentResource(aData, end - start)) {
return false;
mInitializationPromise.Reject(NS_ERROR_FAILURE, __func__);
return p;
}
if (decoders.Length()) {
// TODO: the theory is that we should only ever have one decoder to
// initialize in common use. We can't properly handle the condition where
// the source buffer needs to wait on two decoders to initialize.
return p;
}
// Tell our reader that we have more data to ensure that playback starts if
// required when data is appended.
mParentDecoder->GetReader()->MaybeNotifyHaveData();
return true;
mInitializationPromise.Resolve(end - start > 0, __func__);
return p;
}
bool
@ -410,6 +429,7 @@ bool
TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
{
if (NS_WARN_IF(!mTaskQueue)) {
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return false;
}
@ -418,8 +438,9 @@ TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
&TrackBuffer::InitializeDecoder,
aDecoder);
if (NS_FAILED(mTaskQueue->Dispatch(task))) {
MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
MSE_DEBUG("TrackBuffer(%p): Failed to enqueue decoder initialization task", this);
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return false;
}
return true;
@ -441,6 +462,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
// important pieces of our state (like mTaskQueue) have also been torn down.
if (mShutdown) {
MSE_DEBUG("TrackBuffer(%p) was shut down. Aborting initialization.", this);
mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
return;
}
@ -460,6 +482,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
reader->SetIdle();
if (mShutdown) {
MSE_DEBUG("TrackBuffer(%p) was shut down while reading metadata. Aborting initialization.", this);
mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
return;
}
@ -475,6 +498,7 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
this, reader, rv, mi.HasAudio(), mi.HasVideo());
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return;
}
@ -487,18 +511,51 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
this, reader, mi.mAudio.mRate, mi.mAudio.mChannels);
}
if (!RegisterDecoder(aDecoder)) {
// XXX: Need to signal error back to owning SourceBuffer.
MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", this, reader);
RefPtr<nsIRunnable> task =
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
&TrackBuffer::CompleteInitializeDecoder,
aDecoder);
if (NS_FAILED(NS_DispatchToMainThread(task))) {
MSE_DEBUG("TrackBuffer(%p): Failed to enqueue decoder initialization task", this);
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return;
}
}
void
TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
if (mShutdown) {
MSE_DEBUG("TrackBuffer(%p) was shut down while reading metadata. Aborting initialization.", this);
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
return;
}
if (!RegisterDecoder(aDecoder)) {
MSE_DEBUG("TrackBuffer(%p): Reader %p not activated",
this, aDecoder->GetReader());
RemoveDecoder(aDecoder);
mInitializationPromise.RejectIfExists(NS_ERROR_FAILURE, __func__);
return;
}
int64_t duration = aDecoder->GetMediaDuration();
if (!duration) {
// Treat a duration of 0 as infinity
duration = -1;
}
mParentDecoder->SetInitialDuration(duration);
// Tell our reader that we have more data to ensure that playback starts if
// required when data is appended.
mParentDecoder->GetReader()->MaybeNotifyHaveData();
MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader);
MSE_DEBUG("TrackBuffer(%p): Reader %p activated",
this, aDecoder->GetReader());
mInitializationPromise.ResolveIfExists(aDecoder->GetRealMediaDuration() > 0, __func__);
}
bool

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

@ -33,6 +33,8 @@ class TrackBuffer MOZ_FINAL {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TrackBuffer);
typedef MediaPromise<bool, nsresult, /* IsExclusive = */ false> InitializationPromise;
TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& aType);
nsRefPtr<ShutdownPromise> Shutdown();
@ -40,7 +42,8 @@ public:
// Append data to the current decoder. Also responsible for calling
// NotifyDataArrived on the decoder to keep buffered range computation up
// to date. Returns false if the append failed.
bool AppendData(LargeDataBuffer* aData, int64_t aTimestampOffset /* microseconds */);
nsRefPtr<InitializationPromise> AppendData(LargeDataBuffer* aData,
int64_t aTimestampOffset /* microseconds */);
// Evicts data held in the current decoders SourceBufferResource from the
// start of the buffer through to aPlaybackTime. aThreshold is used to
@ -130,6 +133,11 @@ private:
// Runs decoder initialization including calling ReadMetadata. Runs as an
// event on the decode thread pool.
void InitializeDecoder(SourceBufferDecoder* aDecoder);
// Once decoder has been initialized, set mediasource duration if required
// and resolve any pending InitializationPromise.
// Setting the mediasource duration must be done on the main thread.
// TODO: Why is that so?
void CompleteInitializeDecoder(SourceBufferDecoder* aDecoder);
// Adds a successfully initialized decoder to mDecoders and (if it's the
// first decoder initialized), initializes mHasAudio/mHasVideo. Called
@ -193,6 +201,9 @@ private:
MediaPromiseHolder<ShutdownPromise> mShutdownPromise;
bool mDecoderPerSegment;
bool mShutdown;
MediaPromiseHolder<InitializationPromise> mInitializationPromise;
};
} // namespace mozilla