зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1128420 - remove finished output streams from MediaDecoder::mOutputStreams. r=roc.
This commit is contained in:
Родитель
ae23b9318a
Коммит
42b559fb41
|
@ -350,6 +350,71 @@ MediaDecoder::DecodedStreamGraphListener::NotifyEvent(MediaStreamGraph* aGraph,
|
|||
}
|
||||
}
|
||||
|
||||
class MediaDecoder::OutputStreamListener : public MediaStreamListener {
|
||||
public:
|
||||
OutputStreamListener(MediaDecoder* aDecoder, MediaStream* aStream)
|
||||
: mDecoder(aDecoder), mStream(aStream) {}
|
||||
|
||||
virtual void NotifyEvent(
|
||||
MediaStreamGraph* aGraph,
|
||||
MediaStreamListener::MediaStreamGraphEvent event) MOZ_OVERRIDE {
|
||||
if (event == EVENT_FINISHED) {
|
||||
nsRefPtr<nsIRunnable> r = NS_NewRunnableMethod(
|
||||
this, &OutputStreamListener::DoNotifyFinished);
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(r.forget());
|
||||
}
|
||||
}
|
||||
|
||||
void Forget() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void DoNotifyFinished() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mDecoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the finished stream so it won't block the decoded stream.
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
auto& streams = mDecoder->OutputStreams();
|
||||
// Don't read |mDecoder| in the loop since removing the element will lead
|
||||
// to ~OutputStreamData() which will call Forget() to reset |mDecoder|.
|
||||
for (int32_t i = streams.Length() - 1; i >= 0; --i) {
|
||||
auto& os = streams[i];
|
||||
MediaStream* p = os.mStream.get();
|
||||
if (p == mStream.get()) {
|
||||
if (os.mPort) {
|
||||
os.mPort->Destroy();
|
||||
os.mPort = nullptr;
|
||||
}
|
||||
streams.RemoveElementAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main thread only
|
||||
MediaDecoder* mDecoder;
|
||||
nsRefPtr<MediaStream> mStream;
|
||||
};
|
||||
|
||||
void
|
||||
MediaDecoder::OutputStreamData::Init(MediaDecoder* aDecoder,
|
||||
ProcessedMediaStream* aStream)
|
||||
{
|
||||
mStream = aStream;
|
||||
mListener = new OutputStreamListener(aDecoder, aStream);
|
||||
aStream->AddListener(mListener);
|
||||
}
|
||||
|
||||
MediaDecoder::OutputStreamData::~OutputStreamData()
|
||||
{
|
||||
mListener->Forget();
|
||||
}
|
||||
|
||||
void MediaDecoder::DestroyDecodedStream()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -366,22 +431,20 @@ void MediaDecoder::DestroyDecodedStream()
|
|||
// need to be explicitly blocked again.
|
||||
for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
|
||||
OutputStreamData& os = mOutputStreams[i];
|
||||
// Explicitly remove all existing ports.
|
||||
// This is not strictly necessary but it's good form.
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
os.mPort = nullptr;
|
||||
// During cycle collection, nsDOMMediaStream can be destroyed and send
|
||||
// its Destroy message before this decoder is destroyed. So we have to
|
||||
// be careful not to send any messages after the Destroy().
|
||||
if (os.mStream->IsDestroyed()) {
|
||||
// Probably the DOM MediaStream was GCed. Clean up.
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
continue;
|
||||
} else {
|
||||
os.mStream->ChangeExplicitBlockerCount(1);
|
||||
}
|
||||
os.mStream->ChangeExplicitBlockerCount(1);
|
||||
// Explicitly remove all existing ports. This is not strictly necessary but it's
|
||||
// good form.
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
os.mPort = nullptr;
|
||||
}
|
||||
|
||||
mDecodedStream = nullptr;
|
||||
|
@ -429,12 +492,8 @@ void MediaDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs)
|
|||
// between main-thread stable states take effect atomically.
|
||||
for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
|
||||
OutputStreamData& os = mOutputStreams[i];
|
||||
if (os.mStream->IsDestroyed()) {
|
||||
// Probably the DOM MediaStream was GCed. Clean up.
|
||||
// No need to destroy the port; all ports have been destroyed here.
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
continue;
|
||||
}
|
||||
MOZ_ASSERT(!os.mStream->IsDestroyed(),
|
||||
"Should've been removed in DestroyDecodedStream()");
|
||||
ConnectDecodedStreamToOutputStream(&os);
|
||||
}
|
||||
UpdateStreamBlockingForStateMachinePlaying();
|
||||
|
@ -462,7 +521,7 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream,
|
|||
RecreateDecodedStream(t);
|
||||
}
|
||||
OutputStreamData* os = mOutputStreams.AppendElement();
|
||||
os->Init(aStream, aFinishWhenEnded);
|
||||
os->Init(this, aStream);
|
||||
ConnectDecodedStreamToOutputStream(os);
|
||||
if (aFinishWhenEnded) {
|
||||
// Ensure that aStream finishes the moment mDecodedStream does.
|
||||
|
@ -945,32 +1004,6 @@ void MediaDecoder::PlaybackEnded()
|
|||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
|
||||
for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
|
||||
OutputStreamData& os = mOutputStreams[i];
|
||||
if (os.mStream->IsDestroyed()) {
|
||||
// Probably the DOM MediaStream was GCed. Clean up.
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
continue;
|
||||
}
|
||||
if (os.mFinishWhenEnded) {
|
||||
// Shouldn't really be needed since mDecodedStream should already have
|
||||
// finished, but doesn't hurt.
|
||||
os.mStream->Finish();
|
||||
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
|
||||
os.mPort->Destroy();
|
||||
// Not really needed but it keeps the invariant that a stream not
|
||||
// connected to mDecodedStream is explicity blocked.
|
||||
os.mStream->ChangeExplicitBlockerCount(1);
|
||||
mOutputStreams.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlaybackPositionChanged();
|
||||
ChangeState(PLAY_STATE_ENDED);
|
||||
InvalidateWithFlags(VideoFrameContainer::INVALIDATE_FORCE);
|
||||
|
|
|
@ -479,17 +479,17 @@ public:
|
|||
bool mStreamFinishedOnMainThread;
|
||||
};
|
||||
|
||||
class OutputStreamListener;
|
||||
|
||||
struct OutputStreamData {
|
||||
void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
|
||||
{
|
||||
mStream = aStream;
|
||||
mFinishWhenEnded = aFinishWhenEnded;
|
||||
}
|
||||
void Init(MediaDecoder* aDecoder, ProcessedMediaStream* aStream);
|
||||
~OutputStreamData();
|
||||
nsRefPtr<ProcessedMediaStream> mStream;
|
||||
// mPort connects mDecodedStream->mStream to our mStream.
|
||||
nsRefPtr<MediaInputPort> mPort;
|
||||
bool mFinishWhenEnded;
|
||||
nsRefPtr<OutputStreamListener> mListener;
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects mDecodedStream->mStream to aStream->mStream.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче