зеркало из https://github.com/mozilla/gecko-dev.git
Bug 811381 - Flatten nsMediaDecoder and nsBuiltinDecoder into a single class. r=roc
This commit is contained in:
Родитель
356627a249
Коммит
9fe37d1328
|
@ -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
|
||||
|
@ -163,7 +163,7 @@ The general sequence of events is:
|
|||
While the play state is PLAYING, the decode thread will decode
|
||||
data, and the audio thread will push audio data to the hardware to
|
||||
be played. The state machine will run periodically on the shared
|
||||
state machine thread to ensure video frames are played at the
|
||||
state machine thread to ensure video frames are played at the
|
||||
correct time; i.e. the state machine manages A/V sync.
|
||||
|
||||
The Shutdown method on nsBuiltinDecoder closes the download channel, and
|
||||
|
@ -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
|
||||
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
// If the Theora granulepos has not been captured, it may read several packets
|
||||
// until one with a granulepos has been captured, to ensure that all packets
|
||||
// read have valid time info.
|
||||
// read have valid time info.
|
||||
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
|
||||
int64_t aTimeThreshold);
|
||||
|
||||
|
|
|
@ -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,10 +10,10 @@
|
|||
class nsRawDecoder : public nsBuiltinDecoder
|
||||
{
|
||||
public:
|
||||
virtual nsMediaDecoder* Clone() {
|
||||
virtual nsBuiltinDecoder* Clone() {
|
||||
if (!IsRawEnabled()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return new nsRawDecoder();
|
||||
}
|
||||
virtual nsBuiltinDecoderStateMachine* CreateStateMachine();
|
||||
|
|
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче