Bug 811381 - Flatten nsMediaDecoder and nsBuiltinDecoder into a single class. r=roc

This commit is contained in:
Chris Pearce 2012-11-14 11:45:13 -08:00
Родитель 356627a249
Коммит 9fe37d1328
35 изменённых файлов: 848 добавлений и 1009 удалений

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

@ -172,6 +172,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
#include "nsIDOMScriptObjectFactory.h"
#include "nsSandboxFlags.h"
#include "nsSVGFeatures.h"
#include "nsBuiltinDecoder.h"
#include "nsWrapperCacheInlines.h"
@ -6657,7 +6658,7 @@ nsContentUtils::FindInternalContentViewer(const char* aType,
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (nsMediaDecoder::IsMediaPluginsEnabled() &&
if (nsBuiltinDecoder::IsMediaPluginsEnabled() &&
nsHTMLMediaElement::IsMediaPluginsType(nsDependentCString(aType))) {
docFactory = do_GetService("@mozilla.org/content/document-loader-factory;1");
if (docFactory && aLoaderType) {

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

@ -33,6 +33,8 @@ typedef uint16_t nsMediaReadyState;
namespace mozilla {
class MediaResource;
}
class nsBuiltinDecoder;
#ifdef MOZ_DASH
class nsDASHDecoder;
#endif
@ -215,7 +217,7 @@ public:
// the data for the next frame is available. This method will
// decide whether to set the ready state to HAVE_CURRENT_DATA,
// HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA.
virtual void UpdateReadyStateForData(nsMediaDecoder::NextFrameStatus aNextFrame) MOZ_FINAL MOZ_OVERRIDE;
virtual void UpdateReadyStateForData(nsBuiltinDecoder::NextFrameStatus aNextFrame) MOZ_FINAL MOZ_OVERRIDE;
// Use this method to change the mReadyState member, so required
// events can be fired.
@ -441,14 +443,14 @@ protected:
* Create a decoder for the given aMIMEType. Returns null if we
* were unable to create the decoder.
*/
already_AddRefed<nsMediaDecoder> CreateDecoder(const nsACString& aMIMEType);
already_AddRefed<nsBuiltinDecoder> CreateDecoder(const nsACString& aMIMEType);
/**
* Initialize a decoder as a clone of an existing decoder in another
* element.
* mLoadingSrc must already be set.
*/
nsresult InitializeDecoderAsClone(nsMediaDecoder* aOriginal);
nsresult InitializeDecoderAsClone(nsBuiltinDecoder* aOriginal);
/**
* Initialize a decoder to load the given channel. The decoder's stream
@ -462,10 +464,10 @@ protected:
* Finish setting up the decoder after Load() has been called on it.
* Called by InitializeDecoderForChannel/InitializeDecoderAsClone.
*/
nsresult FinishDecoderSetup(nsMediaDecoder* aDecoder,
nsresult FinishDecoderSetup(nsBuiltinDecoder* aDecoder,
MediaResource* aStream,
nsIStreamListener **aListener,
nsMediaDecoder* aCloneDonor);
nsBuiltinDecoder* aCloneDonor);
/**
* Call this after setting up mLoadingSrc and mDecoder.
@ -658,7 +660,7 @@ protected:
// The current decoder. Load() has been called on this decoder.
// At most one of mDecoder and mSrcStream can be non-null.
nsRefPtr<nsMediaDecoder> mDecoder;
nsRefPtr<nsBuiltinDecoder> mDecoder;
// A reference to the VideoFrameContainer which contains the current frame
// of video to display.

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

@ -4,12 +4,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsHTMLMediaElement.h"
#include "mozilla/Util.h"
#include "base/basictypes.h"
#include "nsIDOMHTMLMediaElement.h"
#include "nsIDOMHTMLSourceElement.h"
#include "nsHTMLMediaElement.h"
#include "nsTimeRanges.h"
#include "nsGenericHTMLElement.h"
#include "nsAttrValueInlines.h"
@ -2021,7 +2021,7 @@ static const char* gRawCodecs[1] = {
static bool IsRawType(const nsACString& aType)
{
if (!nsMediaDecoder::IsRawEnabled()) {
if (!nsBuiltinDecoder::IsRawEnabled()) {
return false;
}
@ -2059,7 +2059,7 @@ char const *const nsHTMLMediaElement::gOggCodecsWithOpus[4] = {
bool
nsHTMLMediaElement::IsOggType(const nsACString& aType)
{
if (!nsMediaDecoder::IsOggEnabled()) {
if (!nsBuiltinDecoder::IsOggEnabled()) {
return false;
}
@ -2092,7 +2092,7 @@ char const *const nsHTMLMediaElement::gWaveCodecs[2] = {
bool
nsHTMLMediaElement::IsWaveType(const nsACString& aType)
{
if (!nsMediaDecoder::IsWaveEnabled()) {
if (!nsBuiltinDecoder::IsWaveEnabled()) {
return false;
}
@ -2122,7 +2122,7 @@ char const *const nsHTMLMediaElement::gWebMCodecs[4] = {
bool
nsHTMLMediaElement::IsWebMType(const nsACString& aType)
{
if (!nsMediaDecoder::IsWebMEnabled()) {
if (!nsBuiltinDecoder::IsWebMEnabled()) {
return false;
}
@ -2181,7 +2181,7 @@ const char nsHTMLMediaElement::gOmxTypes[5][16] = {
bool
nsHTMLMediaElement::IsOmxSupportedType(const nsACString& aType)
{
if (!nsMediaDecoder::IsOmxEnabled()) {
if (!nsBuiltinDecoder::IsOmxEnabled()) {
return false;
}
@ -2199,7 +2199,7 @@ nsHTMLMediaElement::IsOmxSupportedType(const nsACString& aType)
bool
nsHTMLMediaElement::IsMediaPluginsType(const nsACString& aType)
{
if (!nsMediaDecoder::IsMediaPluginsEnabled()) {
if (!nsBuiltinDecoder::IsMediaPluginsEnabled()) {
return false;
}
@ -2225,7 +2225,7 @@ const char nsHTMLMediaElement::gDASHMPDTypes[1][21] = {
bool
nsHTMLMediaElement::IsDASHMPDType(const nsACString& aType)
{
if (!nsMediaDecoder::IsDASHEnabled()) {
if (!nsBuiltinDecoder::IsDASHEnabled()) {
return false;
}
@ -2252,7 +2252,7 @@ nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType,
#endif
#ifdef MOZ_OGG
if (IsOggType(nsDependentCString(aMIMEType))) {
*aCodecList = nsMediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
*aCodecList = nsBuiltinDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
return CANPLAY_MAYBE;
}
#endif
@ -2289,7 +2289,7 @@ nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType,
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (nsMediaDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), aCodecList))
if (nsBuiltinDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), aCodecList))
return CANPLAY_MAYBE;
#endif
return CANPLAY_NO;
@ -2320,7 +2320,7 @@ bool nsHTMLMediaElement::ShouldHandleMediaType(const char* aMIMEType)
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (nsMediaDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), NULL))
if (nsBuiltinDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), NULL))
return true;
#endif
// We should not return true for Wave types, since there are some
@ -2408,7 +2408,7 @@ nsHTMLMediaElement::CanPlayType(const nsAString& aType, nsAString& aResult)
bool
nsHTMLMediaElement::IsGStreamerSupportedType(const nsACString& aMimeType)
{
if (!nsMediaDecoder::IsGStreamerEnabled())
if (!nsBuiltinDecoder::IsGStreamerEnabled())
return false;
if (IsH264Type(aMimeType))
return true;
@ -2426,7 +2426,7 @@ nsHTMLMediaElement::IsGStreamerSupportedType(const nsACString& aMimeType)
}
#endif
already_AddRefed<nsMediaDecoder>
already_AddRefed<nsBuiltinDecoder>
nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
{
@ -2474,7 +2474,7 @@ nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
if (nsMediaDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(aType, NULL)) {
if (nsBuiltinDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(aType, NULL)) {
nsRefPtr<nsMediaPluginDecoder> decoder = new nsMediaPluginDecoder(aType);
if (decoder->Init(this)) {
return decoder.forget();
@ -2502,7 +2502,7 @@ nsHTMLMediaElement::CreateDecoder(const nsACString& aType)
return nullptr;
}
nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsBuiltinDecoder* aOriginal)
{
NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set");
NS_ASSERTION(mDecoder == nullptr, "Shouldn't have a decoder");
@ -2510,7 +2510,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
MediaResource* originalResource = aOriginal->GetResource();
if (!originalResource)
return NS_ERROR_FAILURE;
nsRefPtr<nsMediaDecoder> decoder = aOriginal->Clone();
nsRefPtr<nsBuiltinDecoder> decoder = aOriginal->Clone();
if (!decoder)
return NS_ERROR_FAILURE;
@ -2547,7 +2547,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
aChannel->GetContentType(mMimeType);
NS_ASSERTION(!mMimeType.IsEmpty(), "We should have the Content-Type.");
nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mMimeType);
nsRefPtr<nsBuiltinDecoder> decoder = CreateDecoder(mMimeType);
if (!decoder) {
nsAutoString src;
GetCurrentSrc(src);
@ -2569,10 +2569,10 @@ nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel,
return FinishDecoderSetup(decoder, resource, aListener, nullptr);
}
nsresult nsHTMLMediaElement::FinishDecoderSetup(nsMediaDecoder* aDecoder,
nsresult nsHTMLMediaElement::FinishDecoderSetup(nsBuiltinDecoder* aDecoder,
MediaResource* aStream,
nsIStreamListener **aListener,
nsMediaDecoder* aCloneDonor)
nsBuiltinDecoder* aCloneDonor)
{
mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING;
@ -2653,8 +2653,8 @@ public:
{
if (mElement && mHaveCurrentData) {
mElement->UpdateReadyStateForData(
mBlocked ? nsMediaDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING :
nsMediaDecoder::NEXT_FRAME_AVAILABLE);
mBlocked ? nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING :
nsBuiltinDecoder::NEXT_FRAME_AVAILABLE);
}
}
void DoNotifyBlocked()
@ -3057,7 +3057,7 @@ bool nsHTMLMediaElement::ShouldCheckAllowOrigin()
return mCORSMode != CORS_NONE;
}
void nsHTMLMediaElement::UpdateReadyStateForData(nsMediaDecoder::NextFrameStatus aNextFrame)
void nsHTMLMediaElement::UpdateReadyStateForData(nsBuiltinDecoder::NextFrameStatus aNextFrame)
{
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
// aNextFrame might have a next frame because the decoder can advance
@ -3082,9 +3082,9 @@ void nsHTMLMediaElement::UpdateReadyStateForData(nsMediaDecoder::NextFrameStatus
return;
}
if (aNextFrame != nsMediaDecoder::NEXT_FRAME_AVAILABLE) {
if (aNextFrame != nsBuiltinDecoder::NEXT_FRAME_AVAILABLE) {
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
if (!mWaitingFired && aNextFrame == nsMediaDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
if (!mWaitingFired && aNextFrame == nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
FireTimeUpdate(false);
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
mWaitingFired = true;
@ -3105,7 +3105,7 @@ void nsHTMLMediaElement::UpdateReadyStateForData(nsMediaDecoder::NextFrameStatus
// autoplay elements for live streams will never play. Otherwise we
// move to HAVE_ENOUGH_DATA if we can play through the entire media
// without stopping to buffer.
nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
nsBuiltinDecoder::Statistics stats = mDecoder->GetStatistics();
if (stats.mTotalBytes < 0 ? stats.mDownloadRateReliable :
stats.mTotalBytes == stats.mDownloadPosition ||
mDecoder->CanPlayThrough())

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

@ -30,6 +30,7 @@
#include "nsEventDispatcher.h"
#include "nsIDOMProgressEvent.h"
#include "nsMediaError.h"
#include "nsBuiltinDecoder.h"
using namespace mozilla;
using namespace mozilla::dom;

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

@ -28,7 +28,6 @@ EXPORTS = \
nsBuiltinDecoderReader.h \
nsDOMMediaStream.h \
nsMediaCache.h \
nsMediaDecoder.h \
SharedBuffer.h \
StreamBuffer.h \
TimeVarying.h \
@ -49,7 +48,6 @@ CPPSRCS = \
nsBuiltinDecoderReader.cpp \
nsDOMMediaStream.cpp \
nsMediaCache.cpp \
nsMediaDecoder.cpp \
StreamBuffer.cpp \
VideoFrameContainer.cpp \
VideoSegment.cpp \

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

@ -6,7 +6,7 @@
#ifndef MediaDecoderOwner_h_
#define MediaDecoderOwner_h_
#include "nsMediaDecoder.h"
#include "nsBuiltinDecoder.h"
namespace mozilla {
@ -120,7 +120,7 @@ public:
// the data for the next frame is available. This method will
// decide whether to set the ready state to HAVE_CURRENT_DATA,
// HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA.
virtual void UpdateReadyStateForData(nsMediaDecoder::NextFrameStatus aNextFrame) = 0;
virtual void UpdateReadyStateForData(nsBuiltinDecoder::NextFrameStatus aNextFrame) = 0;
// Called by the media decoder and the video frame to get the
// ImageContainer containing the video data.

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

@ -8,7 +8,7 @@
#include "mozilla/Mutex.h"
#include "nsDebug.h"
#include "nsMediaDecoder.h"
#include "nsBuiltinDecoder.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsIFile.h"
@ -47,7 +47,7 @@ static const uint32_t HTTP_PARTIAL_RESPONSE_CODE = 206;
using namespace mozilla;
ChannelMediaResource::ChannelMediaResource(nsMediaDecoder* aDecoder,
ChannelMediaResource::ChannelMediaResource(nsBuiltinDecoder* aDecoder,
nsIChannel* aChannel, nsIURI* aURI)
: MediaResource(aDecoder, aChannel, aURI),
mOffset(0), mSuspendCount(0),
@ -684,7 +684,7 @@ bool ChannelMediaResource::CanClone()
return mCacheStream.IsAvailableForSharing();
}
MediaResource* ChannelMediaResource::CloneData(nsMediaDecoder* aDecoder)
MediaResource* ChannelMediaResource::CloneData(nsBuiltinDecoder* aDecoder)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
NS_ASSERTION(mCacheStream.IsAvailableForSharing(), "Stream can't be cloned");
@ -932,14 +932,14 @@ ChannelMediaResource::CacheClientNotifyDataReceived()
class DataEnded : public nsRunnable {
public:
DataEnded(nsMediaDecoder* aDecoder, nsresult aStatus) :
DataEnded(nsBuiltinDecoder* aDecoder, nsresult aStatus) :
mDecoder(aDecoder), mStatus(aStatus) {}
NS_IMETHOD Run() {
mDecoder->NotifyDownloadEnded(mStatus);
return NS_OK;
}
private:
nsRefPtr<nsMediaDecoder> mDecoder;
nsRefPtr<nsBuiltinDecoder> mDecoder;
nsresult mStatus;
};
@ -1156,7 +1156,7 @@ ChannelMediaResource::PossiblyResume()
class FileMediaResource : public MediaResource
{
public:
FileMediaResource(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
FileMediaResource(nsBuiltinDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
MediaResource(aDecoder, aChannel, aURI),
mSize(-1),
mLock("FileMediaResource.mLock"),
@ -1174,7 +1174,7 @@ public:
virtual void Resume() {}
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
virtual bool CanClone();
virtual MediaResource* CloneData(nsMediaDecoder* aDecoder);
virtual MediaResource* CloneData(nsBuiltinDecoder* aDecoder);
virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount);
// These methods are called off the main thread.
@ -1268,7 +1268,7 @@ private:
class LoadedEvent : public nsRunnable
{
public:
LoadedEvent(nsMediaDecoder* aDecoder) :
LoadedEvent(nsBuiltinDecoder* aDecoder) :
mDecoder(aDecoder)
{
MOZ_COUNT_CTOR(LoadedEvent);
@ -1284,7 +1284,7 @@ public:
}
private:
nsRefPtr<nsMediaDecoder> mDecoder;
nsRefPtr<nsBuiltinDecoder> mDecoder;
};
void FileMediaResource::EnsureSizeInitialized()
@ -1404,7 +1404,7 @@ bool FileMediaResource::CanClone()
return true;
}
MediaResource* FileMediaResource::CloneData(nsMediaDecoder* aDecoder)
MediaResource* FileMediaResource::CloneData(nsBuiltinDecoder* aDecoder)
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
@ -1495,7 +1495,7 @@ int64_t FileMediaResource::Tell()
}
MediaResource*
MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)
MediaResource::Create(nsBuiltinDecoder* aDecoder, nsIChannel* aChannel)
{
NS_ASSERTION(NS_IsMainThread(),
"MediaResource::Open called on non-main thread");

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

@ -26,7 +26,7 @@ static const int64_t SEEK_VS_READ_THRESHOLD = 32*1024;
static const uint32_t HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
class nsMediaDecoder;
class nsBuiltinDecoder;
namespace mozilla {
@ -177,7 +177,7 @@ public:
// Create a new stream of the same type that refers to the same URI
// with a new channel. Any cached data associated with the original
// stream should be accessible in the new stream too.
virtual MediaResource* CloneData(nsMediaDecoder* aDecoder) = 0;
virtual MediaResource* CloneData(nsBuiltinDecoder* aDecoder) = 0;
// These methods are called off the main thread.
// The mode is initially MODE_PLAYBACK.
@ -260,7 +260,7 @@ public:
// Returns true if this stream is suspended by the cache because the
// cache is full. If true then the decoder should try to start consuming
// data, otherwise we may not be able to make progress.
// nsMediaDecoder::NotifySuspendedStatusChanged is called when this
// nsBuiltinDecoder::NotifySuspendedStatusChanged is called when this
// changes.
// For resources using the media cache, this returns true only when all
// streams for the same resource are all suspended.
@ -282,7 +282,7 @@ public:
* Create a resource, reading data from the channel. Call on main thread only.
* The caller must follow up by calling resource->Open().
*/
static MediaResource* Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel);
static MediaResource* Create(nsBuiltinDecoder* aDecoder, nsIChannel* aChannel);
/**
* Open the stream. This creates a stream listener and returns it in
@ -309,7 +309,7 @@ public:
virtual nsresult GetCachedRanges(nsTArray<MediaByteRange>& aRanges) = 0;
protected:
MediaResource(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
MediaResource(nsBuiltinDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
mDecoder(aDecoder),
mChannel(aChannel),
mURI(aURI),
@ -326,7 +326,7 @@ protected:
// 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.
nsMediaDecoder* mDecoder;
nsBuiltinDecoder* mDecoder;
// Channel used to download the media data. Must be accessed
// from the main thread only.
@ -352,7 +352,7 @@ protected:
class ChannelMediaResource : public MediaResource
{
public:
ChannelMediaResource(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI);
ChannelMediaResource(nsBuiltinDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI);
~ChannelMediaResource();
// These are called on the main thread by nsMediaCache. These must
@ -392,7 +392,7 @@ public:
// Return true if the stream has been closed.
bool IsClosed() const { return mCacheStream.IsClosed(); }
virtual bool CanClone();
virtual MediaResource* CloneData(nsMediaDecoder* aDecoder);
virtual MediaResource* CloneData(nsBuiltinDecoder* aDecoder);
virtual nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount);
virtual void EnsureCacheUpToDate();

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

@ -39,7 +39,7 @@
*
* Media element creates new |nsDASHDecoder| object:
* member var initialization to default values, including a/v sub-decoders.
* nsBuiltinDecoder and nsMediaDecoder constructors are called.
* nsBuiltinDecoder and nsBuiltinDecoder constructors are called.
* nsBuiltinDecoder::Init() is called.
*
* Media element creates new |ChannelMediaResource|:
@ -128,6 +128,8 @@
#include "nsDASHRepDecoder.h"
#include "nsDASHDecoder.h"
using mozilla::ReentrantMonitorAutoEnter;
#ifdef PR_LOGGING
extern PRLogModuleInfo* gBuiltinDecoderLog;
#define LOG(msg, ...) PR_LOG(gBuiltinDecoderLog, PR_LOG_DEBUG, \
@ -185,7 +187,7 @@ nsDASHDecoder::ReleaseStateMachine()
nsresult
nsDASHDecoder::Load(MediaResource* aResource,
nsIStreamListener** aStreamListener,
nsMediaDecoder* aCloneDonor)
nsBuiltinDecoder* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -238,8 +240,8 @@ nsDASHDecoder::NotifyDownloadEnded(nsresult aStatus)
}
} else if (aStatus == NS_BINDING_ABORTED) {
LOG("MPD download has been cancelled by the user: aStatus [%x].", aStatus);
if (mElement) {
mElement->LoadAborted();
if (mOwner) {
mOwner->LoadAborted();
}
return;
} else if (aStatus != NS_BASE_STREAM_CLOSED) {
@ -433,11 +435,11 @@ nsDASHDecoder::CreateAudioRepDecoder(nsIURI* aUrl,
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_ARG(aUrl);
NS_ENSURE_ARG(aRep);
NS_ENSURE_TRUE(mElement, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_INITIALIZED);
// Create subdecoder and init with media element.
nsDASHRepDecoder* audioDecoder = new nsDASHRepDecoder(this);
NS_ENSURE_TRUE(audioDecoder->Init(mElement), NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(audioDecoder->Init(mOwner), NS_ERROR_NOT_INITIALIZED);
if (!mAudioRepDecoder) {
mAudioRepDecoder = audioDecoder;
@ -453,7 +455,7 @@ nsDASHDecoder::CreateAudioRepDecoder(nsIURI* aUrl,
// Create media resource with URL and connect to sub-decoder.
MediaResource* audioResource
= CreateAudioSubResource(aUrl, static_cast<nsMediaDecoder*>(audioDecoder));
= CreateAudioSubResource(aUrl, static_cast<nsBuiltinDecoder*>(audioDecoder));
NS_ENSURE_TRUE(audioResource, NS_ERROR_NOT_INITIALIZED);
audioDecoder->SetResource(audioResource);
@ -469,11 +471,11 @@ nsDASHDecoder::CreateVideoRepDecoder(nsIURI* aUrl,
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_ARG(aUrl);
NS_ENSURE_ARG(aRep);
NS_ENSURE_TRUE(mElement, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(mOwner, NS_ERROR_NOT_INITIALIZED);
// Create subdecoder and init with media element.
nsDASHRepDecoder* videoDecoder = new nsDASHRepDecoder(this);
NS_ENSURE_TRUE(videoDecoder->Init(mElement), NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(videoDecoder->Init(mOwner), NS_ERROR_NOT_INITIALIZED);
if (!mVideoRepDecoder) {
mVideoRepDecoder = videoDecoder;
@ -489,7 +491,7 @@ nsDASHDecoder::CreateVideoRepDecoder(nsIURI* aUrl,
// Create media resource with URL and connect to sub-decoder.
MediaResource* videoResource
= CreateVideoSubResource(aUrl, static_cast<nsMediaDecoder*>(videoDecoder));
= CreateVideoSubResource(aUrl, static_cast<nsBuiltinDecoder*>(videoDecoder));
NS_ENSURE_TRUE(videoResource, NS_ERROR_NOT_INITIALIZED);
videoDecoder->SetResource(videoResource);
@ -500,7 +502,7 @@ nsDASHDecoder::CreateVideoRepDecoder(nsIURI* aUrl,
mozilla::MediaResource*
nsDASHDecoder::CreateAudioSubResource(nsIURI* aUrl,
nsMediaDecoder* aAudioDecoder)
nsBuiltinDecoder* aAudioDecoder)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE(aUrl, nullptr);
@ -521,7 +523,7 @@ nsDASHDecoder::CreateAudioSubResource(nsIURI* aUrl,
mozilla::MediaResource*
nsDASHDecoder::CreateVideoSubResource(nsIURI* aUrl,
nsMediaDecoder* aVideoDecoder)
nsBuiltinDecoder* aVideoDecoder)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE(aUrl, nullptr);
@ -546,14 +548,19 @@ nsDASHDecoder::CreateSubChannel(nsIURI* aUrl, nsIChannel** aChannel)
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_ARG(aUrl);
nsCOMPtr<nsILoadGroup> loadGroup = mElement->GetDocumentLoadGroup();
NS_ENSURE_TRUE(mOwner, NS_ERROR_NULL_POINTER);
nsHTMLMediaElement* element = mOwner->GetMediaElement();
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsILoadGroup> loadGroup =
element->GetDocumentLoadGroup();
NS_ENSURE_TRUE(loadGroup, NS_ERROR_NULL_POINTER);
// Check for a Content Security Policy to pass down to the channel
// created to load the media content.
nsCOMPtr<nsIChannelPolicy> channelPolicy;
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsresult rv = mElement->NodePrincipal()->GetCsp(getter_AddRefs(csp));
nsresult rv = element->NodePrincipal()->GetCsp(getter_AddRefs(csp));
NS_ENSURE_SUCCESS(rv,rv);
if (csp) {
channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1");
@ -653,8 +660,8 @@ nsDASHDecoder::NotifyDownloadEnded(nsDASHRepDecoder* aRepDecoder,
return;
} else if (aStatus == NS_BINDING_ABORTED) {
LOG("MPD download has been cancelled by the user: aStatus [%x].", aStatus);
if (mElement) {
mElement->LoadAborted();
if (mOwner) {
mOwner->LoadAborted();
}
return;
} else if (aStatus != NS_BASE_STREAM_CLOSED) {
@ -668,8 +675,8 @@ nsDASHDecoder::LoadAborted()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (!mNotifiedLoadAborted && mElement) {
mElement->LoadAborted();
if (!mNotifiedLoadAborted && mOwner) {
mOwner->LoadAborted();
mNotifiedLoadAborted = true;
LOG1("Load Aborted! Notifying media element.");
}

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

@ -46,7 +46,7 @@ public:
~nsDASHDecoder();
// Clone not supported; just return nullptr.
nsMediaDecoder* Clone() { return nullptr; }
nsBuiltinDecoder* Clone() { return nullptr; }
// Creates a single state machine for all stream decoders.
// Called from Load on the main thread only.
@ -56,7 +56,7 @@ public:
// Called from the main thread only.
nsresult Load(MediaResource* aResource,
nsIStreamListener** aListener,
nsMediaDecoder* aCloneDonor);
nsBuiltinDecoder* aCloneDonor);
// Notifies download of MPD file has ended.
// Called on the main thread only.
@ -111,9 +111,9 @@ private:
// Creates audio/video resources for individual |Representation|s.
// On the main thread.
MediaResource* CreateAudioSubResource(nsIURI* aUrl,
nsMediaDecoder* aAudioDecoder);
nsBuiltinDecoder* aAudioDecoder);
MediaResource* CreateVideoSubResource(nsIURI* aUrl,
nsMediaDecoder* aVideoDecoder);
nsBuiltinDecoder* aVideoDecoder);
// Creates an http channel for a |Representation|.
// On the main thread.

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

@ -20,6 +20,8 @@
#include "MediaResource.h"
#include "nsDASHRepDecoder.h"
using mozilla::ReentrantMonitor;
#ifdef PR_LOGGING
extern PRLogModuleInfo* gBuiltinDecoderLog;
#define LOG(msg, ...) PR_LOG(gBuiltinDecoderLog, PR_LOG_DEBUG, \
@ -71,7 +73,7 @@ nsDASHRepDecoder::SetReader(nsWebMReader* aReader)
nsresult
nsDASHRepDecoder::Load(MediaResource* aResource,
nsIStreamListener** aListener,
nsMediaDecoder* aCloneDonor)
nsBuiltinDecoder* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ENSURE_TRUE(mMPDRepresentation, NS_ERROR_NOT_INITIALIZED);

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

@ -49,7 +49,7 @@ public:
}
// Clone not supported; just return nullptr.
virtual nsMediaDecoder* Clone() { return nullptr; }
virtual nsBuiltinDecoder* Clone() { return nullptr; }
// Called by the main decoder at creation time; points to the main state
// machine managed by the main decoder. Called on the main thread only.
@ -72,7 +72,7 @@ public:
// Called from nsDASHDecoder on main thread; Starts media stream download.
nsresult Load(MediaResource* aResource = nullptr,
nsIStreamListener** aListener = nullptr,
nsMediaDecoder* aCloneDonor = nullptr);
nsBuiltinDecoder* aCloneDonor = nullptr);
// Loads the next byte range (or first one on first call). Called on the main
// thread only.

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

@ -12,7 +12,7 @@
class nsGStreamerDecoder : public nsBuiltinDecoder
{
public:
virtual nsMediaDecoder* Clone() { return new nsGStreamerDecoder(); }
virtual nsBuiltinDecoder* Clone() { return new nsGStreamerDecoder(); }
virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
};

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

@ -618,12 +618,12 @@ int64_t nsGStreamerReader::QueryDuration()
}
}
if (mDecoder->mDuration != -1 &&
/*if (mDecoder->mDuration != -1 &&
mDecoder->mDuration > duration) {
/* We decoded more than the reported duration (which could be estimated) */
// We decoded more than the reported duration (which could be estimated)
LOG(PR_LOG_DEBUG, ("mDuration > duration"));
duration = mDecoder->mDuration;
}
}*/
return duration;
}

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

@ -11,8 +11,7 @@
#include <gst/video/video.h>
#include "nsBuiltinDecoderReader.h"
class nsMediaDecoder;
class nsBuiltinDecoder;
class nsTimeRanges;
class nsGStreamerReader : public nsBuiltinDecoderReader

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

@ -17,6 +17,27 @@
#include "nsTimeRanges.h"
#include "nsContentUtils.h"
#include "ImageContainer.h"
#include "MediaResource.h"
#include "nsError.h"
#include "mozilla/Preferences.h"
using namespace mozilla;
using namespace mozilla::layers;
// Number of milliseconds between progress events as defined by spec
static const uint32_t PROGRESS_MS = 350;
// Number of milliseconds of no data before a stall event is fired as defined by spec
static const uint32_t STALL_MS = 3000;
// Number of estimated seconds worth of data we need to have buffered
// ahead of the current playback position before we allow the media decoder
// to report that it can play through the entire media without the decode
// catching up with the download. Having this margin make the
// nsBuiltinDecoder::CanPlayThrough() calculation more stable in the case of
// fluctuating bitrates.
static const int64_t CAN_PLAY_THROUGH_MARGIN = 10;
using namespace mozilla;
@ -27,6 +48,65 @@ PRLogModuleInfo* gBuiltinDecoderLog;
#define LOG(type, msg)
#endif
namespace mozilla {
class MediaMemoryReporter
{
MediaMemoryReporter();
~MediaMemoryReporter();
static MediaMemoryReporter* sUniqueInstance;
static MediaMemoryReporter* UniqueInstance() {
if (!sUniqueInstance) {
sUniqueInstance = new MediaMemoryReporter;
}
return sUniqueInstance;
}
typedef nsTArray<nsBuiltinDecoder*> DecodersArray;
static DecodersArray& Decoders() {
return UniqueInstance()->mDecoders;
}
DecodersArray mDecoders;
nsCOMPtr<nsIMemoryReporter> mMediaDecodedVideoMemory;
nsCOMPtr<nsIMemoryReporter> mMediaDecodedAudioMemory;
public:
static void AddMediaDecoder(nsBuiltinDecoder* aDecoder) {
Decoders().AppendElement(aDecoder);
}
static void RemoveMediaDecoder(nsBuiltinDecoder* aDecoder) {
DecodersArray& decoders = Decoders();
decoders.RemoveElement(aDecoder);
if (decoders.IsEmpty()) {
delete sUniqueInstance;
sUniqueInstance = nullptr;
}
}
static int64_t GetDecodedVideoMemory() {
DecodersArray& decoders = Decoders();
int64_t result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->VideoQueueMemoryInUse();
}
return result;
}
static int64_t GetDecodedAudioMemory() {
DecodersArray& decoders = Decoders();
int64_t result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->AudioQueueMemoryInUse();
}
return result;
}
};
} //namespace mozilla
NS_IMPL_THREADSAFE_ISUPPORTS1(nsBuiltinDecoder, nsIObserver)
void nsBuiltinDecoder::Pause()
@ -229,10 +309,15 @@ nsBuiltinDecoder::nsBuiltinDecoder() :
mResourceLoaded(false),
mIgnoreProgressData(false),
mInfiniteStream(false),
mTriggerPlaybackEndedWhenSourceStreamFinishes(false)
mTriggerPlaybackEndedWhenSourceStreamFinishes(false),
mOwner(nullptr),
mFrameBufferLength(0),
mPinnedForSeek(false),
mShuttingDown(false)
{
MOZ_COUNT_CTOR(nsBuiltinDecoder);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
MediaMemoryReporter::AddMediaDecoder(this);
#ifdef PR_LOGGING
if (!gBuiltinDecoderLog) {
gBuiltinDecoderLog = PR_NewLogModule("nsBuiltinDecoder");
@ -243,9 +328,8 @@ nsBuiltinDecoder::nsBuiltinDecoder() :
bool nsBuiltinDecoder::Init(MediaDecoderOwner* aOwner)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
if (!nsMediaDecoder::Init(aOwner))
return false;
mOwner = aOwner;
mVideoFrameContainer = aOwner->GetVideoFrameContainer();
nsContentUtils::RegisterShutdownObserver(this);
return true;
}
@ -278,7 +362,9 @@ void nsBuiltinDecoder::Shutdown()
}
ChangeState(PLAY_STATE_SHUTDOWN);
nsMediaDecoder::Shutdown();
StopProgress();
mOwner = nullptr;
nsContentUtils::UnregisterShutdownObserver(this);
}
@ -286,6 +372,7 @@ void nsBuiltinDecoder::Shutdown()
nsBuiltinDecoder::~nsBuiltinDecoder()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
MediaMemoryReporter::RemoveMediaDecoder(this);
UnpinForSeek();
MOZ_COUNT_DTOR(nsBuiltinDecoder);
}
@ -318,7 +405,7 @@ nsresult nsBuiltinDecoder::OpenResource(MediaResource* aResource,
nsresult nsBuiltinDecoder::Load(MediaResource* aResource,
nsIStreamListener** aStreamListener,
nsMediaDecoder* aCloneDonor)
nsBuiltinDecoder* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -334,7 +421,7 @@ nsresult nsBuiltinDecoder::Load(MediaResource* aResource,
return InitializeStateMachine(aCloneDonor);
}
nsresult nsBuiltinDecoder::InitializeStateMachine(nsMediaDecoder* aCloneDonor)
nsresult nsBuiltinDecoder::InitializeStateMachine(nsBuiltinDecoder* aCloneDonor)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -364,14 +451,16 @@ nsresult nsBuiltinDecoder::InitializeStateMachine(nsMediaDecoder* aCloneDonor)
nsresult nsBuiltinDecoder::RequestFrameBufferLength(uint32_t aLength)
{
nsresult res = nsMediaDecoder::RequestFrameBufferLength(aLength);
NS_ENSURE_SUCCESS(res,res);
if (aLength < FRAMEBUFFER_LENGTH_MIN || aLength > FRAMEBUFFER_LENGTH_MAX) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
mFrameBufferLength = aLength;
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
if (mDecoderStateMachine) {
mDecoderStateMachine->SetFrameBufferLength(aLength);
}
return res;
return NS_OK;
}
nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
@ -735,7 +824,7 @@ NS_IMETHODIMP nsBuiltinDecoder::Observe(nsISupports *aSubjet,
return NS_OK;
}
nsMediaDecoder::Statistics
nsBuiltinDecoder::Statistics
nsBuiltinDecoder::GetStatistics()
{
NS_ASSERTION(NS_IsMainThread() || OnStateMachineThread(),
@ -878,7 +967,7 @@ void nsBuiltinDecoder::NextFrameUnavailableBuffering()
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(nsMediaDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING);
mOwner->UpdateReadyStateForData(nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING);
}
void nsBuiltinDecoder::NextFrameAvailable()
@ -887,7 +976,7 @@ void nsBuiltinDecoder::NextFrameAvailable()
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(nsMediaDecoder::NEXT_FRAME_AVAILABLE);
mOwner->UpdateReadyStateForData(nsBuiltinDecoder::NEXT_FRAME_AVAILABLE);
}
void nsBuiltinDecoder::NextFrameUnavailable()
@ -895,7 +984,7 @@ void nsBuiltinDecoder::NextFrameUnavailable()
NS_ASSERTION(NS_IsMainThread(), "Should be called on main thread");
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(nsMediaDecoder::NEXT_FRAME_UNAVAILABLE);
mOwner->UpdateReadyStateForData(nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE);
}
void nsBuiltinDecoder::UpdateReadyStateForData()
@ -1220,6 +1309,18 @@ ReentrantMonitor& nsBuiltinDecoder::GetReentrantMonitor() {
return mReentrantMonitor.GetReentrantMonitor();
}
ImageContainer* nsBuiltinDecoder::GetImageContainer()
{
return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nullptr;
}
void nsBuiltinDecoder::Invalidate()
{
if (mVideoFrameContainer) {
mVideoFrameContainer->Invalidate();
}
}
// Constructs the time ranges representing what segments of the media
// are buffered and playable.
nsresult nsBuiltinDecoder::GetBuffered(nsTimeRanges* aBuffered) {
@ -1264,3 +1365,230 @@ void nsBuiltinDecoder::ReleaseStateMachine() {
mDecoderStateMachine = nullptr;
}
MediaDecoderOwner* nsBuiltinDecoder::GetMediaOwner() const
{
return mOwner;
}
static void ProgressCallback(nsITimer* aTimer, void* aClosure)
{
nsBuiltinDecoder* decoder = static_cast<nsBuiltinDecoder*>(aClosure);
decoder->Progress(true);
}
void nsBuiltinDecoder::Progress(bool aTimer)
{
if (!mOwner)
return;
TimeStamp now = TimeStamp::Now();
if (!aTimer) {
mDataTime = now;
}
// If PROGRESS_MS has passed since the last progress event fired and more
// data has arrived since then, fire another progress event.
if ((mProgressTime.IsNull() ||
now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
!mDataTime.IsNull() &&
now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
mProgressTime = now;
}
if (!mDataTime.IsNull() &&
now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
mOwner->DownloadStalled();
// Null it out
mDataTime = TimeStamp();
}
}
nsresult nsBuiltinDecoder::StartProgress()
{
if (mProgressTimer)
return NS_OK;
mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
return mProgressTimer->InitWithFuncCallback(ProgressCallback,
this,
PROGRESS_MS,
nsITimer::TYPE_REPEATING_SLACK);
}
nsresult nsBuiltinDecoder::StopProgress()
{
if (!mProgressTimer)
return NS_OK;
nsresult rv = mProgressTimer->Cancel();
mProgressTimer = nullptr;
return rv;
}
void nsBuiltinDecoder::FireTimeUpdate()
{
if (!mOwner)
return;
mOwner->FireTimeUpdate(true);
}
void nsBuiltinDecoder::PinForSeek()
{
MediaResource* resource = GetResource();
if (!resource || mPinnedForSeek) {
return;
}
mPinnedForSeek = true;
resource->Pin();
}
void nsBuiltinDecoder::UnpinForSeek()
{
MediaResource* resource = GetResource();
if (!resource || !mPinnedForSeek) {
return;
}
mPinnedForSeek = false;
resource->Unpin();
}
bool nsBuiltinDecoder::CanPlayThrough()
{
Statistics stats = GetStatistics();
if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
return false;
}
int64_t bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
int64_t bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
double timeToDownload = bytesToDownload / stats.mDownloadRate;
double timeToPlay = bytesToPlayback / stats.mPlaybackRate;
if (timeToDownload > timeToPlay) {
// Estimated time to download is greater than the estimated time to play.
// We probably can't play through without having to stop to buffer.
return false;
}
// Estimated time to download is less than the estimated time to play.
// We can probably play through without having to buffer, but ensure that
// we've got a reasonable amount of data buffered after the current
// playback position, so that if the bitrate of the media fluctuates, or if
// our download rate or decode rate estimation is otherwise inaccurate,
// we don't suddenly discover that we need to buffer. This is particularly
// required near the start of the media, when not much data is downloaded.
int64_t readAheadMargin =
static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
return stats.mTotalBytes == stats.mDownloadPosition ||
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
}
#ifdef MOZ_RAW
bool
nsBuiltinDecoder::IsRawEnabled()
{
return Preferences::GetBool("media.raw.enabled");
}
#endif
#ifdef MOZ_OGG
bool
nsBuiltinDecoder::IsOpusEnabled()
{
#ifdef MOZ_OPUS
return Preferences::GetBool("media.opus.enabled");
#else
return false;
#endif
}
bool
nsBuiltinDecoder::IsOggEnabled()
{
return Preferences::GetBool("media.ogg.enabled");
}
#endif
#ifdef MOZ_WAVE
bool
nsBuiltinDecoder::IsWaveEnabled()
{
return Preferences::GetBool("media.wave.enabled");
}
#endif
#ifdef MOZ_WEBM
bool
nsBuiltinDecoder::IsWebMEnabled()
{
return Preferences::GetBool("media.webm.enabled");
}
#endif
#ifdef MOZ_GSTREAMER
bool
nsBuiltinDecoder::IsGStreamerEnabled()
{
return Preferences::GetBool("media.gstreamer.enabled");
}
#endif
#ifdef MOZ_WIDGET_GONK
bool
nsBuiltinDecoder::IsOmxEnabled()
{
return Preferences::GetBool("media.omx.enabled", false);
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
bool
nsBuiltinDecoder::IsMediaPluginsEnabled()
{
return Preferences::GetBool("media.plugins.enabled");
}
#endif
#ifdef MOZ_DASH
bool
nsBuiltinDecoder::IsDASHEnabled()
{
return Preferences::GetBool("media.dash.enabled");
}
#endif
namespace mozilla {
MediaMemoryReporter* MediaMemoryReporter::sUniqueInstance;
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedVideoMemory,
"explicit/media/decoded-video",
KIND_HEAP,
UNITS_BYTES,
MediaMemoryReporter::GetDecodedVideoMemory,
"Memory used by decoded video frames.")
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedAudioMemory,
"explicit/media/decoded-audio",
KIND_HEAP,
UNITS_BYTES,
MediaMemoryReporter::GetDecodedAudioMemory,
"Memory used by decoded audio chunks.")
MediaMemoryReporter::MediaMemoryReporter()
: mMediaDecodedVideoMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedVideoMemory))
, mMediaDecodedAudioMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedAudioMemory))
{
NS_RegisterMemoryReporter(mMediaDecodedVideoMemory);
NS_RegisterMemoryReporter(mMediaDecodedAudioMemory);
}
MediaMemoryReporter::~MediaMemoryReporter()
{
NS_UnregisterMemoryReporter(mMediaDecodedVideoMemory);
NS_UnregisterMemoryReporter(mMediaDecodedAudioMemory);
}
} // namespace mozilla

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

@ -138,7 +138,7 @@ player SHUTDOWN decoder SHUTDOWN
The general sequence of events is:
1) The video element calls Load on nsMediaDecoder. This creates the
1) The video element calls Load on nsBuiltinDecoder. This creates the
state machine and starts the channel for downloading the
file. It instantiates and schedules the nsBuiltinDecoderStateMachine. The
high level LOADING state is entered, which results in the decode
@ -178,8 +178,6 @@ destroying the nsBuiltinDecoder object.
#if !defined(nsBuiltinDecoder_h_)
#define nsBuiltinDecoder_h_
#include "nsMediaDecoder.h"
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
@ -191,28 +189,58 @@ destroying the nsBuiltinDecoder object.
#include "gfxContext.h"
#include "gfxRect.h"
#include "MediaResource.h"
#include "nsMediaDecoder.h"
#include "mozilla/ReentrantMonitor.h"
#include "MediaStreamGraph.h"
namespace mozilla {
namespace layers {
class Image;
} //namespace
class nsMediaByteRange;
class VideoFrameContainer;
class MediaDecoderOwner;
} //namespace
typedef mozilla::layers::Image Image;
class nsAudioStream;
class nsBuiltinDecoderStateMachine;
class nsIStreamListener;
class nsTimeRanges;
class nsIMemoryReporter;
class nsIPrincipal;
class nsITimer;
// The size to use for audio data frames in MozAudioAvailable events.
// This value is per channel, and is chosen to give ~43 fps of events,
// for example, 44100 with 2 channels, 2*1024 = 2048.
static const uint32_t FRAMEBUFFER_LENGTH_PER_CHANNEL = 1024;
// The total size of the framebuffer used for MozAudioAvailable events
// has to be within the following range.
static const uint32_t FRAMEBUFFER_LENGTH_MIN = 512;
static const uint32_t FRAMEBUFFER_LENGTH_MAX = 16384;
static inline bool IsCurrentThread(nsIThread* aThread) {
return NS_GetCurrentThread() == aThread;
}
class nsBuiltinDecoder : public nsMediaDecoder
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
class nsBuiltinDecoder : public nsIObserver
{
public:
typedef mozilla::MediaChannelStatistics MediaChannelStatistics;
typedef mozilla::MediaResource MediaResource;
typedef mozilla::MediaByteRange MediaByteRange;
typedef mozilla::ReentrantMonitor ReentrantMonitor;
typedef mozilla::SourceMediaStream SourceMediaStream;
typedef mozilla::ProcessedMediaStream ProcessedMediaStream;
typedef mozilla::MediaInputPort MediaInputPort;
typedef mozilla::MainThreadMediaStreamListener MainThreadMediaStreamListener;
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
typedef mozilla::VideoFrameContainer VideoFrameContainer;
typedef mozilla::layers::Image Image;
class DecodedStreamMainThreadListener;
NS_DECL_ISUPPORTS
@ -230,40 +258,84 @@ public:
};
nsBuiltinDecoder();
~nsBuiltinDecoder();
virtual ~nsBuiltinDecoder();
// Create a new decoder of the same type as this one.
// Subclasses must implement this.
virtual nsBuiltinDecoder* Clone() = 0;
// Create a new state machine to run this decoder.
// Subclasses must implement this.
virtual nsBuiltinDecoderStateMachine* CreateStateMachine() = 0;
// Call on the main thread only.
// Perform any initialization required for the decoder.
// Return true on successful initialisation, false
// on failure.
virtual bool Init(mozilla::MediaDecoderOwner* aOwner);
// This method must be called by the owning object before that
// object disposes of this decoder object.
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.
virtual void Shutdown();
virtual double GetCurrentTime();
// Start downloading the media. Decode the downloaded data up to the
// point of the first frame of data.
// aResource is the media stream to use. Ownership of aResource passes to
// the decoder, even if Load returns an error.
// This is called at most once per decoder, after Init().
virtual nsresult Load(MediaResource* aResource,
nsIStreamListener** aListener,
nsMediaDecoder* aCloneDonor);
nsBuiltinDecoder* aCloneDonor);
// Called in |Load| to open the media resource.
nsresult OpenResource(MediaResource* aResource,
nsIStreamListener** aStreamListener);
virtual nsBuiltinDecoderStateMachine* CreateStateMachine() = 0;
// Called when the video file has completed downloading.
virtual void ResourceLoaded();
// Called if the media file encounters a network error.
virtual 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.
virtual MediaResource* GetResource() { return mResource; }
// Return the principal of the current URI being played or downloaded.
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
// Return the time position in the video stream being
// played measured in seconds.
virtual double GetCurrentTime();
// Seek to the time position in (seconds) from the start of the video.
virtual nsresult Seek(double aTime);
// Enables decoders to supply an enclosing byte range for a seek offset.
// E.g. used by ChannelMediaResource to download a whole cluster for
// DASH-WebM.
virtual nsresult GetByteRangeForSeek(int64_t const aOffset,
MediaByteRange &aByteRange) {
return NS_ERROR_NOT_AVAILABLE;
}
// Initialize state machine and schedule it.
nsresult InitializeStateMachine(nsMediaDecoder* aCloneDonor);
nsresult InitializeStateMachine(nsBuiltinDecoder* aCloneDonor);
// Start playback of a video. 'Load' must have previously been
// called.
virtual nsresult Play();
// Seek to the time position in (seconds) from the start of the video.
virtual nsresult Seek(double aTime);
// Called by the element when the playback rate has been changed.
// Adjust the speed of the playback, optionally with pitch correction,
// when this is called.
virtual nsresult PlaybackRateChanged();
// Pause video playback.
virtual void Pause();
// Adjust the speed of the playback, optionally with pitch correction,
virtual void SetVolume(double aVolume);
// Sets whether audio is being captured. If it is, we won't play any
// of our audio.
virtual void SetAudioCaptured(bool aCaptured);
// All MediaStream-related data is protected by mReentrantMonitor.
@ -365,32 +437,54 @@ public:
nsBuiltinDecoder* mDecoder;
};
// Add an output stream. All decoder output will be sent to the stream.
// The stream is initially blocked. The decoder is responsible for unblocking
// it while it is playing back.
virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
// 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);
// Return true if the stream is infinite (see SetInfinite).
virtual bool IsInfinite();
virtual MediaResource* GetResource() { return mResource; }
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
// 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();
// Called by MediaResource when some data has been received.
// Call on the main thread only.
virtual void NotifyBytesDownloaded();
// 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);
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
virtual void NotifyPrincipalChanged();
// Called by the decode thread to keep track of the number of bytes read
// from the resource.
void NotifyBytesConsumed(int64_t aBytes);
// Called when the video file has completed downloading.
// Call on the main thread only.
void ResourceLoaded();
// Called if the media file encounters a network error.
// Call on the main thread only.
virtual void NetworkError();
// Return true if we are currently seeking in the media resource.
// Call on the main thread only.
virtual bool IsSeeking() const;
@ -410,27 +504,45 @@ public:
// Return true if seeking is supported.
virtual bool IsSeekable();
// Return the time ranges that can be seeked into.
virtual nsresult GetSeekable(nsTimeRanges* aSeekable);
// Set the end time of the media resource. When playback reaches
// this point the media pauses. aTime is in seconds.
virtual void SetEndTime(double aTime);
virtual Statistics GetStatistics();
// Invalidate the frame.
void Invalidate();
// Suspend any media downloads that are in progress. Called by the
// media element when it is sent to the bfcache. Call on the main
// thread only.
// media element when it is sent to the bfcache, or when we need
// to throttle the download. Call on the main thread only. This can
// be called multiple times, there's an internal "suspend count".
virtual void Suspend();
// Resume any media downloads that have been suspended. Called by the
// media element when it is restored from the bfcache. Call on the
// main thread only.
// media element when it is restored from the bfcache, or when we need
// to stop throttling the download. Call on the main thread only.
// The download will only actually resume once as many Resume calls
// have been made as Suspend calls. When aForceBuffering is true,
// we force the decoder to go into buffering state before resuming
// playback.
virtual void Resume(bool aForceBuffering);
// Tells our MediaResource to put all loads in the background.
// Moves any existing channel loads into the background, so that they don't
// block the load event. This is called when we stop delaying the load
// event. Any new loads initiated (for example to seek) will also be in the
// background. Implementations of this must call MoveLoadsToBackground() on
// their MediaResource.
virtual void MoveLoadsToBackground();
// Returns a weak reference to the media decoder owner.
mozilla::MediaDecoderOwner* GetMediaOwner() const;
// Returns the current size of the framebuffer used in
// MozAudioAvailable events.
uint32_t GetFrameBufferLength() { return mFrameBufferLength; }
void AudioAvailable(float* aFrameBuffer, uint32_t aFrameBufferLength, float aTime);
// Called by the state machine to notify the decoder that the duration
@ -449,11 +561,13 @@ public:
// are buffered and playable.
virtual nsresult GetBuffered(nsTimeRanges* aBuffered);
// Returns the size, in bytes, of the heap memory used by the currently
// queued decoded video and audio data.
virtual int64_t VideoQueueMemoryInUse();
virtual int64_t AudioQueueMemoryInUse();
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset);
VideoFrameContainer* GetVideoFrameContainer() { return mVideoFrameContainer; }
virtual mozilla::layers::ImageContainer* GetImageContainer();
// Sets the length of the framebuffer used in MozAudioAvailable events.
// The new size must be between 512 and 16384.
@ -465,6 +579,16 @@ public:
return mPlayState;
}
// Fire progress events if needed according to the time and byte
// constraints outlined in the specification. aTimer is true
// if the method is called as a result of the progress timer rather
// than the result of downloaded data.
void Progress(bool aTimer);
// Fire timeupdate events if needed according to the time constraints
// outlined in the specification.
void FireTimeUpdate();
// Stop updating the bytes downloaded for progress notifications. Called
// when seeking to prevent wild changes to the progress notification.
// Must be called with the decoder monitor held.
@ -481,6 +605,10 @@ public:
// The actual playback rate computation. The monitor must be held.
double ComputePlaybackRate(bool* aReliable);
// Returns true if we can play the entire media through without stopping
// to buffer, given the current download and playback rates.
bool CanPlayThrough();
// Make the decoder state machine update the playback position. Called by
// the reader on the decoder thread (Assertions for this checked by
// mDecoderStateMachine). This must be called with the decode monitor
@ -556,17 +684,181 @@ public:
// Drop reference to state machine. Only called during shutdown dance.
virtual void ReleaseStateMachine();
// Called when a "MozAudioAvailable" event listener is added to the media
// element. Called on the main thread.
virtual void NotifyAudioAvailableListener();
// Called when a "MozAudioAvailable" event listener is added. This enables
// the decoder to only dispatch "MozAudioAvailable" events when a
// handler exists, reducing overhead. Called on the main thread.
virtual void NotifyAudioAvailableListener();
// Notifies the element that decoding has failed.
virtual void DecodeError();
// The status of the next frame which might be available from the decoder
enum NextFrameStatus {
// The next frame of audio/video is available
NEXT_FRAME_AVAILABLE,
// The next frame of audio/video is unavailable because the decoder
// is paused while it buffers up data
NEXT_FRAME_UNAVAILABLE_BUFFERING,
// The next frame of audio/video is unavailable for some other reasons
NEXT_FRAME_UNAVAILABLE
};
#ifdef MOZ_RAW
static bool IsRawEnabled();
#endif
#ifdef MOZ_OGG
static bool IsOggEnabled();
static bool IsOpusEnabled();
#endif
#ifdef MOZ_WAVE
static bool IsWaveEnabled();
#endif
#ifdef MOZ_WEBM
static bool IsWebMEnabled();
#endif
#ifdef MOZ_GSTREAMER
static bool IsGStreamerEnabled();
#endif
#ifdef MOZ_WIDGET_GONK
static bool IsOmxEnabled();
#endif
#ifdef MOZ_MEDIA_PLUGINS
static bool IsMediaPluginsEnabled();
#endif
#ifdef MOZ_DASH
static bool IsDASHEnabled();
#endif
// Schedules the state machine to run one cycle on the shared state
// machine thread. Main thread only.
nsresult ScheduleStateMachineThread();
struct Statistics {
// Estimate of the current playback rate (bytes/second).
double mPlaybackRate;
// Estimate of the current download rate (bytes/second). This
// ignores time that the channel was paused by Gecko.
double mDownloadRate;
// Total length of media stream in bytes; -1 if not known
int64_t mTotalBytes;
// Current position of the download, in bytes. This is the offset of
// the first uncached byte after the decoder position.
int64_t mDownloadPosition;
// Current position of decoding, in bytes (how much of the stream
// has been consumed)
int64_t mDecoderPosition;
// Current position of playback, in bytes
int64_t mPlaybackPosition;
// If false, then mDownloadRate cannot be considered a reliable
// estimate (probably because the download has only been running
// a short time).
bool mDownloadRateReliable;
// If false, then mPlaybackRate cannot be considered a reliable
// estimate (probably because playback has only been running
// a short time).
bool mPlaybackRateReliable;
};
// Return statistics. This is used for progress events and other things.
// This can be called from any thread. It's only a snapshot of the
// current state, since other threads might be changing the state
// at any time.
Statistics GetStatistics();
// Frame decoding/painting related performance counters.
// Threadsafe.
class FrameStatistics {
public:
FrameStatistics() :
mReentrantMonitor("nsBuiltinDecoder::FrameStats"),
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
uint32_t GetParsedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mParsedFrames;
}
// Returns the number of parsed frames which have been decoded.
// Can be called on any thread.
uint32_t GetDecodedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDecodedFrames;
}
// Returns the number of decoded frames which have been sent to the rendering
// pipeline for painting ("presented").
// Can be called on any thread.
uint32_t GetPresentedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mPresentedFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) {
if (aParsed == 0 && aDecoded == 0)
return;
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mParsedFrames += aParsed;
mDecodedFrames += aDecoded;
}
// Increments the presented frame counters.
// Can be called on any thread.
void NotifyPresentedFrame() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mPresentedFrames;
}
private:
// ReentrantMonitor to protect access of playback statistics.
ReentrantMonitor mReentrantMonitor;
// Number of frames parsed and demuxed from media.
// Access protected by mStatsReentrantMonitor.
uint32_t mParsedFrames;
// Number of parsed frames which were actually decoded.
// Access protected by mStatsReentrantMonitor.
uint32_t mDecodedFrames;
// Number of decoded frames which were actually sent down the rendering
// pipeline to be painted ("presented"). Access protected by mStatsReentrantMonitor.
uint32_t mPresentedFrames;
};
// Stack based class to assist in notifying the frame statistics of
// parsed and decoded frames. Use inside video demux & decode functions
// to ensure all parsed and decoded frames are reported on all return paths.
class AutoNotifyDecoded {
public:
AutoNotifyDecoded(nsBuiltinDecoder* aDecoder, uint32_t& aParsed, uint32_t& aDecoded)
: mDecoder(aDecoder), mParsed(aParsed), mDecoded(aDecoded) {}
~AutoNotifyDecoded() {
mDecoder->GetFrameStatistics().NotifyDecodedFrames(mParsed, mDecoded);
}
private:
nsBuiltinDecoder* mDecoder;
uint32_t& mParsed;
uint32_t& mDecoded;
};
// Return the frame decode/paint related statistics.
FrameStatistics& GetFrameStatistics() { return mFrameStats; }
/******
* The following members should be accessed with the decoder lock held.
******/
@ -708,6 +1000,57 @@ public:
// True if NotifyDecodedStreamMainThreadStateChanged should retrigger
// PlaybackEnded when mDecodedStream->mStream finishes.
bool mTriggerPlaybackEndedWhenSourceStreamFinishes;
protected:
// Start timer to update download progress information.
nsresult StartProgress();
// Stop progress information timer.
nsresult StopProgress();
// Ensures our media stream has been pinned.
void PinForSeek();
// Ensures our media stream has been unpinned.
void UnpinForSeek();
// Timer used for updating progress events
nsCOMPtr<nsITimer> mProgressTimer;
// This should only ever be accessed from the main thread.
// It is set in Init and cleared in Shutdown when the element goes away.
// The decoder does not add a reference the element.
mozilla::MediaDecoderOwner* mOwner;
// Counters related to decode and presentation of frames.
FrameStatistics mFrameStats;
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
// Time that the last progress event was fired. Read/Write from the
// main thread only.
TimeStamp mProgressTime;
// Time that data was last read from the media resource. Used for
// computing if the download has stalled and to rate limit progress events
// when data is arriving slower than PROGRESS_MS. A value of null indicates
// that a stall event has already fired and not to fire another one until
// more data is received. Read/Write from the main thread only.
TimeStamp mDataTime;
// The framebuffer size to use for audioavailable events.
uint32_t mFrameBufferLength;
// True when our media stream has been pinned. We pin the stream
// while seeking.
bool mPinnedForSeek;
// True if the decoder is being shutdown. At this point all events that
// are currently queued need to return immediately to prevent javascript
// being run that operates on the element and decoder during shutdown.
// Read/Write from the main thread only.
bool mShuttingDown;
};
#endif

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

@ -1308,15 +1308,15 @@ void nsBuiltinDecoderStateMachine::ClearPositionChangeFlag()
mPositionChangeQueued = false;
}
nsMediaDecoder::NextFrameStatus nsBuiltinDecoderStateMachine::GetNextFrameStatus()
nsBuiltinDecoder::NextFrameStatus nsBuiltinDecoderStateMachine::GetNextFrameStatus()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (IsBuffering() || IsSeeking()) {
return nsMediaDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING;
return nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING;
} else if (HaveNextFrameData()) {
return nsMediaDecoder::NEXT_FRAME_AVAILABLE;
return nsBuiltinDecoder::NEXT_FRAME_AVAILABLE;
}
return nsMediaDecoder::NEXT_FRAME_UNAVAILABLE;
return nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE;
}
void nsBuiltinDecoderStateMachine::SetVolume(double volume)
@ -2389,13 +2389,13 @@ void nsBuiltinDecoderStateMachine::UpdateReadyState() {
nsCOMPtr<nsIRunnable> event;
switch (GetNextFrameStatus()) {
case nsMediaDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING:
case nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE_BUFFERING:
event = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::NextFrameUnavailableBuffering);
break;
case nsMediaDecoder::NEXT_FRAME_AVAILABLE:
case nsBuiltinDecoder::NEXT_FRAME_AVAILABLE:
event = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::NextFrameAvailable);
break;
case nsMediaDecoder::NEXT_FRAME_UNAVAILABLE:
case nsBuiltinDecoder::NEXT_FRAME_UNAVAILABLE:
event = NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::NextFrameUnavailable);
break;
default:
@ -2443,7 +2443,7 @@ void nsBuiltinDecoderStateMachine::StartBuffering()
LOG(PR_LOG_DEBUG, ("%p Changed state from DECODING to BUFFERING, decoded for %.3lfs",
mDecoder.get(), decodeDuration.ToSeconds()));
#ifdef PR_LOGGING
nsMediaDecoder::Statistics stats = mDecoder->GetStatistics();
nsBuiltinDecoder::Statistics stats = mDecoder->GetStatistics();
#endif
LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s",
mDecoder.get(),

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

@ -164,7 +164,7 @@ public:
return IsCurrentThread(mAudioThread);
}
nsMediaDecoder::NextFrameStatus GetNextFrameStatus();
nsBuiltinDecoder::NextFrameStatus GetNextFrameStatus();
// Cause state transitions. These methods obtain the decoder monitor
// to synchronise the change of state, and to notify other threads

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

@ -160,7 +160,7 @@ class ReentrantMonitorAutoEnter;
*
* nsMediaCache has a single internal monitor for all synchronization.
* This is treated as the lowest level monitor in the media code. So,
* we must not acquire any nsMediaDecoder locks or MediaResource locks
* we must not acquire any nsBuiltinDecoder locks or MediaResource locks
* while holding the nsMediaCache lock. But it's OK to hold those locks
* and then get the nsMediaCache lock.
*

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

@ -1,294 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaDecoderOwner.h"
#include "MediaResource.h"
#include "mozilla/Preferences.h"
#include "nsError.h"
using namespace mozilla;
// Number of milliseconds between progress events as defined by spec
static const uint32_t PROGRESS_MS = 350;
// Number of milliseconds of no data before a stall event is fired as defined by spec
static const uint32_t STALL_MS = 3000;
// Number of estimated seconds worth of data we need to have buffered
// ahead of the current playback position before we allow the media decoder
// to report that it can play through the entire media without the decode
// catching up with the download. Having this margin make the
// nsMediaDecoder::CanPlayThrough() calculation more stable in the case of
// fluctuating bitrates.
static const int64_t CAN_PLAY_THROUGH_MARGIN = 10;
nsMediaDecoder::nsMediaDecoder() :
mOwner(nullptr),
mFrameBufferLength(0),
mPinnedForSeek(false),
mShuttingDown(false)
{
MOZ_COUNT_CTOR(nsMediaDecoder);
MediaMemoryReporter::AddMediaDecoder(this);
}
nsMediaDecoder::~nsMediaDecoder()
{
MOZ_COUNT_DTOR(nsMediaDecoder);
MediaMemoryReporter::RemoveMediaDecoder(this);
}
bool nsMediaDecoder::Init(MediaDecoderOwner* aOwner)
{
mOwner = aOwner;
mVideoFrameContainer = aOwner->GetVideoFrameContainer();
return true;
}
void nsMediaDecoder::Shutdown()
{
StopProgress();
mOwner = nullptr;
}
MediaDecoderOwner* nsMediaDecoder::GetMediaOwner() const
{
return mOwner;
}
nsresult nsMediaDecoder::RequestFrameBufferLength(uint32_t aLength)
{
if (aLength < FRAMEBUFFER_LENGTH_MIN || aLength > FRAMEBUFFER_LENGTH_MAX) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
mFrameBufferLength = aLength;
return NS_OK;
}
static void ProgressCallback(nsITimer* aTimer, void* aClosure)
{
nsMediaDecoder* decoder = static_cast<nsMediaDecoder*>(aClosure);
decoder->Progress(true);
}
void nsMediaDecoder::Progress(bool aTimer)
{
if (!mOwner)
return;
TimeStamp now = TimeStamp::Now();
if (!aTimer) {
mDataTime = now;
}
// If PROGRESS_MS has passed since the last progress event fired and more
// data has arrived since then, fire another progress event.
if ((mProgressTime.IsNull() ||
now - mProgressTime >= TimeDuration::FromMilliseconds(PROGRESS_MS)) &&
!mDataTime.IsNull() &&
now - mDataTime <= TimeDuration::FromMilliseconds(PROGRESS_MS)) {
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
mProgressTime = now;
}
if (!mDataTime.IsNull() &&
now - mDataTime >= TimeDuration::FromMilliseconds(STALL_MS)) {
mOwner->DownloadStalled();
// Null it out
mDataTime = TimeStamp();
}
}
nsresult nsMediaDecoder::StartProgress()
{
if (mProgressTimer)
return NS_OK;
mProgressTimer = do_CreateInstance("@mozilla.org/timer;1");
return mProgressTimer->InitWithFuncCallback(ProgressCallback,
this,
PROGRESS_MS,
nsITimer::TYPE_REPEATING_SLACK);
}
nsresult nsMediaDecoder::StopProgress()
{
if (!mProgressTimer)
return NS_OK;
nsresult rv = mProgressTimer->Cancel();
mProgressTimer = nullptr;
return rv;
}
void nsMediaDecoder::FireTimeUpdate()
{
if (!mOwner)
return;
mOwner->FireTimeUpdate(true);
}
void nsMediaDecoder::PinForSeek()
{
MediaResource* resource = GetResource();
if (!resource || mPinnedForSeek) {
return;
}
mPinnedForSeek = true;
resource->Pin();
}
void nsMediaDecoder::UnpinForSeek()
{
MediaResource* resource = GetResource();
if (!resource || !mPinnedForSeek) {
return;
}
mPinnedForSeek = false;
resource->Unpin();
}
bool nsMediaDecoder::CanPlayThrough()
{
Statistics stats = GetStatistics();
if (!stats.mDownloadRateReliable || !stats.mPlaybackRateReliable) {
return false;
}
int64_t bytesToDownload = stats.mTotalBytes - stats.mDownloadPosition;
int64_t bytesToPlayback = stats.mTotalBytes - stats.mPlaybackPosition;
double timeToDownload = bytesToDownload / stats.mDownloadRate;
double timeToPlay = bytesToPlayback / stats.mPlaybackRate;
if (timeToDownload > timeToPlay) {
// Estimated time to download is greater than the estimated time to play.
// We probably can't play through without having to stop to buffer.
return false;
}
// Estimated time to download is less than the estimated time to play.
// We can probably play through without having to buffer, but ensure that
// we've got a reasonable amount of data buffered after the current
// playback position, so that if the bitrate of the media fluctuates, or if
// our download rate or decode rate estimation is otherwise inaccurate,
// we don't suddenly discover that we need to buffer. This is particularly
// required near the start of the media, when not much data is downloaded.
int64_t readAheadMargin =
static_cast<int64_t>(stats.mPlaybackRate * CAN_PLAY_THROUGH_MARGIN);
return stats.mTotalBytes == stats.mDownloadPosition ||
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
}
#ifdef MOZ_RAW
bool
nsMediaDecoder::IsRawEnabled()
{
return Preferences::GetBool("media.raw.enabled");
}
#endif
#ifdef MOZ_OGG
bool
nsMediaDecoder::IsOpusEnabled()
{
#ifdef MOZ_OPUS
return Preferences::GetBool("media.opus.enabled");
#else
return false;
#endif
}
bool
nsMediaDecoder::IsOggEnabled()
{
return Preferences::GetBool("media.ogg.enabled");
}
#endif
#ifdef MOZ_WAVE
bool
nsMediaDecoder::IsWaveEnabled()
{
return Preferences::GetBool("media.wave.enabled");
}
#endif
#ifdef MOZ_WEBM
bool
nsMediaDecoder::IsWebMEnabled()
{
return Preferences::GetBool("media.webm.enabled");
}
#endif
#ifdef MOZ_GSTREAMER
bool
nsMediaDecoder::IsGStreamerEnabled()
{
return Preferences::GetBool("media.gstreamer.enabled");
}
#endif
#ifdef MOZ_WIDGET_GONK
bool
nsMediaDecoder::IsOmxEnabled()
{
return Preferences::GetBool("media.omx.enabled", false);
}
#endif
#ifdef MOZ_MEDIA_PLUGINS
bool
nsMediaDecoder::IsMediaPluginsEnabled()
{
return Preferences::GetBool("media.plugins.enabled");
}
#endif
#ifdef MOZ_DASH
bool
nsMediaDecoder::IsDASHEnabled()
{
return Preferences::GetBool("media.dash.enabled");
}
#endif
namespace mozilla {
MediaMemoryReporter* MediaMemoryReporter::sUniqueInstance;
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedVideoMemory,
"explicit/media/decoded-video",
KIND_HEAP,
UNITS_BYTES,
MediaMemoryReporter::GetDecodedVideoMemory,
"Memory used by decoded video frames.")
NS_MEMORY_REPORTER_IMPLEMENT(MediaDecodedAudioMemory,
"explicit/media/decoded-audio",
KIND_HEAP,
UNITS_BYTES,
MediaMemoryReporter::GetDecodedAudioMemory,
"Memory used by decoded audio chunks.")
MediaMemoryReporter::MediaMemoryReporter()
: mMediaDecodedVideoMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedVideoMemory))
, mMediaDecodedAudioMemory(new NS_MEMORY_REPORTER_NAME(MediaDecodedAudioMemory))
{
NS_RegisterMemoryReporter(mMediaDecodedVideoMemory);
NS_RegisterMemoryReporter(mMediaDecodedAudioMemory);
}
MediaMemoryReporter::~MediaMemoryReporter()
{
NS_UnregisterMemoryReporter(mMediaDecodedVideoMemory);
NS_UnregisterMemoryReporter(mMediaDecodedAudioMemory);
}
} // namespace mozilla

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

@ -1,548 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(nsMediaDecoder_h_)
#define nsMediaDecoder_h_
#include "mozilla/ReentrantMonitor.h"
#include "VideoFrameContainer.h"
#include "MediaStreamGraph.h"
#include "nsIObserver.h"
#include "nsDataHashtable.h"
class nsHTMLMediaElement;
class nsIStreamListener;
class nsTimeRanges;
class nsIMemoryReporter;
class nsIPrincipal;
class nsITimer;
namespace mozilla {
class MediaResource;
class MediaByteRange;
class MediaDecoderOwner;
}
// The size to use for audio data frames in MozAudioAvailable events.
// This value is per channel, and is chosen to give ~43 fps of events,
// for example, 44100 with 2 channels, 2*1024 = 2048.
static const uint32_t FRAMEBUFFER_LENGTH_PER_CHANNEL = 1024;
// The total size of the framebuffer used for MozAudioAvailable events
// has to be within the following range.
static const uint32_t FRAMEBUFFER_LENGTH_MIN = 512;
static const uint32_t FRAMEBUFFER_LENGTH_MAX = 16384;
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
// All methods of nsMediaDecoder must be called from the main thread only
// with the exception of GetVideoFrameContainer and GetStatistics,
// which can be called from any thread.
class nsMediaDecoder : public nsIObserver
{
public:
typedef mozilla::MediaResource MediaResource;
typedef mozilla::MediaByteRange MediaByteRange;
typedef mozilla::ReentrantMonitor ReentrantMonitor;
typedef mozilla::SourceMediaStream SourceMediaStream;
typedef mozilla::ProcessedMediaStream ProcessedMediaStream;
typedef mozilla::MediaInputPort MediaInputPort;
typedef mozilla::MainThreadMediaStreamListener MainThreadMediaStreamListener;
typedef mozilla::TimeStamp TimeStamp;
typedef mozilla::TimeDuration TimeDuration;
typedef mozilla::VideoFrameContainer VideoFrameContainer;
nsMediaDecoder();
virtual ~nsMediaDecoder();
// Create a new decoder of the same type as this one.
virtual nsMediaDecoder* Clone() = 0;
// Perform any initialization required for the decoder.
// Return true on successful initialisation, false
// on failure.
virtual bool Init(mozilla::MediaDecoderOwner* aOwner);
// Get the current MediaResource being used. Its URI will be returned
// by currentSrc. Returns what was passed to Load(), if Load() has been called.
virtual MediaResource* GetResource() = 0;
// Return the principal of the current URI being played or downloaded.
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0;
// Return the time position in the video stream being
// played measured in seconds.
virtual double GetCurrentTime() = 0;
// Seek to the time position in (seconds) from the start of the video.
virtual nsresult Seek(double aTime) = 0;
// Enables decoders to supply an enclosing byte range for a seek offset.
// E.g. used by ChannelMediaResource to download a whole cluster for
// DASH-WebM.
virtual nsresult GetByteRangeForSeek(int64_t const aOffset,
MediaByteRange &aByteRange) {
return NS_ERROR_NOT_AVAILABLE;
}
// Called by the element when the playback rate has been changed.
// Adjust the speed of the playback, optionally with pitch correction,
// when this is called.
virtual nsresult PlaybackRateChanged() = 0;
// Return the duration of the video in seconds.
virtual double GetDuration() = 0;
// 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) = 0;
// Return true if the stream is infinite (see SetInfinite).
virtual bool IsInfinite() = 0;
// Pause video playback.
virtual void Pause() = 0;
// Set the audio volume. It should be a value from 0 to 1.0.
virtual void SetVolume(double aVolume) = 0;
// Sets whether audio is being captured. If it is, we won't play any
// of our audio.
virtual void SetAudioCaptured(bool aCaptured) = 0;
// Add an output stream. All decoder output will be sent to the stream.
// The stream is initially blocked. The decoder is responsible for unblocking
// it while it is playing back.
virtual void AddOutputStream(ProcessedMediaStream* aStream,
bool aFinishWhenEnded) = 0;
// Start playback of a video. 'Load' must have previously been
// called.
virtual nsresult Play() = 0;
// Start downloading the media. Decode the downloaded data up to the
// point of the first frame of data.
// aResource is the media stream to use. Ownership of aResource passes to
// the decoder, even if Load returns an error.
// This is called at most once per decoder, after Init().
virtual nsresult Load(MediaResource* aResource,
nsIStreamListener **aListener,
nsMediaDecoder* aCloneDonor) = 0;
// Called when the video file has completed downloading.
virtual void ResourceLoaded() = 0;
// Called if the media file encounters a network error.
virtual void NetworkError() = 0;
// Call from any thread safely. Return true if we are currently
// seeking in the media resource.
virtual bool IsSeeking() const = 0;
// Return true if the decoder has reached the end of playback.
// Call in the main thread only.
virtual bool IsEnded() const = 0;
// Called when a "MozAudioAvailable" event listener is added. This enables
// the decoder to only dispatch "MozAudioAvailable" events when a
// handler exists, reducing overhead. Called on the main thread.
virtual void NotifyAudioAvailableListener() = 0;
struct Statistics {
// Estimate of the current playback rate (bytes/second).
double mPlaybackRate;
// Estimate of the current download rate (bytes/second). This
// ignores time that the channel was paused by Gecko.
double mDownloadRate;
// Total length of media stream in bytes; -1 if not known
int64_t mTotalBytes;
// Current position of the download, in bytes. This is the offset of
// the first uncached byte after the decoder position.
int64_t mDownloadPosition;
// Current position of decoding, in bytes (how much of the stream
// has been consumed)
int64_t mDecoderPosition;
// Current position of playback, in bytes
int64_t mPlaybackPosition;
// If false, then mDownloadRate cannot be considered a reliable
// estimate (probably because the download has only been running
// a short time).
bool mDownloadRateReliable;
// If false, then mPlaybackRate cannot be considered a reliable
// estimate (probably because playback has only been running
// a short time).
bool mPlaybackRateReliable;
};
// Frame decoding/painting related performance counters.
// Threadsafe.
class FrameStatistics {
public:
FrameStatistics() :
mReentrantMonitor("nsMediaDecoder::FrameStats"),
mParsedFrames(0),
mDecodedFrames(0),
mPresentedFrames(0) {}
// Returns number of frames which have been parsed from the media.
// Can be called on any thread.
uint32_t GetParsedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mParsedFrames;
}
// Returns the number of parsed frames which have been decoded.
// Can be called on any thread.
uint32_t GetDecodedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mDecodedFrames;
}
// Returns the number of decoded frames which have been sent to the rendering
// pipeline for painting ("presented").
// Can be called on any thread.
uint32_t GetPresentedFrames() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
return mPresentedFrames;
}
// Increments the parsed and decoded frame counters by the passed in counts.
// Can be called on any thread.
void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded) {
if (aParsed == 0 && aDecoded == 0)
return;
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mParsedFrames += aParsed;
mDecodedFrames += aDecoded;
}
// Increments the presented frame counters.
// Can be called on any thread.
void NotifyPresentedFrame() {
mozilla::ReentrantMonitorAutoEnter mon(mReentrantMonitor);
++mPresentedFrames;
}
private:
// ReentrantMonitor to protect access of playback statistics.
ReentrantMonitor mReentrantMonitor;
// Number of frames parsed and demuxed from media.
// Access protected by mStatsReentrantMonitor.
uint32_t mParsedFrames;
// Number of parsed frames which were actually decoded.
// Access protected by mStatsReentrantMonitor.
uint32_t mDecodedFrames;
// Number of decoded frames which were actually sent down the rendering
// pipeline to be painted ("presented"). Access protected by mStatsReentrantMonitor.
uint32_t mPresentedFrames;
};
// Stack based class to assist in notifying the frame statistics of
// parsed and decoded frames. Use inside video demux & decode functions
// to ensure all parsed and decoded frames are reported on all return paths.
class AutoNotifyDecoded {
public:
AutoNotifyDecoded(nsMediaDecoder* aDecoder, uint32_t& aParsed, uint32_t& aDecoded)
: mDecoder(aDecoder), mParsed(aParsed), mDecoded(aDecoded) {}
~AutoNotifyDecoded() {
mDecoder->GetFrameStatistics().NotifyDecodedFrames(mParsed, mDecoded);
}
private:
nsMediaDecoder* mDecoder;
uint32_t& mParsed;
uint32_t& mDecoded;
};
// Return statistics. This is used for progress events and other things.
// This can be called from any thread. It's only a snapshot of the
// current state, since other threads might be changing the state
// at any time.
virtual Statistics GetStatistics() = 0;
// Return the frame decode/paint related statistics.
FrameStatistics& GetFrameStatistics() { return mFrameStats; }
// Set the duration of the media resource in units of seconds.
// This is called via a channel listener if it can pick up the duration
// from a content header. Must be called from the main thread only.
virtual void SetDuration(double aDuration) = 0;
// Set a flag indicating whether seeking is supported
virtual void SetSeekable(bool aSeekable) = 0;
// Return true if seeking is supported.
virtual bool IsSeekable() = 0;
// Return the time ranges that can be seeked into.
virtual nsresult GetSeekable(nsTimeRanges* aSeekable) = 0;
// Set the end time of the media resource. When playback reaches
// this point the media pauses. aTime is in seconds.
virtual void SetEndTime(double aTime) = 0;
// Invalidate the frame.
void Invalidate()
{
if (mVideoFrameContainer) {
mVideoFrameContainer->Invalidate();
}
}
// Fire progress events if needed according to the time and byte
// constraints outlined in the specification. aTimer is true
// if the method is called as a result of the progress timer rather
// than the result of downloaded data.
virtual void Progress(bool aTimer);
// Fire timeupdate events if needed according to the time constraints
// outlined in the specification.
virtual void FireTimeUpdate();
// 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() = 0;
// Called by MediaResource when some data has been received.
// Call on the main thread only.
virtual void NotifyBytesDownloaded() = 0;
// 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) = 0;
// Called by MediaResource when the principal of the resource has
// changed. Called on main thread only.
virtual void NotifyPrincipalChanged() = 0;
// Called as data arrives on the stream and is read into the cache. Called
// on the main thread only.
virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) = 0;
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.
virtual void Shutdown();
// Suspend any media downloads that are in progress. Called by the
// media element when it is sent to the bfcache, or when we need
// to throttle the download. Call on the main thread only. This can
// be called multiple times, there's an internal "suspend count".
virtual void Suspend() = 0;
// Resume any media downloads that have been suspended. Called by the
// media element when it is restored from the bfcache, or when we need
// to stop throttling the download. Call on the main thread only.
// The download will only actually resume once as many Resume calls
// have been made as Suspend calls. When aForceBuffering is true,
// we force the decoder to go into buffering state before resuming
// playback.
virtual void Resume(bool aForceBuffering) = 0;
// Returns a weak reference to the media element we're decoding for,
// if it's available.
mozilla::MediaDecoderOwner* GetMediaOwner() const;
// Returns the current size of the framebuffer used in
// MozAudioAvailable events.
uint32_t GetFrameBufferLength() { return mFrameBufferLength; }
// Sets the length of the framebuffer used in MozAudioAvailable events.
// The new size must be between 512 and 16384.
virtual nsresult RequestFrameBufferLength(uint32_t aLength);
// Moves any existing channel loads into the background, so that they don't
// block the load event. This is called when we stop delaying the load
// event. Any new loads initiated (for example to seek) will also be in the
// background. Implementations of this must call MoveLoadsToBackground() on
// their MediaResource.
virtual void MoveLoadsToBackground()=0;
// Constructs the time ranges representing what segments of the media
// are buffered and playable.
virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
// Returns true if we can play the entire media through without stopping
// to buffer, given the current download and playback rates.
bool CanPlayThrough();
// Returns the size, in bytes, of the heap memory used by the currently
// queued decoded video and audio data.
virtual int64_t VideoQueueMemoryInUse() = 0;
virtual int64_t AudioQueueMemoryInUse() = 0;
VideoFrameContainer* GetVideoFrameContainer() { return mVideoFrameContainer; }
virtual mozilla::layers::ImageContainer* GetImageContainer()
{
return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer() : nullptr;
}
// The status of the next frame which might be available from the decoder
enum NextFrameStatus {
// The next frame of audio/video is available
NEXT_FRAME_AVAILABLE,
// The next frame of audio/video is unavailable because the decoder
// is paused while it buffers up data
NEXT_FRAME_UNAVAILABLE_BUFFERING,
// The next frame of audio/video is unavailable for some other reasons
NEXT_FRAME_UNAVAILABLE
};
#ifdef MOZ_RAW
static bool IsRawEnabled();
#endif
#ifdef MOZ_OGG
static bool IsOggEnabled();
static bool IsOpusEnabled();
#endif
#ifdef MOZ_WAVE
static bool IsWaveEnabled();
#endif
#ifdef MOZ_WEBM
static bool IsWebMEnabled();
#endif
#ifdef MOZ_GSTREAMER
static bool IsGStreamerEnabled();
#endif
#ifdef MOZ_WIDGET_GONK
static bool IsOmxEnabled();
#endif
#ifdef MOZ_MEDIA_PLUGINS
static bool IsMediaPluginsEnabled();
#endif
#ifdef MOZ_DASH
static bool IsDASHEnabled();
#endif
protected:
// Start timer to update download progress information.
nsresult StartProgress();
// Stop progress information timer.
nsresult StopProgress();
// Ensures our media stream has been pinned.
void PinForSeek();
// Ensures our media stream has been unpinned.
void UnpinForSeek();
// Timer used for updating progress events
nsCOMPtr<nsITimer> mProgressTimer;
// This should only ever be accessed from the main thread.
// It is set in Init and cleared in Shutdown when the element goes away.
// The decoder does not add a reference the element.
mozilla::MediaDecoderOwner* mOwner;
// Counters related to decode and presentation of frames.
FrameStatistics mFrameStats;
nsRefPtr<VideoFrameContainer> mVideoFrameContainer;
// Time that the last progress event was fired. Read/Write from the
// main thread only.
TimeStamp mProgressTime;
// Time that data was last read from the media resource. Used for
// computing if the download has stalled and to rate limit progress events
// when data is arriving slower than PROGRESS_MS. A value of null indicates
// that a stall event has already fired and not to fire another one until
// more data is received. Read/Write from the main thread only.
TimeStamp mDataTime;
// The framebuffer size to use for audioavailable events.
uint32_t mFrameBufferLength;
// True when our media stream has been pinned. We pin the stream
// while seeking.
bool mPinnedForSeek;
// True if the decoder is being shutdown. At this point all events that
// are currently queued need to return immediately to prevent javascript
// being run that operates on the element and decoder during shutdown.
// Read/Write from the main thread only.
bool mShuttingDown;
};
namespace mozilla {
class MediaMemoryReporter
{
MediaMemoryReporter();
~MediaMemoryReporter();
static MediaMemoryReporter* sUniqueInstance;
static MediaMemoryReporter* UniqueInstance() {
if (!sUniqueInstance) {
sUniqueInstance = new MediaMemoryReporter;
}
return sUniqueInstance;
}
typedef nsTArray<nsMediaDecoder*> DecodersArray;
static DecodersArray& Decoders() {
return UniqueInstance()->mDecoders;
}
DecodersArray mDecoders;
nsCOMPtr<nsIMemoryReporter> mMediaDecodedVideoMemory;
nsCOMPtr<nsIMemoryReporter> mMediaDecodedAudioMemory;
public:
static void AddMediaDecoder(nsMediaDecoder* aDecoder) {
Decoders().AppendElement(aDecoder);
}
static void RemoveMediaDecoder(nsMediaDecoder* aDecoder) {
DecodersArray& decoders = Decoders();
decoders.RemoveElement(aDecoder);
if (decoders.IsEmpty()) {
delete sUniqueInstance;
sUniqueInstance = nullptr;
}
}
static int64_t GetDecodedVideoMemory() {
DecodersArray& decoders = Decoders();
int64_t result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->VideoQueueMemoryInUse();
}
return result;
}
static int64_t GetDecodedAudioMemory() {
DecodersArray& decoders = Decoders();
int64_t result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->AudioQueueMemoryInUse();
}
return result;
}
};
} //namespace mozilla
#endif

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

@ -11,7 +11,7 @@
class nsOggDecoder : public nsBuiltinDecoder
{
public:
virtual nsMediaDecoder* Clone() {
virtual nsBuiltinDecoder* Clone() {
if (!IsOggEnabled()) {
return nullptr;
}

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

@ -80,7 +80,7 @@ nsOggReader::nsOggReader(nsBuiltinDecoder* aDecoder)
mTheoraState(nullptr),
mVorbisState(nullptr),
mOpusState(nullptr),
mOpusEnabled(nsMediaDecoder::IsOpusEnabled()),
mOpusEnabled(nsBuiltinDecoder::IsOpusEnabled()),
mSkeletonState(nullptr),
mVorbisSerial(0),
mOpusSerial(0),
@ -669,7 +669,7 @@ bool nsOggReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsBuiltinDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
// Read the next data packet. Skip any non-data packets we encounter.
ogg_packet* packet = 0;

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

@ -18,7 +18,7 @@
#include "VideoUtils.h"
class nsMediaDecoder;
class nsBuiltinDecoder;
class nsTimeRanges;
class nsOggReader : public nsBuiltinDecoderReader

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

@ -13,7 +13,7 @@ nsMediaOmxDecoder::nsMediaOmxDecoder() :
{
}
nsMediaDecoder* nsMediaOmxDecoder::Clone()
nsBuiltinDecoder* nsMediaOmxDecoder::Clone()
{
return new nsMediaOmxDecoder();
}

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

@ -15,7 +15,7 @@ public:
nsMediaOmxDecoder();
~nsMediaOmxDecoder();
virtual nsMediaDecoder* Clone();
virtual nsBuiltinDecoder* Clone();
virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
};

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

@ -123,7 +123,7 @@ bool nsMediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsBuiltinDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
// Throw away the currently buffered frame if we are seeking.
if (mLastVideoFrame && mVideoSeekTimeUs != -1) {

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

@ -20,7 +20,7 @@ public:
return NS_OK;
}
virtual nsMediaDecoder* Clone() { return new nsMediaPluginDecoder(mType); }
virtual nsBuiltinDecoder* Clone() { return new nsMediaPluginDecoder(mType); }
virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
};

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

@ -116,7 +116,7 @@ bool nsMediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsBuiltinDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
// Throw away the currently buffered frame if we are seeking.
if (mLastVideoFrame && mVideoSeekTimeUs != -1) {

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

@ -10,7 +10,7 @@
class nsRawDecoder : public nsBuiltinDecoder
{
public:
virtual nsMediaDecoder* Clone() {
virtual nsBuiltinDecoder* Clone() {
if (!IsRawEnabled()) {
return nullptr;
}

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

@ -150,7 +150,7 @@ bool nsRawReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsBuiltinDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
if (!mFrameSize)
return false; // Metadata read failed. We should refuse to play.

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

@ -23,7 +23,7 @@
class nsWaveDecoder : public nsBuiltinDecoder
{
public:
virtual nsMediaDecoder* Clone() {
virtual nsBuiltinDecoder* Clone() {
if (!IsWaveEnabled()) {
return nullptr;
}

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

@ -11,7 +11,7 @@
class nsWebMDecoder : public nsBuiltinDecoder
{
public:
virtual nsMediaDecoder* Clone() {
virtual nsBuiltinDecoder* Clone() {
if (!IsWebMEnabled()) {
return nullptr;
}

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

@ -603,7 +603,7 @@ bool nsWebMReader::DecodeVideoFrame(bool &aKeyframeSkip,
// Record number of frames decoded and parsed. Automatically update the
// stats counters using the AutoNotifyDecoded stack-based class.
uint32_t parsed = 0, decoded = 0;
nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsBuiltinDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded);
nsAutoRef<NesteggPacketHolder> holder(NextPacket(VIDEO));
if (!holder) {