Bug 672755 - Add memory reporters for decoded video and audio queues. r=cpearce r=joe

This commit is contained in:
Matthew Gregan 2011-07-22 15:17:23 +12:00
parent 36d24c4340
commit db3428cfec
13 changed files with 199 additions and 7 deletions

View File

@ -327,6 +327,9 @@ public:
virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
virtual PRInt64 VideoQueueMemoryInUse() = 0;
virtual PRInt64 AudioQueueMemoryInUse() = 0;
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) = 0;
// Causes the state machine to switch to buffering state, and to
@ -471,6 +474,20 @@ class nsBuiltinDecoder : public nsMediaDecoder
return NS_ERROR_FAILURE;
}
virtual PRInt64 VideoQueueMemoryInUse() {
if (mDecoderStateMachine) {
return mDecoderStateMachine->VideoQueueMemoryInUse();
}
return 0;
}
virtual PRInt64 AudioQueueMemoryInUse() {
if (mDecoderStateMachine) {
return mDecoderStateMachine->AudioQueueMemoryInUse();
}
return 0;
}
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
return mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
}

View File

@ -50,8 +50,6 @@ using namespace mozilla;
using mozilla::layers::ImageContainer;
using mozilla::layers::PlanarYCbCrImage;
using mozilla::layers::PlanarYCbCrImage;
// Verify these values are sane. Once we've checked the frame sizes, we then
// can do less integer overflow checking.
PR_STATIC_ASSERT(MAX_VIDEO_WIDTH < PlanarYCbCrImage::MAX_DIMENSION);

View File

@ -390,8 +390,13 @@ template <class T> class MediaQueue : private nsDeque {
return last->mTime - first->mTime;
}
void LockedForEach(nsDequeFunctor& aFunctor) const {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
ForEach(aFunctor);
}
private:
ReentrantMonitor mReentrantMonitor;
mutable ReentrantMonitor mReentrantMonitor;
// PR_TRUE when we've decoded the last frame of data in the
// bitstream for which we're queueing sample-data.
@ -465,6 +470,48 @@ public:
virtual nsresult GetBuffered(nsTimeRanges* aBuffered,
PRInt64 aStartTime) = 0;
class VideoQueueMemoryFunctor : public nsDequeFunctor {
public:
VideoQueueMemoryFunctor() : mResult(0) {}
virtual void* operator()(void* anObject) {
const VideoData* v = static_cast<const VideoData*>(anObject);
NS_ASSERTION(v->mImage->GetFormat() == mozilla::layers::Image::PLANAR_YCBCR,
"Wrong format?");
mozilla::layers::PlanarYCbCrImage* vi = static_cast<mozilla::layers::PlanarYCbCrImage*>(v->mImage.get());
mResult += vi->GetDataSize();
return nsnull;
}
PRInt64 mResult;
};
PRInt64 VideoQueueMemoryInUse() {
VideoQueueMemoryFunctor functor;
mVideoQueue.LockedForEach(functor);
return functor.mResult;
}
class AudioQueueMemoryFunctor : public nsDequeFunctor {
public:
AudioQueueMemoryFunctor() : mResult(0) {}
virtual void* operator()(void* anObject) {
const SoundData* soundData = static_cast<const SoundData*>(anObject);
mResult += soundData->mSamples * soundData->mChannels * sizeof(SoundDataValue);
return nsnull;
}
PRInt64 mResult;
};
PRInt64 AudioQueueMemoryInUse() {
AudioQueueMemoryFunctor functor;
mAudioQueue.LockedForEach(functor);
return functor.mResult;
}
// Only used by nsWebMReader for now, so stub here rather than in every
// reader than inherits from nsBuiltinDecoderReader.
virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {}

View File

@ -228,6 +228,20 @@ public:
nsresult GetBuffered(nsTimeRanges* aBuffered);
PRInt64 VideoQueueMemoryInUse() {
if (mReader) {
return mReader->VideoQueueMemoryInUse();
}
return 0;
}
PRInt64 AudioQueueMemoryInUse() {
if (mReader) {
return mReader->AudioQueueMemoryInUse();
}
return 0;
}
void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRUint32 aOffset) {
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
mReader->NotifyDataArrived(aBuffer, aLength, aOffset);

View File

@ -52,6 +52,7 @@
#include "nsDOMError.h"
#include "nsDisplayList.h"
#include "nsSVGEffects.h"
#include "VideoUtils.h"
using namespace mozilla;
@ -81,11 +82,13 @@ nsMediaDecoder::nsMediaDecoder() :
mShuttingDown(PR_FALSE)
{
MOZ_COUNT_CTOR(nsMediaDecoder);
MediaMemoryReporter::AddMediaDecoder(this);
}
nsMediaDecoder::~nsMediaDecoder()
{
MOZ_COUNT_DTOR(nsMediaDecoder);
MediaMemoryReporter::RemoveMediaDecoder(this);
}
PRBool nsMediaDecoder::Init(nsHTMLMediaElement* aElement)
@ -305,3 +308,37 @@ PRBool nsMediaDecoder::CanPlayThrough()
return stats.mTotalBytes == stats.mDownloadPosition ||
stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
}
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

View File

@ -49,6 +49,7 @@
#include "ImageLayers.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/Mutex.h"
#include "nsIMemoryReporter.h"
class nsHTMLMediaElement;
class nsMediaStream;
@ -369,6 +370,11 @@ public:
// to buffer, given the current download and playback rates.
PRBool CanPlayThrough();
// Returns the size, in bytes, of the heap memory used by the currently
// queued decoded video and audio data.
virtual PRInt64 VideoQueueMemoryInUse() = 0;
virtual PRInt64 AudioQueueMemoryInUse() = 0;
protected:
// Start timer to update download progress information.
@ -458,4 +464,62 @@ protected:
PRPackedBool 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 = nsnull;
}
}
static PRInt64 GetDecodedVideoMemory() {
DecodersArray& decoders = Decoders();
PRInt64 result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->VideoQueueMemoryInUse();
}
return result;
}
static PRInt64 GetDecodedAudioMemory() {
DecodersArray& decoders = Decoders();
PRInt64 result = 0;
for (size_t i = 0; i < decoders.Length(); ++i) {
result += decoders[i]->AudioQueueMemoryInUse();
}
return result;
}
};
} //namespace mozilla
#endif

View File

@ -454,6 +454,11 @@ public:
virtual PRUint8* AllocateBuffer(PRUint32 aSize);
/**
* Return the number of bytes of heap memory used to store this image.
*/
virtual PRUint32 GetDataSize() = 0;
protected:
PlanarYCbCrImage(void* aImplData) : Image(aImplData, PLANAR_YCBCR) {}
};

View File

@ -129,6 +129,8 @@ public:
void SetOffscreenFormat(gfxImageFormat aFormat) { mOffscreenFormat = aFormat; }
gfxImageFormat GetOffscreenFormat() { return mOffscreenFormat; }
PRUint32 GetDataSize() { return mBuffer ? mDelayedConversion ? mBufferSize : mSize.height * mStride : 0; }
protected:
nsAutoArrayPtr<PRUint8> mBuffer;
nsCountedRef<nsMainThreadSurfaceRef> mSurface;

View File

@ -371,6 +371,7 @@ ImageLayerD3D10::RenderLayer()
PlanarYCbCrImageD3D10::PlanarYCbCrImageD3D10(ID3D10Device1 *aDevice)
: PlanarYCbCrImage(static_cast<ImageD3D10*>(this))
, mBufferSize(0)
, mDevice(aDevice)
, mHasData(PR_FALSE)
{
@ -379,8 +380,7 @@ PlanarYCbCrImageD3D10::PlanarYCbCrImageD3D10(ID3D10Device1 *aDevice)
void
PlanarYCbCrImageD3D10::SetData(const PlanarYCbCrImage::Data &aData)
{
PRUint32 dummy;
mBuffer = CopyData(mData, mSize, dummy, aData);
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
AllocateTextures();

View File

@ -114,9 +114,12 @@ public:
PRBool HasData() { return mHasData; }
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
virtual already_AddRefed<gfxASurface> GetAsSurface();
nsAutoArrayPtr<PRUint8> mBuffer;
PRUint32 mBufferSize;
nsRefPtr<ID3D10Device1> mDevice;
Data mData;
gfxIntSize mSize;

View File

@ -397,6 +397,7 @@ ImageLayerD3D9::RenderLayer()
PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9()
: PlanarYCbCrImage(static_cast<ImageD3D9*>(this))
, mBufferSize(0)
, mHasData(PR_FALSE)
{
}
@ -404,8 +405,7 @@ PlanarYCbCrImageD3D9::PlanarYCbCrImageD3D9()
void
PlanarYCbCrImageD3D9::SetData(const PlanarYCbCrImage::Data &aData)
{
PRUint32 dummy;
mBuffer = CopyData(mData, mSize, dummy, aData);
mBuffer = CopyData(mData, mSize, mBufferSize, aData);
mHasData = PR_TRUE;
}

View File

@ -124,9 +124,12 @@ public:
void FreeTextures();
PRBool HasData() { return mHasData; }
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
virtual already_AddRefed<gfxASurface> GetAsSurface();
nsAutoArrayPtr<PRUint8> mBuffer;
PRUint32 mBufferSize;
LayerManagerD3D9 *mManager;
Data mData;
gfxIntSize mSize;

View File

@ -211,6 +211,8 @@ public:
return mRecycleBin->GetBuffer(aSize);
}
PRUint32 GetDataSize() { return mBuffer ? mBufferSize : 0; }
nsAutoArrayPtr<PRUint8> mBuffer;
PRUint32 mBufferSize;
nsRefPtr<RecycleBin> mRecycleBin;