Bug 1062669 - Consider only SourceBuffers created before the first initialization segment is appended as essential for parent decoder initialization. r=cajbir

This commit is contained in:
Matthew Gregan 2014-09-05 12:04:54 +12:00
Родитель 0f5f1f0b5d
Коммит 4335ec1e50
7 изменённых файлов: 80 добавлений и 5 удалений

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

@ -339,6 +339,7 @@ MediaSource::Detach()
}
mDecoder->DetachMediaSource();
mDecoder = nullptr;
mFirstSourceBufferInitialization = false;
SetReadyState(MediaSourceReadyState::Closed);
mDuration = UnspecifiedNaN<double>();
if (mActiveSourceBuffers) {
@ -395,6 +396,7 @@ MediaSource::MediaSource(nsPIDOMWindow* aWindow)
, mDuration(UnspecifiedNaN<double>())
, mDecoder(nullptr)
, mReadyState(MediaSourceReadyState::Closed)
, mFirstSourceBufferInitialization(false)
{
MOZ_ASSERT(NS_IsMainThread());
mSourceBuffers = new SourceBufferList(this);
@ -482,6 +484,29 @@ MediaSource::NotifyEvicted(double aStart, double aEnd)
mSourceBuffers->Evict(aStart, aEnd);
}
void
MediaSource::QueueInitializationEvent()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mFirstSourceBufferInitialization) {
mFirstSourceBufferInitialization = true;
}
MSE_DEBUG("MediaSource(%p)::QueueInitializationEvent()", this);
nsRefPtr<nsIRunnable> task =
NS_NewRunnableMethod(this, &MediaSource::InitializationEvent);
NS_DispatchToMainThread(task);
}
void
MediaSource::InitializationEvent()
{
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("MediaSource(%p)::InitializationEvent()", this);
if (mDecoder) {
mDecoder->PrepareReaderInitialization();
}
}
nsPIDOMWindow*
MediaSource::GetParentObject() const
{

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

@ -90,6 +90,14 @@ public:
// that were evicted are provided.
void NotifyEvicted(double aStart, double aEnd);
// Queue InitializationEvent to run on the main thread. Called when a
// SourceBuffer has an initialization segment appended, but only
// dispatched the first time (using mFirstSourceBufferInitialization).
// Demarcates the point in time at which only currently registered
// TrackBuffers are treated as essential by the MediaSourceReader for
// initialization.
void QueueInitializationEvent();
private:
~MediaSource();
@ -101,6 +109,8 @@ private:
void DurationChange(double aNewDuration, ErrorResult& aRv);
void InitializationEvent();
double mDuration;
nsRefPtr<SourceBufferList> mSourceBuffers;
@ -109,6 +119,8 @@ private:
nsRefPtr<MediaSourceDecoder> mDecoder;
MediaSourceReadyState mReadyState;
bool mFirstSourceBufferInitialization;
};
NS_DEFINE_STATIC_IID_ACCESSOR(MediaSource, MOZILLA_DOM_MEDIASOURCE_IMPLEMENTATION_IID)

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

@ -188,4 +188,11 @@ MediaSourceDecoder::NotifyGotData()
mon.NotifyAll();
}
void
MediaSourceDecoder::PrepareReaderInitialization()
{
MOZ_ASSERT(mReader);
mReader->PrepareInitialization();
}
} // namespace mozilla

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

@ -61,6 +61,10 @@ public:
// Called whenever a SourceBuffer has new data appended.
void NotifyGotData();
// Indicates the point in time at which the reader should consider
// registered TrackBuffers essential for initialization.
void PrepareReaderInitialization();
private:
// The owning MediaSource holds a strong reference to this decoder, and
// calls Attach/DetachMediaSource on this decoder to set and clear

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

@ -46,19 +46,33 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
, mEnded(false)
, mAudioIsSeeking(false)
, mVideoIsSeeking(false)
, mHasEssentialTrackBuffers(false)
{
}
void
MediaSourceReader::PrepareInitialization()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MSE_DEBUG("MediaSourceReader(%p)::PrepareInitialization trackBuffers=%u",
this, mTrackBuffers.Length());
mEssentialTrackBuffers.AppendElements(mTrackBuffers);
mHasEssentialTrackBuffers = true;
mDecoder->NotifyWaitingForResourcesStatusChanged();
}
bool
MediaSourceReader::IsWaitingMediaResources()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) {
if (!mTrackBuffers[i]->IsReady()) {
for (uint32_t i = 0; i < mEssentialTrackBuffers.Length(); ++i) {
if (!mEssentialTrackBuffers[i]->IsReady()) {
return true;
}
}
return mTrackBuffers.IsEmpty();
return !mHasEssentialTrackBuffers;
}
void
@ -367,6 +381,7 @@ void
MediaSourceReader::OnTrackBufferConfigured(TrackBuffer* aTrackBuffer, const MediaInfo& aInfo)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
MOZ_ASSERT(aTrackBuffer->IsReady());
MOZ_ASSERT(mTrackBuffers.Contains(aTrackBuffer));
if (aInfo.HasAudio() && !mAudioTrack) {
MSE_DEBUG("MediaSourceReader(%p)::OnTrackBufferConfigured %p audio", this, aTrackBuffer);
@ -472,11 +487,15 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
nsresult
MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
{
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata tracks=%u", this, mTrackBuffers.Length());
bool waiting = IsWaitingMediaResources();
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata waiting=%d tracks=%u/%u audio=%p video=%p",
this, waiting, mEssentialTrackBuffers.Length(), mTrackBuffers.Length(),
mAudioTrack.get(), mVideoTrack.get());
// ReadMetadata is called *before* checking IsWaitingMediaResources.
if (IsWaitingMediaResources()) {
if (waiting) {
return NS_OK;
}
mEssentialTrackBuffers.Clear();
if (!mAudioTrack && !mVideoTrack) {
MSE_DEBUG("MediaSourceReader(%p)::ReadMetadata missing track: mAudioTrack=%p mVideoTrack=%p",
this, mAudioTrack.get(), mVideoTrack.get());

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

@ -40,6 +40,10 @@ public:
return NS_OK;
}
// Indicates the point in time at which the reader should consider
// registered TrackBuffers essential for initialization.
void PrepareInitialization();
bool IsWaitingMediaResources() MOZ_OVERRIDE;
void RequestAudioData() MOZ_OVERRIDE;
@ -105,6 +109,7 @@ private:
nsRefPtr<MediaDecoderReader> mVideoReader;
nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
nsRefPtr<TrackBuffer> mAudioTrack;
nsRefPtr<TrackBuffer> mVideoTrack;
@ -125,6 +130,8 @@ private:
// after a seek.
bool mAudioIsSeeking;
bool mVideoIsSeeking;
bool mHasEssentialTrackBuffers;
};
} // namespace mozilla

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

@ -564,6 +564,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
if (mParser->IsInitSegmentPresent(aData, aLength)) {
MSE_DEBUG("SourceBuffer(%p)::AppendData: New initialization segment.", this);
mMediaSource->QueueInitializationEvent();
mTrackBuffer->DiscardDecoder();
if (!mTrackBuffer->NewDecoder()) {
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.