Bug 1221009. Part 1 - add a class to forward notifications from MediaResource to MediaDecoder. r=roc.

This commit is contained in:
JW Wang 2015-11-16 07:50:55 +08:00
parent 19e4536fc1
commit 987294af08
7 changed files with 256 additions and 99 deletions

View File

@ -2773,7 +2773,9 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
RefPtr<MediaResource> resource = originalResource->CloneData(decoder);
RefPtr<MediaResource> resource =
originalResource->CloneData(decoder->GetResourceCallback());
if (!resource) {
LOG(LogLevel::Debug, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
@ -2805,7 +2807,9 @@ nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
LOG(LogLevel::Debug, ("%p Created decoder %p for type %s", this, decoder.get(), mimeType.get()));
RefPtr<MediaResource> resource = MediaResource::Create(decoder, aChannel);
RefPtr<MediaResource> resource =
MediaResource::Create(decoder->GetResourceCallback(), aChannel);
if (!resource)
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -127,6 +127,155 @@ NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter)
NS_IMPL_ISUPPORTS0(MediaDecoder)
void
MediaDecoder::ResourceCallback::Connect(MediaDecoder* aDecoder)
{
MOZ_ASSERT(NS_IsMainThread());
mDecoder = aDecoder;
}
void
MediaDecoder::ResourceCallback::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
mDecoder = nullptr;
}
MediaDecoderOwner*
MediaDecoder::ResourceCallback::GetMediaOwner() const
{
MOZ_ASSERT(NS_IsMainThread());
return mDecoder ? mDecoder->GetOwner() : nullptr;
}
void
MediaDecoder::ResourceCallback::SetInfinite(bool aInfinite)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->SetInfinite(aInfinite);
}
}
void
MediaDecoder::ResourceCallback::SetMediaSeekable(bool aMediaSeekable)
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->SetMediaSeekable(aMediaSeekable);
}
}
void
MediaDecoder::ResourceCallback::ResetConnectionState()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->ResetConnectionState();
}
}
nsresult
MediaDecoder::ResourceCallback::FinishDecoderSetup(MediaResource* aResource)
{
MOZ_ASSERT(NS_IsMainThread());
return mDecoder ? mDecoder->FinishDecoderSetup(aResource) : NS_ERROR_FAILURE;
}
void
MediaDecoder::ResourceCallback::NotifyNetworkError()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NetworkError();
}
}
void
MediaDecoder::ResourceCallback::NotifyDecodeError()
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mDecoder) {
self->mDecoder->DecodeError();
}
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::ResourceCallback::NotifyDataArrived()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifyDataArrived();
}
}
void
MediaDecoder::ResourceCallback::NotifyBytesDownloaded()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifyBytesDownloaded();
}
}
void
MediaDecoder::ResourceCallback::NotifyDataEnded(nsresult aStatus)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (!self->mDecoder) {
return;
}
self->mDecoder->NotifyDownloadEnded(aStatus);
if (NS_SUCCEEDED(aStatus)) {
HTMLMediaElement* element = self->GetMediaOwner()->GetMediaElement();
if (element) {
element->DownloadSuspended();
}
// NotifySuspendedStatusChanged will tell the element that download
// has been suspended "by the cache", which is true since we never
// download anything. The element can then transition to HAVE_ENOUGH_DATA.
self->mDecoder->NotifySuspendedStatusChanged();
}
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::ResourceCallback::NotifyPrincipalChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifyPrincipalChanged();
}
}
void
MediaDecoder::ResourceCallback::NotifySuspendedStatusChanged()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecoder) {
mDecoder->NotifySuspendedStatusChanged();
}
}
void
MediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes,
int64_t aOffset)
{
RefPtr<ResourceCallback> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mDecoder) {
self->mDecoder->NotifyBytesConsumed(aBytes, aOffset);
}
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::NotifyOwnerActivityChanged()
{
@ -343,6 +492,7 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
, mDormantSupported(false)
, mLogicalPosition(0.0)
, mDuration(std::numeric_limits<double>::quiet_NaN())
, mResourceCallback(new ResourceCallback())
#ifdef MOZ_EME
, mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
#endif
@ -410,6 +560,7 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
MediaMemoryTracker::AddMediaDecoder(this);
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
mResourceCallback->Connect(this);
//
// Initialize watchers.
@ -446,6 +597,8 @@ MediaDecoder::Shutdown()
mShuttingDown = true;
mResourceCallback->Disconnect();
#ifdef MOZ_EME
mCDMProxyPromiseHolder.RejectIfExists(true, __func__);
#endif
@ -479,6 +632,12 @@ MediaDecoder::~MediaDecoder()
MOZ_COUNT_DTOR(MediaDecoder);
}
MediaResourceCallback*
MediaDecoder::GetResourceCallback() const
{
return mResourceCallback;
}
nsresult
MediaDecoder::OpenResource(nsIStreamListener** aStreamListener)
{
@ -719,43 +878,6 @@ MediaDecoder::FinishDecoderSetup(MediaResource* aResource)
return NS_OK;
}
void
MediaDecoder::NotifyNetworkError()
{
NetworkError();
}
void
MediaDecoder::NotifyDecodeError()
{
nsCOMPtr<nsIRunnable> r =
NS_NewRunnableMethod(this, &MediaDecoder::DecodeError);
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::NotifyDataEnded(nsresult aStatus)
{
RefPtr<MediaDecoder> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mShuttingDown) {
return;
}
self->NotifyDownloadEnded(aStatus);
if (NS_SUCCEEDED(aStatus)) {
HTMLMediaElement* element = self->mOwner->GetMediaElement();
if (element) {
element->DownloadSuspended();
}
// NotifySuspendedStatusChanged will tell the element that download
// has been suspended "by the cache", which is true since we never
// download anything. The element can then transition to HAVE_ENOUGH_DATA.
self->NotifySuspendedStatusChanged();
}
});
AbstractThread::MainThread()->Dispatch(r.forget());
}
void
MediaDecoder::ResetConnectionState()
{
@ -967,13 +1089,6 @@ MediaDecoder::NotifyPrincipalChanged()
void
MediaDecoder::NotifyBytesConsumed(int64_t aBytes, int64_t aOffset)
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArgs<int64_t, int64_t>(
this, &MediaDecoder::NotifyBytesConsumed, aBytes, aOffset);
AbstractThread::MainThread()->Dispatch(r.forget());
return;
}
MOZ_ASSERT(NS_IsMainThread());
if (mShuttingDown || mIgnoreProgressData) {

View File

@ -273,7 +273,7 @@ struct SeekTarget {
MediaDecoderEventVisibility mEventVisibility;
};
class MediaDecoder : public AbstractMediaDecoder, public MediaResourceCallback
class MediaDecoder : public AbstractMediaDecoder
{
public:
struct SeekResolveValue {
@ -283,6 +283,35 @@ public:
MediaDecoderEventVisibility mEventVisibility;
};
// Used to register with MediaResource to receive notifications which will
// be forwarded to MediaDecoder.
class ResourceCallback : public MediaResourceCallback {
public:
// Start to receive notifications from ResourceCallback.
void Connect(MediaDecoder* aDecoder);
// Called upon shutdown to stop receiving notifications.
void Disconnect();
private:
/* MediaResourceCallback functions */
MediaDecoderOwner* GetMediaOwner() const override;
void SetInfinite(bool aInfinite) override;
void SetMediaSeekable(bool aMediaSeekable) override;
void ResetConnectionState() override;
nsresult FinishDecoderSetup(MediaResource* aResource) override;
void NotifyNetworkError() override;
void NotifyDecodeError() override;
void NotifyDataArrived() override;
void NotifyBytesDownloaded() override;
void NotifyDataEnded(nsresult aStatus) override;
void NotifyPrincipalChanged() override;
void NotifySuspendedStatusChanged() override;
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) override;
// The decoder to send notifications. Main-thread only.
MediaDecoder* mDecoder = nullptr;
};
typedef MozPromise<SeekResolveValue, bool /* aIgnored */, /* IsExclusive = */ true> SeekPromise;
NS_DECL_THREADSAFE_ISUPPORTS
@ -302,9 +331,10 @@ public:
explicit MediaDecoder(MediaDecoderOwner* aOwner);
// Reset the decoder and notify the media element that
// server connection is closed.
virtual void ResetConnectionState() override;
// Return a callback object used to register with MediaResource to receive
// notifications.
MediaResourceCallback* GetResourceCallback() const;
// Create a new decoder of the same type as this one.
// Subclasses must implement this.
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) = 0;
@ -325,7 +355,7 @@ public:
nsresult OpenResource(nsIStreamListener** aStreamListener);
// Called if the media file encounters a network error.
virtual void NetworkError();
void NetworkError();
// Get the current MediaResource being used. Its URI will be returned
// by currentSrc. Returns what was passed to Load(), if Load() has been called.
@ -403,47 +433,17 @@ public:
// Return the duration of the video in seconds.
virtual double GetDuration();
// A media stream is assumed to be infinite if the metadata doesn't
// contain the duration, and range requests are not supported, and
// no headers give a hint of a possible duration (Content-Length,
// Content-Duration, and variants), and we cannot seek in the media
// stream to determine the duration.
//
// When the media stream ends, we can know the duration, thus the stream is
// no longer considered to be infinite.
virtual void SetInfinite(bool aInfinite) override;
// Return true if the stream is infinite (see SetInfinite).
virtual bool IsInfinite();
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
virtual void NotifySuspendedStatusChanged() override;
// Called by MediaResource when some data has been received.
// Call on the main thread only.
virtual void NotifyBytesDownloaded() override;
// Called by nsChannelToPipeListener or MediaResource when the
// download has ended. Called on the main thread only. aStatus is
// the result from OnStopRequest.
virtual void NotifyDownloadEnded(nsresult aStatus);
virtual void NotifyBytesDownloaded();
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
virtual void NotifyDataArrived() override;
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
virtual void NotifyPrincipalChanged() override;
// Called by the MediaResource to keep track of the number of bytes read
// from the resource. Called on the main by an event runner dispatched
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;
// Return true if we are currently seeking in the media resource.
// Call on the main thread only.
virtual bool IsSeeking() const;
@ -509,7 +509,7 @@ public:
void SetLoadInBackground(bool aLoadInBackground);
// Returns a weak reference to the media decoder owner.
MediaDecoderOwner* GetMediaOwner() const override;
MediaDecoderOwner* GetMediaOwner() const;
MediaDecoderStateMachine* GetStateMachine() const;
void SetStateMachine(MediaDecoderStateMachine* aStateMachine);
@ -673,7 +673,7 @@ private:
virtual void BreakCycles();
// Notifies the element that decoding has failed.
virtual void DecodeError();
void DecodeError();
// Indicate whether the media is same-origin with the element.
void UpdateSameOriginStatus(bool aSameOrigin);
@ -832,6 +832,8 @@ private:
// Explicitly prievate to force access via accessors.
RefPtr<MediaDecoderStateMachine> mDecoderStateMachine;
RefPtr<ResourceCallback> mResourceCallback;
#ifdef MOZ_EME
MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder;
RefPtr<CDMProxyPromise> mCDMProxyPromise;
@ -1054,11 +1056,43 @@ public:
}
private:
/* MediaResourceCallback functions */
virtual nsresult FinishDecoderSetup(MediaResource* aResource) override;
virtual void NotifyNetworkError() override;
virtual void NotifyDecodeError() override;
virtual void NotifyDataEnded(nsresult aStatus) override;
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't
// contain the duration, and range requests are not supported, and
// no headers give a hint of a possible duration (Content-Length,
// Content-Duration, and variants), and we cannot seek in the media
// stream to determine the duration.
//
// When the media stream ends, we can know the duration, thus the stream is
// no longer considered to be infinite.
void SetInfinite(bool aInfinite);
// Reset the decoder and notify the media element that
// server connection is closed.
void ResetConnectionState();
nsresult FinishDecoderSetup(MediaResource* aResource);
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
void NotifyPrincipalChanged();
// Called by MediaResource when the "cache suspended" status changes.
// If MediaResource::IsSuspendedByCache returns true, then the decoder
// should stop buffering or otherwise waiting for download progress and
// start consuming data, if possible, because the cache is full.
void NotifySuspendedStatusChanged();
// Called by the MediaResource to keep track of the number of bytes read
// from the resource. Called on the main by an event runner dispatched
// by the MediaResource read functions.
void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) final override;
// Called by nsChannelToPipeListener or MediaResource when the
// download has ended. Called on the main thread only. aStatus is
// the result from OnStopRequest.
void NotifyDownloadEnded(nsresult aStatus);
};
} // namespace mozilla

View File

@ -246,7 +246,7 @@ ChannelMediaResource::OnStartRequest(nsIRequest* aRequest)
// Content-Range header text should be parse-able.
CMLOG("Error processing \'Content-Range' for "
"HTTP_PARTIAL_RESPONSE_CODE: rv[%x] channel[%p] decoder[%p]",
rv, hc.get(), mCallback);
rv, hc.get(), mCallback.get());
mCallback->NotifyNetworkError();
CloseChannel();
return NS_OK;
@ -374,7 +374,7 @@ ChannelMediaResource::ParseContentRangeHeader(nsIHttpChannel * aHttpChan,
}
CMLOG("Received bytes [%lld] to [%lld] of [%lld] for decoder[%p]",
aRangeStart, aRangeEnd, aRangeTotal, mCallback);
aRangeStart, aRangeEnd, aRangeTotal, mCallback.get());
return NS_OK;
}
@ -458,7 +458,7 @@ ChannelMediaResource::CopySegmentToCache(nsIInputStream *aInStream,
RESOURCE_LOG("%p [ChannelMediaResource]: CopySegmentToCache at mOffset [%lld] add "
"[%d] bytes for decoder[%p]",
closure->mResource, closure->mResource->mOffset, aCount,
closure->mResource->mCallback);
closure->mResource->mCallback.get());
closure->mResource->mOffset += aCount;
closure->mResource->mCacheStream.NotifyDataReceived(aCount, aFromSegment,
@ -927,7 +927,7 @@ ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
CMLOG("CacheClientSeek requested for aOffset [%lld] for decoder [%p]",
aOffset, mCallback);
aOffset, mCallback.get());
CloseChannel();

View File

@ -16,6 +16,7 @@
#include "nsIInterfaceRequestor.h"
#include "MediaCache.h"
#include "MediaData.h"
#include "MediaResourceCallback.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h"
@ -43,7 +44,6 @@ class nsIPrincipal;
namespace mozilla {
class MediaResourceCallback;
class MediaChannelStatistics;
/**
@ -513,10 +513,7 @@ protected:
// on the main thread. This is called automatically after every read.
void DispatchBytesConsumed(int64_t aNumBytes, int64_t aOffset);
// This is not an nsCOMPointer to prevent a circular reference
// between the decoder to the media stream object. The stream never
// outlives the lifetime of the decoder.
MediaResourceCallback* mCallback;
RefPtr<MediaResourceCallback> mCallback;
// Channel used to download the media data. Must be accessed
// from the main thread only.

View File

@ -8,9 +8,11 @@
#define MediaResourceCallback_h_
#include "nsError.h"
#include "nsISupportsImpl.h"
namespace mozilla {
class MediaDecoderOwner;
class MediaResource;
/**
@ -24,6 +26,8 @@ class MediaResource;
*/
class MediaResourceCallback {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaResourceCallback);
// Returns a weak reference to the media decoder owner.
virtual MediaDecoderOwner* GetMediaOwner() const { return nullptr; }
@ -67,6 +71,9 @@ public:
// Notify the number of bytes read from the resource.
virtual void NotifyBytesConsumed(int64_t aBytes, int64_t aOffset) {}
protected:
virtual ~MediaResourceCallback() {}
};
} // namespace mozilla

View File

@ -857,7 +857,7 @@ nsresult RtspMediaResource::SeekTime(int64_t aOffset)
NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
RTSPMLOG("Seek requested for aOffset [%lld] for decoder [%p]",
aOffset, mCallback);
aOffset, mCallback.get());
// Clear buffer and raise the frametype flag.
for(uint32_t i = 0 ; i < mTrackBuffer.Length(); ++i) {
mTrackBuffer[i]->ResetWithFrameType(MEDIASTREAM_FRAMETYPE_DISCONTINUITY);